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