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