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