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