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