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