1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * Test nfsmapid. This program is not shipped on the binary release.
31  */
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <stropts.h>
35 #include <strings.h>
36 #include <signal.h>
37 #include <fcntl.h>
38 #include <locale.h>
39 #include <unistd.h>
40 #include <netconfig.h>
41 #include <door.h>
42 #include <sys/types.h>
43 #include <sys/utsname.h>
44 #include <sys/param.h>
45 #include <sys/errno.h>
46 #include <sys/cred.h>
47 #include <sys/systm.h>
48 #include <sys/kmem.h>
49 #include <sys/debug.h>
50 #include <rpcsvc/nfs4_prot.h>
51 #include <nfs/nfsid_map.h>
52 
53 static char nobody_str[] = "nobody";
54 static int nfs_idmap_str_uid(utf8string *, uid_t *);
55 static int nfs_idmap_uid_str(uid_t, utf8string *);
56 static int nfs_idmap_str_gid(utf8string *, gid_t *);
57 static int nfs_idmap_gid_str(gid_t, utf8string *);
58 
59 static void
60 usage()
61 {
62 	fprintf(stderr, gettext(
63 		"\nUsage:\tstr2uid string\n"
64 		"\tstr2gid string\n"
65 		"\tuid2str uid\n"
66 		"\tgid2str gid\n"
67 		"\techo string\n"
68 		"\texit|quit\n"));
69 }
70 
71 static int read_line(char *buf, int size)
72 {
73 	int len;
74 
75 	/* read the next line. If cntl-d, return with zero char count */
76 	printf(gettext("\n> "));
77 
78 	if (fgets(buf, size, stdin) == NULL)
79 		return (0);
80 
81 	len = strlen(buf);
82 	buf[--len] = '\0';
83 	return (len);
84 }
85 
86 static int
87 parse_input_line(char *input_line, int *argc, char ***argv)
88 {
89 	const char nil = '\0';
90 	char *chptr;
91 	int chr_cnt;
92 	int arg_cnt = 0;
93 	int ch_was_space = 1;
94 	int ch_is_space;
95 
96 	chr_cnt = strlen(input_line);
97 
98 	/* Count the arguments in the input_line string */
99 
100 	*argc = 1;
101 
102 	for (chptr = &input_line[0]; *chptr != nil; chptr++) {
103 		ch_is_space = isspace(*chptr);
104 		if (ch_is_space && !ch_was_space) {
105 			(*argc)++;
106 		}
107 		ch_was_space = ch_is_space;
108 	}
109 
110 	if (ch_was_space) {
111 		(*argc)--;
112 	}	/* minus trailing spaces */
113 
114 	/* Now that we know how many args calloc the argv array */
115 
116 	*argv = calloc((*argc)+1, sizeof (char *));
117 	chptr = (char *)(&input_line[0]);
118 
119 	for (ch_was_space = 1; *chptr != nil; chptr++) {
120 		ch_is_space = isspace(*chptr);
121 		if (ch_is_space) {
122 			*chptr = nil;	/* replace each space with nil  */
123 		} else if (ch_was_space) {	/* begining of word? */
124 			(*argv)[arg_cnt++] = chptr;	/* new argument ? */
125 		}
126 
127 		ch_was_space = ch_is_space;
128 	}
129 
130 	return (chr_cnt);
131 }
132 
133 char *
134 mapstat(int stat)
135 {
136 	switch (stat) {
137 	case NFSMAPID_OK:
138 		return ("NFSMAPID_OK");
139 	case NFSMAPID_NUMSTR:
140 		return ("NFSMAPID_NUMSTR");
141 	case NFSMAPID_UNMAPPABLE:
142 		return ("NFSMAPID_UNMAPPABLE");
143 	case NFSMAPID_INVALID:
144 		return ("NFSMAPID_INVALID");
145 	case NFSMAPID_INTERNAL:
146 		return ("NFSMAPID_INTERNAL");
147 	case NFSMAPID_BADDOMAIN:
148 		return ("NFSMAPID_BADDOMAIN");
149 	case NFSMAPID_BADID:
150 		return ("NFSMAPID_BADID");
151 	case NFSMAPID_NOTFOUND:
152 		return ("NFSMAPID_NOTFOUND");
153 	case EINVAL:
154 		return ("EINVAL");
155 	case ECOMM:
156 		return ("ECOMM");
157 	case ENOMEM:
158 		return ("ENOMEM");
159 	default:
160 		printf(" unknown error %d ", stat);
161 		return ("...");
162 	}
163 }
164 
165 int
166 do_test(char *input_buf)
167 {
168 	int argc, seal_argc;
169 	char **argv, **argv_array;
170 	char *cmd;
171 	int i, bufsize = 512;
172 	char str_buf[512];
173 	utf8string str;
174 	uid_t uid;
175 	gid_t gid;
176 	int stat;
177 
178 	argv = 0;
179 
180 	if (parse_input_line(input_buf, &argc, &argv) == 0) {
181 		printf(gettext("\n"));
182 		return (1);
183 	}
184 
185 	/*
186 	 * remember argv_array address, which is memory calloc'd by
187 	 * parse_input_line, so it can be free'd at the end of the loop.
188 	 */
189 	argv_array = argv;
190 
191 	if (argc < 1) {
192 		usage();
193 		free(argv_array);
194 		return (0);
195 	}
196 
197 	cmd = argv[0];
198 
199 	if (strcmp(cmd, "str2uid") == 0) {
200 		if (argc < 2) {
201 			usage();
202 			free(argv_array);
203 			return (0);
204 		}
205 		str.utf8string_val = argv[1];
206 		str.utf8string_len = strlen(argv[1]);
207 		stat = nfs_idmap_str_uid(&str, &uid);
208 		printf(gettext("%d stat=%s \n"), uid, mapstat(stat));
209 
210 	} else if (strcmp(cmd, "str2gid") == 0) {
211 		if (argc < 2) {
212 			usage();
213 			free(argv_array);
214 			return (0);
215 		}
216 		str.utf8string_val = argv[1];
217 		str.utf8string_len = strlen(argv[1]);
218 		stat = nfs_idmap_str_gid(&str, &gid);
219 		printf(gettext("%d stat=%s \n"), gid, mapstat(stat));
220 
221 	} else if (strcmp(cmd, "uid2str") == 0) {
222 		if (argc < 2) {
223 			usage();
224 			free(argv_array);
225 			return (0);
226 		}
227 		uid = atoi(argv[1]);
228 		bzero(str_buf, bufsize);
229 		str.utf8string_val = str_buf;
230 		stat = nfs_idmap_uid_str(uid, &str);
231 		printf(gettext("%s stat=%s\n"), str.utf8string_val,
232 					mapstat(stat));
233 
234 	} else if (strcmp(cmd, "gid2str") == 0) {
235 		if (argc < 2) {
236 			usage();
237 			free(argv_array);
238 			return (0);
239 		}
240 		gid = atoi(argv[1]);
241 		bzero(str_buf, bufsize);
242 		str.utf8string_val = str_buf;
243 		stat = nfs_idmap_gid_str(gid, &str);
244 		printf(gettext("%s stat=%s\n"), str.utf8string_val,
245 					mapstat(stat));
246 
247 	} else if (strcmp(cmd, "echo") == 0) {
248 		for (i = 1; i < argc; i++)
249 			printf("%s ", argv[i]);
250 		printf("\n");
251 	} else if (strcmp(cmd, "exit") == 0 ||
252 		    strcmp(cmd, "quit") == 0) {
253 		printf(gettext("\n"));
254 		free(argv_array);
255 		return (1);
256 
257 	} else
258 		usage();
259 
260 	/* free argv array */
261 	free(argv_array);
262 	return (0);
263 }
264 
265 
266 int
267 main(int argc, char **argv)
268 {
269 	char buf[512];
270 	int len, ret;
271 
272 	(void) setlocale(LC_ALL, "");
273 #ifndef TEXT_DOMAIN
274 #define	TEXT_DOMAIN	""
275 #endif
276 	(void) textdomain(TEXT_DOMAIN);
277 
278 	usage();
279 
280 	/*
281 	 * Loop, repeatedly calling parse_input_line() to get the
282 	 * next line and parse it into argc and argv. Act on the
283 	 * arguements found on the line.
284 	 */
285 
286 	do {
287 		len = read_line(buf, 512);
288 		if (len)
289 			ret = do_test(buf);
290 	} while (!ret);
291 
292 	return (0);
293 }
294 
295 #define	NFSMAPID_DOOR	"/var/run/nfsmapid_door"
296 
297 /*
298  * Gen the door handle for connecting to the nfsmapid process.
299  * Keep the door cached.  This call may be made quite often.
300  */
301 int
302 nfs_idmap_doorget()
303 {
304 	static int doorfd = -1;
305 
306 	if (doorfd != -1)
307 		return (doorfd);
308 
309 	if ((doorfd = open(NFSMAPID_DOOR, O_RDWR)) == -1) {
310 		perror(NFSMAPID_DOOR);
311 		exit(1);
312 	}
313 	return (doorfd);
314 }
315 
316 /*
317  * Convert a user utf-8 string identifier into its local uid.
318  */
319 int
320 nfs_idmap_str_uid(utf8string *u8s, uid_t *uid)
321 {
322 	struct mapid_arg *mapargp;
323 	struct mapid_res mapres;
324 	struct mapid_res *mapresp = &mapres;
325 	struct mapid_res *resp = mapresp;
326 	door_arg_t	door_args;
327 	int		doorfd;
328 	int		error = 0;
329 	static int	msg_done = 0;
330 
331 	if (!u8s || !u8s->utf8string_val || !u8s->utf8string_len ||
332 			(u8s->utf8string_val[0] == '\0')) {
333 		error = EINVAL;
334 		goto s2u_done;
335 	}
336 
337 	if (bcmp(u8s->utf8string_val, "nobody", 6) == 0) {
338 		/*
339 		 * If "nobody", just short circuit and bail
340 		 */
341 		*uid = UID_NOBODY;
342 		goto s2u_done;
343 
344 	}
345 
346 	if ((mapargp = malloc(MAPID_ARG_LEN(u8s->utf8string_len))) == NULL) {
347 		(void) fprintf(stderr, "Unable to malloc %d bytes\n",
348 				MAPID_ARG_LEN(u8s->utf8string_len));
349 		error = ENOMEM;
350 		goto s2u_done;
351 	}
352 	mapargp->cmd = NFSMAPID_STR_UID;
353 	mapargp->u_arg.len = u8s->utf8string_len;
354 	(void) bcopy(u8s->utf8string_val, mapargp->str, mapargp->u_arg.len);
355 	mapargp->str[mapargp->u_arg.len] = '\0';
356 
357 	door_args.data_ptr = (char *)mapargp;
358 	door_args.data_size = MAPID_ARG_LEN(mapargp->u_arg.len);
359 	door_args.desc_ptr = NULL;
360 	door_args.desc_num = 0;
361 	door_args.rbuf = (char *)mapresp;
362 	door_args.rsize = sizeof (struct mapid_res);
363 
364 	/*
365 	 * call to the nfsmapid daemon
366 	 */
367 	if ((doorfd = nfs_idmap_doorget()) == -1) {
368 		if (!msg_done) {
369 			fprintf(stderr, "nfs_idmap_str_uid: Can't communicate"
370 				" with mapping daemon nfsmapid\n");
371 			msg_done = 1;
372 		}
373 		error = ECOMM;
374 		free(mapargp);
375 		goto s2u_done;
376 	}
377 
378 	if (door_call(doorfd, &door_args) == -1) {
379 		perror("door_call failed");
380 		error = EINVAL;
381 		free(mapargp);
382 		goto s2u_done;
383 	}
384 
385 	free(mapargp);
386 
387 	resp = (struct mapid_res *)door_args.rbuf;
388 	switch (resp->status) {
389 	case NFSMAPID_OK:
390 		*uid = resp->u_res.uid;
391 		break;
392 
393 	case NFSMAPID_NUMSTR:
394 		*uid = resp->u_res.uid;
395 		error = resp->status;
396 		goto out;
397 
398 	default:
399 	case NFSMAPID_UNMAPPABLE:
400 	case NFSMAPID_INVALID:
401 	case NFSMAPID_INTERNAL:
402 	case NFSMAPID_BADDOMAIN:
403 	case NFSMAPID_BADID:
404 	case NFSMAPID_NOTFOUND:
405 		error = resp->status;
406 		goto s2u_done;
407 	}
408 
409 s2u_done:
410 	if (error)
411 		*uid = UID_NOBODY;
412 out:
413 	if (resp != mapresp)
414 		munmap(door_args.rbuf, door_args.rsize);
415 	return (error);
416 }
417 
418 /*
419  * Convert a uid into its utf-8 string representation.
420  */
421 int
422 nfs_idmap_uid_str(uid_t uid,		/* uid to map */
423 		utf8string *u8s)	/* resulting utf-8 string for uid */
424 {
425 	struct mapid_arg maparg;
426 	struct mapid_res mapres;
427 	struct mapid_res *mapresp = &mapres;
428 	struct mapid_res *resp = mapresp;
429 	door_arg_t	door_args;
430 	int		doorfd;
431 	int		error = 0;
432 	static int	msg_done = 0;
433 
434 	if (uid == UID_NOBODY) {
435 		u8s->utf8string_len = strlen("nobody");
436 		u8s->utf8string_val = nobody_str;
437 		goto u2s_done;
438 	}
439 
440 	/*
441 	 * Daemon call...
442 	 */
443 	maparg.cmd = NFSMAPID_UID_STR;
444 	maparg.u_arg.uid = uid;
445 
446 	door_args.data_ptr = (char *)&maparg;
447 	door_args.data_size = sizeof (struct mapid_arg);
448 	door_args.desc_ptr = NULL;
449 	door_args.desc_num = 0;
450 	door_args.rbuf = (char *)mapresp;
451 	door_args.rsize = sizeof (struct mapid_res);
452 
453 	if ((doorfd = nfs_idmap_doorget()) == -1) {
454 		if (!msg_done) {
455 			fprintf(stderr, "nfs_idmap_uid_str: Can't "
456 				"communicate with mapping daemon nfsmapid\n");
457 			msg_done = 1;
458 		}
459 		error = ECOMM;
460 		goto u2s_done;
461 	}
462 
463 	if (door_call(doorfd, &door_args) == -1) {
464 		perror("door_call failed");
465 		error = EINVAL;
466 		goto u2s_done;
467 	}
468 
469 	resp = (struct mapid_res *)door_args.rbuf;
470 	if (resp->status != NFSMAPID_OK) {
471 		error = resp->status;
472 		goto u2s_done;
473 	}
474 
475 	if (resp->u_res.len != strlen(resp->str)) {
476 		(void) fprintf(stderr, "Incorrect length %d expected %d\n",
477 			resp->u_res.len, strlen(resp->str));
478 		error = NFSMAPID_INVALID;
479 		goto u2s_done;
480 	}
481 	u8s->utf8string_len = resp->u_res.len;
482 	bcopy(resp->str, u8s->utf8string_val, u8s->utf8string_len);
483 
484 u2s_done:
485 	if (resp != mapresp)
486 		munmap(door_args.rbuf, door_args.rsize);
487 	return (error);
488 }
489 
490 /*
491  * Convert a group utf-8 string identifier into its local gid.
492  */
493 int
494 nfs_idmap_str_gid(utf8string *u8s, gid_t *gid)
495 {
496 	struct mapid_arg *mapargp;
497 	struct mapid_res mapres;
498 	struct mapid_res *mapresp = &mapres;
499 	struct mapid_res *resp = mapresp;
500 	door_arg_t	door_args;
501 	int		doorfd;
502 	int		error = 0;
503 	static int	msg_done = 0;
504 
505 	if (!u8s || !u8s->utf8string_val || !u8s->utf8string_len ||
506 		(u8s->utf8string_val[0] == '\0')) {
507 		error = EINVAL;
508 		goto s2g_done;
509 	}
510 
511 	if (bcmp(u8s->utf8string_val, "nobody", 6) == 0) {
512 		/*
513 		 * If "nobody", just short circuit and bail
514 		 */
515 		*gid = GID_NOBODY;
516 		goto s2g_done;
517 
518 	}
519 
520 	if ((mapargp = malloc(MAPID_ARG_LEN(u8s->utf8string_len))) == NULL) {
521 		(void) fprintf(stderr, "Unable to malloc %d bytes\n",
522 				MAPID_ARG_LEN(u8s->utf8string_len));
523 		error = ENOMEM;
524 		goto s2g_done;
525 	}
526 	mapargp->cmd = NFSMAPID_STR_GID;
527 	mapargp->u_arg.len = u8s->utf8string_len;
528 	(void) bcopy(u8s->utf8string_val, mapargp->str, mapargp->u_arg.len);
529 	mapargp->str[mapargp->u_arg.len] = '\0';
530 
531 	door_args.data_ptr = (char *)mapargp;
532 	door_args.data_size = MAPID_ARG_LEN(mapargp->u_arg.len);
533 	door_args.desc_ptr = NULL;
534 	door_args.desc_num = 0;
535 	door_args.rbuf = (char *)mapresp;
536 	door_args.rsize = sizeof (struct mapid_res);
537 
538 	/*
539 	 * call to the nfsmapid daemon
540 	 */
541 	if ((doorfd = nfs_idmap_doorget()) == -1) {
542 		if (!msg_done) {
543 			fprintf(stderr, "nfs_idmap_str_uid: Can't communicate"
544 				" with mapping daemon nfsmapid\n");
545 			msg_done = 1;
546 		}
547 		error = ECOMM;
548 		free(mapargp);
549 		goto s2g_done;
550 	}
551 
552 	if (door_call(doorfd, &door_args) == -1) {
553 		perror("door_call failed");
554 		error = EINVAL;
555 		free(mapargp);
556 		goto s2g_done;
557 	}
558 
559 	free(mapargp);
560 
561 	resp = (struct mapid_res *)door_args.rbuf;
562 	switch (resp->status) {
563 	case NFSMAPID_OK:
564 		*gid = resp->u_res.gid;
565 		break;
566 
567 	case NFSMAPID_NUMSTR:
568 		*gid = resp->u_res.gid;
569 		error = resp->status;
570 		goto out;
571 
572 	default:
573 	case NFSMAPID_UNMAPPABLE:
574 	case NFSMAPID_INVALID:
575 	case NFSMAPID_INTERNAL:
576 	case NFSMAPID_BADDOMAIN:
577 	case NFSMAPID_BADID:
578 	case NFSMAPID_NOTFOUND:
579 		error = resp->status;
580 		goto s2g_done;
581 	}
582 
583 s2g_done:
584 	if (error)
585 		*gid = GID_NOBODY;
586 out:
587 	if (resp != mapresp)
588 		munmap(door_args.rbuf, door_args.rsize);
589 	return (error);
590 }
591 
592 /*
593  * Convert a gid into its utf-8 string representation.
594  */
595 int
596 nfs_idmap_gid_str(gid_t gid,		/* gid to map */
597 		utf8string *g8s)	/* resulting utf-8 string for gid */
598 {
599 	struct mapid_arg maparg;
600 	struct mapid_res mapres;
601 	struct mapid_res *mapresp = &mapres;
602 	struct mapid_res *resp = mapresp;
603 	door_arg_t	door_args;
604 	int		error = 0;
605 	int		doorfd;
606 	static int	msg_done = 0;
607 
608 	if (gid == GID_NOBODY) {
609 		g8s->utf8string_len = strlen("nobody");
610 		g8s->utf8string_val = nobody_str;
611 		goto g2s_done;
612 
613 	}
614 
615 	/*
616 	 * Daemon call...
617 	 */
618 	maparg.cmd = NFSMAPID_GID_STR;
619 	maparg.u_arg.gid = gid;
620 
621 	door_args.data_ptr = (char *)&maparg;
622 	door_args.data_size = sizeof (struct mapid_arg);
623 	door_args.desc_ptr = NULL;
624 	door_args.desc_num = 0;
625 	door_args.rbuf = (char *)mapresp;
626 	door_args.rsize = sizeof (struct mapid_res);
627 
628 	if ((doorfd = nfs_idmap_doorget()) == -1) {
629 		if (!msg_done) {
630 			fprintf(stderr, "nfs_idmap_uid_str: Can't "
631 				"communicate with mapping daemon nfsmapid\n");
632 			msg_done = 1;
633 		}
634 		error = ECOMM;
635 		goto g2s_done;
636 	}
637 
638 	if (door_call(doorfd, &door_args) == -1) {
639 		perror("door_call failed");
640 		error = EINVAL;
641 		goto g2s_done;
642 	}
643 
644 	resp = (struct mapid_res *)door_args.rbuf;
645 	if (resp->status != NFSMAPID_OK) {
646 		error = resp->status;
647 		goto g2s_done;
648 	}
649 
650 	if (resp->u_res.len != strlen(resp->str)) {
651 		(void) fprintf(stderr, "Incorrect length %d expected %d\n",
652 			resp->u_res.len, strlen(resp->str));
653 		error = NFSMAPID_INVALID;
654 		goto g2s_done;
655 	}
656 	g8s->utf8string_len = resp->u_res.len;
657 	bcopy(resp->str, g8s->utf8string_val, g8s->utf8string_len);
658 
659 g2s_done:
660 	if (resp != mapresp)
661 		munmap(door_args.rbuf, door_args.rsize);
662 	return (error);
663 }
664