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