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.
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.
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]
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
27 * This module contains smbadm CLI which offers smb configuration
45 #include <netinet/in.h>
46 #include <auth_attr.h>
48 #include <smbsrv/libsmb.h>
49 #include <smbsrv/libsmbns.h>
51 #if !defined(TEXT_DOMAIN)
52 #define TEXT_DOMAIN "SYS_TEST"
71 #define SMBADM_CMDF_NONE 0x00
72 #define SMBADM_CMDF_USER 0x01
73 #define SMBADM_CMDF_GROUP 0x02
74 #define SMBADM_CMDF_TYPEMASK 0x0F
77 SMBADM_GRP_ADDMEMBER
= 0,
79 } smbadm_grp_action_t
;
81 #define SMBADM_ANSBUFSIZ 64
83 typedef struct smbadm_cmdinfo
{
85 int (*func
)(int, char **);
91 smbadm_cmdinfo_t
*curcmd
;
92 static char *progname
;
94 #define SMBADM_ACTION_AUTH "solaris.smf.manage.smb"
95 #define SMBADM_VALUE_AUTH "solaris.smf.value.smb"
96 #define SMBADM_BASIC_AUTH "solaris.network.hosts.read"
98 static boolean_t
smbadm_checkauth(const char *);
100 static void smbadm_usage(boolean_t
);
101 static int smbadm_join_workgroup(const char *, boolean_t
);
102 static int smbadm_join_domain(const char *, const char *, boolean_t
);
103 static void smbadm_extract_domain(char *, char **, char **);
105 static int smbadm_join(int, char **);
106 static int smbadm_list(int, char **);
107 static int smbadm_lookup(int, char **);
108 static void smbadm_lookup_name(char *);
109 static void smbadm_lookup_sid(char *);
110 static int smbadm_group_create(int, char **);
111 static int smbadm_group_delete(int, char **);
112 static int smbadm_group_rename(int, char **);
113 static int smbadm_group_show(int, char **);
114 static void smbadm_group_show_name(const char *, const char *);
115 static int smbadm_group_getprop(int, char **);
116 static int smbadm_group_setprop(int, char **);
117 static int smbadm_group_addmember(int, char **);
118 static int smbadm_group_delmember(int, char **);
119 static int smbadm_group_add_del_member(char *, char *, smbadm_grp_action_t
);
121 static int smbadm_user_disable(int, char **);
122 static int smbadm_user_enable(int, char **);
124 static smbadm_cmdinfo_t smbadm_cmdtable
[] =
126 { "add-member", smbadm_group_addmember
, HELP_ADD_MEMBER
,
127 SMBADM_CMDF_GROUP
, SMBADM_ACTION_AUTH
},
128 { "create", smbadm_group_create
, HELP_CREATE
,
129 SMBADM_CMDF_GROUP
, SMBADM_ACTION_AUTH
},
130 { "delete", smbadm_group_delete
, HELP_DELETE
,
131 SMBADM_CMDF_GROUP
, SMBADM_ACTION_AUTH
},
132 { "disable-user", smbadm_user_disable
, HELP_USER_DISABLE
,
133 SMBADM_CMDF_USER
, SMBADM_ACTION_AUTH
},
134 { "enable-user", smbadm_user_enable
, HELP_USER_ENABLE
,
135 SMBADM_CMDF_USER
, SMBADM_ACTION_AUTH
},
136 { "get", smbadm_group_getprop
, HELP_GET
,
137 SMBADM_CMDF_GROUP
, SMBADM_ACTION_AUTH
},
138 { "join", smbadm_join
, HELP_JOIN
,
139 SMBADM_CMDF_NONE
, SMBADM_VALUE_AUTH
},
140 { "list", smbadm_list
, HELP_LIST
,
141 SMBADM_CMDF_NONE
, SMBADM_BASIC_AUTH
},
142 { "lookup", smbadm_lookup
, HELP_LOOKUP
,
143 SMBADM_CMDF_NONE
, SMBADM_BASIC_AUTH
},
144 { "remove-member", smbadm_group_delmember
, HELP_DEL_MEMBER
,
145 SMBADM_CMDF_GROUP
, SMBADM_ACTION_AUTH
},
146 { "rename", smbadm_group_rename
, HELP_RENAME
,
147 SMBADM_CMDF_GROUP
, SMBADM_ACTION_AUTH
},
148 { "set", smbadm_group_setprop
, HELP_SET
,
149 SMBADM_CMDF_GROUP
, SMBADM_ACTION_AUTH
},
150 { "show", smbadm_group_show
, HELP_SHOW
,
151 SMBADM_CMDF_GROUP
, SMBADM_ACTION_AUTH
},
154 #define SMBADM_NCMD (sizeof (smbadm_cmdtable) / sizeof (smbadm_cmdtable[0]))
156 typedef struct smbadm_prop
{
161 typedef struct smbadm_prop_handle
{
164 int (*p_setfn
)(char *, smbadm_prop_t
*);
165 int (*p_getfn
)(char *, smbadm_prop_t
*);
166 boolean_t (*p_chkfn
)(smbadm_prop_t
*);
167 } smbadm_prop_handle_t
;
169 static boolean_t
smbadm_prop_validate(smbadm_prop_t
*prop
, boolean_t chkval
);
170 static int smbadm_prop_parse(char *arg
, smbadm_prop_t
*prop
);
171 static smbadm_prop_handle_t
*smbadm_prop_gethandle(char *pname
);
173 static boolean_t
smbadm_chkprop_priv(smbadm_prop_t
*prop
);
174 static int smbadm_setprop_tkowner(char *gname
, smbadm_prop_t
*prop
);
175 static int smbadm_getprop_tkowner(char *gname
, smbadm_prop_t
*prop
);
176 static int smbadm_setprop_backup(char *gname
, smbadm_prop_t
*prop
);
177 static int smbadm_getprop_backup(char *gname
, smbadm_prop_t
*prop
);
178 static int smbadm_setprop_restore(char *gname
, smbadm_prop_t
*prop
);
179 static int smbadm_getprop_restore(char *gname
, smbadm_prop_t
*prop
);
180 static int smbadm_setprop_desc(char *gname
, smbadm_prop_t
*prop
);
181 static int smbadm_getprop_desc(char *gname
, smbadm_prop_t
*prop
);
183 static smbadm_prop_handle_t smbadm_ptable
[] = {
184 {"backup", "on | off", smbadm_setprop_backup
,
185 smbadm_getprop_backup
, smbadm_chkprop_priv
},
186 {"restore", "on | off", smbadm_setprop_restore
,
187 smbadm_getprop_restore
, smbadm_chkprop_priv
},
188 {"take-ownership", "on | off", smbadm_setprop_tkowner
,
189 smbadm_getprop_tkowner
, smbadm_chkprop_priv
},
190 {"description", "<string>", smbadm_setprop_desc
,
191 smbadm_getprop_desc
, NULL
},
194 static int smbadm_init(void);
195 static void smbadm_fini(void);
196 static const char *smbadm_pwd_strerror(int error
);
199 * Number of supported properties
201 #define SMBADM_NPROP (sizeof (smbadm_ptable) / sizeof (smbadm_ptable[0]))
204 smbadm_cmdusage(FILE *fp
, smbadm_cmdinfo_t
*cmd
)
206 switch (cmd
->usage
) {
207 case HELP_ADD_MEMBER
:
209 gettext("\t%s -m member [[-m member] ...] group\n"),
214 (void) fprintf(fp
, gettext("\t%s [-d description] group\n"),
219 (void) fprintf(fp
, gettext("\t%s group\n"), cmd
->name
);
222 case HELP_USER_DISABLE
:
223 case HELP_USER_ENABLE
:
224 (void) fprintf(fp
, gettext("\t%s user\n"), cmd
->name
);
228 (void) fprintf(fp
, gettext("\t%s [[-p property] ...] group\n"),
233 #if 0 /* Don't document "-p" yet, still needs work (NX 11960) */
234 (void) fprintf(fp
, gettext("\t%s [-y] -p domain\n"
235 "\t%s [-y] -u username domain\n\t%s [-y] -w workgroup\n"),
236 cmd
->name
, cmd
->name
, cmd
->name
);
238 (void) fprintf(fp
, gettext("\t%s [-y] -u username domain\n"
239 "\t%s [-y] -w workgroup\n"), cmd
->name
, cmd
->name
);
244 (void) fprintf(fp
, gettext("\t%s\n"), cmd
->name
);
246 gettext("\t\t[*] primary domain\n"));
247 (void) fprintf(fp
, gettext("\t\t[.] local domain\n"));
248 (void) fprintf(fp
, gettext("\t\t[-] other domains\n"));
250 gettext("\t\t[+] selected domain controller\n"));
255 gettext("\t%s user-or-group-name\n"),
259 case HELP_DEL_MEMBER
:
261 gettext("\t%s -m member [[-m member] ...] group\n"),
266 (void) fprintf(fp
, gettext("\t%s group new-group\n"),
271 (void) fprintf(fp
, gettext("\t%s -p property=value "
272 "[[-p property=value] ...] group\n"), cmd
->name
);
276 (void) fprintf(fp
, gettext("\t%s [-m] [-p] [group]\n"),
289 smbadm_usage(boolean_t requested
)
291 FILE *fp
= requested
? stdout
: stderr
;
292 boolean_t show_props
= B_FALSE
;
295 if (curcmd
== NULL
) {
297 gettext("usage: %s [-h | <command> [options]]\n"),
300 gettext("where 'command' is one of the following:\n\n"));
302 for (i
= 0; i
< SMBADM_NCMD
; i
++)
303 smbadm_cmdusage(fp
, &smbadm_cmdtable
[i
]);
306 gettext("\nFor property list, run %s %s|%s\n"),
307 progname
, "get", "set");
309 exit(requested
? 0 : 2);
312 (void) fprintf(fp
, gettext("usage:\n"));
313 smbadm_cmdusage(fp
, curcmd
);
315 if (strcmp(curcmd
->name
, "get") == 0 ||
316 strcmp(curcmd
->name
, "set") == 0)
321 gettext("\nThe following properties are supported:\n"));
323 (void) fprintf(fp
, "\n\t%-16s %s\n\n",
324 "PROPERTY", "VALUES");
326 for (i
= 0; i
< SMBADM_NPROP
; i
++) {
327 (void) fprintf(fp
, "\t%-16s %s\n",
328 smbadm_ptable
[i
].p_name
,
329 smbadm_ptable
[i
].p_dispvalue
);
333 exit(requested
? 0 : 2);
337 * smbadm_strcasecmplist
339 * Find a string 's' within a list of strings.
341 * Returns the index of the matching string or -1 if there is no match.
344 smbadm_strcasecmplist(const char *s
, ...)
352 for (ndx
= 0; ((p
= va_arg(ap
, char *)) != NULL
); ++ndx
) {
353 if (strcasecmp(s
, p
) == 0) {
364 * smbadm_answer_prompt
366 * Prompt for the answer to a question. A default response must be
367 * specified, which will be used if the user presses <enter> without
368 * answering the question.
371 smbadm_answer_prompt(const char *prompt
, char *answer
, const char *dflt
)
373 char buf
[SMBADM_ANSBUFSIZ
];
376 (void) printf(gettext("%s [%s]: "), prompt
, dflt
);
378 if (fgets(buf
, SMBADM_ANSBUFSIZ
, stdin
) == NULL
)
381 if ((p
= strchr(buf
, '\n')) != NULL
)
385 (void) strlcpy(answer
, dflt
, SMBADM_ANSBUFSIZ
);
387 (void) strlcpy(answer
, buf
, SMBADM_ANSBUFSIZ
);
395 * Ask a question that requires a yes/no answer.
396 * A default response must be specified.
399 smbadm_confirm(const char *prompt
, const char *dflt
)
401 char buf
[SMBADM_ANSBUFSIZ
];
404 if (smbadm_answer_prompt(prompt
, buf
, dflt
) < 0)
407 if (smbadm_strcasecmplist(buf
, "n", "no", 0) >= 0)
410 if (smbadm_strcasecmplist(buf
, "y", "yes", 0) >= 0)
413 (void) printf(gettext("Please answer yes or no.\n"));
418 smbadm_join_prompt(const char *domain
)
420 (void) printf(gettext("After joining %s the smb service will be "
421 "restarted automatically.\n"), domain
);
423 return (smbadm_confirm("Would you like to continue?", "no"));
427 smbadm_restart_service(void)
429 if (smb_smf_restart_service() != 0) {
430 (void) fprintf(stderr
,
431 gettext("Unable to restart smb service. "
432 "Run 'svcs -xv smb/server' for more information."));
439 * Join a domain or workgroup.
441 * When joining a domain, we may receive the username, password and
442 * domain name in any of the following combinations. Note that the
443 * password is optional on the command line: if it is not provided,
444 * we will prompt for it later.
446 * username+password domain
447 * domain\username+password
448 * domain/username+password
451 * We allow domain\name+password or domain/name+password but not
452 * name+password@domain because @ is a valid password character.
454 * If the username and domain name are passed as separate command
455 * line arguments, we process them directly. Otherwise we separate
456 * them and continue as if they were separate command line arguments.
459 smbadm_join(int argc
, char **argv
)
461 char buf
[MAXHOSTNAMELEN
* 2];
463 char *username
= NULL
;
465 boolean_t do_prompt
= B_TRUE
;
468 while ((option
= getopt(argc
, argv
, "pu:wy")) != -1) {
470 (void) fprintf(stderr
, gettext(
471 "join options are mutually exclusive\n"));
472 smbadm_usage(B_FALSE
);
476 mode
= SMB_SECMODE_DOMAIN
;
477 /* leave username = NULL */
481 mode
= SMB_SECMODE_DOMAIN
;
486 mode
= SMB_SECMODE_WORKGRP
;
494 smbadm_usage(B_FALSE
);
500 domain
= argv
[optind
];
502 if (username
!= NULL
&& domain
== NULL
) {
504 * The domain was not specified as a separate
505 * argument, check for the combination forms.
507 (void) strlcpy(buf
, username
, sizeof (buf
));
508 smbadm_extract_domain(buf
, &username
, &domain
);
511 if ((domain
== NULL
) || (*domain
== '\0')) {
512 (void) fprintf(stderr
, gettext("missing %s name\n"),
513 (mode
== SMB_SECMODE_WORKGRP
) ? "workgroup" : "domain");
514 smbadm_usage(B_FALSE
);
517 if (mode
== SMB_SECMODE_WORKGRP
) {
518 return (smbadm_join_workgroup(domain
, do_prompt
));
520 return (smbadm_join_domain(domain
, username
, do_prompt
));
524 * Workgroups comprise a collection of standalone, independently administered
525 * computers that use a common workgroup name. This is a peer-to-peer model
526 * with no formal membership mechanism.
529 smbadm_join_workgroup(const char *workgroup
, boolean_t prompt
)
535 bzero(&jdres
, sizeof (jdres
));
536 bzero(&jdi
, sizeof (jdi
));
537 jdi
.mode
= SMB_SECMODE_WORKGRP
;
538 (void) strlcpy(jdi
.domain_name
, workgroup
, sizeof (jdi
.domain_name
));
539 (void) strtrim(jdi
.domain_name
, " \t\n");
541 if (smb_name_validate_workgroup(jdi
.domain_name
) != ERROR_SUCCESS
) {
542 (void) fprintf(stderr
, gettext("workgroup name is invalid\n"));
543 smbadm_usage(B_FALSE
);
546 if (prompt
&& !smbadm_join_prompt(jdi
.domain_name
))
549 if ((status
= smb_join(&jdi
, &jdres
)) != NT_STATUS_SUCCESS
) {
550 (void) fprintf(stderr
, gettext("failed to join %s: %s\n"),
551 jdi
.domain_name
, xlate_nt_status(status
));
555 (void) printf(gettext("Successfully joined %s\n"), jdi
.domain_name
);
556 smbadm_restart_service();
561 * Domains comprise a centrally administered group of computers and accounts
562 * that share a common security and administration policy and database.
563 * Computers must join a domain and become domain members, which requires
564 * an administrator level account name.
566 * The '+' character is invalid within a username. We allow the password
567 * to be appended to the username using '+' as a scripting convenience.
570 smbadm_join_domain(const char *domain
, const char *username
, boolean_t prompt
)
578 bzero(&jdres
, sizeof (jdres
));
579 bzero(&jdi
, sizeof (jdi
));
580 jdi
.mode
= SMB_SECMODE_DOMAIN
;
581 (void) strlcpy(jdi
.domain_name
, domain
, sizeof (jdi
.domain_name
));
582 (void) strtrim(jdi
.domain_name
, " \t\n");
584 if (smb_name_validate_domain(jdi
.domain_name
) != ERROR_SUCCESS
) {
585 (void) fprintf(stderr
, gettext("domain name is invalid\n"));
586 smbadm_usage(B_FALSE
);
589 if (prompt
&& !smbadm_join_prompt(jdi
.domain_name
))
593 * Note: username is null for "unsecure join"
594 * (join using a pre-created computer account)
595 * No password either.
597 if (username
!= NULL
) {
598 if ((p
= strchr(username
, '+')) != NULL
) {
601 len
= (int)(p
- username
);
602 if (len
> sizeof (jdi
.domain_name
))
603 len
= sizeof (jdi
.domain_name
);
605 (void) strlcpy(jdi
.domain_username
, username
, len
);
606 (void) strlcpy(jdi
.domain_passwd
, p
,
607 sizeof (jdi
.domain_passwd
));
609 (void) strlcpy(jdi
.domain_username
, username
,
610 sizeof (jdi
.domain_username
));
613 if (smb_name_validate_account(jdi
.domain_username
)
615 (void) fprintf(stderr
,
616 gettext("username contains invalid characters\n"));
617 smbadm_usage(B_FALSE
);
620 if (*jdi
.domain_passwd
== '\0') {
621 passwd_prompt
= gettext("Enter domain password: ");
623 if ((p
= getpassphrase(passwd_prompt
)) == NULL
) {
624 (void) fprintf(stderr
, gettext(
625 "missing password\n"));
626 smbadm_usage(B_FALSE
);
629 (void) strlcpy(jdi
.domain_passwd
, p
,
630 sizeof (jdi
.domain_passwd
));
634 (void) printf(gettext("Joining %s ... this may take a minute ...\n"),
637 rc
= smb_join(&jdi
, &jdres
);
639 (void) printf(gettext("Cannot call the SMB service. "
641 "Please check the service status "
642 "(svcs -vx network/smb/server)\n"),
644 bzero(&jdi
, sizeof (jdi
));
648 switch (jdres
.status
) {
649 case NT_STATUS_SUCCESS
:
650 (void) printf(gettext(
651 "Successfully joined domain %s using AD server %s\n"),
652 jdi
.domain_name
, jdres
.dc_name
);
653 bzero(&jdi
, sizeof (jdi
));
654 smbadm_restart_service();
657 case NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND
:
658 /* See: smb_ads_lookup_msdcs */
659 (void) fprintf(stderr
, gettext(
660 "failed to find any AD servers for domain: %s\n"),
664 case NT_STATUS_BAD_NETWORK_PATH
:
665 /* See: smbrdr_ctx_new / smb_ctx_resolve */
666 (void) fprintf(stderr
, gettext(
667 "failed to resolve address of AD server: %s\n"),
671 case NT_STATUS_NETWORK_ACCESS_DENIED
:
672 /* See: smbrdr_ctx_new / smb_ctx_get_ssn */
673 (void) fprintf(stderr
, gettext(
674 "failed to authenticate with AD server: %s\n"),
678 case NT_STATUS_BAD_NETWORK_NAME
:
680 * See: smbrdr_ctx_new / smb_ctx_get_tree
681 * and: ndr_rpc_bind / smb_fh_open
683 (void) fprintf(stderr
, gettext(
684 "failed connecting to services on AD server: %s\n"),
689 (void) fprintf(stderr
, gettext(
690 "failed to join domain %s\n"),
692 if (jdres
.dc_name
[0] != '\0') {
693 (void) fprintf(stderr
, gettext(
694 "using AD server: %s\n"),
699 if (jdres
.join_err
!= 0) {
700 (void) fprintf(stderr
, "%s\n",
701 smb_ads_strerror(jdres
.join_err
));
702 } else if (jdres
.status
!= 0) {
703 (void) fprintf(stderr
, "(%s)\n",
704 xlate_nt_status(jdres
.status
));
706 (void) fprintf(stderr
, gettext("Please refer to the "
707 "service log for more information.\n"));
708 bzero(&jdi
, sizeof (jdi
));
714 * We want to process the user and domain names as separate strings.
715 * Check for names of the forms below and separate the components as
722 * If we encounter any of the forms above in arg, the @, / or \
723 * separator is replaced by \0 and the username and domain pointers
724 * are changed to point to the appropriate components (in arg).
726 * If none of the separators are encountered, the username and domain
727 * pointers remain unchanged.
730 smbadm_extract_domain(char *arg
, char **username
, char **domain
)
734 if ((p
= strpbrk(arg
, "/\\@")) != NULL
) {
739 if (strchr(arg
, '+') != NULL
)
756 * Displays current security mode and domain/workgroup name.
760 smbadm_list(int argc
, char **argv
)
762 char domain
[MAXHOSTNAMELEN
];
763 char fqdn
[MAXHOSTNAMELEN
];
764 char srvname
[MAXHOSTNAMELEN
];
767 smb_inaddr_t srvipaddr
;
768 char ipstr
[INET6_ADDRSTRLEN
];
770 rc
= smb_config_getstr(SMB_CI_SECURITY
, modename
, sizeof (modename
));
771 if (rc
!= SMBD_SMF_OK
) {
772 (void) fprintf(stderr
,
773 gettext("cannot determine the operational mode\n"));
777 if (smb_getdomainname(domain
, sizeof (domain
)) != 0) {
778 (void) fprintf(stderr
, gettext("failed to get the %s name\n"),
783 if (strcmp(modename
, "workgroup") == 0) {
784 (void) printf(gettext("[*] [%s]\n"), domain
);
788 (void) printf(gettext("[*] [%s]\n"), domain
);
789 if ((smb_getfqdomainname(fqdn
, sizeof (fqdn
)) == 0) && (*fqdn
!= '\0'))
790 (void) printf(gettext("[*] [%s]\n"), fqdn
);
792 if ((smb_get_dcinfo(srvname
, MAXHOSTNAMELEN
, &srvipaddr
)
793 == NT_STATUS_SUCCESS
) && (*srvname
!= '\0') &&
794 (!smb_inet_iszero(&srvipaddr
))) {
795 (void) smb_inet_ntop(&srvipaddr
, ipstr
,
796 SMB_IPSTRLEN(srvipaddr
.a_family
));
797 (void) printf(gettext("\t[+%s] [%s]\n"),
801 /* Print the local and domain SID. */
809 * Lookup the SID for a given account (user or group)
812 smbadm_lookup(int argc
, char **argv
)
817 (void) fprintf(stderr
, gettext("missing account name\n"));
818 smbadm_usage(B_FALSE
);
821 for (i
= 1; i
< argc
; i
++) {
822 if (strncmp(argv
[i
], "S-1-", 4) == 0)
823 smbadm_lookup_sid(argv
[i
]);
825 smbadm_lookup_name(argv
[i
]);
831 smbadm_lookup_name(char *name
)
836 if ((rc
= smb_lookup_name(name
, SidTypeUnknown
, &acct
)) != 0) {
837 (void) fprintf(stderr
, gettext(
838 "\t\t%s: lookup name failed, rc=%d\n"),
842 if (acct
.a_status
!= NT_STATUS_SUCCESS
) {
843 (void) fprintf(stderr
, gettext("\t\t%s [%s]\n"),
844 name
, xlate_nt_status(acct
.a_status
));
847 (void) printf("\t%s\n", acct
.a_sid
);
851 smbadm_lookup_sid(char *sidstr
)
856 if ((rc
= smb_lookup_sid(sidstr
, &acct
)) != 0) {
857 (void) fprintf(stderr
, gettext(
858 "\t\t%s: lookup SID failed, rc=%d\n"),
862 if (acct
.a_status
!= NT_STATUS_SUCCESS
) {
863 (void) fprintf(stderr
, gettext("\t\t%s [%s]\n"),
864 sidstr
, xlate_nt_status(acct
.a_status
));
867 (void) printf("\t%s\\%s\n", acct
.a_domain
, acct
.a_name
);
871 * smbadm_group_create
873 * Creates a local SMB group
876 smbadm_group_create(int argc
, char **argv
)
883 while ((option
= getopt(argc
, argv
, "d:")) != -1) {
890 smbadm_usage(B_FALSE
);
894 gname
= argv
[optind
];
895 if (optind
>= argc
|| gname
== NULL
|| *gname
== '\0') {
896 (void) fprintf(stderr
, gettext("missing group name\n"));
897 smbadm_usage(B_FALSE
);
900 status
= smb_lgrp_add(gname
, desc
);
901 if (status
!= SMB_LGRP_SUCCESS
) {
902 (void) fprintf(stderr
,
903 gettext("failed to create %s (%s)\n"), gname
,
904 smb_lgrp_strerror(status
));
906 (void) printf(gettext("%s created\n"), gname
);
913 * smbadm_group_dump_members
915 * Dump group members details.
918 smbadm_group_dump_members(smb_gsid_t
*members
, int num
)
920 char sidstr
[SMB_SID_STRSZ
];
925 (void) printf(gettext("\tNo members\n"));
929 (void) printf(gettext("\tMembers:\n"));
930 for (i
= 0; i
< num
; i
++) {
931 smb_sid_tostr(members
[i
].gs_sid
, sidstr
);
933 if (smb_lookup_sid(sidstr
, &acct
) == 0) {
934 if (acct
.a_status
== NT_STATUS_SUCCESS
)
935 smbadm_group_show_name(acct
.a_domain
,
938 (void) printf(gettext("\t\t%s [%s]\n"),
939 sidstr
, xlate_nt_status(acct
.a_status
));
941 (void) printf(gettext("\t\t%s\n"), sidstr
);
947 smbadm_group_show_name(const char *domain
, const char *name
)
949 if (strchr(domain
, '.') != NULL
)
950 (void) printf("\t\t%s@%s\n", name
, domain
);
952 (void) printf("\t\t%s\\%s\n", domain
, name
);
956 * smbadm_group_dump_privs
958 * Dump group privilege details.
961 smbadm_group_dump_privs(smb_privset_t
*privs
)
963 smb_privinfo_t
*pinfo
;
967 (void) printf(gettext("\tPrivileges: \n"));
969 for (i
= 0; i
< privs
->priv_cnt
; i
++) {
970 pinfo
= smb_priv_getbyvalue(privs
->priv
[i
].luid
.lo_part
);
971 if ((pinfo
== NULL
) || (pinfo
->flags
& PF_PRESENTABLE
) == 0)
974 switch (privs
->priv
[i
].attrs
) {
975 case SE_PRIVILEGE_ENABLED
:
978 case SE_PRIVILEGE_DISABLED
:
985 (void) printf(gettext("\t\t%s: %s\n"), pinfo
->name
, pstatus
);
988 if (privs
->priv_cnt
== 0)
989 (void) printf(gettext("\t\tNo privileges\n"));
995 * Dump group details.
998 smbadm_group_dump(smb_group_t
*grp
, boolean_t show_mem
, boolean_t show_privs
)
1000 char sidstr
[SMB_SID_STRSZ
];
1002 (void) printf(gettext("%s (%s)\n"), grp
->sg_name
, grp
->sg_cmnt
);
1004 smb_sid_tostr(grp
->sg_id
.gs_sid
, sidstr
);
1005 (void) printf(gettext("\tSID: %s\n"), sidstr
);
1008 smbadm_group_dump_privs(grp
->sg_privs
);
1011 smbadm_group_dump_members(grp
->sg_members
, grp
->sg_nmembers
);
1019 smbadm_group_show(int argc
, char **argv
)
1022 boolean_t show_privs
;
1023 boolean_t show_members
;
1029 show_privs
= show_members
= B_FALSE
;
1031 while ((option
= getopt(argc
, argv
, "mp")) != -1) {
1034 show_members
= B_TRUE
;
1037 show_privs
= B_TRUE
;
1041 smbadm_usage(B_FALSE
);
1045 gname
= argv
[optind
];
1046 if (optind
>= argc
|| gname
== NULL
|| *gname
== '\0')
1049 if (strcmp(gname
, "*")) {
1050 status
= smb_lgrp_getbyname(gname
, &grp
);
1051 if (status
== SMB_LGRP_SUCCESS
) {
1052 smbadm_group_dump(&grp
, show_members
, show_privs
);
1053 smb_lgrp_free(&grp
);
1055 (void) fprintf(stderr
,
1056 gettext("failed to find %s (%s)\n"),
1057 gname
, smb_lgrp_strerror(status
));
1062 if ((status
= smb_lgrp_iteropen(&gi
)) != SMB_LGRP_SUCCESS
) {
1063 (void) fprintf(stderr
, gettext("failed to list groups (%s)\n"),
1064 smb_lgrp_strerror(status
));
1068 while ((status
= smb_lgrp_iterate(&gi
, &grp
)) == SMB_LGRP_SUCCESS
) {
1069 smbadm_group_dump(&grp
, show_members
, show_privs
);
1070 smb_lgrp_free(&grp
);
1073 smb_lgrp_iterclose(&gi
);
1075 if ((status
!= SMB_LGRP_NO_MORE
) || smb_lgrp_itererror(&gi
)) {
1076 if (status
!= SMB_LGRP_NO_MORE
)
1077 smb_syslog(LOG_ERR
, "smb_lgrp_iterate: %s",
1078 smb_lgrp_strerror(status
));
1080 (void) fprintf(stderr
,
1081 gettext("\nAn error occurred while retrieving group data.\n"
1082 "Check the system log for more information.\n"));
1090 * smbadm_group_delete
1093 smbadm_group_delete(int argc
, char **argv
)
1098 gname
= argv
[optind
];
1099 if (optind
>= argc
|| gname
== NULL
|| *gname
== '\0') {
1100 (void) fprintf(stderr
, gettext("missing group name\n"));
1101 smbadm_usage(B_FALSE
);
1104 status
= smb_lgrp_delete(gname
);
1105 if (status
!= SMB_LGRP_SUCCESS
) {
1106 (void) fprintf(stderr
,
1107 gettext("failed to delete %s (%s)\n"), gname
,
1108 smb_lgrp_strerror(status
));
1110 (void) printf(gettext("%s deleted\n"), gname
);
1117 * smbadm_group_rename
1120 smbadm_group_rename(int argc
, char **argv
)
1123 char *ngname
= NULL
;
1126 gname
= argv
[optind
];
1127 if (optind
++ >= argc
|| gname
== NULL
|| *gname
== '\0') {
1128 (void) fprintf(stderr
, gettext("missing group name\n"));
1129 smbadm_usage(B_FALSE
);
1132 ngname
= argv
[optind
];
1133 if (optind
>= argc
|| ngname
== NULL
|| *ngname
== '\0') {
1134 (void) fprintf(stderr
, gettext("missing new group name\n"));
1135 smbadm_usage(B_FALSE
);
1138 status
= smb_lgrp_rename(gname
, ngname
);
1139 if (status
!= SMB_LGRP_SUCCESS
) {
1140 if (status
== SMB_LGRP_EXISTS
)
1141 (void) fprintf(stderr
,
1142 gettext("failed to rename '%s' (%s already "
1143 "exists)\n"), gname
, ngname
);
1145 (void) fprintf(stderr
,
1146 gettext("failed to rename '%s' (%s)\n"), gname
,
1147 smb_lgrp_strerror(status
));
1149 (void) printf(gettext("'%s' renamed to '%s'\n"), gname
, ngname
);
1156 * smbadm_group_setprop
1158 * Set the group properties.
1161 smbadm_group_setprop(int argc
, char **argv
)
1164 smbadm_prop_t props
[SMBADM_NPROP
];
1165 smbadm_prop_handle_t
*phandle
;
1171 bzero(props
, SMBADM_NPROP
* sizeof (smbadm_prop_t
));
1173 while ((option
= getopt(argc
, argv
, "p:")) != -1) {
1176 if (pcnt
>= SMBADM_NPROP
) {
1177 (void) fprintf(stderr
,
1178 gettext("exceeded number of supported"
1180 smbadm_usage(B_FALSE
);
1183 if (smbadm_prop_parse(optarg
, &props
[pcnt
++]) != 0)
1184 smbadm_usage(B_FALSE
);
1188 smbadm_usage(B_FALSE
);
1193 (void) fprintf(stderr
,
1194 gettext("missing property=value argument\n"));
1195 smbadm_usage(B_FALSE
);
1198 gname
= argv
[optind
];
1199 if (optind
>= argc
|| gname
== NULL
|| *gname
== '\0') {
1200 (void) fprintf(stderr
, gettext("missing group name\n"));
1201 smbadm_usage(B_FALSE
);
1204 for (p
= 0; p
< pcnt
; p
++) {
1205 phandle
= smbadm_prop_gethandle(props
[p
].p_name
);
1207 if (phandle
->p_setfn(gname
, &props
[p
]) != 0)
1216 * smbadm_group_getprop
1218 * Get the group properties.
1221 smbadm_group_getprop(int argc
, char **argv
)
1224 smbadm_prop_t props
[SMBADM_NPROP
];
1225 smbadm_prop_handle_t
*phandle
;
1231 bzero(props
, SMBADM_NPROP
* sizeof (smbadm_prop_t
));
1233 while ((option
= getopt(argc
, argv
, "p:")) != -1) {
1236 if (pcnt
>= SMBADM_NPROP
) {
1237 (void) fprintf(stderr
,
1238 gettext("exceeded number of supported"
1240 smbadm_usage(B_FALSE
);
1243 if (smbadm_prop_parse(optarg
, &props
[pcnt
++]) != 0)
1244 smbadm_usage(B_FALSE
);
1248 smbadm_usage(B_FALSE
);
1252 gname
= argv
[optind
];
1253 if (optind
>= argc
|| gname
== NULL
|| *gname
== '\0') {
1254 (void) fprintf(stderr
, gettext("missing group name\n"));
1255 smbadm_usage(B_FALSE
);
1260 * If no property has be specified then get
1261 * all the properties.
1263 pcnt
= SMBADM_NPROP
;
1264 for (p
= 0; p
< pcnt
; p
++)
1265 props
[p
].p_name
= smbadm_ptable
[p
].p_name
;
1268 for (p
= 0; p
< pcnt
; p
++) {
1269 phandle
= smbadm_prop_gethandle(props
[p
].p_name
);
1271 if (phandle
->p_getfn(gname
, &props
[p
]) != 0)
1280 * smbadm_group_addmember
1284 smbadm_group_addmember(int argc
, char **argv
)
1294 mname
= (char **)malloc(argc
* sizeof (char *));
1295 if (mname
== NULL
) {
1296 warn(gettext("failed to add group member"));
1299 bzero(mname
, argc
* sizeof (char *));
1301 while ((option
= getopt(argc
, argv
, "m:")) != -1) {
1304 mname
[mcnt
++] = optarg
;
1309 smbadm_usage(B_FALSE
);
1314 (void) fprintf(stderr
, gettext("missing member name\n"));
1316 smbadm_usage(B_FALSE
);
1319 gname
= argv
[optind
];
1320 if (optind
>= argc
|| gname
== NULL
|| *gname
== 0) {
1321 (void) fprintf(stderr
, gettext("missing group name\n"));
1323 smbadm_usage(B_FALSE
);
1326 for (i
= 0; i
< mcnt
; i
++) {
1327 if (mname
[i
] == NULL
)
1329 ret
|= smbadm_group_add_del_member(
1330 gname
, mname
[i
], SMBADM_GRP_ADDMEMBER
);
1338 * smbadm_group_delmember
1341 smbadm_group_delmember(int argc
, char **argv
)
1350 mname
= (char **)malloc(argc
* sizeof (char *));
1351 if (mname
== NULL
) {
1352 warn(gettext("failed to delete group member"));
1355 bzero(mname
, argc
* sizeof (char *));
1357 while ((option
= getopt(argc
, argv
, "m:")) != -1) {
1360 mname
[mcnt
++] = optarg
;
1365 smbadm_usage(B_FALSE
);
1370 (void) fprintf(stderr
, gettext("missing member name\n"));
1372 smbadm_usage(B_FALSE
);
1375 gname
= argv
[optind
];
1376 if (optind
>= argc
|| gname
== NULL
|| *gname
== 0) {
1377 (void) fprintf(stderr
, gettext("missing group name\n"));
1379 smbadm_usage(B_FALSE
);
1383 for (i
= 0; i
< mcnt
; i
++) {
1385 if (mname
[i
] == NULL
)
1387 ret
|= smbadm_group_add_del_member(
1388 gname
, mname
[i
], SMBADM_GRP_DELMEMBER
);
1396 smbadm_group_add_del_member(char *gname
, char *mname
,
1397 smbadm_grp_action_t act
)
1405 if (strncmp(mname
, "S-1-", 4) == 0) {
1407 * We are given a SID. Just use it.
1409 * We'e like the real account type if we can get it,
1410 * but don't want to error out if we can't get it.
1413 rc
= smb_lookup_sid(sidstr
, &acct
);
1414 if ((rc
!= 0) || (acct
.a_status
!= NT_STATUS_SUCCESS
))
1415 acct
.a_sidtype
= SidTypeUnknown
;
1417 rc
= smb_lookup_name(mname
, SidTypeUnknown
, &acct
);
1418 if ((rc
!= 0) || (acct
.a_status
!= NT_STATUS_SUCCESS
)) {
1419 (void) fprintf(stderr
,
1420 gettext("%s: name lookup failed\n"), mname
);
1423 sidstr
= acct
.a_sid
;
1426 msid
.gs_type
= acct
.a_sidtype
;
1427 if ((msid
.gs_sid
= smb_sid_fromstr(sidstr
)) == NULL
) {
1428 (void) fprintf(stderr
,
1429 gettext("%s: no memory for SID\n"), sidstr
);
1434 case SMBADM_GRP_ADDMEMBER
:
1435 act_str
= gettext("add");
1436 rc
= smb_lgrp_add_member(gname
,
1437 msid
.gs_sid
, msid
.gs_type
);
1439 case SMBADM_GRP_DELMEMBER
:
1440 act_str
= gettext("remove");
1441 rc
= smb_lgrp_del_member(gname
,
1442 msid
.gs_sid
, msid
.gs_type
);
1445 rc
= SMB_LGRP_INTERNAL_ERROR
;
1449 smb_sid_free(msid
.gs_sid
);
1451 if (rc
!= SMB_LGRP_SUCCESS
) {
1452 (void) fprintf(stderr
,
1453 gettext("failed to %s %s (%s)\n"),
1454 act_str
, mname
, smb_lgrp_strerror(rc
));
1461 smbadm_user_disable(int argc
, char **argv
)
1466 user
= argv
[optind
];
1467 if (optind
>= argc
|| user
== NULL
|| *user
== '\0') {
1468 (void) fprintf(stderr
, gettext("missing user name\n"));
1469 smbadm_usage(B_FALSE
);
1472 error
= smb_pwd_setcntl(user
, SMB_PWC_DISABLE
);
1473 if (error
== SMB_PWE_SUCCESS
)
1474 (void) printf(gettext("%s is disabled.\n"), user
);
1476 (void) fprintf(stderr
, "%s\n", smbadm_pwd_strerror(error
));
1482 smbadm_user_enable(int argc
, char **argv
)
1487 user
= argv
[optind
];
1488 if (optind
>= argc
|| user
== NULL
|| *user
== '\0') {
1489 (void) fprintf(stderr
, gettext("missing user name\n"));
1490 smbadm_usage(B_FALSE
);
1493 error
= smb_pwd_setcntl(user
, SMB_PWC_ENABLE
);
1494 if (error
== SMB_PWE_SUCCESS
)
1495 (void) printf(gettext("%s is enabled.\n"), user
);
1497 (void) fprintf(stderr
, "%s\n", smbadm_pwd_strerror(error
));
1504 main(int argc
, char **argv
)
1509 (void) setlocale(LC_ALL
, "");
1510 (void) textdomain(TEXT_DOMAIN
);
1512 (void) malloc(0); /* satisfy libumem dependency */
1514 progname
= basename(argv
[0]);
1517 (void) fprintf(stderr
, gettext("missing command\n"));
1518 smbadm_usage(B_FALSE
);
1522 * Special case "cmd --help/-?"
1524 if (strcmp(argv
[1], "-?") == 0 ||
1525 strcmp(argv
[1], "--help") == 0 ||
1526 strcmp(argv
[1], "-h") == 0)
1527 smbadm_usage(B_TRUE
);
1529 for (i
= 0; i
< SMBADM_NCMD
; ++i
) {
1530 curcmd
= &smbadm_cmdtable
[i
];
1531 if (strcasecmp(argv
[1], curcmd
->name
) == 0) {
1533 /* cmd subcmd --help/-? */
1534 if (strcmp(argv
[2], "-?") == 0 ||
1535 strcmp(argv
[2], "--help") == 0 ||
1536 strcmp(argv
[2], "-h") == 0)
1537 smbadm_usage(B_TRUE
);
1540 if (!smbadm_checkauth(curcmd
->auth
)) {
1541 (void) fprintf(stderr
,
1542 gettext("%s: %s: authorization denied\n"),
1543 progname
, curcmd
->name
);
1547 if ((ret
= smbadm_init()) != 0)
1550 ret
= curcmd
->func(argc
- 1, &argv
[1]);
1558 (void) fprintf(stderr
, gettext("unknown subcommand (%s)\n"), argv
[1]);
1559 smbadm_usage(B_FALSE
);
1568 switch (curcmd
->flags
& SMBADM_CMDF_TYPEMASK
) {
1569 case SMBADM_CMDF_GROUP
:
1570 if ((rc
= smb_lgrp_start()) != SMB_LGRP_SUCCESS
) {
1571 (void) fprintf(stderr
,
1572 gettext("failed to initialize (%s)\n"),
1573 smb_lgrp_strerror(rc
));
1578 case SMBADM_CMDF_USER
:
1579 smb_pwd_init(B_FALSE
);
1592 switch (curcmd
->flags
& SMBADM_CMDF_TYPEMASK
) {
1593 case SMBADM_CMDF_GROUP
:
1597 case SMBADM_CMDF_USER
:
1607 smbadm_checkauth(const char *auth
)
1611 if ((pw
= getpwuid(getuid())) == NULL
)
1614 if (chkauthattr(auth
, pw
->pw_name
) == 0)
1621 smbadm_prop_validate(smbadm_prop_t
*prop
, boolean_t chkval
)
1623 smbadm_prop_handle_t
*pinfo
;
1626 for (i
= 0; i
< SMBADM_NPROP
; i
++) {
1627 pinfo
= &smbadm_ptable
[i
];
1628 if (strcmp(pinfo
->p_name
, prop
->p_name
) == 0) {
1629 if (pinfo
->p_chkfn
&& chkval
)
1630 return (pinfo
->p_chkfn(prop
));
1636 (void) fprintf(stderr
, gettext("unrecognized property '%s'\n"),
1643 smbadm_prop_parse(char *arg
, smbadm_prop_t
*prop
)
1645 boolean_t parse_value
;
1651 prop
->p_name
= prop
->p_value
= NULL
;
1653 if (strcmp(curcmd
->name
, "set") == 0)
1654 parse_value
= B_TRUE
;
1656 parse_value
= B_FALSE
;
1661 equal
= strchr(arg
, '=');
1666 prop
->p_value
= equal
;
1669 if (smbadm_prop_validate(prop
, parse_value
) == B_FALSE
)
1675 static smbadm_prop_handle_t
*
1676 smbadm_prop_gethandle(char *pname
)
1680 for (i
= 0; i
< SMBADM_NPROP
; i
++)
1681 if (strcmp(pname
, smbadm_ptable
[i
].p_name
) == 0)
1682 return (&smbadm_ptable
[i
]);
1688 smbadm_setprop_desc(char *gname
, smbadm_prop_t
*prop
)
1692 status
= smb_lgrp_setcmnt(gname
, prop
->p_value
);
1693 if (status
!= SMB_LGRP_SUCCESS
) {
1694 (void) fprintf(stderr
,
1695 gettext("failed to modify the group description (%s)\n"),
1696 smb_lgrp_strerror(status
));
1700 (void) printf(gettext("%s: description modified\n"), gname
);
1705 smbadm_getprop_desc(char *gname
, smbadm_prop_t
*prop
)
1710 status
= smb_lgrp_getcmnt(gname
, &cmnt
);
1711 if (status
!= SMB_LGRP_SUCCESS
) {
1712 (void) fprintf(stderr
,
1713 gettext("failed to get the group description (%s)\n"),
1714 smb_lgrp_strerror(status
));
1718 (void) printf(gettext("\t%s: %s\n"), prop
->p_name
, cmnt
);
1724 smbadm_group_setpriv(char *gname
, uint8_t priv_id
, smbadm_prop_t
*prop
)
1730 if (strcasecmp(prop
->p_value
, "on") == 0) {
1731 (void) printf(gettext("Enabling %s privilege "), prop
->p_name
);
1734 (void) printf(gettext("Disabling %s privilege "), prop
->p_name
);
1738 status
= smb_lgrp_setpriv(gname
, priv_id
, enable
);
1739 if (status
== SMB_LGRP_SUCCESS
) {
1740 (void) printf(gettext("succeeded\n"));
1743 (void) printf(gettext("failed: %s\n"),
1744 smb_lgrp_strerror(status
));
1752 smbadm_group_getpriv(char *gname
, uint8_t priv_id
, smbadm_prop_t
*prop
)
1757 status
= smb_lgrp_getpriv(gname
, priv_id
, &enable
);
1758 if (status
!= SMB_LGRP_SUCCESS
) {
1759 (void) fprintf(stderr
, gettext("failed to get %s (%s)\n"),
1760 prop
->p_name
, smb_lgrp_strerror(status
));
1764 (void) printf(gettext("\t%s: %s\n"), prop
->p_name
,
1765 (enable
) ? "On" : "Off");
1771 smbadm_setprop_tkowner(char *gname
, smbadm_prop_t
*prop
)
1773 return (smbadm_group_setpriv(gname
, SE_TAKE_OWNERSHIP_LUID
, prop
));
1777 smbadm_getprop_tkowner(char *gname
, smbadm_prop_t
*prop
)
1779 return (smbadm_group_getpriv(gname
, SE_TAKE_OWNERSHIP_LUID
, prop
));
1783 smbadm_setprop_backup(char *gname
, smbadm_prop_t
*prop
)
1785 return (smbadm_group_setpriv(gname
, SE_BACKUP_LUID
, prop
));
1789 smbadm_getprop_backup(char *gname
, smbadm_prop_t
*prop
)
1791 return (smbadm_group_getpriv(gname
, SE_BACKUP_LUID
, prop
));
1795 smbadm_setprop_restore(char *gname
, smbadm_prop_t
*prop
)
1797 return (smbadm_group_setpriv(gname
, SE_RESTORE_LUID
, prop
));
1801 smbadm_getprop_restore(char *gname
, smbadm_prop_t
*prop
)
1803 return (smbadm_group_getpriv(gname
, SE_RESTORE_LUID
, prop
));
1807 smbadm_chkprop_priv(smbadm_prop_t
*prop
)
1809 if (prop
->p_value
== NULL
|| *prop
->p_value
== '\0') {
1810 (void) fprintf(stderr
,
1811 gettext("missing value for '%s'\n"), prop
->p_name
);
1815 if (strcasecmp(prop
->p_value
, "on") == 0)
1818 if (strcasecmp(prop
->p_value
, "off") == 0)
1821 (void) fprintf(stderr
,
1822 gettext("%s: unrecognized value for '%s' property\n"),
1823 prop
->p_value
, prop
->p_name
);
1829 smbadm_pwd_strerror(int error
)
1832 case SMB_PWE_SUCCESS
:
1833 return (gettext("Success."));
1835 case SMB_PWE_USER_UNKNOWN
:
1836 return (gettext("User does not exist."));
1838 case SMB_PWE_USER_DISABLE
:
1839 return (gettext("User is disabled."));
1841 case SMB_PWE_CLOSE_FAILED
:
1842 case SMB_PWE_OPEN_FAILED
:
1843 case SMB_PWE_WRITE_FAILED
:
1844 case SMB_PWE_UPDATE_FAILED
:
1845 return (gettext("Unexpected failure. "
1846 "SMB password database unchanged."));
1848 case SMB_PWE_STAT_FAILED
:
1849 return (gettext("stat of SMB password file failed."));
1852 return (gettext("SMB password database busy. "
1853 "Try again later."));
1855 case SMB_PWE_DENIED
:
1856 return (gettext("Operation not permitted."));
1858 case SMB_PWE_SYSTEM_ERROR
:
1859 return (gettext("System error."));
1865 return (gettext("Unknown error code."));
1869 * Enable libumem debugging by default on DEBUG builds.
1873 _umem_debug_init(void)
1875 return ("default,verbose"); /* $UMEM_DEBUG setting */
1879 _umem_logging_init(void)
1881 return ("fail,contents"); /* $UMEM_LOGGING setting */