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