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