xref: /netbsd-src/usr.sbin/ypserv/mknetid/mknetid.c (revision 60ab2ca5c0570c0013b39de285ddaa91fe27d029)
1 /*	$NetBSD: mknetid.c,v 1.17 2009/10/20 00:51:14 snj 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  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
17  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 #ifndef lint
31 __RCSID("$NetBSD: mknetid.c,v 1.17 2009/10/20 00:51:14 snj Exp $");
32 #endif
33 
34 /*
35  * Originally written by Mats O Jansson <moj@stacken.kth.se>
36  * Simplified a bit by Jason R. Thorpe <thorpej@NetBSD.org>
37  */
38 
39 #include <sys/param.h>
40 #include <sys/queue.h>
41 #include <ctype.h>
42 #include <err.h>
43 #include <grp.h>
44 #include <limits.h>
45 #include <netdb.h>
46 #include <pwd.h>
47 #include <stdio.h>
48 #include <string.h>
49 #include <stdlib.h>
50 #include <unistd.h>
51 
52 #include <rpcsvc/ypclnt.h>
53 
54 #include "protos.h"
55 
56 struct user {
57 	char 	*usr_name;		/* user name */
58 	int	usr_uid;		/* user uid */
59 	int	usr_gid;		/* user gid */
60 	int	gid_count;		/* number of gids */
61 	int	gid[NGROUPS];		/* additional gids */
62 	TAILQ_ENTRY(user) read;		/* links in read order */
63 	TAILQ_ENTRY(user) hash;		/* links in hash order */
64 };
65 
66 #define HASHMAX 55
67 
68 void	add_group(const char *, const char *);
69 void	add_user(const char *, const char *, const char *);
70 int	hashidx(char);
71 int	isgsep(char);
72 int	main(int, char *[]);
73 void	print_hosts(const char *, const char *);
74 void	print_netid(const char *);
75 void	print_passwd_group(int, const char *);
76 void	read_group(const char *);
77 void	read_passwd(const char *);
78 void	usage(void);
79 
80 TAILQ_HEAD(user_list, user);
81 struct user_list root;
82 struct user_list hroot[HASHMAX];
83 
84 int
85 main(int argc, char *argv[])
86 {
87 	const char *HostFile = _PATH_HOSTS;
88 	const char *PasswdFile = _PATH_PASSWD;
89 	const char *GroupFile = _PATH_GROUP;
90 	const char *NetidFile = "/etc/netid";
91 
92 	int qflag, ch;
93 	char *domain;
94 
95 	TAILQ_INIT(&root);
96 	for (ch = 0; ch < HASHMAX; ch++)
97 		TAILQ_INIT((&hroot[ch]));
98 
99 	qflag = 0;
100 	domain = NULL;
101 
102 	while ((ch = getopt(argc, argv, "d:g:h:m:p:q")) != -1) {
103 		switch (ch) {
104 		case 'd':
105 			domain = optarg;
106 			break;
107 
108 		case 'g':
109 			GroupFile = optarg;
110 			break;
111 
112 		case 'h':
113 			HostFile = optarg;
114 			break;
115 
116 		case 'm':
117 			NetidFile = optarg;
118 			break;
119 
120 		case 'p':
121 			PasswdFile = optarg;
122 			break;
123 
124 		case 'q':
125 			qflag++;
126 			break;
127 
128 		default:
129 			usage();
130 		}
131 	}
132 	if (argc != optind)
133 		usage();
134 
135 	if (domain == NULL)
136 		if (yp_get_default_domain(&domain))
137 			errx(1, "Can't get YP domain name");
138 
139 	read_passwd(PasswdFile);
140 	read_group(GroupFile);
141 
142 	print_passwd_group(qflag, domain);
143 	print_hosts(HostFile, domain);
144 	print_netid(NetidFile);
145 
146 	exit (0);
147 }
148 
149 int
150 hashidx(char key)
151 {
152 	if (key < 'A')
153 		return(0);
154 
155 	if (key <= 'Z')
156 		return(1 + key - 'A');
157 
158 	if (key < 'a')
159 		return(27);
160 
161 	if (key <= 'z')
162 		return(28 + key - 'a');
163 
164 	return(54);
165 }
166 
167 void
168 add_user(const char *username, const char *uid, const char *gid)
169 {
170 	struct user *u;
171 	int idx;
172 
173 	idx = hashidx(username[0]);
174 
175 	u = (struct user *)malloc(sizeof(struct user));
176 	if (u == NULL)
177 		err(1, "can't allocate user");
178 	memset(u, 0, sizeof(struct user));
179 
180 	u->usr_name = strdup(username);
181 	if (u->usr_name == NULL)
182 		err(1, "can't allocate user name");
183 
184 	u->usr_uid = atoi(uid);
185 	u->usr_gid = atoi(gid);
186 	u->gid_count = -1;
187 
188 	TAILQ_INSERT_TAIL(&root, u, read);
189 	TAILQ_INSERT_TAIL((&hroot[idx]), u, hash);
190 }
191 
192 void
193 add_group(const char *username, const char *gid)
194 {
195 	struct user *u;
196 	int g, idx;
197 
198 	g = atoi(gid);
199 	idx = hashidx(username[0]);
200 
201 	for (u = hroot[idx].tqh_first;
202 	    u != NULL; u = u->hash.tqe_next) {
203 		if (strcmp(username, u->usr_name) == 0) {
204 			if (g != u->usr_gid) {
205 				u->gid_count++;
206 				if (u->gid_count < NGROUPS)
207 					u->gid[u->gid_count] = g;
208 			}
209 			return;
210 		}
211 	}
212 }
213 
214 void
215 read_passwd(const char *fname)
216 {
217 	FILE	*pfile;
218 	size_t	 line_no;
219 	int	 colon;
220 	size_t	 len;
221 	char	*line, *p, *k, *u, *g;
222 
223 	if ((pfile = fopen(fname, "r")) == NULL)
224 		err(1, "%s", fname);
225 
226 	line_no = 0;
227 	for (;
228 	    (line = fparseln(pfile, &len, &line_no, NULL, FPARSELN_UNESCALL));
229 	    free(line)) {
230 		if (len == 0) {
231 			warnx("%s line %lu: empty line", fname,
232 			    (unsigned long)line_no);
233 			continue;
234 		}
235 
236 		p = line;
237 		for (k = p, colon = 0; *k != '\0'; k++)
238 			if (*k == ':')
239 				colon++;
240 
241 		if (colon != 6) {
242 			warnx("%s line %lu: incorrect number of fields",
243 			    fname, (unsigned long)line_no);
244 			continue;
245 		}
246 
247 		k = p;
248 		p = strchr(p, ':');
249 		*p++ = '\0';
250 
251 		/* If it's a YP entry, skip it. */
252 		if (*k == '+' || *k == '-')
253 			continue;
254 
255 		/* terminate password */
256 		p = strchr(p, ':');
257 		*p++ = '\0';
258 
259 		/* terminate uid */
260 		u = p;
261 		p = strchr(p, ':');
262 		*p++ = '\0';
263 
264 		/* terminate gid */
265 		g = p;
266 		p = strchr(p, ':');
267 		*p++ = '\0';
268 
269 		add_user(k, u, g);
270 	}
271 	(void)fclose(pfile);
272 }
273 
274 int
275 isgsep(char ch)
276 {
277 
278 	switch (ch) {
279 	case ',':
280 	case ' ':
281 	case '\t':
282 	case '\0':
283 		return (1);
284 	}
285 
286 	return (0);
287 }
288 
289 void
290 read_group(const char *fname)
291 {
292 	FILE	*gfile;
293 	size_t	 line_no;
294 	int	 colon;
295 	size_t	 len;
296 	char	*line, *p, *k, *u, *g;
297 
298 	if ((gfile = fopen(fname, "r")) == NULL)
299 		err(1, "%s", fname);
300 
301 	line_no = 0;
302 	for (;
303 	    (line = fparseln(gfile, &len, &line_no, NULL, FPARSELN_UNESCALL));
304 	    free(line)) {
305 		if (len == 0) {
306 			warnx("%s line %lu: empty line", fname,
307 			    (unsigned long)line_no);
308 			continue;
309 		}
310 
311 		p = line;
312 		for (k = p, colon = 0; *k != '\0'; k++)
313 			if (*k == ':')
314 				colon++;
315 
316 		if (colon != 3) {
317 			warnx("%s line %lu: incorrect number of fields",
318 			    fname, (unsigned long)line_no);
319 			continue;
320 		}
321 
322 		/* terminate key */
323 		k = p;
324 		p = strchr(p, ':');
325 		*p++ = '\0';
326 
327 		if (*k == '+' || *k == '-')
328 			continue;
329 
330 		/* terminate password */
331 		p = strchr(p, ':');
332 		*p++ = '\0';
333 
334 		/* terminate gid */
335 		g = p;
336 		p = strchr(p, ':');
337 		*p++ = '\0';
338 
339 		/* get the group list */
340 		for (u = p; *u != '\0'; u = p) {
341 			/* find separator */
342 			for (; isgsep(*p) == 0; p++)
343 				;
344 
345 			if (*p != '\0') {
346 				*p = '\0';
347 				if (u != p)
348 					add_group(u, g);
349 				p++;
350 			} else if (u != p)
351 				add_group(u, g);
352 		}
353 	}
354 	(void)fclose(gfile);
355 }
356 
357 void
358 print_passwd_group(int qflag, const char *domain)
359 {
360 	struct user *u, *p;
361 	int i;
362 
363 	for (u = root.tqh_first; u != NULL; u = u->read.tqe_next) {
364 		for (p = root.tqh_first; p->usr_uid != u->usr_uid;
365 		    p = p->read.tqe_next)
366 			/* empty */ ;
367 		if (p != u) {
368 			if (!qflag) {
369 				warnx("unix.%d@%s %s", u->usr_uid, domain,
370 				 "multiply defined, ignoring duplicate");
371 			}
372 		} else {
373 			printf("unix.%d@%s %d:%d", u->usr_uid, domain,
374 			    u->usr_uid, u->usr_gid);
375 			if (u->gid_count >= 0)
376 				for (i = 0; i <= u->gid_count; i++)
377 					printf(",%d", u->gid[i]);
378 			printf("\n");
379 		}
380 	}
381 }
382 
383 void
384 print_hosts(const char *fname, const char *domain)
385 {
386 	FILE	*hfile;
387 	size_t	 len;
388 	char	*line, *p, *k, *u;
389 
390 	if ((hfile = fopen(fname, "r")) == NULL)
391 		err(1, "%s", fname);
392 
393 	for (;
394 	    (line = fparseln(hfile, &len, NULL, NULL, FPARSELN_UNESCALL));
395 	    free(line)) {
396 		if (len == 0)
397 			continue;
398 
399 		p = line;
400 		/* Find the key, replace trailing whitespace will <NUL> */
401 		for (k = p; *p && isspace((unsigned char)*p) == 0; p++)
402 			;
403 		while (*p && isspace((unsigned char)*p))
404 			*p++ = '\0';
405 
406 		/* Get first hostname. */
407 		for (u = p; *p && !isspace((unsigned char)*p); p++)
408 			;
409 		*p = '\0';
410 
411 		printf("unix.%s@%s 0:%s\n", u, domain, u);
412 	}
413 	(void) fclose(hfile);
414 }
415 
416 void
417 print_netid(const char *fname)
418 {
419 	FILE	*mfile;
420 	size_t	 len;
421 	char	*line, *p, *k, *u;
422 
423 	mfile = fopen(fname, "r");
424 	if (mfile == NULL)
425 		return;
426 
427 	for (;
428 	    (line = fparseln(mfile, &len, NULL, NULL, FPARSELN_UNESCALL));
429 	    free(line)) {
430 		if (len == 0)
431 			continue;
432 
433 		p = line;
434 		/* Find the key, replace trailing whitespace will <NUL> */
435 		for (k = p; *p && !isspace((unsigned char)*p); p++)
436 			;
437 		while (*p && isspace((unsigned char)*p))
438 			*p++ = '\0';
439 
440 		/* Get netid entry. */
441 		for (u = p; *p && !isspace((unsigned char)*p); p++)
442 			;
443 		*p = '\0';
444 
445 		printf("%s %s\n", k, u);
446 	}
447 }
448 
449 void
450 usage(void)
451 {
452 
453 	fprintf(stderr, "usage: %s %s\n", getprogname(),
454 	    "[-d domain] [-q] [-p passwdfile] [-g groupfile]");
455 	fprintf(stderr, "       %s  %s", getprogname(),
456 	    "[-g groupfile] [-h hostfile] [-m netidfile]");
457 	exit(1);
458 }
459