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