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 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 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 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 * 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 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 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 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 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 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 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 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