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