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 /* FALLTHROUGH */
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 {
2344 int i;
2345 int code = TYPE_INVALID;
2346
2347 for (i = 0; i < sizeof (identity2code) / sizeof (id_code_t); i++) {
2348 if (strcasecmp(identity2code[i].identity, str) == 0) {
2349 code = identity2code[i].code;
2350 break;
2351 }
2352 }
2353
2354 if (code == TYPE_INVALID) {
2355 print_error(pos,
2356 gettext("Error: invalid identity type \"%s\"\n"), str);
2357 }
2358
2359 return (code);
2360 }
2361
2362
2363
2364
2365 /*
2366 * Split argument to its identity code and a name part
2367 * return values:
2368 * TYPE_INVALID for unknown identity
2369 * TYPE_AUTO for no identity (to be autodetected)
2370 * <TYPE_XXX> for known identity
2371 */
2372
2373 static int
get_identity(char * arg,char ** name,cmd_pos_t * pos)2374 get_identity(char *arg, char **name, cmd_pos_t *pos)
2375 {
2376 char *it;
2377 int code = TYPE_INVALID;
2378
2379 if ((it = strchr(arg, ':')) == NULL) {
2380 *name = arg;
2381 return (TYPE_AUTO);
2382 }
2383
2384
2385 *it = '\0';
2386 code = string2type(arg, pos);
2387 *it = ':'; /* restore the original string: */
2388
2389 *name = it + 1;
2390 return (code);
2391 }
2392
2393 /*
2394 * This function splits name to the relevant pieces: is_user, winname,
2395 * windomain unixname. E.g. for winname, it strdups nm->winname and possibly
2396 * nm->windomain and return TYPE_WN.
2397 *
2398 * If there is already one of the text fields allocated, it is OK.
2399 * Return values:
2400 * -1 ... syntax error
2401 * 0 ... it wasnt possible to determine
2402 * <TYPE_XXX> otherwise
2403 */
2404
2405 static int
name2parts(char * name,name_mapping_t * nm,cmd_pos_t * pos)2406 name2parts(char *name, name_mapping_t *nm, cmd_pos_t *pos)
2407 {
2408 char *it;
2409 int code;
2410
2411 code = get_identity(name, &it, pos);
2412
2413 switch (code) {
2414 case TYPE_INVALID:
2415 /* syntax error: */
2416 return (-1);
2417 case TYPE_AUTO:
2418 /* autodetection: */
2419 if (nm->winname != NULL && nm->is_wuser != IDMAP_UNKNOWN)
2420 code = nm->is_wuser == IDMAP_YES ? TYPE_UU : TYPE_UG;
2421 else if (nm->unixname != NULL ||
2422 strchr(name, '@') != NULL ||
2423 strchr(name, '\\') != NULL)
2424 /* btw, nm->is_user can never be IDMAP_UNKNOWN here */
2425 code = TYPE_WN;
2426 else
2427 return (0);
2428 /* If the code was guessed succesfully, we are OK. */
2429 break;
2430 default:
2431 name = it;
2432 }
2433
2434 if (code & IS_WIN) {
2435 if (code & IS_USER)
2436 nm->is_wuser = IDMAP_YES;
2437 else if (code & IS_GROUP)
2438 nm->is_wuser = IDMAP_NO;
2439 } else {
2440 if (code & IS_USER)
2441 nm->is_user = IDMAP_YES;
2442 else if (code & IS_GROUP)
2443 nm->is_user = IDMAP_NO;
2444 }
2445
2446 if (code & IS_WIN && code & IS_NAME) {
2447 if (nm->winname != NULL || nm->windomain != NULL)
2448 return (code);
2449
2450 if ((it = strchr(name, '@')) != NULL) {
2451 int length = it - name + 1;
2452 nm->winname = (char *)malloc(length);
2453 (void) strncpy(nm->winname, name, length - 1);
2454 nm->winname[length - 1] = '\0';
2455 nm->windomain = strdup(it + 1);
2456 } else if ((it = strrchr(name, '\\')) != NULL) {
2457 int length = it - name + 1;
2458 nm->windomain = (char *)malloc(length);
2459 (void) strncpy(nm->windomain, name, length - 1);
2460 nm->windomain[length - 1] = '\0';
2461 nm->winname = strdup(it + 1);
2462 nm->is_nt4 = B_TRUE;
2463 } else
2464 nm->winname = strdup(name);
2465
2466 return (code);
2467 }
2468
2469
2470 if (!(code & IS_WIN) && code & IS_NAME) {
2471 if (nm->unixname != NULL)
2472 return (code);
2473
2474 if (strlen(name) == 0)
2475 nm->unixname = strdup("\"\"");
2476 else
2477 nm->unixname = strdup(name);
2478 return (code);
2479 }
2480
2481
2482 if (code & IS_WIN && !(code & IS_NAME)) {
2483 if (!sid_convert(name, &nm->sidprefix, &nm->rid, pos))
2484 return (-1);
2485 else
2486 return (code);
2487 }
2488
2489 /*
2490 * it is (!(code & TYPE_WIN) && !(code & TYPE_NAME)) here - the other
2491 * possiblities are exhausted.
2492 */
2493
2494 if (!pid_convert(name, &nm->pid, code, pos))
2495 return (-1);
2496 else
2497 return (code);
2498
2499 }
2500
2501 /*
2502 * Cycle through add/remove arguments until they are identified or found
2503 * invalid.
2504 */
2505 static
2506 name_mapping_t *
args2nm(int * is_first_win,int argc,char ** argv,cmd_pos_t * pos)2507 args2nm(int *is_first_win, int argc, char **argv,
2508 cmd_pos_t *pos)
2509 {
2510 int code;
2511 int i;
2512 name_mapping_t *nm;
2513
2514 nm = name_mapping_init();
2515 if (nm == NULL)
2516 return (NULL);
2517
2518 for (i = 0; i < 2 * argc - 1; i++) {
2519 code = name2parts(argv[i % 2], nm, pos);
2520 switch (code) {
2521 case -1:
2522 goto fail;
2523 case 0:
2524 if (i > 0) {
2525 print_error(pos,
2526 gettext("Missing identity type"
2527 " cannot be determined for %s.\n"),
2528 argv[i % 2]);
2529 goto fail;
2530 }
2531 break;
2532 default:
2533 if (!(code & IS_NAME)) {
2534 print_error(pos,
2535 gettext("%s is not a valid name\n"),
2536 argv[i % 2]);
2537 goto fail;
2538 }
2539 }
2540 }
2541
2542 if (argc == 2 && nm->winname == NULL) {
2543 print_error(pos, gettext("No windows identity found.\n"));
2544 goto fail;
2545 }
2546 if (argc == 2 && nm->unixname == NULL) {
2547 print_error(pos, gettext("No unix identity found.\n"));
2548 goto fail;
2549 }
2550 if (argc == 1 && nm->winname == NULL && nm->unixname == NULL) {
2551 print_error(pos, gettext("No identity type determined.\n"));
2552 goto fail;
2553 }
2554
2555 if (is_first_win != NULL)
2556 *is_first_win = code & IS_WIN;
2557 return (nm);
2558 fail:
2559 name_mapping_fini(nm);
2560 return (NULL);
2561 }
2562
2563
2564
2565 /* add command handler. */
2566 static int
do_add_name_mapping(flag_t * f,int argc,char ** argv,cmd_pos_t * pos)2567 do_add_name_mapping(flag_t *f, int argc, char **argv, cmd_pos_t *pos)
2568 {
2569 name_mapping_t *nm;
2570 int rc = 0;
2571 int is_first_win;
2572 idmap_stat stat;
2573 int is_wuser;
2574 print_handle_t *ph;
2575
2576
2577
2578 /* Exactly two arguments must be specified */
2579 if (argc < 2) {
2580 print_error(pos, gettext("Not enough arguments.\n"));
2581 return (-1);
2582 } else if (argc > 2) {
2583 print_error(pos, gettext("Too many arguments.\n"));
2584 return (-1);
2585 }
2586
2587 nm = args2nm(&is_first_win, argc, argv, pos);
2588 if (nm == NULL)
2589 return (-1);
2590
2591 if (f[d_FLAG] != NULL)
2592 nm->direction = is_first_win
2593 ? IDMAP_DIRECTION_W2U
2594 : IDMAP_DIRECTION_U2W;
2595 else
2596 nm->direction = IDMAP_DIRECTION_BI;
2597
2598 /* Now let us write it: */
2599
2600 if (init_udt_command()) {
2601 name_mapping_fini(nm);
2602 return (-1);
2603 }
2604
2605 for (is_wuser = IDMAP_YES; is_wuser >= IDMAP_NO; is_wuser--) {
2606 /* nm->is_wuser can be IDMAP_YES, IDMAP_NO or IDMAP_UNKNOWN */
2607 if ((is_wuser == IDMAP_YES && nm->is_wuser == IDMAP_NO) ||
2608 (is_wuser == IDMAP_NO && nm->is_wuser == IDMAP_YES))
2609 continue;
2610
2611 stat = idmap_udt_add_namerule(udt, nm->windomain,
2612 nm->is_user ? B_TRUE : B_FALSE,
2613 is_wuser ? B_TRUE : B_FALSE,
2614 nm->winname, nm->unixname, nm->is_nt4, nm->direction);
2615 }
2616
2617 /* We echo the mapping */
2618 ph = print_mapping_init(DEFAULT_FORMAT, stdout);
2619 if (ph == NULL) {
2620 rc = -1;
2621 goto cleanup;
2622 }
2623 (void) print_mapping(ph, nm);
2624 (void) print_mapping_fini(ph);
2625
2626 if (stat != IDMAP_SUCCESS) {
2627 print_error(pos,
2628 gettext("Mapping not created (%s)\n"),
2629 idmap_stat2string(stat));
2630 rc = -1;
2631 }
2632
2633 if (rc == 0)
2634 rc = positions_add(pos);
2635
2636 cleanup:
2637 name_mapping_fini(nm);
2638 if (fini_udt_command(1, pos))
2639 rc = -1;
2640 return (rc);
2641 }
2642
2643 /* remove command handler */
2644 static int
do_remove_name_mapping(flag_t * f,int argc,char ** argv,cmd_pos_t * pos)2645 do_remove_name_mapping(flag_t *f, int argc, char **argv, cmd_pos_t *pos)
2646 {
2647 name_mapping_t *nm;
2648 int rc = 0;
2649 idmap_stat stat;
2650 int is_first_win;
2651 int is_wuser;
2652
2653 /* "-a" means we flush all of them */
2654 if (f[a_FLAG] != NULL) {
2655 if (argc) {
2656 print_error(pos,
2657 gettext("Too many arguments.\n"));
2658 return (-1);
2659 }
2660
2661 if (init_udt_command())
2662 return (-1);
2663 rc = flush_nm(B_TRUE, pos);
2664
2665 if (rc >= 0)
2666 rc = flush_nm(B_FALSE, pos);
2667
2668 if (fini_udt_command(rc ? 0 : 1, pos))
2669 rc = -1;
2670 return (rc);
2671 }
2672
2673 /* Contrary to add_name_mapping, we can have only one argument */
2674 if (argc < 1) {
2675 print_error(pos, gettext("Not enough arguments.\n"));
2676 return (-1);
2677 } else if (argc > 2) {
2678 print_error(pos, gettext("Too many arguments.\n"));
2679 return (-1);
2680 } else if (
2681 /* both -f and -t: */
2682 f[f_FLAG] != NULL && f[t_FLAG] != NULL ||
2683 /* -d with a single argument: */
2684 argc == 1 && f[d_FLAG] != NULL ||
2685 /* -f or -t with two arguments: */
2686 argc == 2 && (f[f_FLAG] != NULL || f[t_FLAG] != NULL)) {
2687 print_error(pos,
2688 gettext("Direction ambiguous.\n"));
2689 return (-1);
2690 }
2691
2692
2693 /*
2694 * Similar to do_add_name_mapping - see the comments
2695 * there. Except we may have only one argument here.
2696 */
2697 nm = args2nm(&is_first_win, argc, argv, pos);
2698 if (nm == NULL)
2699 return (-1);
2700
2701 /*
2702 * If the direction is not specified by a -d/-f/-t flag, then it
2703 * is IDMAP_DIRECTION_UNDEF, because in that case we want to
2704 * remove any mapping. If it was IDMAP_DIRECTION_BI, idmap_api would
2705 * delete a bidirectional one only.
2706 */
2707 if (f[d_FLAG] != NULL || f[f_FLAG] != NULL)
2708 nm->direction = is_first_win
2709 ? IDMAP_DIRECTION_W2U
2710 : IDMAP_DIRECTION_U2W;
2711 else if (f[t_FLAG] != NULL)
2712 nm->direction = is_first_win
2713 ? IDMAP_DIRECTION_U2W
2714 : IDMAP_DIRECTION_W2U;
2715 else
2716 nm->direction = IDMAP_DIRECTION_UNDEF;
2717
2718 if (init_udt_command()) {
2719 name_mapping_fini(nm);
2720 return (-1);
2721 }
2722
2723 for (is_wuser = IDMAP_YES; is_wuser >= IDMAP_NO; is_wuser--) {
2724 if ((is_wuser == IDMAP_YES && nm->is_wuser == IDMAP_NO) ||
2725 (is_wuser == IDMAP_NO && nm->is_wuser == IDMAP_YES))
2726 continue;
2727
2728 stat = idmap_udt_rm_namerule(udt,
2729 nm->is_user ? B_TRUE : B_FALSE,
2730 is_wuser ? B_TRUE : B_FALSE,
2731 nm->windomain, nm->winname, nm->unixname, nm->direction);
2732
2733 if (stat != IDMAP_SUCCESS) {
2734 print_error(pos,
2735 gettext("Mapping not deleted (%s)\n"),
2736 idmap_stat2string(stat));
2737 rc = -1;
2738 break;
2739 }
2740 }
2741
2742 if (rc == 0)
2743 rc = positions_add(pos);
2744
2745 cleanup:
2746 name_mapping_fini(nm);
2747 if (fini_udt_command(1, pos))
2748 rc = -1;
2749 return (rc);
2750 }
2751
2752 /* flush command handler */
2753 static int
do_flush(flag_t * f,int argc,char ** argv,cmd_pos_t * pos)2754 do_flush(flag_t *f, int argc, char **argv, cmd_pos_t *pos)
2755 {
2756 NOTE(ARGUNUSED(argv))
2757 idmap_flush_op op;
2758 idmap_stat stat;
2759 int rc = 0;
2760
2761 if (argc > 0) {
2762 print_error(pos,
2763 gettext("Too many arguments.\n"));
2764 return (-1);
2765 }
2766 if (f[a_FLAG] != NULL)
2767 op = IDMAP_FLUSH_DELETE;
2768 else
2769 op = IDMAP_FLUSH_EXPIRE;
2770
2771 stat = idmap_flush(op);
2772 if (stat != IDMAP_SUCCESS) {
2773 print_error(pos,
2774 gettext("%s\n"),
2775 idmap_stat2string(stat));
2776 rc = -1;
2777 }
2778
2779 return (rc);
2780 }
2781
2782
2783 /* exit command handler */
2784 static int
2785 /* LINTED E_FUNC_ARG_UNUSED */
do_exit(flag_t * f,int argc,char ** argv,cmd_pos_t * pos)2786 do_exit(flag_t *f, int argc, char **argv, cmd_pos_t *pos)
2787 {
2788 return (0);
2789 }
2790
2791
2792 /* debug command handler: just print the parameters */
2793 static int
2794 /* LINTED E_STATIC_UNUSED */
debug_print_params(flag_t * f,int argc,char ** argv,cmd_pos_t * pos)2795 debug_print_params(flag_t *f, int argc, char **argv, cmd_pos_t *pos)
2796 {
2797 int i;
2798 #if 0
2799 char *leaktest = (char *)malloc(100);
2800 #endif
2801
2802 print_flags(f);
2803
2804 for (i = 0; i < argc; i++) {
2805 (void) printf("Argument %d: %s\n", i, argv[i]);
2806 }
2807
2808 (void) fflush(stdout);
2809 return (0);
2810 }
2811
2812 /*
2813 * From name_mapping_t, asseble a string containing identity of the
2814 * given type.
2815 */
2816 static int
nm2type(name_mapping_t * nm,int type,char ** to)2817 nm2type(name_mapping_t *nm, int type, char **to)
2818 {
2819 switch (type) {
2820 case TYPE_SID:
2821 case TYPE_USID:
2822 case TYPE_GSID:
2823 if (nm->sidprefix == NULL)
2824 return (-1);
2825 *to = sid_format(nm);
2826 return (0);
2827 case TYPE_WN:
2828 case TYPE_WU:
2829 case TYPE_WG:
2830 return (nm2winqn(nm, to));
2831 case TYPE_UID:
2832 case TYPE_GID:
2833 case TYPE_PID:
2834 *to = pid_format(nm->pid, nm->is_user);
2835 if (*to == NULL)
2836 return (-1);
2837 else
2838 return (0);
2839 case TYPE_UN:
2840 case TYPE_UU:
2841 case TYPE_UG:
2842 return (nm2unixname(nm, to));
2843 default:
2844 /* This can never happen: */
2845 print_error(NULL,
2846 gettext("Internal error: invalid name type.\n"));
2847 return (-1);
2848 }
2849 /* never reached */
2850 }
2851
2852 /* show command handler */
2853 static int
do_show_mapping(flag_t * f,int argc,char ** argv,cmd_pos_t * pos)2854 do_show_mapping(flag_t *f, int argc, char **argv, cmd_pos_t *pos)
2855 {
2856 idmap_stat stat = 0;
2857 int flag;
2858 idmap_stat map_stat = 0;
2859 int type_from;
2860 int type_to;
2861 name_mapping_t *nm = NULL;
2862 char *fromname;
2863 char *toname;
2864 idmap_info info;
2865
2866 (void) memset(&info, 0, sizeof (info));
2867
2868 if (argc == 0) {
2869 print_error(pos,
2870 gettext("No identity given\n"));
2871 return (-1);
2872 } else if (argc > 2) {
2873 print_error(pos,
2874 gettext("Too many arguments.\n"));
2875 return (-1);
2876 }
2877
2878 flag = 0;
2879 if (f[c_FLAG] == NULL)
2880 flag |= IDMAP_REQ_FLG_NO_NEW_ID_ALLOC;
2881 if (f[v_FLAG] != NULL)
2882 flag |= IDMAP_REQ_FLG_MAPPING_INFO;
2883 if (f[V_FLAG] != NULL)
2884 flag |= IDMAP_REQ_FLG_TRACE;
2885
2886 nm = name_mapping_init();
2887 if (nm == NULL)
2888 goto cleanup;
2889
2890 type_from = name2parts(argv[0], nm, pos);
2891 if (type_from <= 0) {
2892 stat = IDMAP_ERR_ARG;
2893 goto cleanup;
2894 }
2895
2896
2897 /* Second, determine type_to: */
2898 if (argc < 2) {
2899 type_to = type_from & IS_WIN ? TYPE_PID : TYPE_SID;
2900 if (type_from & IS_NAME)
2901 type_to |= IS_NAME;
2902 } else {
2903 type_to = string2type(argv[1], pos);
2904 if (type_to == TYPE_INVALID) {
2905 stat = IDMAP_ERR_ARG;
2906 goto cleanup;
2907 }
2908 }
2909
2910 if (type_to & IS_WIN) {
2911 if (type_to & IS_USER)
2912 nm->is_wuser = IDMAP_YES;
2913 else if (type_to & IS_GROUP)
2914 nm->is_wuser = IDMAP_NO;
2915 else
2916 nm->is_wuser = IDMAP_UNKNOWN;
2917 } else {
2918 if (type_to & IS_USER)
2919 nm->is_user = IDMAP_YES;
2920 else if (type_to & IS_GROUP)
2921 nm->is_user = IDMAP_NO;
2922 }
2923
2924 /* Are both arguments the same OS side? */
2925 if (!(type_from & IS_WIN ^ type_to & IS_WIN)) {
2926 print_error(pos,
2927 gettext("Direction ambiguous.\n"));
2928 stat = IDMAP_ERR_ARG;
2929 goto cleanup;
2930 }
2931
2932 /*
2933 * We have two interfaces for retrieving the mappings:
2934 * idmap_get_sidbyuid & comp (the batch interface) and
2935 * idmap_get_w2u_mapping & comp. We want to use both of them, because
2936 * the former mimicks kernel interface better and the later offers the
2937 * string names. In the batch case, our batch has always size 1.
2938 *
2939 * Btw, type_from cannot be IDMAP_PID, because there is no type string
2940 * for it.
2941 */
2942
2943 if (type_from & IS_NAME || type_to & IS_NAME ||
2944 type_from == TYPE_GSID || type_from == TYPE_USID ||
2945 type_to == TYPE_GSID || type_to == TYPE_USID) {
2946 if (type_from & IS_WIN) {
2947 map_stat = idmap_get_w2u_mapping(
2948 nm->sidprefix,
2949 &nm->rid,
2950 nm->winname,
2951 nm->windomain,
2952 flag,
2953 &nm->is_user, &nm->is_wuser,
2954 &nm->pid,
2955 &nm->unixname,
2956 &nm->direction,
2957 &info);
2958 } else {
2959 map_stat = idmap_get_u2w_mapping(
2960 &nm->pid,
2961 nm->unixname,
2962 flag,
2963 nm->is_user, &nm->is_wuser,
2964 &nm->sidprefix,
2965 &nm->rid,
2966 &nm->winname,
2967 &nm->windomain,
2968 &nm->direction,
2969 &info);
2970 }
2971
2972 } else {
2973 /* batch handle */
2974 idmap_get_handle_t *ghandle = NULL;
2975 /* To be passed to idmap_get_uidbysid */
2976 gid_t gid = UNDEFINED_GID;
2977 /* To be passed to idmap_get_gidbysid */
2978 uid_t uid = UNDEFINED_UID;
2979
2980
2981 /* Create an in-memory structure for all the batch: */
2982 stat = idmap_get_create(&ghandle);
2983 if (stat != IDMAP_SUCCESS) {
2984 print_error(pos,
2985 gettext("Unable to create handle for communicating"
2986 " with idmapd(8) (%s)\n"),
2987 idmap_stat2string(stat));
2988 idmap_get_destroy(ghandle);
2989 goto cleanup;
2990 }
2991
2992 /* Schedule the request: */
2993 if (type_to == TYPE_UID) {
2994 stat = idmap_getext_uidbysid(ghandle,
2995 nm->sidprefix,
2996 nm->rid,
2997 flag,
2998 &uid,
2999 &info,
3000 &map_stat);
3001 } else if (type_to == TYPE_GID) {
3002 stat = idmap_getext_gidbysid(ghandle,
3003 nm->sidprefix,
3004 nm->rid,
3005 flag,
3006 &gid,
3007 &info,
3008 &map_stat);
3009 } else if (type_to == TYPE_PID) {
3010 stat = idmap_getext_pidbysid(ghandle,
3011 nm->sidprefix,
3012 nm->rid,
3013 flag,
3014 &nm->pid,
3015 &nm->is_user,
3016 &info,
3017 &map_stat);
3018 } else if (type_from == TYPE_UID) {
3019 stat = idmap_getext_sidbyuid(ghandle,
3020 nm->pid,
3021 flag,
3022 &nm->sidprefix,
3023 &nm->rid,
3024 &info,
3025 &map_stat);
3026 } else if (type_from == TYPE_GID) {
3027 stat = idmap_getext_sidbygid(ghandle,
3028 (gid_t)nm->pid,
3029 flag,
3030 &nm->sidprefix,
3031 &nm->rid,
3032 &info,
3033 &map_stat);
3034 } else {
3035 /* This can never happen: */
3036 print_error(pos,
3037 gettext("Internal error in show.\n"));
3038 exit(1);
3039 }
3040
3041 if (stat < 0) {
3042 print_error(pos,
3043 gettext("Request for %.3s not sent (%s)\n"),
3044 argv[0], idmap_stat2string(stat));
3045 idmap_get_destroy(ghandle);
3046 goto cleanup;
3047 }
3048
3049 /* Send the batch to idmapd and obtain results: */
3050 stat = idmap_get_mappings(ghandle);
3051 if (stat < 0) {
3052 print_error(pos,
3053 gettext("Mappings not obtained because of"
3054 " RPC problem (%s)\n"),
3055 idmap_stat2string(stat));
3056 idmap_get_destroy(ghandle);
3057 goto cleanup;
3058 }
3059
3060 /* Destroy the batch handle: */
3061 idmap_get_destroy(ghandle);
3062
3063 if (type_to == TYPE_UID)
3064 nm->pid = uid;
3065 else if (type_to == TYPE_GID)
3066 nm->pid = (uid_t)gid;
3067
3068 }
3069
3070 /*
3071 * If there was -c flag, we do output whatever we can even in
3072 * the case of error:
3073 */
3074 if (map_stat < 0 && flag & IDMAP_REQ_FLG_NO_NEW_ID_ALLOC)
3075 goto errormsg;
3076
3077 /*
3078 * idmapd returns fallback uid/gid in case of errors. However
3079 * it uses special sentinel value i.e 4294967295 (or -1) to
3080 * indicate that falbback pid is not available either. In such
3081 * case idmap(8) should not display the mapping because there
3082 * is no fallback mapping.
3083 */
3084
3085 if ((type_to == TYPE_UID || type_to == TYPE_GID ||
3086 type_to == TYPE_PID) && nm->pid == UNDEFINED_UID)
3087 goto errormsg;
3088
3089 if (nm2type(nm, type_from, &fromname) < 0)
3090 goto errormsg;
3091
3092 if (nm2type(nm, type_to, &toname) < 0) {
3093 if (!(flag & IDMAP_REQ_FLG_NO_NEW_ID_ALLOC))
3094 (void) printf("%s -> %s:%u\n",
3095 fromname,
3096 type_to & IS_GROUP ? ID_GID : ID_UID,
3097 UID_NOBODY);
3098 free(fromname);
3099 } else {
3100 (void) printf("%s -> %s\n", fromname, toname);
3101 free(fromname);
3102 free(toname);
3103 }
3104
3105 errormsg:
3106 if (map_stat < 0) {
3107 print_error(pos, gettext("Error:\t%s\n"),
3108 idmap_stat2string(map_stat));
3109 print_error_info(&info);
3110 } else {
3111 print_info(&info);
3112 }
3113 idmap_info_free(&info);
3114
3115 cleanup:
3116 if (nm != NULL)
3117 name_mapping_fini(nm);
3118 return (stat < 0 || map_stat < 0 ? -1 : 0);
3119 }
3120
3121
3122 static int
flags2cred(flag_t * f,char ** user,char ** passwd,cmd_pos_t * pos)3123 flags2cred(flag_t *f, char **user, char **passwd, cmd_pos_t *pos)
3124 {
3125
3126 *user = NULL;
3127 *passwd = NULL;
3128
3129 if (f[D_FLAG] == NULL)
3130 return (0); /* GSSAPI authentification => OK */
3131
3132 *user = strdup(f[D_FLAG]);
3133 if (*user == NULL) {
3134 print_error(pos, "%s.\n", strerror(ENOMEM));
3135 return (-1);
3136 }
3137
3138 /* Password: */
3139
3140 if (f[j_FLAG] != NULL) {
3141 char line[MAX_INPUT_LINE_SZ];
3142 int i;
3143 FILE *file = fopen(f[j_FLAG], "r");
3144
3145 if (file == NULL) {
3146 print_error(pos,
3147 gettext("Failed to open password file \"%s\": (%s)"
3148 ".\n"), f[j_FLAG], strerror(errno));
3149 goto fail;
3150 }
3151
3152 /* The password is the fist line, we ignore the rest: */
3153 if (fgets(line, MAX_INPUT_LINE_SZ, file) == NULL) {
3154 print_error(pos,
3155 gettext("The password file \"%s\" is empty.\n"),
3156 f[j_FLAG]);
3157 (void) fclose(file);
3158 goto fail;
3159 }
3160
3161 if (fclose(file) != 0) {
3162 print_error(pos,
3163 gettext("Unable to close the password file \"%s\""
3164 ".\n"), f[j_FLAG], strerror(errno));
3165 goto fail;
3166 }
3167
3168 /* Trim the eol: */
3169 for (i = strlen(line) - 1;
3170 i >= 0 && (line[i] == '\r' || line[i] == '\n');
3171 i--)
3172 line[i] = '\0';
3173
3174 *passwd = strdup(line);
3175 if (*passwd == NULL) {
3176 print_error(pos, "%s.\n", strerror(ENOMEM));
3177 goto fail;
3178 }
3179 } else if (!batch_mode) {
3180 /* If in the interactive mode, read the terminal input: */
3181 char *it = getpassphrase("Enter password:");
3182 if (it == NULL) {
3183 print_error(NULL,
3184 gettext("Failed to get password (%s).\n"),
3185 strerror(errno));
3186 goto fail;
3187 }
3188
3189 *passwd = strdup(it);
3190 (void) memset(it, 0, strlen(it));
3191
3192 if (*passwd == NULL) {
3193 print_error(pos, "%s.\n", strerror(ENOMEM));
3194 goto fail;
3195 }
3196 } else {
3197 print_error(pos, gettext("No password given.\n"));
3198 goto fail;
3199 }
3200
3201 return (0);
3202 fail:
3203 if (*passwd != NULL) {
3204 (void) memset(*passwd, 0, strlen(*passwd));
3205 free(*passwd);
3206 *passwd = NULL;
3207 }
3208
3209 free(*user);
3210 return (-1);
3211 }
3212
3213
3214 static int
do_set_namemap(flag_t * f,int argc,char ** argv,cmd_pos_t * pos)3215 do_set_namemap(flag_t *f, int argc, char **argv, cmd_pos_t *pos)
3216 {
3217 idmap_stat stat;
3218 name_mapping_t *nm;
3219 int is_first_win;
3220 char *user;
3221 char *passwd;
3222
3223 if (argc < 2) {
3224 print_error(pos,
3225 gettext("Not enough arguments: two names needed for a "
3226 "namemap.\n"));
3227 return (-1);
3228 } else if (argc > 2) {
3229 print_error(pos,
3230 gettext("Too many arguments: two names needed for a "
3231 "namemap.\n"));
3232 return (-1);
3233 }
3234
3235 nm = args2nm(&is_first_win, argc, argv, pos);
3236 if (nm == NULL)
3237 return (-1);
3238
3239 if (flags2cred(f, &user, &passwd, pos) < 0)
3240 return (-1);
3241
3242 nm->direction = is_first_win ? IDMAP_DIRECTION_W2U
3243 : IDMAP_DIRECTION_U2W;
3244
3245 if (init_nm_command(user, passwd, f[a_FLAG], nm->windomain,
3246 nm->direction, pos) < 0)
3247 return (-1);
3248
3249
3250 stat = idmap_set_namemap(namemaps.handle, nm->winname, nm->unixname,
3251 nm->is_user, nm->is_wuser, nm->direction);
3252
3253 if (stat != IDMAP_SUCCESS) {
3254 print_error(pos,
3255 gettext("Failed to set namemap (%s).\n"),
3256 idmap_stat2string(stat));
3257 }
3258
3259 if (passwd != NULL) {
3260 (void) memset(passwd, 0, strlen(passwd));
3261 free(passwd);
3262 }
3263
3264 free(user);
3265
3266 fini_nm_command();
3267 name_mapping_fini(nm);
3268 return (stat != IDMAP_SUCCESS ? -1 : 0);
3269 }
3270
3271 static int
do_unset_namemap(flag_t * f,int argc,char ** argv,cmd_pos_t * pos)3272 do_unset_namemap(flag_t *f, int argc, char **argv, cmd_pos_t *pos)
3273 {
3274 idmap_stat stat;
3275 name_mapping_t *nm;
3276 int is_first_win;
3277 char *user;
3278 char *passwd;
3279
3280 if (argc < 1) {
3281 print_error(pos,
3282 gettext("Not enough arguments: a name needed to unset a "
3283 "namemap.\n"));
3284 return (-1);
3285 } else if (argc > 2) {
3286 print_error(pos,
3287 gettext("Too many arguments: Only target name and type is "
3288 "needed to unset namemap.\n"));
3289 return (-1);
3290 }
3291
3292 nm = args2nm(&is_first_win, 1, argv, pos);
3293 if (nm == NULL)
3294 return (-1);
3295
3296 if (flags2cred(f, &user, &passwd, pos) < 0)
3297 return (-1);
3298
3299 nm->direction = is_first_win ? IDMAP_DIRECTION_W2U
3300 : IDMAP_DIRECTION_U2W;
3301
3302 if (argc > 1 && !is_first_win) {
3303 print_error(pos,
3304 gettext("Target type \"%s\" is redundant.\n"),
3305 argv[1]);
3306 stat = IDMAP_ERR_ARG;
3307 goto cleanup;
3308 } else if (argc > 1) {
3309 switch (string2type(argv[1], pos)) {
3310 case TYPE_INVALID:
3311 name_mapping_fini(nm);
3312 return (-1);
3313 case TYPE_UU:
3314 nm->is_user = IDMAP_YES;
3315 break;
3316 case TYPE_UG:
3317 nm->is_user = IDMAP_NO;
3318 break;
3319 default:
3320 print_error(pos,
3321 gettext("Invalid target type \"%s\": here the "
3322 "possible target type is unixuser or "
3323 "unixgroup.\n"), argv[1]);
3324 stat = IDMAP_ERR_ARG;
3325 goto cleanup;
3326 }
3327 }
3328
3329 if (init_nm_command(user, passwd, f[a_FLAG], nm->windomain,
3330 nm->direction, pos) < 0)
3331 return (-1);
3332
3333 stat = idmap_unset_namemap(namemaps.handle, nm->winname, nm->unixname,
3334 nm->is_user, nm->is_wuser, nm->direction);
3335
3336 if (stat != IDMAP_SUCCESS) {
3337 print_error(pos,
3338 gettext("Failed to unset namemap (%s).\n"),
3339 idmap_stat2string(stat));
3340 }
3341
3342 cleanup:
3343 if (passwd != NULL) {
3344 (void) memset(passwd, 0, strlen(passwd));
3345 free(passwd);
3346 }
3347
3348 free(user);
3349
3350 fini_nm_command();
3351 name_mapping_fini(nm);
3352 return (stat == IDMAP_SUCCESS ? 0 : -1);
3353 }
3354
3355 static int
3356 /* LINTED E_FUNC_ARG_UNUSED */
do_get_namemap(flag_t * f,int argc,char ** argv,cmd_pos_t * pos)3357 do_get_namemap(flag_t *f, int argc, char **argv, cmd_pos_t *pos)
3358 {
3359 idmap_stat stat;
3360 name_mapping_t *nm;
3361 int is_first_win;
3362 int is_source_ad;
3363 char *winname = NULL;
3364 char *unixname = NULL;
3365 char *unixuser = NULL;
3366 char *unixgroup = NULL;
3367
3368 if (argc < 1) {
3369 print_error(pos,
3370 gettext("Not enough arguments: a name needed to get a "
3371 "namemap.\n"));
3372 return (-1);
3373 } else if (argc > 1) {
3374 print_error(pos,
3375 gettext("Too many arguments: just one name needed to get "
3376 "a namemap.\n"));
3377 return (-1);
3378 }
3379
3380 nm = args2nm(&is_first_win, argc, argv, pos);
3381 if (nm == NULL)
3382 return (-1);
3383
3384 nm->direction = is_first_win ? IDMAP_DIRECTION_W2U
3385 : IDMAP_DIRECTION_U2W;
3386
3387 /* nm->is_user is IDMAP_UNKNOWN for IDMAP_DIRECTION_W2U */
3388 if (nm->is_user == IDMAP_YES) {
3389 unixuser = strdup(nm->unixname);
3390 if (unixuser == NULL) {
3391 print_error(pos, "%s.\n", strerror(ENOMEM));
3392 goto cleanup;
3393 }
3394 } else if (nm->is_user == IDMAP_NO) {
3395 unixgroup = strdup(nm->unixname);
3396 if (unixgroup == NULL) {
3397 print_error(pos, "%s.\n", strerror(ENOMEM));
3398 goto cleanup;
3399 }
3400 }
3401
3402 if (init_nm_command(NULL, NULL, NULL, nm->windomain,
3403 nm->direction, pos) < 0)
3404 return (-1);
3405
3406 stat = idmap_get_namemap(namemaps.handle, &is_source_ad, &nm->winname,
3407 &nm->windomain, &nm->is_wuser, &unixuser, &unixgroup);
3408
3409 if (stat != IDMAP_SUCCESS) {
3410 print_error(pos,
3411 gettext("Failed to get namemap info (%s).\n"),
3412 idmap_stat2string(stat));
3413 goto cleanup;
3414 }
3415
3416 if (nm2winqn(nm, &winname) < 0)
3417 goto cleanup;
3418
3419 switch (is_source_ad) {
3420 case IDMAP_YES:
3421 if (unixuser == NULL && unixgroup == NULL)
3422 (void) printf(gettext("\t\tNo namemap found in AD.\n"));
3423 else {
3424 (void) printf(gettext("AD namemaps for %s\n"), winname);
3425 if (unixuser != NULL)
3426 (void) printf(gettext("\t\t->\t%s:%s\n"),
3427 ID_UNIXUSER, unixuser);
3428
3429 if (unixgroup != NULL)
3430 (void) printf(gettext("\t\t->\t%s:%s\n"),
3431 ID_UNIXGROUP, unixgroup);
3432 }
3433 break;
3434 case IDMAP_NO:
3435 if (nm2unixname(nm, &unixname) < 0)
3436 goto cleanup;
3437
3438 if (nm->winname == NULL)
3439 (void) printf(gettext("\t\tNo namemap found in "
3440 "native LDAP.\n"));
3441 else {
3442 (void) printf(gettext("Native LDAP namemap for %s\n"),
3443 unixname);
3444 (void) printf(gettext("\t\t->\t%s\n"), winname);
3445 }
3446 break;
3447 default:
3448 /*
3449 * This can never happen; the error must be recognized in
3450 * args2nm
3451 */
3452 print_error(pos,
3453 gettext("Internal error: unknown source of namemaps.\n"));
3454 }
3455
3456 cleanup:
3457 fini_nm_command();
3458 name_mapping_fini(nm);
3459 if (winname != NULL)
3460 free(winname);
3461 if (unixuser != NULL)
3462 free(unixuser);
3463 if (unixgroup != NULL)
3464 free(unixgroup);
3465 return (stat == IDMAP_SUCCESS ? 0 : -1);
3466 }
3467
3468
3469 /* printflike */
3470 static
3471 void
idmap_cli_logger(int pri,const char * format,...)3472 idmap_cli_logger(int pri, const char *format, ...)
3473 {
3474 va_list args;
3475
3476 if (pri == LOG_DEBUG)
3477 return;
3478
3479 va_start(args, format);
3480
3481 (void) vfprintf(stderr, format, args);
3482 (void) fprintf(stderr, "\n");
3483
3484 va_end(args);
3485 }
3486
3487
3488 /* main function. Returns 1 for error, 0 otherwise */
3489 int
main(int argc,char * argv[])3490 main(int argc, char *argv[])
3491 {
3492 int rc;
3493
3494 /* set locale and domain for internationalization */
3495 (void) setlocale(LC_ALL, "");
3496 (void) textdomain(TEXT_DOMAIN);
3497
3498 /* Redirect logging */
3499 idmap_set_logger(idmap_cli_logger);
3500 adutils_set_logger(idmap_cli_logger);
3501
3502 /* idmap_engine determines the batch_mode: */
3503 rc = engine_init(sizeof (commands) / sizeof (cmd_ops_t),
3504 commands,
3505 argc - 1,
3506 argv + 1,
3507 &batch_mode);
3508
3509 if (rc < 0) {
3510 (void) engine_fini();
3511 if (rc == IDMAP_ENG_ERROR_SILENT)
3512 help();
3513 return (1);
3514 }
3515
3516 udt_used = 0;
3517 if (batch_mode) {
3518 if (init_udt_batch() < 0)
3519 return (1);
3520 }
3521
3522 rc = run_engine(argc - 1, argv + 1);
3523
3524 if (batch_mode) {
3525 batch_mode = 0;
3526 if (fini_udt_command(rc == 0 ? 1 : 0, NULL))
3527 rc = -1;
3528 fini_nm_command();
3529 }
3530
3531 (void) engine_fini();
3532 return (rc == 0 ? 0 : 1);
3533 }
3534