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 /* FALLTHROUGH */ 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 { 2344 int i; 2345 int code = TYPE_INVALID; 2346 2347 for (i = 0; i < sizeof (identity2code) / sizeof (id_code_t); i++) { 2348 if (strcasecmp(identity2code[i].identity, str) == 0) { 2349 code = identity2code[i].code; 2350 break; 2351 } 2352 } 2353 2354 if (code == TYPE_INVALID) { 2355 print_error(pos, 2356 gettext("Error: invalid identity type \"%s\"\n"), str); 2357 } 2358 2359 return (code); 2360 } 2361 2362 2363 2364 2365 /* 2366 * Split argument to its identity code and a name part 2367 * return values: 2368 * TYPE_INVALID for unknown identity 2369 * TYPE_AUTO for no identity (to be autodetected) 2370 * <TYPE_XXX> for known identity 2371 */ 2372 2373 static int 2374 get_identity(char *arg, char **name, cmd_pos_t *pos) 2375 { 2376 char *it; 2377 int code = TYPE_INVALID; 2378 2379 if ((it = strchr(arg, ':')) == NULL) { 2380 *name = arg; 2381 return (TYPE_AUTO); 2382 } 2383 2384 2385 *it = '\0'; 2386 code = string2type(arg, pos); 2387 *it = ':'; /* restore the original string: */ 2388 2389 *name = it + 1; 2390 return (code); 2391 } 2392 2393 /* 2394 * This function splits name to the relevant pieces: is_user, winname, 2395 * windomain unixname. E.g. for winname, it strdups nm->winname and possibly 2396 * nm->windomain and return TYPE_WN. 2397 * 2398 * If there is already one of the text fields allocated, it is OK. 2399 * Return values: 2400 * -1 ... syntax error 2401 * 0 ... it wasnt possible to determine 2402 * <TYPE_XXX> otherwise 2403 */ 2404 2405 static int 2406 name2parts(char *name, name_mapping_t *nm, cmd_pos_t *pos) 2407 { 2408 char *it; 2409 int code; 2410 2411 code = get_identity(name, &it, pos); 2412 2413 switch (code) { 2414 case TYPE_INVALID: 2415 /* syntax error: */ 2416 return (-1); 2417 case TYPE_AUTO: 2418 /* autodetection: */ 2419 if (nm->winname != NULL && nm->is_wuser != IDMAP_UNKNOWN) 2420 code = nm->is_wuser == IDMAP_YES ? TYPE_UU : TYPE_UG; 2421 else if (nm->unixname != NULL || 2422 strchr(name, '@') != NULL || 2423 strchr(name, '\\') != NULL) 2424 /* btw, nm->is_user can never be IDMAP_UNKNOWN here */ 2425 code = TYPE_WN; 2426 else 2427 return (0); 2428 /* If the code was guessed succesfully, we are OK. */ 2429 break; 2430 default: 2431 name = it; 2432 } 2433 2434 if (code & IS_WIN) { 2435 if (code & IS_USER) 2436 nm->is_wuser = IDMAP_YES; 2437 else if (code & IS_GROUP) 2438 nm->is_wuser = IDMAP_NO; 2439 } else { 2440 if (code & IS_USER) 2441 nm->is_user = IDMAP_YES; 2442 else if (code & IS_GROUP) 2443 nm->is_user = IDMAP_NO; 2444 } 2445 2446 if (code & IS_WIN && code & IS_NAME) { 2447 if (nm->winname != NULL || nm->windomain != NULL) 2448 return (code); 2449 2450 if ((it = strchr(name, '@')) != NULL) { 2451 int length = it - name + 1; 2452 nm->winname = (char *)malloc(length); 2453 (void) strncpy(nm->winname, name, length - 1); 2454 nm->winname[length - 1] = '\0'; 2455 nm->windomain = strdup(it + 1); 2456 } else if ((it = strrchr(name, '\\')) != NULL) { 2457 int length = it - name + 1; 2458 nm->windomain = (char *)malloc(length); 2459 (void) strncpy(nm->windomain, name, length - 1); 2460 nm->windomain[length - 1] = '\0'; 2461 nm->winname = strdup(it + 1); 2462 nm->is_nt4 = B_TRUE; 2463 } else 2464 nm->winname = strdup(name); 2465 2466 return (code); 2467 } 2468 2469 2470 if (!(code & IS_WIN) && code & IS_NAME) { 2471 if (nm->unixname != NULL) 2472 return (code); 2473 2474 if (strlen(name) == 0) 2475 nm->unixname = strdup("\"\""); 2476 else 2477 nm->unixname = strdup(name); 2478 return (code); 2479 } 2480 2481 2482 if (code & IS_WIN && !(code & IS_NAME)) { 2483 if (!sid_convert(name, &nm->sidprefix, &nm->rid, pos)) 2484 return (-1); 2485 else 2486 return (code); 2487 } 2488 2489 /* 2490 * it is (!(code & TYPE_WIN) && !(code & TYPE_NAME)) here - the other 2491 * possiblities are exhausted. 2492 */ 2493 2494 if (!pid_convert(name, &nm->pid, code, pos)) 2495 return (-1); 2496 else 2497 return (code); 2498 2499 } 2500 2501 /* 2502 * Cycle through add/remove arguments until they are identified or found 2503 * invalid. 2504 */ 2505 static 2506 name_mapping_t * 2507 args2nm(int *is_first_win, int argc, char **argv, 2508 cmd_pos_t *pos) 2509 { 2510 int code; 2511 int i; 2512 name_mapping_t *nm; 2513 2514 nm = name_mapping_init(); 2515 if (nm == NULL) 2516 return (NULL); 2517 2518 for (i = 0; i < 2 * argc - 1; i++) { 2519 code = name2parts(argv[i % 2], nm, pos); 2520 switch (code) { 2521 case -1: 2522 goto fail; 2523 case 0: 2524 if (i > 0) { 2525 print_error(pos, 2526 gettext("Missing identity type" 2527 " cannot be determined for %s.\n"), 2528 argv[i % 2]); 2529 goto fail; 2530 } 2531 break; 2532 default: 2533 if (!(code & IS_NAME)) { 2534 print_error(pos, 2535 gettext("%s is not a valid name\n"), 2536 argv[i % 2]); 2537 goto fail; 2538 } 2539 } 2540 } 2541 2542 if (argc == 2 && nm->winname == NULL) { 2543 print_error(pos, gettext("No windows identity found.\n")); 2544 goto fail; 2545 } 2546 if (argc == 2 && nm->unixname == NULL) { 2547 print_error(pos, gettext("No unix identity found.\n")); 2548 goto fail; 2549 } 2550 if (argc == 1 && nm->winname == NULL && nm->unixname == NULL) { 2551 print_error(pos, gettext("No identity type determined.\n")); 2552 goto fail; 2553 } 2554 2555 if (is_first_win != NULL) 2556 *is_first_win = code & IS_WIN; 2557 return (nm); 2558 fail: 2559 name_mapping_fini(nm); 2560 return (NULL); 2561 } 2562 2563 2564 2565 /* add command handler. */ 2566 static int 2567 do_add_name_mapping(flag_t *f, int argc, char **argv, cmd_pos_t *pos) 2568 { 2569 name_mapping_t *nm; 2570 int rc = 0; 2571 int is_first_win; 2572 idmap_stat stat; 2573 int is_wuser; 2574 print_handle_t *ph; 2575 2576 2577 2578 /* Exactly two arguments must be specified */ 2579 if (argc < 2) { 2580 print_error(pos, gettext("Not enough arguments.\n")); 2581 return (-1); 2582 } else if (argc > 2) { 2583 print_error(pos, gettext("Too many arguments.\n")); 2584 return (-1); 2585 } 2586 2587 nm = args2nm(&is_first_win, argc, argv, pos); 2588 if (nm == NULL) 2589 return (-1); 2590 2591 if (f[d_FLAG] != NULL) 2592 nm->direction = is_first_win 2593 ? IDMAP_DIRECTION_W2U 2594 : IDMAP_DIRECTION_U2W; 2595 else 2596 nm->direction = IDMAP_DIRECTION_BI; 2597 2598 /* Now let us write it: */ 2599 2600 if (init_udt_command()) { 2601 name_mapping_fini(nm); 2602 return (-1); 2603 } 2604 2605 for (is_wuser = IDMAP_YES; is_wuser >= IDMAP_NO; is_wuser--) { 2606 /* nm->is_wuser can be IDMAP_YES, IDMAP_NO or IDMAP_UNKNOWN */ 2607 if ((is_wuser == IDMAP_YES && nm->is_wuser == IDMAP_NO) || 2608 (is_wuser == IDMAP_NO && nm->is_wuser == IDMAP_YES)) 2609 continue; 2610 2611 stat = idmap_udt_add_namerule(udt, nm->windomain, 2612 nm->is_user ? B_TRUE : B_FALSE, 2613 is_wuser ? B_TRUE : B_FALSE, 2614 nm->winname, nm->unixname, nm->is_nt4, nm->direction); 2615 } 2616 2617 /* We echo the mapping */ 2618 ph = print_mapping_init(DEFAULT_FORMAT, stdout); 2619 if (ph == NULL) { 2620 rc = -1; 2621 goto cleanup; 2622 } 2623 (void) print_mapping(ph, nm); 2624 (void) print_mapping_fini(ph); 2625 2626 if (stat != IDMAP_SUCCESS) { 2627 print_error(pos, 2628 gettext("Mapping not created (%s)\n"), 2629 idmap_stat2string(stat)); 2630 rc = -1; 2631 } 2632 2633 if (rc == 0) 2634 rc = positions_add(pos); 2635 2636 cleanup: 2637 name_mapping_fini(nm); 2638 if (fini_udt_command(1, pos)) 2639 rc = -1; 2640 return (rc); 2641 } 2642 2643 /* remove command handler */ 2644 static int 2645 do_remove_name_mapping(flag_t *f, int argc, char **argv, cmd_pos_t *pos) 2646 { 2647 name_mapping_t *nm; 2648 int rc = 0; 2649 idmap_stat stat; 2650 int is_first_win; 2651 int is_wuser; 2652 2653 /* "-a" means we flush all of them */ 2654 if (f[a_FLAG] != NULL) { 2655 if (argc) { 2656 print_error(pos, 2657 gettext("Too many arguments.\n")); 2658 return (-1); 2659 } 2660 2661 if (init_udt_command()) 2662 return (-1); 2663 rc = flush_nm(B_TRUE, pos); 2664 2665 if (rc >= 0) 2666 rc = flush_nm(B_FALSE, pos); 2667 2668 if (fini_udt_command(rc ? 0 : 1, pos)) 2669 rc = -1; 2670 return (rc); 2671 } 2672 2673 /* Contrary to add_name_mapping, we can have only one argument */ 2674 if (argc < 1) { 2675 print_error(pos, gettext("Not enough arguments.\n")); 2676 return (-1); 2677 } else if (argc > 2) { 2678 print_error(pos, gettext("Too many arguments.\n")); 2679 return (-1); 2680 } else if ( 2681 /* both -f and -t: */ 2682 f[f_FLAG] != NULL && f[t_FLAG] != NULL || 2683 /* -d with a single argument: */ 2684 argc == 1 && f[d_FLAG] != NULL || 2685 /* -f or -t with two arguments: */ 2686 argc == 2 && (f[f_FLAG] != NULL || f[t_FLAG] != NULL)) { 2687 print_error(pos, 2688 gettext("Direction ambiguous.\n")); 2689 return (-1); 2690 } 2691 2692 2693 /* 2694 * Similar to do_add_name_mapping - see the comments 2695 * there. Except we may have only one argument here. 2696 */ 2697 nm = args2nm(&is_first_win, argc, argv, pos); 2698 if (nm == NULL) 2699 return (-1); 2700 2701 /* 2702 * If the direction is not specified by a -d/-f/-t flag, then it 2703 * is IDMAP_DIRECTION_UNDEF, because in that case we want to 2704 * remove any mapping. If it was IDMAP_DIRECTION_BI, idmap_api would 2705 * delete a bidirectional one only. 2706 */ 2707 if (f[d_FLAG] != NULL || f[f_FLAG] != NULL) 2708 nm->direction = is_first_win 2709 ? IDMAP_DIRECTION_W2U 2710 : IDMAP_DIRECTION_U2W; 2711 else if (f[t_FLAG] != NULL) 2712 nm->direction = is_first_win 2713 ? IDMAP_DIRECTION_U2W 2714 : IDMAP_DIRECTION_W2U; 2715 else 2716 nm->direction = IDMAP_DIRECTION_UNDEF; 2717 2718 if (init_udt_command()) { 2719 name_mapping_fini(nm); 2720 return (-1); 2721 } 2722 2723 for (is_wuser = IDMAP_YES; is_wuser >= IDMAP_NO; is_wuser--) { 2724 if ((is_wuser == IDMAP_YES && nm->is_wuser == IDMAP_NO) || 2725 (is_wuser == IDMAP_NO && nm->is_wuser == IDMAP_YES)) 2726 continue; 2727 2728 stat = idmap_udt_rm_namerule(udt, 2729 nm->is_user ? B_TRUE : B_FALSE, 2730 is_wuser ? B_TRUE : B_FALSE, 2731 nm->windomain, nm->winname, nm->unixname, nm->direction); 2732 2733 if (stat != IDMAP_SUCCESS) { 2734 print_error(pos, 2735 gettext("Mapping not deleted (%s)\n"), 2736 idmap_stat2string(stat)); 2737 rc = -1; 2738 break; 2739 } 2740 } 2741 2742 if (rc == 0) 2743 rc = positions_add(pos); 2744 2745 cleanup: 2746 name_mapping_fini(nm); 2747 if (fini_udt_command(1, pos)) 2748 rc = -1; 2749 return (rc); 2750 } 2751 2752 /* flush command handler */ 2753 static int 2754 do_flush(flag_t *f, int argc, char **argv, cmd_pos_t *pos) 2755 { 2756 NOTE(ARGUNUSED(argv)) 2757 idmap_flush_op op; 2758 idmap_stat stat; 2759 int rc = 0; 2760 2761 if (argc > 0) { 2762 print_error(pos, 2763 gettext("Too many arguments.\n")); 2764 return (-1); 2765 } 2766 if (f[a_FLAG] != NULL) 2767 op = IDMAP_FLUSH_DELETE; 2768 else 2769 op = IDMAP_FLUSH_EXPIRE; 2770 2771 stat = idmap_flush(op); 2772 if (stat != IDMAP_SUCCESS) { 2773 print_error(pos, 2774 gettext("%s\n"), 2775 idmap_stat2string(stat)); 2776 rc = -1; 2777 } 2778 2779 return (rc); 2780 } 2781 2782 2783 /* exit command handler */ 2784 static int 2785 /* LINTED E_FUNC_ARG_UNUSED */ 2786 do_exit(flag_t *f, int argc, char **argv, cmd_pos_t *pos) 2787 { 2788 return (0); 2789 } 2790 2791 2792 /* debug command handler: just print the parameters */ 2793 static int 2794 /* LINTED E_STATIC_UNUSED */ 2795 debug_print_params(flag_t *f, int argc, char **argv, cmd_pos_t *pos) 2796 { 2797 int i; 2798 #if 0 2799 char *leaktest = (char *)malloc(100); 2800 #endif 2801 2802 print_flags(f); 2803 2804 for (i = 0; i < argc; i++) { 2805 (void) printf("Argument %d: %s\n", i, argv[i]); 2806 } 2807 2808 (void) fflush(stdout); 2809 return (0); 2810 } 2811 2812 /* 2813 * From name_mapping_t, asseble a string containing identity of the 2814 * given type. 2815 */ 2816 static int 2817 nm2type(name_mapping_t *nm, int type, char **to) 2818 { 2819 switch (type) { 2820 case TYPE_SID: 2821 case TYPE_USID: 2822 case TYPE_GSID: 2823 if (nm->sidprefix == NULL) 2824 return (-1); 2825 *to = sid_format(nm); 2826 return (0); 2827 case TYPE_WN: 2828 case TYPE_WU: 2829 case TYPE_WG: 2830 return (nm2winqn(nm, to)); 2831 case TYPE_UID: 2832 case TYPE_GID: 2833 case TYPE_PID: 2834 *to = pid_format(nm->pid, nm->is_user); 2835 if (*to == NULL) 2836 return (-1); 2837 else 2838 return (0); 2839 case TYPE_UN: 2840 case TYPE_UU: 2841 case TYPE_UG: 2842 return (nm2unixname(nm, to)); 2843 default: 2844 /* This can never happen: */ 2845 print_error(NULL, 2846 gettext("Internal error: invalid name type.\n")); 2847 return (-1); 2848 } 2849 /* never reached */ 2850 } 2851 2852 /* show command handler */ 2853 static int 2854 do_show_mapping(flag_t *f, int argc, char **argv, cmd_pos_t *pos) 2855 { 2856 idmap_stat stat = 0; 2857 int flag; 2858 idmap_stat map_stat = 0; 2859 int type_from; 2860 int type_to; 2861 name_mapping_t *nm = NULL; 2862 char *fromname; 2863 char *toname; 2864 idmap_info info; 2865 2866 (void) memset(&info, 0, sizeof (info)); 2867 2868 if (argc == 0) { 2869 print_error(pos, 2870 gettext("No identity given\n")); 2871 return (-1); 2872 } else if (argc > 2) { 2873 print_error(pos, 2874 gettext("Too many arguments.\n")); 2875 return (-1); 2876 } 2877 2878 flag = 0; 2879 if (f[c_FLAG] == NULL) 2880 flag |= IDMAP_REQ_FLG_NO_NEW_ID_ALLOC; 2881 if (f[v_FLAG] != NULL) 2882 flag |= IDMAP_REQ_FLG_MAPPING_INFO; 2883 if (f[V_FLAG] != NULL) 2884 flag |= IDMAP_REQ_FLG_TRACE; 2885 2886 nm = name_mapping_init(); 2887 if (nm == NULL) 2888 goto cleanup; 2889 2890 type_from = name2parts(argv[0], nm, pos); 2891 if (type_from <= 0) { 2892 stat = IDMAP_ERR_ARG; 2893 goto cleanup; 2894 } 2895 2896 2897 /* Second, determine type_to: */ 2898 if (argc < 2) { 2899 type_to = type_from & IS_WIN ? TYPE_PID : TYPE_SID; 2900 if (type_from & IS_NAME) 2901 type_to |= IS_NAME; 2902 } else { 2903 type_to = string2type(argv[1], pos); 2904 if (type_to == TYPE_INVALID) { 2905 stat = IDMAP_ERR_ARG; 2906 goto cleanup; 2907 } 2908 } 2909 2910 if (type_to & IS_WIN) { 2911 if (type_to & IS_USER) 2912 nm->is_wuser = IDMAP_YES; 2913 else if (type_to & IS_GROUP) 2914 nm->is_wuser = IDMAP_NO; 2915 else 2916 nm->is_wuser = IDMAP_UNKNOWN; 2917 } else { 2918 if (type_to & IS_USER) 2919 nm->is_user = IDMAP_YES; 2920 else if (type_to & IS_GROUP) 2921 nm->is_user = IDMAP_NO; 2922 } 2923 2924 /* Are both arguments the same OS side? */ 2925 if (!(type_from & IS_WIN ^ type_to & IS_WIN)) { 2926 print_error(pos, 2927 gettext("Direction ambiguous.\n")); 2928 stat = IDMAP_ERR_ARG; 2929 goto cleanup; 2930 } 2931 2932 /* 2933 * We have two interfaces for retrieving the mappings: 2934 * idmap_get_sidbyuid & comp (the batch interface) and 2935 * idmap_get_w2u_mapping & comp. We want to use both of them, because 2936 * the former mimicks kernel interface better and the later offers the 2937 * string names. In the batch case, our batch has always size 1. 2938 * 2939 * Btw, type_from cannot be IDMAP_PID, because there is no type string 2940 * for it. 2941 */ 2942 2943 if (type_from & IS_NAME || type_to & IS_NAME || 2944 type_from == TYPE_GSID || type_from == TYPE_USID || 2945 type_to == TYPE_GSID || type_to == TYPE_USID) { 2946 if (type_from & IS_WIN) { 2947 map_stat = idmap_get_w2u_mapping( 2948 nm->sidprefix, 2949 &nm->rid, 2950 nm->winname, 2951 nm->windomain, 2952 flag, 2953 &nm->is_user, &nm->is_wuser, 2954 &nm->pid, 2955 &nm->unixname, 2956 &nm->direction, 2957 &info); 2958 } else { 2959 map_stat = idmap_get_u2w_mapping( 2960 &nm->pid, 2961 nm->unixname, 2962 flag, 2963 nm->is_user, &nm->is_wuser, 2964 &nm->sidprefix, 2965 &nm->rid, 2966 &nm->winname, 2967 &nm->windomain, 2968 &nm->direction, 2969 &info); 2970 } 2971 2972 } else { 2973 /* batch handle */ 2974 idmap_get_handle_t *ghandle = NULL; 2975 /* To be passed to idmap_get_uidbysid */ 2976 gid_t gid = UNDEFINED_GID; 2977 /* To be passed to idmap_get_gidbysid */ 2978 uid_t uid = UNDEFINED_UID; 2979 2980 2981 /* Create an in-memory structure for all the batch: */ 2982 stat = idmap_get_create(&ghandle); 2983 if (stat != IDMAP_SUCCESS) { 2984 print_error(pos, 2985 gettext("Unable to create handle for communicating" 2986 " with idmapd(1M) (%s)\n"), 2987 idmap_stat2string(stat)); 2988 idmap_get_destroy(ghandle); 2989 goto cleanup; 2990 } 2991 2992 /* Schedule the request: */ 2993 if (type_to == TYPE_UID) { 2994 stat = idmap_getext_uidbysid(ghandle, 2995 nm->sidprefix, 2996 nm->rid, 2997 flag, 2998 &uid, 2999 &info, 3000 &map_stat); 3001 } else if (type_to == TYPE_GID) { 3002 stat = idmap_getext_gidbysid(ghandle, 3003 nm->sidprefix, 3004 nm->rid, 3005 flag, 3006 &gid, 3007 &info, 3008 &map_stat); 3009 } else if (type_to == TYPE_PID) { 3010 stat = idmap_getext_pidbysid(ghandle, 3011 nm->sidprefix, 3012 nm->rid, 3013 flag, 3014 &nm->pid, 3015 &nm->is_user, 3016 &info, 3017 &map_stat); 3018 } else if (type_from == TYPE_UID) { 3019 stat = idmap_getext_sidbyuid(ghandle, 3020 nm->pid, 3021 flag, 3022 &nm->sidprefix, 3023 &nm->rid, 3024 &info, 3025 &map_stat); 3026 } else if (type_from == TYPE_GID) { 3027 stat = idmap_getext_sidbygid(ghandle, 3028 (gid_t)nm->pid, 3029 flag, 3030 &nm->sidprefix, 3031 &nm->rid, 3032 &info, 3033 &map_stat); 3034 } else { 3035 /* This can never happen: */ 3036 print_error(pos, 3037 gettext("Internal error in show.\n")); 3038 exit(1); 3039 } 3040 3041 if (stat < 0) { 3042 print_error(pos, 3043 gettext("Request for %.3s not sent (%s)\n"), 3044 argv[0], idmap_stat2string(stat)); 3045 idmap_get_destroy(ghandle); 3046 goto cleanup; 3047 } 3048 3049 /* Send the batch to idmapd and obtain results: */ 3050 stat = idmap_get_mappings(ghandle); 3051 if (stat < 0) { 3052 print_error(pos, 3053 gettext("Mappings not obtained because of" 3054 " RPC problem (%s)\n"), 3055 idmap_stat2string(stat)); 3056 idmap_get_destroy(ghandle); 3057 goto cleanup; 3058 } 3059 3060 /* Destroy the batch handle: */ 3061 idmap_get_destroy(ghandle); 3062 3063 if (type_to == TYPE_UID) 3064 nm->pid = uid; 3065 else if (type_to == TYPE_GID) 3066 nm->pid = (uid_t)gid; 3067 3068 } 3069 3070 /* 3071 * If there was -c flag, we do output whatever we can even in 3072 * the case of error: 3073 */ 3074 if (map_stat < 0 && flag & IDMAP_REQ_FLG_NO_NEW_ID_ALLOC) 3075 goto errormsg; 3076 3077 /* 3078 * idmapd returns fallback uid/gid in case of errors. However 3079 * it uses special sentinel value i.e 4294967295 (or -1) to 3080 * indicate that falbback pid is not available either. In such 3081 * case idmap(1M) should not display the mapping because there 3082 * is no fallback mapping. 3083 */ 3084 3085 if ((type_to == TYPE_UID || type_to == TYPE_GID || 3086 type_to == TYPE_PID) && nm->pid == UNDEFINED_UID) 3087 goto errormsg; 3088 3089 if (nm2type(nm, type_from, &fromname) < 0) 3090 goto errormsg; 3091 3092 if (nm2type(nm, type_to, &toname) < 0) { 3093 if (!(flag & IDMAP_REQ_FLG_NO_NEW_ID_ALLOC)) 3094 (void) printf("%s -> %s:%u\n", 3095 fromname, 3096 type_to & IS_GROUP ? ID_GID : ID_UID, 3097 UID_NOBODY); 3098 free(fromname); 3099 } else { 3100 (void) printf("%s -> %s\n", fromname, toname); 3101 free(fromname); 3102 free(toname); 3103 } 3104 3105 errormsg: 3106 if (map_stat < 0) { 3107 print_error(pos, gettext("Error:\t%s\n"), 3108 idmap_stat2string(map_stat)); 3109 print_error_info(&info); 3110 } else { 3111 print_info(&info); 3112 } 3113 idmap_info_free(&info); 3114 3115 cleanup: 3116 if (nm != NULL) 3117 name_mapping_fini(nm); 3118 return (stat < 0 || map_stat < 0 ? -1 : 0); 3119 } 3120 3121 3122 static int 3123 flags2cred(flag_t *f, char **user, char **passwd, cmd_pos_t *pos) 3124 { 3125 3126 *user = NULL; 3127 *passwd = NULL; 3128 3129 if (f[D_FLAG] == NULL) 3130 return (0); /* GSSAPI authentification => OK */ 3131 3132 *user = strdup(f[D_FLAG]); 3133 if (*user == NULL) { 3134 print_error(pos, "%s.\n", strerror(ENOMEM)); 3135 return (-1); 3136 } 3137 3138 /* Password: */ 3139 3140 if (f[j_FLAG] != NULL) { 3141 char line[MAX_INPUT_LINE_SZ]; 3142 int i; 3143 FILE *file = fopen(f[j_FLAG], "r"); 3144 3145 if (file == NULL) { 3146 print_error(pos, 3147 gettext("Failed to open password file \"%s\": (%s)" 3148 ".\n"), f[j_FLAG], strerror(errno)); 3149 goto fail; 3150 } 3151 3152 /* The password is the fist line, we ignore the rest: */ 3153 if (fgets(line, MAX_INPUT_LINE_SZ, file) == NULL) { 3154 print_error(pos, 3155 gettext("The password file \"%s\" is empty.\n"), 3156 f[j_FLAG]); 3157 (void) fclose(file); 3158 goto fail; 3159 } 3160 3161 if (fclose(file) != 0) { 3162 print_error(pos, 3163 gettext("Unable to close the password file \"%s\"" 3164 ".\n"), f[j_FLAG], strerror(errno)); 3165 goto fail; 3166 } 3167 3168 /* Trim the eol: */ 3169 for (i = strlen(line) - 1; 3170 i >= 0 && (line[i] == '\r' || line[i] == '\n'); 3171 i--) 3172 line[i] = '\0'; 3173 3174 *passwd = strdup(line); 3175 if (*passwd == NULL) { 3176 print_error(pos, "%s.\n", strerror(ENOMEM)); 3177 goto fail; 3178 } 3179 } else if (!batch_mode) { 3180 /* If in the interactive mode, read the terminal input: */ 3181 char *it = getpassphrase("Enter password:"); 3182 if (it == NULL) { 3183 print_error(NULL, 3184 gettext("Failed to get password (%s).\n"), 3185 strerror(errno)); 3186 goto fail; 3187 } 3188 3189 *passwd = strdup(it); 3190 (void) memset(it, 0, strlen(it)); 3191 3192 if (*passwd == NULL) { 3193 print_error(pos, "%s.\n", strerror(ENOMEM)); 3194 goto fail; 3195 } 3196 } else { 3197 print_error(pos, gettext("No password given.\n")); 3198 goto fail; 3199 } 3200 3201 return (0); 3202 fail: 3203 if (*passwd != NULL) { 3204 (void) memset(*passwd, 0, strlen(*passwd)); 3205 free(*passwd); 3206 *passwd = NULL; 3207 } 3208 3209 free(*user); 3210 return (-1); 3211 } 3212 3213 3214 static int 3215 do_set_namemap(flag_t *f, int argc, char **argv, cmd_pos_t *pos) 3216 { 3217 idmap_stat stat; 3218 name_mapping_t *nm; 3219 int is_first_win; 3220 char *user; 3221 char *passwd; 3222 3223 if (argc < 2) { 3224 print_error(pos, 3225 gettext("Not enough arguments: two names needed for a " 3226 "namemap.\n")); 3227 return (-1); 3228 } else if (argc > 2) { 3229 print_error(pos, 3230 gettext("Too many arguments: two names needed for a " 3231 "namemap.\n")); 3232 return (-1); 3233 } 3234 3235 nm = args2nm(&is_first_win, argc, argv, pos); 3236 if (nm == NULL) 3237 return (-1); 3238 3239 if (flags2cred(f, &user, &passwd, pos) < 0) 3240 return (-1); 3241 3242 nm->direction = is_first_win ? IDMAP_DIRECTION_W2U 3243 : IDMAP_DIRECTION_U2W; 3244 3245 if (init_nm_command(user, passwd, f[a_FLAG], nm->windomain, 3246 nm->direction, pos) < 0) 3247 return (-1); 3248 3249 3250 stat = idmap_set_namemap(namemaps.handle, nm->winname, nm->unixname, 3251 nm->is_user, nm->is_wuser, nm->direction); 3252 3253 if (stat != IDMAP_SUCCESS) { 3254 print_error(pos, 3255 gettext("Failed to set namemap (%s).\n"), 3256 idmap_stat2string(stat)); 3257 } 3258 3259 if (passwd != NULL) { 3260 (void) memset(passwd, 0, strlen(passwd)); 3261 free(passwd); 3262 } 3263 3264 free(user); 3265 3266 fini_nm_command(); 3267 name_mapping_fini(nm); 3268 return (stat != IDMAP_SUCCESS ? -1 : 0); 3269 } 3270 3271 static int 3272 do_unset_namemap(flag_t *f, int argc, char **argv, cmd_pos_t *pos) 3273 { 3274 idmap_stat stat; 3275 name_mapping_t *nm; 3276 int is_first_win; 3277 char *user; 3278 char *passwd; 3279 3280 if (argc < 1) { 3281 print_error(pos, 3282 gettext("Not enough arguments: a name needed to unset a " 3283 "namemap.\n")); 3284 return (-1); 3285 } else if (argc > 2) { 3286 print_error(pos, 3287 gettext("Too many arguments: Only target name and type is " 3288 "needed to unset namemap.\n")); 3289 return (-1); 3290 } 3291 3292 nm = args2nm(&is_first_win, 1, argv, pos); 3293 if (nm == NULL) 3294 return (-1); 3295 3296 if (flags2cred(f, &user, &passwd, pos) < 0) 3297 return (-1); 3298 3299 nm->direction = is_first_win ? IDMAP_DIRECTION_W2U 3300 : IDMAP_DIRECTION_U2W; 3301 3302 if (argc > 1 && !is_first_win) { 3303 print_error(pos, 3304 gettext("Target type \"%s\" is redundant.\n"), 3305 argv[1]); 3306 stat = IDMAP_ERR_ARG; 3307 goto cleanup; 3308 } else if (argc > 1) { 3309 switch (string2type(argv[1], pos)) { 3310 case TYPE_INVALID: 3311 name_mapping_fini(nm); 3312 return (-1); 3313 case TYPE_UU: 3314 nm->is_user = IDMAP_YES; 3315 break; 3316 case TYPE_UG: 3317 nm->is_user = IDMAP_NO; 3318 break; 3319 default: 3320 print_error(pos, 3321 gettext("Invalid target type \"%s\": here the " 3322 "possible target type is unixuser or " 3323 "unixgroup.\n"), argv[1]); 3324 stat = IDMAP_ERR_ARG; 3325 goto cleanup; 3326 } 3327 } 3328 3329 if (init_nm_command(user, passwd, f[a_FLAG], nm->windomain, 3330 nm->direction, pos) < 0) 3331 return (-1); 3332 3333 stat = idmap_unset_namemap(namemaps.handle, nm->winname, nm->unixname, 3334 nm->is_user, nm->is_wuser, nm->direction); 3335 3336 if (stat != IDMAP_SUCCESS) { 3337 print_error(pos, 3338 gettext("Failed to unset namemap (%s).\n"), 3339 idmap_stat2string(stat)); 3340 } 3341 3342 cleanup: 3343 if (passwd != NULL) { 3344 (void) memset(passwd, 0, strlen(passwd)); 3345 free(passwd); 3346 } 3347 3348 free(user); 3349 3350 fini_nm_command(); 3351 name_mapping_fini(nm); 3352 return (stat == IDMAP_SUCCESS ? 0 : -1); 3353 } 3354 3355 static int 3356 /* LINTED E_FUNC_ARG_UNUSED */ 3357 do_get_namemap(flag_t *f, int argc, char **argv, cmd_pos_t *pos) 3358 { 3359 idmap_stat stat; 3360 name_mapping_t *nm; 3361 int is_first_win; 3362 int is_source_ad; 3363 char *winname = NULL; 3364 char *unixname = NULL; 3365 char *unixuser = NULL; 3366 char *unixgroup = NULL; 3367 3368 if (argc < 1) { 3369 print_error(pos, 3370 gettext("Not enough arguments: a name needed to get a " 3371 "namemap.\n")); 3372 return (-1); 3373 } else if (argc > 1) { 3374 print_error(pos, 3375 gettext("Too many arguments: just one name needed to get " 3376 "a namemap.\n")); 3377 return (-1); 3378 } 3379 3380 nm = args2nm(&is_first_win, argc, argv, pos); 3381 if (nm == NULL) 3382 return (-1); 3383 3384 nm->direction = is_first_win ? IDMAP_DIRECTION_W2U 3385 : IDMAP_DIRECTION_U2W; 3386 3387 /* nm->is_user is IDMAP_UNKNOWN for IDMAP_DIRECTION_W2U */ 3388 if (nm->is_user == IDMAP_YES) { 3389 unixuser = strdup(nm->unixname); 3390 if (unixuser == NULL) { 3391 print_error(pos, "%s.\n", strerror(ENOMEM)); 3392 goto cleanup; 3393 } 3394 } else if (nm->is_user == IDMAP_NO) { 3395 unixgroup = strdup(nm->unixname); 3396 if (unixgroup == NULL) { 3397 print_error(pos, "%s.\n", strerror(ENOMEM)); 3398 goto cleanup; 3399 } 3400 } 3401 3402 if (init_nm_command(NULL, NULL, NULL, nm->windomain, 3403 nm->direction, pos) < 0) 3404 return (-1); 3405 3406 stat = idmap_get_namemap(namemaps.handle, &is_source_ad, &nm->winname, 3407 &nm->windomain, &nm->is_wuser, &unixuser, &unixgroup); 3408 3409 if (stat != IDMAP_SUCCESS) { 3410 print_error(pos, 3411 gettext("Failed to get namemap info (%s).\n"), 3412 idmap_stat2string(stat)); 3413 goto cleanup; 3414 } 3415 3416 if (nm2winqn(nm, &winname) < 0) 3417 goto cleanup; 3418 3419 switch (is_source_ad) { 3420 case IDMAP_YES: 3421 if (unixuser == NULL && unixgroup == NULL) 3422 (void) printf(gettext("\t\tNo namemap found in AD.\n")); 3423 else { 3424 (void) printf(gettext("AD namemaps for %s\n"), winname); 3425 if (unixuser != NULL) 3426 (void) printf(gettext("\t\t->\t%s:%s\n"), 3427 ID_UNIXUSER, unixuser); 3428 3429 if (unixgroup != NULL) 3430 (void) printf(gettext("\t\t->\t%s:%s\n"), 3431 ID_UNIXGROUP, unixgroup); 3432 } 3433 break; 3434 case IDMAP_NO: 3435 if (nm2unixname(nm, &unixname) < 0) 3436 goto cleanup; 3437 3438 if (nm->winname == NULL) 3439 (void) printf(gettext("\t\tNo namemap found in " 3440 "native LDAP.\n")); 3441 else { 3442 (void) printf(gettext("Native LDAP namemap for %s\n"), 3443 unixname); 3444 (void) printf(gettext("\t\t->\t%s\n"), winname); 3445 } 3446 break; 3447 default: 3448 /* 3449 * This can never happen; the error must be recognized in 3450 * args2nm 3451 */ 3452 print_error(pos, 3453 gettext("Internal error: unknown source of namemaps.\n")); 3454 } 3455 3456 cleanup: 3457 fini_nm_command(); 3458 name_mapping_fini(nm); 3459 if (winname != NULL) 3460 free(winname); 3461 if (unixuser != NULL) 3462 free(unixuser); 3463 if (unixgroup != NULL) 3464 free(unixgroup); 3465 return (stat == IDMAP_SUCCESS ? 0 : -1); 3466 } 3467 3468 3469 /* printflike */ 3470 static 3471 void 3472 idmap_cli_logger(int pri, const char *format, ...) 3473 { 3474 va_list args; 3475 3476 if (pri == LOG_DEBUG) 3477 return; 3478 3479 va_start(args, format); 3480 3481 (void) vfprintf(stderr, format, args); 3482 (void) fprintf(stderr, "\n"); 3483 3484 va_end(args); 3485 } 3486 3487 3488 /* main function. Returns 1 for error, 0 otherwise */ 3489 int 3490 main(int argc, char *argv[]) 3491 { 3492 int rc; 3493 3494 /* set locale and domain for internationalization */ 3495 (void) setlocale(LC_ALL, ""); 3496 (void) textdomain(TEXT_DOMAIN); 3497 3498 /* Redirect logging */ 3499 idmap_set_logger(idmap_cli_logger); 3500 adutils_set_logger(idmap_cli_logger); 3501 3502 /* idmap_engine determines the batch_mode: */ 3503 rc = engine_init(sizeof (commands) / sizeof (cmd_ops_t), 3504 commands, 3505 argc - 1, 3506 argv + 1, 3507 &batch_mode); 3508 3509 if (rc < 0) { 3510 (void) engine_fini(); 3511 if (rc == IDMAP_ENG_ERROR_SILENT) 3512 help(); 3513 return (1); 3514 } 3515 3516 udt_used = 0; 3517 if (batch_mode) { 3518 if (init_udt_batch() < 0) 3519 return (1); 3520 } 3521 3522 rc = run_engine(argc - 1, argv + 1); 3523 3524 if (batch_mode) { 3525 batch_mode = 0; 3526 if (fini_udt_command(rc == 0 ? 1 : 0, NULL)) 3527 rc = -1; 3528 fini_nm_command(); 3529 } 3530 3531 (void) engine_fini(); 3532 return (rc == 0 ? 0 : 1); 3533 } 3534