1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
24 */
25
26 /*
27 * This module contains smbadm CLI which offers smb configuration
28 * functionalities.
29 */
30 #include <errno.h>
31 #include <err.h>
32 #include <ctype.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <stdio.h>
36 #include <syslog.h>
37 #include <strings.h>
38 #include <limits.h>
39 #include <getopt.h>
40 #include <libintl.h>
41 #include <zone.h>
42 #include <pwd.h>
43 #include <grp.h>
44 #include <libgen.h>
45 #include <netinet/in.h>
46 #include <auth_attr.h>
47 #include <locale.h>
48 #include <smbsrv/libsmb.h>
49 #include <smbsrv/libsmbns.h>
50
51 #if !defined(TEXT_DOMAIN)
52 #define TEXT_DOMAIN "SYS_TEST"
53 #endif
54
55 typedef enum {
56 HELP_ADD_MEMBER,
57 HELP_CREATE,
58 HELP_DELETE,
59 HELP_DEL_MEMBER,
60 HELP_GET,
61 HELP_JOIN,
62 HELP_LIST,
63 HELP_LOOKUP,
64 HELP_RENAME,
65 HELP_SET,
66 HELP_SHOW,
67 HELP_USER_DISABLE,
68 HELP_USER_ENABLE,
69 HELP_USER_DELETE
70 } smbadm_help_t;
71
72 #define SMBADM_CMDF_NONE 0x00
73 #define SMBADM_CMDF_USER 0x01
74 #define SMBADM_CMDF_GROUP 0x02
75 #define SMBADM_CMDF_TYPEMASK 0x0F
76
77 typedef enum {
78 SMBADM_GRP_ADDMEMBER = 0,
79 SMBADM_GRP_DELMEMBER,
80 } smbadm_grp_action_t;
81
82 #define SMBADM_ANSBUFSIZ 64
83
84 typedef struct smbadm_cmdinfo {
85 char *name;
86 int (*func)(int, char **);
87 smbadm_help_t usage;
88 uint32_t flags;
89 char *auth;
90 } smbadm_cmdinfo_t;
91
92 smbadm_cmdinfo_t *curcmd;
93 static char *progname;
94
95 #define SMBADM_ACTION_AUTH "solaris.smf.manage.smb"
96 #define SMBADM_VALUE_AUTH "solaris.smf.value.smb"
97 #define SMBADM_BASIC_AUTH "solaris.network.hosts.read"
98
99 static boolean_t smbadm_checkauth(const char *);
100
101 static void smbadm_usage(boolean_t);
102 static int smbadm_join_workgroup(const char *, boolean_t);
103 static int smbadm_join_domain(const char *, const char *, boolean_t);
104 static void smbadm_extract_domain(char *, char **, char **);
105
106 static int smbadm_join(int, char **);
107 static int smbadm_list(int, char **);
108 static int smbadm_lookup(int, char **);
109 static void smbadm_lookup_name(char *);
110 static void smbadm_lookup_sid(char *);
111 static int smbadm_group_create(int, char **);
112 static int smbadm_group_delete(int, char **);
113 static int smbadm_group_rename(int, char **);
114 static int smbadm_group_show(int, char **);
115 static void smbadm_group_show_name(const char *, const char *);
116 static int smbadm_group_getprop(int, char **);
117 static int smbadm_group_setprop(int, char **);
118 static int smbadm_group_addmember(int, char **);
119 static int smbadm_group_delmember(int, char **);
120 static int smbadm_group_add_del_member(char *, char *, smbadm_grp_action_t);
121
122 static int smbadm_user_delete(int, char **);
123 static int smbadm_user_disable(int, char **);
124 static int smbadm_user_enable(int, char **);
125
126 /* Please keep the order consistent with smbadm(1M) man page */
127 static smbadm_cmdinfo_t smbadm_cmdtable[] =
128 {
129 { "create", smbadm_group_create, HELP_CREATE,
130 SMBADM_CMDF_GROUP, SMBADM_ACTION_AUTH },
131 { "delete", smbadm_group_delete, HELP_DELETE,
132 SMBADM_CMDF_GROUP, SMBADM_ACTION_AUTH },
133 { "rename", smbadm_group_rename, HELP_RENAME,
134 SMBADM_CMDF_GROUP, SMBADM_ACTION_AUTH },
135 { "show", smbadm_group_show, HELP_SHOW,
136 SMBADM_CMDF_GROUP, SMBADM_ACTION_AUTH },
137 { "get", smbadm_group_getprop, HELP_GET,
138 SMBADM_CMDF_GROUP, SMBADM_ACTION_AUTH },
139 { "set", smbadm_group_setprop, HELP_SET,
140 SMBADM_CMDF_GROUP, SMBADM_ACTION_AUTH },
141 { "add-member", smbadm_group_addmember, HELP_ADD_MEMBER,
142 SMBADM_CMDF_GROUP, SMBADM_ACTION_AUTH },
143 { "remove-member", smbadm_group_delmember, HELP_DEL_MEMBER,
144 SMBADM_CMDF_GROUP, SMBADM_ACTION_AUTH },
145 { "delete-user", smbadm_user_delete, HELP_USER_DELETE,
146 SMBADM_CMDF_USER, SMBADM_ACTION_AUTH },
147 { "disable-user", smbadm_user_disable, HELP_USER_DISABLE,
148 SMBADM_CMDF_USER, SMBADM_ACTION_AUTH },
149 { "enable-user", smbadm_user_enable, HELP_USER_ENABLE,
150 SMBADM_CMDF_USER, SMBADM_ACTION_AUTH },
151 { "join", smbadm_join, HELP_JOIN,
152 SMBADM_CMDF_NONE, SMBADM_VALUE_AUTH },
153 { "list", smbadm_list, HELP_LIST,
154 SMBADM_CMDF_NONE, SMBADM_BASIC_AUTH },
155 { "lookup", smbadm_lookup, HELP_LOOKUP,
156 SMBADM_CMDF_NONE, SMBADM_BASIC_AUTH },
157 };
158
159 #define SMBADM_NCMD (sizeof (smbadm_cmdtable) / sizeof (smbadm_cmdtable[0]))
160
161 typedef struct smbadm_prop {
162 char *p_name;
163 char *p_value;
164 } smbadm_prop_t;
165
166 typedef struct smbadm_prop_handle {
167 char *p_name;
168 char *p_dispvalue;
169 int (*p_setfn)(char *, smbadm_prop_t *);
170 int (*p_getfn)(char *, smbadm_prop_t *);
171 boolean_t (*p_chkfn)(smbadm_prop_t *);
172 } smbadm_prop_handle_t;
173
174 static boolean_t smbadm_prop_validate(smbadm_prop_t *prop, boolean_t chkval);
175 static int smbadm_prop_parse(char *arg, smbadm_prop_t *prop);
176 static smbadm_prop_handle_t *smbadm_prop_gethandle(char *pname);
177
178 static boolean_t smbadm_chkprop_priv(smbadm_prop_t *prop);
179 static int smbadm_setprop_tkowner(char *gname, smbadm_prop_t *prop);
180 static int smbadm_getprop_tkowner(char *gname, smbadm_prop_t *prop);
181 static int smbadm_setprop_backup(char *gname, smbadm_prop_t *prop);
182 static int smbadm_getprop_backup(char *gname, smbadm_prop_t *prop);
183 static int smbadm_setprop_restore(char *gname, smbadm_prop_t *prop);
184 static int smbadm_getprop_restore(char *gname, smbadm_prop_t *prop);
185 static int smbadm_setprop_desc(char *gname, smbadm_prop_t *prop);
186 static int smbadm_getprop_desc(char *gname, smbadm_prop_t *prop);
187
188 static smbadm_prop_handle_t smbadm_ptable[] = {
189 {"backup", "on|off", smbadm_setprop_backup,
190 smbadm_getprop_backup, smbadm_chkprop_priv },
191 {"restore", "on|off", smbadm_setprop_restore,
192 smbadm_getprop_restore, smbadm_chkprop_priv },
193 {"take-ownership", "on|off", smbadm_setprop_tkowner,
194 smbadm_getprop_tkowner, smbadm_chkprop_priv },
195 {"description", "<string>", smbadm_setprop_desc,
196 smbadm_getprop_desc, NULL },
197 };
198
199 static int smbadm_init(void);
200 static void smbadm_fini(void);
201 static const char *smbadm_pwd_strerror(int error);
202
203 /*
204 * Number of supported properties
205 */
206 #define SMBADM_NPROP (sizeof (smbadm_ptable) / sizeof (smbadm_ptable[0]))
207
208 static void
209 smbadm_cmdusage(FILE *fp, smbadm_cmdinfo_t *cmd)
210 {
211 switch (cmd->usage) {
212 case HELP_ADD_MEMBER:
213 (void) fprintf(fp,
214 gettext("\t%s -m <member> [-m <member>]... <group>\n"),
215 cmd->name);
216 return;
217
218 case HELP_CREATE:
219 (void) fprintf(fp, gettext("\t%s [-d <description>] <group>\n"),
220 cmd->name);
221 return;
222
223 case HELP_DELETE:
224 (void) fprintf(fp, gettext("\t%s <group>\n"), cmd->name);
225 return;
226
227 case HELP_USER_DELETE:
228 case HELP_USER_DISABLE:
229 case HELP_USER_ENABLE:
230 (void) fprintf(fp, gettext("\t%s <username>\n"), cmd->name);
231 return;
232
233 case HELP_GET:
234 (void) fprintf(fp, gettext("\t%s [-p <property>]... <group>\n"),
235 cmd->name);
236 return;
237
238 case HELP_JOIN:
239 #if 0 /* Don't document "-p" yet, still needs work (NEX-11960) */
240 (void) fprintf(fp, gettext("\t%s [-y] -p <domain>\n"
241 "\t%s [-y] -u <username domain>\n"
242 "\t%s [-y] -w <workgroup>\n"),
243 cmd->name, cmd->name, cmd->name);
244 #else
245 (void) fprintf(fp, gettext("\t%s [-y] -u <username> <domain>\n"
246 "\t%s [-y] -w <workgroup>\n"), cmd->name, cmd->name);
247 #endif
248 return;
249
250 case HELP_LIST:
251 (void) fprintf(fp, gettext("\t%s\n"), cmd->name);
252 return;
253
254 case HELP_LOOKUP:
255 (void) fprintf(fp,
256 gettext("\t%s <account-name>\n"),
257 cmd->name);
258 return;
259
260 case HELP_DEL_MEMBER:
261 (void) fprintf(fp,
262 gettext("\t%s -m <member> [-m <member>]... <group>\n"),
263 cmd->name);
264 return;
265
266 case HELP_RENAME:
267 (void) fprintf(fp, gettext("\t%s <group> <new-group>\n"),
268 cmd->name);
269 return;
270
271 case HELP_SET:
272 (void) fprintf(fp, gettext("\t%s -p <property>=<value> "
273 "[-p <property>=<value>]... <group>\n"), cmd->name);
274 return;
275
276 case HELP_SHOW:
277 (void) fprintf(fp, gettext("\t%s [-mp] [<group>]\n"),
278 cmd->name);
279 return;
280
281 default:
282 break;
283 }
284
285 abort();
286 /* NOTREACHED */
287 }
288
289 static void
290 smbadm_usage(boolean_t requested)
291 {
292 FILE *fp = requested ? stdout : stderr;
293 boolean_t show_props = B_FALSE;
294 int i;
295
296 if (curcmd == NULL) {
297 (void) fprintf(fp,
298 gettext("usage: %s <subcommand> <args> ...\n"),
299 progname);
300
301 for (i = 0; i < SMBADM_NCMD; i++)
302 smbadm_cmdusage(fp, &smbadm_cmdtable[i]);
303
304 (void) fprintf(fp,
305 gettext("\nFor property list, run %s %s|%s\n"),
306 progname, "get", "set");
307
308 exit(requested ? 0 : 2);
309 }
310
311 (void) fprintf(fp, gettext("usage:\n"));
312 smbadm_cmdusage(fp, curcmd);
313
314 if (strcmp(curcmd->name, "get") == 0 ||
315 strcmp(curcmd->name, "set") == 0)
316 show_props = B_TRUE;
317
318 if (show_props) {
319 (void) fprintf(fp,
320 gettext("\nThe following properties are supported:\n"));
321
322 (void) fprintf(fp, "\n\t%-16s %s\n\n",
323 "PROPERTY", "VALUES");
324
325 for (i = 0; i < SMBADM_NPROP; i++) {
326 (void) fprintf(fp, "\t%-16s %s\n",
327 smbadm_ptable[i].p_name,
328 smbadm_ptable[i].p_dispvalue);
329 }
330 }
331
332 exit(requested ? 0 : 2);
333 }
334
335 /*
336 * smbadm_strcasecmplist
337 *
338 * Find a string 's' within a list of strings.
339 *
340 * Returns the index of the matching string or -1 if there is no match.
341 */
342 static int
343 smbadm_strcasecmplist(const char *s, ...)
344 {
345 va_list ap;
346 char *p;
347 int ndx;
348
349 va_start(ap, s);
350
351 for (ndx = 0; ((p = va_arg(ap, char *)) != NULL); ++ndx) {
352 if (strcasecmp(s, p) == 0) {
353 va_end(ap);
354 return (ndx);
355 }
356 }
357
358 va_end(ap);
359 return (-1);
360 }
361
362 /*
363 * smbadm_answer_prompt
364 *
365 * Prompt for the answer to a question. A default response must be
366 * specified, which will be used if the user presses <enter> without
367 * answering the question.
368 */
369 static int
370 smbadm_answer_prompt(const char *prompt, char *answer, const char *dflt)
371 {
372 char buf[SMBADM_ANSBUFSIZ];
373 char *p;
374
375 (void) printf(gettext("%s [%s]: "), prompt, dflt);
376
377 if (fgets(buf, SMBADM_ANSBUFSIZ, stdin) == NULL)
378 return (-1);
379
380 if ((p = strchr(buf, '\n')) != NULL)
381 *p = '\0';
382
383 if (*buf == '\0')
384 (void) strlcpy(answer, dflt, SMBADM_ANSBUFSIZ);
385 else
386 (void) strlcpy(answer, buf, SMBADM_ANSBUFSIZ);
387
388 return (0);
389 }
390
391 /*
392 * smbadm_confirm
393 *
394 * Ask a question that requires a yes/no answer.
395 * A default response must be specified.
396 */
397 static boolean_t
398 smbadm_confirm(const char *prompt, const char *dflt)
399 {
400 char buf[SMBADM_ANSBUFSIZ];
401
402 for (;;) {
403 if (smbadm_answer_prompt(prompt, buf, dflt) < 0)
404 return (B_FALSE);
405
406 if (smbadm_strcasecmplist(buf, "n", "no", 0) >= 0)
407 return (B_FALSE);
408
409 if (smbadm_strcasecmplist(buf, "y", "yes", 0) >= 0)
410 return (B_TRUE);
411
412 (void) printf(gettext("Please answer yes or no.\n"));
413 }
414 }
415
416 static boolean_t
417 smbadm_join_prompt(const char *domain)
418 {
419 (void) printf(gettext("After joining %s the smb service will be "
420 "restarted automatically.\n"), domain);
421
422 return (smbadm_confirm("Would you like to continue?", "no"));
423 }
424
425 static void
426 smbadm_restart_service(void)
427 {
428 if (smb_smf_restart_service() != 0) {
429 (void) fprintf(stderr,
430 gettext("Unable to restart smb service. "
431 "Run 'svcs -xv smb/server' for more information."));
432 }
433 }
434
435 /*
436 * smbadm_join
437 *
438 * Join a domain or workgroup.
439 *
440 * When joining a domain, we may receive the username, password and
441 * domain name in any of the following combinations. Note that the
442 * password is optional on the command line: if it is not provided,
443 * we will prompt for it later.
444 *
445 * username+password domain
446 * domain\username+password
447 * domain/username+password
448 * username@domain
449 *
450 * We allow domain\name+password or domain/name+password but not
451 * name+password@domain because @ is a valid password character.
452 *
453 * If the username and domain name are passed as separate command
454 * line arguments, we process them directly. Otherwise we separate
455 * them and continue as if they were separate command line arguments.
456 */
457 static int
458 smbadm_join(int argc, char **argv)
459 {
460 char buf[MAXHOSTNAMELEN * 2];
461 char *domain = NULL;
462 char *username = NULL;
463 uint32_t mode = 0;
464 boolean_t do_prompt = B_TRUE;
465 char option;
466
467 while ((option = getopt(argc, argv, "pu:wy")) != -1) {
468 if (mode != 0) {
469 (void) fprintf(stderr, gettext(
470 "join options are mutually exclusive\n"));
471 smbadm_usage(B_FALSE);
472 }
473 switch (option) {
474 case 'p':
475 mode = SMB_SECMODE_DOMAIN;
476 /* leave username = NULL */
477 break;
478
479 case 'u':
480 mode = SMB_SECMODE_DOMAIN;
481 username = optarg;
482 break;
483
484 case 'w':
485 mode = SMB_SECMODE_WORKGRP;
486 break;
487
488 case 'y':
489 do_prompt = B_FALSE;
490 break;
491
492 default:
493 smbadm_usage(B_FALSE);
494 break;
495 }
496 }
497
498 if (optind < argc)
499 domain = argv[optind];
500
501 if (username != NULL && domain == NULL) {
502 /*
503 * The domain was not specified as a separate
504 * argument, check for the combination forms.
505 */
506 (void) strlcpy(buf, username, sizeof (buf));
507 smbadm_extract_domain(buf, &username, &domain);
508 }
509
510 if ((domain == NULL) || (*domain == '\0')) {
511 (void) fprintf(stderr, gettext("missing %s name\n"),
512 (mode == SMB_SECMODE_WORKGRP) ? "workgroup" : "domain");
513 smbadm_usage(B_FALSE);
514 }
515
516 if (mode == SMB_SECMODE_WORKGRP) {
517 return (smbadm_join_workgroup(domain, do_prompt));
518 }
519 return (smbadm_join_domain(domain, username, do_prompt));
520 }
521
522 /*
523 * Workgroups comprise a collection of standalone, independently administered
524 * computers that use a common workgroup name. This is a peer-to-peer model
525 * with no formal membership mechanism.
526 */
527 static int
528 smbadm_join_workgroup(const char *workgroup, boolean_t prompt)
529 {
530 smb_joininfo_t jdi;
531 smb_joinres_t jdres;
532 uint32_t status;
533
534 bzero(&jdres, sizeof (jdres));
535 bzero(&jdi, sizeof (jdi));
536 jdi.mode = SMB_SECMODE_WORKGRP;
537 (void) strlcpy(jdi.domain_name, workgroup, sizeof (jdi.domain_name));
538 (void) strtrim(jdi.domain_name, " \t\n");
539
540 if (smb_name_validate_workgroup(jdi.domain_name) != ERROR_SUCCESS) {
541 (void) fprintf(stderr, gettext("workgroup name is invalid\n"));
542 smbadm_usage(B_FALSE);
543 }
544
545 if (prompt && !smbadm_join_prompt(jdi.domain_name))
546 return (0);
547
548 if ((status = smb_join(&jdi, &jdres)) != NT_STATUS_SUCCESS) {
549 (void) fprintf(stderr, gettext("failed to join %s: %s\n"),
550 jdi.domain_name, xlate_nt_status(status));
551 return (1);
552 }
553
554 (void) printf(gettext("Successfully joined %s\n"), jdi.domain_name);
555 smbadm_restart_service();
556 return (0);
557 }
558
559 /*
560 * Domains comprise a centrally administered group of computers and accounts
561 * that share a common security and administration policy and database.
562 * Computers must join a domain and become domain members, which requires
563 * an administrator level account name.
564 *
565 * The '+' character is invalid within a username. We allow the password
566 * to be appended to the username using '+' as a scripting convenience.
567 */
568 static int
569 smbadm_join_domain(const char *domain, const char *username, boolean_t prompt)
570 {
571 smb_joininfo_t jdi;
572 smb_joinres_t jdres;
573 char *passwd_prompt;
574 char *p;
575 int len, rc;
576
577 bzero(&jdres, sizeof (jdres));
578 bzero(&jdi, sizeof (jdi));
579 jdi.mode = SMB_SECMODE_DOMAIN;
580 (void) strlcpy(jdi.domain_name, domain, sizeof (jdi.domain_name));
581 (void) strtrim(jdi.domain_name, " \t\n");
582
583 if (smb_name_validate_domain(jdi.domain_name) != ERROR_SUCCESS) {
584 (void) fprintf(stderr, gettext("domain name is invalid\n"));
585 smbadm_usage(B_FALSE);
586 }
587
588 if (prompt && !smbadm_join_prompt(jdi.domain_name))
589 return (0);
590
591 /*
592 * Note: username is null for "unsecure join"
593 * (join using a pre-created computer account)
594 * No password either.
595 */
596 if (username != NULL) {
597 if ((p = strchr(username, '+')) != NULL) {
598 ++p;
599
600 len = (int)(p - username);
601 if (len > sizeof (jdi.domain_name))
602 len = sizeof (jdi.domain_name);
603
604 (void) strlcpy(jdi.domain_username, username, len);
605 (void) strlcpy(jdi.domain_passwd, p,
606 sizeof (jdi.domain_passwd));
607 } else {
608 (void) strlcpy(jdi.domain_username, username,
609 sizeof (jdi.domain_username));
610 }
611
612 if (smb_name_validate_account(jdi.domain_username)
613 != ERROR_SUCCESS) {
614 (void) fprintf(stderr,
615 gettext("username contains invalid characters\n"));
616 smbadm_usage(B_FALSE);
617 }
618
619 if (*jdi.domain_passwd == '\0') {
620 passwd_prompt = gettext("Enter domain password: ");
621
622 if ((p = getpassphrase(passwd_prompt)) == NULL) {
623 (void) fprintf(stderr, gettext(
624 "missing password\n"));
625 smbadm_usage(B_FALSE);
626 }
627
628 (void) strlcpy(jdi.domain_passwd, p,
629 sizeof (jdi.domain_passwd));
630 }
631 }
632
633 (void) printf(gettext("Joining %s ... this may take a minute ...\n"),
634 jdi.domain_name);
635
636 rc = smb_join(&jdi, &jdres);
637 if (rc != 0) {
638 (void) printf(gettext("Cannot call the SMB service. "
639 " (error %d: %s) "
640 "Please check the service status "
641 "(svcs -vx network/smb/server)\n"),
642 rc, strerror(rc));
643 bzero(&jdi, sizeof (jdi));
644 return (1);
645 }
646
647 switch (jdres.status) {
648 case NT_STATUS_SUCCESS:
649 (void) printf(gettext(
650 "Successfully joined domain %s using AD server %s\n"),
651 jdi.domain_name, jdres.dc_name);
652 bzero(&jdi, sizeof (jdi));
653 smbadm_restart_service();
654 return (0);
655
656 case NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND:
657 /* See: smb_ads_lookup_msdcs */
658 (void) fprintf(stderr, gettext(
659 "failed to find any AD servers for domain: %s\n"),
660 jdi.domain_name);
661 goto common;
662
663 case NT_STATUS_BAD_NETWORK_PATH:
664 /* See: smbrdr_ctx_new / smb_ctx_resolve */
665 (void) fprintf(stderr, gettext(
666 "failed to resolve address of AD server: %s\n"),
667 jdres.dc_name);
668 goto common;
669
670 case NT_STATUS_NETWORK_ACCESS_DENIED:
671 /* See: smbrdr_ctx_new / smb_ctx_get_ssn */
672 (void) fprintf(stderr, gettext(
673 "failed to authenticate with AD server: %s\n"),
674 jdres.dc_name);
675 goto common;
676
677 case NT_STATUS_BAD_NETWORK_NAME:
678 /*
679 * See: smbrdr_ctx_new / smb_ctx_get_tree
680 * and: ndr_rpc_bind / smb_fh_open
681 */
682 (void) fprintf(stderr, gettext(
683 "failed connecting to services on AD server: %s\n"),
684 jdres.dc_name);
685 goto common;
686
687 default:
688 (void) fprintf(stderr, gettext(
689 "failed to join domain %s\n"),
690 jdi.domain_name);
691 if (jdres.dc_name[0] != '\0') {
692 (void) fprintf(stderr, gettext(
693 "using AD server: %s\n"),
694 jdres.dc_name);
695 }
696 /* FALLTHROUGH */
697 common:
698 if (jdres.join_err != 0) {
699 (void) fprintf(stderr, "%s\n",
700 smb_ads_strerror(jdres.join_err));
701 } else if (jdres.status != 0) {
702 (void) fprintf(stderr, "(%s)\n",
703 xlate_nt_status(jdres.status));
704 }
705 (void) fprintf(stderr, gettext("Please refer to the "
706 "service log for more information.\n"));
707 bzero(&jdi, sizeof (jdi));
708 return (1);
709 }
710 }
711
712 /*
713 * We want to process the user and domain names as separate strings.
714 * Check for names of the forms below and separate the components as
715 * required.
716 *
717 * name@domain
718 * domain\name
719 * domain/name
720 *
721 * If we encounter any of the forms above in arg, the @, / or \
722 * separator is replaced by \0 and the username and domain pointers
723 * are changed to point to the appropriate components (in arg).
724 *
725 * If none of the separators are encountered, the username and domain
726 * pointers remain unchanged.
727 */
728 static void
729 smbadm_extract_domain(char *arg, char **username, char **domain)
730 {
731 char *p;
732
733 if ((p = strpbrk(arg, "/\\@")) != NULL) {
734 if (*p == '@') {
735 *p = '\0';
736 ++p;
737
738 if (strchr(arg, '+') != NULL)
739 return;
740
741 *domain = p;
742 *username = arg;
743 } else {
744 *p = '\0';
745 ++p;
746 *username = p;
747 *domain = arg;
748 }
749 }
750 }
751
752 /*
753 * smbadm_list
754 *
755 * Displays current security mode and domain/workgroup name.
756 */
757 /*ARGSUSED*/
758 static int
759 smbadm_list(int argc, char **argv)
760 {
761 char domain[MAXHOSTNAMELEN];
762 char fqdn[MAXHOSTNAMELEN];
763 char srvname[MAXHOSTNAMELEN];
764 char modename[16];
765 int rc;
766 smb_inaddr_t srvipaddr;
767 char ipstr[INET6_ADDRSTRLEN];
768
769 rc = smb_config_getstr(SMB_CI_SECURITY, modename, sizeof (modename));
770 if (rc != SMBD_SMF_OK) {
771 (void) fprintf(stderr,
772 gettext("cannot determine the operational mode\n"));
773 return (1);
774 }
775
776 if (smb_getdomainname(domain, sizeof (domain)) != 0) {
777 (void) fprintf(stderr, gettext("failed to get the %s name\n"),
778 modename);
779 return (1);
780 }
781
782 if (strcmp(modename, "workgroup") == 0) {
783 (void) printf(gettext("[*] [%s]\n"), domain);
784 return (0);
785 }
786
787 (void) printf(gettext("[*] [%s]\n"), domain);
788 if ((smb_getfqdomainname(fqdn, sizeof (fqdn)) == 0) && (*fqdn != '\0'))
789 (void) printf(gettext("[*] [%s]\n"), fqdn);
790
791 if ((smb_get_dcinfo(srvname, MAXHOSTNAMELEN, &srvipaddr)
792 == NT_STATUS_SUCCESS) && (*srvname != '\0') &&
793 (!smb_inet_iszero(&srvipaddr))) {
794 (void) smb_inet_ntop(&srvipaddr, ipstr,
795 SMB_IPSTRLEN(srvipaddr.a_family));
796 (void) printf(gettext("\t[+%s] [%s]\n"),
797 srvname, ipstr);
798 }
799
800 /* Print the local and domain SID. */
801 smb_domain_show();
802 return (0);
803 }
804
805 /*
806 * smbadm_lookup
807 *
808 * Lookup the SID for a given account (user or group)
809 */
810 static int
811 smbadm_lookup(int argc, char **argv)
812 {
813 int i;
814
815 if (argc < 2) {
816 (void) fprintf(stderr, gettext("missing account name\n"));
817 smbadm_usage(B_FALSE);
818 }
819
820 for (i = 1; i < argc; i++) {
821 if (strncmp(argv[i], "S-1-", 4) == 0)
822 smbadm_lookup_sid(argv[i]);
823 else
824 smbadm_lookup_name(argv[i]);
825 }
826 return (0);
827 }
828
829 static void
830 smbadm_lookup_name(char *name)
831 {
832 lsa_account_t acct;
833 int rc;
834
835 if ((rc = smb_lookup_name(name, SidTypeUnknown, &acct)) != 0) {
836 (void) fprintf(stderr, gettext(
837 "\t\t%s: lookup name failed, rc=%d\n"),
838 name, rc);
839 return;
840 }
841 if (acct.a_status != NT_STATUS_SUCCESS) {
842 (void) fprintf(stderr, gettext("\t\t%s [%s]\n"),
843 name, xlate_nt_status(acct.a_status));
844 return;
845 }
846 (void) printf("\t%s\n", acct.a_sid);
847 }
848
849 static void
850 smbadm_lookup_sid(char *sidstr)
851 {
852 lsa_account_t acct;
853 int rc;
854
855 if ((rc = smb_lookup_sid(sidstr, &acct)) != 0) {
856 (void) fprintf(stderr, gettext(
857 "\t\t%s: lookup SID failed, rc=%d\n"),
858 sidstr, rc);
859 return;
860 }
861 if (acct.a_status != NT_STATUS_SUCCESS) {
862 (void) fprintf(stderr, gettext("\t\t%s [%s]\n"),
863 sidstr, xlate_nt_status(acct.a_status));
864 return;
865 }
866 (void) printf("\t%s\\%s\n", acct.a_domain, acct.a_name);
867 }
868
869 /*
870 * smbadm_group_create
871 *
872 * Creates a local SMB group
873 */
874 static int
875 smbadm_group_create(int argc, char **argv)
876 {
877 char *gname = NULL;
878 char *desc = NULL;
879 char option;
880 int status;
881
882 while ((option = getopt(argc, argv, "d:")) != -1) {
883 switch (option) {
884 case 'd':
885 desc = optarg;
886 break;
887
888 default:
889 smbadm_usage(B_FALSE);
890 }
891 }
892
893 gname = argv[optind];
894 if (optind >= argc || gname == NULL || *gname == '\0') {
895 (void) fprintf(stderr, gettext("missing group name\n"));
896 smbadm_usage(B_FALSE);
897 }
898
899 status = smb_lgrp_add(gname, desc);
900 if (status != SMB_LGRP_SUCCESS) {
901 (void) fprintf(stderr,
902 gettext("failed to create %s (%s)\n"), gname,
903 smb_lgrp_strerror(status));
904 } else {
905 (void) printf(gettext("%s created\n"), gname);
906 }
907
908 return (status);
909 }
910
911 /*
912 * smbadm_group_dump_members
913 *
914 * Dump group members details.
915 */
916 static void
917 smbadm_group_dump_members(smb_gsid_t *members, int num)
918 {
919 char sidstr[SMB_SID_STRSZ];
920 lsa_account_t acct;
921 int i;
922
923 if (num == 0) {
924 (void) printf(gettext("\tNo members\n"));
925 return;
926 }
927
928 (void) printf(gettext("\tMembers:\n"));
929 for (i = 0; i < num; i++) {
930 smb_sid_tostr(members[i].gs_sid, sidstr);
931
932 if (smb_lookup_sid(sidstr, &acct) == 0) {
933 if (acct.a_status == NT_STATUS_SUCCESS)
934 smbadm_group_show_name(acct.a_domain,
935 acct.a_name);
936 else
937 (void) printf(gettext("\t\t%s [%s]\n"),
938 sidstr, xlate_nt_status(acct.a_status));
939 } else {
940 (void) printf(gettext("\t\t%s\n"), sidstr);
941 }
942 }
943 }
944
945 static void
946 smbadm_group_show_name(const char *domain, const char *name)
947 {
948 if (strchr(domain, '.') != NULL)
949 (void) printf("\t\t%s@%s\n", name, domain);
950 else
951 (void) printf("\t\t%s\\%s\n", domain, name);
952 }
953
954 /*
955 * smbadm_group_dump_privs
956 *
957 * Dump group privilege details.
958 */
959 static void
960 smbadm_group_dump_privs(smb_privset_t *privs)
961 {
962 smb_privinfo_t *pinfo;
963 char *pstatus;
964 int i;
965
966 (void) printf(gettext("\tPrivileges: \n"));
967
968 for (i = 0; i < privs->priv_cnt; i++) {
969 pinfo = smb_priv_getbyvalue(privs->priv[i].luid.lo_part);
970 if ((pinfo == NULL) || (pinfo->flags & PF_PRESENTABLE) == 0)
971 continue;
972
973 switch (privs->priv[i].attrs) {
974 case SE_PRIVILEGE_ENABLED:
975 pstatus = "On";
976 break;
977 case SE_PRIVILEGE_DISABLED:
978 pstatus = "Off";
979 break;
980 default:
981 pstatus = "Unknown";
982 break;
983 }
984 (void) printf(gettext("\t\t%s: %s\n"), pinfo->name, pstatus);
985 }
986
987 if (privs->priv_cnt == 0)
988 (void) printf(gettext("\t\tNo privileges\n"));
989 }
990
991 /*
992 * smbadm_group_dump
993 *
994 * Dump group details.
995 */
996 static void
997 smbadm_group_dump(smb_group_t *grp, boolean_t show_mem, boolean_t show_privs)
998 {
999 char sidstr[SMB_SID_STRSZ];
1000
1001 (void) printf(gettext("%s (%s)\n"), grp->sg_name, grp->sg_cmnt);
1002
1003 smb_sid_tostr(grp->sg_id.gs_sid, sidstr);
1004 (void) printf(gettext("\tSID: %s\n"), sidstr);
1005
1006 if (show_privs)
1007 smbadm_group_dump_privs(grp->sg_privs);
1008
1009 if (show_mem)
1010 smbadm_group_dump_members(grp->sg_members, grp->sg_nmembers);
1011 }
1012
1013 /*
1014 * smbadm_group_show
1015 *
1016 */
1017 static int
1018 smbadm_group_show(int argc, char **argv)
1019 {
1020 char *gname = NULL;
1021 boolean_t show_privs;
1022 boolean_t show_members;
1023 char option;
1024 int status;
1025 smb_group_t grp;
1026 smb_giter_t gi;
1027
1028 show_privs = show_members = B_FALSE;
1029
1030 while ((option = getopt(argc, argv, "mp")) != -1) {
1031 switch (option) {
1032 case 'm':
1033 show_members = B_TRUE;
1034 break;
1035 case 'p':
1036 show_privs = B_TRUE;
1037 break;
1038
1039 default:
1040 smbadm_usage(B_FALSE);
1041 }
1042 }
1043
1044 gname = argv[optind];
1045 if (optind >= argc || gname == NULL || *gname == '\0')
1046 gname = "*";
1047
1048 if (strcmp(gname, "*")) {
1049 status = smb_lgrp_getbyname(gname, &grp);
1050 if (status == SMB_LGRP_SUCCESS) {
1051 smbadm_group_dump(&grp, show_members, show_privs);
1052 smb_lgrp_free(&grp);
1053 } else {
1054 (void) fprintf(stderr,
1055 gettext("failed to find %s (%s)\n"),
1056 gname, smb_lgrp_strerror(status));
1057 }
1058 return (status);
1059 }
1060
1061 if ((status = smb_lgrp_iteropen(&gi)) != SMB_LGRP_SUCCESS) {
1062 (void) fprintf(stderr, gettext("failed to list groups (%s)\n"),
1063 smb_lgrp_strerror(status));
1064 return (status);
1065 }
1066
1067 while ((status = smb_lgrp_iterate(&gi, &grp)) == SMB_LGRP_SUCCESS) {
1068 smbadm_group_dump(&grp, show_members, show_privs);
1069 smb_lgrp_free(&grp);
1070 }
1071
1072 smb_lgrp_iterclose(&gi);
1073
1074 if ((status != SMB_LGRP_NO_MORE) || smb_lgrp_itererror(&gi)) {
1075 if (status != SMB_LGRP_NO_MORE)
1076 smb_syslog(LOG_ERR, "smb_lgrp_iterate: %s",
1077 smb_lgrp_strerror(status));
1078
1079 (void) fprintf(stderr,
1080 gettext("\nAn error occurred while retrieving group data.\n"
1081 "Check the system log for more information.\n"));
1082 return (status);
1083 }
1084
1085 return (0);
1086 }
1087
1088 /*
1089 * smbadm_group_delete
1090 */
1091 static int
1092 smbadm_group_delete(int argc, char **argv)
1093 {
1094 char *gname = NULL;
1095 int status;
1096
1097 gname = argv[optind];
1098 if (optind >= argc || gname == NULL || *gname == '\0') {
1099 (void) fprintf(stderr, gettext("missing group name\n"));
1100 smbadm_usage(B_FALSE);
1101 }
1102
1103 status = smb_lgrp_delete(gname);
1104 if (status != SMB_LGRP_SUCCESS) {
1105 (void) fprintf(stderr,
1106 gettext("failed to delete %s (%s)\n"), gname,
1107 smb_lgrp_strerror(status));
1108 } else {
1109 (void) printf(gettext("%s deleted\n"), gname);
1110 }
1111
1112 return (status);
1113 }
1114
1115 /*
1116 * smbadm_group_rename
1117 */
1118 static int
1119 smbadm_group_rename(int argc, char **argv)
1120 {
1121 char *gname = NULL;
1122 char *ngname = NULL;
1123 int status;
1124
1125 gname = argv[optind];
1126 if (optind++ >= argc || gname == NULL || *gname == '\0') {
1127 (void) fprintf(stderr, gettext("missing group name\n"));
1128 smbadm_usage(B_FALSE);
1129 }
1130
1131 ngname = argv[optind];
1132 if (optind >= argc || ngname == NULL || *ngname == '\0') {
1133 (void) fprintf(stderr, gettext("missing new group name\n"));
1134 smbadm_usage(B_FALSE);
1135 }
1136
1137 status = smb_lgrp_rename(gname, ngname);
1138 if (status != SMB_LGRP_SUCCESS) {
1139 if (status == SMB_LGRP_EXISTS)
1140 (void) fprintf(stderr,
1141 gettext("failed to rename '%s' (%s already "
1142 "exists)\n"), gname, ngname);
1143 else
1144 (void) fprintf(stderr,
1145 gettext("failed to rename '%s' (%s)\n"), gname,
1146 smb_lgrp_strerror(status));
1147 } else {
1148 (void) printf(gettext("'%s' renamed to '%s'\n"), gname, ngname);
1149 }
1150
1151 return (status);
1152 }
1153
1154 /*
1155 * smbadm_group_setprop
1156 *
1157 * Set the group properties.
1158 */
1159 static int
1160 smbadm_group_setprop(int argc, char **argv)
1161 {
1162 char *gname = NULL;
1163 smbadm_prop_t props[SMBADM_NPROP];
1164 smbadm_prop_handle_t *phandle;
1165 char option;
1166 int pcnt = 0;
1167 int ret;
1168 int p;
1169
1170 bzero(props, SMBADM_NPROP * sizeof (smbadm_prop_t));
1171
1172 while ((option = getopt(argc, argv, "p:")) != -1) {
1173 switch (option) {
1174 case 'p':
1175 if (pcnt >= SMBADM_NPROP) {
1176 (void) fprintf(stderr,
1177 gettext("exceeded number of supported"
1178 " properties\n"));
1179 smbadm_usage(B_FALSE);
1180 }
1181
1182 if (smbadm_prop_parse(optarg, &props[pcnt++]) != 0)
1183 smbadm_usage(B_FALSE);
1184 break;
1185
1186 default:
1187 smbadm_usage(B_FALSE);
1188 }
1189 }
1190
1191 if (pcnt == 0) {
1192 (void) fprintf(stderr,
1193 gettext("missing property=value argument\n"));
1194 smbadm_usage(B_FALSE);
1195 }
1196
1197 gname = argv[optind];
1198 if (optind >= argc || gname == NULL || *gname == '\0') {
1199 (void) fprintf(stderr, gettext("missing group name\n"));
1200 smbadm_usage(B_FALSE);
1201 }
1202
1203 for (p = 0; p < pcnt; p++) {
1204 phandle = smbadm_prop_gethandle(props[p].p_name);
1205 if (phandle) {
1206 if (phandle->p_setfn(gname, &props[p]) != 0)
1207 ret = 1;
1208 }
1209 }
1210
1211 return (ret);
1212 }
1213
1214 /*
1215 * smbadm_group_getprop
1216 *
1217 * Get the group properties.
1218 */
1219 static int
1220 smbadm_group_getprop(int argc, char **argv)
1221 {
1222 char *gname = NULL;
1223 smbadm_prop_t props[SMBADM_NPROP];
1224 smbadm_prop_handle_t *phandle;
1225 char option;
1226 int pcnt = 0;
1227 int ret;
1228 int p;
1229
1230 bzero(props, SMBADM_NPROP * sizeof (smbadm_prop_t));
1231
1232 while ((option = getopt(argc, argv, "p:")) != -1) {
1233 switch (option) {
1234 case 'p':
1235 if (pcnt >= SMBADM_NPROP) {
1236 (void) fprintf(stderr,
1237 gettext("exceeded number of supported"
1238 " properties\n"));
1239 smbadm_usage(B_FALSE);
1240 }
1241
1242 if (smbadm_prop_parse(optarg, &props[pcnt++]) != 0)
1243 smbadm_usage(B_FALSE);
1244 break;
1245
1246 default:
1247 smbadm_usage(B_FALSE);
1248 }
1249 }
1250
1251 gname = argv[optind];
1252 if (optind >= argc || gname == NULL || *gname == '\0') {
1253 (void) fprintf(stderr, gettext("missing group name\n"));
1254 smbadm_usage(B_FALSE);
1255 }
1256
1257 if (pcnt == 0) {
1258 /*
1259 * If no property has be specified then get
1260 * all the properties.
1261 */
1262 pcnt = SMBADM_NPROP;
1263 for (p = 0; p < pcnt; p++)
1264 props[p].p_name = smbadm_ptable[p].p_name;
1265 }
1266
1267 for (p = 0; p < pcnt; p++) {
1268 phandle = smbadm_prop_gethandle(props[p].p_name);
1269 if (phandle) {
1270 if (phandle->p_getfn(gname, &props[p]) != 0)
1271 ret = 1;
1272 }
1273 }
1274
1275 return (ret);
1276 }
1277
1278 /*
1279 * smbadm_group_addmember
1280 *
1281 */
1282 static int
1283 smbadm_group_addmember(int argc, char **argv)
1284 {
1285 char *gname = NULL;
1286 char **mname;
1287 char option;
1288 int mcnt = 0;
1289 int ret = 0;
1290 int i;
1291
1292
1293 mname = (char **)malloc(argc * sizeof (char *));
1294 if (mname == NULL) {
1295 warn(gettext("failed to add group member"));
1296 return (1);
1297 }
1298 bzero(mname, argc * sizeof (char *));
1299
1300 while ((option = getopt(argc, argv, "m:")) != -1) {
1301 switch (option) {
1302 case 'm':
1303 mname[mcnt++] = optarg;
1304 break;
1305
1306 default:
1307 free(mname);
1308 smbadm_usage(B_FALSE);
1309 }
1310 }
1311
1312 if (mcnt == 0) {
1313 (void) fprintf(stderr, gettext("missing member name\n"));
1314 free(mname);
1315 smbadm_usage(B_FALSE);
1316 }
1317
1318 gname = argv[optind];
1319 if (optind >= argc || gname == NULL || *gname == 0) {
1320 (void) fprintf(stderr, gettext("missing group name\n"));
1321 free(mname);
1322 smbadm_usage(B_FALSE);
1323 }
1324
1325 for (i = 0; i < mcnt; i++) {
1326 if (mname[i] == NULL)
1327 continue;
1328 ret |= smbadm_group_add_del_member(
1329 gname, mname[i], SMBADM_GRP_ADDMEMBER);
1330 }
1331
1332 free(mname);
1333 return (ret);
1334 }
1335
1336 /*
1337 * smbadm_group_delmember
1338 */
1339 static int
1340 smbadm_group_delmember(int argc, char **argv)
1341 {
1342 char *gname = NULL;
1343 char **mname;
1344 char option;
1345 int mcnt = 0;
1346 int ret = 0;
1347 int i;
1348
1349 mname = (char **)malloc(argc * sizeof (char *));
1350 if (mname == NULL) {
1351 warn(gettext("failed to delete group member"));
1352 return (1);
1353 }
1354 bzero(mname, argc * sizeof (char *));
1355
1356 while ((option = getopt(argc, argv, "m:")) != -1) {
1357 switch (option) {
1358 case 'm':
1359 mname[mcnt++] = optarg;
1360 break;
1361
1362 default:
1363 free(mname);
1364 smbadm_usage(B_FALSE);
1365 }
1366 }
1367
1368 if (mcnt == 0) {
1369 (void) fprintf(stderr, gettext("missing member name\n"));
1370 free(mname);
1371 smbadm_usage(B_FALSE);
1372 }
1373
1374 gname = argv[optind];
1375 if (optind >= argc || gname == NULL || *gname == 0) {
1376 (void) fprintf(stderr, gettext("missing group name\n"));
1377 free(mname);
1378 smbadm_usage(B_FALSE);
1379 }
1380
1381
1382 for (i = 0; i < mcnt; i++) {
1383 ret = 0;
1384 if (mname[i] == NULL)
1385 continue;
1386 ret |= smbadm_group_add_del_member(
1387 gname, mname[i], SMBADM_GRP_DELMEMBER);
1388 }
1389
1390 free(mname);
1391 return (ret);
1392 }
1393
1394 static int
1395 smbadm_group_add_del_member(char *gname, char *mname,
1396 smbadm_grp_action_t act)
1397 {
1398 lsa_account_t acct;
1399 smb_gsid_t msid;
1400 char *sidstr;
1401 char *act_str;
1402 int rc;
1403
1404 if (strncmp(mname, "S-1-", 4) == 0) {
1405 /*
1406 * We are given a SID. Just use it.
1407 *
1408 * We'e like the real account type if we can get it,
1409 * but don't want to error out if we can't get it.
1410 * Lacking other info, assume it's a group.
1411 */
1412 sidstr = mname;
1413 rc = smb_lookup_sid(sidstr, &acct);
1414 if ((rc != 0) || (acct.a_status != NT_STATUS_SUCCESS))
1415 acct.a_sidtype = SidTypeGroup;
1416 } else {
1417 rc = smb_lookup_name(mname, SidTypeUnknown, &acct);
1418 if ((rc != 0) || (acct.a_status != NT_STATUS_SUCCESS)) {
1419 (void) fprintf(stderr,
1420 gettext("%s: name lookup failed\n"), mname);
1421 return (1);
1422 }
1423 sidstr = acct.a_sid;
1424 }
1425
1426 msid.gs_type = acct.a_sidtype;
1427 if ((msid.gs_sid = smb_sid_fromstr(sidstr)) == NULL) {
1428 (void) fprintf(stderr,
1429 gettext("%s: no memory for SID\n"), sidstr);
1430 return (1);
1431 }
1432
1433 switch (act) {
1434 case SMBADM_GRP_ADDMEMBER:
1435 act_str = gettext("add");
1436 rc = smb_lgrp_add_member(gname,
1437 msid.gs_sid, msid.gs_type);
1438 break;
1439 case SMBADM_GRP_DELMEMBER:
1440 act_str = gettext("remove");
1441 rc = smb_lgrp_del_member(gname,
1442 msid.gs_sid, msid.gs_type);
1443 break;
1444 default:
1445 rc = SMB_LGRP_INTERNAL_ERROR;
1446 break;
1447 }
1448
1449 smb_sid_free(msid.gs_sid);
1450
1451 if (rc != SMB_LGRP_SUCCESS) {
1452 (void) fprintf(stderr,
1453 gettext("failed to %s %s (%s)\n"),
1454 act_str, mname, smb_lgrp_strerror(rc));
1455 return (1);
1456 }
1457 return (0);
1458 }
1459
1460 static int
1461 smbadm_user_delete(int argc, char **argv)
1462 {
1463 int error;
1464 char *user = NULL;
1465
1466 user = argv[optind];
1467 if (optind >= argc || user == NULL || *user == '\0') {
1468 (void) fprintf(stderr, gettext("missing user name\n"));
1469 smbadm_usage(B_FALSE);
1470 }
1471
1472 error = smb_pwd_setcntl(user, SMB_PWC_DELETE);
1473 if (error == SMB_PWE_SUCCESS)
1474 (void) printf(gettext("%s has been deleted.\n"), user);
1475 else
1476 (void) fprintf(stderr, "%s\n", smbadm_pwd_strerror(error));
1477
1478 return (error);
1479 }
1480
1481 static int
1482 smbadm_user_disable(int argc, char **argv)
1483 {
1484 int error;
1485 char *user = NULL;
1486
1487 user = argv[optind];
1488 if (optind >= argc || user == NULL || *user == '\0') {
1489 (void) fprintf(stderr, gettext("missing user name\n"));
1490 smbadm_usage(B_FALSE);
1491 }
1492
1493 error = smb_pwd_setcntl(user, SMB_PWC_DISABLE);
1494 if (error == SMB_PWE_SUCCESS)
1495 (void) printf(gettext("%s is disabled.\n"), user);
1496 else
1497 (void) fprintf(stderr, "%s\n", smbadm_pwd_strerror(error));
1498
1499 return (error);
1500 }
1501
1502 static int
1503 smbadm_user_enable(int argc, char **argv)
1504 {
1505 int error;
1506 char *user = NULL;
1507
1508 user = argv[optind];
1509 if (optind >= argc || user == NULL || *user == '\0') {
1510 (void) fprintf(stderr, gettext("missing user name\n"));
1511 smbadm_usage(B_FALSE);
1512 }
1513
1514 error = smb_pwd_setcntl(user, SMB_PWC_ENABLE);
1515 if (error == SMB_PWE_SUCCESS)
1516 (void) printf(gettext("%s is enabled.\n"), user);
1517 else
1518 (void) fprintf(stderr, "%s\n", smbadm_pwd_strerror(error));
1519
1520 return (error);
1521 }
1522
1523
1524 int
1525 main(int argc, char **argv)
1526 {
1527 int ret;
1528 int i;
1529
1530 (void) setlocale(LC_ALL, "");
1531 (void) textdomain(TEXT_DOMAIN);
1532
1533 (void) malloc(0); /* satisfy libumem dependency */
1534
1535 progname = basename(argv[0]);
1536
1537 if (is_system_labeled()) {
1538 (void) fprintf(stderr,
1539 gettext("Trusted Extensions not supported\n"));
1540 return (1);
1541 }
1542
1543 if (argc < 2) {
1544 (void) fprintf(stderr, gettext("missing command\n"));
1545 smbadm_usage(B_FALSE);
1546 }
1547
1548 /*
1549 * Special case "cmd --help/-?"
1550 */
1551 if (strcmp(argv[1], "-?") == 0 ||
1552 strcmp(argv[1], "--help") == 0 ||
1553 strcmp(argv[1], "-h") == 0)
1554 smbadm_usage(B_TRUE);
1555
1556 for (i = 0; i < SMBADM_NCMD; ++i) {
1557 curcmd = &smbadm_cmdtable[i];
1558 if (strcasecmp(argv[1], curcmd->name) == 0) {
1559 if (argc > 2) {
1560 /* cmd subcmd --help/-? */
1561 if (strcmp(argv[2], "-?") == 0 ||
1562 strcmp(argv[2], "--help") == 0 ||
1563 strcmp(argv[2], "-h") == 0)
1564 smbadm_usage(B_TRUE);
1565 }
1566
1567 if (!smbadm_checkauth(curcmd->auth)) {
1568 (void) fprintf(stderr,
1569 gettext("%s: %s: authorization denied\n"),
1570 progname, curcmd->name);
1571 return (1);
1572 }
1573
1574 if ((ret = smbadm_init()) != 0)
1575 return (ret);
1576
1577 ret = curcmd->func(argc - 1, &argv[1]);
1578
1579 smbadm_fini();
1580 return (ret);
1581 }
1582 }
1583
1584 curcmd = NULL;
1585 (void) fprintf(stderr, gettext("unknown subcommand (%s)\n"), argv[1]);
1586 smbadm_usage(B_FALSE);
1587 return (2);
1588 }
1589
1590 static int
1591 smbadm_init(void)
1592 {
1593 int rc;
1594
1595 switch (curcmd->flags & SMBADM_CMDF_TYPEMASK) {
1596 case SMBADM_CMDF_GROUP:
1597 if ((rc = smb_lgrp_start()) != SMB_LGRP_SUCCESS) {
1598 (void) fprintf(stderr,
1599 gettext("failed to initialize (%s)\n"),
1600 smb_lgrp_strerror(rc));
1601 return (1);
1602 }
1603 break;
1604
1605 case SMBADM_CMDF_USER:
1606 smb_pwd_init(B_FALSE);
1607 break;
1608
1609 default:
1610 break;
1611 }
1612
1613 return (0);
1614 }
1615
1616 static void
1617 smbadm_fini(void)
1618 {
1619 switch (curcmd->flags & SMBADM_CMDF_TYPEMASK) {
1620 case SMBADM_CMDF_GROUP:
1621 smb_lgrp_stop();
1622 break;
1623
1624 case SMBADM_CMDF_USER:
1625 smb_pwd_fini();
1626 break;
1627
1628 default:
1629 break;
1630 }
1631 }
1632
1633 static boolean_t
1634 smbadm_checkauth(const char *auth)
1635 {
1636 struct passwd *pw;
1637
1638 if ((pw = getpwuid(getuid())) == NULL)
1639 return (B_FALSE);
1640
1641 if (chkauthattr(auth, pw->pw_name) == 0)
1642 return (B_FALSE);
1643
1644 return (B_TRUE);
1645 }
1646
1647 static boolean_t
1648 smbadm_prop_validate(smbadm_prop_t *prop, boolean_t chkval)
1649 {
1650 smbadm_prop_handle_t *pinfo;
1651 int i;
1652
1653 for (i = 0; i < SMBADM_NPROP; i++) {
1654 pinfo = &smbadm_ptable[i];
1655 if (strcmp(pinfo->p_name, prop->p_name) == 0) {
1656 if (pinfo->p_chkfn && chkval)
1657 return (pinfo->p_chkfn(prop));
1658
1659 return (B_TRUE);
1660 }
1661 }
1662
1663 (void) fprintf(stderr, gettext("unrecognized property '%s'\n"),
1664 prop->p_name);
1665
1666 return (B_FALSE);
1667 }
1668
1669 static int
1670 smbadm_prop_parse(char *arg, smbadm_prop_t *prop)
1671 {
1672 boolean_t parse_value;
1673 char *equal;
1674
1675 if (arg == NULL)
1676 return (2);
1677
1678 prop->p_name = prop->p_value = NULL;
1679
1680 if (strcmp(curcmd->name, "set") == 0)
1681 parse_value = B_TRUE;
1682 else
1683 parse_value = B_FALSE;
1684
1685 prop->p_name = arg;
1686
1687 if (parse_value) {
1688 equal = strchr(arg, '=');
1689 if (equal == NULL)
1690 return (2);
1691
1692 *equal++ = '\0';
1693 prop->p_value = equal;
1694 }
1695
1696 if (smbadm_prop_validate(prop, parse_value) == B_FALSE)
1697 return (2);
1698
1699 return (0);
1700 }
1701
1702 static smbadm_prop_handle_t *
1703 smbadm_prop_gethandle(char *pname)
1704 {
1705 int i;
1706
1707 for (i = 0; i < SMBADM_NPROP; i++)
1708 if (strcmp(pname, smbadm_ptable[i].p_name) == 0)
1709 return (&smbadm_ptable[i]);
1710
1711 return (NULL);
1712 }
1713
1714 static int
1715 smbadm_setprop_desc(char *gname, smbadm_prop_t *prop)
1716 {
1717 int status;
1718
1719 status = smb_lgrp_setcmnt(gname, prop->p_value);
1720 if (status != SMB_LGRP_SUCCESS) {
1721 (void) fprintf(stderr,
1722 gettext("failed to modify the group description (%s)\n"),
1723 smb_lgrp_strerror(status));
1724 return (1);
1725 }
1726
1727 (void) printf(gettext("%s: description modified\n"), gname);
1728 return (0);
1729 }
1730
1731 static int
1732 smbadm_getprop_desc(char *gname, smbadm_prop_t *prop)
1733 {
1734 char *cmnt = NULL;
1735 int status;
1736
1737 status = smb_lgrp_getcmnt(gname, &cmnt);
1738 if (status != SMB_LGRP_SUCCESS) {
1739 (void) fprintf(stderr,
1740 gettext("failed to get the group description (%s)\n"),
1741 smb_lgrp_strerror(status));
1742 return (1);
1743 }
1744
1745 (void) printf(gettext("\t%s: %s\n"), prop->p_name, cmnt);
1746 free(cmnt);
1747 return (0);
1748 }
1749
1750 static int
1751 smbadm_group_setpriv(char *gname, uint8_t priv_id, smbadm_prop_t *prop)
1752 {
1753 boolean_t enable;
1754 int status;
1755 int ret;
1756
1757 if (strcasecmp(prop->p_value, "on") == 0) {
1758 (void) printf(gettext("Enabling %s privilege "), prop->p_name);
1759 enable = B_TRUE;
1760 } else {
1761 (void) printf(gettext("Disabling %s privilege "), prop->p_name);
1762 enable = B_FALSE;
1763 }
1764
1765 status = smb_lgrp_setpriv(gname, priv_id, enable);
1766 if (status == SMB_LGRP_SUCCESS) {
1767 (void) printf(gettext("succeeded\n"));
1768 ret = 0;
1769 } else {
1770 (void) printf(gettext("failed: %s\n"),
1771 smb_lgrp_strerror(status));
1772 ret = 1;
1773 }
1774
1775 return (ret);
1776 }
1777
1778 static int
1779 smbadm_group_getpriv(char *gname, uint8_t priv_id, smbadm_prop_t *prop)
1780 {
1781 boolean_t enable;
1782 int status;
1783
1784 status = smb_lgrp_getpriv(gname, priv_id, &enable);
1785 if (status != SMB_LGRP_SUCCESS) {
1786 (void) fprintf(stderr, gettext("failed to get %s (%s)\n"),
1787 prop->p_name, smb_lgrp_strerror(status));
1788 return (1);
1789 }
1790
1791 (void) printf(gettext("\t%s: %s\n"), prop->p_name,
1792 (enable) ? "On" : "Off");
1793
1794 return (0);
1795 }
1796
1797 static int
1798 smbadm_setprop_tkowner(char *gname, smbadm_prop_t *prop)
1799 {
1800 return (smbadm_group_setpriv(gname, SE_TAKE_OWNERSHIP_LUID, prop));
1801 }
1802
1803 static int
1804 smbadm_getprop_tkowner(char *gname, smbadm_prop_t *prop)
1805 {
1806 return (smbadm_group_getpriv(gname, SE_TAKE_OWNERSHIP_LUID, prop));
1807 }
1808
1809 static int
1810 smbadm_setprop_backup(char *gname, smbadm_prop_t *prop)
1811 {
1812 return (smbadm_group_setpriv(gname, SE_BACKUP_LUID, prop));
1813 }
1814
1815 static int
1816 smbadm_getprop_backup(char *gname, smbadm_prop_t *prop)
1817 {
1818 return (smbadm_group_getpriv(gname, SE_BACKUP_LUID, prop));
1819 }
1820
1821 static int
1822 smbadm_setprop_restore(char *gname, smbadm_prop_t *prop)
1823 {
1824 return (smbadm_group_setpriv(gname, SE_RESTORE_LUID, prop));
1825 }
1826
1827 static int
1828 smbadm_getprop_restore(char *gname, smbadm_prop_t *prop)
1829 {
1830 return (smbadm_group_getpriv(gname, SE_RESTORE_LUID, prop));
1831 }
1832
1833 static boolean_t
1834 smbadm_chkprop_priv(smbadm_prop_t *prop)
1835 {
1836 if (prop->p_value == NULL || *prop->p_value == '\0') {
1837 (void) fprintf(stderr,
1838 gettext("missing value for '%s'\n"), prop->p_name);
1839 return (B_FALSE);
1840 }
1841
1842 if (strcasecmp(prop->p_value, "on") == 0)
1843 return (B_TRUE);
1844
1845 if (strcasecmp(prop->p_value, "off") == 0)
1846 return (B_TRUE);
1847
1848 (void) fprintf(stderr,
1849 gettext("%s: unrecognized value for '%s' property\n"),
1850 prop->p_value, prop->p_name);
1851
1852 return (B_FALSE);
1853 }
1854
1855 static const char *
1856 smbadm_pwd_strerror(int error)
1857 {
1858 switch (error) {
1859 case SMB_PWE_SUCCESS:
1860 return (gettext("Success."));
1861
1862 case SMB_PWE_USER_UNKNOWN:
1863 return (gettext("User does not exist."));
1864
1865 case SMB_PWE_USER_DISABLE:
1866 return (gettext("User is disabled."));
1867
1868 case SMB_PWE_CLOSE_FAILED:
1869 case SMB_PWE_OPEN_FAILED:
1870 case SMB_PWE_WRITE_FAILED:
1871 case SMB_PWE_UPDATE_FAILED:
1872 return (gettext("Unexpected failure. "
1873 "SMB password database unchanged."));
1874
1875 case SMB_PWE_STAT_FAILED:
1876 return (gettext("stat of SMB password file failed."));
1877
1878 case SMB_PWE_BUSY:
1879 return (gettext("SMB password database busy. "
1880 "Try again later."));
1881
1882 case SMB_PWE_DENIED:
1883 return (gettext("Operation not permitted."));
1884
1885 case SMB_PWE_SYSTEM_ERROR:
1886 return (gettext("System error."));
1887
1888 default:
1889 break;
1890 }
1891
1892 return (gettext("Unknown error code."));
1893 }
1894
1895 /*
1896 * Enable libumem debugging by default on DEBUG builds.
1897 */
1898 #ifdef DEBUG
1899 const char *
1900 _umem_debug_init(void)
1901 {
1902 return ("default,verbose"); /* $UMEM_DEBUG setting */
1903 }
1904
1905 const char *
1906 _umem_logging_init(void)
1907 {
1908 return ("fail,contents"); /* $UMEM_LOGGING setting */
1909 }
1910 #endif