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