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
usage()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
read_line(char * buf,int size)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
parse_input_line(char * input_line,int * argc,char *** argv)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 *
mapstat(int stat)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
do_test(char * input_buf)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
main(int argc,char ** argv)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
nfs_idmap_doorget()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
nfs_idmap_str_uid(utf8string * u8s,uid_t * uid)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
nfs_idmap_uid_str(uid_t uid,utf8string * u8s)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
nfs_idmap_str_gid(utf8string * u8s,gid_t * gid)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
nfs_idmap_gid_str(gid_t gid,utf8string * g8s)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