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