1 /* $OpenBSD: mknetid.c,v 1.22 2015/02/09 23:00:15 deraadt Exp $ */
2
3 /*
4 * Copyright (c) 1996 Mats O Jansson <moj@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 <stdio.h>
30 #include <unistd.h>
31 #include <ctype.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include <pwd.h>
35 #include <grp.h>
36 #include <err.h>
37 #include <netdb.h>
38 #include <limits.h>
39
40 #include <rpcsvc/ypclnt.h>
41
42 struct user {
43 char *usr_name; /* user name */
44 int usr_uid; /* user uid */
45 int usr_gid; /* user gid */
46 int gid_count; /* number of gids */
47 int gid[NGROUPS_MAX]; /* additional gids */
48 struct user *prev, *next; /* links in read order */
49 struct user *hprev, *hnext; /* links in hash order */
50 };
51
52 char *HostFile = _PATH_HOSTS;
53 char *PasswdFile = _PATH_PASSWD;
54 char *MasterPasswdFile = _PATH_MASTERPASSWD;
55 char *GroupFile = _PATH_GROUP;
56 char *NetidFile = "/etc/netid";
57
58 #define HASHMAX 55
59
60 struct user *root = NULL, *tail = NULL;
61 struct user *hroot[HASHMAX], *htail[HASHMAX];
62
63 static int
read_line(FILE * fp,char * buf,int size)64 read_line(FILE *fp, char *buf, int size)
65 {
66 int done = 0;
67
68 do {
69 while (fgets(buf, size, fp)) {
70 int len = strlen(buf);
71
72 done += len;
73 if (len > 1 && buf[len-2] == '\\' &&
74 buf[len-1] == '\n') {
75 int ch;
76
77 buf += len - 2;
78 size -= len - 2;
79 *buf = '\n'; buf[1] = '\0';
80
81 /*
82 * Skip leading white space on next line
83 */
84 while ((ch = getc(fp)) != EOF &&
85 isascii(ch) && isspace(ch))
86 ;
87 (void) ungetc(ch, fp);
88 } else {
89 return done;
90 }
91 }
92 } while (size > 0 && !feof(fp));
93
94 return done;
95 }
96
97 static int
hashidx(char key)98 hashidx(char key)
99 {
100 if (key < 'A')
101 return (0);
102 if (key <= 'Z')
103 return (1 + key - 'A');
104 if (key < 'a')
105 return (27);
106 if (key <= 'z')
107 return (28 + key - 'a');
108 return (54);
109 }
110
111 static void
add_user(char * username,char * uid,char * gid)112 add_user(char *username, char *uid, char *gid)
113 {
114 struct user *u;
115 int idx;
116
117 u = malloc(sizeof(struct user));
118 if (u == NULL)
119 err(1, "malloc");
120 bzero(u, sizeof(struct user));
121 u->usr_name = strdup(username);
122 if (u->usr_name == NULL)
123 err(1, "strdup");
124 u->usr_uid = atoi(uid);
125 u->usr_gid = atoi(gid);
126 u->gid_count = -1;
127 if (root == NULL) {
128 root = tail = u;
129 } else {
130 u->prev = tail;
131 tail->next = u;
132 tail = u;
133 }
134 idx = hashidx(username[0]);
135 if (hroot[idx] == NULL) {
136 hroot[idx] = htail[idx] = u;
137 } else {
138 u->hprev = htail[idx];
139 htail[idx]->hnext = u;
140 htail[idx] = u;
141 }
142 }
143
144 static void
add_group(char * username,char * gid)145 add_group(char *username, char *gid)
146 {
147 struct user *u;
148 int idx, g;
149
150 idx = hashidx(username[0]);
151 u = hroot[idx];
152 g = atoi(gid);
153
154 while (u != NULL) {
155 if (strcmp(username, u->usr_name) == 0) {
156 if (g != u->usr_gid) {
157 u->gid_count++;
158 if (u->gid_count < NGROUPS_MAX)
159 u->gid[u->gid_count] = atoi(gid);
160 }
161 u = htail[idx];
162 }
163 u = u->hnext;
164 }
165 }
166
167 static void
read_passwd(FILE * pfile,char * fname)168 read_passwd(FILE *pfile, char *fname)
169 {
170 char line[1024], *p, *k, *u, *g;
171 int line_no = 0, len, colon;
172
173 while (read_line(pfile, line, sizeof(line))) {
174 line_no++;
175 len = strlen(line);
176
177 if (len > 0) {
178 if (line[0] == '#')
179 continue;
180 }
181
182 /*
183 * Check if we have the whole line
184 */
185 if (line[len-1] != '\n') {
186 fprintf(stderr, "line %d in \"%s\" is too long\n",
187 line_no, fname);
188 } else {
189 line[len-1] = '\0';
190 }
191
192 p = (char *)&line;
193
194 k = p; colon = 0;
195 while (*k != '\0') {
196 if (*k == ':')
197 colon++;
198 k++;
199 }
200
201 if (colon > 0) {
202 k = p; /* save start of key */
203 while (*p != ':')
204 p++; /* find first "colon" */
205 if (*p==':')
206 *p++ = '\0'; /* terminate key */
207 if (strlen(k) == 1) {
208 if (*k == '+')
209 continue;
210 }
211 }
212
213 if (colon < 4) {
214 fprintf(stderr, "syntax error at line %d in \"%s\"\n",
215 line_no, fname);
216 continue;
217 }
218
219 while (*p != ':')
220 p++; /* find second "colon" */
221 if (*p==':')
222 *p++ = '\0'; /* terminate passwd */
223 u = p;
224 while (*p != ':')
225 p++; /* find third "colon" */
226 if (*p==':')
227 *p++ = '\0'; /* terminate uid */
228 g = p;
229 while (*p != ':')
230 p++; /* find fourth "colon" */
231 if (*p==':')
232 *p++ = '\0'; /* terminate gid */
233 while (*p != '\0')
234 p++; /* find end of string */
235
236 add_user(k, u, g);
237 }
238 }
239
240 static int
isgsep(char ch)241 isgsep(char ch)
242 {
243 switch (ch) {
244 case ',':
245 case ' ':
246 case '\t':
247 case '\0':
248 return (1);
249 default:
250 return (0);
251 }
252 }
253
254 static void
read_group(FILE * gfile,char * fname)255 read_group(FILE *gfile, char *fname)
256 {
257 char line[2048], *p, *k, *u, *g;
258 int line_no = 0, len, colon;
259
260 while (read_line(gfile, line, sizeof(line))) {
261 line_no++;
262 len = strlen(line);
263
264 if (len > 0) {
265 if (line[0] == '#')
266 continue;
267 }
268
269 /*
270 * Check if we have the whole line
271 */
272 if (line[len-1] != '\n') {
273 fprintf(stderr, "line %d in \"%s\" is too long\n",
274 line_no, fname);
275 } else {
276 line[len-1] = '\0';
277 }
278
279 p = (char *)&line;
280
281 k = p; colon = 0;
282 while (*k != '\0') {
283 if (*k == ':')
284 colon++;
285 k++;
286 }
287
288 if (colon > 0) {
289 k = p; /* save start of key */
290 while (*p != ':')
291 p++; /* find first "colon" */
292 if (*p==':')
293 *p++ = '\0'; /* terminate key */
294 if (strlen(k) == 1) {
295 if (*k == '+')
296 continue;
297 }
298 }
299
300 if (colon < 3) {
301 fprintf(stderr, "syntax error at line %d in \"%s\"\n",
302 line_no, fname);
303 continue;
304 }
305
306 while (*p != ':')
307 p++; /* find second "colon" */
308 if (*p==':')
309 *p++ = '\0'; /* terminate passwd */
310 g = p;
311 while (*p != ':')
312 p++; /* find third "colon" */
313 if (*p==':')
314 *p++ = '\0'; /* terminate gid */
315
316 u = p;
317
318 while (*u != '\0') {
319 while (!isgsep(*p))
320 p++; /* find separator */
321 if (*p != '\0') {
322 *p = '\0';
323 if (u != p)
324 add_group(u, g);
325 p++;
326 } else {
327 if (u != p)
328 add_group(u, g);
329 }
330 u = p;
331 }
332 }
333 }
334
335 static void
print_passwd_group(int qflag,char * domain)336 print_passwd_group(int qflag, char *domain)
337 {
338 struct user *u, *p;
339 int i;
340
341 u = root;
342
343 while (u != NULL) {
344 p = root;
345 while (p->usr_uid != u->usr_uid)
346 p = p->next;
347
348 if (p != u) {
349 if (!qflag) {
350 fprintf(stderr, "mknetid: unix.%d@%s %s\n",
351 u->usr_uid, domain,
352 "multiply defined, other definitions ignored");
353 }
354 } else {
355 printf("unix.%d@%s %d:%d",
356 u->usr_uid, domain, u->usr_uid, u->usr_gid);
357 if (u->gid_count >= 0) {
358 i = 0;
359 while (i <= u->gid_count) {
360 printf(",%d", u->gid[i]);
361 i++;
362 }
363 }
364 printf("\n");
365 }
366 u = u->next;
367 }
368 }
369
370 static void
print_hosts(FILE * pfile,char * fname,char * domain)371 print_hosts(FILE *pfile, char *fname, char *domain)
372 {
373 char line[1024], *p, *u;
374 int line_no = 0, len;
375
376 while (read_line(pfile, line, sizeof(line))) {
377 line_no++;
378 len = strlen(line);
379
380 if (len > 0) {
381 if (line[0] == '#')
382 continue;
383 }
384
385 /*
386 * Check if we have the whole line
387 */
388 if (line[len-1] != '\n') {
389 fprintf(stderr, "line %d in \"%s\" is too long\n",
390 line_no, fname);
391 } else {
392 line[len-1] = '\0';
393 }
394
395 p = (char *)&line;
396
397 while (!isspace((unsigned char)*p))
398 p++; /* find first "space" */
399 while (isspace((unsigned char)*p))
400 *p++ = '\0'; /* replace space with <NUL> */
401
402 u = p;
403 while (p != NULL) {
404 if (*p == '\0') {
405 p = NULL;
406 } else {
407 if (!isspace((unsigned char)*p)) {
408 p++;
409 } else {
410 *p = '\0';
411 p = NULL;
412 }
413 }
414 }
415
416 printf("unix.%s@%s 0:%s\n", u, domain, u);
417 }
418 }
419
420 static void
print_netid(FILE * mfile,char * fname)421 print_netid(FILE *mfile, char *fname)
422 {
423 char line[1024], *p, *k, *u;
424 int line_no = 0, len;
425
426 while (read_line(mfile, line, sizeof(line))) {
427 line_no++;
428 len = strlen(line);
429
430 if (len > 0) {
431 if (line[0] == '#')
432 continue;
433 }
434
435 /*
436 * Check if we have the whole line
437 */
438 if (line[len-1] != '\n') {
439 fprintf(stderr, "line %d in \"%s\" is too long\n",
440 line_no, fname);
441 } else {
442 line[len-1] = '\0';
443 }
444
445 p = (char *)&line;
446
447 k = p; /* save start of key */
448 while (!isspace((unsigned char)*p))
449 p++; /* find first "space" */
450 while (isspace((unsigned char)*p))
451 *p++ = '\0'; /* replace space with <NUL> */
452
453 u = p;
454 while (p != NULL) {
455 if (*p == '\0') {
456 p = NULL;
457 } else {
458 if (!isspace((unsigned char)*p)) {
459 p++;
460 } else {
461 *p = '\0';
462 p = NULL;
463 }
464 }
465 }
466
467 printf("%s %s\n", k, u);
468 }
469 }
470
471 static void
usage(void)472 usage(void)
473 {
474 fprintf(stderr, "usage: mknetid [-q] [-d domain] [-g groupfile] "
475 "[-h hostfile] [-m netidfile]\n"
476 " [-P master.passwdfile] [-p passwdfile]\n");
477 exit(1);
478 }
479
480 int
main(int argc,char * argv[])481 main(int argc, char *argv[])
482 {
483 FILE *pfile, *gfile, *hfile, *mfile;
484 int qflag = 0, ch;
485 char *domain = NULL;
486
487 while ((ch = getopt(argc, argv, "d:g:h:m:p:P:q")) != -1)
488 switch (ch) {
489 case 'd':
490 domain = optarg;
491 break;
492 case 'g':
493 GroupFile = optarg;
494 break;
495 case 'h':
496 HostFile = optarg;
497 break;
498 case 'm':
499 NetidFile = optarg;
500 break;
501 case 'p':
502 PasswdFile = optarg;
503 break;
504 case 'P':
505 MasterPasswdFile = optarg;
506 break;
507 case 'q':
508 qflag = 1;
509 break;
510 default:
511 usage();
512 break;
513 }
514
515 if (argc > optind)
516 usage();
517
518 if (domain == NULL)
519 yp_get_default_domain(&domain);
520
521 pfile = fopen(PasswdFile, "r");
522 if (pfile == NULL)
523 pfile = fopen(MasterPasswdFile, "r");
524 if (pfile == NULL)
525 err(1, "%s", MasterPasswdFile);
526
527 gfile = fopen(GroupFile, "r");
528 if (gfile == NULL)
529 err(1, "%s", GroupFile);
530
531 hfile = fopen(HostFile, "r");
532 if (hfile == NULL)
533 err(1, "%s", HostFile);
534
535 mfile = fopen(NetidFile, "r");
536
537 read_passwd(pfile, PasswdFile);
538 read_group(gfile, GroupFile);
539
540 print_passwd_group(qflag, domain);
541 print_hosts(hfile, HostFile, domain);
542
543 if (mfile != NULL)
544 print_netid(mfile, NetidFile);
545
546 return 0;
547 }
548