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