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