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