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