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