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