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