xref: /netbsd-src/usr.sbin/ypserv/mknetid/mknetid.c (revision ace896fac114f559f7469472324fbe68bbe378e5)
1 /*	$NetBSD: mknetid.c,v 1.7 1997/11/13 18:38:26 thorpej Exp $	*/
2 
3 /*
4  * Copyright (c) 1996 Mats O Jansson <moj@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.7 1997/11/13 18:38:26 thorpej Exp $");
37 #endif
38 
39 /*
40  * Originally written by Mats O Jansson <moj@stacken.kth.se>
41  * Simplified a bit by Jason R. Thorpe <thorpej@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 __P((const char *, const char *));
74 void	add_user __P((const char *, const char *, const char *));
75 int	hashidx __P((char));
76 int	isgsep __P((char));
77 int	main __P((int, char *[]));
78 void	print_hosts __P((const char *, const char *));
79 void	print_netid __P((const char *));
80 void	print_passwd_group __P((int, const char *));
81 void	read_group __P((const char *));
82 void	read_passwd __P((const char *));
83 void	usage __P((void));
84 
85 TAILQ_HEAD(user_list, user);
86 struct user_list root;
87 struct user_list hroot[HASHMAX];
88 
89 extern	char *__progname;		/* from crt0.o */
90 
91 int
92 main(argc, argv)
93 	int argc;
94 	char *argv[];
95 {
96 	char *HostFile = _PATH_HOSTS;
97 	char *PasswdFile = _PATH_PASSWD;
98 	char *GroupFile = _PATH_GROUP;
99 	char *NetidFile = "/etc/netid";
100 
101 	int qflag, ch;
102 	char *domain;
103 
104 	TAILQ_INIT(&root);
105 	for (ch = 0; ch < HASHMAX; ch++)
106 		TAILQ_INIT((&hroot[ch]));
107 
108 	qflag = 0;
109 	domain = NULL;
110 
111 	while ((ch = getopt(argc, argv, "d:g:h:m:p:q")) != -1) {
112 		switch (ch) {
113 		case 'd':
114 			domain = optarg;
115 			break;
116 
117 		case 'g':
118 			GroupFile = optarg;
119 			break;
120 
121 		case 'h':
122 			HostFile = optarg;
123 			break;
124 
125 		case 'm':
126 			NetidFile = optarg;
127 			break;
128 
129 		case 'p':
130 			PasswdFile = optarg;
131 			break;
132 
133 		case 'q':
134 			qflag++;
135 			break;
136 
137 		default:
138 			usage();
139 		}
140 	}
141 	if (argc != optind)
142 		usage();
143 
144 	if (domain == NULL)
145 		if (yp_get_default_domain(&domain))
146 			errx(1, "Can't get YP domain name");
147 
148 	read_passwd(PasswdFile);
149 	read_group(GroupFile);
150 
151 	print_passwd_group(qflag, domain);
152 	print_hosts(HostFile, domain);
153 	print_netid(NetidFile);
154 
155 	exit (0);
156 }
157 
158 int
159 hashidx(key)
160 	char key;
161 {
162 	if (key < 'A')
163 		return(0);
164 
165 	if (key <= 'Z')
166 		return(1 + key - 'A');
167 
168 	if (key < 'a')
169 		return(27);
170 
171 	if (key <= 'z')
172 		return(28 + key - 'a');
173 
174 	return(54);
175 }
176 
177 void
178 add_user(username, uid, gid)
179 	const char *username, *uid, *gid;
180 {
181 	struct user *u;
182 	int idx;
183 
184 	idx = hashidx(username[0]);
185 
186 	u = (struct user *)malloc(sizeof(struct user));
187 	if (u == NULL)
188 		err(1, "can't allocate user");
189 	memset(u, 0, sizeof(struct user));
190 
191 	u->usr_name = strdup(username);
192 	if (u->usr_name == NULL)
193 		err(1, "can't allocate user name");
194 
195 	u->usr_uid = atoi(uid);
196 	u->usr_gid = atoi(gid);
197 	u->gid_count = -1;
198 
199 	TAILQ_INSERT_TAIL(&root, u, read);
200 	TAILQ_INSERT_TAIL((&hroot[idx]), u, hash);
201 }
202 
203 void
204 add_group(username, gid)
205 	const char *username, *gid;
206 {
207 	struct user *u;
208 	int g, idx;
209 
210 	g = atoi(gid);
211 	idx = hashidx(username[0]);
212 
213 	for (u = hroot[idx].tqh_first;
214 	    u != NULL; u = u->hash.tqe_next) {
215 		if (strcmp(username, u->usr_name) == 0) {
216 			if (g != u->usr_gid) {
217 				u->gid_count++;
218 				if (u->gid_count < NGROUPS)
219 					u->gid[u->gid_count] = g;
220 			}
221 			return;
222 		}
223 	}
224 }
225 
226 void
227 read_passwd(fname)
228 	const char *fname;
229 {
230 	FILE	*pfile;
231 	int	 line_no, colon;
232 	size_t	 len;
233 	char	*p, *k, *u, *g;
234 
235 	if ((pfile = fopen(fname, "r")) == NULL)
236 		err(1, "%s", fname);
237 
238 	line_no = 0;
239 	while ((p = read_line(pfile, &len, &line_no)) != NULL) {
240 		if (len == 0) {
241 			warnx("%s line %d: empty line", fname, line_no);
242 			continue;
243 		}
244 
245 		for (k = p, colon = 0; *k != '\0'; k++)
246 			if (*k == ':')
247 				colon++;
248 
249 		if (colon != 6) {
250 			warnx("%s line %d: incorrect number of fields",
251 			    fname, line_no);
252 			continue;
253 		}
254 
255 		k = p;
256 		p = strchr(p, ':');
257 		*p++ = '\0';
258 
259 		/* If it's a YP entry, skip it. */
260 		if (*k == '+' || *k == '-')
261 			continue;
262 
263 		/* terminate password */
264 		p = strchr(p, ':');
265 		*p++ = '\0';
266 
267 		/* terminate uid */
268 		u = p;
269 		p = strchr(p, ':');
270 		*p++ = '\0';
271 
272 		/* terminate gid */
273 		g = p;
274 		p = strchr(p, ':');
275 		*p++ = '\0';
276 
277 		add_user(k, u, g);
278 	}
279 	(void)fclose(pfile);
280 }
281 
282 int
283 isgsep(ch)
284 	char ch;
285 {
286 
287 	switch (ch) {
288 	case ',':
289 	case ' ':
290 	case '\t':
291 	case '\0':
292 		return (1);
293 	}
294 
295 	return (0);
296 }
297 
298 void
299 read_group(fname)
300 	const char *fname;
301 {
302 	FILE	*gfile;
303 	int	 line_no, colon;
304 	size_t	 len;
305 	char	*p, *k, *u, *g;
306 
307 	if ((gfile = fopen(fname, "r")) == NULL)
308 		err(1, "%s", fname);
309 
310 	line_no = 0;
311 	while ((p = read_line(gfile, &len, &line_no)) != NULL) {
312 		if (len == 0) {
313 			warnx("%s line %d: empty line", fname, line_no);
314 			continue;
315 		}
316 
317 		for (k = p, colon = 0; *k != '\0'; k++)
318 			if (*k == ':')
319 				colon++;
320 
321 		if (colon != 3) {
322 			warnx("%s line %d: incorrect number of fields",
323 			    fname, 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(qflag, domain)
364 	int qflag;
365 	const char *domain;
366 {
367 	struct user *u, *p;
368 	int i;
369 
370 	for (u = root.tqh_first; u != NULL; u = u->read.tqe_next) {
371 		for (p = root.tqh_first; p->usr_uid != u->usr_uid;
372 		    p = p->read.tqe_next)
373 			/* empty */ ;
374 		if (p != u) {
375 			if (!qflag) {
376 				warnx("unix.%d@%s %s", u->usr_uid, domain,
377 				 "multiply defined, ignoring duplicate");
378 			}
379 		} else {
380 			printf("unix.%d@%s %d:%d", u->usr_uid, domain,
381 			    u->usr_uid, u->usr_gid);
382 			if (u->gid_count >= 0)
383 				for (i = 0; i <= u->gid_count; i++)
384 					printf(",%d", u->gid[i]);
385 			printf("\n");
386 		}
387 	}
388 }
389 
390 void
391 print_hosts(fname, domain)
392 	const char *fname, *domain;
393 {
394 	FILE	*hfile;
395 	size_t	 len;
396 	char	*p, *k, *u;
397 
398 	if ((hfile = fopen(fname, "r")) == NULL)
399 		err(1, "%s", fname);
400 
401 	while ((p = read_line(hfile, &len, NULL)) != NULL) {
402 		if (len == 0 || *p == '#')
403 			continue;
404 
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(fname)
423 	const char *fname;
424 {
425 	FILE	*mfile;
426 	size_t	 len;
427 	char	*p, *k, *u;
428 
429 	mfile = fopen(fname, "r");
430 	if (mfile == NULL)
431 		return;
432 
433 	while ((p = read_line(mfile, &len, NULL)) != NULL) {
434 		if (len == 0 || *p == '#')
435 			continue;
436 
437 		/* Find the key, replace trailing whitespace will <NUL> */
438 		for (k = p; *p && !isspace(*p); p++)
439 			;
440 		while (*p && isspace(*p))
441 			*p++ = '\0';
442 
443 		/* Get netid entry. */
444 		for (u = p; *p && !isspace(*p); p++)
445 			;
446 		*p = '\0';
447 
448 		printf("%s %s\n", k, u);
449 	}
450 }
451 
452 void
453 usage()
454 {
455 
456 	fprintf(stderr, "usage: %s %s\n", __progname,
457 	    "[-d domain] [-q] [-p passwdfile] [-g groupfile]");
458 	fprintf(stderr, "       %s  %s", __progname,
459 	    "[-g groupfile] [-h hostfile] [-m netidfile]");
460 	exit(1);
461 }
462