mknetid.c revision 1.18 1 /* $NetBSD: mknetid.c,v 1.18 2011/08/30 21:10:28 joerg Exp $ */
2
3 /*
4 * Copyright (c) 1996 Mats O Jansson <moj (at) stacken.kth.se>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
17 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 #ifndef lint
31 __RCSID("$NetBSD: mknetid.c,v 1.18 2011/08/30 21:10:28 joerg Exp $");
32 #endif
33
34 /*
35 * Originally written by Mats O Jansson <moj (at) stacken.kth.se>
36 * Simplified a bit by Jason R. Thorpe <thorpej (at) NetBSD.org>
37 */
38
39 #include <sys/param.h>
40 #include <sys/queue.h>
41 #include <ctype.h>
42 #include <err.h>
43 #include <grp.h>
44 #include <limits.h>
45 #include <netdb.h>
46 #include <pwd.h>
47 #include <stdio.h>
48 #include <string.h>
49 #include <stdlib.h>
50 #include <unistd.h>
51
52 #include <rpcsvc/ypclnt.h>
53
54 #include "protos.h"
55
56 struct user {
57 char *usr_name; /* user name */
58 int usr_uid; /* user uid */
59 int usr_gid; /* user gid */
60 int gid_count; /* number of gids */
61 int gid[NGROUPS]; /* additional gids */
62 TAILQ_ENTRY(user) read; /* links in read order */
63 TAILQ_ENTRY(user) hash; /* links in hash order */
64 };
65
66 #define HASHMAX 55
67
68 static void add_group(const char *, const char *);
69 static void add_user(const char *, const char *, const char *);
70 static int hashidx(char);
71 static int isgsep(char);
72 static void print_hosts(const char *, const char *);
73 static void print_netid(const char *);
74 static void print_passwd_group(int, const char *);
75 static void read_group(const char *);
76 static void read_passwd(const char *);
77 __dead static void usage(void);
78
79 TAILQ_HEAD(user_list, user);
80 static struct user_list root;
81 static struct user_list hroot[HASHMAX];
82
83 int
84 main(int argc, char *argv[])
85 {
86 const char *HostFile = _PATH_HOSTS;
87 const char *PasswdFile = _PATH_PASSWD;
88 const char *GroupFile = _PATH_GROUP;
89 const char *NetidFile = "/etc/netid";
90
91 int qflag, ch;
92 char *domain;
93
94 TAILQ_INIT(&root);
95 for (ch = 0; ch < HASHMAX; ch++)
96 TAILQ_INIT((&hroot[ch]));
97
98 qflag = 0;
99 domain = NULL;
100
101 while ((ch = getopt(argc, argv, "d:g:h:m:p:q")) != -1) {
102 switch (ch) {
103 case 'd':
104 domain = optarg;
105 break;
106
107 case 'g':
108 GroupFile = optarg;
109 break;
110
111 case 'h':
112 HostFile = optarg;
113 break;
114
115 case 'm':
116 NetidFile = optarg;
117 break;
118
119 case 'p':
120 PasswdFile = optarg;
121 break;
122
123 case 'q':
124 qflag++;
125 break;
126
127 default:
128 usage();
129 }
130 }
131 if (argc != optind)
132 usage();
133
134 if (domain == NULL)
135 if (yp_get_default_domain(&domain))
136 errx(1, "Can't get YP domain name");
137
138 read_passwd(PasswdFile);
139 read_group(GroupFile);
140
141 print_passwd_group(qflag, domain);
142 print_hosts(HostFile, domain);
143 print_netid(NetidFile);
144
145 exit (0);
146 }
147
148 static int
149 hashidx(char key)
150 {
151 if (key < 'A')
152 return(0);
153
154 if (key <= 'Z')
155 return(1 + key - 'A');
156
157 if (key < 'a')
158 return(27);
159
160 if (key <= 'z')
161 return(28 + key - 'a');
162
163 return(54);
164 }
165
166 static void
167 add_user(const char *username, const char *uid, const char *gid)
168 {
169 struct user *u;
170 int idx;
171
172 idx = hashidx(username[0]);
173
174 u = (struct user *)malloc(sizeof(struct user));
175 if (u == NULL)
176 err(1, "can't allocate user");
177 memset(u, 0, sizeof(struct user));
178
179 u->usr_name = strdup(username);
180 if (u->usr_name == NULL)
181 err(1, "can't allocate user name");
182
183 u->usr_uid = atoi(uid);
184 u->usr_gid = atoi(gid);
185 u->gid_count = -1;
186
187 TAILQ_INSERT_TAIL(&root, u, read);
188 TAILQ_INSERT_TAIL((&hroot[idx]), u, hash);
189 }
190
191 static void
192 add_group(const char *username, const char *gid)
193 {
194 struct user *u;
195 int g, idx;
196
197 g = atoi(gid);
198 idx = hashidx(username[0]);
199
200 for (u = hroot[idx].tqh_first;
201 u != NULL; u = u->hash.tqe_next) {
202 if (strcmp(username, u->usr_name) == 0) {
203 if (g != u->usr_gid) {
204 u->gid_count++;
205 if (u->gid_count < NGROUPS)
206 u->gid[u->gid_count] = g;
207 }
208 return;
209 }
210 }
211 }
212
213 static void
214 read_passwd(const char *fname)
215 {
216 FILE *pfile;
217 size_t line_no;
218 int colon;
219 size_t len;
220 char *line, *p, *k, *u, *g;
221
222 if ((pfile = fopen(fname, "r")) == NULL)
223 err(1, "%s", fname);
224
225 line_no = 0;
226 for (;
227 (line = fparseln(pfile, &len, &line_no, NULL, FPARSELN_UNESCALL));
228 free(line)) {
229 if (len == 0) {
230 warnx("%s line %lu: empty line", fname,
231 (unsigned long)line_no);
232 continue;
233 }
234
235 p = line;
236 for (k = p, colon = 0; *k != '\0'; k++)
237 if (*k == ':')
238 colon++;
239
240 if (colon != 6) {
241 warnx("%s line %lu: incorrect number of fields",
242 fname, (unsigned long)line_no);
243 continue;
244 }
245
246 k = p;
247 p = strchr(p, ':');
248 *p++ = '\0';
249
250 /* If it's a YP entry, skip it. */
251 if (*k == '+' || *k == '-')
252 continue;
253
254 /* terminate password */
255 p = strchr(p, ':');
256 *p++ = '\0';
257
258 /* terminate uid */
259 u = p;
260 p = strchr(p, ':');
261 *p++ = '\0';
262
263 /* terminate gid */
264 g = p;
265 p = strchr(p, ':');
266 *p++ = '\0';
267
268 add_user(k, u, g);
269 }
270 (void)fclose(pfile);
271 }
272
273 static int
274 isgsep(char ch)
275 {
276
277 switch (ch) {
278 case ',':
279 case ' ':
280 case '\t':
281 case '\0':
282 return (1);
283 }
284
285 return (0);
286 }
287
288 static void
289 read_group(const char *fname)
290 {
291 FILE *gfile;
292 size_t line_no;
293 int colon;
294 size_t len;
295 char *line, *p, *k, *u, *g;
296
297 if ((gfile = fopen(fname, "r")) == NULL)
298 err(1, "%s", fname);
299
300 line_no = 0;
301 for (;
302 (line = fparseln(gfile, &len, &line_no, NULL, FPARSELN_UNESCALL));
303 free(line)) {
304 if (len == 0) {
305 warnx("%s line %lu: empty line", fname,
306 (unsigned long)line_no);
307 continue;
308 }
309
310 p = line;
311 for (k = p, colon = 0; *k != '\0'; k++)
312 if (*k == ':')
313 colon++;
314
315 if (colon != 3) {
316 warnx("%s line %lu: incorrect number of fields",
317 fname, (unsigned long)line_no);
318 continue;
319 }
320
321 /* terminate key */
322 k = p;
323 p = strchr(p, ':');
324 *p++ = '\0';
325
326 if (*k == '+' || *k == '-')
327 continue;
328
329 /* terminate password */
330 p = strchr(p, ':');
331 *p++ = '\0';
332
333 /* terminate gid */
334 g = p;
335 p = strchr(p, ':');
336 *p++ = '\0';
337
338 /* get the group list */
339 for (u = p; *u != '\0'; u = p) {
340 /* find separator */
341 for (; isgsep(*p) == 0; p++)
342 ;
343
344 if (*p != '\0') {
345 *p = '\0';
346 if (u != p)
347 add_group(u, g);
348 p++;
349 } else if (u != p)
350 add_group(u, g);
351 }
352 }
353 (void)fclose(gfile);
354 }
355
356 static void
357 print_passwd_group(int qflag, const char *domain)
358 {
359 struct user *u, *p;
360 int i;
361
362 for (u = root.tqh_first; u != NULL; u = u->read.tqe_next) {
363 for (p = root.tqh_first; p->usr_uid != u->usr_uid;
364 p = p->read.tqe_next)
365 /* empty */ ;
366 if (p != u) {
367 if (!qflag) {
368 warnx("unix.%d@%s %s", u->usr_uid, domain,
369 "multiply defined, ignoring duplicate");
370 }
371 } else {
372 printf("unix.%d@%s %d:%d", u->usr_uid, domain,
373 u->usr_uid, u->usr_gid);
374 if (u->gid_count >= 0)
375 for (i = 0; i <= u->gid_count; i++)
376 printf(",%d", u->gid[i]);
377 printf("\n");
378 }
379 }
380 }
381
382 static void
383 print_hosts(const char *fname, const char *domain)
384 {
385 FILE *hfile;
386 size_t len;
387 char *line, *p, *k, *u;
388
389 if ((hfile = fopen(fname, "r")) == NULL)
390 err(1, "%s", fname);
391
392 for (;
393 (line = fparseln(hfile, &len, NULL, NULL, FPARSELN_UNESCALL));
394 free(line)) {
395 if (len == 0)
396 continue;
397
398 p = line;
399 /* Find the key, replace trailing whitespace will <NUL> */
400 for (k = p; *p && isspace((unsigned char)*p) == 0; p++)
401 ;
402 while (*p && isspace((unsigned char)*p))
403 *p++ = '\0';
404
405 /* Get first hostname. */
406 for (u = p; *p && !isspace((unsigned char)*p); p++)
407 ;
408 *p = '\0';
409
410 printf("unix.%s@%s 0:%s\n", u, domain, u);
411 }
412 (void) fclose(hfile);
413 }
414
415 static void
416 print_netid(const char *fname)
417 {
418 FILE *mfile;
419 size_t len;
420 char *line, *p, *k, *u;
421
422 mfile = fopen(fname, "r");
423 if (mfile == NULL)
424 return;
425
426 for (;
427 (line = fparseln(mfile, &len, NULL, NULL, FPARSELN_UNESCALL));
428 free(line)) {
429 if (len == 0)
430 continue;
431
432 p = line;
433 /* Find the key, replace trailing whitespace will <NUL> */
434 for (k = p; *p && !isspace((unsigned char)*p); p++)
435 ;
436 while (*p && isspace((unsigned char)*p))
437 *p++ = '\0';
438
439 /* Get netid entry. */
440 for (u = p; *p && !isspace((unsigned char)*p); p++)
441 ;
442 *p = '\0';
443
444 printf("%s %s\n", k, u);
445 }
446 }
447
448 static void
449 usage(void)
450 {
451
452 fprintf(stderr, "usage: %s %s\n", getprogname(),
453 "[-d domain] [-q] [-p passwdfile] [-g groupfile]");
454 fprintf(stderr, " %s %s", getprogname(),
455 "[-g groupfile] [-h hostfile] [-m netidfile]");
456 exit(1);
457 }
458