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