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