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