mknetid.c revision 1.11 1 /* $NetBSD: mknetid.c,v 1.11 2001/02/19 23:22:51 cgd 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.11 2001/02/19 23:22:51 cgd 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 int
91 main(argc, argv)
92 int argc;
93 char *argv[];
94 {
95 char *HostFile = _PATH_HOSTS;
96 char *PasswdFile = _PATH_PASSWD;
97 char *GroupFile = _PATH_GROUP;
98 char *NetidFile = "/etc/netid";
99
100 int qflag, ch;
101 char *domain;
102
103 TAILQ_INIT(&root);
104 for (ch = 0; ch < HASHMAX; ch++)
105 TAILQ_INIT((&hroot[ch]));
106
107 qflag = 0;
108 domain = NULL;
109
110 while ((ch = getopt(argc, argv, "d:g:h:m:p:q")) != -1) {
111 switch (ch) {
112 case 'd':
113 domain = optarg;
114 break;
115
116 case 'g':
117 GroupFile = optarg;
118 break;
119
120 case 'h':
121 HostFile = optarg;
122 break;
123
124 case 'm':
125 NetidFile = optarg;
126 break;
127
128 case 'p':
129 PasswdFile = optarg;
130 break;
131
132 case 'q':
133 qflag++;
134 break;
135
136 default:
137 usage();
138 }
139 }
140 if (argc != optind)
141 usage();
142
143 if (domain == NULL)
144 if (yp_get_default_domain(&domain))
145 errx(1, "Can't get YP domain name");
146
147 read_passwd(PasswdFile);
148 read_group(GroupFile);
149
150 print_passwd_group(qflag, domain);
151 print_hosts(HostFile, domain);
152 print_netid(NetidFile);
153
154 exit (0);
155 }
156
157 int
158 hashidx(key)
159 char key;
160 {
161 if (key < 'A')
162 return(0);
163
164 if (key <= 'Z')
165 return(1 + key - 'A');
166
167 if (key < 'a')
168 return(27);
169
170 if (key <= 'z')
171 return(28 + key - 'a');
172
173 return(54);
174 }
175
176 void
177 add_user(username, uid, gid)
178 const char *username, *uid, *gid;
179 {
180 struct user *u;
181 int idx;
182
183 idx = hashidx(username[0]);
184
185 u = (struct user *)malloc(sizeof(struct user));
186 if (u == NULL)
187 err(1, "can't allocate user");
188 memset(u, 0, sizeof(struct user));
189
190 u->usr_name = strdup(username);
191 if (u->usr_name == NULL)
192 err(1, "can't allocate user name");
193
194 u->usr_uid = atoi(uid);
195 u->usr_gid = atoi(gid);
196 u->gid_count = -1;
197
198 TAILQ_INSERT_TAIL(&root, u, read);
199 TAILQ_INSERT_TAIL((&hroot[idx]), u, hash);
200 }
201
202 void
203 add_group(username, gid)
204 const char *username, *gid;
205 {
206 struct user *u;
207 int g, idx;
208
209 g = atoi(gid);
210 idx = hashidx(username[0]);
211
212 for (u = hroot[idx].tqh_first;
213 u != NULL; u = u->hash.tqe_next) {
214 if (strcmp(username, u->usr_name) == 0) {
215 if (g != u->usr_gid) {
216 u->gid_count++;
217 if (u->gid_count < NGROUPS)
218 u->gid[u->gid_count] = g;
219 }
220 return;
221 }
222 }
223 }
224
225 void
226 read_passwd(fname)
227 const char *fname;
228 {
229 FILE *pfile;
230 size_t line_no;
231 int colon;
232 size_t len;
233 char *line, *p, *k, *u, *g;
234
235 if ((pfile = fopen(fname, "r")) == NULL)
236 err(1, "%s", fname);
237
238 line_no = 0;
239 for (;
240 (line = fparseln(pfile, &len, &line_no, NULL, FPARSELN_UNESCALL));
241 free(line)) {
242 if (len == 0) {
243 warnx("%s line %lu: empty line", fname,
244 (unsigned long)line_no);
245 continue;
246 }
247
248 p = line;
249 for (k = p, colon = 0; *k != '\0'; k++)
250 if (*k == ':')
251 colon++;
252
253 if (colon != 6) {
254 warnx("%s line %lu: incorrect number of fields",
255 fname, (unsigned long)line_no);
256 continue;
257 }
258
259 k = p;
260 p = strchr(p, ':');
261 *p++ = '\0';
262
263 /* If it's a YP entry, skip it. */
264 if (*k == '+' || *k == '-')
265 continue;
266
267 /* terminate password */
268 p = strchr(p, ':');
269 *p++ = '\0';
270
271 /* terminate uid */
272 u = p;
273 p = strchr(p, ':');
274 *p++ = '\0';
275
276 /* terminate gid */
277 g = p;
278 p = strchr(p, ':');
279 *p++ = '\0';
280
281 add_user(k, u, g);
282 }
283 (void)fclose(pfile);
284 }
285
286 int
287 isgsep(ch)
288 char ch;
289 {
290
291 switch (ch) {
292 case ',':
293 case ' ':
294 case '\t':
295 case '\0':
296 return (1);
297 }
298
299 return (0);
300 }
301
302 void
303 read_group(fname)
304 const char *fname;
305 {
306 FILE *gfile;
307 size_t line_no;
308 int colon;
309 size_t len;
310 char *line, *p, *k, *u, *g;
311
312 if ((gfile = fopen(fname, "r")) == NULL)
313 err(1, "%s", fname);
314
315 line_no = 0;
316 for (;
317 (line = fparseln(gfile, &len, &line_no, NULL, FPARSELN_UNESCALL));
318 free(line)) {
319 if (len == 0) {
320 warnx("%s line %lu: empty line", fname,
321 (unsigned long)line_no);
322 continue;
323 }
324
325 p = line;
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 *line, *p, *k, *u;
406
407 if ((hfile = fopen(fname, "r")) == NULL)
408 err(1, "%s", fname);
409
410 for (;
411 (line = fparseln(hfile, &len, NULL, NULL, FPARSELN_UNESCALL));
412 free(line)) {
413 if (len == 0)
414 continue;
415
416 p = line;
417 /* Find the key, replace trailing whitespace will <NUL> */
418 for (k = p; *p && isspace(*p) == 0; p++)
419 ;
420 while (*p && isspace(*p))
421 *p++ = '\0';
422
423 /* Get first hostname. */
424 for (u = p; *p && !isspace(*p); p++)
425 ;
426 *p = '\0';
427
428 printf("unix.%s@%s 0:%s\n", u, domain, u);
429 }
430 (void) fclose(hfile);
431 }
432
433 void
434 print_netid(fname)
435 const char *fname;
436 {
437 FILE *mfile;
438 size_t len;
439 char *line, *p, *k, *u;
440
441 mfile = fopen(fname, "r");
442 if (mfile == NULL)
443 return;
444
445 for (;
446 (line = fparseln(mfile, &len, NULL, NULL, FPARSELN_UNESCALL));
447 free(line)) {
448 if (len == 0)
449 continue;
450
451 p = line;
452 /* Find the key, replace trailing whitespace will <NUL> */
453 for (k = p; *p && !isspace(*p); p++)
454 ;
455 while (*p && isspace(*p))
456 *p++ = '\0';
457
458 /* Get netid entry. */
459 for (u = p; *p && !isspace(*p); p++)
460 ;
461 *p = '\0';
462
463 printf("%s %s\n", k, u);
464 }
465 }
466
467 void
468 usage()
469 {
470
471 fprintf(stderr, "usage: %s %s\n", getprogname(),
472 "[-d domain] [-q] [-p passwdfile] [-g groupfile]");
473 fprintf(stderr, " %s %s", getprogname(),
474 "[-g groupfile] [-h hostfile] [-m netidfile]");
475 exit(1);
476 }
477