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 2008 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 #include <stdio.h> 29 #include <stdlib.h> 30 #include <locale.h> 31 #include <strings.h> 32 #include <errno.h> 33 #include <limits.h> 34 #include <sys/varargs.h> 35 #include "idmap_engine.h" 36 #include "idmap_priv.h" 37 #include "idmap_impl.h" 38 39 /* Initialization values for pids/rids: */ 40 41 #define UNDEFINED_UID (uid_t)-1 42 #define UNDEFINED_GID (gid_t)-1 43 #define UNDEFINED_RID (idmap_rid_t)-1; 44 45 #define CHECK_NULL(s) (s != NULL ? s : "null") 46 /* 47 * used in do_show for the type of argument, which can be winname, 48 * unixname, uid, gid, sid or not given at all: 49 */ 50 51 #define TYPE_SID 0x010 /* sid */ 52 #define TYPE_USID 0x011 /* usid */ 53 #define TYPE_GSID 0x012 /* gsid */ 54 #define TYPE_WN 0x110 /* winname */ 55 #define TYPE_WU 0x111 /* winuser */ 56 #define TYPE_WG 0x112 /* wingroup */ 57 #define TYPE_UID 0x001 /* uid */ 58 #define TYPE_GID 0x002 /* gid */ 59 #define TYPE_PID 0x000 /* pid */ 60 #define TYPE_UN 0x100 /* unixname */ 61 #define TYPE_UU 0x101 /* unixuser */ 62 #define TYPE_UG 0x102 /* unixgroup */ 63 64 #define IS_WIN 0x010 /* mask for the windows types */ 65 #define IS_NAME 0x100 /* mask for string name types */ 66 #define IS_USER 0x001 /* mask for user types */ 67 #define IS_GROUP 0x002 /* mask for group types */ 68 69 #define TYPE_INVALID 0x1000 /* Invalid input */ 70 #define TYPE_AUTO 0xaaa /* Autodetection required */ 71 72 /* Identity type strings */ 73 74 #define ID_WINNAME "winname" 75 #define ID_UNIXUSER "unixuser" 76 #define ID_UNIXGROUP "unixgroup" 77 #define ID_WINUSER "winuser" 78 #define ID_WINGROUP "wingroup" 79 #define ID_USID "usid" 80 #define ID_GSID "gsid" 81 #define ID_SID "sid" 82 #define ID_UID "uid" 83 #define ID_GID "gid" 84 85 #define ID_UNKNOWN "unknown" 86 87 #define INHIBITED(str) (str == NULL || *str == 0 || strcmp(str, "\"\"") == 0) 88 89 typedef struct { 90 char *identity; 91 int code; 92 } id_code_t; 93 94 id_code_t identity2code[] = { 95 {ID_WINNAME, TYPE_WN}, 96 {ID_UNIXUSER, TYPE_UU}, 97 {ID_UNIXGROUP, TYPE_UG}, 98 {ID_WINUSER, TYPE_WU}, 99 {ID_WINGROUP, TYPE_WG}, 100 {ID_USID, TYPE_USID}, 101 {ID_GSID, TYPE_GSID}, 102 {ID_SID, TYPE_SID}, 103 {ID_UID, TYPE_UID}, 104 {ID_GID, TYPE_GID} 105 }; 106 107 108 /* Flags */ 109 110 #define f_FLAG 'f' 111 #define t_FLAG 't' 112 #define d_FLAG 'd' 113 #define D_FLAG 'D' 114 #define F_FLAG 'F' 115 #define a_FLAG 'a' 116 #define n_FLAG 'n' 117 #define c_FLAG 'c' 118 #define v_FLAG 'v' 119 #define j_FLAG 'j' 120 121 122 /* used in the function do_import */ 123 #define MAX_INPUT_LINE_SZ 2047 124 125 126 typedef struct { 127 int is_user; 128 int is_wuser; 129 int direction; 130 boolean_t is_nt4; 131 char *unixname; 132 char *winname; 133 char *windomain; 134 char *sidprefix; 135 idmap_rid_t rid; 136 uid_t pid; 137 } name_mapping_t; 138 139 /* 140 * Formats of the output: 141 * 142 * Idmap reads/prints mappings in several formats: ordinary mappings, 143 * name mappings in Samba username map format (smbusers), Netapp 144 * usermap.cfg. 145 * 146 * DEFAULT_FORMAT are in fact the idmap subcommands suitable for 147 * piping to idmap standart input. For example 148 * add -d winuser:bob@foo.com unixuser:fred 149 * add -d winuser:bob2bar.com unixuser:fred 150 * 151 * SMBUSERS is the format of Samba username map (smbusers). For full 152 * documentation, search for "username map" in smb.conf manpage. 153 * The format is for example 154 * fred = bob@foo.com bob2@bar.com 155 * 156 * USERMAP_CFG is the format of Netapp usermap.cfg file. Search 157 * http://www.netapp.com/ for more documentation. IP qualifiers are not 158 * supported. 159 * The format is for example 160 * bob@foo.com => fred 161 * "Bob With Spaces"@bar.com => fred #comment 162 * 163 * The previous formats were for name rules. MAPPING_NAME and 164 * MAPPING_ID are for the actual mappings, as seen in show/dump 165 * commands. MAPPING_NAME prefers the string names of the user over 166 * their numerical identificators. MAPPING_ID prints just the 167 * identificators. 168 * Example of the MAPPING_NAME: 169 * winname:bob@foo.com -> unixname:fred 170 * 171 * Example of the MAPPING_ID: 172 * sid:S-1-2-3-4 -> uid:5678 173 */ 174 175 typedef enum { 176 UNDEFINED_FORMAT = -1, 177 DEFAULT_FORMAT = 0, 178 MAPPING_ID, 179 MAPPING_NAME, 180 USERMAP_CFG, 181 SMBUSERS 182 } format_t; 183 184 185 typedef struct { 186 format_t format; 187 FILE *file; 188 name_mapping_t *last; 189 } print_handle_t; 190 191 /* 192 * idmap_api batch related variables: 193 * 194 * idmap can operate in two modes. It the batch mode, the idmap_api 195 * batch is committed at the end of a batch of several 196 * commands. At the end of input file, typically. This mode is used 197 * for processing input from a file. 198 * In the non-batch mode, each command is committed immediately. This 199 * mode is used for tty input. 200 */ 201 202 /* Are we in the batch mode? */ 203 static int batch_mode = 0; 204 205 /* Self describing stricture for positions */ 206 struct pos_sds { 207 int size; 208 int last; 209 cmd_pos_t *pos[1]; 210 }; 211 212 static struct pos_sds *positions; 213 214 /* Handles for idmap_api batch */ 215 static idmap_handle_t *handle = NULL; 216 static idmap_udt_handle_t *udt = NULL; 217 218 /* Do we need to commit the udt batch at the end? */ 219 static int udt_used; 220 221 /* Command handlers */ 222 223 static int do_show_mapping(flag_t *f, int argc, char **argv, cmd_pos_t *pos); 224 static int do_dump(flag_t *f, int argc, char **argv, cmd_pos_t *pos); 225 static int do_import(flag_t *f, int argc, char **argv, cmd_pos_t *pos); 226 static int do_list_name_mappings(flag_t *f, int argc, char **argv, 227 cmd_pos_t *pos); 228 static int do_add_name_mapping(flag_t *f, int argc, char **argv, 229 cmd_pos_t *pos); 230 static int do_remove_name_mapping(flag_t *f, int argc, char **argv, 231 cmd_pos_t *pos); 232 static int do_exit(flag_t *f, int argc, char **argv, cmd_pos_t *pos); 233 static int do_export(flag_t *f, int argc, char **argv, cmd_pos_t *pos); 234 static int do_help(flag_t *f, int argc, char **argv, cmd_pos_t *pos); 235 static int do_set_namemap(flag_t *f, int argc, char **argv, cmd_pos_t *pos); 236 static int do_unset_namemap(flag_t *f, int argc, char **argv, cmd_pos_t *pos); 237 static int do_get_namemap(flag_t *f, int argc, char **argv, cmd_pos_t *pos); 238 239 /* Command names and their hanlers to be passed to idmap_engine */ 240 241 static cmd_ops_t commands[] = { 242 { 243 "show", 244 "c(create)v(verbose)", 245 do_show_mapping 246 }, 247 { 248 "dump", 249 "n(names)v(verbose)", 250 do_dump 251 }, 252 { 253 "import", 254 "F(flush)f:(file)", 255 do_import 256 }, 257 { 258 "export", 259 "f:(file)", 260 do_export 261 }, 262 { 263 "list", 264 "", 265 do_list_name_mappings 266 }, 267 { 268 "add", 269 "d(directional)", 270 do_add_name_mapping 271 }, 272 { 273 "remove", 274 "a(all)t(to)f(from)d(directional)", 275 do_remove_name_mapping 276 }, 277 { 278 "exit", 279 "", 280 do_exit 281 }, 282 { 283 "help", 284 "", 285 do_help 286 }, 287 { 288 "set-namemap", 289 "a:(authentication)D:(bindDN)j:(passwd-file)", 290 do_set_namemap 291 }, 292 { 293 "get-namemap", 294 "", 295 do_get_namemap 296 }, 297 { 298 "unset-namemap", 299 "a:(authentication)D:(bindDN)j:(passwd-file):", 300 do_unset_namemap 301 } 302 }; 303 304 /* Print error message, possibly with a position */ 305 /* printflike */ 306 static void 307 print_error(cmd_pos_t *pos, const char *format, ...) 308 { 309 size_t length; 310 311 va_list ap; 312 313 va_start(ap, format); 314 315 if (pos != NULL) { 316 length = strlen(pos->line); 317 318 /* Skip newlines etc at the end: */ 319 while (length > 0 && isspace(pos->line[length - 1])) 320 length--; 321 322 (void) fprintf(stderr, 323 gettext("Error at line %d: %.*s\n"), 324 pos->linenum, 325 length, 326 pos->line); 327 } 328 (void) vfprintf(stderr, format, ap); 329 330 va_end(ap); 331 } 332 333 /* Inits positions sds. 0 means everything went OK, -1 for errors */ 334 static int 335 init_positions() 336 { 337 int init_size = 32; /* Initial size of the positions array */ 338 339 positions = (struct pos_sds *) malloc(sizeof (struct pos_sds) + 340 (init_size - 1) * sizeof (cmd_pos_t *)); 341 342 if (positions == NULL) { 343 print_error(NULL, gettext("Not enough memory.\n")); 344 return (-1); 345 } 346 347 positions->size = init_size; 348 positions->last = 0; 349 return (0); 350 } 351 352 /* Free the positions array */ 353 static void 354 fini_positions() 355 { 356 int i; 357 for (i = 0; i < positions->last; i++) { 358 if (positions->pos[i] == NULL) 359 continue; 360 free(positions->pos[i]->line); 361 free(positions->pos[i]); 362 } 363 free(positions); 364 365 positions = NULL; 366 } 367 368 /* 369 * Add another position to the positions array. 0 means everything 370 * went OK, -1 for errors 371 */ 372 static int 373 positions_add(cmd_pos_t *pos) 374 { 375 if (positions->last >= positions->size) { 376 positions->size *= 2; 377 positions = (struct pos_sds *)realloc(positions, 378 sizeof (struct pos_sds) + 379 (positions->size - 1) * sizeof (cmd_pos_t *)); 380 if (positions == NULL) 381 goto nomemory; 382 } 383 384 if (pos == NULL) 385 positions->pos[positions->last] = NULL; 386 else { 387 positions->pos[positions->last] = (cmd_pos_t *)calloc(1, 388 sizeof (cmd_pos_t)); 389 if (positions->pos[positions->last] == NULL) 390 goto nomemory; 391 392 *positions->pos[positions->last] = *pos; 393 positions->pos[positions->last]->line = strdup(pos->line); 394 if (positions->pos[positions->last]->line == NULL) 395 goto nomemory; 396 } 397 398 positions->last++; 399 return (0); 400 401 nomemory: 402 print_error(NULL, gettext("Not enough memory.\n")); 403 return (-1); 404 } 405 406 407 408 409 /* 410 * Compare two strings just like strcmp, but stop before the end of 411 * the s2 412 */ 413 static int 414 strcmp_no0(const char *s1, const char *s2) 415 { 416 return (strncmp(s1, s2, strlen(s2))); 417 } 418 419 /* Print help message */ 420 static void 421 help() 422 { 423 (void) fprintf(stderr, 424 "idmap\n" 425 "idmap -f command-file\n" 426 "idmap add [-d] name1 name2\n" 427 "idmap dump [-n] [-v]\n" 428 "idmap export [-f file] format\n" 429 "idmap get-namemap name\n" 430 "idmap help\n" 431 "idmap import [-F] [-f file] format\n" 432 "idmap list\n" 433 "idmap remove -a\n" 434 "idmap remove [-f|-t] name\n" 435 "idmap remove [-d] name1 name2\n" 436 "idmap set-namemap [-a authenticationMethod] [-D bindDN] " 437 "[-j passwdfile] name1 name2\n" 438 "idmap show [-c] [-v] identity [targettype]\n" 439 "idmap unset-namemap [-a authenticationMethod] [-D bindDN]" 440 "[-j passwdfile] name\n"); 441 } 442 443 /* The handler for the "help" command. */ 444 static int 445 /* LINTED E_FUNC_ARG_UNUSED */ 446 do_help(flag_t *f, int argc, char **argv, cmd_pos_t *pos) 447 { 448 help(); 449 return (0); 450 } 451 452 /* Initialization of the idmap api batch */ 453 static int 454 init_batch() 455 { 456 idmap_stat stat; 457 458 stat = idmap_init(&handle); 459 if (stat != IDMAP_SUCCESS) { 460 print_error(NULL, 461 gettext("Connection not established (%s)\n"), 462 idmap_stat2string(NULL, stat)); 463 return (-1); 464 } 465 466 return (0); 467 } 468 469 /* Initialization common to all commands */ 470 static int 471 init_command() 472 { 473 if (batch_mode) 474 return (0); 475 476 return (init_batch()); 477 } 478 479 /* Finalization common to all commands */ 480 static void 481 fini_command() 482 { 483 if (batch_mode) 484 return; 485 (void) idmap_fini(handle); 486 handle = NULL; 487 } 488 489 /* Initialization of the commands which perform write operations */ 490 static int 491 init_udt_batch() 492 { 493 idmap_stat stat; 494 495 if (init_batch()) 496 return (-1); 497 498 stat = idmap_udt_create(handle, &udt); 499 if (stat != IDMAP_SUCCESS) { 500 print_error(NULL, 501 gettext("Error initiating transaction (%s)"), 502 idmap_stat2string(handle, stat)); 503 return (-1); 504 } 505 506 if (init_positions() < 0) 507 return (-1); 508 509 return (0); 510 } 511 512 513 /* Finalization of the write commands */ 514 static int 515 init_udt_command() 516 { 517 udt_used = 1; 518 if (batch_mode) 519 return (0); 520 521 return (init_udt_batch()); 522 } 523 524 525 /* If everythings is OK, send the udt batch to idmapd */ 526 static int 527 fini_udt_command(int ok, cmd_pos_t *pos) 528 { 529 int rc = 0; 530 int64_t failpos; 531 idmap_stat stat, stat1; 532 cmd_pos_t *reported_pos; 533 534 if (batch_mode) 535 return (0); 536 if (udt == NULL) { 537 print_error(pos, 538 gettext("Internal error: uninitiated batch.\n")); 539 return (-1); 540 } 541 542 if (ok && udt_used) { 543 stat = idmap_udt_commit(udt); 544 if (stat == IDMAP_SUCCESS) 545 goto out; 546 547 rc = -1; 548 549 stat1 = idmap_udt_get_error_index(udt, &failpos); 550 if (stat1 != IDMAP_SUCCESS) { 551 print_error(NULL, 552 gettext("Error diagnosing transaction (%s)\n"), 553 idmap_stat2string(handle, stat1)); 554 goto out; 555 } 556 557 558 if (failpos < 0) 559 reported_pos = pos; 560 else 561 reported_pos = positions->pos[failpos]; 562 563 print_error(reported_pos, 564 gettext("Error commiting transaction (%s)\n"), 565 idmap_stat2string(handle, stat)); 566 } 567 568 out: 569 idmap_udt_destroy(udt); 570 udt = NULL; 571 udt_used = 0; 572 fini_command(); 573 fini_positions(); 574 return (rc); 575 } 576 577 /* Convert numeric expression of the direction to it's string form */ 578 static char * 579 direction2string(int direction) 580 { 581 switch (direction) { 582 case IDMAP_DIRECTION_BI: 583 return ("=="); 584 case IDMAP_DIRECTION_W2U: 585 return ("=>"); 586 case IDMAP_DIRECTION_U2W: 587 return ("<="); 588 default: 589 /* This can never happen: */ 590 print_error(NULL, 591 gettext("Internal error: invalid direction.\n")); 592 return (""); 593 } 594 /* never reached */ 595 } 596 597 /* 598 * Returns 1 if c is a shell-meta-character requiring quoting, 0 599 * otherwise. 600 * 601 * We don't quote '*' and ':' because they cannot do any harm 602 * a) they have no meaning to idmap_engine b) even ifsomebody copy & 603 * paste idmap output to a shell commandline, there is the identity 604 * type string in front of them. On the other hand, '*' and ':' are 605 * everywhere. 606 */ 607 static int 608 is_shell_special(char c) 609 { 610 if (isspace(c)) 611 return (1); 612 613 if (strchr("&^{}#;'\"\\`!$()[]><|~", c) != NULL) 614 return (1); 615 616 return (0); 617 } 618 619 /* 620 * Returns 1 if c is a shell-meta-character requiring quoting even 621 * inside double quotes, 0 otherwise. It means \, " and $ . 622 * 623 * This set of characters is a subset of those in is_shell_special(). 624 */ 625 static int 626 is_dq_special(char c) 627 { 628 if (strchr("\\\"$", c) != NULL) 629 return (1); 630 return (0); 631 } 632 633 634 635 636 /* 637 * Quote any shell meta-characters in the given string. If 'quote' is 638 * true then use double-quotes to quote the whole string, else use 639 * back-slash to quote each individual meta-character. 640 * 641 * The resulting string is placed in *res. Callers must free *res if the 642 * return value isn't 0 (even if the given string had no meta-chars). 643 * If there are any errors this returns -1, else 0. 644 */ 645 static int 646 shell_app(char **res, char *string, int quote) 647 { 648 int i, j; 649 uint_t noss = 0; /* Number Of Shell Special chars in the input */ 650 uint_t noqb = 0; /* Number Of Quotes and Backslahes in the input */ 651 char *out; 652 size_t len_orig = strlen(string); 653 size_t len; 654 655 if (INHIBITED(string)) { 656 out = strdup("\"\""); 657 if (out == NULL) { 658 print_error(NULL, gettext("Not enough memory.\n")); 659 return (-1); 660 } 661 *res = out; 662 return (0); 663 } 664 665 /* First, let us count how many characters we need to quote: */ 666 for (i = 0; i < len_orig; i++) { 667 if (is_shell_special(string[i])) { 668 noss++; 669 if (is_dq_special(string[i])) 670 noqb++; 671 } 672 673 } 674 675 /* Do we need to quote at all? */ 676 if (noss == 0) { 677 out = strdup(string); 678 if (out == NULL) { 679 print_error(NULL, gettext("Not enough memory.\n")); 680 return (-1); 681 } 682 *res = out; 683 return (0); 684 } 685 686 /* What is the length of the result? */ 687 if (quote) 688 len = strlen(string) + 2 + noqb + 1; /* 2 for quotation marks */ 689 else 690 len = strlen(string) + noss + 1; 691 692 out = (char *)malloc(len); 693 if (out == NULL) { 694 print_error(NULL, gettext("Not enough memory.\n")); 695 return (-1); 696 } 697 698 j = 0; 699 if (quote) 700 out[j++] = '"'; 701 702 for (i = 0; i < len_orig; i++) { 703 /* Quote the dangerous chars by a backslash */ 704 if (quote && is_dq_special(string[i]) || 705 (!quote && is_shell_special(string[i]))) { 706 out[j++] = '\\'; 707 } 708 out[j++] = string[i]; 709 } 710 711 if (quote) 712 out[j++] = '"'; 713 714 out[j] = '\0'; 715 *res = out; 716 return (0); 717 } 718 719 /* Assemble string form sid */ 720 static char * 721 sid_format(name_mapping_t *nm) 722 { 723 char *to; 724 size_t len; 725 char *typestring; 726 727 switch (nm->is_wuser) { 728 case IDMAP_YES: 729 typestring = ID_USID; 730 break; 731 case IDMAP_NO: 732 typestring = ID_GSID; 733 break; 734 default: 735 typestring = ID_SID; 736 break; 737 } 738 739 /* 'usid:' + sidprefix + '-' + rid + '\0' */ 740 len = strlen(nm->sidprefix) + 7 + 3 * sizeof (nm->rid); 741 to = (char *)malloc(len); 742 if (to == NULL) 743 return (NULL); 744 745 (void) snprintf(to, len, "%s:%s-%u", typestring, nm->sidprefix, 746 nm->rid); 747 return (to); 748 } 749 750 /* Assemble string form uid or gid */ 751 static char * 752 pid_format(uid_t from, int is_user) 753 { 754 char *to; 755 size_t len; 756 757 /* ID_UID ":" + uid + '\0' */ 758 len = 5 + 3 * sizeof (uid_t); 759 to = (char *)malloc(len); 760 if (to == NULL) 761 return (NULL); 762 763 (void) snprintf(to, len, "%s:%u", is_user ? ID_UID : ID_GID, from); 764 return (to); 765 } 766 767 /* Assemble winname, e.g. "winuser:bob@foo.sun.com", from name_mapping_t */ 768 static int 769 nm2winqn(name_mapping_t *nm, char **winqn) 770 { 771 char *out; 772 size_t length = 0; 773 int is_domain = 1; 774 char *prefix; 775 776 /* Sometimes there are no text names. Return a sid, then. */ 777 if (nm->winname == NULL && nm->sidprefix != NULL) { 778 *winqn = sid_format(nm); 779 return (0); 780 } 781 782 switch (nm->is_wuser) { 783 case IDMAP_YES: 784 prefix = ID_WINUSER ":"; 785 break; 786 case IDMAP_NO: 787 prefix = ID_WINGROUP ":"; 788 break; 789 case IDMAP_UNKNOWN: 790 prefix = ID_WINNAME ":"; 791 break; 792 793 } 794 795 length = strlen(prefix); 796 797 if (nm->winname != NULL) 798 length += strlen(nm->winname); 799 800 /* Windomain is not mandatory: */ 801 if (nm->windomain == NULL || INHIBITED(nm->winname)) 802 is_domain = 0; 803 else 804 length += strlen(nm->windomain) + 1; 805 806 out = (char *)malloc(length + 1); 807 if (out == NULL) { 808 print_error(NULL, 809 gettext("Not enough memory.\n")); 810 return (-1); 811 } 812 813 (void) strcpy(out, prefix); 814 815 /* LINTED E_NOP_IF_STMT */ 816 if (nm->winname == NULL) 817 ; 818 else if (!is_domain) 819 (void) strcat(out, nm->winname); 820 else if (nm->is_nt4) { 821 (void) strcat(out, nm->windomain); 822 (void) strcat(out, "\\"); 823 (void) strcat(out, nm->winname); 824 } else { 825 (void) strcat(out, nm->winname); 826 (void) strcat(out, "@"); 827 (void) strcat(out, nm->windomain); 828 } 829 830 *winqn = out; 831 return (0); 832 } 833 834 /* 835 * Assemble a text unixname, e.g. unixuser:fred. Use only for 836 * mapping, not namerules - there an empty name means inhibited 837 * mappings, while here pid is printed if there is no name. 838 */ 839 static 840 int 841 nm2unixname(name_mapping_t *nm, char **unixname) 842 { 843 size_t length = 0; 844 char *out, *it, *prefix; 845 846 /* Sometimes there is no name, just pid: */ 847 if (nm->unixname == NULL) { 848 if (nm->pid == UNDEFINED_UID) 849 return (-1); 850 851 *unixname = pid_format(nm->pid, nm->is_user); 852 return (0); 853 } 854 855 if (shell_app(&it, nm->unixname, 0)) 856 return (-1); 857 858 859 switch (nm->is_user) { 860 case IDMAP_YES: 861 prefix = ID_UNIXUSER ":"; 862 break; 863 case IDMAP_NO: 864 prefix = ID_UNIXGROUP ":"; 865 break; 866 case IDMAP_UNKNOWN: 867 prefix = ID_UNIXUSER ":"; 868 break; 869 870 } 871 872 length = strlen(prefix) + strlen(it); 873 874 out = (char *)malloc(length + 1); 875 if (out == NULL) { 876 print_error(NULL, 877 gettext("Not enough memory.\n")); 878 free(it); 879 return (-1); 880 } 881 882 (void) strcpy(out, prefix); 883 (void) strcat(out, it); 884 free(it); 885 886 *unixname = out; 887 return (0); 888 } 889 890 /* Allocate a new name_mapping_t and initialize the values. */ 891 static name_mapping_t * 892 name_mapping_init() 893 { 894 name_mapping_t *nm = (name_mapping_t *)malloc(sizeof (name_mapping_t)); 895 if (nm == NULL) { 896 print_error(NULL, gettext("Not enough memory.\n")); 897 return (NULL); 898 } 899 nm->winname = nm->windomain = nm->unixname = nm->sidprefix = NULL; 900 nm->rid = UNDEFINED_RID; 901 nm->is_nt4 = B_FALSE; 902 nm->is_user = IDMAP_UNKNOWN; 903 nm->is_wuser = IDMAP_UNKNOWN; 904 nm->direction = IDMAP_DIRECTION_UNDEF; 905 nm->pid = UNDEFINED_UID; 906 return (nm); 907 } 908 909 /* Free name_mapping_t */ 910 static void 911 name_mapping_fini(name_mapping_t *nm) 912 { 913 914 free(nm->winname); 915 free(nm->windomain); 916 free(nm->unixname); 917 free(nm->sidprefix); 918 919 free(nm); 920 } 921 922 static int 923 name_mapping_cpy(name_mapping_t *to, name_mapping_t *from) 924 { 925 free(to->winname); 926 free(to->windomain); 927 free(to->unixname); 928 free(to->sidprefix); 929 930 (void) memcpy(to, from, sizeof (name_mapping_t)); 931 to->winname = to->windomain = to->unixname = to->sidprefix = NULL; 932 933 if (from->winname != NULL) { 934 to->winname = strdup(from->winname); 935 if (to->winname == NULL) { 936 print_error(NULL, gettext("Not enough memory.\n")); 937 return (-1); 938 } 939 } 940 941 if (from->windomain != NULL) { 942 to->windomain = strdup(from->windomain); 943 if (to->windomain == NULL) { 944 print_error(NULL, gettext("Not enough memory.\n")); 945 return (-1); 946 } 947 } 948 949 if (from->unixname != NULL) { 950 to->unixname = strdup(from->unixname); 951 if (to->unixname == NULL) { 952 print_error(NULL, gettext("Not enough memory.\n")); 953 return (-1); 954 } 955 } 956 957 if (from->sidprefix != NULL) { 958 to->sidprefix = strdup(from->sidprefix); 959 if (to->sidprefix == NULL) { 960 print_error(NULL, gettext("Not enough memory.\n")); 961 return (-1); 962 } 963 } 964 965 return (0); 966 } 967 968 static int 969 name_mapping_format(name_mapping_t *nm, char **out) 970 { 971 char *winname = NULL; 972 char *winname1 = NULL; 973 char *unixname = NULL; 974 int maxlen; 975 976 *out = NULL; 977 978 if (nm2winqn(nm, &winname1) < 0) 979 return (-1); 980 981 if (shell_app(&winname, winname1, 1)) { 982 free(winname1); 983 return (-1); 984 } 985 986 free(winname1); 987 988 if (nm2unixname(nm, &unixname)) { 989 free(winname); 990 return (-1); 991 } 992 993 /* 10 is strlen("add -d\t\t\n") + 1 */ 994 maxlen = 10 + strlen(unixname) + strlen(winname); 995 996 *out = (char *)malloc(maxlen); 997 998 if (nm->direction == IDMAP_DIRECTION_U2W) { 999 (void) snprintf(*out, maxlen, "add -d\t%s\t%s\n", 1000 unixname, winname); 1001 } else { 1002 (void) snprintf(*out, maxlen, "add %s\t%s\t%s\n", 1003 nm->direction == IDMAP_DIRECTION_BI? "" : "-d", 1004 winname, unixname); 1005 } 1006 free(winname); 1007 free(unixname); 1008 return (0); 1009 } 1010 1011 /* Initialize print_mapping variables. Must be called before print_mapping */ 1012 static print_handle_t * 1013 print_mapping_init(format_t f, FILE *fi) 1014 { 1015 print_handle_t *out; 1016 1017 out = (print_handle_t *)malloc(sizeof (print_handle_t)); 1018 if (out == NULL) { 1019 print_error(NULL, gettext("Not enough memory.\n")); 1020 return (NULL); 1021 } 1022 1023 out->format = f; 1024 out->file = fi; 1025 out->last = name_mapping_init(); 1026 1027 if (out->last == NULL) 1028 return (NULL); 1029 1030 return (out); 1031 } 1032 1033 /* Finalize print_mapping. */ 1034 static int 1035 print_mapping_fini(print_handle_t *pnm) 1036 { 1037 char *out = NULL; 1038 int rc = 0; 1039 1040 switch (pnm->format) { 1041 case SMBUSERS: 1042 if (pnm->last->unixname != NULL) { 1043 (void) fprintf(pnm->file, "\n"); 1044 } 1045 break; 1046 case DEFAULT_FORMAT: 1047 if (pnm->last->unixname == NULL) 1048 break; 1049 rc = name_mapping_format(pnm->last, &out); 1050 if (rc >= 0) { 1051 (void) fprintf(pnm->file, "%s", out); 1052 free(out); 1053 } 1054 break; 1055 default: 1056 ; 1057 } 1058 1059 name_mapping_fini(pnm->last); 1060 free(pnm); 1061 1062 return (rc); 1063 } 1064 1065 static char * 1066 usermap_cfg_string(char *in) 1067 { 1068 int len; 1069 char *out; 1070 1071 if (INHIBITED(in)) 1072 return (strdup("\"\"")); 1073 1074 len = strlen(in); 1075 if (len == strcspn(in, " \t#")) 1076 return (strdup(in)); 1077 1078 out = malloc(len + 3); 1079 if (out == NULL) 1080 return (NULL); 1081 1082 (void) snprintf(out, len + 3, "\"%s\"", in); 1083 return (out); 1084 } 1085 1086 /* 1087 * Compare two possibly NULL strings 1088 */ 1089 static int 1090 strcmp_null(char *a, char *b) 1091 { 1092 if (a == NULL && b == NULL) 1093 return (0); 1094 if (a == NULL) 1095 return (-1); 1096 if (b == NULL) 1097 return (1); 1098 return (strcmp(a, b)); 1099 } 1100 1101 /* 1102 * This prints both name rules and ordinary mappings, based on the pnm_format 1103 * set in print_mapping_init(). 1104 */ 1105 1106 static int 1107 print_mapping(print_handle_t *pnm, name_mapping_t *nm) 1108 { 1109 char *dirstring; 1110 char *winname = NULL; 1111 char *windomain = NULL; 1112 char *unixname = NULL; 1113 FILE *f = pnm->file; 1114 1115 switch (pnm->format) { 1116 case MAPPING_NAME: 1117 if (nm2winqn(nm, &winname) < 0) 1118 return (-1); 1119 if (nm2unixname(nm, &unixname) < 0) { 1120 free(winname); 1121 return (-1); 1122 } 1123 /* LINTED E_CASE_FALLTHRU */ 1124 case MAPPING_ID: 1125 if (pnm->format == MAPPING_ID) { 1126 if (nm->sidprefix == NULL) { 1127 print_error(NULL, 1128 gettext("SID not given.\n")); 1129 return (-1); 1130 } 1131 winname = sid_format(nm); 1132 if (winname == NULL) 1133 return (-1); 1134 unixname = pid_format(nm->pid, nm->is_user); 1135 if (unixname == NULL) { 1136 free(winname); 1137 return (-1); 1138 } 1139 } 1140 1141 dirstring = direction2string(nm->direction); 1142 1143 (void) fprintf(f, "%s\t%s\t%s\n", winname, dirstring, 1144 unixname); 1145 1146 break; 1147 case SMBUSERS: 1148 if (nm->is_user != IDMAP_YES || nm->is_wuser != IDMAP_YES) { 1149 print_error(NULL, 1150 gettext("Group rule: ")); 1151 f = stderr; 1152 } else if (nm->direction == IDMAP_DIRECTION_U2W) { 1153 print_error(NULL, 1154 gettext("Opposite direction of the mapping: ")); 1155 f = stderr; 1156 } else if (INHIBITED(nm->winname) || INHIBITED(nm->unixname)) { 1157 print_error(NULL, gettext("Inhibited rule: ")); 1158 f = stderr; 1159 } 1160 1161 if (shell_app(&winname, nm->winname, 1)) 1162 return (-1); 1163 1164 unixname = INHIBITED(nm->unixname) ? "\"\"" : nm->unixname; 1165 1166 if (pnm->file != f) { 1167 (void) fprintf(f, "%s=%s\n", unixname, winname); 1168 } else if (pnm->last->unixname != NULL && 1169 strcmp(pnm->last->unixname, unixname) == 0) { 1170 (void) fprintf(f, " %s", winname); 1171 } else { 1172 if (pnm->last->unixname != NULL) { 1173 (void) fprintf(f, "\n"); 1174 free(pnm->last->unixname); 1175 } 1176 pnm->last->unixname = strdup(unixname); 1177 if (pnm->last->unixname == NULL) { 1178 print_error(NULL, 1179 gettext("Not enough memory.\n")); 1180 } 1181 1182 (void) fprintf(f, "%s=%s", unixname, winname); 1183 } 1184 1185 unixname = NULL; 1186 break; 1187 case USERMAP_CFG: 1188 if (nm->is_user != IDMAP_YES || nm->is_wuser != IDMAP_YES) { 1189 print_error(NULL, 1190 gettext("Group rule: ")); 1191 f = stderr; 1192 } 1193 1194 dirstring = direction2string(nm->direction); 1195 1196 if ((winname = usermap_cfg_string(nm->winname)) == NULL || 1197 (unixname = usermap_cfg_string(nm->unixname)) == NULL || 1198 (windomain = usermap_cfg_string(nm->windomain)) == NULL) { 1199 print_error(NULL, gettext("Not enough memory.\n")); 1200 free(winname); 1201 free(unixname); 1202 free(windomain); 1203 return (-1); 1204 } 1205 1206 1207 if (nm->windomain == NULL) { 1208 (void) fprintf(f, "%s\t%s\t%s\n", 1209 winname, dirstring, unixname); 1210 } else 1211 (void) fprintf(f, nm->is_nt4 ? 1212 "%s\\%s\t%s\t%s\n" : 1213 "%2$s@%1$s\t%3$s\t%4$s\n", 1214 windomain, winname, dirstring, unixname); 1215 1216 break; 1217 1218 /* This is a format for namerules */ 1219 case DEFAULT_FORMAT: 1220 /* 1221 * If nm is the same as the last one except is_wuser, we combine 1222 * winuser & wingroup to winname 1223 */ 1224 if (nm->direction == pnm->last->direction && 1225 nm->is_user == pnm->last->is_user && 1226 1227 strcmp_null(pnm->last->unixname, nm->unixname) == 0 && 1228 strcmp_null(pnm->last->winname, nm->winname) == 0 && 1229 strcmp_null(pnm->last->windomain, nm->windomain) == 0) { 1230 pnm->last->is_wuser = IDMAP_UNKNOWN; 1231 } else { 1232 if (pnm->last->unixname != NULL || 1233 pnm->last->winname != NULL) { 1234 char *out = NULL; 1235 if (name_mapping_format(pnm->last, &out) < 0) 1236 return (-1); 1237 (void) fprintf(f, "%s", out); 1238 free(out); 1239 } 1240 if (name_mapping_cpy(pnm->last, nm) < 0) 1241 return (-1); 1242 } 1243 break; 1244 default: 1245 /* This can never happen: */ 1246 print_error(NULL, 1247 gettext("Internal error: invalid print format.\n")); 1248 return (-1); 1249 } 1250 1251 free(winname); 1252 free(unixname); 1253 free(windomain); 1254 return (0); 1255 } 1256 1257 1258 static 1259 void 1260 print_how(idmap_how *how) 1261 { 1262 idmap_namerule *rule; 1263 name_mapping_t nm; 1264 char *rule_text; 1265 1266 switch (how->map_type) { 1267 case IDMAP_MAP_TYPE_DS_AD: 1268 (void) printf(gettext("Method:\tAD Directory\n")); 1269 (void) printf(gettext("DN:\t%s\n"), 1270 CHECK_NULL(how->idmap_how_u.ad.dn)); 1271 (void) printf(gettext("Attribute:\t%s=%s\n"), 1272 CHECK_NULL(how->idmap_how_u.ad.attr), 1273 CHECK_NULL(how->idmap_how_u.ad.value)); 1274 break; 1275 1276 case IDMAP_MAP_TYPE_DS_NLDAP: 1277 (void) printf(gettext("Method:\tNative LDAP Directory\n")); 1278 (void) printf(gettext("DN:\t%s\n"), 1279 CHECK_NULL(how->idmap_how_u.nldap.dn)); 1280 (void) printf(gettext("Attribute:\t%s=%s\n"), 1281 CHECK_NULL(how->idmap_how_u.nldap.attr), 1282 CHECK_NULL(how->idmap_how_u.nldap.value)); 1283 break; 1284 1285 case IDMAP_MAP_TYPE_RULE_BASED: 1286 (void) printf(gettext("Method:\tName Rule\n")); 1287 rule = &how->idmap_how_u.rule; 1288 /* 1289 * The name rules as specified by the user can have a 1290 * "winname", "winuser" or "wingroup". "Winname" rules are 1291 * decomposed to a "winuser" and "wingroup" rules by idmap. 1292 * Currently is_wuser is a boolean. Due to these reasons 1293 * the returned is_wuser does not represent the original rule. 1294 * It is therefore better set is_wuser to unknown. 1295 */ 1296 nm.is_user = rule->is_user; 1297 nm.is_wuser = IDMAP_UNKNOWN; 1298 nm.direction = rule->direction; 1299 nm.winname = rule->winname; 1300 nm.windomain = rule->windomain; 1301 nm.unixname = rule->unixname; 1302 nm.is_nt4 = rule->is_nt4; 1303 if (name_mapping_format(&nm, &rule_text) == 0) { 1304 (void) printf(gettext("Rule:\t%s"), rule_text); 1305 free(rule_text); 1306 } 1307 break; 1308 1309 case IDMAP_MAP_TYPE_EPHEMERAL: 1310 (void) printf(gettext("Method:\tEphemeral\n")); 1311 break; 1312 1313 case IDMAP_MAP_TYPE_LOCAL_SID: 1314 (void) printf(gettext("Method:\tLocal SID\n")); 1315 break; 1316 1317 case IDMAP_MAP_TYPE_KNOWN_SID: 1318 (void) printf(gettext("Method:\tWell-Known mapping\n")); 1319 break; 1320 } 1321 } 1322 1323 1324 1325 1326 1327 static 1328 void 1329 print_info(idmap_info *info) 1330 { 1331 if (info->how.map_type != IDMAP_MAP_TYPE_UNKNOWN) { 1332 switch (info->src) { 1333 case IDMAP_MAP_SRC_NEW: 1334 (void) printf(gettext("Source:\tNew\n")); 1335 break; 1336 1337 case IDMAP_MAP_SRC_CACHE: 1338 (void) printf(gettext("Source:\tCache\n")); 1339 break; 1340 1341 case IDMAP_MAP_SRC_HARD_CODED: 1342 (void) printf(gettext("Source:\tHard Coded\n")); 1343 break; 1344 1345 case IDMAP_MAP_SRC_ALGORITHMIC: 1346 (void) printf(gettext("Source:\tAlgorithmic\n")); 1347 break; 1348 } 1349 print_how(&info->how); 1350 } 1351 } 1352 1353 1354 static 1355 void 1356 print_error_info(idmap_info *info) 1357 { 1358 idmap_how *how = &info->how; 1359 idmap_namerule *rule; 1360 name_mapping_t nm; 1361 char *rule_text; 1362 1363 switch (how->map_type) { 1364 case IDMAP_MAP_TYPE_DS_AD: 1365 (void) fprintf(stderr, 1366 gettext("Failed Method:\tAD Directory\n")); 1367 (void) fprintf(stderr, gettext("DN:\t%s\n"), 1368 how->idmap_how_u.ad.dn); 1369 (void) fprintf(stderr, gettext("Attribute:\t%s=%s\n"), 1370 how->idmap_how_u.ad.attr, 1371 how->idmap_how_u.ad.value); 1372 break; 1373 1374 case IDMAP_MAP_TYPE_DS_NLDAP: 1375 (void) fprintf(stderr, 1376 gettext("Failed Method:\tNative LDAP Directory\n")); 1377 (void) fprintf(stderr, gettext("DN:\t%s\n"), 1378 how->idmap_how_u.nldap.dn); 1379 (void) fprintf(stderr, gettext("Attribute:\t%s=%s\n"), 1380 how->idmap_how_u.nldap.attr, 1381 how->idmap_how_u.nldap.value); 1382 break; 1383 1384 case IDMAP_MAP_TYPE_RULE_BASED: 1385 (void) fprintf(stderr, gettext("Failed Method:\tName Rule\n")); 1386 rule = &how->idmap_how_u.rule; 1387 /* 1388 * The name rules as specified by the user can have a 1389 * "winname", "winuser" or "wingroup". "Winname" rules are 1390 * decomposed to a "winuser" and "wingroup" rules by idmap. 1391 * Currently is_wuser is a boolean. Due to these reasons 1392 * the returned is_wuser does not represent the original rule. 1393 * It is therefore better to set is_wuser to unknown. 1394 */ 1395 nm.is_user = rule->is_user; 1396 nm.is_wuser = IDMAP_UNKNOWN; 1397 nm.direction = rule->direction; 1398 nm.winname = rule->winname; 1399 nm.windomain = rule->windomain; 1400 nm.unixname = rule->unixname; 1401 nm.is_nt4 = rule->is_nt4; 1402 if (name_mapping_format(&nm, &rule_text) == 0) { 1403 (void) fprintf(stderr, gettext("Rule:\t%s"), rule_text); 1404 free(rule_text); 1405 } 1406 break; 1407 1408 case IDMAP_MAP_TYPE_EPHEMERAL: 1409 (void) fprintf(stderr, gettext("Failed Method:\tEphemeral\n")); 1410 break; 1411 1412 case IDMAP_MAP_TYPE_LOCAL_SID: 1413 (void) fprintf(stderr, gettext("Failed Method:\tLocal SID\n")); 1414 break; 1415 1416 case IDMAP_MAP_TYPE_KNOWN_SID: 1417 (void) fprintf(stderr, 1418 gettext("Failed Method:\tWell-Known mapping\n")); 1419 break; 1420 } 1421 } 1422 1423 1424 1425 /* dump command handler */ 1426 static int 1427 /* LINTED E_FUNC_ARG_UNUSED */ 1428 do_dump(flag_t *f, int argc, char **argv, cmd_pos_t *pos) 1429 { 1430 idmap_stat stat; 1431 idmap_iter_t *ihandle; 1432 int rc = 0; 1433 boolean_t is_user; 1434 boolean_t is_wuser; 1435 print_handle_t *ph; 1436 int flag = 0; 1437 idmap_info info; 1438 1439 if (init_command()) 1440 return (-1); 1441 1442 ph = print_mapping_init(f[n_FLAG] != NULL ? MAPPING_NAME : MAPPING_ID, 1443 stdout); 1444 if (ph == NULL) 1445 return (-1); 1446 1447 if (f[v_FLAG] != NULL) 1448 flag = IDMAP_REQ_FLG_MAPPING_INFO; 1449 1450 stat = idmap_iter_mappings(handle, &ihandle, flag); 1451 if (stat < 0) { 1452 print_error(pos, 1453 gettext("Iteration handle not obtained (%s)\n"), 1454 idmap_stat2string(handle, stat)); 1455 rc = -1; 1456 goto cleanup; 1457 } 1458 1459 do { 1460 name_mapping_t *nm = name_mapping_init(); 1461 if (nm == NULL) { 1462 rc = -1; 1463 goto cleanup; 1464 } 1465 1466 stat = idmap_iter_next_mapping(ihandle, 1467 &nm->sidprefix, &nm->rid, &nm->pid, 1468 &nm->winname, &nm->windomain, 1469 &nm->unixname, &is_user, &is_wuser, 1470 &nm->direction, &info); 1471 1472 nm->is_user = is_user ? IDMAP_YES : IDMAP_NO; 1473 nm->is_wuser = is_wuser ? IDMAP_YES : IDMAP_NO; 1474 1475 if (stat >= 0) { 1476 (void) print_mapping(ph, nm); 1477 (void) print_how(&info.how); 1478 idmap_info_free(&info); 1479 } 1480 name_mapping_fini(nm); 1481 1482 } while (stat > 0); 1483 1484 /* IDMAP_ERR_NOTFOUND indicates end of the list */ 1485 if (stat < 0 && stat != IDMAP_ERR_NOTFOUND) { 1486 print_error(pos, 1487 gettext("Error during iteration (%s)\n"), 1488 idmap_stat2string(handle, stat)); 1489 rc = -1; 1490 goto cleanup; 1491 } 1492 1493 idmap_iter_destroy(ihandle); 1494 1495 cleanup: 1496 (void) print_mapping_fini(ph); 1497 fini_command(); 1498 return (rc); 1499 } 1500 1501 /* 1502 * The same as strdup, but length chars is duplicated, no matter on 1503 * '\0'. The caller must guarantee "length" chars in "from". 1504 */ 1505 static char * 1506 strndup(char *from, size_t length) 1507 { 1508 char *out = (char *)malloc(length + 1); 1509 if (out == NULL) { 1510 print_error(NULL, gettext("Not enough memory\n")); 1511 return (NULL); 1512 } 1513 (void) strncpy(out, from, length); 1514 out[length] = '\0'; 1515 return (out); 1516 } 1517 1518 /* 1519 * Convert pid from string to it's numerical representation. If it is 1520 * a valid string, i.e. number of a proper length, return 1. Otherwise 1521 * print an error message and return 0. 1522 */ 1523 static int 1524 pid_convert(char *string, uid_t *number, int type, cmd_pos_t *pos) 1525 { 1526 int i; 1527 long long ll; 1528 char *type_string; 1529 size_t len = strlen(string); 1530 1531 if (type == TYPE_GID) 1532 type_string = ID_GID; 1533 else if (type == TYPE_UID) 1534 type_string = ID_UID; 1535 else 1536 return (0); 1537 1538 for (i = 0; i < len; i++) { 1539 if (!isdigit(string[i])) { 1540 print_error(pos, 1541 gettext("\"%s\" is not a valid %s: the non-digit" 1542 " character '%c' found.\n"), string, 1543 type_string, string[i]); 1544 return (0); 1545 } 1546 } 1547 1548 ll = atoll(string); 1549 1550 /* Isn't it too large? */ 1551 if (type == TYPE_UID && (uid_t)ll != ll || 1552 type == TYPE_GID && (gid_t)ll != ll) { 1553 print_error(pos, 1554 gettext("%llu: too large for a %s.\n"), ll, 1555 type_string); 1556 return (0); 1557 } 1558 1559 *number = (uid_t)ll; 1560 return (1); 1561 } 1562 1563 /* 1564 * Convert SID from string to prefix and rid. If it has a valid 1565 * format, i.e. S(\-\d+)+, return 1. Otherwise print an error 1566 * message and return 0. 1567 */ 1568 static int 1569 sid_convert(char *from, char **prefix, idmap_rid_t *rid, cmd_pos_t *pos) 1570 { 1571 int i, j; 1572 char *cp; 1573 char *ecp; 1574 char *prefix_end; 1575 u_longlong_t a; 1576 unsigned long r; 1577 1578 if (strcmp_no0(from, "S-1-") != 0) { 1579 print_error(pos, 1580 gettext("Invalid %s \"%s\": it doesn't start " 1581 "with \"%s\".\n"), ID_SID, from, "S-1-"); 1582 return (0); 1583 } 1584 1585 if (strlen(from) <= strlen("S-1-")) { 1586 print_error(pos, 1587 gettext("Invalid %s \"%s\": the authority and RID parts are" 1588 " missing.\n"), 1589 ID_SID, from); 1590 return (0); 1591 } 1592 1593 /* count '-'s */ 1594 for (j = 0, cp = strchr(from, '-'); 1595 cp != NULL; 1596 j++, cp = strchr(cp + 1, '-')) { 1597 /* can't end on a '-' */ 1598 if (*(cp + 1) == '\0') { 1599 print_error(pos, 1600 gettext("Invalid %s \"%s\": '-' at the end.\n"), 1601 ID_SID, from); 1602 return (0); 1603 } else if (*(cp + 1) == '-') { 1604 print_error(pos, 1605 gettext("Invalid %s \"%s\": double '-'.\n"), 1606 ID_SID, from); 1607 return (0); 1608 } 1609 } 1610 1611 1612 /* check that we only have digits and '-' */ 1613 i = strspn(from + 1, "0123456789-") + 1; 1614 if (i < strlen(from)) { 1615 print_error(pos, 1616 gettext("Invalid %s \"%s\": invalid character '%c'.\n"), 1617 ID_SID, from, from[i]); 1618 return (0); 1619 } 1620 1621 1622 cp = from + strlen("S-1-"); 1623 1624 /* 64-bit safe parsing of unsigned 48-bit authority value */ 1625 errno = 0; 1626 a = strtoull(cp, &ecp, 10); 1627 1628 /* errors parsing the authority or too many bits */ 1629 if (cp == ecp || (a == 0 && errno == EINVAL)) { 1630 print_error(pos, 1631 gettext("Invalid %s \"%s\": unable to parse the " 1632 "authority \"%.*s\".\n"), ID_SID, from, ecp - cp, 1633 cp); 1634 return (0); 1635 } 1636 1637 if ((a == ULLONG_MAX && errno == ERANGE) || 1638 (a & 0x0000ffffffffffffULL) != a) { 1639 print_error(pos, 1640 gettext("Invalid %s \"%s\": the authority " 1641 "\"%.*s\" is too large.\n"), ID_SID, from, 1642 ecp - cp, cp); 1643 return (0); 1644 } 1645 1646 cp = ecp; 1647 1648 if (j < 3) { 1649 print_error(pos, 1650 gettext("Invalid %s \"%s\": must have at least one RID.\n"), 1651 ID_SID, from); 1652 return (0); 1653 } 1654 1655 for (i = 2; i < j; i++) { 1656 if (*cp++ != '-') { 1657 /* Should never happen */ 1658 print_error(pos, 1659 gettext("Invalid %s \"%s\": internal error:" 1660 " '-' missing.\n"), 1661 ID_SID, from); 1662 return (0); 1663 } 1664 /* 32-bit safe parsing of unsigned 32-bit RID */ 1665 errno = 0; 1666 r = strtoul(cp, &ecp, 10); 1667 1668 /* errors parsing the RID */ 1669 if (cp == ecp || (r == 0 && errno == EINVAL)) { 1670 /* should never happen */ 1671 print_error(pos, 1672 gettext("Invalid %s \"%s\": internal error: " 1673 "unable to parse the RID " 1674 "after \"%.*s\".\n"), ID_SID, 1675 from, cp - from, from); 1676 return (0); 1677 } 1678 1679 if (r == ULONG_MAX && errno == ERANGE) { 1680 print_error(pos, 1681 gettext("Invalid %s \"%s\": the RID \"%.*s\"" 1682 " is too large.\n"), ID_SID, 1683 from, ecp - cp, cp); 1684 return (0); 1685 } 1686 prefix_end = cp; 1687 cp = ecp; 1688 } 1689 1690 /* check that all of the string SID has been consumed */ 1691 if (*cp != '\0') { 1692 /* Should never happen */ 1693 print_error(pos, 1694 gettext("Invalid %s \"%s\": internal error: " 1695 "something is still left.\n"), 1696 ID_SID, from); 1697 return (0); 1698 } 1699 1700 *rid = (idmap_rid_t)r; 1701 1702 /* -1 for the '-' at the end: */ 1703 *prefix = strndup(from, prefix_end - from - 1); 1704 if (*prefix == NULL) { 1705 print_error(pos, 1706 gettext("Not enough memory.\n")); 1707 return (0); 1708 } 1709 1710 return (1); 1711 } 1712 1713 /* Does the line start with USERMAP_CFG IP qualifier? */ 1714 static int 1715 ucp_is_IP_qualifier(char *line) 1716 { 1717 char *it; 1718 it = line + strcspn(line, " \t\n#:"); 1719 return (*(it + 1) == ':' ? 1 : 0); 1720 } 1721 1722 1723 /* 1724 * returns interior of quotation marks in USERMAP_CFG. In this format, 1725 * there cannot be a protected quotation mark inside. 1726 */ 1727 static char * 1728 ucp_qm_interior(char **line, cmd_pos_t *pos) 1729 { 1730 char *out; 1731 char *qm = strchr(*line + 1, '"'); 1732 if (qm == NULL) { 1733 print_error(pos, 1734 gettext("Unclosed quotations\n")); 1735 return (NULL); 1736 } 1737 1738 out = strndup(*line + 1, qm - *line - 1); 1739 *line = qm + 1; 1740 return (out); 1741 } 1742 1743 /* 1744 * Grab next token from the line in USERMAP_CFG format. terminators, 1745 * the 3rd parameter, contains all the characters which can terminate 1746 * the token. line_num is the line number of input used for error 1747 * reporting. 1748 */ 1749 static char * 1750 ucp_grab_token(char **line, cmd_pos_t *pos, const char *terminators) 1751 { 1752 char *token; 1753 if (**line == '"') 1754 token = ucp_qm_interior(line, pos); 1755 else { 1756 int length = strcspn(*line, terminators); 1757 token = strndup(*line, length); 1758 *line += length; 1759 } 1760 1761 return (token); 1762 } 1763 1764 1765 /* 1766 * Convert a line in usermap.cfg format to name_mapping. 1767 * 1768 * Return values: -1 for error, 0 for empty line, 1 for a mapping 1769 * found. 1770 */ 1771 static int 1772 ucp_line2nm(char *line, cmd_pos_t *pos, name_mapping_t *nm) 1773 { 1774 char *it; 1775 char *token; 1776 char *token2; 1777 char separator; 1778 int is_direction = 0; 1779 1780 it = line + strspn(line, " \t\n"); 1781 1782 /* empty or comment lines are OK: */ 1783 if (*it == '\0' || *it == '#') 1784 return (0); 1785 1786 /* We do not support network qualifiers */ 1787 if (ucp_is_IP_qualifier(it)) { 1788 print_error(pos, 1789 gettext("Unable to handle network qualifier.\n")); 1790 return (-1); 1791 } 1792 1793 /* The windows name: */ 1794 token = ucp_grab_token(&it, pos, " \t#\\\n@=<"); 1795 if (token == NULL) 1796 return (-1); 1797 1798 separator = *it; 1799 1800 /* Didn't we bump to the end of line? */ 1801 if (separator == '\0' || separator == '#') { 1802 free(token); 1803 print_error(pos, 1804 gettext("UNIX_name not found.\n")); 1805 return (-1); 1806 } 1807 1808 /* Do we have a domainname? */ 1809 if (separator == '\\' || separator == '@') { 1810 it ++; 1811 token2 = ucp_grab_token(&it, pos, " \t\n#"); 1812 if (token2 == NULL) { 1813 free(token); 1814 return (-1); 1815 } else if (*it == '\0' || *it == '#') { 1816 free(token); 1817 free(token2); 1818 print_error(pos, 1819 gettext("UNIX_name not found.\n")); 1820 } 1821 1822 if (separator == '\\') { 1823 nm->windomain = token; 1824 nm->winname = token2; 1825 nm->is_nt4 = 1; 1826 } else { 1827 nm->windomain = token2; 1828 nm->winname = token; 1829 nm->is_nt4 = 0; 1830 1831 } 1832 } else { 1833 nm->windomain = NULL; 1834 nm->winname = token; 1835 nm->is_nt4 = 0; 1836 } 1837 1838 1839 it = it + strspn(it, " \t\n"); 1840 1841 /* Direction string is optional: */ 1842 if (strncmp(it, "==", 2) == 0) { 1843 nm->direction = IDMAP_DIRECTION_BI; 1844 is_direction = 1; 1845 } else if (strncmp(it, "<=", 2) == 0) { 1846 nm->direction = IDMAP_DIRECTION_U2W; 1847 is_direction = 1; 1848 } else if (strncmp(it, "=>", 2) == 0) { 1849 nm->direction = IDMAP_DIRECTION_W2U; 1850 is_direction = 1; 1851 } else { 1852 nm->direction = IDMAP_DIRECTION_BI; 1853 is_direction = 0; 1854 } 1855 1856 if (is_direction) { 1857 it += 2; 1858 it += strspn(it, " \t\n"); 1859 1860 if (*it == '\0' || *it == '#') { 1861 print_error(pos, 1862 gettext("UNIX_name not found.\n")); 1863 return (-1); 1864 } 1865 } 1866 1867 /* Now unixname: */ 1868 it += strspn(it, " \t\n"); 1869 token = ucp_grab_token(&it, pos, " \t\n#"); 1870 1871 if (token == NULL) 1872 /* nm->winname to be freed by name_mapping_fini */ 1873 return (-1); 1874 1875 /* Neither here we support IP qualifiers */ 1876 if (ucp_is_IP_qualifier(token)) { 1877 print_error(pos, 1878 gettext("Unable to handle network qualifier.\n")); 1879 free(token); 1880 return (-1); 1881 } 1882 1883 nm->unixname = token; 1884 1885 it += strspn(it, " \t\n"); 1886 1887 /* Does something remain on the line */ 1888 if (*it != '\0' && *it != '#') { 1889 print_error(pos, 1890 gettext("Unrecognized parameters \"%s\".\n"), it); 1891 return (-1); 1892 } 1893 1894 return (1); 1895 } 1896 1897 /* 1898 * Parse SMBUSERS line to name_mapping_t. if line is NULL, then 1899 * pasrsing of the previous line is continued. line_num is input line 1900 * number used for error reporting. 1901 * Return values: 1902 * rc -1: error 1903 * rc = 0: mapping found and the line is finished, 1904 * rc = 1: mapping found and there remains other on the line 1905 */ 1906 static int 1907 sup_line2nm(char *line, cmd_pos_t *pos, name_mapping_t *nm) 1908 { 1909 static char *ll = NULL; 1910 static char *unixname = NULL; 1911 static size_t unixname_l = 0; 1912 char *token; 1913 1914 if (line != NULL) { 1915 ll = line; 1916 1917 unixname = ll += strspn(ll, " \t"); 1918 if (*ll == '\0' || *ll == '#') 1919 return (0); 1920 1921 unixname_l = strcspn(ll, " \t:=#\n"); 1922 ll += unixname_l; 1923 1924 if (*ll == '\0'|| *ll == '#') 1925 return (0); 1926 1927 ll += strspn(ll, " \t:=#\n"); 1928 1929 } 1930 1931 if (*ll == '\0'|| *ll == '#') 1932 return (0); 1933 1934 token = ucp_grab_token(&ll, pos, " \t\n"); 1935 if (token == NULL) 1936 return (-1); 1937 1938 nm->is_nt4 = 0; 1939 nm->direction = IDMAP_DIRECTION_W2U; 1940 1941 nm->windomain = NULL; 1942 nm->winname = token; 1943 nm->unixname = strndup(unixname, unixname_l); 1944 if (nm->unixname == NULL) 1945 return (-1); 1946 1947 ll += strspn(ll, " \t\n"); 1948 return (1); 1949 } 1950 1951 /* Parse line to name_mapping_t. Basicaly just a format switch. */ 1952 static int 1953 line2nm(char *line, cmd_pos_t *pos, name_mapping_t *nm, format_t f) 1954 { 1955 switch (f) { 1956 case USERMAP_CFG: 1957 if (line == NULL) 1958 return (0); 1959 else 1960 return (ucp_line2nm(line, pos, nm)); 1961 case SMBUSERS: 1962 return (sup_line2nm(line, pos, nm)); 1963 default: 1964 /* This can never happen */ 1965 print_error(pos, 1966 gettext("Internal error: invalid line format.\n")); 1967 } 1968 1969 return (-1); 1970 } 1971 1972 1973 /* Examine -f flag and return the appropriate format_t */ 1974 static format_t 1975 ff2format(char *ff, int is_mandatory) 1976 { 1977 1978 if (ff == NULL && is_mandatory) { 1979 print_error(NULL, gettext("Format not given.\n")); 1980 return (UNDEFINED_FORMAT); 1981 } 1982 1983 if (ff == NULL) 1984 return (DEFAULT_FORMAT); 1985 1986 if (strcasecmp(ff, "usermap.cfg") == 0) 1987 return (USERMAP_CFG); 1988 1989 if (strcasecmp(ff, "smbusers") == 0) 1990 return (SMBUSERS); 1991 1992 print_error(NULL, 1993 gettext("The only known formats are: \"usermap.cfg\" and " 1994 "\"smbusers\".\n")); 1995 return (UNDEFINED_FORMAT); 1996 } 1997 1998 /* Delete all namerules of the given type */ 1999 static int 2000 flush_nm(boolean_t is_user, cmd_pos_t *pos) 2001 { 2002 idmap_stat stat; 2003 2004 stat = idmap_udt_flush_namerules(udt); 2005 if (stat < 0) { 2006 print_error(pos, 2007 is_user ? gettext("Unable to flush users (%s).\n") 2008 : gettext("Unable to flush groups (%s).\n"), 2009 idmap_stat2string(handle, stat)); 2010 return (-1); 2011 } 2012 2013 if (positions_add(pos) < 0) 2014 return (-1); 2015 2016 return (0); 2017 } 2018 2019 /* import command handler */ 2020 static int 2021 /* LINTED E_FUNC_ARG_UNUSED */ 2022 do_import(flag_t *f, int argc, char **argv, cmd_pos_t *pos) 2023 { 2024 name_mapping_t *nm; 2025 cmd_pos_t pos2; 2026 char line[MAX_INPUT_LINE_SZ]; 2027 format_t format; 2028 int rc = 0; 2029 idmap_stat stat; 2030 FILE *file = NULL; 2031 2032 if (batch_mode) { 2033 print_error(pos, 2034 gettext("Import is not allowed in the batch mode.\n")); 2035 return (-1); 2036 } 2037 2038 format = ff2format(argv[0], 1); 2039 if (format == UNDEFINED_FORMAT) 2040 return (-1); 2041 2042 if (init_udt_command()) 2043 return (-1); 2044 2045 /* We don't flush groups in the usermap.cfg nor smbusers format */ 2046 if (f[F_FLAG] != NULL && 2047 flush_nm(B_TRUE, pos) < 0 && 2048 (format == USERMAP_CFG || format == SMBUSERS || 2049 flush_nm(B_FALSE, pos) < 0)) { 2050 rc = -1; 2051 goto cleanup; 2052 } 2053 2054 /* Where we import from? */ 2055 if (f[f_FLAG] == NULL) 2056 file = stdin; 2057 else { 2058 file = fopen(f[f_FLAG], "r"); 2059 if (file == NULL) { 2060 perror(f[f_FLAG]); 2061 goto cleanup; 2062 } 2063 } 2064 2065 pos2.linenum = 0; 2066 pos2.line = line; 2067 2068 while (fgets(line, MAX_INPUT_LINE_SZ, file)) { 2069 char *line2 = line; 2070 pos2.linenum++; 2071 2072 /* 2073 * In SMBUSERS format there can be more mappings on 2074 * each line. So we need the internal cycle for each line. 2075 */ 2076 do { 2077 nm = name_mapping_init(); 2078 if (nm == NULL) { 2079 rc = -1; 2080 goto cleanup; 2081 } 2082 2083 rc = line2nm(line2, &pos2, nm, format); 2084 line2 = NULL; 2085 2086 if (rc < 1) { 2087 name_mapping_fini(nm); 2088 break; 2089 } 2090 2091 stat = idmap_udt_add_namerule(udt, nm->windomain, 2092 nm->is_user ? B_TRUE : B_FALSE, 2093 nm->is_wuser ? B_TRUE : B_FALSE, 2094 nm->winname, 2095 nm->unixname, nm->is_nt4, nm->direction); 2096 if (stat < 0) { 2097 print_error(&pos2, 2098 gettext("Transaction error (%s)\n"), 2099 idmap_stat2string(handle, stat)); 2100 rc = -1; 2101 } 2102 2103 if (rc >= 0) 2104 rc = positions_add(&pos2); 2105 2106 name_mapping_fini(nm); 2107 2108 } while (rc >= 0); 2109 2110 if (rc < 0) { 2111 print_error(NULL, 2112 gettext("Import canceled.\n")); 2113 break; 2114 } 2115 } 2116 2117 cleanup: 2118 if (fini_udt_command((rc < 0 ? 0 : 1), pos)) 2119 rc = -1; 2120 if (file != NULL && file != stdin) 2121 (void) fclose(file); 2122 return (rc); 2123 } 2124 2125 2126 /* 2127 * List name mappings in the format specified. list_users / 2128 * list_groups determine which type to list. The output goes to the 2129 * file fi. 2130 */ 2131 static int 2132 list_name_mappings(format_t format, FILE *fi) 2133 { 2134 idmap_stat stat; 2135 idmap_iter_t *ihandle; 2136 name_mapping_t *nm; 2137 boolean_t is_user; 2138 boolean_t is_wuser; 2139 print_handle_t *ph; 2140 2141 stat = idmap_iter_namerules(handle, NULL, 0, 0, NULL, NULL, &ihandle); 2142 if (stat < 0) { 2143 print_error(NULL, 2144 gettext("Iteration handle not obtained (%s)\n"), 2145 idmap_stat2string(handle, stat)); 2146 idmap_iter_destroy(ihandle); 2147 return (-1); 2148 } 2149 2150 ph = print_mapping_init(format, fi); 2151 if (ph == NULL) 2152 return (-1); 2153 2154 do { 2155 nm = name_mapping_init(); 2156 if (nm == NULL) { 2157 idmap_iter_destroy(ihandle); 2158 return (-1); 2159 } 2160 2161 stat = idmap_iter_next_namerule(ihandle, &nm->windomain, 2162 &nm->winname, &nm->unixname, &is_user, &is_wuser, 2163 &nm->is_nt4, &nm->direction); 2164 if (stat >= 0) { 2165 nm->is_user = is_user ? IDMAP_YES : IDMAP_NO; 2166 nm->is_wuser = is_wuser ? IDMAP_YES : IDMAP_NO; 2167 (void) print_mapping(ph, nm); 2168 } 2169 2170 name_mapping_fini(nm); 2171 2172 } while (stat > 0); 2173 2174 (void) print_mapping_fini(ph); 2175 2176 if (stat < 0 && stat != IDMAP_ERR_NOTFOUND) { 2177 print_error(NULL, 2178 gettext("Error during iteration (%s)\n"), 2179 idmap_stat2string(handle, stat)); 2180 idmap_iter_destroy(ihandle); 2181 return (-1); 2182 } 2183 2184 idmap_iter_destroy(ihandle); 2185 return (0); 2186 } 2187 2188 /* Export command handler */ 2189 static int 2190 /* LINTED E_FUNC_ARG_UNUSED */ 2191 do_export(flag_t *f, int argc, char **argv, cmd_pos_t *pos) 2192 { 2193 int rc; 2194 format_t format; 2195 FILE *fi; 2196 2197 format = ff2format(argv[0], 1); 2198 if (format == UNDEFINED_FORMAT) 2199 return (-1); 2200 2201 /* Where do we output to? */ 2202 if (f[f_FLAG] == NULL) 2203 fi = stdout; 2204 else { 2205 fi = fopen(f[f_FLAG], "w"); 2206 if (fi == NULL) { 2207 perror(f[f_FLAG]); 2208 return (-1); 2209 } 2210 } 2211 2212 if (init_command() < 0) { 2213 rc = -1; 2214 goto cleanup; 2215 } 2216 2217 /* List the requested types: */ 2218 rc = list_name_mappings(format, fi); 2219 2220 fini_command(); 2221 2222 cleanup: 2223 if (fi != NULL && fi != stdout) 2224 (void) fclose(fi); 2225 return (rc); 2226 } 2227 2228 /* List command handler */ 2229 static int 2230 /* LINTED E_FUNC_ARG_UNUSED */ 2231 do_list_name_mappings(flag_t *f, int argc, char **argv, cmd_pos_t *pos) 2232 { 2233 int rc; 2234 2235 if (init_command()) { 2236 return (-1); 2237 } 2238 2239 /* List the requested types: */ 2240 rc = list_name_mappings(DEFAULT_FORMAT, stdout); 2241 2242 fini_command(); 2243 return (rc); 2244 } 2245 2246 /* This is just a debug function for dumping flags */ 2247 static void 2248 print_flags(flag_t *f) 2249 { 2250 int c; 2251 for (c = 0; c < FLAG_ALPHABET_SIZE; c++) { 2252 if (f[c] == FLAG_SET) 2253 (void) printf("FLAG: -%c, VALUE: %p\n", c, 2254 (void *) f[c]); 2255 else if (f[c]) 2256 (void) printf("FLAG: -%c, VALUE: %s\n", c, f[c]); 2257 } 2258 } 2259 2260 /* Convert string like sid or winname to the identity type code */ 2261 2262 static int 2263 string2type(char *str, cmd_pos_t *pos) { 2264 int i; 2265 int code = TYPE_INVALID; 2266 2267 for (i = 0; i < sizeof (identity2code) / sizeof (id_code_t); i++) { 2268 if (strcasecmp(identity2code[i].identity, str) == 0) { 2269 code = identity2code[i].code; 2270 break; 2271 } 2272 } 2273 2274 if (code == TYPE_INVALID) { 2275 print_error(pos, 2276 gettext("Error: invalid identity type \"%s\"\n"), str); 2277 } 2278 2279 return (code); 2280 } 2281 2282 2283 2284 2285 /* 2286 * Split argument to its identity code and a name part 2287 * return values: 2288 * TYPE_INVALID for unknown identity 2289 * TYPE_AUTO for no identity (to be autodetected) 2290 * <TYPE_XXX> for known identity 2291 */ 2292 2293 static int 2294 get_identity(char *arg, char **name, cmd_pos_t *pos) 2295 { 2296 char *it; 2297 int code = TYPE_INVALID; 2298 2299 if ((it = strchr(arg, ':')) == NULL) { 2300 *name = arg; 2301 return (TYPE_AUTO); 2302 } 2303 2304 2305 *it = '\0'; 2306 code = string2type(arg, pos); 2307 *it = ':'; /* restore the original string: */ 2308 2309 *name = it + 1; 2310 return (code); 2311 } 2312 2313 /* 2314 * This function splits name to the relevant pieces: is_user, winname, 2315 * windomain unixname. E.g. for winname, it strdups nm->winname and possibly 2316 * nm->windomain and return TYPE_WN. 2317 * 2318 * If there is already one of the text fields allocated, it is OK. 2319 * Return values: 2320 * -1 ... syntax error 2321 * 0 ... it wasnt possible to determine 2322 * <TYPE_XXX> otherwise 2323 */ 2324 2325 static int 2326 name2parts(char *name, name_mapping_t *nm, cmd_pos_t *pos) 2327 { 2328 char *it; 2329 int code; 2330 2331 code = get_identity(name, &it, pos); 2332 2333 switch (code) { 2334 case TYPE_INVALID: 2335 /* syntax error: */ 2336 return (-1); 2337 case TYPE_AUTO: 2338 /* autodetection: */ 2339 if (nm->winname != NULL && nm->is_wuser != IDMAP_UNKNOWN) 2340 code = nm->is_wuser == IDMAP_YES ? TYPE_UU : TYPE_UG; 2341 else if (nm->unixname != NULL || 2342 strchr(name, '@') != NULL || 2343 strchr(name, '\\') != NULL) 2344 /* btw, nm->is_user can never be IDMAP_UNKNOWN here */ 2345 code = TYPE_WN; 2346 else 2347 return (0); 2348 /* If the code was guessed succesfully, we are OK. */ 2349 break; 2350 default: 2351 name = it; 2352 } 2353 2354 if (code & IS_WIN) { 2355 if (code & IS_USER) 2356 nm->is_wuser = IDMAP_YES; 2357 else if (code & IS_GROUP) 2358 nm->is_wuser = IDMAP_NO; 2359 } else { 2360 if (code & IS_USER) 2361 nm->is_user = IDMAP_YES; 2362 else if (code & IS_GROUP) 2363 nm->is_user = IDMAP_NO; 2364 } 2365 2366 if (code & IS_WIN && code & IS_NAME) { 2367 if (nm->winname != NULL || nm->windomain != NULL) 2368 return (code); 2369 2370 if ((it = strchr(name, '@')) != NULL) { 2371 int length = it - name + 1; 2372 nm->winname = (char *)malloc(length); 2373 (void) strncpy(nm->winname, name, length - 1); 2374 nm->winname[length - 1] = '\0'; 2375 nm->windomain = strdup(it + 1); 2376 } else if ((it = strrchr(name, '\\')) != NULL) { 2377 int length = it - name + 1; 2378 nm->windomain = (char *)malloc(length); 2379 (void) strncpy(nm->windomain, name, length - 1); 2380 nm->windomain[length - 1] = '\0'; 2381 nm->winname = strdup(it + 1); 2382 nm->is_nt4 = B_TRUE; 2383 } else 2384 nm->winname = strdup(name); 2385 2386 return (code); 2387 } 2388 2389 2390 if (!(code & IS_WIN) && code & IS_NAME) { 2391 if (nm->unixname != NULL) 2392 return (code); 2393 2394 if (strlen(name) == 0) 2395 nm->unixname = strdup("\"\""); 2396 else 2397 nm->unixname = strdup(name); 2398 return (code); 2399 } 2400 2401 2402 if (code & IS_WIN && !(code & IS_NAME)) { 2403 if (!sid_convert(name, &nm->sidprefix, &nm->rid, pos)) 2404 return (-1); 2405 else 2406 return (code); 2407 } 2408 2409 /* 2410 * it is (!(code & TYPE_WIN) && !(code & TYPE_NAME)) here - the other 2411 * possiblities are exhausted. 2412 */ 2413 2414 if (!pid_convert(name, &nm->pid, code, pos)) 2415 return (-1); 2416 else 2417 return (code); 2418 2419 } 2420 2421 /* 2422 * Cycle through add/remove arguments until they are identified or found 2423 * invalid. 2424 */ 2425 static 2426 name_mapping_t * 2427 args2nm(int *is_first_win, int argc, char **argv, 2428 cmd_pos_t *pos) 2429 { 2430 int code; 2431 int i; 2432 name_mapping_t *nm; 2433 2434 nm = name_mapping_init(); 2435 if (nm == NULL) 2436 return (NULL); 2437 2438 for (i = 0; i < 2 * argc - 1; i++) { 2439 code = name2parts(argv[i % 2], nm, pos); 2440 switch (code) { 2441 case -1: 2442 goto fail; 2443 case 0: 2444 if (i > 0) { 2445 print_error(pos, 2446 gettext("Missing identity type" 2447 " cannot be determined for %s.\n"), 2448 argv[i % 2]); 2449 goto fail; 2450 } 2451 break; 2452 default: 2453 if (!(code & IS_NAME)) { 2454 print_error(pos, 2455 gettext("%s is not a valid name\n"), 2456 argv[i % 2]); 2457 goto fail; 2458 } 2459 } 2460 } 2461 2462 if (argc == 2 && nm->winname == NULL) { 2463 print_error(pos, gettext("No windows identity found.\n")); 2464 goto fail; 2465 } 2466 if (argc == 2 && nm->unixname == NULL) { 2467 print_error(pos, gettext("No unix identity found.\n")); 2468 goto fail; 2469 } 2470 if (argc == 1 && nm->winname == NULL && nm->unixname == NULL) { 2471 print_error(pos, gettext("No identity type determined.\n")); 2472 goto fail; 2473 } 2474 2475 if (is_first_win != NULL) 2476 *is_first_win = code & IS_WIN; 2477 return (nm); 2478 fail: 2479 name_mapping_fini(nm); 2480 return (NULL); 2481 } 2482 2483 2484 2485 /* add command handler. */ 2486 static int 2487 do_add_name_mapping(flag_t *f, int argc, char **argv, cmd_pos_t *pos) 2488 { 2489 name_mapping_t *nm; 2490 int rc = 0; 2491 int is_first_win; 2492 idmap_stat stat; 2493 int is_wuser; 2494 print_handle_t *ph; 2495 2496 2497 2498 /* Exactly two arguments must be specified */ 2499 if (argc < 2) { 2500 print_error(pos, gettext("Not enough arguments.\n")); 2501 return (-1); 2502 } else if (argc > 2) { 2503 print_error(pos, gettext("Too many arguments.\n")); 2504 return (-1); 2505 } 2506 2507 nm = args2nm(&is_first_win, argc, argv, pos); 2508 if (nm == NULL) 2509 return (-1); 2510 2511 if (f[d_FLAG] != NULL) 2512 nm->direction = is_first_win 2513 ? IDMAP_DIRECTION_W2U 2514 : IDMAP_DIRECTION_U2W; 2515 else 2516 nm->direction = IDMAP_DIRECTION_BI; 2517 2518 /* Now let us write it: */ 2519 2520 if (init_udt_command()) { 2521 name_mapping_fini(nm); 2522 return (-1); 2523 } 2524 2525 for (is_wuser = IDMAP_YES; is_wuser >= IDMAP_NO; is_wuser--) { 2526 /* nm->is_wuser can be IDMAP_YES, IDMAP_NO or IDMAP_UNKNOWN */ 2527 if ((is_wuser == IDMAP_YES && nm->is_wuser == IDMAP_NO) || 2528 (is_wuser == IDMAP_NO && nm->is_wuser == IDMAP_YES)) 2529 continue; 2530 2531 stat = idmap_udt_add_namerule(udt, nm->windomain, 2532 nm->is_user ? B_TRUE : B_FALSE, 2533 is_wuser ? B_TRUE : B_FALSE, 2534 nm->winname, nm->unixname, nm->is_nt4, nm->direction); 2535 } 2536 2537 /* We echo the mapping */ 2538 ph = print_mapping_init(DEFAULT_FORMAT, stdout); 2539 if (ph == NULL) { 2540 rc = -1; 2541 goto cleanup; 2542 } 2543 (void) print_mapping(ph, nm); 2544 (void) print_mapping_fini(ph); 2545 2546 if (stat != IDMAP_SUCCESS) { 2547 print_error(pos, 2548 gettext("Mapping not created (%s)\n"), 2549 idmap_stat2string(handle, stat)); 2550 rc = -1; 2551 } 2552 2553 if (rc == 0) 2554 rc = positions_add(pos); 2555 2556 cleanup: 2557 name_mapping_fini(nm); 2558 if (fini_udt_command(1, pos)) 2559 rc = -1; 2560 return (rc); 2561 } 2562 2563 /* remove command handler */ 2564 static int 2565 do_remove_name_mapping(flag_t *f, int argc, char **argv, cmd_pos_t *pos) 2566 { 2567 name_mapping_t *nm; 2568 int rc = 0; 2569 idmap_stat stat; 2570 int is_first_win; 2571 int is_wuser; 2572 2573 /* "-a" means we flush all of them */ 2574 if (f[a_FLAG] != NULL) { 2575 if (argc) { 2576 print_error(pos, 2577 gettext("Too many arguments.\n")); 2578 return (-1); 2579 } 2580 2581 if (init_udt_command()) 2582 return (-1); 2583 rc = flush_nm(B_TRUE, pos); 2584 2585 if (rc >= 0) 2586 rc = flush_nm(B_FALSE, pos); 2587 2588 if (fini_udt_command(rc ? 0 : 1, pos)) 2589 rc = -1; 2590 return (rc); 2591 } 2592 2593 /* Contrary to add_name_mapping, we can have only one argument */ 2594 if (argc < 1) { 2595 print_error(pos, gettext("Not enough arguments.\n")); 2596 return (-1); 2597 } else if (argc > 2) { 2598 print_error(pos, gettext("Too many arguments.\n")); 2599 return (-1); 2600 } else if ( 2601 /* both -f and -t: */ 2602 f[f_FLAG] != NULL && f[t_FLAG] != NULL || 2603 /* -d with a single argument: */ 2604 argc == 1 && f[d_FLAG] != NULL || 2605 /* -f or -t with two arguments: */ 2606 argc == 2 && (f[f_FLAG] != NULL || f[t_FLAG] != NULL)) { 2607 print_error(pos, 2608 gettext("Direction ambiguous.\n")); 2609 return (-1); 2610 } 2611 2612 2613 /* 2614 * Similar to do_add_name_mapping - see the comments 2615 * there. Except we may have only one argument here. 2616 */ 2617 nm = args2nm(&is_first_win, argc, argv, pos); 2618 if (nm == NULL) 2619 return (-1); 2620 2621 /* 2622 * If the direction is not specified by a -d/-f/-t flag, then it 2623 * is IDMAP_DIRECTION_UNDEF, because in that case we want to 2624 * remove any mapping. If it was IDMAP_DIRECTION_BI, idmap_api would 2625 * delete a bidirectional one only. 2626 */ 2627 if (f[d_FLAG] != NULL || f[f_FLAG] != NULL) 2628 nm->direction = is_first_win 2629 ? IDMAP_DIRECTION_W2U 2630 : IDMAP_DIRECTION_U2W; 2631 else if (f[t_FLAG] != NULL) 2632 nm->direction = is_first_win 2633 ? IDMAP_DIRECTION_U2W 2634 : IDMAP_DIRECTION_W2U; 2635 else 2636 nm->direction = IDMAP_DIRECTION_UNDEF; 2637 2638 if (init_udt_command()) { 2639 name_mapping_fini(nm); 2640 return (-1); 2641 } 2642 2643 for (is_wuser = IDMAP_YES; is_wuser >= IDMAP_NO; is_wuser--) { 2644 if ((is_wuser == IDMAP_YES && nm->is_wuser == IDMAP_NO) || 2645 (is_wuser == IDMAP_NO && nm->is_wuser == IDMAP_YES)) 2646 continue; 2647 2648 stat = idmap_udt_rm_namerule(udt, 2649 nm->is_user ? B_TRUE : B_FALSE, 2650 is_wuser ? B_TRUE : B_FALSE, 2651 nm->windomain, nm->winname, nm->unixname, nm->direction); 2652 2653 if (stat != IDMAP_SUCCESS) { 2654 print_error(pos, 2655 gettext("Mapping not deleted (%s)\n"), 2656 idmap_stat2string(handle, stat)); 2657 rc = -1; 2658 break; 2659 } 2660 } 2661 2662 if (rc == 0) 2663 rc = positions_add(pos); 2664 2665 cleanup: 2666 name_mapping_fini(nm); 2667 if (fini_udt_command(1, pos)) 2668 rc = -1; 2669 return (rc); 2670 } 2671 2672 2673 /* exit command handler */ 2674 static int 2675 /* LINTED E_FUNC_ARG_UNUSED */ 2676 do_exit(flag_t *f, int argc, char **argv, cmd_pos_t *pos) 2677 { 2678 return (0); 2679 } 2680 2681 2682 /* debug command handler: just print the parameters */ 2683 static int 2684 /* LINTED E_STATIC_UNUSED */ 2685 debug_print_params(flag_t *f, int argc, char **argv, cmd_pos_t *pos) 2686 { 2687 int i; 2688 #if 0 2689 char *leaktest = (char *)malloc(100); 2690 #endif 2691 2692 print_flags(f); 2693 2694 for (i = 0; i < argc; i++) { 2695 (void) printf("Argument %d: %s\n", i, argv[i]); 2696 } 2697 2698 (void) fflush(stdout); 2699 return (0); 2700 } 2701 2702 /* 2703 * From name_mapping_t, asseble a string containing identity of the 2704 * given type. 2705 */ 2706 static int 2707 nm2type(name_mapping_t *nm, int type, char **to) 2708 { 2709 switch (type) { 2710 case TYPE_SID: 2711 case TYPE_USID: 2712 case TYPE_GSID: 2713 if (nm->sidprefix == NULL) 2714 return (-1); 2715 *to = sid_format(nm); 2716 return (0); 2717 case TYPE_WN: 2718 case TYPE_WU: 2719 case TYPE_WG: 2720 return (nm2winqn(nm, to)); 2721 case TYPE_UID: 2722 case TYPE_GID: 2723 case TYPE_PID: 2724 *to = pid_format(nm->pid, nm->is_user); 2725 if (*to == NULL) 2726 return (-1); 2727 else 2728 return (0); 2729 case TYPE_UN: 2730 case TYPE_UU: 2731 case TYPE_UG: 2732 return (nm2unixname(nm, to)); 2733 default: 2734 /* This can never happen: */ 2735 print_error(NULL, 2736 gettext("Internal error: invalid name type.\n")); 2737 return (-1); 2738 } 2739 /* never reached */ 2740 } 2741 2742 /* show command handler */ 2743 static int 2744 do_show_mapping(flag_t *f, int argc, char **argv, cmd_pos_t *pos) 2745 { 2746 idmap_stat stat = 0; 2747 int flag; 2748 idmap_stat map_stat = 0; 2749 int type_from; 2750 int type_to; 2751 name_mapping_t *nm = NULL; 2752 char *fromname; 2753 char *toname; 2754 idmap_info info; 2755 2756 (void) memset(&info, 0, sizeof (info)); 2757 2758 if (argc == 0) { 2759 print_error(pos, 2760 gettext("No identity given\n")); 2761 return (-1); 2762 } else if (argc > 2) { 2763 print_error(pos, 2764 gettext("Too many arguments.\n")); 2765 return (-1); 2766 } 2767 2768 flag = f[c_FLAG] != NULL ? 0 : IDMAP_REQ_FLG_NO_NEW_ID_ALLOC; 2769 flag |= f[v_FLAG] == NULL ? 0 : IDMAP_REQ_FLG_MAPPING_INFO; 2770 2771 if (init_command()) 2772 return (-1); 2773 2774 nm = name_mapping_init(); 2775 if (nm == NULL) 2776 goto cleanup; 2777 2778 type_from = name2parts(argv[0], nm, pos); 2779 if (type_from <= 0) { 2780 stat = IDMAP_ERR_ARG; 2781 goto cleanup; 2782 } 2783 2784 2785 /* Second, determine type_to: */ 2786 if (argc < 2) { 2787 type_to = type_from & IS_WIN ? TYPE_PID : TYPE_SID; 2788 if (type_from & IS_NAME) 2789 type_to |= IS_NAME; 2790 } else { 2791 type_to = string2type(argv[1], pos); 2792 if (type_to == TYPE_INVALID) { 2793 stat = IDMAP_ERR_ARG; 2794 goto cleanup; 2795 } 2796 } 2797 2798 if (type_to & IS_WIN) { 2799 if (type_to & IS_USER) 2800 nm->is_wuser = IDMAP_YES; 2801 else if (type_to & IS_GROUP) 2802 nm->is_wuser = IDMAP_NO; 2803 else 2804 nm->is_wuser = IDMAP_UNKNOWN; 2805 } else { 2806 if (type_to & IS_USER) 2807 nm->is_user = IDMAP_YES; 2808 else if (type_to & IS_GROUP) 2809 nm->is_user = IDMAP_NO; 2810 } 2811 2812 /* Are both arguments the same OS side? */ 2813 if (!(type_from & IS_WIN ^ type_to & IS_WIN)) { 2814 print_error(pos, 2815 gettext("Direction ambiguous.\n")); 2816 stat = IDMAP_ERR_ARG; 2817 goto cleanup; 2818 } 2819 2820 /* 2821 * We have two interfaces for retrieving the mappings: 2822 * idmap_get_sidbyuid & comp (the batch interface) and 2823 * idmap_get_w2u_mapping & comp. We want to use both of them, because 2824 * the former mimicks kernel interface better and the later offers the 2825 * string names. In the batch case, our batch has always size 1. 2826 * 2827 * Btw, type_from cannot be IDMAP_PID, because there is no type string 2828 * for it. 2829 */ 2830 2831 if (type_from & IS_NAME || type_to & IS_NAME || 2832 type_from == TYPE_GSID || type_from == TYPE_USID || 2833 type_to == TYPE_GSID || type_to == TYPE_USID) { 2834 if (type_from & IS_WIN) { 2835 map_stat = idmap_get_w2u_mapping(handle, 2836 nm->sidprefix, 2837 &nm->rid, 2838 nm->winname, 2839 nm->windomain, 2840 flag, 2841 &nm->is_user, &nm->is_wuser, 2842 &nm->pid, 2843 &nm->unixname, 2844 &nm->direction, 2845 &info); 2846 } else { 2847 map_stat = idmap_get_u2w_mapping(handle, 2848 &nm->pid, 2849 nm->unixname, 2850 flag, 2851 nm->is_user, &nm->is_wuser, 2852 &nm->sidprefix, 2853 &nm->rid, 2854 &nm->winname, 2855 &nm->windomain, 2856 &nm->direction, 2857 &info); 2858 } 2859 2860 } else { 2861 /* batch handle */ 2862 idmap_get_handle_t *ghandle = NULL; 2863 /* To be passed to idmap_get_uidbysid */ 2864 gid_t gid = UNDEFINED_GID; 2865 /* To be passed to idmap_get_gidbysid */ 2866 uid_t uid = UNDEFINED_UID; 2867 2868 2869 /* Create an in-memory structure for all the batch: */ 2870 stat = idmap_get_create(handle, &ghandle); 2871 if (stat != IDMAP_SUCCESS) { 2872 print_error(pos, 2873 gettext("Unable to create handle for communicating" 2874 " with idmapd(1M) (%s)\n"), 2875 idmap_stat2string(handle, stat)); 2876 idmap_get_destroy(ghandle); 2877 goto cleanup; 2878 } 2879 2880 /* Schedule the request: */ 2881 if (type_to == TYPE_UID) { 2882 stat = idmap_getext_uidbysid(ghandle, 2883 nm->sidprefix, 2884 nm->rid, 2885 flag, 2886 &uid, 2887 &info, 2888 &map_stat); 2889 } else if (type_to == TYPE_GID) { 2890 stat = idmap_getext_gidbysid(ghandle, 2891 nm->sidprefix, 2892 nm->rid, 2893 flag, 2894 &gid, 2895 &info, 2896 &map_stat); 2897 } else if (type_to == TYPE_PID) { 2898 stat = idmap_getext_pidbysid(ghandle, 2899 nm->sidprefix, 2900 nm->rid, 2901 flag, 2902 &nm->pid, 2903 &nm->is_user, 2904 &info, 2905 &map_stat); 2906 } else if (type_from == TYPE_UID) { 2907 stat = idmap_getext_sidbyuid(ghandle, 2908 nm->pid, 2909 flag, 2910 &nm->sidprefix, 2911 &nm->rid, 2912 &info, 2913 &map_stat); 2914 } else if (type_from == TYPE_GID) { 2915 stat = idmap_getext_sidbygid(ghandle, 2916 (gid_t)nm->pid, 2917 flag, 2918 &nm->sidprefix, 2919 &nm->rid, 2920 &info, 2921 &map_stat); 2922 } else { 2923 /* This can never happen: */ 2924 print_error(pos, 2925 gettext("Internal error in show.\n")); 2926 exit(1); 2927 } 2928 2929 if (stat < 0) { 2930 print_error(pos, 2931 gettext("Request for %.3s not sent (%s)\n"), 2932 argv[0], idmap_stat2string(handle, stat)); 2933 idmap_get_destroy(ghandle); 2934 goto cleanup; 2935 } 2936 2937 /* Send the batch to idmapd and obtain results: */ 2938 stat = idmap_get_mappings(ghandle); 2939 if (stat < 0) { 2940 print_error(pos, 2941 gettext("Mappings not obtained because of" 2942 " RPC problem (%s)\n"), 2943 idmap_stat2string(handle, stat)); 2944 idmap_get_destroy(ghandle); 2945 goto cleanup; 2946 } 2947 2948 /* Destroy the batch handle: */ 2949 idmap_get_destroy(ghandle); 2950 2951 if (type_to == TYPE_UID) 2952 nm->pid = uid; 2953 else if (type_to == TYPE_GID) 2954 nm->pid = (uid_t)gid; 2955 2956 } 2957 2958 /* 2959 * If there was -c flag, we do output whatever we can even in 2960 * the case of error: 2961 */ 2962 if (map_stat < 0 && flag & IDMAP_REQ_FLG_NO_NEW_ID_ALLOC) 2963 goto errormsg; 2964 2965 /* 2966 * idmapd returns fallback uid/gid in case of errors. However 2967 * it uses special sentinel value i.e 4294967295 (or -1) to 2968 * indicate that falbback pid is not available either. In such 2969 * case idmap(1M) should not display the mapping because there 2970 * is no fallback mapping. 2971 */ 2972 2973 if ((type_to == TYPE_UID || type_to == TYPE_GID || 2974 type_to == TYPE_PID) && nm->pid == UNDEFINED_UID) 2975 goto errormsg; 2976 2977 if (nm2type(nm, type_from, &fromname) < 0) 2978 goto errormsg; 2979 2980 if (nm2type(nm, type_to, &toname) < 0) { 2981 if (!(flag & IDMAP_REQ_FLG_NO_NEW_ID_ALLOC)) 2982 (void) printf("%s -> %s:%u\n", 2983 fromname, 2984 type_to & IS_GROUP ? ID_GID : ID_UID, 2985 UID_NOBODY); 2986 free(fromname); 2987 } else { 2988 (void) printf("%s -> %s\n", fromname, toname); 2989 free(fromname); 2990 free(toname); 2991 } 2992 2993 errormsg: 2994 if (map_stat < 0) { 2995 print_error(pos, gettext("Error:\t%s\n"), 2996 idmap_stat2string(handle, map_stat)); 2997 print_error_info(&info); 2998 } else 2999 print_info(&info); 3000 idmap_info_free(&info); 3001 3002 cleanup: 3003 if (nm != NULL) 3004 name_mapping_fini(nm); 3005 fini_command(); 3006 return (stat < 0 || map_stat < 0 ? -1 : 0); 3007 } 3008 3009 3010 static int 3011 flags2cred(flag_t *f, char **user, char **passwd, cmd_pos_t *pos) 3012 { 3013 3014 *user = NULL; 3015 *passwd = NULL; 3016 3017 if (f[D_FLAG] == NULL) 3018 return (0); /* GSSAPI authentification => OK */ 3019 3020 *user = strdup(f[D_FLAG]); 3021 if (*user == NULL) { 3022 print_error(pos, gettext("Not enough memory.\n")); 3023 return (-1); 3024 } 3025 3026 /* Password: */ 3027 3028 if (f[j_FLAG] != NULL) { 3029 char line[MAX_INPUT_LINE_SZ]; 3030 int i; 3031 FILE *file = fopen(f[j_FLAG], "r"); 3032 3033 if (file == NULL) { 3034 print_error(pos, 3035 gettext("Failed to open password file \"%s\": (%s)" 3036 ".\n"), f[j_FLAG], strerror(errno)); 3037 goto fail; 3038 } 3039 3040 /* The password is the fist line, we ignore the rest: */ 3041 if (fgets(line, MAX_INPUT_LINE_SZ, file) == NULL) { 3042 print_error(pos, 3043 gettext("The password file \"%s\" is empty.\n"), 3044 f[j_FLAG]); 3045 (void) fclose(file); 3046 goto fail; 3047 } 3048 3049 if (fclose(file) != 0) { 3050 print_error(pos, 3051 gettext("Unable to close the password file \"%s\"" 3052 ".\n"), f[j_FLAG], strerror(errno)); 3053 goto fail; 3054 } 3055 3056 /* Trim the eol: */ 3057 for (i = strlen(line) - 1; 3058 i >= 0 && (line[i] == '\r' || line[i] == '\n'); 3059 i--) 3060 line[i] = '\0'; 3061 3062 *passwd = strdup(line); 3063 if (*passwd == NULL) { 3064 print_error(pos, gettext("Not enough memory.\n")); 3065 goto fail; 3066 } 3067 } else if (!batch_mode) { 3068 /* If in the interactive mode, read the terminal input: */ 3069 char *it = getpassphrase("Enter password:"); 3070 if (it == NULL) { 3071 print_error(NULL, 3072 gettext("Failed to get password (%s).\n"), 3073 strerror(errno)); 3074 goto fail; 3075 } 3076 3077 *passwd = strdup(it); 3078 (void) memset(it, 0, strlen(it)); 3079 3080 if (*passwd == NULL) { 3081 print_error(pos, gettext("Not enough memory.\n")); 3082 goto fail; 3083 } 3084 } else { 3085 print_error(pos, gettext("No password given.\n")); 3086 goto fail; 3087 } 3088 3089 return (0); 3090 fail: 3091 if (*passwd != NULL) { 3092 (void) memset(*passwd, 0, strlen(*passwd)); 3093 free(*passwd); 3094 *passwd = NULL; 3095 } 3096 3097 free(*user); 3098 return (-1); 3099 } 3100 3101 3102 static int 3103 do_set_namemap(flag_t *f, int argc, char **argv, cmd_pos_t *pos) 3104 { 3105 idmap_stat stat; 3106 name_mapping_t *nm; 3107 int is_first_win; 3108 char *user; 3109 char *passwd; 3110 3111 if (argc < 2) { 3112 print_error(pos, 3113 gettext("Not enough arguments: two names needed for a " 3114 "namemap.\n")); 3115 return (-1); 3116 } else if (argc > 2) { 3117 print_error(pos, 3118 gettext("Too many arguments: two names needed for a " 3119 "namemap.\n")); 3120 return (-1); 3121 } 3122 3123 nm = args2nm(&is_first_win, argc, argv, pos); 3124 if (nm == NULL) 3125 return (-1); 3126 3127 if (flags2cred(f, &user, &passwd, pos) < 0) 3128 return (-1); 3129 3130 nm->direction = is_first_win ? IDMAP_DIRECTION_W2U 3131 : IDMAP_DIRECTION_U2W; 3132 3133 idmap_log_stderr(LOG_INFO); 3134 3135 stat = idmap_set_namemap(user, passwd, f[a_FLAG], 3136 nm->windomain, nm->winname, nm->unixname, 3137 nm->is_user, nm->is_wuser, nm->direction); 3138 3139 if (stat != IDMAP_SUCCESS) { 3140 print_error(pos, 3141 gettext("Failed to set namemap (%s).\n"), 3142 idmap_stat2string(NULL, stat)); 3143 } 3144 3145 if (passwd != NULL) { 3146 (void) memset(passwd, 0, strlen(passwd)); 3147 free(passwd); 3148 } 3149 3150 free(user); 3151 3152 name_mapping_fini(nm); 3153 return (stat != IDMAP_SUCCESS ? -1 : 0); 3154 } 3155 3156 static int 3157 do_unset_namemap(flag_t *f, int argc, char **argv, cmd_pos_t *pos) 3158 { 3159 idmap_stat stat; 3160 name_mapping_t *nm; 3161 int is_first_win; 3162 char *user; 3163 char *passwd; 3164 3165 if (argc < 1) { 3166 print_error(pos, 3167 gettext("Not enough arguments: a name needed to unset a " 3168 "namemap.\n")); 3169 return (-1); 3170 } else if (argc > 2) { 3171 print_error(pos, 3172 gettext("Too many arguments: Only target name and type is " 3173 "needed to unset namemap.\n")); 3174 return (-1); 3175 } 3176 3177 nm = args2nm(&is_first_win, 1, argv, pos); 3178 if (nm == NULL) 3179 return (-1); 3180 3181 if (flags2cred(f, &user, &passwd, pos) < 0) 3182 return (-1); 3183 3184 nm->direction = is_first_win ? IDMAP_DIRECTION_W2U 3185 : IDMAP_DIRECTION_U2W; 3186 3187 if (argc > 1 && !is_first_win) { 3188 print_error(pos, 3189 gettext("Target type \"%s\" is redundant.\n"), 3190 argv[1]); 3191 stat = IDMAP_ERR_ARG; 3192 goto cleanup; 3193 } else if (argc > 1) { 3194 switch (string2type(argv[1], pos)) { 3195 case TYPE_INVALID: 3196 name_mapping_fini(nm); 3197 return (-1); 3198 case TYPE_UU: 3199 nm->is_user = IDMAP_YES; 3200 break; 3201 case TYPE_UG: 3202 nm->is_user = IDMAP_NO; 3203 break; 3204 default: 3205 print_error(pos, 3206 gettext("Invalid target type \"%s\": here the " 3207 "possible target type is unixuser or " 3208 "unixgroup.\n"), argv[1]); 3209 stat = IDMAP_ERR_ARG; 3210 goto cleanup; 3211 } 3212 } 3213 3214 idmap_log_stderr(LOG_INFO); 3215 3216 stat = idmap_unset_namemap(user, passwd, f[a_FLAG], 3217 nm->windomain, nm->winname, nm->unixname, 3218 nm->is_user, nm->is_wuser, nm->direction); 3219 3220 if (stat != IDMAP_SUCCESS) { 3221 print_error(pos, 3222 gettext("Failed to unset namemap (%s).\n"), 3223 idmap_stat2string(NULL, stat)); 3224 } 3225 3226 cleanup: 3227 if (passwd != NULL) { 3228 (void) memset(passwd, 0, strlen(passwd)); 3229 free(passwd); 3230 } 3231 3232 free(user); 3233 3234 name_mapping_fini(nm); 3235 return (stat == IDMAP_SUCCESS ? 0 : -1); 3236 } 3237 3238 static int 3239 /* LINTED E_FUNC_ARG_UNUSED */ 3240 do_get_namemap(flag_t *f, int argc, char **argv, cmd_pos_t *pos) 3241 { 3242 idmap_stat stat; 3243 name_mapping_t *nm; 3244 int is_first_win; 3245 int is_source_ad; 3246 char *winname = NULL; 3247 char *unixname = NULL; 3248 char *unixuser = NULL; 3249 char *unixgroup = NULL; 3250 3251 if (argc < 1) { 3252 print_error(pos, 3253 gettext("Not enough arguments: a name needed to get a " 3254 "namemap.\n")); 3255 return (-1); 3256 } else if (argc > 1) { 3257 print_error(pos, 3258 gettext("Too many arguments: just one name needed to get " 3259 "a namemap.\n")); 3260 return (-1); 3261 } 3262 3263 nm = args2nm(&is_first_win, argc, argv, pos); 3264 if (nm == NULL) 3265 return (-1); 3266 3267 nm->direction = is_first_win ? IDMAP_DIRECTION_W2U 3268 : IDMAP_DIRECTION_U2W; 3269 3270 /* nm->is_user is IDMAP_UNKNOWN for IDMAP_DIRECTION_W2U */ 3271 if (nm->is_user == IDMAP_YES) { 3272 unixuser = strdup(nm->unixname); 3273 if (unixuser == NULL) { 3274 print_error(pos, gettext("Not enough memory.\n")); 3275 goto cleanup; 3276 } 3277 } else if (nm->is_user == IDMAP_NO) { 3278 unixgroup = strdup(nm->unixname); 3279 if (unixgroup == NULL) { 3280 print_error(pos, gettext("Not enough memory.\n")); 3281 goto cleanup; 3282 } 3283 } 3284 3285 idmap_log_stderr(LOG_INFO); 3286 3287 stat = idmap_get_namemap(&is_source_ad, &nm->windomain, &nm->winname, 3288 &nm->is_wuser, &unixuser, &unixgroup); 3289 3290 if (stat != IDMAP_SUCCESS) { 3291 print_error(pos, 3292 gettext("Failed to get namemap info (%s).\n"), 3293 idmap_stat2string(NULL, stat)); 3294 goto cleanup; 3295 } 3296 3297 if (nm2winqn(nm, &winname) < 0) 3298 goto cleanup; 3299 3300 switch (is_source_ad) { 3301 case IDMAP_YES: 3302 if (unixuser == NULL && unixgroup == NULL) 3303 (void) printf(gettext("\t\tNo namemap found in AD.\n")); 3304 else { 3305 (void) printf(gettext("AD namemaps for %s\n"), winname); 3306 if (unixuser != NULL) 3307 (void) printf(gettext("\t\t->\t%s:%s\n"), 3308 ID_UNIXUSER, unixuser); 3309 3310 if (unixgroup != NULL) 3311 (void) printf(gettext("\t\t->\t%s:%s\n"), 3312 ID_UNIXGROUP, unixgroup); 3313 } 3314 break; 3315 case IDMAP_NO: 3316 if (nm2unixname(nm, &unixname) < 0) 3317 goto cleanup; 3318 3319 if (nm->winname == NULL) 3320 (void) printf(gettext("\t\tNo namemap found in " 3321 "native LDAP.\n")); 3322 else { 3323 (void) printf(gettext("Native LDAP namemap for %s\n"), 3324 unixname); 3325 (void) printf(gettext("\t\t->\t%s\n"), winname); 3326 } 3327 break; 3328 default: 3329 /* 3330 * This can never happen; the error must be recognized in 3331 * args2nm 3332 */ 3333 print_error(pos, 3334 gettext("Internal error: unknown source of namemaps.\n")); 3335 } 3336 3337 cleanup: 3338 name_mapping_fini(nm); 3339 if (winname != NULL) 3340 free(winname); 3341 if (unixuser != NULL) 3342 free(unixuser); 3343 if (unixgroup != NULL) 3344 free(unixgroup); 3345 return (stat == IDMAP_SUCCESS ? 0 : -1); 3346 } 3347 3348 3349 3350 /* main function. Returns 1 for error, 0 otherwise */ 3351 int 3352 main(int argc, char *argv[]) 3353 { 3354 int rc; 3355 3356 /* set locale and domain for internationalization */ 3357 (void) setlocale(LC_ALL, ""); 3358 (void) textdomain(TEXT_DOMAIN); 3359 3360 /* idmap_engine determines the batch_mode: */ 3361 rc = engine_init(sizeof (commands) / sizeof (cmd_ops_t), 3362 commands, 3363 argc - 1, 3364 argv + 1, 3365 &batch_mode); 3366 3367 if (rc < 0) { 3368 (void) engine_fini(); 3369 if (rc == IDMAP_ENG_ERROR_SILENT) 3370 help(); 3371 return (1); 3372 } 3373 3374 udt_used = 0; 3375 if (batch_mode) { 3376 if (init_udt_batch() < 0) 3377 return (1); 3378 } 3379 3380 rc = run_engine(argc - 1, argv + 1); 3381 3382 if (batch_mode) { 3383 batch_mode = 0; 3384 if (fini_udt_command(rc == 0 ? 1 : 0, NULL)) 3385 rc = -1; 3386 } 3387 3388 (void) engine_fini(); 3389 return (rc == 0 ? 0 : 1); 3390 } 3391