mknetid.c revision 1.6 1 /* $NetBSD: mknetid.c,v 1.6 1997/11/01 14:25:00 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.6 1997/11/01 14:25:00 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
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, len, colon;
232 char *p, *k, *u, *g;
233
234 if ((pfile = fopen(fname, "r")) == NULL)
235 err(1, "%s", fname);
236
237 line_no = 0;
238 while ((p = read_line(pfile, &len, &line_no)) != NULL) {
239 if (len == 0) {
240 warnx("%s line %d: empty line", fname, line_no);
241 continue;
242 }
243
244 for (k = p, colon = 0; *k != '\0'; k++)
245 if (*k == ':')
246 colon++;
247
248 if (colon != 6) {
249 warnx("%s line %d: incorrect number of fields",
250 fname, line_no);
251 continue;
252 }
253
254 k = p;
255 p = strchr(p, ':');
256 *p++ = '\0';
257
258 /* If it's a YP entry, skip it. */
259 if (*k == '+' || *k == '-')
260 continue;
261
262 /* terminate password */
263 p = strchr(p, ':');
264 *p++ = '\0';
265
266 /* terminate uid */
267 u = p;
268 p = strchr(p, ':');
269 *p++ = '\0';
270
271 /* terminate gid */
272 g = p;
273 p = strchr(p, ':');
274 *p++ = '\0';
275
276 add_user(k, u, g);
277 }
278 (void)fclose(pfile);
279 }
280
281 int
282 isgsep(ch)
283 char ch;
284 {
285
286 switch (ch) {
287 case ',':
288 case ' ':
289 case '\t':
290 case '\0':
291 return (1);
292 }
293
294 return (0);
295 }
296
297 void
298 read_group(fname)
299 const char *fname;
300 {
301 FILE *gfile;
302 int line_no, len, colon;
303 char *p, *k, *u, *g;
304
305 if ((gfile = fopen(fname, "r")) == NULL)
306 err(1, "%s", fname);
307
308 line_no = 0;
309 while ((p = read_line(gfile, &len, &line_no)) != NULL) {
310 if (len == 0) {
311 warnx("%s line %d: empty line", fname, line_no);
312 continue;
313 }
314
315 for (k = p, colon = 0; *k != '\0'; k++)
316 if (*k == ':')
317 colon++;
318
319 if (colon != 3) {
320 warnx("%s line %d: incorrect number of fields",
321 fname, line_no);
322 continue;
323 }
324
325 /* terminate key */
326 k = p;
327 p = strchr(p, ':');
328 *p++ = '\0';
329
330 if (*k == '+' || *k == '-')
331 continue;
332
333 /* terminate password */
334 p = strchr(p, ':');
335 *p++ = '\0';
336
337 /* terminate gid */
338 g = p;
339 p = strchr(p, ':');
340 *p++ = '\0';
341
342 /* get the group list */
343 for (u = p; *u != '\0'; u = p) {
344 /* find separator */
345 for (; isgsep(*p) == 0; p++)
346 ;
347
348 if (*p != '\0') {
349 *p = '\0';
350 if (u != p)
351 add_group(u, g);
352 p++;
353 } else if (u != p)
354 add_group(u, g);
355 }
356 }
357 (void)fclose(gfile);
358 }
359
360 void
361 print_passwd_group(qflag, domain)
362 int qflag;
363 const char *domain;
364 {
365 struct user *u, *p;
366 int i;
367
368 for (u = root.tqh_first; u != NULL; u = u->read.tqe_next) {
369 for (p = root.tqh_first; p->usr_uid != u->usr_uid;
370 p = p->read.tqe_next)
371 /* empty */ ;
372 if (p != u) {
373 if (!qflag) {
374 warnx("unix.%d@%s %s", u->usr_uid, domain,
375 "multiply defined, ignoring duplicate");
376 }
377 } else {
378 printf("unix.%d@%s %d:%d", u->usr_uid, domain,
379 u->usr_uid, u->usr_gid);
380 if (u->gid_count >= 0)
381 for (i = 0; i <= u->gid_count; i++)
382 printf(",%d", u->gid[i]);
383 printf("\n");
384 }
385 }
386 }
387
388 void
389 print_hosts(fname, domain)
390 const char *fname, *domain;
391 {
392 FILE *hfile;
393 int len;
394 char *p, *k, *u;
395
396 if ((hfile = fopen(fname, "r")) == NULL)
397 err(1, "%s", fname);
398
399 while ((p = read_line(hfile, &len, NULL)) != NULL) {
400 if (len == 0 || *p == '#')
401 continue;
402
403 /* Find the key, replace trailing whitespace will <NUL> */
404 for (k = p; *p && isspace(*p) == 0; p++)
405 ;
406 while (*p && isspace(*p))
407 *p++ = '\0';
408
409 /* Get first hostname. */
410 for (u = p; *p && !isspace(*p); p++)
411 ;
412 *p = '\0';
413
414 printf("unix.%s@%s 0:%s\n", u, domain, u);
415 }
416 (void) fclose(hfile);
417 }
418
419 void
420 print_netid(fname)
421 const char *fname;
422 {
423 FILE *mfile;
424 int len;
425 char *p, *k, *u;
426
427 mfile = fopen(fname, "r");
428 if (mfile == NULL)
429 return;
430
431 while ((p = read_line(mfile, &len, NULL)) != NULL) {
432 if (len == 0 || *p == '#')
433 continue;
434
435 /* Find the key, replace trailing whitespace will <NUL> */
436 for (k = p; *p && !isspace(*p); p++)
437 ;
438 while (*p && isspace(*p))
439 *p++ = '\0';
440
441 /* Get netid entry. */
442 for (u = p; *p && !isspace(*p); p++)
443 ;
444 *p = '\0';
445
446 printf("%s %s\n", k, u);
447 }
448 }
449
450 void
451 usage()
452 {
453
454 fprintf(stderr, "usage: %s %s\n", __progname,
455 "[-d domain] [-q] [-p passwdfile] [-g groupfile]");
456 fprintf(stderr, " %s %s", __progname,
457 "[-g groupfile] [-h hostfile] [-m netidfile]");
458 exit(1);
459 }
460