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