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