mknetid.c revision 1.5 1 /* $NetBSD: mknetid.c,v 1.5 1997/10/13 03:51:58 lukem 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 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Mats O Jansson
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
22 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
25 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 #ifndef lint
36 __RCSID("$NetBSD: mknetid.c,v 1.5 1997/10/13 03:51:58 lukem Exp $");
37 #endif
38
39 /*
40 * Originally written by Mats O Jansson <moj (at) stacken.kth.se>
41 * Simplified a bit by Jason R. Thorpe <thorpej (at) NetBSD.ORG>
42 */
43
44 #include <sys/param.h>
45 #include <sys/queue.h>
46 #include <ctype.h>
47 #include <err.h>
48 #include <grp.h>
49 #include <limits.h>
50 #include <netdb.h>
51 #include <pwd.h>
52 #include <stdio.h>
53 #include <string.h>
54 #include <stdlib.h>
55 #include <unistd.h>
56
57 #include <rpcsvc/ypclnt.h>
58
59 #include "protos.h"
60
61 struct user {
62 char *usr_name; /* user name */
63 int usr_uid; /* user uid */
64 int usr_gid; /* user gid */
65 int gid_count; /* number of gids */
66 int gid[NGROUPS]; /* additional gids */
67 TAILQ_ENTRY(user) read; /* links in read order */
68 TAILQ_ENTRY(user) hash; /* links in hash order */
69 };
70
71 #ifdef HOSTS
72 char *HostFile = HOSTS;
73 #else
74 char *HostFile = _PATH_HOSTS;
75 #endif
76
77 #ifdef PASSWD
78 char *PasswdFile = PASSWD;
79 #else
80 char *PasswdFile = _PATH_PASSWD;
81 #endif
82
83 #ifdef GROUP
84 char *GroupFile = GROUP;
85 #else
86 char *GroupFile = _PATH_GROUP;
87 #endif
88
89 #ifdef NETID
90 char *NetidFile = NETID;
91 #else
92 char *NetidFile = "/etc/netid";
93 #endif
94
95 #define HASHMAX 55
96
97 int main __P((int, char *[]));
98 void print_passwd_group __P((int, char *));
99 void print_hosts __P((FILE *, char *, char *));
100 void print_netid __P((FILE *, char *));
101 void add_user __P((char *, char *, char *));
102 void add_group __P((char *, char *));
103 void read_passwd __P((FILE *, char *));
104 void read_group __P((FILE *, char *));
105 void usage __P((void));
106 int hashidx __P((char));
107 int isgsep __P((char));
108
109 TAILQ_HEAD(user_list, user);
110 struct user_list root;
111 struct user_list hroot[HASHMAX];
112
113 extern char *__progname; /* from crt0.o */
114
115 int
116 main(argc, argv)
117 int argc;
118 char *argv[];
119 {
120 int qflag, ch;
121 char *domain;
122 FILE *pfile, *gfile, *hfile, *mfile;
123
124 TAILQ_INIT(&root);
125 for (ch = 0; ch < HASHMAX; ch++)
126 TAILQ_INIT((&hroot[ch]));
127
128 qflag = 0;
129 domain = NULL;
130
131 while ((ch = getopt(argc, argv, "d:g:h:m:p:q")) != -1) {
132 switch (ch) {
133 case 'd':
134 domain = optarg;
135 break;
136
137 case 'g':
138 GroupFile = optarg;
139 break;
140
141 case 'h':
142 HostFile = optarg;
143 break;
144
145 case 'm':
146 NetidFile = optarg;
147 break;
148
149 case 'p':
150 PasswdFile = optarg;
151 break;
152
153 case 'q':
154 qflag++;
155 break;
156
157 default:
158 usage();
159 }
160 }
161 argc -= optind; argv += optind;
162
163 if (argc != 0)
164 usage();
165
166 if (domain == NULL)
167 if (yp_get_default_domain(&domain))
168 errx(1, "Can't get YP domain name");
169
170 if ((pfile = fopen(PasswdFile, "r")) == NULL)
171 err(1, "%s", PasswdFile);
172
173 if ((gfile = fopen(GroupFile, "r")) == NULL)
174 err(1, "%s", GroupFile);
175
176 if ((hfile = fopen(HostFile, "r")) == NULL)
177 err(1, "%s", HostFile);
178
179 mfile = fopen(NetidFile, "r");
180
181 read_passwd(pfile, PasswdFile);
182 read_group(gfile, GroupFile);
183
184 print_passwd_group(qflag, domain);
185 print_hosts(hfile, HostFile, domain);
186
187 if (mfile != NULL)
188 print_netid(mfile, NetidFile);
189
190 exit (0);
191 }
192
193 int
194 hashidx(key)
195 char key;
196 {
197 if (key < 'A')
198 return(0);
199
200 if (key <= 'Z')
201 return(1 + key - 'A');
202
203 if (key < 'a')
204 return(27);
205
206 if (key <= 'z')
207 return(28 + key - 'a');
208
209 return(54);
210 }
211
212 void
213 add_user(username, uid, gid)
214 char *username, *uid, *gid;
215 {
216 struct user *u;
217 int idx;
218
219 idx = hashidx(username[0]);
220
221 u = (struct user *)malloc(sizeof(struct user));
222 if (u == NULL)
223 err(1, "can't allocate user");
224 memset(u, 0, sizeof(struct user));
225
226 u->usr_name = (char *)malloc(strlen(username) + 1);
227 if (u->usr_name == NULL)
228 err(1, "can't allocate user name");
229 strcpy(u->usr_name, username);
230
231 u->usr_uid = atoi(uid);
232 u->usr_gid = atoi(gid);
233 u->gid_count = -1;
234
235 TAILQ_INSERT_TAIL(&root, u, read);
236 TAILQ_INSERT_TAIL((&hroot[idx]), u, hash);
237 }
238
239 void
240 add_group(username, gid)
241 char *username, *gid;
242 {
243 struct user *u;
244 int g, idx;
245
246 g = atoi(gid);
247 idx = hashidx(username[0]);
248
249 for (u = hroot[idx].tqh_first;
250 u != NULL; u = u->hash.tqe_next) {
251 if (strcmp(username, u->usr_name) == 0) {
252 if (g != u->usr_gid) {
253 u->gid_count++;
254 if (u->gid_count < NGROUPS)
255 u->gid[u->gid_count] = g;
256 }
257 return;
258 }
259 }
260 }
261
262 void
263 read_passwd(pfile, fname)
264 FILE *pfile;
265 char *fname;
266 {
267 char line[_POSIX2_LINE_MAX];
268 int line_no = 0, len, colon;
269 char *p, *k, *u, *g;
270
271 while (read_line(pfile, line, sizeof(line))) {
272 line_no++;
273 len = strlen(line);
274
275 if (len <= 1 || line[0] == '#')
276 continue;
277
278 /*
279 * Check if we have the whole line
280 */
281 if (line[len - 1] != '\n') {
282 warnx("%s line %d: line to long, skipping",
283 fname, line_no);
284 continue;
285 } else
286 line[len - 1] = '\0';
287
288 p = line;
289
290 for (k = p, colon = 0; *k != '\0'; k++)
291 if (*k == ':')
292 colon++;
293
294 if (colon > 0) {
295 /* terminate key */
296 for (k = p; *p != ':'; p++);
297 *p++ = '\0';
298
299 /* If it's a YP entry, skip it. */
300 if (strlen(k) == 1)
301 if (*k == '+' || *k == '-')
302 continue;
303 }
304
305 if (colon < 4) {
306 warnx("%s line %d: syntax error",
307 fname, line_no);
308 continue;
309 }
310
311 /* terminate password */
312 for (; *p != ':'; p++);
313 *p++ = '\0';
314
315 /* terminate uid */
316 for (u = p; *p != ':'; p++);
317 *p++ = '\0';
318
319 /* terminate gid */
320 for (g = p; *p != ':'; p++);
321 *p++ = '\0';
322
323 add_user(k, u, g);
324 }
325 }
326
327 int
328 isgsep(ch)
329 char ch;
330 {
331
332 switch (ch) {
333 case ',':
334 case ' ':
335 case '\t':
336 case '\0':
337 return (1);
338 }
339
340 return (0);
341 }
342
343 void
344 read_group(gfile, fname)
345 FILE *gfile;
346 char *fname;
347 {
348 char line[_POSIX2_LINE_MAX];
349 int line_no = 0, len, colon;
350 char *p, *k, *u, *g;
351
352 while (read_line(gfile, line, sizeof(line))) {
353 line_no++;
354 len = strlen(line);
355
356 if (len > 1) {
357 if (line[0] == '#') {
358 continue;
359 }
360 } else
361 continue;
362
363 /*
364 * Check if we have the whole line
365 */
366 if (line[len - 1] != '\n') {
367 warnx("%s line %d: line to long, skipping",
368 fname, line_no);
369 continue;
370 } else
371 line[len - 1] = '\0';
372
373 p = line;
374
375 for (k = p, colon = 0; *k != '\0'; k++)
376 if (*k == ':')
377 colon++;
378
379 if (colon > 0) {
380 /* terminate key */
381 for (k = p; *p != ':'; p++);
382 *p++ = '\0';
383
384 /* If it's a YP entry, skip it. */
385 if (strlen(k) == 1)
386 if (*k == '+' || *k == '-')
387 continue;
388 }
389
390 if (colon < 3) {
391 warnx("%s line %d: syntax error",
392 fname, line_no);
393 continue;
394 }
395
396 /* terminate password */
397 for (; *p != ':'; p++);
398 *p++ = '\0';
399
400 /* terminate gid */
401 for (g = p; *p != ':'; p++);
402 *p++ = '\0';
403
404 /* get the group list */
405 for (u = p; *u != '\0'; u = p) {
406 /* find separator */
407 for (; isgsep(*p) == 0; p++);
408
409 if (*p != '\0') {
410 *p = '\0';
411 if (u != p)
412 add_group(u, g);
413 p++;
414 } else if (u != p)
415 add_group(u, g);
416 }
417 }
418 }
419
420 void
421 print_passwd_group(qflag, domain)
422 int qflag;
423 char *domain;
424 {
425 struct user *u, *p;
426 int i;
427
428 for (u = root.tqh_first; u != NULL; u = u->read.tqe_next) {
429 for (p = root.tqh_first; p->usr_uid != u->usr_uid;
430 p = p->read.tqe_next)
431 /* empty */ ;
432 if (p != u) {
433 if (!qflag) {
434 warnx("unix.%d@%s %s", u->usr_uid, domain,
435 "multiply defined, ignoring duplicate");
436 }
437 } else {
438 printf("unix.%d@%s %d:%d", u->usr_uid, domain,
439 u->usr_uid, u->usr_gid);
440 if (u->gid_count >= 0)
441 for (i = 0; i <= u->gid_count; i++)
442 printf(",%d", u->gid[i]);
443 printf("\n");
444 }
445 }
446 }
447
448 void
449 print_hosts(pfile, fname, domain)
450 FILE *pfile;
451 char *fname, *domain;
452 {
453 char line[_POSIX2_LINE_MAX];
454 int line_no = 0, len;
455 char *p, *k, *u;
456
457 while (read_line(pfile, line, sizeof(line))) {
458 line_no++;
459 len = strlen(line);
460
461 if (len > 1) {
462 if (line[0] == '#') {
463 continue;
464 }
465 } else
466 continue;
467
468 /*
469 * Check if we have the whole line
470 */
471 if (line[len - 1] != '\n') {
472 warnx("%s line %d: line to long, skipping",
473 fname, line_no);
474 continue;
475 } else
476 line[len - 1] = '\0';
477
478 p = line;
479
480 /* Find the key, replace trailing whitespace will <NUL> */
481 for (k = p; isspace(*p) == 0; p++);
482 while (isspace(*p))
483 *p++ = '\0';
484
485 /* Get first hostname. */
486 for (u = p; ; ) {
487 /* Check for EOL */
488 if (*p == '\0')
489 break;
490
491 if (isspace(*p) == 0)
492 p++;
493 else {
494 /* Got it. */
495 *p = '\0';
496 break;
497 }
498 }
499
500 printf("unix.%s@%s 0:%s\n", u, domain, u);
501 }
502 }
503
504 void
505 print_netid(mfile, fname)
506 FILE *mfile;
507 char *fname;
508 {
509 char line[_POSIX2_LINE_MAX];
510 int line_no = 0, len;
511 char *p, *k, *u;
512
513 while (read_line(mfile, line, sizeof(line))) {
514 line_no++;
515 len = strlen(line);
516
517 if (len > 1)
518 if (line[0] == '#')
519 continue;
520 else
521 continue;
522
523 /*
524 * Check if we have the while line
525 */
526 if (line[len - 1] != '\n') {
527 warnx("%s line %d: line to long, skipping",
528 fname, line_no);
529 continue;
530 } else
531 line[len - 1] = '\0';
532
533 p = line;
534
535 /* Find the key, replace trailing whitespace will <NUL> */
536 for (k = p; isspace(*p) == 0; p++);
537 while (isspace(*p))
538 *p++ = '\0';
539
540 /* Get netid entry. */
541 for (u = p; ; ) {
542 /* Check for EOL */
543 if (*p == '\0')
544 break;
545
546 if (isspace(*p) == 0)
547 p++;
548 else {
549 /* Got it. */
550 *p = '\0';
551 break;
552 }
553 }
554
555 printf("%s %s\n", k, u);
556 }
557 }
558
559 void
560 usage()
561 {
562
563 fprintf(stderr, "usage: %s %s\n", __progname,
564 "[-d domain] [-q] [-p passwdfile] [-g groupfile]");
565 fprintf(stderr, " %s %s", __progname,
566 "[-g groupfile] [-h hostfile] [-m netidfile]");
567 exit(1);
568 }
569