xref: /illumos-gate/usr/src/cmd/smbsrv/smbadm/smbadm.c (revision c8ec8eea)
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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"@(#)smbadm.c	1.9	08/07/30 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 #include <netinet/in.h>
43 
44 #include <smbsrv/libsmb.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_USER_DISABLE,
58 	HELP_USER_ENABLE
59 } smbadm_help_t;
60 
61 #define	SMBADM_CMDF_USER	0x01
62 #define	SMBADM_CMDF_GROUP	0x02
63 #define	SMBADM_CMDF_TYPEMASK	0x0F
64 
65 #define	SMBADM_CHANGE_SECMODE	1
66 #define	SMBADM_CHANGE_DOMAIN	2
67 
68 #define	SMBADM_ANSBUFSIZ	64
69 
70 typedef struct smbadm_cmdinfo {
71 	char *name;
72 	int (*func)(int, char **);
73 	smbadm_help_t usage;
74 	uint32_t flags;
75 } smbadm_cmdinfo_t;
76 
77 smbadm_cmdinfo_t *curcmd;
78 static char *progname;
79 
80 static int smbadm_join(int, char **);
81 static int smbadm_list(int, char **);
82 static int smbadm_group_create(int, char **);
83 static int smbadm_group_delete(int, char **);
84 static int smbadm_group_rename(int, char **);
85 static int smbadm_group_show(int, char **);
86 static int smbadm_group_getprop(int, char **);
87 static int smbadm_group_setprop(int, char **);
88 static int smbadm_group_addmember(int, char **);
89 static int smbadm_group_delmember(int, char **);
90 static int smbadm_user_disable(int, char **);
91 static int smbadm_user_enable(int, char **);
92 
93 static smbadm_cmdinfo_t smbadm_cmdtable[] =
94 {
95 	{ "add-member",		smbadm_group_addmember,	HELP_ADD_MEMBER,
96 	SMBADM_CMDF_GROUP },
97 	{ "create",		smbadm_group_create,	HELP_CREATE,
98 	SMBADM_CMDF_GROUP },
99 	{ "delete",		smbadm_group_delete,	HELP_DELETE,
100 	SMBADM_CMDF_GROUP },
101 	{ "disable-user",	smbadm_user_disable,	HELP_USER_DISABLE,
102 	SMBADM_CMDF_USER },
103 	{ "enable-user",	smbadm_user_enable,	HELP_USER_ENABLE,
104 	SMBADM_CMDF_USER },
105 	{ "get",		smbadm_group_getprop,	HELP_GET,
106 	SMBADM_CMDF_GROUP },
107 	{ "join",		smbadm_join,		HELP_JOIN,	0 },
108 	{ "list",		smbadm_list,		HELP_LIST,	0 },
109 	{ "remove-member",	smbadm_group_delmember,	HELP_DEL_MEMBER,
110 	SMBADM_CMDF_GROUP },
111 	{ "rename",		smbadm_group_rename,	HELP_RENAME,
112 	SMBADM_CMDF_GROUP },
113 	{ "set",		smbadm_group_setprop,	HELP_SET,
114 	SMBADM_CMDF_GROUP },
115 	{ "show",		smbadm_group_show,	HELP_SHOW,
116 	SMBADM_CMDF_GROUP },
117 };
118 
119 #define	SMBADM_NCMD	(sizeof (smbadm_cmdtable) / sizeof (smbadm_cmdtable[0]))
120 
121 typedef struct smbadm_prop {
122 	char *p_name;
123 	char *p_value;
124 } smbadm_prop_t;
125 
126 typedef struct smbadm_prop_handle {
127 	char *p_name;
128 	char *p_dispvalue;
129 	int (*p_setfn)(char *, smbadm_prop_t *);
130 	int (*p_getfn)(char *, smbadm_prop_t *);
131 	boolean_t (*p_chkfn)(smbadm_prop_t *);
132 } smbadm_prop_handle_t;
133 
134 static boolean_t smbadm_prop_validate(smbadm_prop_t *prop, boolean_t chkval);
135 static int smbadm_prop_parse(char *arg, smbadm_prop_t *prop);
136 static smbadm_prop_handle_t *smbadm_prop_gethandle(char *pname);
137 
138 static boolean_t smbadm_chkprop_priv(smbadm_prop_t *prop);
139 static int smbadm_setprop_tkowner(char *gname, smbadm_prop_t *prop);
140 static int smbadm_getprop_tkowner(char *gname, smbadm_prop_t *prop);
141 static int smbadm_setprop_backup(char *gname, smbadm_prop_t *prop);
142 static int smbadm_getprop_backup(char *gname, smbadm_prop_t *prop);
143 static int smbadm_setprop_restore(char *gname, smbadm_prop_t *prop);
144 static int smbadm_getprop_restore(char *gname, smbadm_prop_t *prop);
145 static int smbadm_setprop_desc(char *gname, smbadm_prop_t *prop);
146 static int smbadm_getprop_desc(char *gname, smbadm_prop_t *prop);
147 
148 static smbadm_prop_handle_t smbadm_ptable[] = {
149 	{"backup",	"on | off", 	smbadm_setprop_backup,
150 	smbadm_getprop_backup,	smbadm_chkprop_priv 	},
151 	{"restore",	"on | off",	smbadm_setprop_restore,
152 	smbadm_getprop_restore,	smbadm_chkprop_priv	},
153 	{"take-ownership", "on | off",	smbadm_setprop_tkowner,
154 	smbadm_getprop_tkowner,	smbadm_chkprop_priv	},
155 	{"description",	"<string>",	smbadm_setprop_desc,
156 	smbadm_getprop_desc,	NULL			},
157 };
158 
159 static int smbadm_init(void);
160 static void smbadm_fini(void);
161 static const char *smbadm_pwd_strerror(int error);
162 
163 /*
164  * Number of supported properties
165  */
166 #define	SMBADM_NPROP	(sizeof (smbadm_ptable) / sizeof (smbadm_ptable[0]))
167 
168 static void
169 smbadm_cmdusage(FILE *fp, smbadm_cmdinfo_t *cmd)
170 {
171 	switch (cmd->usage) {
172 	case HELP_ADD_MEMBER:
173 		(void) fprintf(fp,
174 		    gettext("\t%s -m member [[-m member] ...] group\n"),
175 		    cmd->name);
176 		return;
177 
178 	case HELP_CREATE:
179 		(void) fprintf(fp, gettext("\t%s [-d description] group\n"),
180 		    cmd->name);
181 		return;
182 
183 	case HELP_DELETE:
184 		(void) fprintf(fp, gettext("\t%s group\n"), cmd->name);
185 		return;
186 
187 	case HELP_USER_DISABLE:
188 	case HELP_USER_ENABLE:
189 		(void) fprintf(fp, gettext("\t%s user\n"), cmd->name);
190 		return;
191 
192 	case HELP_GET:
193 		(void) fprintf(fp, gettext("\t%s [[-p property] ...] group\n"),
194 		    cmd->name);
195 		return;
196 
197 	case HELP_JOIN:
198 		(void) fprintf(fp, gettext("\t%s -u username domain\n"
199 		    "\t%s -w workgroup\n"), cmd->name, cmd->name);
200 		return;
201 
202 	case HELP_LIST:
203 		(void) fprintf(fp, gettext("\t%s\n"), cmd->name);
204 		return;
205 
206 	case HELP_DEL_MEMBER:
207 		(void) fprintf(fp,
208 		    gettext("\t%s -m member [[-m member] ...] group\n"),
209 		    cmd->name);
210 		return;
211 
212 	case HELP_RENAME:
213 		(void) fprintf(fp, gettext("\t%s group new-group\n"),
214 		    cmd->name);
215 		return;
216 
217 	case HELP_SET:
218 		(void) fprintf(fp, gettext("\t%s -p property=value "
219 		    "[[-p property=value] ...] group\n"), cmd->name);
220 		return;
221 
222 	case HELP_SHOW:
223 		(void) fprintf(fp, gettext("\t%s [-m] [-p] [group]\n"),
224 		    cmd->name);
225 		return;
226 
227 	default:
228 		break;
229 	}
230 
231 	abort();
232 	/* NOTREACHED */
233 }
234 
235 static void
236 smbadm_usage(boolean_t requested)
237 {
238 	FILE *fp = requested ? stdout : stderr;
239 	boolean_t show_props = B_FALSE;
240 	int i;
241 
242 	if (curcmd == NULL) {
243 		(void) fprintf(fp,
244 		    gettext("usage: %s [-h | <command> [options]]\n"),
245 		    progname);
246 		(void) fprintf(fp,
247 		    gettext("where 'command' is one of the following:\n\n"));
248 
249 		for (i = 0; i < SMBADM_NCMD; i++)
250 			smbadm_cmdusage(fp, &smbadm_cmdtable[i]);
251 
252 		(void) fprintf(fp,
253 		    gettext("\nFor property list, run %s %s|%s\n"),
254 		    progname, "get", "set");
255 
256 		exit(requested ? 0 : 2);
257 	}
258 
259 	(void) fprintf(fp, gettext("usage:\n"));
260 	smbadm_cmdusage(fp, curcmd);
261 
262 	if (strcmp(curcmd->name, "get") == 0 ||
263 	    strcmp(curcmd->name, "set") == 0)
264 		show_props = B_TRUE;
265 
266 	if (show_props) {
267 		(void) fprintf(fp,
268 		    gettext("\nThe following properties are supported:\n"));
269 
270 		(void) fprintf(fp, "\n\t%-16s   %s\n\n",
271 		    "PROPERTY", "VALUES");
272 
273 		for (i = 0; i < SMBADM_NPROP; i++) {
274 			(void) fprintf(fp, "\t%-16s   %s\n",
275 			    smbadm_ptable[i].p_name,
276 			    smbadm_ptable[i].p_dispvalue);
277 		}
278 	}
279 
280 	exit(requested ? 0 : 2);
281 }
282 
283 /*
284  * smbadm_strcasecmplist
285  *
286  * Find a string 's' within a list of strings.
287  *
288  * Returns the index of the matching string or -1 if there is no match.
289  */
290 static int
291 smbadm_strcasecmplist(const char *s, ...)
292 {
293 	va_list ap;
294 	char *p;
295 	int ndx;
296 
297 	va_start(ap, s);
298 
299 	for (ndx = 0; ((p = va_arg(ap, char *)) != NULL); ++ndx) {
300 		if (strcasecmp(s, p) == 0) {
301 			va_end(ap);
302 			return (ndx);
303 		}
304 	}
305 
306 	va_end(ap);
307 	return (-1);
308 }
309 
310 /*
311  * smbadm_answer_prompt
312  *
313  * Prompt for the answer to a question.  A default response must be
314  * specified, which will be used if the user presses <enter> without
315  * answering the question.
316  */
317 static int
318 smbadm_answer_prompt(const char *prompt, char *answer, const char *dflt)
319 {
320 	char buf[SMBADM_ANSBUFSIZ];
321 	char *p;
322 
323 	(void) printf(gettext("%s [%s]: "), prompt, dflt);
324 
325 	if (fgets(buf, SMBADM_ANSBUFSIZ, stdin) == NULL)
326 		return (-1);
327 
328 	if ((p = strchr(buf, '\n')) != NULL)
329 		*p = '\0';
330 
331 	if (*buf == '\0')
332 		(void) strlcpy(answer, dflt, SMBADM_ANSBUFSIZ);
333 	else
334 		(void) strlcpy(answer, buf, SMBADM_ANSBUFSIZ);
335 
336 	return (0);
337 }
338 
339 /*
340  * smbadm_confirm
341  *
342  * Ask a question that requires a yes/no answer.
343  * A default response must be specified.
344  */
345 static boolean_t
346 smbadm_confirm(const char *prompt, const char *dflt)
347 {
348 	char buf[SMBADM_ANSBUFSIZ];
349 
350 	for (;;) {
351 		if (smbadm_answer_prompt(prompt, buf, dflt) < 0)
352 			return (B_FALSE);
353 
354 		if (smbadm_strcasecmplist(buf, "n", "no", 0) >= 0)
355 			return (B_FALSE);
356 
357 		if (smbadm_strcasecmplist(buf, "y", "yes", 0) >= 0)
358 			return (B_TRUE);
359 
360 		(void) printf(gettext("Please answer yes or no.\n"));
361 	}
362 }
363 
364 static boolean_t
365 smbadm_join_prompt(char *curdom, int prmpt_type)
366 {
367 	boolean_t ret = B_FALSE;
368 
369 	switch (prmpt_type) {
370 
371 		case SMBADM_CHANGE_SECMODE:
372 			(void) printf(gettext("This operation requires that "
373 			    "the service be restarted.\n"));
374 			ret = smbadm_confirm(
375 			    "Would you like to continue ?", "no");
376 			break;
377 
378 		case SMBADM_CHANGE_DOMAIN:
379 			(void) printf(gettext("This system has already "
380 			    "joined to '%s' domain.\n"), curdom);
381 			ret = smbadm_confirm(
382 			    "Would you like to join the new domain ?", "no");
383 			break;
384 
385 		default:
386 			break;
387 	}
388 
389 	return (ret);
390 }
391 
392 /*
393  * smbadm_join
394  *
395  * Join the given domain/workgroup
396  */
397 static int
398 smbadm_join(int argc, char **argv)
399 {
400 	char option;
401 	smb_joininfo_t jdi;
402 	boolean_t join_w = B_FALSE;
403 	boolean_t join_d = B_FALSE;
404 	boolean_t mode_change = B_FALSE;
405 	uint32_t status;
406 	char curdom[MAXHOSTNAMELEN];
407 
408 	bzero(&jdi, sizeof (jdi));
409 
410 	while ((option = getopt(argc, argv, "u:w:")) != -1) {
411 		switch (option) {
412 		case 'w':
413 			(void) strlcpy(jdi.domain_name, optarg,
414 			    sizeof (jdi.domain_name));
415 			jdi.mode = SMB_SECMODE_WORKGRP;
416 			join_w = B_TRUE;
417 			break;
418 
419 		case 'u':
420 			/* admin username */
421 			(void) strlcpy(jdi.domain_username, optarg,
422 			    sizeof (jdi.domain_username));
423 			jdi.mode = SMB_SECMODE_DOMAIN;
424 			join_d = B_TRUE;
425 			break;
426 
427 		default:
428 			smbadm_usage(B_FALSE);
429 		}
430 	}
431 
432 	if (join_w && join_d) {
433 		(void) fprintf(stderr,
434 		    gettext("domain and workgroup "
435 		    "can not be specified together\n"));
436 		smbadm_usage(B_FALSE);
437 	}
438 
439 	if (join_d && (argv[optind] != NULL)) {
440 		(void) strlcpy(jdi.domain_name, argv[optind],
441 		    sizeof (jdi.domain_name));
442 	}
443 
444 	if (*jdi.domain_name == '\0') {
445 		(void) fprintf(stderr, gettext("missing %s name\n"),
446 		    (join_d) ? "domain" : "workgroup");
447 		smbadm_usage(B_FALSE);
448 	}
449 
450 	if (join_d && *jdi.domain_username == '\0') {
451 		(void) fprintf(stderr, gettext("missing username\n"));
452 		smbadm_usage(B_FALSE);
453 	}
454 
455 	if (smb_config_get_secmode() != jdi.mode)
456 		mode_change = B_TRUE;
457 
458 	if (join_w) {
459 
460 		if (mode_change)
461 			if (!smbadm_join_prompt(NULL, SMBADM_CHANGE_SECMODE))
462 				return (0);
463 
464 		status = smb_join(&jdi);
465 		if (status == NT_STATUS_SUCCESS) {
466 
467 			if (mode_change)
468 				if (smb_smf_restart_service() != 0)
469 					(void) fprintf(stderr, gettext(
470 					    "Unable to restart smb service. "
471 					    "Run 'svcs -xv smb/server' for "
472 					    "more information."));
473 
474 			(void) printf(
475 			    gettext("Successfully joined workgroup '%s'\n"),
476 			    jdi.domain_name);
477 			return (0);
478 		}
479 
480 		(void) fprintf(stderr,
481 		    gettext("failed to join workgroup '%s' (%s)\n"),
482 		    jdi.domain_name, xlate_nt_status(status));
483 
484 		return (1);
485 	}
486 
487 	if (smb_config_get_secmode() == SMB_SECMODE_DOMAIN) {
488 		(void) smb_getdomainname(curdom, MAXHOSTNAMELEN);
489 		if (*curdom != 0 && strncasecmp(curdom, jdi.domain_name,
490 		    strlen(curdom))) {
491 			if (!smbadm_join_prompt(curdom, SMBADM_CHANGE_DOMAIN))
492 				return (0);
493 		}
494 	}
495 
496 	if (mode_change)
497 		if (!smbadm_join_prompt(NULL, SMBADM_CHANGE_SECMODE))
498 			return (0);
499 
500 	/* Join the domain */
501 	if (*jdi.domain_passwd == '\0') {
502 		char *p = NULL;
503 		char *prompt = gettext("Enter domain password: ");
504 		p = getpassphrase(prompt);
505 		if (!p) {
506 			(void) fprintf(stderr, gettext("missing password\n"));
507 			smbadm_usage(B_FALSE);
508 		}
509 
510 		(void) strlcpy(jdi.domain_passwd, p,
511 		    sizeof (jdi.domain_passwd));
512 	}
513 
514 	(void) printf(gettext("Joining '%s' ... this may take a minute ...\n"),
515 	    jdi.domain_name);
516 
517 	status = smb_join(&jdi);
518 
519 	switch (status) {
520 	case NT_STATUS_SUCCESS:
521 
522 		if (mode_change)
523 			if (smb_smf_restart_service() != 0)
524 				(void) fprintf(stderr, gettext(
525 				    "Unable to restart smb service. "
526 				    "Run 'svcs -xv smb/server' for "
527 				    "more information."));
528 
529 		(void) printf(gettext("Successfully joined domain '%s'\n"),
530 		    jdi.domain_name);
531 
532 		return (0);
533 
534 	case NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND:
535 		(void) fprintf(stderr, gettext("failed to find "
536 		    "any domain controllers for '%s'\n"),
537 		    jdi.domain_name);
538 		break;
539 
540 	default:
541 		(void) fprintf(stderr,
542 		    gettext("failed to join domain '%s' (%s)\n"),
543 		    jdi.domain_name, xlate_nt_status(status));
544 	}
545 
546 	return (1);
547 }
548 
549 /*
550  * smbadm_list
551  *
552  * Displays current security mode and domain/workgroup name.
553  */
554 /*ARGSUSED*/
555 static int
556 smbadm_list(int argc, char **argv)
557 {
558 	char domain[MAXHOSTNAMELEN];
559 	char modename[16];
560 	int rc;
561 	char ipstr[INET6_ADDRSTRLEN];
562 	smb_ntdomain_t domain_info;
563 
564 	rc = smb_config_getstr(SMB_CI_SECURITY, modename, sizeof (modename));
565 	if (rc != SMBD_SMF_OK) {
566 		(void) fprintf(stderr,
567 		    gettext("failed to get the connected mode\n"));
568 		return (1);
569 	}
570 
571 	if (smb_getdomainname(domain, sizeof (domain)) != 0) {
572 		(void) fprintf(stderr, gettext("failed to get the %s name\n"),
573 		    modename);
574 		return (1);
575 	}
576 	if (strcmp(modename, "workgroup") == 0) {
577 		(void) printf(gettext("Workgroup: %s\n"), domain);
578 		return (0);
579 	}
580 	(void) printf(gettext("Domain: %s\n"), domain);
581 
582 	bzero(&domain_info, sizeof (smb_ntdomain_t));
583 	if ((smb_get_dcinfo(&domain_info) == NT_STATUS_SUCCESS) &&
584 	    (*domain_info.domain != '\0') && (domain_info.ipaddr != 0)) {
585 		(void) inet_ntop(AF_INET, (const void *)&domain_info.ipaddr,
586 		    ipstr, sizeof (ipstr));
587 		(void) printf(gettext("Selected Domain Controller: %s (%s)\n"),
588 		    domain_info.server, ipstr);
589 	}
590 
591 	return (0);
592 }
593 
594 /*
595  * smbadm_group_create
596  *
597  * Creates a local SMB group
598  */
599 static int
600 smbadm_group_create(int argc, char **argv)
601 {
602 	char *gname = NULL;
603 	char *desc = NULL;
604 	char option;
605 	int status;
606 
607 	while ((option = getopt(argc, argv, "d:")) != -1) {
608 		switch (option) {
609 		case 'd':
610 			desc = optarg;
611 			break;
612 
613 		default:
614 			smbadm_usage(B_FALSE);
615 		}
616 	}
617 
618 	gname = argv[optind];
619 	if (optind >= argc || gname == NULL || *gname == '\0') {
620 		(void) fprintf(stderr, gettext("missing group name\n"));
621 		smbadm_usage(B_FALSE);
622 	}
623 
624 	if (getgrnam(gname) == NULL) {
625 		(void) fprintf(stderr,
626 		    gettext("failed to get the Solaris group '%s'\n"), gname);
627 		(void) fprintf(stderr,
628 		    gettext("use 'groupadd' to add '%s'\n"), gname);
629 		return (1);
630 	}
631 
632 	status = smb_lgrp_add(gname, desc);
633 	if (status != SMB_LGRP_SUCCESS) {
634 		(void) fprintf(stderr,
635 		    gettext("failed to create the group (%s)\n"),
636 		    smb_lgrp_strerror(status));
637 	} else {
638 		(void) printf(gettext("'%s' created.\n"),
639 		    gname);
640 	}
641 
642 	return (status);
643 }
644 
645 /*
646  * smbadm_group_dump_members
647  *
648  * Dump group members details.
649  */
650 static void
651 smbadm_group_dump_members(smb_gsid_t *members, int num)
652 {
653 	char sidstr[SMB_SID_STRSZ];
654 	int i;
655 
656 	if (num == 0) {
657 		(void) printf(gettext("\tNo members\n"));
658 		return;
659 	}
660 
661 	(void) printf(gettext("\tMembers:\n"));
662 	for (i = 0; i < num; i++) {
663 		*sidstr = '\0';
664 		if (smb_lookup_sid(members[i].gs_sid, sidstr,
665 		    sizeof (sidstr)) == NT_STATUS_SUCCESS)
666 			(void) printf(gettext("\t\t%s\n"), sidstr);
667 		else
668 			(void) printf(gettext("\t\tERROR! Invalid SID\n"));
669 	}
670 }
671 
672 /*
673  * smbadm_group_dump_privs
674  *
675  * Dump group privilege details.
676  */
677 static void
678 smbadm_group_dump_privs(smb_privset_t *privs)
679 {
680 	smb_privinfo_t *pinfo;
681 	char *pstatus;
682 	int i;
683 
684 	(void) printf(gettext("\tPrivileges: \n"));
685 
686 	for (i = 0; i < privs->priv_cnt; i++) {
687 		pinfo = smb_priv_getbyvalue(privs->priv[i].luid.lo_part);
688 		if ((pinfo == NULL) || (pinfo->flags & PF_PRESENTABLE) == 0)
689 			continue;
690 
691 		switch (privs->priv[i].attrs) {
692 		case SE_PRIVILEGE_ENABLED:
693 			pstatus = "On";
694 			break;
695 		case SE_PRIVILEGE_DISABLED:
696 			pstatus = "Off";
697 			break;
698 		default:
699 			pstatus = "Unknown";
700 			break;
701 		}
702 		(void) printf(gettext("\t\t%s: %s\n"), pinfo->name, pstatus);
703 	}
704 
705 	if (privs->priv_cnt == 0)
706 		(void) printf(gettext("\t\tNo privileges\n"));
707 }
708 
709 /*
710  * smbadm_group_dump
711  *
712  * Dump group details.
713  */
714 static void
715 smbadm_group_dump(smb_group_t *grp, boolean_t show_mem, boolean_t show_privs)
716 {
717 	char sidstr[SMB_SID_STRSZ];
718 
719 	(void) printf(gettext("%s (%s)\n"), grp->sg_name, grp->sg_cmnt);
720 
721 	smb_sid_tostr(grp->sg_id.gs_sid, sidstr);
722 	(void) printf(gettext("\tSID: %s\n"), sidstr);
723 
724 	if (show_privs)
725 		smbadm_group_dump_privs(grp->sg_privs);
726 
727 	if (show_mem)
728 		smbadm_group_dump_members(grp->sg_members, grp->sg_nmembers);
729 }
730 
731 /*
732  * smbadm_group_show
733  *
734  */
735 static int
736 smbadm_group_show(int argc, char **argv)
737 {
738 	char *gname = NULL;
739 	boolean_t show_privs;
740 	boolean_t show_members;
741 	char option;
742 	int status;
743 	smb_group_t grp;
744 	smb_giter_t gi;
745 
746 	show_privs = show_members = B_FALSE;
747 
748 	while ((option = getopt(argc, argv, "mp")) != -1) {
749 		switch (option) {
750 		case 'm':
751 			show_members = B_TRUE;
752 			break;
753 		case 'p':
754 			show_privs = B_TRUE;
755 			break;
756 
757 		default:
758 			smbadm_usage(B_FALSE);
759 		}
760 	}
761 
762 	gname = argv[optind];
763 	if (optind >= argc || gname == NULL || *gname == '\0')
764 		gname = "*";
765 
766 	if (strcmp(gname, "*")) {
767 		status = smb_lgrp_getbyname(gname, &grp);
768 		if (status == SMB_LGRP_SUCCESS) {
769 			smbadm_group_dump(&grp, show_members, show_privs);
770 			smb_lgrp_free(&grp);
771 		} else {
772 			(void) fprintf(stderr,
773 			    gettext("failed to find '%s' (%s)\n"),
774 			    gname, smb_lgrp_strerror(status));
775 		}
776 		return (status);
777 	}
778 
779 	if ((status = smb_lgrp_iteropen(&gi)) != SMB_LGRP_SUCCESS) {
780 		(void) fprintf(stderr,
781 		    gettext("failed to list groups (%s)\n"),
782 		    smb_lgrp_strerror(status));
783 		return (status);
784 	}
785 
786 	while ((status = smb_lgrp_iterate(&gi, &grp)) == SMB_LGRP_SUCCESS) {
787 		smbadm_group_dump(&grp, show_members, show_privs);
788 		smb_lgrp_free(&grp);
789 	}
790 
791 	smb_lgrp_iterclose(&gi);
792 
793 	if (status != SMB_LGRP_NO_MORE) {
794 		(void) fprintf(stderr,
795 		    gettext("failed to get all the groups (%s)\n"),
796 		    smb_lgrp_strerror(status));
797 		return (status);
798 	}
799 
800 	return (0);
801 }
802 
803 /*
804  * smbadm_group_delete
805  */
806 static int
807 smbadm_group_delete(int argc, char **argv)
808 {
809 	char *gname = NULL;
810 	int status;
811 
812 	gname = argv[optind];
813 	if (optind >= argc || gname == NULL || *gname == '\0') {
814 		(void) fprintf(stderr, gettext("missing group name\n"));
815 		smbadm_usage(B_FALSE);
816 	}
817 
818 	status = smb_lgrp_delete(gname);
819 	if (status != SMB_LGRP_SUCCESS) {
820 		(void) fprintf(stderr,
821 		    gettext("failed to delete the group (%s)\n"),
822 		    smb_lgrp_strerror(status));
823 	} else {
824 		(void) printf(gettext("'%s' deleted.\n"),
825 		    gname);
826 	}
827 
828 	return (status);
829 }
830 
831 /*
832  * smbadm_group_rename
833  */
834 static int
835 smbadm_group_rename(int argc, char **argv)
836 {
837 	char *gname = NULL;
838 	char *ngname = NULL;
839 	int status;
840 
841 	gname = argv[optind];
842 	if (optind++ >= argc || gname == NULL || *gname == '\0') {
843 		(void) fprintf(stderr, gettext("missing group name\n"));
844 		smbadm_usage(B_FALSE);
845 	}
846 
847 	ngname = argv[optind];
848 	if (optind >= argc || ngname == NULL || *ngname == '\0') {
849 		(void) fprintf(stderr, gettext("missing new group name\n"));
850 		smbadm_usage(B_FALSE);
851 	}
852 
853 	if (getgrnam(ngname) == NULL) {
854 		(void) fprintf(stderr,
855 		    gettext("failed to get the Solaris group '%s'\n"), ngname);
856 		(void) fprintf(stderr,
857 		    gettext("use 'groupadd' to add '%s'\n"), ngname);
858 		return (1);
859 	}
860 
861 	status = smb_lgrp_rename(gname, ngname);
862 	if (status != SMB_LGRP_SUCCESS) {
863 		if (status == SMB_LGRP_EXISTS)
864 			(void) fprintf(stderr,
865 			    gettext("failed to rename '%s' (%s already "
866 			    "exists)\n"), gname, ngname);
867 		else
868 			(void) fprintf(stderr,
869 			    gettext("failed to rename '%s' (%s)\n"), gname,
870 			    smb_lgrp_strerror(status));
871 	} else {
872 		(void) printf(gettext("'%s' renamed to '%s'\n"), gname, ngname);
873 	}
874 
875 	return (status);
876 }
877 
878 /*
879  * smbadm_group_setprop
880  *
881  * Set the group properties.
882  */
883 static int
884 smbadm_group_setprop(int argc, char **argv)
885 {
886 	char *gname = NULL;
887 	smbadm_prop_t props[SMBADM_NPROP];
888 	smbadm_prop_handle_t *phandle;
889 	char option;
890 	int pcnt = 0;
891 	int ret;
892 	int p;
893 
894 	bzero(props, SMBADM_NPROP * sizeof (smbadm_prop_t));
895 
896 	while ((option = getopt(argc, argv, "p:")) != -1) {
897 		switch (option) {
898 		case 'p':
899 			if (pcnt >= SMBADM_NPROP) {
900 				(void) fprintf(stderr,
901 				    gettext("exceeded number of supported"
902 				    " properties\n"));
903 				smbadm_usage(B_FALSE);
904 			}
905 
906 			if (smbadm_prop_parse(optarg, &props[pcnt++]) != 0)
907 				smbadm_usage(B_FALSE);
908 			break;
909 
910 		default:
911 			smbadm_usage(B_FALSE);
912 		}
913 	}
914 
915 	if (pcnt == 0) {
916 		(void) fprintf(stderr,
917 		    gettext("missing property=value argument\n"));
918 		smbadm_usage(B_FALSE);
919 	}
920 
921 	gname = argv[optind];
922 	if (optind >= argc || gname == NULL || *gname == '\0') {
923 		(void) fprintf(stderr, gettext("missing group name\n"));
924 		smbadm_usage(B_FALSE);
925 	}
926 
927 	for (p = 0; p < pcnt; p++) {
928 		phandle = smbadm_prop_gethandle(props[p].p_name);
929 		if (phandle) {
930 			if (phandle->p_setfn(gname, &props[p]) != 0)
931 				ret = 1;
932 		}
933 	}
934 
935 	return (ret);
936 }
937 
938 /*
939  * smbadm_group_getprop
940  *
941  * Get the group properties.
942  */
943 static int
944 smbadm_group_getprop(int argc, char **argv)
945 {
946 	char *gname = NULL;
947 	smbadm_prop_t props[SMBADM_NPROP];
948 	smbadm_prop_handle_t *phandle;
949 	char option;
950 	int pcnt = 0;
951 	int ret;
952 	int p;
953 
954 	bzero(props, SMBADM_NPROP * sizeof (smbadm_prop_t));
955 
956 	while ((option = getopt(argc, argv, "p:")) != -1) {
957 		switch (option) {
958 		case 'p':
959 			if (pcnt >= SMBADM_NPROP) {
960 				(void) fprintf(stderr,
961 				    gettext("exceeded number of supported"
962 				    " properties\n"));
963 				smbadm_usage(B_FALSE);
964 			}
965 
966 			if (smbadm_prop_parse(optarg, &props[pcnt++]) != 0)
967 				smbadm_usage(B_FALSE);
968 			break;
969 
970 		default:
971 			smbadm_usage(B_FALSE);
972 		}
973 	}
974 
975 	gname = argv[optind];
976 	if (optind >= argc || gname == NULL || *gname == '\0') {
977 		(void) fprintf(stderr, gettext("missing group name\n"));
978 		smbadm_usage(B_FALSE);
979 	}
980 
981 	if (pcnt == 0) {
982 		/*
983 		 * If no property has be specified then get
984 		 * all the properties.
985 		 */
986 		pcnt = SMBADM_NPROP;
987 		for (p = 0; p < pcnt; p++)
988 			props[p].p_name = smbadm_ptable[p].p_name;
989 	}
990 
991 	for (p = 0; p < pcnt; p++) {
992 		phandle = smbadm_prop_gethandle(props[p].p_name);
993 		if (phandle) {
994 			if (phandle->p_getfn(gname, &props[p]) != 0)
995 				ret = 1;
996 		}
997 	}
998 
999 	return (ret);
1000 }
1001 
1002 /*
1003  * smbadm_group_addmember
1004  *
1005  */
1006 static int
1007 smbadm_group_addmember(int argc, char **argv)
1008 {
1009 	char *gname = NULL;
1010 	char **mname;
1011 	char option;
1012 	smb_gsid_t msid;
1013 	int status;
1014 	int mcnt = 0;
1015 	int ret = 0;
1016 	int i;
1017 
1018 
1019 	mname = (char **)malloc(argc * sizeof (char *));
1020 	if (mname == NULL) {
1021 		(void) fprintf(stderr, gettext("out of memory\n"));
1022 		return (1);
1023 	}
1024 	bzero(mname, argc * sizeof (char *));
1025 
1026 	while ((option = getopt(argc, argv, "m:")) != -1) {
1027 		switch (option) {
1028 		case 'm':
1029 			mname[mcnt++] = optarg;
1030 			break;
1031 
1032 		default:
1033 			free(mname);
1034 			smbadm_usage(B_FALSE);
1035 		}
1036 	}
1037 
1038 	if (mcnt == 0) {
1039 		(void) fprintf(stderr, gettext("missing member name\n"));
1040 		free(mname);
1041 		smbadm_usage(B_FALSE);
1042 	}
1043 
1044 	gname = argv[optind];
1045 	if (optind >= argc || gname == NULL || *gname == 0) {
1046 		(void) fprintf(stderr, gettext("missing group name\n"));
1047 		free(mname);
1048 		smbadm_usage(B_FALSE);
1049 	}
1050 
1051 
1052 	for (i = 0; i < mcnt; i++) {
1053 		if (mname[i] == NULL)
1054 			continue;
1055 
1056 		if (smb_lookup_name(mname[i], &msid) != NT_STATUS_SUCCESS) {
1057 			(void) fprintf(stderr,
1058 			    gettext("failed to add %s "
1059 			    "(could not obtain the SID)\n"),
1060 			    mname[i]);
1061 			continue;
1062 		}
1063 
1064 		status = smb_lgrp_add_member(gname, msid.gs_sid, msid.gs_type);
1065 		free(msid.gs_sid);
1066 		if (status != SMB_LGRP_SUCCESS) {
1067 			(void) fprintf(stderr,
1068 			    gettext("failed to add %s (%s)\n"),
1069 			    mname[i], smb_lgrp_strerror(status));
1070 			ret = 1;
1071 		} else {
1072 			(void) printf(gettext("'%s' is now a member of '%s'\n"),
1073 			    mname[i], gname);
1074 		}
1075 	}
1076 
1077 	free(mname);
1078 	return (ret);
1079 }
1080 
1081 /*
1082  * smbadm_group_delmember
1083  */
1084 static int
1085 smbadm_group_delmember(int argc, char **argv)
1086 {
1087 	char *gname = NULL;
1088 	char **mname;
1089 	char option;
1090 	smb_gsid_t msid;
1091 	int status;
1092 	int mcnt = 0;
1093 	int ret = 0;
1094 	int i;
1095 
1096 	mname = (char **)malloc(argc * sizeof (char *));
1097 	if (mname == NULL) {
1098 		(void) fprintf(stderr, gettext("out of memory\n"));
1099 		return (1);
1100 	}
1101 	bzero(mname, argc * sizeof (char *));
1102 
1103 	while ((option = getopt(argc, argv, "m:")) != -1) {
1104 		switch (option) {
1105 		case 'm':
1106 			mname[mcnt++] = optarg;
1107 			break;
1108 
1109 		default:
1110 			free(mname);
1111 			smbadm_usage(B_FALSE);
1112 		}
1113 	}
1114 
1115 	if (mcnt == 0) {
1116 		(void) fprintf(stderr, gettext("missing member name\n"));
1117 		free(mname);
1118 		smbadm_usage(B_FALSE);
1119 	}
1120 
1121 	gname = argv[optind];
1122 	if (optind >= argc || gname == NULL || *gname == 0) {
1123 		(void) fprintf(stderr, gettext("missing group name\n"));
1124 		free(mname);
1125 		smbadm_usage(B_FALSE);
1126 	}
1127 
1128 
1129 	for (i = 0; i < mcnt; i++) {
1130 		if (mname[i] == NULL)
1131 			continue;
1132 
1133 		if (smb_lookup_name(mname[i], &msid) != NT_STATUS_SUCCESS) {
1134 			(void) fprintf(stderr,
1135 			    gettext("failed to remove %s "
1136 			    "(could not obtain the SID)\n"),
1137 			    mname[i]);
1138 			continue;
1139 		}
1140 
1141 		status = smb_lgrp_del_member(gname, msid.gs_sid, msid.gs_type);
1142 		free(msid.gs_sid);
1143 		if (status != SMB_LGRP_SUCCESS) {
1144 			(void) fprintf(stderr,
1145 			    gettext("failed to remove %s (%s)\n"),
1146 			    mname[i], smb_lgrp_strerror(status));
1147 			ret = 1;
1148 		} else {
1149 			(void) printf(
1150 			    gettext("'%s' has been removed from %s\n"),
1151 			    mname[i], gname);
1152 		}
1153 	}
1154 
1155 	return (ret);
1156 }
1157 
1158 static int
1159 smbadm_user_disable(int argc, char **argv)
1160 {
1161 	int error;
1162 	char *user = NULL;
1163 
1164 	user = argv[optind];
1165 	if (optind >= argc || user == NULL || *user == '\0') {
1166 		(void) fprintf(stderr, gettext("missing user name\n"));
1167 		smbadm_usage(B_FALSE);
1168 	}
1169 
1170 	error = smb_pwd_setcntl(user, SMB_PWC_DISABLE);
1171 	if (error == SMB_PWE_SUCCESS)
1172 		(void) printf(gettext("%s is disabled.\n"), user);
1173 	else
1174 		(void) fprintf(stderr, "%s\n", smbadm_pwd_strerror(error));
1175 
1176 	return (error);
1177 }
1178 
1179 static int
1180 smbadm_user_enable(int argc, char **argv)
1181 {
1182 	int error;
1183 	char *user = NULL;
1184 
1185 	user = argv[optind];
1186 	if (optind >= argc || user == NULL || *user == '\0') {
1187 		(void) fprintf(stderr, gettext("missing user name\n"));
1188 		smbadm_usage(B_FALSE);
1189 	}
1190 
1191 	error = smb_pwd_setcntl(user, SMB_PWC_ENABLE);
1192 	if (error == SMB_PWE_SUCCESS)
1193 		(void) printf(gettext("%s is enabled.\n"), user);
1194 	else
1195 		(void) fprintf(stderr, "%s\n", smbadm_pwd_strerror(error));
1196 
1197 	return (error);
1198 }
1199 
1200 
1201 int
1202 main(int argc, char **argv)
1203 {
1204 	int ret;
1205 	int i;
1206 
1207 	(void) malloc(0);	/* satisfy libumem dependency */
1208 
1209 	progname = basename(argv[0]);
1210 
1211 	if (getzoneid() != GLOBAL_ZONEID) {
1212 		(void) fprintf(stderr,
1213 		    gettext("cannot execute in non-global zone\n"));
1214 		return (0);
1215 	}
1216 
1217 	if (is_system_labeled()) {
1218 		(void) fprintf(stderr,
1219 		    gettext("Trusted Extensions not supported\n"));
1220 		return (0);
1221 	}
1222 
1223 	if (argc < 2) {
1224 		(void) fprintf(stderr, gettext("missing command\n"));
1225 		smbadm_usage(B_FALSE);
1226 	}
1227 
1228 	/*
1229 	 * Special case "cmd --help/-?"
1230 	 */
1231 	if (strcmp(argv[1], "-?") == 0 ||
1232 	    strcmp(argv[1], "--help") == 0 ||
1233 	    strcmp(argv[1], "-h") == 0)
1234 		smbadm_usage(B_TRUE);
1235 
1236 	for (i = 0; i < SMBADM_NCMD; ++i) {
1237 		curcmd = &smbadm_cmdtable[i];
1238 		if (strcasecmp(argv[1], curcmd->name) == 0) {
1239 			if (argc > 2) {
1240 				/* cmd subcmd --help/-? */
1241 				if (strcmp(argv[2], "-?") == 0 ||
1242 				    strcmp(argv[2], "--help") == 0 ||
1243 				    strcmp(argv[2], "-h") == 0)
1244 					smbadm_usage(B_TRUE);
1245 			}
1246 
1247 			if ((ret = smbadm_init()) != 0)
1248 				return (ret);
1249 
1250 			ret = curcmd->func(argc - 1, &argv[1]);
1251 
1252 			smbadm_fini();
1253 			return (ret);
1254 		}
1255 	}
1256 
1257 	curcmd = NULL;
1258 	(void) fprintf(stderr, gettext("unknown subcommand (%s)\n"), argv[1]);
1259 	smbadm_usage(B_FALSE);
1260 	return (2);
1261 }
1262 
1263 static int
1264 smbadm_init(void)
1265 {
1266 	int rc;
1267 
1268 	switch (curcmd->flags & SMBADM_CMDF_TYPEMASK) {
1269 	case SMBADM_CMDF_GROUP:
1270 		if (smb_idmap_start() != 0) {
1271 			(void) fprintf(stderr,
1272 			    gettext("failed to contact idmap service\n"));
1273 			return (1);
1274 		}
1275 
1276 		if ((rc = smb_lgrp_start()) != SMB_LGRP_SUCCESS) {
1277 			(void) fprintf(stderr,
1278 			    gettext("failed to initialize (%s)\n"),
1279 			    smb_lgrp_strerror(rc));
1280 			smb_idmap_stop();
1281 			return (1);
1282 		}
1283 		break;
1284 
1285 	case SMBADM_CMDF_USER:
1286 		smb_pwd_init(B_FALSE);
1287 		break;
1288 
1289 	default:
1290 		break;
1291 	}
1292 
1293 	return (0);
1294 }
1295 
1296 static void
1297 smbadm_fini(void)
1298 {
1299 	switch (curcmd->flags & SMBADM_CMDF_TYPEMASK) {
1300 	case SMBADM_CMDF_GROUP:
1301 		smb_lgrp_stop();
1302 		smb_idmap_stop();
1303 		break;
1304 
1305 	case SMBADM_CMDF_USER:
1306 		smb_pwd_fini();
1307 		break;
1308 
1309 	default:
1310 		break;
1311 	}
1312 }
1313 
1314 static boolean_t
1315 smbadm_prop_validate(smbadm_prop_t *prop, boolean_t chkval)
1316 {
1317 	smbadm_prop_handle_t *pinfo;
1318 	int i;
1319 
1320 	for (i = 0; i < SMBADM_NPROP; i++) {
1321 		pinfo = &smbadm_ptable[i];
1322 		if (strcmp(pinfo->p_name, prop->p_name) == 0) {
1323 			if (pinfo->p_chkfn && chkval)
1324 				return (pinfo->p_chkfn(prop));
1325 
1326 			return (B_TRUE);
1327 		}
1328 	}
1329 
1330 	(void) fprintf(stderr,
1331 	    gettext("unrecognized property '%s'\n"), prop->p_name);
1332 
1333 	return (B_FALSE);
1334 }
1335 
1336 static int
1337 smbadm_prop_parse(char *arg, smbadm_prop_t *prop)
1338 {
1339 	boolean_t parse_value;
1340 	char *equal;
1341 
1342 	if (arg == NULL)
1343 		return (2);
1344 
1345 	prop->p_name = prop->p_value = NULL;
1346 
1347 	if (strcmp(curcmd->name, "set") == 0)
1348 		parse_value = B_TRUE;
1349 	else
1350 		parse_value = B_FALSE;
1351 
1352 	prop->p_name = arg;
1353 
1354 	if (parse_value) {
1355 		equal = strchr(arg, '=');
1356 		if (equal == NULL)
1357 			return (2);
1358 
1359 		*equal++ = '\0';
1360 		prop->p_value = equal;
1361 	}
1362 
1363 	if (smbadm_prop_validate(prop, parse_value) == B_FALSE)
1364 		return (2);
1365 
1366 	return (0);
1367 }
1368 
1369 static smbadm_prop_handle_t *
1370 smbadm_prop_gethandle(char *pname)
1371 {
1372 	int i;
1373 
1374 	for (i = 0; i < SMBADM_NPROP; i++)
1375 		if (strcmp(pname, smbadm_ptable[i].p_name) == 0)
1376 			return (&smbadm_ptable[i]);
1377 
1378 	return (NULL);
1379 }
1380 
1381 static int
1382 smbadm_setprop_desc(char *gname, smbadm_prop_t *prop)
1383 {
1384 	int status;
1385 
1386 	status = smb_lgrp_setcmnt(gname, prop->p_value);
1387 	if (status != SMB_LGRP_SUCCESS) {
1388 		(void) fprintf(stderr,
1389 		    gettext("failed to modify the group description (%s)\n"),
1390 		    smb_lgrp_strerror(status));
1391 		return (1);
1392 	}
1393 
1394 	(void) printf(gettext("Successfully modified "
1395 	    "'%s' description\n"), gname);
1396 
1397 	return (0);
1398 }
1399 
1400 static int
1401 smbadm_getprop_desc(char *gname, smbadm_prop_t *prop)
1402 {
1403 	char *cmnt = NULL;
1404 	int status;
1405 
1406 	status = smb_lgrp_getcmnt(gname, &cmnt);
1407 	if (status != SMB_LGRP_SUCCESS) {
1408 		(void) fprintf(stderr,
1409 		    gettext("failed to get the group description (%s)\n"),
1410 		    smb_lgrp_strerror(status));
1411 		return (1);
1412 	}
1413 
1414 	(void) printf(gettext("\t%s: %s\n"), prop->p_name, cmnt);
1415 	free(cmnt);
1416 	return (0);
1417 }
1418 
1419 static int
1420 smbadm_group_setpriv(char *gname, uint8_t priv_id, smbadm_prop_t *prop)
1421 {
1422 	boolean_t enable;
1423 	int status;
1424 	int ret;
1425 
1426 	if (strcasecmp(prop->p_value, "on") == 0) {
1427 		(void) printf(gettext("Enabling %s privilege "), prop->p_name);
1428 		enable = B_TRUE;
1429 	} else {
1430 		(void) printf(gettext("Disabling %s privilege "), prop->p_name);
1431 		enable = B_FALSE;
1432 	}
1433 
1434 	status = smb_lgrp_setpriv(gname, priv_id, enable);
1435 	if (status == SMB_LGRP_SUCCESS) {
1436 		(void) printf(gettext("succeeded\n"));
1437 		ret = 0;
1438 	} else {
1439 		(void) printf(gettext("failed: %s\n"),
1440 		    smb_lgrp_strerror(status));
1441 		ret = 1;
1442 	}
1443 
1444 	return (ret);
1445 }
1446 
1447 static int
1448 smbadm_group_getpriv(char *gname, uint8_t priv_id, smbadm_prop_t *prop)
1449 {
1450 	boolean_t enable;
1451 	int status;
1452 
1453 	status = smb_lgrp_getpriv(gname, priv_id, &enable);
1454 	if (status != SMB_LGRP_SUCCESS) {
1455 		(void) fprintf(stderr, gettext("failed to get %s (%s)\n"),
1456 		    prop->p_name, smb_lgrp_strerror(status));
1457 		return (1);
1458 	}
1459 
1460 	(void) printf(gettext("\t%s: %s\n"), prop->p_name,
1461 	    (enable) ? "On" : "Off");
1462 
1463 	return (0);
1464 }
1465 
1466 static int
1467 smbadm_setprop_tkowner(char *gname, smbadm_prop_t *prop)
1468 {
1469 	return (smbadm_group_setpriv(gname, SE_TAKE_OWNERSHIP_LUID, prop));
1470 }
1471 
1472 static int
1473 smbadm_getprop_tkowner(char *gname, smbadm_prop_t *prop)
1474 {
1475 	return (smbadm_group_getpriv(gname, SE_TAKE_OWNERSHIP_LUID, prop));
1476 }
1477 
1478 static int
1479 smbadm_setprop_backup(char *gname, smbadm_prop_t *prop)
1480 {
1481 	return (smbadm_group_setpriv(gname, SE_BACKUP_LUID, prop));
1482 }
1483 
1484 static int
1485 smbadm_getprop_backup(char *gname, smbadm_prop_t *prop)
1486 {
1487 	return (smbadm_group_getpriv(gname, SE_BACKUP_LUID, prop));
1488 }
1489 
1490 static int
1491 smbadm_setprop_restore(char *gname, smbadm_prop_t *prop)
1492 {
1493 	return (smbadm_group_setpriv(gname, SE_RESTORE_LUID, prop));
1494 }
1495 
1496 static int
1497 smbadm_getprop_restore(char *gname, smbadm_prop_t *prop)
1498 {
1499 	return (smbadm_group_getpriv(gname, SE_RESTORE_LUID, prop));
1500 }
1501 
1502 static boolean_t
1503 smbadm_chkprop_priv(smbadm_prop_t *prop)
1504 {
1505 	if (prop->p_value == NULL || *prop->p_value == '\0') {
1506 		(void) fprintf(stderr,
1507 		    gettext("missing value for '%s'\n"), prop->p_name);
1508 		return (B_FALSE);
1509 	}
1510 
1511 	if (strcasecmp(prop->p_value, "on") == 0)
1512 		return (B_TRUE);
1513 
1514 	if (strcasecmp(prop->p_value, "off") == 0)
1515 		return (B_TRUE);
1516 
1517 	(void) fprintf(stderr,
1518 	    gettext("%s: unrecognized value for '%s' property\n"),
1519 	    prop->p_value, prop->p_name);
1520 
1521 	return (B_FALSE);
1522 }
1523 
1524 static const char *
1525 smbadm_pwd_strerror(int error)
1526 {
1527 	switch (error) {
1528 	case SMB_PWE_SUCCESS:
1529 		return (gettext("Success."));
1530 
1531 	case SMB_PWE_USER_UNKNOWN:
1532 		return (gettext("User does not exist."));
1533 
1534 	case SMB_PWE_USER_DISABLE:
1535 		return (gettext("User is disable."));
1536 
1537 	case SMB_PWE_CLOSE_FAILED:
1538 	case SMB_PWE_OPEN_FAILED:
1539 	case SMB_PWE_WRITE_FAILED:
1540 	case SMB_PWE_UPDATE_FAILED:
1541 		return (gettext("Unexpected failure. "
1542 		    "SMB password database unchanged."));
1543 
1544 	case SMB_PWE_STAT_FAILED:
1545 		return (gettext("stat of SMB password file failed."));
1546 
1547 	case SMB_PWE_BUSY:
1548 		return (gettext("SMB password database busy. "
1549 		    "Try again later."));
1550 
1551 	case SMB_PWE_DENIED:
1552 		return (gettext("Operation not permitted."));
1553 
1554 	case SMB_PWE_SYSTEM_ERROR:
1555 		return (gettext("System error."));
1556 
1557 	default:
1558 		break;
1559 	}
1560 
1561 	return (gettext("Unknown error code."));
1562 }
1563 
1564 /*
1565  * Enable libumem debugging by default on DEBUG builds.
1566  */
1567 #ifdef DEBUG
1568 const char *
1569 _umem_debug_init(void)
1570 {
1571 	return ("default,verbose"); /* $UMEM_DEBUG setting */
1572 }
1573 
1574 const char *
1575 _umem_logging_init(void)
1576 {
1577 	return ("fail,contents"); /* $UMEM_LOGGING setting */
1578 }
1579 #endif
1580