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 /* 23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 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]\n" 459 " [-j passwdfile] name1 name2\n" 460 "idmap show [-c] [-v] identity [targettype]\n" 461 "idmap unset-namemap [-a authenticationMethod] [-D bindDN]\n" 462 " [-j passwdfile] name [targettype]\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 * Convert pid from string to it's numerical representation. If it is 1611 * a valid string, i.e. number of a proper length, return 1. Otherwise 1612 * print an error message and return 0. 1613 */ 1614 static int 1615 pid_convert(char *string, uid_t *number, int type, cmd_pos_t *pos) 1616 { 1617 int i; 1618 long long ll; 1619 char *type_string; 1620 size_t len = strlen(string); 1621 1622 if (type == TYPE_GID) 1623 type_string = ID_GID; 1624 else if (type == TYPE_UID) 1625 type_string = ID_UID; 1626 else 1627 return (0); 1628 1629 for (i = 0; i < len; i++) { 1630 if (!isdigit(string[i])) { 1631 print_error(pos, 1632 gettext("\"%s\" is not a valid %s: the non-digit" 1633 " character '%c' found.\n"), string, 1634 type_string, string[i]); 1635 return (0); 1636 } 1637 } 1638 1639 ll = atoll(string); 1640 1641 /* Isn't it too large? */ 1642 if (type == TYPE_UID && (uid_t)ll != ll || 1643 type == TYPE_GID && (gid_t)ll != ll) { 1644 print_error(pos, 1645 gettext("%llu: too large for a %s.\n"), ll, 1646 type_string); 1647 return (0); 1648 } 1649 1650 *number = (uid_t)ll; 1651 return (1); 1652 } 1653 1654 /* 1655 * Convert SID from string to prefix and rid. If it has a valid 1656 * format, i.e. S(\-\d+)+, return 1. Otherwise print an error 1657 * message and return 0. 1658 */ 1659 static int 1660 sid_convert(char *from, char **prefix, idmap_rid_t *rid, cmd_pos_t *pos) 1661 { 1662 int i, j; 1663 char *cp; 1664 char *ecp; 1665 char *prefix_end; 1666 u_longlong_t a; 1667 unsigned long r; 1668 1669 if (strcmp_no0(from, "S-1-") != 0) { 1670 print_error(pos, 1671 gettext("Invalid %s \"%s\": it doesn't start " 1672 "with \"%s\".\n"), ID_SID, from, "S-1-"); 1673 return (0); 1674 } 1675 1676 if (strlen(from) <= strlen("S-1-")) { 1677 print_error(pos, 1678 gettext("Invalid %s \"%s\": the authority and RID parts are" 1679 " missing.\n"), 1680 ID_SID, from); 1681 return (0); 1682 } 1683 1684 /* count '-'s */ 1685 for (j = 0, cp = strchr(from, '-'); 1686 cp != NULL; 1687 j++, cp = strchr(cp + 1, '-')) { 1688 /* can't end on a '-' */ 1689 if (*(cp + 1) == '\0') { 1690 print_error(pos, 1691 gettext("Invalid %s \"%s\": '-' at the end.\n"), 1692 ID_SID, from); 1693 return (0); 1694 } else if (*(cp + 1) == '-') { 1695 print_error(pos, 1696 gettext("Invalid %s \"%s\": double '-'.\n"), 1697 ID_SID, from); 1698 return (0); 1699 } 1700 } 1701 1702 1703 /* check that we only have digits and '-' */ 1704 i = strspn(from + 1, "0123456789-") + 1; 1705 if (i < strlen(from)) { 1706 print_error(pos, 1707 gettext("Invalid %s \"%s\": invalid character '%c'.\n"), 1708 ID_SID, from, from[i]); 1709 return (0); 1710 } 1711 1712 1713 cp = from + strlen("S-1-"); 1714 1715 /* 64-bit safe parsing of unsigned 48-bit authority value */ 1716 errno = 0; 1717 a = strtoull(cp, &ecp, 10); 1718 1719 /* errors parsing the authority or too many bits */ 1720 if (cp == ecp || (a == 0 && errno == EINVAL)) { 1721 print_error(pos, 1722 gettext("Invalid %s \"%s\": unable to parse the " 1723 "authority \"%.*s\".\n"), ID_SID, from, ecp - cp, 1724 cp); 1725 return (0); 1726 } 1727 1728 if ((a == ULLONG_MAX && errno == ERANGE) || 1729 (a & 0x0000ffffffffffffULL) != a) { 1730 print_error(pos, 1731 gettext("Invalid %s \"%s\": the authority " 1732 "\"%.*s\" is too large.\n"), ID_SID, from, 1733 ecp - cp, cp); 1734 return (0); 1735 } 1736 1737 cp = ecp; 1738 1739 if (j < 3) { 1740 print_error(pos, 1741 gettext("Invalid %s \"%s\": must have at least one RID.\n"), 1742 ID_SID, from); 1743 return (0); 1744 } 1745 1746 for (i = 2; i < j; i++) { 1747 if (*cp++ != '-') { 1748 /* Should never happen */ 1749 print_error(pos, 1750 gettext("Invalid %s \"%s\": internal error:" 1751 " '-' missing.\n"), 1752 ID_SID, from); 1753 return (0); 1754 } 1755 /* 32-bit safe parsing of unsigned 32-bit RID */ 1756 errno = 0; 1757 r = strtoul(cp, &ecp, 10); 1758 1759 /* errors parsing the RID */ 1760 if (cp == ecp || (r == 0 && errno == EINVAL)) { 1761 /* should never happen */ 1762 print_error(pos, 1763 gettext("Invalid %s \"%s\": internal error: " 1764 "unable to parse the RID " 1765 "after \"%.*s\".\n"), ID_SID, 1766 from, cp - from, from); 1767 return (0); 1768 } 1769 1770 if (r == ULONG_MAX && errno == ERANGE) { 1771 print_error(pos, 1772 gettext("Invalid %s \"%s\": the RID \"%.*s\"" 1773 " is too large.\n"), ID_SID, 1774 from, ecp - cp, cp); 1775 return (0); 1776 } 1777 prefix_end = cp; 1778 cp = ecp; 1779 } 1780 1781 /* check that all of the string SID has been consumed */ 1782 if (*cp != '\0') { 1783 /* Should never happen */ 1784 print_error(pos, 1785 gettext("Invalid %s \"%s\": internal error: " 1786 "something is still left.\n"), 1787 ID_SID, from); 1788 return (0); 1789 } 1790 1791 *rid = (idmap_rid_t)r; 1792 1793 /* -1 for the '-' at the end: */ 1794 *prefix = strndup(from, prefix_end - from - 1); 1795 if (*prefix == NULL) { 1796 print_error(pos, 1797 "%s.\n", strerror(ENOMEM)); 1798 return (0); 1799 } 1800 1801 return (1); 1802 } 1803 1804 /* Does the line start with USERMAP_CFG IP qualifier? */ 1805 static int 1806 ucp_is_IP_qualifier(char *line) 1807 { 1808 char *it; 1809 it = line + strcspn(line, " \t\n#:"); 1810 return (*(it + 1) == ':' ? 1 : 0); 1811 } 1812 1813 1814 /* 1815 * returns interior of quotation marks in USERMAP_CFG. In this format, 1816 * there cannot be a protected quotation mark inside. 1817 */ 1818 static char * 1819 ucp_qm_interior(char **line, cmd_pos_t *pos) 1820 { 1821 char *out; 1822 char *qm = strchr(*line + 1, '"'); 1823 if (qm == NULL) { 1824 print_error(pos, 1825 gettext("Unclosed quotations\n")); 1826 return (NULL); 1827 } 1828 1829 out = strndup(*line + 1, qm - *line - 1); 1830 *line = qm + 1; 1831 return (out); 1832 } 1833 1834 /* 1835 * Grab next token from the line in USERMAP_CFG format. terminators, 1836 * the 3rd parameter, contains all the characters which can terminate 1837 * the token. line_num is the line number of input used for error 1838 * reporting. 1839 */ 1840 static char * 1841 ucp_grab_token(char **line, cmd_pos_t *pos, const char *terminators) 1842 { 1843 char *token; 1844 if (**line == '"') 1845 token = ucp_qm_interior(line, pos); 1846 else { 1847 int length = strcspn(*line, terminators); 1848 token = strndup(*line, length); 1849 *line += length; 1850 } 1851 1852 return (token); 1853 } 1854 1855 1856 /* 1857 * Convert a line in usermap.cfg format to name_mapping. 1858 * 1859 * Return values: -1 for error, 0 for empty line, 1 for a mapping 1860 * found. 1861 */ 1862 static int 1863 ucp_line2nm(char *line, cmd_pos_t *pos, name_mapping_t *nm) 1864 { 1865 char *it; 1866 char *token; 1867 char *token2; 1868 char separator; 1869 int is_direction = 0; 1870 1871 it = line + strspn(line, " \t\n"); 1872 1873 /* empty or comment lines are OK: */ 1874 if (*it == '\0' || *it == '#') 1875 return (0); 1876 1877 /* We do not support network qualifiers */ 1878 if (ucp_is_IP_qualifier(it)) { 1879 print_error(pos, 1880 gettext("Unable to handle network qualifier.\n")); 1881 return (-1); 1882 } 1883 1884 /* The windows name: */ 1885 token = ucp_grab_token(&it, pos, " \t#\\\n@=<"); 1886 if (token == NULL) 1887 return (-1); 1888 1889 separator = *it; 1890 1891 /* Didn't we bump to the end of line? */ 1892 if (separator == '\0' || separator == '#') { 1893 free(token); 1894 print_error(pos, 1895 gettext("UNIX_name not found.\n")); 1896 return (-1); 1897 } 1898 1899 /* Do we have a domainname? */ 1900 if (separator == '\\' || separator == '@') { 1901 it ++; 1902 token2 = ucp_grab_token(&it, pos, " \t\n#"); 1903 if (token2 == NULL) { 1904 free(token); 1905 return (-1); 1906 } else if (*it == '\0' || *it == '#') { 1907 free(token); 1908 free(token2); 1909 print_error(pos, 1910 gettext("UNIX_name not found.\n")); 1911 } 1912 1913 if (separator == '\\') { 1914 nm->windomain = token; 1915 nm->winname = token2; 1916 nm->is_nt4 = 1; 1917 } else { 1918 nm->windomain = token2; 1919 nm->winname = token; 1920 nm->is_nt4 = 0; 1921 1922 } 1923 } else { 1924 nm->windomain = NULL; 1925 nm->winname = token; 1926 nm->is_nt4 = 0; 1927 } 1928 1929 1930 it = it + strspn(it, " \t\n"); 1931 1932 /* Direction string is optional: */ 1933 if (strncmp(it, "==", 2) == 0) { 1934 nm->direction = IDMAP_DIRECTION_BI; 1935 is_direction = 1; 1936 } else if (strncmp(it, "<=", 2) == 0) { 1937 nm->direction = IDMAP_DIRECTION_U2W; 1938 is_direction = 1; 1939 } else if (strncmp(it, "=>", 2) == 0) { 1940 nm->direction = IDMAP_DIRECTION_W2U; 1941 is_direction = 1; 1942 } else { 1943 nm->direction = IDMAP_DIRECTION_BI; 1944 is_direction = 0; 1945 } 1946 1947 if (is_direction) { 1948 it += 2; 1949 it += strspn(it, " \t\n"); 1950 1951 if (*it == '\0' || *it == '#') { 1952 print_error(pos, 1953 gettext("UNIX_name not found.\n")); 1954 return (-1); 1955 } 1956 } 1957 1958 /* Now unixname: */ 1959 it += strspn(it, " \t\n"); 1960 token = ucp_grab_token(&it, pos, " \t\n#"); 1961 1962 if (token == NULL) 1963 /* nm->winname to be freed by name_mapping_fini */ 1964 return (-1); 1965 1966 /* Neither here we support IP qualifiers */ 1967 if (ucp_is_IP_qualifier(token)) { 1968 print_error(pos, 1969 gettext("Unable to handle network qualifier.\n")); 1970 free(token); 1971 return (-1); 1972 } 1973 1974 nm->unixname = token; 1975 1976 it += strspn(it, " \t\n"); 1977 1978 /* Does something remain on the line */ 1979 if (*it != '\0' && *it != '#') { 1980 print_error(pos, 1981 gettext("Unrecognized parameters \"%s\".\n"), it); 1982 return (-1); 1983 } 1984 1985 return (1); 1986 } 1987 1988 /* 1989 * Parse SMBUSERS line to name_mapping_t. if line is NULL, then 1990 * pasrsing of the previous line is continued. line_num is input line 1991 * number used for error reporting. 1992 * Return values: 1993 * rc -1: error 1994 * rc = 0: mapping found and the line is finished, 1995 * rc = 1: mapping found and there remains other on the line 1996 */ 1997 static int 1998 sup_line2nm(char *line, cmd_pos_t *pos, name_mapping_t *nm) 1999 { 2000 static char *ll = NULL; 2001 static char *unixname = NULL; 2002 static size_t unixname_l = 0; 2003 char *token; 2004 2005 if (line != NULL) { 2006 ll = line; 2007 2008 unixname = ll += strspn(ll, " \t"); 2009 if (*ll == '\0' || *ll == '#') 2010 return (0); 2011 2012 unixname_l = strcspn(ll, " \t:=#\n"); 2013 ll += unixname_l; 2014 2015 if (*ll == '\0'|| *ll == '#') 2016 return (0); 2017 2018 ll += strspn(ll, " \t:=#\n"); 2019 2020 } 2021 2022 if (*ll == '\0'|| *ll == '#') 2023 return (0); 2024 2025 token = ucp_grab_token(&ll, pos, " \t\n"); 2026 if (token == NULL) 2027 return (-1); 2028 2029 nm->is_nt4 = 0; 2030 nm->direction = IDMAP_DIRECTION_W2U; 2031 2032 nm->windomain = NULL; 2033 nm->winname = token; 2034 nm->unixname = strndup(unixname, unixname_l); 2035 if (nm->unixname == NULL) 2036 return (-1); 2037 2038 ll += strspn(ll, " \t\n"); 2039 return (1); 2040 } 2041 2042 /* Parse line to name_mapping_t. Basicaly just a format switch. */ 2043 static int 2044 line2nm(char *line, cmd_pos_t *pos, name_mapping_t *nm, format_t f) 2045 { 2046 switch (f) { 2047 case USERMAP_CFG: 2048 if (line == NULL) 2049 return (0); 2050 else 2051 return (ucp_line2nm(line, pos, nm)); 2052 case SMBUSERS: 2053 return (sup_line2nm(line, pos, nm)); 2054 default: 2055 /* This can never happen */ 2056 print_error(pos, 2057 gettext("Internal error: invalid line format.\n")); 2058 } 2059 2060 return (-1); 2061 } 2062 2063 2064 /* Examine -f flag and return the appropriate format_t */ 2065 static format_t 2066 ff2format(char *ff, int is_mandatory) 2067 { 2068 2069 if (ff == NULL && is_mandatory) { 2070 print_error(NULL, gettext("Format not given.\n")); 2071 return (UNDEFINED_FORMAT); 2072 } 2073 2074 if (ff == NULL) 2075 return (DEFAULT_FORMAT); 2076 2077 if (strcasecmp(ff, "usermap.cfg") == 0) 2078 return (USERMAP_CFG); 2079 2080 if (strcasecmp(ff, "smbusers") == 0) 2081 return (SMBUSERS); 2082 2083 print_error(NULL, 2084 gettext("The only known formats are: \"usermap.cfg\" and " 2085 "\"smbusers\".\n")); 2086 return (UNDEFINED_FORMAT); 2087 } 2088 2089 /* Delete all namerules of the given type */ 2090 static int 2091 flush_nm(boolean_t is_user, cmd_pos_t *pos) 2092 { 2093 idmap_stat stat; 2094 2095 stat = idmap_udt_flush_namerules(udt); 2096 if (stat < 0) { 2097 print_error(pos, 2098 is_user ? gettext("Unable to flush users (%s).\n") 2099 : gettext("Unable to flush groups (%s).\n"), 2100 idmap_stat2string(stat)); 2101 return (-1); 2102 } 2103 2104 if (positions_add(pos) < 0) 2105 return (-1); 2106 2107 return (0); 2108 } 2109 2110 /* import command handler */ 2111 static int 2112 /* LINTED E_FUNC_ARG_UNUSED */ 2113 do_import(flag_t *f, int argc, char **argv, cmd_pos_t *pos) 2114 { 2115 name_mapping_t *nm; 2116 cmd_pos_t pos2; 2117 char line[MAX_INPUT_LINE_SZ]; 2118 format_t format; 2119 int rc = 0; 2120 idmap_stat stat; 2121 FILE *file = NULL; 2122 2123 if (batch_mode) { 2124 print_error(pos, 2125 gettext("Import is not allowed in the batch mode.\n")); 2126 return (-1); 2127 } 2128 2129 format = ff2format(argv[0], 1); 2130 if (format == UNDEFINED_FORMAT) 2131 return (-1); 2132 2133 if (init_udt_command()) 2134 return (-1); 2135 2136 /* We don't flush groups in the usermap.cfg nor smbusers format */ 2137 if (f[F_FLAG] != NULL && 2138 flush_nm(B_TRUE, pos) < 0 && 2139 (format == USERMAP_CFG || format == SMBUSERS || 2140 flush_nm(B_FALSE, pos) < 0)) { 2141 rc = -1; 2142 goto cleanup; 2143 } 2144 2145 /* Where we import from? */ 2146 if (f[f_FLAG] == NULL) 2147 file = stdin; 2148 else { 2149 file = fopen(f[f_FLAG], "r"); 2150 if (file == NULL) { 2151 perror(f[f_FLAG]); 2152 goto cleanup; 2153 } 2154 } 2155 2156 pos2.linenum = 0; 2157 pos2.line = line; 2158 2159 while (fgets(line, MAX_INPUT_LINE_SZ, file)) { 2160 char *line2 = line; 2161 pos2.linenum++; 2162 2163 /* 2164 * In SMBUSERS format there can be more mappings on 2165 * each line. So we need the internal cycle for each line. 2166 */ 2167 do { 2168 nm = name_mapping_init(); 2169 if (nm == NULL) { 2170 rc = -1; 2171 goto cleanup; 2172 } 2173 2174 rc = line2nm(line2, &pos2, nm, format); 2175 line2 = NULL; 2176 2177 if (rc < 1) { 2178 name_mapping_fini(nm); 2179 break; 2180 } 2181 2182 stat = idmap_udt_add_namerule(udt, nm->windomain, 2183 nm->is_user ? B_TRUE : B_FALSE, 2184 nm->is_wuser ? B_TRUE : B_FALSE, 2185 nm->winname, 2186 nm->unixname, nm->is_nt4, nm->direction); 2187 if (stat < 0) { 2188 print_error(&pos2, 2189 gettext("Transaction error (%s)\n"), 2190 idmap_stat2string(stat)); 2191 rc = -1; 2192 } 2193 2194 if (rc >= 0) 2195 rc = positions_add(&pos2); 2196 2197 name_mapping_fini(nm); 2198 2199 } while (rc >= 0); 2200 2201 if (rc < 0) { 2202 print_error(NULL, 2203 gettext("Import canceled.\n")); 2204 break; 2205 } 2206 } 2207 2208 cleanup: 2209 if (fini_udt_command((rc < 0 ? 0 : 1), pos)) 2210 rc = -1; 2211 if (file != NULL && file != stdin) 2212 (void) fclose(file); 2213 return (rc); 2214 } 2215 2216 2217 /* 2218 * List name mappings in the format specified. list_users / 2219 * list_groups determine which type to list. The output goes to the 2220 * file fi. 2221 */ 2222 static int 2223 list_name_mappings(format_t format, FILE *fi) 2224 { 2225 idmap_stat stat; 2226 idmap_iter_t *ihandle; 2227 name_mapping_t *nm; 2228 boolean_t is_user; 2229 boolean_t is_wuser; 2230 print_handle_t *ph; 2231 2232 stat = idmap_iter_namerules(NULL, 0, 0, NULL, NULL, &ihandle); 2233 if (stat < 0) { 2234 print_error(NULL, 2235 gettext("Iteration handle not obtained (%s)\n"), 2236 idmap_stat2string(stat)); 2237 idmap_iter_destroy(ihandle); 2238 return (-1); 2239 } 2240 2241 ph = print_mapping_init(format, fi); 2242 if (ph == NULL) 2243 return (-1); 2244 2245 do { 2246 nm = name_mapping_init(); 2247 if (nm == NULL) { 2248 idmap_iter_destroy(ihandle); 2249 return (-1); 2250 } 2251 2252 stat = idmap_iter_next_namerule(ihandle, &nm->windomain, 2253 &nm->winname, &nm->unixname, &is_user, &is_wuser, 2254 &nm->is_nt4, &nm->direction); 2255 if (stat >= 0) { 2256 nm->is_user = is_user ? IDMAP_YES : IDMAP_NO; 2257 nm->is_wuser = is_wuser ? IDMAP_YES : IDMAP_NO; 2258 (void) print_mapping(ph, nm); 2259 } 2260 2261 name_mapping_fini(nm); 2262 2263 } while (stat > 0); 2264 2265 (void) print_mapping_fini(ph); 2266 2267 if (stat < 0 && stat != IDMAP_ERR_NOTFOUND) { 2268 print_error(NULL, 2269 gettext("Error during iteration (%s)\n"), 2270 idmap_stat2string(stat)); 2271 idmap_iter_destroy(ihandle); 2272 return (-1); 2273 } 2274 2275 idmap_iter_destroy(ihandle); 2276 return (0); 2277 } 2278 2279 /* Export command handler */ 2280 static int 2281 /* LINTED E_FUNC_ARG_UNUSED */ 2282 do_export(flag_t *f, int argc, char **argv, cmd_pos_t *pos) 2283 { 2284 int rc; 2285 format_t format; 2286 FILE *fi; 2287 2288 format = ff2format(argv[0], 1); 2289 if (format == UNDEFINED_FORMAT) 2290 return (-1); 2291 2292 /* Where do we output to? */ 2293 if (f[f_FLAG] == NULL) 2294 fi = stdout; 2295 else { 2296 fi = fopen(f[f_FLAG], "w"); 2297 if (fi == NULL) { 2298 perror(f[f_FLAG]); 2299 return (-1); 2300 } 2301 } 2302 2303 /* List the requested types: */ 2304 rc = list_name_mappings(format, fi); 2305 2306 cleanup: 2307 if (fi != NULL && fi != stdout) 2308 (void) fclose(fi); 2309 return (rc); 2310 } 2311 2312 /* List command handler */ 2313 static int 2314 /* LINTED E_FUNC_ARG_UNUSED */ 2315 do_list_name_mappings(flag_t *f, int argc, char **argv, cmd_pos_t *pos) 2316 { 2317 int rc; 2318 2319 /* List the requested types: */ 2320 rc = list_name_mappings(DEFAULT_FORMAT, stdout); 2321 2322 return (rc); 2323 } 2324 2325 /* This is just a debug function for dumping flags */ 2326 static void 2327 print_flags(flag_t *f) 2328 { 2329 int c; 2330 for (c = 0; c < FLAG_ALPHABET_SIZE; c++) { 2331 if (f[c] == FLAG_SET) 2332 (void) printf("FLAG: -%c, VALUE: %p\n", c, 2333 (void *) f[c]); 2334 else if (f[c]) 2335 (void) printf("FLAG: -%c, VALUE: %s\n", c, f[c]); 2336 } 2337 } 2338 2339 /* Convert string like sid or winname to the identity type code */ 2340 2341 static int 2342 string2type(char *str, cmd_pos_t *pos) { 2343 int i; 2344 int code = TYPE_INVALID; 2345 2346 for (i = 0; i < sizeof (identity2code) / sizeof (id_code_t); i++) { 2347 if (strcasecmp(identity2code[i].identity, str) == 0) { 2348 code = identity2code[i].code; 2349 break; 2350 } 2351 } 2352 2353 if (code == TYPE_INVALID) { 2354 print_error(pos, 2355 gettext("Error: invalid identity type \"%s\"\n"), str); 2356 } 2357 2358 return (code); 2359 } 2360 2361 2362 2363 2364 /* 2365 * Split argument to its identity code and a name part 2366 * return values: 2367 * TYPE_INVALID for unknown identity 2368 * TYPE_AUTO for no identity (to be autodetected) 2369 * <TYPE_XXX> for known identity 2370 */ 2371 2372 static int 2373 get_identity(char *arg, char **name, cmd_pos_t *pos) 2374 { 2375 char *it; 2376 int code = TYPE_INVALID; 2377 2378 if ((it = strchr(arg, ':')) == NULL) { 2379 *name = arg; 2380 return (TYPE_AUTO); 2381 } 2382 2383 2384 *it = '\0'; 2385 code = string2type(arg, pos); 2386 *it = ':'; /* restore the original string: */ 2387 2388 *name = it + 1; 2389 return (code); 2390 } 2391 2392 /* 2393 * This function splits name to the relevant pieces: is_user, winname, 2394 * windomain unixname. E.g. for winname, it strdups nm->winname and possibly 2395 * nm->windomain and return TYPE_WN. 2396 * 2397 * If there is already one of the text fields allocated, it is OK. 2398 * Return values: 2399 * -1 ... syntax error 2400 * 0 ... it wasnt possible to determine 2401 * <TYPE_XXX> otherwise 2402 */ 2403 2404 static int 2405 name2parts(char *name, name_mapping_t *nm, cmd_pos_t *pos) 2406 { 2407 char *it; 2408 int code; 2409 2410 code = get_identity(name, &it, pos); 2411 2412 switch (code) { 2413 case TYPE_INVALID: 2414 /* syntax error: */ 2415 return (-1); 2416 case TYPE_AUTO: 2417 /* autodetection: */ 2418 if (nm->winname != NULL && nm->is_wuser != IDMAP_UNKNOWN) 2419 code = nm->is_wuser == IDMAP_YES ? TYPE_UU : TYPE_UG; 2420 else if (nm->unixname != NULL || 2421 strchr(name, '@') != NULL || 2422 strchr(name, '\\') != NULL) 2423 /* btw, nm->is_user can never be IDMAP_UNKNOWN here */ 2424 code = TYPE_WN; 2425 else 2426 return (0); 2427 /* If the code was guessed succesfully, we are OK. */ 2428 break; 2429 default: 2430 name = it; 2431 } 2432 2433 if (code & IS_WIN) { 2434 if (code & IS_USER) 2435 nm->is_wuser = IDMAP_YES; 2436 else if (code & IS_GROUP) 2437 nm->is_wuser = IDMAP_NO; 2438 } else { 2439 if (code & IS_USER) 2440 nm->is_user = IDMAP_YES; 2441 else if (code & IS_GROUP) 2442 nm->is_user = IDMAP_NO; 2443 } 2444 2445 if (code & IS_WIN && code & IS_NAME) { 2446 if (nm->winname != NULL || nm->windomain != NULL) 2447 return (code); 2448 2449 if ((it = strchr(name, '@')) != NULL) { 2450 int length = it - name + 1; 2451 nm->winname = (char *)malloc(length); 2452 (void) strncpy(nm->winname, name, length - 1); 2453 nm->winname[length - 1] = '\0'; 2454 nm->windomain = strdup(it + 1); 2455 } else if ((it = strrchr(name, '\\')) != NULL) { 2456 int length = it - name + 1; 2457 nm->windomain = (char *)malloc(length); 2458 (void) strncpy(nm->windomain, name, length - 1); 2459 nm->windomain[length - 1] = '\0'; 2460 nm->winname = strdup(it + 1); 2461 nm->is_nt4 = B_TRUE; 2462 } else 2463 nm->winname = strdup(name); 2464 2465 return (code); 2466 } 2467 2468 2469 if (!(code & IS_WIN) && code & IS_NAME) { 2470 if (nm->unixname != NULL) 2471 return (code); 2472 2473 if (strlen(name) == 0) 2474 nm->unixname = strdup("\"\""); 2475 else 2476 nm->unixname = strdup(name); 2477 return (code); 2478 } 2479 2480 2481 if (code & IS_WIN && !(code & IS_NAME)) { 2482 if (!sid_convert(name, &nm->sidprefix, &nm->rid, pos)) 2483 return (-1); 2484 else 2485 return (code); 2486 } 2487 2488 /* 2489 * it is (!(code & TYPE_WIN) && !(code & TYPE_NAME)) here - the other 2490 * possiblities are exhausted. 2491 */ 2492 2493 if (!pid_convert(name, &nm->pid, code, pos)) 2494 return (-1); 2495 else 2496 return (code); 2497 2498 } 2499 2500 /* 2501 * Cycle through add/remove arguments until they are identified or found 2502 * invalid. 2503 */ 2504 static 2505 name_mapping_t * 2506 args2nm(int *is_first_win, int argc, char **argv, 2507 cmd_pos_t *pos) 2508 { 2509 int code; 2510 int i; 2511 name_mapping_t *nm; 2512 2513 nm = name_mapping_init(); 2514 if (nm == NULL) 2515 return (NULL); 2516 2517 for (i = 0; i < 2 * argc - 1; i++) { 2518 code = name2parts(argv[i % 2], nm, pos); 2519 switch (code) { 2520 case -1: 2521 goto fail; 2522 case 0: 2523 if (i > 0) { 2524 print_error(pos, 2525 gettext("Missing identity type" 2526 " cannot be determined for %s.\n"), 2527 argv[i % 2]); 2528 goto fail; 2529 } 2530 break; 2531 default: 2532 if (!(code & IS_NAME)) { 2533 print_error(pos, 2534 gettext("%s is not a valid name\n"), 2535 argv[i % 2]); 2536 goto fail; 2537 } 2538 } 2539 } 2540 2541 if (argc == 2 && nm->winname == NULL) { 2542 print_error(pos, gettext("No windows identity found.\n")); 2543 goto fail; 2544 } 2545 if (argc == 2 && nm->unixname == NULL) { 2546 print_error(pos, gettext("No unix identity found.\n")); 2547 goto fail; 2548 } 2549 if (argc == 1 && nm->winname == NULL && nm->unixname == NULL) { 2550 print_error(pos, gettext("No identity type determined.\n")); 2551 goto fail; 2552 } 2553 2554 if (is_first_win != NULL) 2555 *is_first_win = code & IS_WIN; 2556 return (nm); 2557 fail: 2558 name_mapping_fini(nm); 2559 return (NULL); 2560 } 2561 2562 2563 2564 /* add command handler. */ 2565 static int 2566 do_add_name_mapping(flag_t *f, int argc, char **argv, cmd_pos_t *pos) 2567 { 2568 name_mapping_t *nm; 2569 int rc = 0; 2570 int is_first_win; 2571 idmap_stat stat; 2572 int is_wuser; 2573 print_handle_t *ph; 2574 2575 2576 2577 /* Exactly two arguments must be specified */ 2578 if (argc < 2) { 2579 print_error(pos, gettext("Not enough arguments.\n")); 2580 return (-1); 2581 } else if (argc > 2) { 2582 print_error(pos, gettext("Too many arguments.\n")); 2583 return (-1); 2584 } 2585 2586 nm = args2nm(&is_first_win, argc, argv, pos); 2587 if (nm == NULL) 2588 return (-1); 2589 2590 if (f[d_FLAG] != NULL) 2591 nm->direction = is_first_win 2592 ? IDMAP_DIRECTION_W2U 2593 : IDMAP_DIRECTION_U2W; 2594 else 2595 nm->direction = IDMAP_DIRECTION_BI; 2596 2597 /* Now let us write it: */ 2598 2599 if (init_udt_command()) { 2600 name_mapping_fini(nm); 2601 return (-1); 2602 } 2603 2604 for (is_wuser = IDMAP_YES; is_wuser >= IDMAP_NO; is_wuser--) { 2605 /* nm->is_wuser can be IDMAP_YES, IDMAP_NO or IDMAP_UNKNOWN */ 2606 if ((is_wuser == IDMAP_YES && nm->is_wuser == IDMAP_NO) || 2607 (is_wuser == IDMAP_NO && nm->is_wuser == IDMAP_YES)) 2608 continue; 2609 2610 stat = idmap_udt_add_namerule(udt, nm->windomain, 2611 nm->is_user ? B_TRUE : B_FALSE, 2612 is_wuser ? B_TRUE : B_FALSE, 2613 nm->winname, nm->unixname, nm->is_nt4, nm->direction); 2614 } 2615 2616 /* We echo the mapping */ 2617 ph = print_mapping_init(DEFAULT_FORMAT, stdout); 2618 if (ph == NULL) { 2619 rc = -1; 2620 goto cleanup; 2621 } 2622 (void) print_mapping(ph, nm); 2623 (void) print_mapping_fini(ph); 2624 2625 if (stat != IDMAP_SUCCESS) { 2626 print_error(pos, 2627 gettext("Mapping not created (%s)\n"), 2628 idmap_stat2string(stat)); 2629 rc = -1; 2630 } 2631 2632 if (rc == 0) 2633 rc = positions_add(pos); 2634 2635 cleanup: 2636 name_mapping_fini(nm); 2637 if (fini_udt_command(1, pos)) 2638 rc = -1; 2639 return (rc); 2640 } 2641 2642 /* remove command handler */ 2643 static int 2644 do_remove_name_mapping(flag_t *f, int argc, char **argv, cmd_pos_t *pos) 2645 { 2646 name_mapping_t *nm; 2647 int rc = 0; 2648 idmap_stat stat; 2649 int is_first_win; 2650 int is_wuser; 2651 2652 /* "-a" means we flush all of them */ 2653 if (f[a_FLAG] != NULL) { 2654 if (argc) { 2655 print_error(pos, 2656 gettext("Too many arguments.\n")); 2657 return (-1); 2658 } 2659 2660 if (init_udt_command()) 2661 return (-1); 2662 rc = flush_nm(B_TRUE, pos); 2663 2664 if (rc >= 0) 2665 rc = flush_nm(B_FALSE, pos); 2666 2667 if (fini_udt_command(rc ? 0 : 1, pos)) 2668 rc = -1; 2669 return (rc); 2670 } 2671 2672 /* Contrary to add_name_mapping, we can have only one argument */ 2673 if (argc < 1) { 2674 print_error(pos, gettext("Not enough arguments.\n")); 2675 return (-1); 2676 } else if (argc > 2) { 2677 print_error(pos, gettext("Too many arguments.\n")); 2678 return (-1); 2679 } else if ( 2680 /* both -f and -t: */ 2681 f[f_FLAG] != NULL && f[t_FLAG] != NULL || 2682 /* -d with a single argument: */ 2683 argc == 1 && f[d_FLAG] != NULL || 2684 /* -f or -t with two arguments: */ 2685 argc == 2 && (f[f_FLAG] != NULL || f[t_FLAG] != NULL)) { 2686 print_error(pos, 2687 gettext("Direction ambiguous.\n")); 2688 return (-1); 2689 } 2690 2691 2692 /* 2693 * Similar to do_add_name_mapping - see the comments 2694 * there. Except we may have only one argument here. 2695 */ 2696 nm = args2nm(&is_first_win, argc, argv, pos); 2697 if (nm == NULL) 2698 return (-1); 2699 2700 /* 2701 * If the direction is not specified by a -d/-f/-t flag, then it 2702 * is IDMAP_DIRECTION_UNDEF, because in that case we want to 2703 * remove any mapping. If it was IDMAP_DIRECTION_BI, idmap_api would 2704 * delete a bidirectional one only. 2705 */ 2706 if (f[d_FLAG] != NULL || f[f_FLAG] != NULL) 2707 nm->direction = is_first_win 2708 ? IDMAP_DIRECTION_W2U 2709 : IDMAP_DIRECTION_U2W; 2710 else if (f[t_FLAG] != NULL) 2711 nm->direction = is_first_win 2712 ? IDMAP_DIRECTION_U2W 2713 : IDMAP_DIRECTION_W2U; 2714 else 2715 nm->direction = IDMAP_DIRECTION_UNDEF; 2716 2717 if (init_udt_command()) { 2718 name_mapping_fini(nm); 2719 return (-1); 2720 } 2721 2722 for (is_wuser = IDMAP_YES; is_wuser >= IDMAP_NO; is_wuser--) { 2723 if ((is_wuser == IDMAP_YES && nm->is_wuser == IDMAP_NO) || 2724 (is_wuser == IDMAP_NO && nm->is_wuser == IDMAP_YES)) 2725 continue; 2726 2727 stat = idmap_udt_rm_namerule(udt, 2728 nm->is_user ? B_TRUE : B_FALSE, 2729 is_wuser ? B_TRUE : B_FALSE, 2730 nm->windomain, nm->winname, nm->unixname, nm->direction); 2731 2732 if (stat != IDMAP_SUCCESS) { 2733 print_error(pos, 2734 gettext("Mapping not deleted (%s)\n"), 2735 idmap_stat2string(stat)); 2736 rc = -1; 2737 break; 2738 } 2739 } 2740 2741 if (rc == 0) 2742 rc = positions_add(pos); 2743 2744 cleanup: 2745 name_mapping_fini(nm); 2746 if (fini_udt_command(1, pos)) 2747 rc = -1; 2748 return (rc); 2749 } 2750 2751 /* flush command handler */ 2752 static int 2753 do_flush(flag_t *f, int argc, char **argv, cmd_pos_t *pos) 2754 { 2755 NOTE(ARGUNUSED(argv)) 2756 idmap_flush_op op; 2757 idmap_stat stat; 2758 int rc = 0; 2759 2760 if (argc > 0) { 2761 print_error(pos, 2762 gettext("Too many arguments.\n")); 2763 return (-1); 2764 } 2765 if (f[a_FLAG] != NULL) 2766 op = IDMAP_FLUSH_DELETE; 2767 else 2768 op = IDMAP_FLUSH_EXPIRE; 2769 2770 stat = idmap_flush(op); 2771 if (stat != IDMAP_SUCCESS) { 2772 print_error(pos, 2773 gettext("%s\n"), 2774 idmap_stat2string(stat)); 2775 rc = -1; 2776 } 2777 2778 return (rc); 2779 } 2780 2781 2782 /* exit command handler */ 2783 static int 2784 /* LINTED E_FUNC_ARG_UNUSED */ 2785 do_exit(flag_t *f, int argc, char **argv, cmd_pos_t *pos) 2786 { 2787 return (0); 2788 } 2789 2790 2791 /* debug command handler: just print the parameters */ 2792 static int 2793 /* LINTED E_STATIC_UNUSED */ 2794 debug_print_params(flag_t *f, int argc, char **argv, cmd_pos_t *pos) 2795 { 2796 int i; 2797 #if 0 2798 char *leaktest = (char *)malloc(100); 2799 #endif 2800 2801 print_flags(f); 2802 2803 for (i = 0; i < argc; i++) { 2804 (void) printf("Argument %d: %s\n", i, argv[i]); 2805 } 2806 2807 (void) fflush(stdout); 2808 return (0); 2809 } 2810 2811 /* 2812 * From name_mapping_t, asseble a string containing identity of the 2813 * given type. 2814 */ 2815 static int 2816 nm2type(name_mapping_t *nm, int type, char **to) 2817 { 2818 switch (type) { 2819 case TYPE_SID: 2820 case TYPE_USID: 2821 case TYPE_GSID: 2822 if (nm->sidprefix == NULL) 2823 return (-1); 2824 *to = sid_format(nm); 2825 return (0); 2826 case TYPE_WN: 2827 case TYPE_WU: 2828 case TYPE_WG: 2829 return (nm2winqn(nm, to)); 2830 case TYPE_UID: 2831 case TYPE_GID: 2832 case TYPE_PID: 2833 *to = pid_format(nm->pid, nm->is_user); 2834 if (*to == NULL) 2835 return (-1); 2836 else 2837 return (0); 2838 case TYPE_UN: 2839 case TYPE_UU: 2840 case TYPE_UG: 2841 return (nm2unixname(nm, to)); 2842 default: 2843 /* This can never happen: */ 2844 print_error(NULL, 2845 gettext("Internal error: invalid name type.\n")); 2846 return (-1); 2847 } 2848 /* never reached */ 2849 } 2850 2851 /* show command handler */ 2852 static int 2853 do_show_mapping(flag_t *f, int argc, char **argv, cmd_pos_t *pos) 2854 { 2855 idmap_stat stat = 0; 2856 int flag; 2857 idmap_stat map_stat = 0; 2858 int type_from; 2859 int type_to; 2860 name_mapping_t *nm = NULL; 2861 char *fromname; 2862 char *toname; 2863 idmap_info info; 2864 2865 (void) memset(&info, 0, sizeof (info)); 2866 2867 if (argc == 0) { 2868 print_error(pos, 2869 gettext("No identity given\n")); 2870 return (-1); 2871 } else if (argc > 2) { 2872 print_error(pos, 2873 gettext("Too many arguments.\n")); 2874 return (-1); 2875 } 2876 2877 flag = 0; 2878 if (f[c_FLAG] == NULL) 2879 flag |= IDMAP_REQ_FLG_NO_NEW_ID_ALLOC; 2880 if (f[v_FLAG] != NULL) 2881 flag |= IDMAP_REQ_FLG_MAPPING_INFO; 2882 if (f[V_FLAG] != NULL) 2883 flag |= IDMAP_REQ_FLG_TRACE; 2884 2885 nm = name_mapping_init(); 2886 if (nm == NULL) 2887 goto cleanup; 2888 2889 type_from = name2parts(argv[0], nm, pos); 2890 if (type_from <= 0) { 2891 stat = IDMAP_ERR_ARG; 2892 goto cleanup; 2893 } 2894 2895 2896 /* Second, determine type_to: */ 2897 if (argc < 2) { 2898 type_to = type_from & IS_WIN ? TYPE_PID : TYPE_SID; 2899 if (type_from & IS_NAME) 2900 type_to |= IS_NAME; 2901 } else { 2902 type_to = string2type(argv[1], pos); 2903 if (type_to == TYPE_INVALID) { 2904 stat = IDMAP_ERR_ARG; 2905 goto cleanup; 2906 } 2907 } 2908 2909 if (type_to & IS_WIN) { 2910 if (type_to & IS_USER) 2911 nm->is_wuser = IDMAP_YES; 2912 else if (type_to & IS_GROUP) 2913 nm->is_wuser = IDMAP_NO; 2914 else 2915 nm->is_wuser = IDMAP_UNKNOWN; 2916 } else { 2917 if (type_to & IS_USER) 2918 nm->is_user = IDMAP_YES; 2919 else if (type_to & IS_GROUP) 2920 nm->is_user = IDMAP_NO; 2921 } 2922 2923 /* Are both arguments the same OS side? */ 2924 if (!(type_from & IS_WIN ^ type_to & IS_WIN)) { 2925 print_error(pos, 2926 gettext("Direction ambiguous.\n")); 2927 stat = IDMAP_ERR_ARG; 2928 goto cleanup; 2929 } 2930 2931 /* 2932 * We have two interfaces for retrieving the mappings: 2933 * idmap_get_sidbyuid & comp (the batch interface) and 2934 * idmap_get_w2u_mapping & comp. We want to use both of them, because 2935 * the former mimicks kernel interface better and the later offers the 2936 * string names. In the batch case, our batch has always size 1. 2937 * 2938 * Btw, type_from cannot be IDMAP_PID, because there is no type string 2939 * for it. 2940 */ 2941 2942 if (type_from & IS_NAME || type_to & IS_NAME || 2943 type_from == TYPE_GSID || type_from == TYPE_USID || 2944 type_to == TYPE_GSID || type_to == TYPE_USID) { 2945 if (type_from & IS_WIN) { 2946 map_stat = idmap_get_w2u_mapping( 2947 nm->sidprefix, 2948 &nm->rid, 2949 nm->winname, 2950 nm->windomain, 2951 flag, 2952 &nm->is_user, &nm->is_wuser, 2953 &nm->pid, 2954 &nm->unixname, 2955 &nm->direction, 2956 &info); 2957 } else { 2958 map_stat = idmap_get_u2w_mapping( 2959 &nm->pid, 2960 nm->unixname, 2961 flag, 2962 nm->is_user, &nm->is_wuser, 2963 &nm->sidprefix, 2964 &nm->rid, 2965 &nm->winname, 2966 &nm->windomain, 2967 &nm->direction, 2968 &info); 2969 } 2970 2971 } else { 2972 /* batch handle */ 2973 idmap_get_handle_t *ghandle = NULL; 2974 /* To be passed to idmap_get_uidbysid */ 2975 gid_t gid = UNDEFINED_GID; 2976 /* To be passed to idmap_get_gidbysid */ 2977 uid_t uid = UNDEFINED_UID; 2978 2979 2980 /* Create an in-memory structure for all the batch: */ 2981 stat = idmap_get_create(&ghandle); 2982 if (stat != IDMAP_SUCCESS) { 2983 print_error(pos, 2984 gettext("Unable to create handle for communicating" 2985 " with idmapd(1M) (%s)\n"), 2986 idmap_stat2string(stat)); 2987 idmap_get_destroy(ghandle); 2988 goto cleanup; 2989 } 2990 2991 /* Schedule the request: */ 2992 if (type_to == TYPE_UID) { 2993 stat = idmap_getext_uidbysid(ghandle, 2994 nm->sidprefix, 2995 nm->rid, 2996 flag, 2997 &uid, 2998 &info, 2999 &map_stat); 3000 } else if (type_to == TYPE_GID) { 3001 stat = idmap_getext_gidbysid(ghandle, 3002 nm->sidprefix, 3003 nm->rid, 3004 flag, 3005 &gid, 3006 &info, 3007 &map_stat); 3008 } else if (type_to == TYPE_PID) { 3009 stat = idmap_getext_pidbysid(ghandle, 3010 nm->sidprefix, 3011 nm->rid, 3012 flag, 3013 &nm->pid, 3014 &nm->is_user, 3015 &info, 3016 &map_stat); 3017 } else if (type_from == TYPE_UID) { 3018 stat = idmap_getext_sidbyuid(ghandle, 3019 nm->pid, 3020 flag, 3021 &nm->sidprefix, 3022 &nm->rid, 3023 &info, 3024 &map_stat); 3025 } else if (type_from == TYPE_GID) { 3026 stat = idmap_getext_sidbygid(ghandle, 3027 (gid_t)nm->pid, 3028 flag, 3029 &nm->sidprefix, 3030 &nm->rid, 3031 &info, 3032 &map_stat); 3033 } else { 3034 /* This can never happen: */ 3035 print_error(pos, 3036 gettext("Internal error in show.\n")); 3037 exit(1); 3038 } 3039 3040 if (stat < 0) { 3041 print_error(pos, 3042 gettext("Request for %.3s not sent (%s)\n"), 3043 argv[0], idmap_stat2string(stat)); 3044 idmap_get_destroy(ghandle); 3045 goto cleanup; 3046 } 3047 3048 /* Send the batch to idmapd and obtain results: */ 3049 stat = idmap_get_mappings(ghandle); 3050 if (stat < 0) { 3051 print_error(pos, 3052 gettext("Mappings not obtained because of" 3053 " RPC problem (%s)\n"), 3054 idmap_stat2string(stat)); 3055 idmap_get_destroy(ghandle); 3056 goto cleanup; 3057 } 3058 3059 /* Destroy the batch handle: */ 3060 idmap_get_destroy(ghandle); 3061 3062 if (type_to == TYPE_UID) 3063 nm->pid = uid; 3064 else if (type_to == TYPE_GID) 3065 nm->pid = (uid_t)gid; 3066 3067 } 3068 3069 /* 3070 * If there was -c flag, we do output whatever we can even in 3071 * the case of error: 3072 */ 3073 if (map_stat < 0 && flag & IDMAP_REQ_FLG_NO_NEW_ID_ALLOC) 3074 goto errormsg; 3075 3076 /* 3077 * idmapd returns fallback uid/gid in case of errors. However 3078 * it uses special sentinel value i.e 4294967295 (or -1) to 3079 * indicate that falbback pid is not available either. In such 3080 * case idmap(1M) should not display the mapping because there 3081 * is no fallback mapping. 3082 */ 3083 3084 if ((type_to == TYPE_UID || type_to == TYPE_GID || 3085 type_to == TYPE_PID) && nm->pid == UNDEFINED_UID) 3086 goto errormsg; 3087 3088 if (nm2type(nm, type_from, &fromname) < 0) 3089 goto errormsg; 3090 3091 if (nm2type(nm, type_to, &toname) < 0) { 3092 if (!(flag & IDMAP_REQ_FLG_NO_NEW_ID_ALLOC)) 3093 (void) printf("%s -> %s:%u\n", 3094 fromname, 3095 type_to & IS_GROUP ? ID_GID : ID_UID, 3096 UID_NOBODY); 3097 free(fromname); 3098 } else { 3099 (void) printf("%s -> %s\n", fromname, toname); 3100 free(fromname); 3101 free(toname); 3102 } 3103 3104 errormsg: 3105 if (map_stat < 0) { 3106 print_error(pos, gettext("Error:\t%s\n"), 3107 idmap_stat2string(map_stat)); 3108 print_error_info(&info); 3109 } else { 3110 print_info(&info); 3111 } 3112 idmap_info_free(&info); 3113 3114 cleanup: 3115 if (nm != NULL) 3116 name_mapping_fini(nm); 3117 return (stat < 0 || map_stat < 0 ? -1 : 0); 3118 } 3119 3120 3121 static int 3122 flags2cred(flag_t *f, char **user, char **passwd, cmd_pos_t *pos) 3123 { 3124 3125 *user = NULL; 3126 *passwd = NULL; 3127 3128 if (f[D_FLAG] == NULL) 3129 return (0); /* GSSAPI authentification => OK */ 3130 3131 *user = strdup(f[D_FLAG]); 3132 if (*user == NULL) { 3133 print_error(pos, "%s.\n", strerror(ENOMEM)); 3134 return (-1); 3135 } 3136 3137 /* Password: */ 3138 3139 if (f[j_FLAG] != NULL) { 3140 char line[MAX_INPUT_LINE_SZ]; 3141 int i; 3142 FILE *file = fopen(f[j_FLAG], "r"); 3143 3144 if (file == NULL) { 3145 print_error(pos, 3146 gettext("Failed to open password file \"%s\": (%s)" 3147 ".\n"), f[j_FLAG], strerror(errno)); 3148 goto fail; 3149 } 3150 3151 /* The password is the fist line, we ignore the rest: */ 3152 if (fgets(line, MAX_INPUT_LINE_SZ, file) == NULL) { 3153 print_error(pos, 3154 gettext("The password file \"%s\" is empty.\n"), 3155 f[j_FLAG]); 3156 (void) fclose(file); 3157 goto fail; 3158 } 3159 3160 if (fclose(file) != 0) { 3161 print_error(pos, 3162 gettext("Unable to close the password file \"%s\"" 3163 ".\n"), f[j_FLAG], strerror(errno)); 3164 goto fail; 3165 } 3166 3167 /* Trim the eol: */ 3168 for (i = strlen(line) - 1; 3169 i >= 0 && (line[i] == '\r' || line[i] == '\n'); 3170 i--) 3171 line[i] = '\0'; 3172 3173 *passwd = strdup(line); 3174 if (*passwd == NULL) { 3175 print_error(pos, "%s.\n", strerror(ENOMEM)); 3176 goto fail; 3177 } 3178 } else if (!batch_mode) { 3179 /* If in the interactive mode, read the terminal input: */ 3180 char *it = getpassphrase("Enter password:"); 3181 if (it == NULL) { 3182 print_error(NULL, 3183 gettext("Failed to get password (%s).\n"), 3184 strerror(errno)); 3185 goto fail; 3186 } 3187 3188 *passwd = strdup(it); 3189 (void) memset(it, 0, strlen(it)); 3190 3191 if (*passwd == NULL) { 3192 print_error(pos, "%s.\n", strerror(ENOMEM)); 3193 goto fail; 3194 } 3195 } else { 3196 print_error(pos, gettext("No password given.\n")); 3197 goto fail; 3198 } 3199 3200 return (0); 3201 fail: 3202 if (*passwd != NULL) { 3203 (void) memset(*passwd, 0, strlen(*passwd)); 3204 free(*passwd); 3205 *passwd = NULL; 3206 } 3207 3208 free(*user); 3209 return (-1); 3210 } 3211 3212 3213 static int 3214 do_set_namemap(flag_t *f, int argc, char **argv, cmd_pos_t *pos) 3215 { 3216 idmap_stat stat; 3217 name_mapping_t *nm; 3218 int is_first_win; 3219 char *user; 3220 char *passwd; 3221 3222 if (argc < 2) { 3223 print_error(pos, 3224 gettext("Not enough arguments: two names needed for a " 3225 "namemap.\n")); 3226 return (-1); 3227 } else if (argc > 2) { 3228 print_error(pos, 3229 gettext("Too many arguments: two names needed for a " 3230 "namemap.\n")); 3231 return (-1); 3232 } 3233 3234 nm = args2nm(&is_first_win, argc, argv, pos); 3235 if (nm == NULL) 3236 return (-1); 3237 3238 if (flags2cred(f, &user, &passwd, pos) < 0) 3239 return (-1); 3240 3241 nm->direction = is_first_win ? IDMAP_DIRECTION_W2U 3242 : IDMAP_DIRECTION_U2W; 3243 3244 if (init_nm_command(user, passwd, f[a_FLAG], nm->windomain, 3245 nm->direction, pos) < 0) 3246 return (-1); 3247 3248 3249 stat = idmap_set_namemap(namemaps.handle, nm->winname, nm->unixname, 3250 nm->is_user, nm->is_wuser, nm->direction); 3251 3252 if (stat != IDMAP_SUCCESS) { 3253 print_error(pos, 3254 gettext("Failed to set namemap (%s).\n"), 3255 idmap_stat2string(stat)); 3256 } 3257 3258 if (passwd != NULL) { 3259 (void) memset(passwd, 0, strlen(passwd)); 3260 free(passwd); 3261 } 3262 3263 free(user); 3264 3265 fini_nm_command(); 3266 name_mapping_fini(nm); 3267 return (stat != IDMAP_SUCCESS ? -1 : 0); 3268 } 3269 3270 static int 3271 do_unset_namemap(flag_t *f, int argc, char **argv, cmd_pos_t *pos) 3272 { 3273 idmap_stat stat; 3274 name_mapping_t *nm; 3275 int is_first_win; 3276 char *user; 3277 char *passwd; 3278 3279 if (argc < 1) { 3280 print_error(pos, 3281 gettext("Not enough arguments: a name needed to unset a " 3282 "namemap.\n")); 3283 return (-1); 3284 } else if (argc > 2) { 3285 print_error(pos, 3286 gettext("Too many arguments: Only target name and type is " 3287 "needed to unset namemap.\n")); 3288 return (-1); 3289 } 3290 3291 nm = args2nm(&is_first_win, 1, argv, pos); 3292 if (nm == NULL) 3293 return (-1); 3294 3295 if (flags2cred(f, &user, &passwd, pos) < 0) 3296 return (-1); 3297 3298 nm->direction = is_first_win ? IDMAP_DIRECTION_W2U 3299 : IDMAP_DIRECTION_U2W; 3300 3301 if (argc > 1 && !is_first_win) { 3302 print_error(pos, 3303 gettext("Target type \"%s\" is redundant.\n"), 3304 argv[1]); 3305 stat = IDMAP_ERR_ARG; 3306 goto cleanup; 3307 } else if (argc > 1) { 3308 switch (string2type(argv[1], pos)) { 3309 case TYPE_INVALID: 3310 name_mapping_fini(nm); 3311 return (-1); 3312 case TYPE_UU: 3313 nm->is_user = IDMAP_YES; 3314 break; 3315 case TYPE_UG: 3316 nm->is_user = IDMAP_NO; 3317 break; 3318 default: 3319 print_error(pos, 3320 gettext("Invalid target type \"%s\": here the " 3321 "possible target type is unixuser or " 3322 "unixgroup.\n"), argv[1]); 3323 stat = IDMAP_ERR_ARG; 3324 goto cleanup; 3325 } 3326 } 3327 3328 if (init_nm_command(user, passwd, f[a_FLAG], nm->windomain, 3329 nm->direction, pos) < 0) 3330 return (-1); 3331 3332 stat = idmap_unset_namemap(namemaps.handle, nm->winname, nm->unixname, 3333 nm->is_user, nm->is_wuser, nm->direction); 3334 3335 if (stat != IDMAP_SUCCESS) { 3336 print_error(pos, 3337 gettext("Failed to unset namemap (%s).\n"), 3338 idmap_stat2string(stat)); 3339 } 3340 3341 cleanup: 3342 if (passwd != NULL) { 3343 (void) memset(passwd, 0, strlen(passwd)); 3344 free(passwd); 3345 } 3346 3347 free(user); 3348 3349 fini_nm_command(); 3350 name_mapping_fini(nm); 3351 return (stat == IDMAP_SUCCESS ? 0 : -1); 3352 } 3353 3354 static int 3355 /* LINTED E_FUNC_ARG_UNUSED */ 3356 do_get_namemap(flag_t *f, int argc, char **argv, cmd_pos_t *pos) 3357 { 3358 idmap_stat stat; 3359 name_mapping_t *nm; 3360 int is_first_win; 3361 int is_source_ad; 3362 char *winname = NULL; 3363 char *unixname = NULL; 3364 char *unixuser = NULL; 3365 char *unixgroup = NULL; 3366 3367 if (argc < 1) { 3368 print_error(pos, 3369 gettext("Not enough arguments: a name needed to get a " 3370 "namemap.\n")); 3371 return (-1); 3372 } else if (argc > 1) { 3373 print_error(pos, 3374 gettext("Too many arguments: just one name needed to get " 3375 "a namemap.\n")); 3376 return (-1); 3377 } 3378 3379 nm = args2nm(&is_first_win, argc, argv, pos); 3380 if (nm == NULL) 3381 return (-1); 3382 3383 nm->direction = is_first_win ? IDMAP_DIRECTION_W2U 3384 : IDMAP_DIRECTION_U2W; 3385 3386 /* nm->is_user is IDMAP_UNKNOWN for IDMAP_DIRECTION_W2U */ 3387 if (nm->is_user == IDMAP_YES) { 3388 unixuser = strdup(nm->unixname); 3389 if (unixuser == NULL) { 3390 print_error(pos, "%s.\n", strerror(ENOMEM)); 3391 goto cleanup; 3392 } 3393 } else if (nm->is_user == IDMAP_NO) { 3394 unixgroup = strdup(nm->unixname); 3395 if (unixgroup == NULL) { 3396 print_error(pos, "%s.\n", strerror(ENOMEM)); 3397 goto cleanup; 3398 } 3399 } 3400 3401 if (init_nm_command(NULL, NULL, NULL, nm->windomain, 3402 nm->direction, pos) < 0) 3403 return (-1); 3404 3405 stat = idmap_get_namemap(namemaps.handle, &is_source_ad, &nm->winname, 3406 &nm->windomain, &nm->is_wuser, &unixuser, &unixgroup); 3407 3408 if (stat != IDMAP_SUCCESS) { 3409 print_error(pos, 3410 gettext("Failed to get namemap info (%s).\n"), 3411 idmap_stat2string(stat)); 3412 goto cleanup; 3413 } 3414 3415 if (nm2winqn(nm, &winname) < 0) 3416 goto cleanup; 3417 3418 switch (is_source_ad) { 3419 case IDMAP_YES: 3420 if (unixuser == NULL && unixgroup == NULL) 3421 (void) printf(gettext("\t\tNo namemap found in AD.\n")); 3422 else { 3423 (void) printf(gettext("AD namemaps for %s\n"), winname); 3424 if (unixuser != NULL) 3425 (void) printf(gettext("\t\t->\t%s:%s\n"), 3426 ID_UNIXUSER, unixuser); 3427 3428 if (unixgroup != NULL) 3429 (void) printf(gettext("\t\t->\t%s:%s\n"), 3430 ID_UNIXGROUP, unixgroup); 3431 } 3432 break; 3433 case IDMAP_NO: 3434 if (nm2unixname(nm, &unixname) < 0) 3435 goto cleanup; 3436 3437 if (nm->winname == NULL) 3438 (void) printf(gettext("\t\tNo namemap found in " 3439 "native LDAP.\n")); 3440 else { 3441 (void) printf(gettext("Native LDAP namemap for %s\n"), 3442 unixname); 3443 (void) printf(gettext("\t\t->\t%s\n"), winname); 3444 } 3445 break; 3446 default: 3447 /* 3448 * This can never happen; the error must be recognized in 3449 * args2nm 3450 */ 3451 print_error(pos, 3452 gettext("Internal error: unknown source of namemaps.\n")); 3453 } 3454 3455 cleanup: 3456 fini_nm_command(); 3457 name_mapping_fini(nm); 3458 if (winname != NULL) 3459 free(winname); 3460 if (unixuser != NULL) 3461 free(unixuser); 3462 if (unixgroup != NULL) 3463 free(unixgroup); 3464 return (stat == IDMAP_SUCCESS ? 0 : -1); 3465 } 3466 3467 3468 /* printflike */ 3469 static 3470 void 3471 idmap_cli_logger(int pri, const char *format, ...) 3472 { 3473 va_list args; 3474 3475 if (pri == LOG_DEBUG) 3476 return; 3477 3478 va_start(args, format); 3479 3480 (void) vfprintf(stderr, format, args); 3481 (void) fprintf(stderr, "\n"); 3482 3483 va_end(args); 3484 } 3485 3486 3487 /* main function. Returns 1 for error, 0 otherwise */ 3488 int 3489 main(int argc, char *argv[]) 3490 { 3491 int rc; 3492 3493 /* set locale and domain for internationalization */ 3494 (void) setlocale(LC_ALL, ""); 3495 (void) textdomain(TEXT_DOMAIN); 3496 3497 /* Redirect logging */ 3498 idmap_set_logger(idmap_cli_logger); 3499 adutils_set_logger(idmap_cli_logger); 3500 3501 /* idmap_engine determines the batch_mode: */ 3502 rc = engine_init(sizeof (commands) / sizeof (cmd_ops_t), 3503 commands, 3504 argc - 1, 3505 argv + 1, 3506 &batch_mode); 3507 3508 if (rc < 0) { 3509 (void) engine_fini(); 3510 if (rc == IDMAP_ENG_ERROR_SILENT) 3511 help(); 3512 return (1); 3513 } 3514 3515 udt_used = 0; 3516 if (batch_mode) { 3517 if (init_udt_batch() < 0) 3518 return (1); 3519 } 3520 3521 rc = run_engine(argc - 1, argv + 1); 3522 3523 if (batch_mode) { 3524 batch_mode = 0; 3525 if (fini_udt_command(rc == 0 ? 1 : 0, NULL)) 3526 rc = -1; 3527 fini_nm_command(); 3528 } 3529 3530 (void) engine_fini(); 3531 return (rc == 0 ? 0 : 1); 3532 } 3533