xref: /illumos-gate/usr/src/cmd/smbsrv/smbadm/smbadm.c (revision 747cfc73193da6c99aeb06f23e70552319393cc4)
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 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * This module contains smbadm CLI which offers smb configuration
30  * functionalities.
31  */
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <syslog.h>
35 #include <strings.h>
36 #include <limits.h>
37 #include <getopt.h>
38 #include <libintl.h>
39 #include <zone.h>
40 #include <grp.h>
41 #include <libgen.h>
42 
43 #include <smbsrv/libsmb.h>
44 #include <smbsrv/libmlsvc.h>
45 
46 typedef enum {
47 	HELP_ADD_MEMBER,
48 	HELP_CREATE,
49 	HELP_DELETE,
50 	HELP_DEL_MEMBER,
51 	HELP_GET,
52 	HELP_JOIN,
53 	HELP_LIST,
54 	HELP_RENAME,
55 	HELP_SET,
56 	HELP_SHOW,
57 	HELP_UDISABLE,
58 	HELP_UENABLE
59 } smbadm_help_t;
60 
61 typedef struct smbadm_cmdinfo {
62 	char *name;
63 	int (*func)(int, char **);
64 	smbadm_help_t usage;
65 } smbadm_cmdinfo_t;
66 
67 smbadm_cmdinfo_t *curcmd;
68 static char *progname;
69 
70 static int smbadm_join(int, char **);
71 static int smbadm_list(int, char **);
72 static int smbadm_group_create(int, char **);
73 static int smbadm_group_delete(int, char **);
74 static int smbadm_group_rename(int, char **);
75 static int smbadm_group_show(int, char **);
76 static int smbadm_group_getprop(int, char **);
77 static int smbadm_group_setprop(int, char **);
78 static int smbadm_group_addmember(int, char **);
79 static int smbadm_group_delmember(int, char **);
80 static int smbadm_user_disable(int, char **);
81 static int smbadm_user_enable(int, char **);
82 
83 static smbadm_cmdinfo_t smbadm_cmdtable[] =
84 {
85 	{ "add-member",		smbadm_group_addmember,	HELP_ADD_MEMBER	},
86 	{ "create",		smbadm_group_create,	HELP_CREATE	},
87 	{ "delete",		smbadm_group_delete,	HELP_DELETE	},
88 	{ "disable-user",	smbadm_user_disable,	HELP_UDISABLE	},
89 	{ "enable-user",	smbadm_user_enable,	HELP_UENABLE	},
90 	{ "get",		smbadm_group_getprop,	HELP_GET	},
91 	{ "join",		smbadm_join,		HELP_JOIN	},
92 	{ "list",		smbadm_list,		HELP_LIST	},
93 	{ "remove-member",	smbadm_group_delmember,	HELP_DEL_MEMBER	},
94 	{ "rename",		smbadm_group_rename,	HELP_RENAME	},
95 	{ "set",		smbadm_group_setprop,	HELP_SET	},
96 	{ "show",		smbadm_group_show,	HELP_SHOW	},
97 };
98 
99 #define	SMBADM_NCMD	(sizeof (smbadm_cmdtable) / sizeof (smbadm_cmdtable[0]))
100 
101 typedef struct smbadm_prop {
102 	char *p_name;
103 	char *p_value;
104 } smbadm_prop_t;
105 
106 typedef struct smbadm_prop_handle {
107 	char *p_name;
108 	char *p_dispvalue;
109 	int (*p_setfn)(char *, smbadm_prop_t *);
110 	int (*p_getfn)(char *, smbadm_prop_t *);
111 	boolean_t (*p_chkfn)(smbadm_prop_t *);
112 } smbadm_prop_handle_t;
113 
114 static boolean_t smbadm_prop_validate(smbadm_prop_t *prop, boolean_t chkval);
115 static int smbadm_prop_parse(char *arg, smbadm_prop_t *prop);
116 static smbadm_prop_handle_t *smbadm_prop_gethandle(char *pname);
117 
118 static boolean_t smbadm_chkprop_priv(smbadm_prop_t *prop);
119 static int smbadm_setprop_tkowner(char *gname, smbadm_prop_t *prop);
120 static int smbadm_getprop_tkowner(char *gname, smbadm_prop_t *prop);
121 static int smbadm_setprop_backup(char *gname, smbadm_prop_t *prop);
122 static int smbadm_getprop_backup(char *gname, smbadm_prop_t *prop);
123 static int smbadm_setprop_restore(char *gname, smbadm_prop_t *prop);
124 static int smbadm_getprop_restore(char *gname, smbadm_prop_t *prop);
125 static int smbadm_setprop_desc(char *gname, smbadm_prop_t *prop);
126 static int smbadm_getprop_desc(char *gname, smbadm_prop_t *prop);
127 
128 static smbadm_prop_handle_t smbadm_ptable[] = {
129 	{"backup",	"on | off", 	smbadm_setprop_backup,
130 	smbadm_getprop_backup,	smbadm_chkprop_priv 	},
131 	{"restore",	"on | off",	smbadm_setprop_restore,
132 	smbadm_getprop_restore,	smbadm_chkprop_priv	},
133 	{"take-ownership", "on | off",	smbadm_setprop_tkowner,
134 	smbadm_getprop_tkowner,	smbadm_chkprop_priv	},
135 	{"description",	"<string>",	smbadm_setprop_desc,
136 	smbadm_getprop_desc,	NULL			},
137 };
138 
139 static const char *smbadm_pwd_strerror(int error);
140 
141 /*
142  * Number of supported properties
143  */
144 #define	SMBADM_NPROP	(sizeof (smbadm_ptable) / sizeof (smbadm_ptable[0]))
145 
146 static void
147 smbadm_cmdusage(FILE *fp, smbadm_cmdinfo_t *cmd)
148 {
149 	switch (cmd->usage) {
150 	case HELP_ADD_MEMBER:
151 		(void) fprintf(fp,
152 		    gettext("\t%s -m member [[-m member] ...] group\n"),
153 		    cmd->name);
154 		return;
155 
156 	case HELP_CREATE:
157 		(void) fprintf(fp, gettext("\t%s [-d description] group\n"),
158 		    cmd->name);
159 		return;
160 
161 	case HELP_DELETE:
162 		(void) fprintf(fp, gettext("\t%s group\n"), cmd->name);
163 		return;
164 
165 	case HELP_UDISABLE:
166 	case HELP_UENABLE:
167 		(void) fprintf(fp, gettext("\t%s user\n"), cmd->name);
168 		return;
169 
170 	case HELP_GET:
171 		(void) fprintf(fp, gettext("\t%s [[-p property] ...] group\n"),
172 		    cmd->name);
173 		return;
174 
175 	case HELP_JOIN:
176 		(void) fprintf(fp, gettext("\t%s -u username domain\n"
177 		    "\t%s -w workgroup\n"), cmd->name, cmd->name);
178 		return;
179 
180 	case HELP_LIST:
181 		(void) fprintf(fp, gettext("\t%s\n"), cmd->name);
182 		return;
183 
184 	case HELP_DEL_MEMBER:
185 		(void) fprintf(fp,
186 		    gettext("\t%s -m member [[-m member] ...] group\n"),
187 		    cmd->name);
188 		return;
189 
190 	case HELP_RENAME:
191 		(void) fprintf(fp, gettext("\t%s group new-group\n"),
192 		    cmd->name);
193 		return;
194 
195 	case HELP_SET:
196 		(void) fprintf(fp, gettext("\t%s -p property=value "
197 		    "[[-p property=value] ...] group\n"), cmd->name);
198 		return;
199 
200 	case HELP_SHOW:
201 		(void) fprintf(fp, gettext("\t%s [-m] [-p] [group]\n"),
202 		    cmd->name);
203 		return;
204 
205 	}
206 
207 	abort();
208 	/* NOTREACHED */
209 }
210 
211 static void
212 smbadm_usage(boolean_t requested)
213 {
214 	FILE *fp = requested ? stdout : stderr;
215 	boolean_t show_props = B_FALSE;
216 	int i;
217 
218 	if (curcmd == NULL) {
219 		(void) fprintf(fp,
220 		    gettext("usage: %s [-h | <command> [options]]\n"),
221 		    progname);
222 		(void) fprintf(fp,
223 		    gettext("where 'command' is one of the following:\n\n"));
224 
225 		for (i = 0; i < SMBADM_NCMD; i++)
226 			smbadm_cmdusage(fp, &smbadm_cmdtable[i]);
227 
228 		(void) fprintf(fp,
229 		    gettext("\nFor property list, run %s %s|%s\n"),
230 		    progname, "get", "set");
231 
232 		exit(requested ? 0 : 2);
233 	}
234 
235 	(void) fprintf(fp, gettext("usage:\n"));
236 	smbadm_cmdusage(fp, curcmd);
237 
238 	if (strcmp(curcmd->name, "get") == 0 ||
239 	    strcmp(curcmd->name, "set") == 0)
240 		show_props = B_TRUE;
241 
242 	if (show_props) {
243 		(void) fprintf(fp,
244 		    gettext("\nThe following properties are supported:\n"));
245 
246 		(void) fprintf(fp, "\n\t%-16s   %s\n\n",
247 		    "PROPERTY", "VALUES");
248 
249 		for (i = 0; i < SMBADM_NPROP; i++) {
250 			(void) fprintf(fp, "\t%-16s   %s\n",
251 			    smbadm_ptable[i].p_name,
252 			    smbadm_ptable[i].p_dispvalue);
253 		}
254 	}
255 
256 	exit(requested ? 0 : 2);
257 }
258 
259 /*
260  * smbadm_join
261  *
262  * Join the given domain/workgroup
263  */
264 static int
265 smbadm_join(int argc, char **argv)
266 {
267 	char option;
268 	smb_joininfo_t jdi;
269 	boolean_t join_w = B_FALSE;
270 	boolean_t join_d = B_FALSE;
271 	uint32_t status;
272 
273 	bzero(&jdi, sizeof (jdi));
274 
275 	while ((option = getopt(argc, argv, "u:w:")) != -1) {
276 		switch (option) {
277 		case 'w':
278 			(void) strlcpy(jdi.domain_name, optarg,
279 			    sizeof (jdi.domain_name));
280 			jdi.mode = SMB_SECMODE_WORKGRP;
281 			join_w = B_TRUE;
282 			break;
283 
284 		case 'u':
285 			/* admin username */
286 			(void) strlcpy(jdi.domain_username, optarg,
287 			    sizeof (jdi.domain_username));
288 			jdi.mode = SMB_SECMODE_DOMAIN;
289 			join_d = B_TRUE;
290 			break;
291 
292 		default:
293 			smbadm_usage(B_FALSE);
294 		}
295 	}
296 
297 	if (join_w && join_d) {
298 		(void) fprintf(stderr,
299 		    gettext("domain and workgroup "
300 		    "can not be specified together\n"));
301 		smbadm_usage(B_FALSE);
302 	}
303 
304 	if (join_d && (argv[optind] != NULL)) {
305 		(void) strlcpy(jdi.domain_name, argv[optind],
306 		    sizeof (jdi.domain_name));
307 	}
308 
309 	if (*jdi.domain_name == '\0') {
310 		(void) fprintf(stderr, gettext("missing %s name\n"),
311 		    (join_d) ? "domain" : "workgroup");
312 		smbadm_usage(B_FALSE);
313 	}
314 
315 	if (join_d && *jdi.domain_username == '\0') {
316 		(void) fprintf(stderr, gettext("missing username\n"));
317 		smbadm_usage(B_FALSE);
318 	}
319 
320 	if (join_w) {
321 		status = smb_join(&jdi);
322 		if (status == NT_STATUS_SUCCESS) {
323 			(void) printf(
324 			    gettext("Successfully joined workgroup '%s'\n"),
325 			    jdi.domain_name);
326 			return (0);
327 		}
328 
329 		(void) fprintf(stderr,
330 		    gettext("failed to join workgroup '%s' (%s)\n"),
331 		    jdi.domain_name, xlate_nt_status(status));
332 
333 		return (1);
334 	}
335 
336 	/* Join the domain */
337 	if (*jdi.domain_passwd == '\0') {
338 		char *p = NULL;
339 		char *prompt = gettext("Enter domain password: ");
340 		p = getpassphrase(prompt);
341 		if (!p) {
342 			(void) fprintf(stderr, gettext("missing password\n"));
343 			smbadm_usage(B_FALSE);
344 		}
345 
346 		(void) strlcpy(jdi.domain_passwd, p,
347 		    sizeof (jdi.domain_passwd));
348 	}
349 
350 	(void) printf(gettext("Joining '%s' ... this may take a minute ...\n"),
351 	    jdi.domain_name);
352 
353 	status = smb_join(&jdi);
354 
355 	switch (status) {
356 	case NT_STATUS_SUCCESS:
357 		(void) printf(gettext("Successfully joined domain '%s'\n"),
358 		    jdi.domain_name);
359 		return (0);
360 
361 	case NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND:
362 		(void) fprintf(stderr, gettext("failed to find "
363 		    "any domain controllers for '%s'\n"),
364 		    jdi.domain_name);
365 		break;
366 
367 	default:
368 		(void) fprintf(stderr,
369 		    gettext("failed to join domain '%s' (%s)\n"),
370 		    jdi.domain_name, xlate_nt_status(status));
371 	}
372 
373 	return (1);
374 }
375 
376 /*
377  * smbadm_list
378  *
379  * Displays current security mode and domain/workgroup name.
380  */
381 /*ARGSUSED*/
382 static int
383 smbadm_list(int argc, char **argv)
384 {
385 	char resource_domain[SMB_PI_MAX_DOMAIN];
386 	int sec_mode;
387 	char *modename;
388 
389 	if (smbd_get_security_mode(&sec_mode)) {
390 		(void) fprintf(stderr,
391 		    gettext("failed to get the security mode\n"));
392 		return (1);
393 	}
394 
395 	modename = (sec_mode == SMB_SECMODE_DOMAIN) ? "domain" : "workgroup";
396 
397 	(void) printf(gettext("security mode: %s\n"),
398 	    smb_config_secmode_tostr(sec_mode));
399 
400 	if (smbd_get_param(SMB_CI_DOMAIN_NAME, resource_domain) != 0) {
401 		(void) fprintf(stderr,
402 		    gettext("failed to get the %s name\n"), modename);
403 		return (1);
404 	}
405 
406 	(void) printf(gettext("%s name: %s\n"),
407 	    modename, resource_domain);
408 
409 	return (0);
410 }
411 
412 /*
413  * smbadm_group_create
414  *
415  * Creates a local SMB group
416  */
417 static int
418 smbadm_group_create(int argc, char **argv)
419 {
420 	char *gname = NULL;
421 	char *desc = NULL;
422 	char option;
423 	uint32_t status;
424 
425 	while ((option = getopt(argc, argv, "d:")) != -1) {
426 		switch (option) {
427 		case 'd':
428 			desc = optarg;
429 			break;
430 
431 		default:
432 			smbadm_usage(B_FALSE);
433 		}
434 	}
435 
436 	gname = argv[optind];
437 	if (optind >= argc || gname == NULL || *gname == '\0') {
438 		(void) fprintf(stderr, gettext("missing group name\n"));
439 		smbadm_usage(B_FALSE);
440 	}
441 
442 	if (getgrnam(gname) == NULL) {
443 		(void) fprintf(stderr,
444 		    gettext("failed to get the Solaris group\n"));
445 		(void) fprintf(stderr,
446 		    gettext("use 'groupadd' to add the Solaris group\n"));
447 		return (1);
448 	}
449 
450 	status = smb_group_add(gname, desc);
451 	if (status != NT_STATUS_SUCCESS) {
452 		(void) fprintf(stderr,
453 		    gettext("failed to create the group (%s)\n"),
454 		    xlate_nt_status(status));
455 	} else {
456 		(void) printf(gettext("Successfully created group '%s'\n"),
457 		    gname);
458 	}
459 
460 	return (status);
461 }
462 
463 /*
464  * smbadm_group_dump_members
465  *
466  * Dump group members details.
467  */
468 static void
469 smbadm_group_dump_members(char *gname)
470 {
471 	ntgrp_member_list_t *members = NULL;
472 	int mem_cnt = 0;
473 	int offset = 0;
474 	uint32_t status;
475 	int i;
476 
477 	status = smb_group_member_count(gname, &mem_cnt);
478 	if (mem_cnt < 0) {
479 		(void) fprintf(stderr,
480 		    gettext("failed to get the group members (%s)\n"),
481 		    xlate_nt_status(status));
482 	}
483 
484 	if (mem_cnt == 0) {
485 		(void) printf(gettext("\tNo members\n"));
486 		return;
487 	}
488 
489 	(void) printf(gettext("\tMembers:\n"));
490 	while (smb_group_member_list(gname, offset, &members) == 0) {
491 		if (members == NULL)
492 			break;
493 
494 		for (i = 0; i < members->cnt; i++)
495 			(void) printf(gettext("\t\t%s\n"), members->members[i]);
496 
497 		offset += members->cnt;
498 		smb_group_free_memberlist(members, 0);
499 		if (offset >= mem_cnt)
500 			break;
501 	}
502 }
503 
504 /*
505  * smbadm_group_dump_privs
506  *
507  * Dump group privilege details.
508  */
509 static void
510 smbadm_group_dump_privs(char *gname, ntpriv_list_t *privs)
511 {
512 	int privcnt = 0;
513 	uint32_t privval;
514 	char *name = NULL;
515 	int i;
516 
517 	(void) printf(gettext("\tPrivileges: \n"));
518 
519 	for (i = 0; i < privs->cnt; i++) {
520 		name = privs->privs[i]->name;
521 		if (name == NULL)
522 			continue;
523 
524 		if (smb_group_priv_get(gname, privs->privs[i]->id,
525 		    &privval) != 0) {
526 			continue;
527 		}
528 
529 		if (privval == SE_PRIVILEGE_ENABLED) {
530 			(void) printf(gettext("\t\t%s: On\n"), name);
531 		} else if (privval == SE_PRIVILEGE_DISABLED) {
532 			(void) printf(gettext("\t\t%s: Off\n"), name);
533 		} else {
534 			(void) printf(gettext("\t\t%s: %d\n"),
535 			    name, privval);
536 		}
537 
538 		name = NULL;
539 		privcnt++;
540 	}
541 
542 	if (privcnt == 0)
543 		(void) printf(gettext("\t\tNo privileges\n"));
544 }
545 
546 /*
547  * smbadm_group_dump
548  *
549  * Dump group details.
550  */
551 static int
552 smbadm_group_dump(ntgrp_list_t *list, boolean_t show_mem, boolean_t show_privs)
553 {
554 	ntpriv_list_t *privs = NULL;
555 	char *gname;
556 	uint32_t status;
557 	int i;
558 
559 	if (show_privs) {
560 		if ((status = smb_group_priv_list(&privs)) != 0) {
561 			(void) fprintf(stderr,
562 			    gettext("failed to get privileges (%s)\n"),
563 			    xlate_nt_status(status));
564 			return (1);
565 		}
566 	}
567 
568 	for (i = 0; i < list->cnt; i++) {
569 		gname = list->groups[i].name;
570 
571 		(void) printf(gettext("%s (%s)\n"), gname,
572 		    list->groups[i].desc);
573 		(void) printf(gettext("\tType: %s, Attr: %X\n"),
574 		    list->groups[i].type, list->groups[i].attr);
575 		(void) printf(gettext("\tSID: %s\n"),
576 		    list->groups[i].sid);
577 
578 		if (show_privs)
579 			smbadm_group_dump_privs(gname, privs);
580 
581 		if (show_mem)
582 			smbadm_group_dump_members(list->groups[i].name);
583 	}
584 
585 	return (0);
586 }
587 
588 /*
589  * smbadm_group_show
590  *
591  */
592 static int
593 smbadm_group_show(int argc, char **argv)
594 {
595 	char *gname = NULL;
596 	int cnt = 0;
597 	int offset = 0;
598 	boolean_t show_privs;
599 	boolean_t show_members;
600 	char option;
601 	uint32_t status;
602 	ntgrp_list_t *list = NULL;
603 	int ret = 0;
604 
605 	show_privs = show_members = B_FALSE;
606 
607 	while ((option = getopt(argc, argv, "mp")) != -1) {
608 		switch (option) {
609 		case 'm':
610 			show_members = B_TRUE;
611 			break;
612 		case 'p':
613 			show_privs = B_TRUE;
614 			break;
615 
616 		default:
617 			smbadm_usage(B_FALSE);
618 		}
619 	}
620 
621 	gname = argv[optind];
622 	if (optind >= argc || gname == NULL || *gname == '\0')
623 		gname = "*";
624 
625 	status = smb_group_count(&cnt);
626 	if ((status != NT_STATUS_SUCCESS) || (cnt < 0)) {
627 		(void) fprintf(stderr,
628 		    gettext("failed to get the number of group(s) (%s)\n"),
629 		    xlate_nt_status(status));
630 		return (1);
631 	}
632 
633 	while ((offset < cnt)) {
634 		status = smb_group_list(offset, &list, gname, 0);
635 		if (status != NT_STATUS_SUCCESS) {
636 			(void) fprintf(stderr,
637 			    gettext("failed to get the group(s) (%s)\n"),
638 			    xlate_nt_status(status));
639 			return (1);
640 		}
641 
642 		if ((list == NULL) || (list->cnt <= 0))
643 			break;
644 
645 		ret = smbadm_group_dump(list, show_members, show_privs);
646 		if (ret)
647 			break;
648 
649 		offset += list->cnt;
650 		smb_group_free_list(list, 0);
651 		list = NULL;
652 	}
653 
654 	return (ret);
655 }
656 
657 /*
658  * smbadm_group_delete
659  *
660  */
661 static int
662 smbadm_group_delete(int argc, char **argv)
663 {
664 	uint32_t status;
665 	char *gname = NULL;
666 
667 	gname = argv[optind];
668 	if (optind >= argc || gname == NULL || *gname == '\0') {
669 		(void) fprintf(stderr, gettext("missing group name\n"));
670 		smbadm_usage(B_FALSE);
671 	}
672 
673 	status = smb_group_delete(gname);
674 	if (status != NT_STATUS_SUCCESS) {
675 		(void) fprintf(stderr,
676 		    gettext("failed to delete the group (%s)\n"),
677 		    xlate_nt_status(status));
678 	} else {
679 		(void) printf(gettext("Successfully deleted group '%s'\n"),
680 		    gname);
681 	}
682 
683 	return (status);
684 }
685 
686 /*
687  * smbadm_group_rename
688  *
689  */
690 static int
691 smbadm_group_rename(int argc, char **argv)
692 {
693 	char *gname = NULL;
694 	char *ngname = NULL;
695 	uint32_t status;
696 
697 	gname = argv[optind];
698 	if (optind++ >= argc || gname == NULL || *gname == '\0') {
699 		(void) fprintf(stderr, gettext("missing group name\n"));
700 		smbadm_usage(B_FALSE);
701 	}
702 
703 	ngname = argv[optind];
704 	if (optind >= argc || ngname == NULL || *ngname == '\0') {
705 		(void) fprintf(stderr, gettext("missing new group name\n"));
706 		smbadm_usage(B_FALSE);
707 	}
708 
709 	if (getgrnam(gname) == NULL) {
710 		(void) fprintf(stderr,
711 		    gettext("failed to get the Solaris group\n"));
712 		(void) fprintf(stderr,
713 		    gettext("use 'groupadd' to add the Solaris group\n"));
714 		return (1);
715 	}
716 
717 	status = smb_group_modify(gname, ngname, NULL);
718 	if (status != NT_STATUS_SUCCESS) {
719 		(void) fprintf(stderr,
720 		    gettext("failed to modify the group (%s)\n"),
721 		    xlate_nt_status(status));
722 	} else {
723 		(void) printf(gettext("Successfully modified "
724 		    "group '%s'\n"), gname);
725 	}
726 
727 	return (status);
728 }
729 
730 /*
731  * smbadm_group_setprop
732  *
733  * Set the group properties.
734  */
735 static int
736 smbadm_group_setprop(int argc, char **argv)
737 {
738 	char *gname = NULL;
739 	smbadm_prop_t props[SMBADM_NPROP];
740 	smbadm_prop_handle_t *phandle;
741 	char option;
742 	int pcnt = 0;
743 	int ret;
744 	int p;
745 
746 	bzero(props, SMBADM_NPROP * sizeof (smbadm_prop_t));
747 
748 	while ((option = getopt(argc, argv, "p:")) != -1) {
749 		switch (option) {
750 		case 'p':
751 			if (pcnt >= SMBADM_NPROP) {
752 				(void) fprintf(stderr,
753 				    gettext("exceeded number of supported"
754 				    " properties\n"));
755 				smbadm_usage(B_FALSE);
756 			}
757 
758 			ret = smbadm_prop_parse(optarg, &props[pcnt++]);
759 			if (ret) {
760 				if (ret == 1)
761 					exit(1);
762 
763 				if (ret == 2)
764 					smbadm_usage(B_FALSE);
765 			}
766 			break;
767 
768 		default:
769 			smbadm_usage(B_FALSE);
770 		}
771 	}
772 
773 	if (pcnt == 0) {
774 		(void) fprintf(stderr,
775 		    gettext("missing property=value argument\n"));
776 		smbadm_usage(B_FALSE);
777 	}
778 
779 	gname = argv[optind];
780 	if (optind >= argc || gname == NULL || *gname == '\0') {
781 		(void) fprintf(stderr, gettext("missing group name\n"));
782 		smbadm_usage(B_FALSE);
783 	}
784 
785 	for (p = 0; p < pcnt; p++) {
786 		phandle = smbadm_prop_gethandle(props[p].p_name);
787 		if (phandle) {
788 			if (phandle->p_setfn(gname, &props[p]) != 0)
789 				ret = 1;
790 		}
791 	}
792 
793 	return (ret);
794 }
795 
796 /*
797  * smbadm_group_getprop
798  *
799  * Get the group properties.
800  */
801 static int
802 smbadm_group_getprop(int argc, char **argv)
803 {
804 	char *gname = NULL;
805 	smbadm_prop_t props[SMBADM_NPROP];
806 	smbadm_prop_handle_t *phandle;
807 	char option;
808 	int pcnt = 0;
809 	int ret;
810 	int p;
811 
812 	bzero(props, SMBADM_NPROP * sizeof (smbadm_prop_t));
813 
814 	while ((option = getopt(argc, argv, "p:")) != -1) {
815 		switch (option) {
816 		case 'p':
817 			if (pcnt >= SMBADM_NPROP) {
818 				(void) fprintf(stderr,
819 				    gettext("exceeded number of supported"
820 				    " properties\n"));
821 				smbadm_usage(B_FALSE);
822 			}
823 
824 			ret = smbadm_prop_parse(optarg, &props[pcnt++]);
825 			if (ret) {
826 				if (ret == 1)
827 					exit(1);
828 
829 				if (ret == 2)
830 					smbadm_usage(B_FALSE);
831 			}
832 			break;
833 
834 		default:
835 			smbadm_usage(B_FALSE);
836 		}
837 	}
838 
839 	gname = argv[optind];
840 	if (optind >= argc || gname == NULL || *gname == '\0') {
841 		(void) fprintf(stderr, gettext("missing group name\n"));
842 		smbadm_usage(B_FALSE);
843 	}
844 
845 	if (pcnt == 0) {
846 		/*
847 		 * If no property has be specified then get
848 		 * all the properties.
849 		 */
850 		pcnt = SMBADM_NPROP;
851 		for (p = 0; p < pcnt; p++)
852 			props[p].p_name = smbadm_ptable[p].p_name;
853 	}
854 
855 	for (p = 0; p < pcnt; p++) {
856 		phandle = smbadm_prop_gethandle(props[p].p_name);
857 		if (phandle) {
858 			if (phandle->p_getfn(gname, &props[p]) != 0)
859 				ret = 1;
860 		}
861 	}
862 
863 	return (ret);
864 }
865 
866 /*
867  * smbadm_group_addmember
868  *
869  */
870 static int
871 smbadm_group_addmember(int argc, char **argv)
872 {
873 	char *gname = NULL;
874 	char **mname;
875 	char option;
876 	uint32_t status;
877 	int mcnt = 0;
878 	int ret = 0;
879 	int i;
880 
881 
882 	mname = (char **)malloc(argc * sizeof (char *));
883 	if (mname == NULL) {
884 		(void) fprintf(stderr, gettext("out of memory\n"));
885 		return (1);
886 	}
887 	bzero(mname, argc * sizeof (char *));
888 
889 	while ((option = getopt(argc, argv, "m:")) != -1) {
890 		switch (option) {
891 		case 'm':
892 			mname[mcnt++] = optarg;
893 			break;
894 
895 		default:
896 			free(mname);
897 			smbadm_usage(B_FALSE);
898 		}
899 	}
900 
901 	if (mcnt == 0) {
902 		(void) fprintf(stderr, gettext("missing member name\n"));
903 		free(mname);
904 		smbadm_usage(B_FALSE);
905 	}
906 
907 	gname = argv[optind];
908 	if (optind >= argc || gname == NULL || *gname == 0) {
909 		(void) fprintf(stderr, gettext("missing group name\n"));
910 		free(mname);
911 		smbadm_usage(B_FALSE);
912 	}
913 
914 
915 	for (i = 0; i < mcnt; i++) {
916 		if (mname[i] == NULL)
917 			continue;
918 
919 		status = smb_group_member_add(gname, mname[i]);
920 		if (status != NT_STATUS_SUCCESS) {
921 			(void) fprintf(stderr,
922 			    gettext("failed to add %s (%s)\n"),
923 			    mname[i], xlate_nt_status(status));
924 			ret = 1;
925 		}
926 		else
927 			(void) printf(gettext("Successfully added %s to %s\n"),
928 			    mname[i], gname);
929 	}
930 
931 	free(mname);
932 	return (ret);
933 }
934 
935 /*
936  * smbadm_group_delmember
937  */
938 static int
939 smbadm_group_delmember(int argc, char **argv)
940 {
941 	char *gname = NULL;
942 	char **mname;
943 	char option;
944 	uint32_t status;
945 	int mcnt = 0;
946 	int ret = 0;
947 	int i;
948 
949 	mname = (char **)malloc(argc * sizeof (char *));
950 	if (mname == NULL) {
951 		(void) fprintf(stderr, gettext("out of memory\n"));
952 		return (1);
953 	}
954 	bzero(mname, argc * sizeof (char *));
955 
956 	while ((option = getopt(argc, argv, "m:")) != -1) {
957 		switch (option) {
958 		case 'm':
959 			mname[mcnt++] = optarg;
960 			break;
961 
962 		default:
963 			free(mname);
964 			smbadm_usage(B_FALSE);
965 		}
966 	}
967 
968 	if (mcnt == 0) {
969 		(void) fprintf(stderr, gettext("missing member name\n"));
970 		free(mname);
971 		smbadm_usage(B_FALSE);
972 	}
973 
974 	gname = argv[optind];
975 	if (optind >= argc || gname == NULL || *gname == 0) {
976 		(void) fprintf(stderr, gettext("missing group name\n"));
977 		free(mname);
978 		smbadm_usage(B_FALSE);
979 	}
980 
981 
982 	for (i = 0; i < mcnt; i++) {
983 		if (mname[i] == NULL)
984 			continue;
985 
986 		status = smb_group_member_remove(gname, mname[i]);
987 		if (status != NT_STATUS_SUCCESS) {
988 			(void) fprintf(stderr,
989 			    gettext("failed to remove %s (%s)\n"),
990 			    mname[i], xlate_nt_status(status));
991 			ret = 1;
992 		} else {
993 			(void) printf(
994 			    gettext("Successfully removed %s from %s\n"),
995 			    mname[i], gname);
996 		}
997 	}
998 
999 	return (ret);
1000 }
1001 
1002 static int
1003 smbadm_user_disable(int argc, char **argv)
1004 {
1005 	int error;
1006 	char *user = NULL;
1007 
1008 	user = argv[optind];
1009 	if (optind >= argc || user == NULL || *user == '\0') {
1010 		(void) fprintf(stderr, gettext("missing user name\n"));
1011 		smbadm_usage(B_FALSE);
1012 	}
1013 
1014 	error = smb_pwd_setcntl(user, SMB_PWC_DISABLE);
1015 	if (error == SMB_PWE_SUCCESS)
1016 		(void) printf(gettext("%s is disabled.\n"), user);
1017 	else
1018 		(void) fprintf(stderr, "%s\n", smbadm_pwd_strerror(error));
1019 
1020 	return (error);
1021 }
1022 
1023 static int
1024 smbadm_user_enable(int argc, char **argv)
1025 {
1026 	int error;
1027 	char *user = NULL;
1028 
1029 	user = argv[optind];
1030 	if (optind >= argc || user == NULL || *user == '\0') {
1031 		(void) fprintf(stderr, gettext("missing user name\n"));
1032 		smbadm_usage(B_FALSE);
1033 	}
1034 
1035 	error = smb_pwd_setcntl(user, SMB_PWC_ENABLE);
1036 	if (error == SMB_PWE_SUCCESS)
1037 		(void) printf(gettext("%s is enabled.\n"), user);
1038 	else
1039 		(void) fprintf(stderr, "%s\n", smbadm_pwd_strerror(error));
1040 
1041 	return (error);
1042 }
1043 
1044 
1045 int
1046 main(int argc, char **argv)
1047 {
1048 	int i;
1049 
1050 	(void) malloc(0);	/* satisfy libumem dependency */
1051 
1052 	progname = basename(argv[0]);
1053 
1054 	if (getzoneid() != GLOBAL_ZONEID) {
1055 		(void) fprintf(stderr,
1056 		    gettext("cannot execute in non-global zone\n"));
1057 		return (0);
1058 	}
1059 
1060 	if (is_system_labeled()) {
1061 		(void) fprintf(stderr,
1062 		    gettext("Trusted Extensions not supported\n"));
1063 		return (0);
1064 	}
1065 
1066 	if (argc < 2) {
1067 		(void) fprintf(stderr, gettext("missing command\n"));
1068 		smbadm_usage(B_FALSE);
1069 	}
1070 
1071 	/*
1072 	 * Special case "cmd --help/-?"
1073 	 */
1074 	if (strcmp(argv[1], "-?") == 0 ||
1075 	    strcmp(argv[1], "--help") == 0 ||
1076 	    strcmp(argv[1], "-h") == 0)
1077 		smbadm_usage(B_TRUE);
1078 
1079 	for (i = 0; i < SMBADM_NCMD; ++i) {
1080 		curcmd = &smbadm_cmdtable[i];
1081 		if (strcasecmp(argv[1], curcmd->name) == 0) {
1082 			if (argc > 2) {
1083 				/* cmd subcmd --help/-? */
1084 				if (strcmp(argv[2], "-?") == 0 ||
1085 				    strcmp(argv[2], "--help") == 0 ||
1086 				    strcmp(argv[2], "-h") == 0)
1087 					smbadm_usage(B_TRUE);
1088 			}
1089 
1090 			return (curcmd->func(argc - 1, &argv[1]));
1091 		}
1092 	}
1093 
1094 	curcmd = NULL;
1095 	(void) fprintf(stderr, gettext("unknown subcommand (%s)\n"), argv[1]);
1096 	smbadm_usage(B_FALSE);
1097 	return (2);
1098 }
1099 
1100 static boolean_t
1101 smbadm_prop_validate(smbadm_prop_t *prop, boolean_t chkval)
1102 {
1103 	smbadm_prop_handle_t *pinfo;
1104 	int i;
1105 
1106 	for (i = 0; i < SMBADM_NPROP; i++) {
1107 		pinfo = &smbadm_ptable[i];
1108 		if (strcmp(pinfo->p_name, prop->p_name) == 0) {
1109 			if (pinfo->p_chkfn && chkval)
1110 				return (pinfo->p_chkfn(prop));
1111 
1112 			return (B_TRUE);
1113 		}
1114 	}
1115 
1116 	(void) fprintf(stderr,
1117 	    gettext("unrecognized property '%s'\n"), prop->p_name);
1118 
1119 	return (B_FALSE);
1120 }
1121 
1122 static int
1123 smbadm_prop_parse(char *arg, smbadm_prop_t *prop)
1124 {
1125 	boolean_t parse_value;
1126 	char *equal;
1127 
1128 	if (arg == NULL)
1129 		return (2);
1130 
1131 	prop->p_name = prop->p_value = NULL;
1132 
1133 	if (strcmp(curcmd->name, "set") == 0)
1134 		parse_value = B_TRUE;
1135 	else
1136 		parse_value = B_FALSE;
1137 
1138 	prop->p_name = arg;
1139 
1140 	if (parse_value) {
1141 		equal = strchr(arg, '=');
1142 		if (equal == NULL)
1143 			return (2);
1144 
1145 		*equal++ = '\0';
1146 		prop->p_value = equal;
1147 	}
1148 
1149 	if (smbadm_prop_validate(prop, parse_value) == B_FALSE)
1150 		return (2);
1151 
1152 	return (0);
1153 }
1154 
1155 static smbadm_prop_handle_t *
1156 smbadm_prop_gethandle(char *pname)
1157 {
1158 	int i;
1159 
1160 	for (i = 0; i < SMBADM_NPROP; i++)
1161 		if (strcmp(pname, smbadm_ptable[i].p_name) == 0)
1162 			return (&smbadm_ptable[i]);
1163 
1164 	return (NULL);
1165 }
1166 
1167 static int
1168 smbadm_setprop_desc(char *gname, smbadm_prop_t *prop)
1169 {
1170 	uint32_t status;
1171 
1172 	status = smb_group_modify(gname, gname, prop->p_value);
1173 	if (status != NT_STATUS_SUCCESS) {
1174 		(void) fprintf(stderr,
1175 		    gettext("failed to modify the group description (%s)\n"),
1176 		    xlate_nt_status(status));
1177 		return (1);
1178 	}
1179 
1180 	(void) printf(gettext("Successfully modified "
1181 	    "'%s' description\n"), gname);
1182 
1183 	return (0);
1184 }
1185 
1186 static int
1187 smbadm_getprop_desc(char *gname, smbadm_prop_t *prop)
1188 {
1189 	uint32_t status;
1190 	ntgrp_list_t *list = NULL;
1191 
1192 	status = smb_group_list(0, &list, gname, 0);
1193 	if (status != NT_STATUS_SUCCESS) {
1194 		(void) fprintf(stderr,
1195 		    gettext("failed to get the %s (%s)\n"),
1196 		    prop->p_name, xlate_nt_status(status));
1197 		return (1);
1198 	}
1199 
1200 	if ((list == NULL) || (list->cnt <= 0)) {
1201 		(void) fprintf(stderr, gettext("%s: no such group\n"), gname);
1202 		return (1);
1203 	}
1204 
1205 	(void) printf(gettext("\t%s: %s\n"), prop->p_name,
1206 	    list->groups[0].desc);
1207 	smb_group_free_list(list, 0);
1208 	return (0);
1209 }
1210 
1211 static int
1212 smbadm_group_setpriv(char *gname, uint32_t priv_id, smbadm_prop_t *prop)
1213 {
1214 	uint32_t priv_attr;
1215 	uint32_t status;
1216 	int ret;
1217 
1218 	if (strcasecmp(prop->p_value, "on") == 0) {
1219 		(void) printf(gettext("Enabling %s privilege "), prop->p_name);
1220 		priv_attr = SE_PRIVILEGE_ENABLED;
1221 	} else {
1222 		(void) printf(gettext("Disabling %s privilege "), prop->p_name);
1223 		priv_attr = SE_PRIVILEGE_DISABLED;
1224 	}
1225 
1226 	status = smb_group_priv_set(gname, priv_id, priv_attr);
1227 
1228 	if (status == NT_STATUS_SUCCESS) {
1229 		(void) printf(gettext("succeeded\n"));
1230 		ret = 0;
1231 	} else {
1232 		(void) printf(gettext("failed: %s\n"), xlate_nt_status(status));
1233 		ret = 1;
1234 	}
1235 
1236 	return (ret);
1237 }
1238 
1239 static int
1240 smbadm_group_getpriv(char *gname, uint32_t priv_id, smbadm_prop_t *prop)
1241 {
1242 	uint32_t priv_attr;
1243 	uint32_t status;
1244 
1245 	status = smb_group_priv_get(gname, priv_id, &priv_attr);
1246 	if (status != NT_STATUS_SUCCESS) {
1247 		(void) fprintf(stderr, gettext("failed to get %s (%s)\n"),
1248 		    prop->p_name, xlate_nt_status(status));
1249 		return (1);
1250 	}
1251 
1252 	if (priv_attr == SE_PRIVILEGE_ENABLED)
1253 		(void) printf(gettext("\t%s: %s\n"), prop->p_name, "On");
1254 	else if (priv_attr == SE_PRIVILEGE_DISABLED)
1255 		(void) printf(gettext("\t%s: %s\n"), prop->p_name, "Off");
1256 	else
1257 		(void) printf(gettext("\t%s: %s\n"), prop->p_name, "Unknown");
1258 
1259 	return (0);
1260 }
1261 
1262 static int
1263 smbadm_setprop_tkowner(char *gname, smbadm_prop_t *prop)
1264 {
1265 	return (smbadm_group_setpriv(gname, SE_TAKE_OWNERSHIP_LUID, prop));
1266 }
1267 
1268 static int
1269 smbadm_getprop_tkowner(char *gname, smbadm_prop_t *prop)
1270 {
1271 	return (smbadm_group_getpriv(gname, SE_TAKE_OWNERSHIP_LUID, prop));
1272 }
1273 
1274 static int
1275 smbadm_setprop_backup(char *gname, smbadm_prop_t *prop)
1276 {
1277 	return (smbadm_group_setpriv(gname, SE_BACKUP_LUID, prop));
1278 }
1279 
1280 static int
1281 smbadm_getprop_backup(char *gname, smbadm_prop_t *prop)
1282 {
1283 	return (smbadm_group_getpriv(gname, SE_BACKUP_LUID, prop));
1284 }
1285 
1286 static int
1287 smbadm_setprop_restore(char *gname, smbadm_prop_t *prop)
1288 {
1289 	return (smbadm_group_setpriv(gname, SE_RESTORE_LUID, prop));
1290 }
1291 
1292 static int
1293 smbadm_getprop_restore(char *gname, smbadm_prop_t *prop)
1294 {
1295 	return (smbadm_group_getpriv(gname, SE_RESTORE_LUID, prop));
1296 }
1297 
1298 static boolean_t
1299 smbadm_chkprop_priv(smbadm_prop_t *prop)
1300 {
1301 	if (prop->p_value == NULL || *prop->p_value == '\0') {
1302 		(void) fprintf(stderr,
1303 		    gettext("missing value for '%s'\n"), prop->p_name);
1304 		return (B_FALSE);
1305 	}
1306 
1307 	if (strcasecmp(prop->p_value, "on") == 0)
1308 		return (B_TRUE);
1309 
1310 	if (strcasecmp(prop->p_value, "off") == 0)
1311 		return (B_TRUE);
1312 
1313 	(void) fprintf(stderr,
1314 	    gettext("%s: unrecognized value for '%s' property\n"),
1315 	    prop->p_value, prop->p_name);
1316 
1317 	return (B_FALSE);
1318 }
1319 
1320 static const char *
1321 smbadm_pwd_strerror(int error)
1322 {
1323 	switch (error) {
1324 	case SMB_PWE_SUCCESS:
1325 		return (gettext("Success."));
1326 
1327 	case SMB_PWE_USER_UNKNOWN:
1328 		return (gettext("User does not exist."));
1329 
1330 	case SMB_PWE_USER_DISABLE:
1331 		return (gettext("User is disable."));
1332 
1333 	case SMB_PWE_CLOSE_FAILED:
1334 	case SMB_PWE_OPEN_FAILED:
1335 	case SMB_PWE_WRITE_FAILED:
1336 	case SMB_PWE_UPDATE_FAILED:
1337 		return (gettext("Unexpected failure. "
1338 		    "SMB password database unchanged."));
1339 
1340 	case SMB_PWE_STAT_FAILED:
1341 		return (gettext("stat of SMB password file failed."));
1342 
1343 	case SMB_PWE_BUSY:
1344 		return (gettext("SMB password database busy. "
1345 		    "Try again later."));
1346 
1347 	case SMB_PWE_DENIED:
1348 		return (gettext("Operation not permitted."));
1349 
1350 	case SMB_PWE_SYSTEM_ERROR:
1351 		return (gettext("System error."));
1352 	}
1353 
1354 	return (gettext("Unknown error code."));
1355 }
1356 
1357 /*
1358  * Enable libumem debugging by default on DEBUG builds.
1359  */
1360 #ifdef DEBUG
1361 const char *
1362 _umem_debug_init(void)
1363 {
1364 	return ("default,verbose"); /* $UMEM_DEBUG setting */
1365 }
1366 
1367 const char *
1368 _umem_logging_init(void)
1369 {
1370 	return ("fail,contents"); /* $UMEM_LOGGING setting */
1371 }
1372 #endif
1373