mknetid.c revision 1.1 1 /* $NetBSD: mknetid.c,v 1.1 1996/08/09 10:14:55 thorpej 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 /*
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 "protos.h"
53
54 struct user {
55 char *usr_name; /* user name */
56 int usr_uid; /* user uid */
57 int usr_gid; /* user gid */
58 int gid_count; /* number of gids */
59 int gid[NGROUPS]; /* additional gids */
60 TAILQ_ENTRY(user) read; /* links in read order */
61 TAILQ_ENTRY(user) hash; /* links in hash order */
62 };
63
64 #ifdef HOSTS
65 char *HostFile = HOSTS;
66 #else
67 char *HostFile = _PATH_HOSTS;
68 #endif
69
70 #ifdef PASSWD
71 char *PasswdFile = PASSWD;
72 #else
73 char *PasswdFile = _PATH_PASSWD;
74 #endif
75
76 #ifdef GROUP
77 char *GroupFile = GROUP;
78 #else
79 char *GroupFile = _PATH_GROUP;
80 #endif
81
82 #ifdef NETID
83 char *NetidFile = NETID;
84 #else
85 char *NetidFile = "/etc/netid";
86 #endif
87
88 #define HASHMAX 55
89
90 void print_passwd_group __P((int, char *));
91 void print_hosts __P((FILE *, char *, char *));
92 void print_netid __P((FILE *, char *));
93 void add_user __P((char *, char *, char *));
94 void add_group __P((char *, char *));
95 void read_passwd __P((FILE *, char *));
96 void read_group __P((FILE *, char *));
97 void usage __P((void));
98 int hashidx __P((char));
99 int isgsep __P((char));
100
101 TAILQ_HEAD(user_list, user);
102 struct user_list root;
103 struct user_list hroot[HASHMAX];
104
105 extern char *__progname; /* from crt0.s */
106 extern char *optarg;
107 extern int optind;
108
109 int
110 main(argc, argv)
111 int argc;
112 char **argv;
113 {
114 int qflag, ch;
115 char *domain;
116 FILE *pfile, *gfile, *hfile, *mfile;
117
118 TAILQ_INIT(&root);
119 for (ch = 0; ch < HASHMAX; ch++)
120 TAILQ_INIT((&hroot[ch]));
121
122 qflag = 0;
123 domain = NULL;
124
125 while ((ch = getopt(argc, argv, "d:g:h:m:p:q")) != -1) {
126 switch (ch) {
127 case 'd':
128 domain = optarg;
129 break;
130
131 case 'g':
132 GroupFile = optarg;
133 break;
134
135 case 'h':
136 HostFile = optarg;
137 break;
138
139 case 'm':
140 NetidFile = optarg;
141 break;
142
143 case 'p':
144 PasswdFile = optarg;
145 break;
146
147 case 'q':
148 qflag++;
149 break;
150
151 default:
152 usage();
153 }
154 }
155 argc -= optind; argv += optind;
156
157 if (argc != 0)
158 usage();
159
160 if (domain == NULL)
161 if (yp_get_default_domain(&domain))
162 errx(1, "can't get YP domain name");
163
164 if ((pfile = fopen(PasswdFile, "r")) == NULL)
165 err(1, "%s", PasswdFile);
166
167 if ((gfile = fopen(GroupFile, "r")) == NULL)
168 err(1, "%s", GroupFile);
169
170 if ((hfile = fopen(HostFile, "r")) == NULL)
171 err(1, "%s", HostFile);
172
173 mfile = fopen(NetidFile, "r");
174
175 read_passwd(pfile, PasswdFile);
176 read_group(gfile, GroupFile);
177
178 print_passwd_group(qflag, domain);
179 print_hosts(hfile, HostFile, domain);
180
181 if (mfile != NULL)
182 print_netid(mfile, NetidFile);
183
184 exit (0);
185 }
186
187 int
188 hashidx(key)
189 char key;
190 {
191 if (key < 'A')
192 return(0);
193
194 if (key <= 'Z')
195 return(1 + key - 'A');
196
197 if (key < 'a')
198 return(27);
199
200 if (key <= 'z')
201 return(28 + key - 'a');
202
203 return(54);
204 }
205
206 void
207 add_user(username, uid, gid)
208 char *username, *uid, *gid;
209 {
210 struct user *u;
211 int idx;
212
213 idx = hashidx(username[0]);
214
215 u = (struct user *)malloc(sizeof(struct user));
216 if (u == NULL)
217 err(1, "can't allocate user");
218 memset(u, 0, sizeof(struct user));
219
220 u->usr_name = (char *)malloc(strlen(username) + 1);
221 if (u->usr_name == NULL)
222 err(1, "can't allocate user name");
223 strcpy(u->usr_name, username);
224
225 u->usr_uid = atoi(uid);
226 u->usr_gid = atoi(gid);
227 u->gid_count = -1;
228
229 TAILQ_INSERT_TAIL(&root, u, read);
230 TAILQ_INSERT_TAIL((&hroot[idx]), u, hash);
231 }
232
233 void
234 add_group(username, gid)
235 char *username, *gid;
236 {
237 struct user *u;
238 int g, idx;
239
240 g = atoi(gid);
241 idx = hashidx(username[0]);
242
243 for (u = hroot[idx].tqh_first;
244 u != NULL; u = u->hash.tqe_next) {
245 if (strcmp(username, u->usr_name) == 0) {
246 if (g != u->usr_gid) {
247 u->gid_count++;
248 if (u->gid_count < NGROUPS)
249 u->gid[u->gid_count] = g;
250 }
251 return;
252 }
253 }
254 }
255
256 void
257 read_passwd(pfile, fname)
258 FILE *pfile;
259 char *fname;
260 {
261 char line[_POSIX2_LINE_MAX];
262 int line_no = 0, len, colon;
263 char *p, *k, *u, *g;
264
265 while (read_line(pfile, line, sizeof(line))) {
266 line_no++;
267 len = strlen(line);
268
269 if (len > 1) {
270 if (line[0] == '#') {
271 continue;
272 }
273 } else
274 continue;
275
276 /*
277 * Check if we have the whole line
278 */
279 if (line[len - 1] != '\n') {
280 warnx("%s line %d: line to long, skipping",
281 fname, line_no);
282 continue;
283 } else
284 line[len - 1] = '\0';
285
286 p = line;
287
288 for (k = p, colon = 0; *k != '\0'; k++)
289 if (*k == ':')
290 colon++;
291
292 if (colon > 0) {
293 /* terminate key */
294 for (k = p; *p != ':'; p++);
295 *p++ = '\0';
296
297 /* If it's a YP entry, skip it. */
298 if (strlen(k) == 1)
299 if (*k == '+' || *k == '-')
300 continue;
301 }
302
303 if (colon < 4) {
304 warnx("%s line %d: syntax error",
305 fname, line_no);
306 continue;
307 }
308
309 /* terminate password */
310 for (; *p != ':'; p++);
311 *p++ = '\0';
312
313 /* terminate uid */
314 for (u = p; *p != ':'; p++);
315 *p++ = '\0';
316
317 /* terminate gid */
318 for (g = p; *p != ':'; p++);
319 *p++ = '\0';
320
321 add_user(k, u, g);
322 }
323 }
324
325 int
326 isgsep(ch)
327 char ch;
328 {
329
330 switch (ch) {
331 case ',':
332 case ' ':
333 case '\t':
334 case '\0':
335 return (1);
336 }
337
338 return (0);
339 }
340
341 void
342 read_group(gfile, fname)
343 FILE *gfile;
344 char *fname;
345 {
346 char line[_POSIX2_LINE_MAX];
347 int line_no = 0, len, colon;
348 char *p, *k, *u, *g;
349
350 while (read_line(gfile, line, sizeof(line))) {
351 line_no++;
352 len = strlen(line);
353
354 if (len > 1) {
355 if (line[0] == '#') {
356 continue;
357 }
358 } else
359 continue;
360
361 /*
362 * Check if we have the whole line
363 */
364 if (line[len - 1] != '\n') {
365 warnx("%s line %d: line to long, skipping",
366 fname, line_no);
367 continue;
368 } else
369 line[len - 1] = '\0';
370
371 p = line;
372
373 for (k = p, colon = 0; *k != '\0'; k++)
374 if (*k == ':')
375 colon++;
376
377 if (colon > 0) {
378 /* terminate key */
379 for (k = p; *p != ':'; p++);
380 *p++ = '\0';
381
382 /* If it's a YP entry, skip it. */
383 if (strlen(k) == 1)
384 if (*k == '+' || *k == '-')
385 continue;
386 }
387
388 if (colon < 3) {
389 warnx("%s line %d: syntax error",
390 fname, line_no);
391 continue;
392 }
393
394 /* terminate password */
395 for (; *p != ':'; p++);
396 *p++ = '\0';
397
398 /* terminate gid */
399 for (g = p; *p != ':'; p++);
400 *p++ = '\0';
401
402 /* get the group list */
403 for (u = p; *u != '\0'; u = p) {
404 /* find separator */
405 for (; isgsep(*p) == 0; p++);
406
407 if (*p != '\0') {
408 *p = '\0';
409 if (u != p)
410 add_group(u, g);
411 p++;
412 } else if (u != p)
413 add_group(u, g);
414 }
415 }
416 }
417
418 void
419 print_passwd_group(qflag, domain)
420 int qflag;
421 char *domain;
422 {
423 struct user *u, *p;
424 int i;
425
426 for (u = root.tqh_first; u != NULL; u = u->read.tqe_next) {
427 for (p = root.tqh_first; p->usr_uid != u->usr_uid;
428 p = p->read.tqe_next)
429 /* empty */ ;
430 if (p != u) {
431 if (!qflag) {
432 warnx("unix.%d@%s %s", u->usr_uid, domain,
433 "multiply defined, ignoring duplicate");
434 }
435 } else {
436 printf("unix.%d@%s %d:%d", u->usr_uid, domain,
437 u->usr_uid, u->usr_gid);
438 if (u->gid_count >= 0)
439 for (i = 0; i <= u->gid_count; i++)
440 printf(",%d", u->gid[i]);
441 printf("\n");
442 }
443 }
444 }
445
446 void
447 print_hosts(pfile, fname, domain)
448 FILE *pfile;
449 char *fname, *domain;
450 {
451 char line[_POSIX2_LINE_MAX];
452 int line_no = 0, len, colon;
453 char *p, *k, *u;
454
455 while (read_line(pfile, line, sizeof(line))) {
456 line_no++;
457 len = strlen(line);
458
459 if (len > 1) {
460 if (line[0] == '#') {
461 continue;
462 }
463 } else
464 continue;
465
466 /*
467 * Check if we have the whole line
468 */
469 if (line[len - 1] != '\n') {
470 warnx("%s line %d: line to long, skipping",
471 fname, line_no);
472 continue;
473 } else
474 line[len - 1] = '\0';
475
476 p = line;
477
478 /* Find the key, replace trailing whitespace will <NUL> */
479 for (k = p; isspace(*p) == 0; p++);
480 while (isspace(*p))
481 *p++ = '\0';
482
483 /* Get first hostname. */
484 for (u = p; ; ) {
485 /* Check for EOL */
486 if (*p == '\0')
487 break;
488
489 if (isspace(*p) == 0)
490 p++;
491 else {
492 /* Got it. */
493 *p = '\0';
494 break;
495 }
496 }
497
498 printf("unix.%s@%s 0:%s\n", u, domain, u);
499 }
500 }
501
502 void
503 print_netid(mfile, fname)
504 FILE *mfile;
505 char *fname;
506 {
507 char line[_POSIX2_LINE_MAX];
508 int line_no = 0, len, colon;
509 char *p, *k, *u;
510
511 while (read_line(mfile, line, sizeof(line))) {
512 line_no++;
513 len = strlen(line);
514
515 if (len > 1)
516 if (line[0] == '#')
517 continue;
518 else
519 continue;
520
521 /*
522 * Check if we have the while line
523 */
524 if (line[len - 1] != '\n') {
525 warnx("%s line %d: line to long, skipping",
526 fname, line_no);
527 continue;
528 } else
529 line[len - 1] = '\0';
530
531 p = line;
532
533 /* Find the key, replace trailing whitespace will <NUL> */
534 for (k = p; isspace(*p) == 0; p++);
535 while (isspace(*p))
536 *p++ = '\0';
537
538 /* Get netid entry. */
539 for (u = p; ; ) {
540 /* Check for EOL */
541 if (*p == '\0')
542 break;
543
544 if (isspace(*p) == 0)
545 p++;
546 else {
547 /* Got it. */
548 *p = '\0';
549 break;
550 }
551 }
552
553 printf("%s %s\n", k, u);
554 }
555 }
556
557 void
558 usage()
559 {
560
561 fprintf(stderr, "usage %s: %s %s\n", __progname,
562 "[-d domain] [-q] [-p passwdfile] [-g groupfile]");
563 fprintf(stderr, " %s",
564 "[-g groupfile] [-h hostfile] [-m netidfile]");
565 }
566