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 2019 Nexenta by DDN, 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 HELP_USER_DELETE 70 } smbadm_help_t; 71 72 #define SMBADM_CMDF_NONE 0x00 73 #define SMBADM_CMDF_USER 0x01 74 #define SMBADM_CMDF_GROUP 0x02 75 #define SMBADM_CMDF_TYPEMASK 0x0F 76 77 typedef enum { 78 SMBADM_GRP_ADDMEMBER = 0, 79 SMBADM_GRP_DELMEMBER, 80 } smbadm_grp_action_t; 81 82 #define SMBADM_ANSBUFSIZ 64 83 84 typedef struct smbadm_cmdinfo { 85 char *name; 86 int (*func)(int, char **); 87 smbadm_help_t usage; 88 uint32_t flags; 89 char *auth; 90 } smbadm_cmdinfo_t; 91 92 smbadm_cmdinfo_t *curcmd; 93 static char *progname; 94 95 #define SMBADM_ACTION_AUTH "solaris.smf.manage.smb" 96 #define SMBADM_VALUE_AUTH "solaris.smf.value.smb" 97 #define SMBADM_BASIC_AUTH "solaris.network.hosts.read" 98 99 static boolean_t smbadm_checkauth(const char *); 100 101 static void smbadm_usage(boolean_t); 102 static int smbadm_join_workgroup(const char *, boolean_t); 103 static int smbadm_join_domain(const char *, const char *, 104 const char *, boolean_t); 105 static void smbadm_extract_domain(char *, char **, char **); 106 107 static int smbadm_join(int, char **); 108 static int smbadm_list(int, char **); 109 static int smbadm_lookup(int, char **); 110 static void smbadm_lookup_name(char *); 111 static void smbadm_lookup_sid(char *); 112 static int smbadm_group_create(int, char **); 113 static int smbadm_group_delete(int, char **); 114 static int smbadm_group_rename(int, char **); 115 static int smbadm_group_show(int, char **); 116 static void smbadm_group_show_name(const char *, const char *); 117 static int smbadm_group_getprop(int, char **); 118 static int smbadm_group_setprop(int, char **); 119 static int smbadm_group_addmember(int, char **); 120 static int smbadm_group_delmember(int, char **); 121 static int smbadm_group_add_del_member(char *, char *, smbadm_grp_action_t); 122 123 static int smbadm_user_delete(int, char **); 124 static int smbadm_user_disable(int, char **); 125 static int smbadm_user_enable(int, char **); 126 127 /* Please keep the order consistent with smbadm(8) man page */ 128 static smbadm_cmdinfo_t smbadm_cmdtable[] = 129 { 130 { "create", smbadm_group_create, HELP_CREATE, 131 SMBADM_CMDF_GROUP, SMBADM_ACTION_AUTH }, 132 { "delete", smbadm_group_delete, HELP_DELETE, 133 SMBADM_CMDF_GROUP, SMBADM_ACTION_AUTH }, 134 { "rename", smbadm_group_rename, HELP_RENAME, 135 SMBADM_CMDF_GROUP, SMBADM_ACTION_AUTH }, 136 { "show", smbadm_group_show, HELP_SHOW, 137 SMBADM_CMDF_GROUP, SMBADM_ACTION_AUTH }, 138 { "get", smbadm_group_getprop, HELP_GET, 139 SMBADM_CMDF_GROUP, SMBADM_ACTION_AUTH }, 140 { "set", smbadm_group_setprop, HELP_SET, 141 SMBADM_CMDF_GROUP, SMBADM_ACTION_AUTH }, 142 { "add-member", smbadm_group_addmember, HELP_ADD_MEMBER, 143 SMBADM_CMDF_GROUP, SMBADM_ACTION_AUTH }, 144 { "remove-member", smbadm_group_delmember, HELP_DEL_MEMBER, 145 SMBADM_CMDF_GROUP, SMBADM_ACTION_AUTH }, 146 { "delete-user", smbadm_user_delete, HELP_USER_DELETE, 147 SMBADM_CMDF_USER, SMBADM_ACTION_AUTH }, 148 { "disable-user", smbadm_user_disable, HELP_USER_DISABLE, 149 SMBADM_CMDF_USER, SMBADM_ACTION_AUTH }, 150 { "enable-user", smbadm_user_enable, HELP_USER_ENABLE, 151 SMBADM_CMDF_USER, SMBADM_ACTION_AUTH }, 152 { "join", smbadm_join, HELP_JOIN, 153 SMBADM_CMDF_NONE, SMBADM_VALUE_AUTH }, 154 { "list", smbadm_list, HELP_LIST, 155 SMBADM_CMDF_NONE, SMBADM_BASIC_AUTH }, 156 { "lookup", smbadm_lookup, HELP_LOOKUP, 157 SMBADM_CMDF_NONE, SMBADM_BASIC_AUTH }, 158 }; 159 160 #define SMBADM_NCMD (sizeof (smbadm_cmdtable) / sizeof (smbadm_cmdtable[0])) 161 162 typedef struct smbadm_prop { 163 char *p_name; 164 char *p_value; 165 } smbadm_prop_t; 166 167 typedef struct smbadm_prop_handle { 168 char *p_name; 169 char *p_dispvalue; 170 int (*p_setfn)(char *, smbadm_prop_t *); 171 int (*p_getfn)(char *, smbadm_prop_t *); 172 boolean_t (*p_chkfn)(smbadm_prop_t *); 173 } smbadm_prop_handle_t; 174 175 static boolean_t smbadm_prop_validate(smbadm_prop_t *prop, boolean_t chkval); 176 static int smbadm_prop_parse(char *arg, smbadm_prop_t *prop); 177 static smbadm_prop_handle_t *smbadm_prop_gethandle(char *pname); 178 179 static boolean_t smbadm_chkprop_priv(smbadm_prop_t *prop); 180 static int smbadm_setprop_tkowner(char *gname, smbadm_prop_t *prop); 181 static int smbadm_getprop_tkowner(char *gname, smbadm_prop_t *prop); 182 static int smbadm_setprop_readfile(char *gname, smbadm_prop_t *prop); 183 static int smbadm_getprop_readfile(char *gname, smbadm_prop_t *prop); 184 static int smbadm_setprop_writefile(char *gname, smbadm_prop_t *prop); 185 static int smbadm_getprop_writefile(char *gname, smbadm_prop_t *prop); 186 static int smbadm_setprop_backup(char *gname, smbadm_prop_t *prop); 187 static int smbadm_getprop_backup(char *gname, smbadm_prop_t *prop); 188 static int smbadm_setprop_restore(char *gname, smbadm_prop_t *prop); 189 static int smbadm_getprop_restore(char *gname, smbadm_prop_t *prop); 190 static int smbadm_setprop_desc(char *gname, smbadm_prop_t *prop); 191 static int smbadm_getprop_desc(char *gname, smbadm_prop_t *prop); 192 193 static smbadm_prop_handle_t smbadm_ptable[] = { 194 {"backup", "on|off", smbadm_setprop_backup, 195 smbadm_getprop_backup, smbadm_chkprop_priv }, 196 {"restore", "on|off", smbadm_setprop_restore, 197 smbadm_getprop_restore, smbadm_chkprop_priv }, 198 {"take-ownership", "on|off", smbadm_setprop_tkowner, 199 smbadm_getprop_tkowner, smbadm_chkprop_priv }, 200 {"bypass-read", "on|off", smbadm_setprop_readfile, 201 smbadm_getprop_readfile, smbadm_chkprop_priv }, 202 {"bypass-write", "on|off", smbadm_setprop_writefile, 203 smbadm_getprop_writefile, smbadm_chkprop_priv }, 204 {"description", "<string>", smbadm_setprop_desc, 205 smbadm_getprop_desc, NULL }, 206 }; 207 208 static int smbadm_init(void); 209 static void smbadm_fini(void); 210 static const char *smbadm_pwd_strerror(int error); 211 212 /* 213 * Number of supported properties 214 */ 215 #define SMBADM_NPROP (sizeof (smbadm_ptable) / sizeof (smbadm_ptable[0])) 216 217 static void 218 smbadm_cmdusage(FILE *fp, smbadm_cmdinfo_t *cmd) 219 { 220 switch (cmd->usage) { 221 case HELP_ADD_MEMBER: 222 (void) fprintf(fp, 223 gettext("\t%s -m <member> [-m <member>]... <group>\n"), 224 cmd->name); 225 return; 226 227 case HELP_CREATE: 228 (void) fprintf(fp, gettext("\t%s [-d <description>] <group>\n"), 229 cmd->name); 230 return; 231 232 case HELP_DELETE: 233 (void) fprintf(fp, gettext("\t%s <group>\n"), cmd->name); 234 return; 235 236 case HELP_USER_DELETE: 237 case HELP_USER_DISABLE: 238 case HELP_USER_ENABLE: 239 (void) fprintf(fp, gettext("\t%s <username>\n"), cmd->name); 240 return; 241 242 case HELP_GET: 243 (void) fprintf(fp, gettext("\t%s [-p <property>]... <group>\n"), 244 cmd->name); 245 return; 246 247 case HELP_JOIN: 248 #if 0 /* Don't document "-p" yet, still needs work (NEX-11960) */ 249 (void) fprintf(fp, gettext("\t%s [-y] -p <domain>\n" 250 "\t%s [-y] [-c container] -u <username domain>\n" 251 "\t%s [-y] -w <workgroup>\n"), 252 cmd->name, cmd->name, cmd->name); 253 #else 254 (void) fprintf(fp, gettext( 255 "\t%s [-y] [-c container] -u <username> <domain>\n" 256 "\t%s [-y] -w <workgroup>\n"), cmd->name, cmd->name); 257 #endif 258 return; 259 260 case HELP_LIST: 261 (void) fprintf(fp, gettext("\t%s\n"), cmd->name); 262 return; 263 264 case HELP_LOOKUP: 265 (void) fprintf(fp, 266 gettext("\t%s <account-name>\n"), 267 cmd->name); 268 return; 269 270 case HELP_DEL_MEMBER: 271 (void) fprintf(fp, 272 gettext("\t%s -m <member> [-m <member>]... <group>\n"), 273 cmd->name); 274 return; 275 276 case HELP_RENAME: 277 (void) fprintf(fp, gettext("\t%s <group> <new-group>\n"), 278 cmd->name); 279 return; 280 281 case HELP_SET: 282 (void) fprintf(fp, gettext("\t%s -p <property>=<value> " 283 "[-p <property>=<value>]... <group>\n"), cmd->name); 284 return; 285 286 case HELP_SHOW: 287 (void) fprintf(fp, gettext("\t%s [-mp] [<group>]\n"), 288 cmd->name); 289 return; 290 291 default: 292 break; 293 } 294 295 abort(); 296 /* NOTREACHED */ 297 } 298 299 static void 300 smbadm_usage(boolean_t requested) 301 { 302 FILE *fp = requested ? stdout : stderr; 303 boolean_t show_props = B_FALSE; 304 int i; 305 306 if (curcmd == NULL) { 307 (void) fprintf(fp, 308 gettext("usage: %s <subcommand> <args> ...\n"), 309 progname); 310 311 for (i = 0; i < SMBADM_NCMD; i++) 312 smbadm_cmdusage(fp, &smbadm_cmdtable[i]); 313 314 (void) fprintf(fp, 315 gettext("\nFor property list, run %s %s|%s\n"), 316 progname, "get", "set"); 317 318 exit(requested ? 0 : 2); 319 } 320 321 (void) fprintf(fp, gettext("usage:\n")); 322 smbadm_cmdusage(fp, curcmd); 323 324 if (strcmp(curcmd->name, "get") == 0 || 325 strcmp(curcmd->name, "set") == 0) 326 show_props = B_TRUE; 327 328 if (show_props) { 329 (void) fprintf(fp, 330 gettext("\nThe following properties are supported:\n")); 331 332 (void) fprintf(fp, "\n\t%-16s %s\n\n", 333 "PROPERTY", "VALUES"); 334 335 for (i = 0; i < SMBADM_NPROP; i++) { 336 (void) fprintf(fp, "\t%-16s %s\n", 337 smbadm_ptable[i].p_name, 338 smbadm_ptable[i].p_dispvalue); 339 } 340 } 341 342 exit(requested ? 0 : 2); 343 } 344 345 /* 346 * smbadm_strcasecmplist 347 * 348 * Find a string 's' within a list of strings. 349 * 350 * Returns the index of the matching string or -1 if there is no match. 351 */ 352 static int 353 smbadm_strcasecmplist(const char *s, ...) 354 { 355 va_list ap; 356 char *p; 357 int ndx; 358 359 va_start(ap, s); 360 361 for (ndx = 0; ((p = va_arg(ap, char *)) != NULL); ++ndx) { 362 if (strcasecmp(s, p) == 0) { 363 va_end(ap); 364 return (ndx); 365 } 366 } 367 368 va_end(ap); 369 return (-1); 370 } 371 372 /* 373 * smbadm_answer_prompt 374 * 375 * Prompt for the answer to a question. A default response must be 376 * specified, which will be used if the user presses <enter> without 377 * answering the question. 378 */ 379 static int 380 smbadm_answer_prompt(const char *prompt, char *answer, const char *dflt) 381 { 382 char buf[SMBADM_ANSBUFSIZ]; 383 char *p; 384 385 (void) printf(gettext("%s [%s]: "), prompt, dflt); 386 387 if (fgets(buf, SMBADM_ANSBUFSIZ, stdin) == NULL) 388 return (-1); 389 390 if ((p = strchr(buf, '\n')) != NULL) 391 *p = '\0'; 392 393 if (*buf == '\0') 394 (void) strlcpy(answer, dflt, SMBADM_ANSBUFSIZ); 395 else 396 (void) strlcpy(answer, buf, SMBADM_ANSBUFSIZ); 397 398 return (0); 399 } 400 401 /* 402 * smbadm_confirm 403 * 404 * Ask a question that requires a yes/no answer. 405 * A default response must be specified. 406 */ 407 static boolean_t 408 smbadm_confirm(const char *prompt, const char *dflt) 409 { 410 char buf[SMBADM_ANSBUFSIZ]; 411 412 for (;;) { 413 if (smbadm_answer_prompt(prompt, buf, dflt) < 0) 414 return (B_FALSE); 415 416 if (smbadm_strcasecmplist(buf, "n", "no", 0) >= 0) 417 return (B_FALSE); 418 419 if (smbadm_strcasecmplist(buf, "y", "yes", 0) >= 0) 420 return (B_TRUE); 421 422 (void) printf(gettext("Please answer yes or no.\n")); 423 } 424 } 425 426 static boolean_t 427 smbadm_join_prompt(const char *domain) 428 { 429 (void) printf(gettext("After joining %s the smb service will be " 430 "restarted automatically.\n"), domain); 431 432 return (smbadm_confirm("Would you like to continue?", "no")); 433 } 434 435 static void 436 smbadm_restart_service(void) 437 { 438 if (smb_smf_restart_service() != 0) { 439 (void) fprintf(stderr, 440 gettext("Unable to restart smb service. " 441 "Run 'svcs -xv smb/server' for more information.")); 442 } 443 } 444 445 /* 446 * smbadm_join 447 * 448 * Join a domain or workgroup. 449 * 450 * When joining a domain, we may receive the username, password and 451 * domain name in any of the following combinations. Note that the 452 * password is optional on the command line: if it is not provided, 453 * we will prompt for it later. 454 * 455 * username+password domain 456 * domain\username+password 457 * domain/username+password 458 * username@domain 459 * 460 * We allow domain\name+password or domain/name+password but not 461 * name+password@domain because @ is a valid password character. 462 * 463 * If the username and domain name are passed as separate command 464 * line arguments, we process them directly. Otherwise we separate 465 * them and continue as if they were separate command line arguments. 466 */ 467 static int 468 smbadm_join(int argc, char **argv) 469 { 470 char buf[MAXHOSTNAMELEN * 2]; 471 char *domain = NULL; 472 char *username = NULL; 473 char *container = NULL; 474 uint32_t mode = 0; 475 boolean_t do_prompt = B_TRUE; 476 char option; 477 478 while ((option = getopt(argc, argv, "c:pu:wy")) != -1) { 479 if (mode != 0) { 480 (void) fprintf(stderr, gettext( 481 "join options are mutually exclusive\n")); 482 smbadm_usage(B_FALSE); 483 } 484 switch (option) { 485 case 'c': 486 container = optarg; 487 break; 488 case 'p': 489 mode = SMB_SECMODE_DOMAIN; 490 /* leave username = NULL */ 491 break; 492 493 case 'u': 494 mode = SMB_SECMODE_DOMAIN; 495 username = optarg; 496 break; 497 498 case 'w': 499 mode = SMB_SECMODE_WORKGRP; 500 break; 501 502 case 'y': 503 do_prompt = B_FALSE; 504 break; 505 506 default: 507 smbadm_usage(B_FALSE); 508 break; 509 } 510 } 511 512 if (optind < argc) 513 domain = argv[optind]; 514 515 if (username != NULL && domain == NULL) { 516 /* 517 * The domain was not specified as a separate 518 * argument, check for the combination forms. 519 */ 520 (void) strlcpy(buf, username, sizeof (buf)); 521 smbadm_extract_domain(buf, &username, &domain); 522 } 523 524 if ((domain == NULL) || (*domain == '\0')) { 525 (void) fprintf(stderr, gettext("missing %s name\n"), 526 (mode == SMB_SECMODE_WORKGRP) ? "workgroup" : "domain"); 527 smbadm_usage(B_FALSE); 528 } 529 530 if (mode == SMB_SECMODE_WORKGRP) { 531 return (smbadm_join_workgroup(domain, do_prompt)); 532 } 533 return (smbadm_join_domain(domain, container, username, do_prompt)); 534 } 535 536 /* 537 * Workgroups comprise a collection of standalone, independently administered 538 * computers that use a common workgroup name. This is a peer-to-peer model 539 * with no formal membership mechanism. 540 */ 541 static int 542 smbadm_join_workgroup(const char *workgroup, boolean_t prompt) 543 { 544 smb_joininfo_t jdi; 545 smb_joinres_t jdres; 546 uint32_t status; 547 548 bzero(&jdres, sizeof (jdres)); 549 bzero(&jdi, sizeof (jdi)); 550 jdi.mode = SMB_SECMODE_WORKGRP; 551 (void) strlcpy(jdi.domain_name, workgroup, sizeof (jdi.domain_name)); 552 (void) strtrim(jdi.domain_name, " \t\n"); 553 554 if (smb_name_validate_workgroup(jdi.domain_name) != ERROR_SUCCESS) { 555 (void) fprintf(stderr, gettext("workgroup name is invalid\n")); 556 smbadm_usage(B_FALSE); 557 } 558 559 if (prompt && !smbadm_join_prompt(jdi.domain_name)) 560 return (0); 561 562 if ((status = smb_join(&jdi, &jdres)) != NT_STATUS_SUCCESS) { 563 (void) fprintf(stderr, gettext("failed to join %s: %s\n"), 564 jdi.domain_name, xlate_nt_status(status)); 565 return (1); 566 } 567 568 (void) printf(gettext("Successfully joined %s\n"), jdi.domain_name); 569 smbadm_restart_service(); 570 return (0); 571 } 572 573 /* 574 * Domains comprise a centrally administered group of computers and accounts 575 * that share a common security and administration policy and database. 576 * Computers must join a domain and become domain members, which requires 577 * an administrator level account name. 578 * 579 * The '+' character is invalid within a username. We allow the password 580 * to be appended to the username using '+' as a scripting convenience. 581 */ 582 static int 583 smbadm_join_domain(const char *domain, const char *container, 584 const char *username, boolean_t prompt) 585 { 586 smb_joininfo_t jdi; 587 smb_joinres_t jdres; 588 char *passwd_prompt; 589 char *p; 590 int len, rc; 591 592 bzero(&jdres, sizeof (jdres)); 593 bzero(&jdi, sizeof (jdi)); 594 jdi.mode = SMB_SECMODE_DOMAIN; 595 (void) strlcpy(jdi.domain_name, domain, sizeof (jdi.domain_name)); 596 (void) strtrim(jdi.domain_name, " \t\n"); 597 if (container != NULL) { 598 if (strlcpy(jdi.container_name, container, 599 sizeof (jdi.container_name)) >= 600 sizeof (jdi.container_name)) { 601 (void) fprintf(stderr, gettext("container name is " 602 "too long\n")); 603 smbadm_usage(B_FALSE); 604 } 605 } 606 607 if (smb_name_validate_domain(jdi.domain_name) != ERROR_SUCCESS) { 608 (void) fprintf(stderr, gettext("domain name is invalid\n")); 609 smbadm_usage(B_FALSE); 610 } 611 612 if (prompt && !smbadm_join_prompt(jdi.domain_name)) 613 return (0); 614 615 /* 616 * Note: username is null for "unsecure join" 617 * (join using a pre-created computer account) 618 * No password either. 619 */ 620 if (username != NULL) { 621 if ((p = strchr(username, '+')) != NULL) { 622 ++p; 623 624 len = (int)(p - username); 625 if (len > sizeof (jdi.domain_name)) 626 len = sizeof (jdi.domain_name); 627 628 (void) strlcpy(jdi.domain_username, username, len); 629 (void) strlcpy(jdi.domain_passwd, p, 630 sizeof (jdi.domain_passwd)); 631 } else { 632 (void) strlcpy(jdi.domain_username, username, 633 sizeof (jdi.domain_username)); 634 } 635 636 if (smb_name_validate_account(jdi.domain_username) 637 != ERROR_SUCCESS) { 638 (void) fprintf(stderr, 639 gettext("username contains invalid characters\n")); 640 smbadm_usage(B_FALSE); 641 } 642 643 if (*jdi.domain_passwd == '\0') { 644 passwd_prompt = gettext("Enter domain password: "); 645 646 if ((p = getpassphrase(passwd_prompt)) == NULL) { 647 (void) fprintf(stderr, gettext( 648 "missing password\n")); 649 smbadm_usage(B_FALSE); 650 } 651 652 (void) strlcpy(jdi.domain_passwd, p, 653 sizeof (jdi.domain_passwd)); 654 } 655 } 656 657 (void) printf(gettext("Joining %s ... this may take a minute ...\n"), 658 jdi.domain_name); 659 660 rc = smb_join(&jdi, &jdres); 661 if (rc != 0) { 662 (void) printf(gettext("Cannot call the SMB service. " 663 " (error %d: %s) " 664 "Please check the service status " 665 "(svcs -vx network/smb/server)\n"), 666 rc, strerror(rc)); 667 bzero(&jdi, sizeof (jdi)); 668 return (1); 669 } 670 671 switch (jdres.status) { 672 case NT_STATUS_SUCCESS: 673 (void) printf(gettext( 674 "Successfully joined domain %s using AD server %s\n"), 675 jdi.domain_name, jdres.dc_name); 676 bzero(&jdi, sizeof (jdi)); 677 smbadm_restart_service(); 678 return (0); 679 680 case NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND: 681 /* See: smb_ads_lookup_msdcs */ 682 (void) fprintf(stderr, gettext( 683 "failed to find any AD servers for domain: %s\n"), 684 jdi.domain_name); 685 goto common; 686 687 case NT_STATUS_BAD_NETWORK_PATH: 688 /* See: smbrdr_ctx_new / smb_ctx_resolve */ 689 (void) fprintf(stderr, gettext( 690 "failed to resolve address of AD server: %s\n"), 691 jdres.dc_name); 692 goto common; 693 694 case NT_STATUS_NETWORK_ACCESS_DENIED: 695 /* See: smbrdr_ctx_new / smb_ctx_get_ssn */ 696 (void) fprintf(stderr, gettext( 697 "failed to authenticate with AD server: %s\n"), 698 jdres.dc_name); 699 goto common; 700 701 case NT_STATUS_BAD_NETWORK_NAME: 702 /* 703 * See: smbrdr_ctx_new / smb_ctx_get_tree 704 * and: ndr_rpc_bind / smb_fh_open 705 */ 706 (void) fprintf(stderr, gettext( 707 "failed connecting to services on AD server: %s\n"), 708 jdres.dc_name); 709 goto common; 710 711 default: 712 (void) fprintf(stderr, gettext( 713 "failed to join domain %s\n"), 714 jdi.domain_name); 715 if (jdres.dc_name[0] != '\0') { 716 (void) fprintf(stderr, gettext( 717 "using AD server: %s\n"), 718 jdres.dc_name); 719 } 720 /* FALLTHROUGH */ 721 common: 722 if (jdres.join_err != 0) { 723 (void) fprintf(stderr, "%s\n", 724 smb_ads_strerror(jdres.join_err)); 725 } else if (jdres.status != 0) { 726 (void) fprintf(stderr, "(%s)\n", 727 xlate_nt_status(jdres.status)); 728 } 729 (void) fprintf(stderr, gettext("Please refer to the " 730 "service log for more information.\n")); 731 bzero(&jdi, sizeof (jdi)); 732 return (1); 733 } 734 } 735 736 /* 737 * We want to process the user and domain names as separate strings. 738 * Check for names of the forms below and separate the components as 739 * required. 740 * 741 * name@domain 742 * domain\name 743 * domain/name 744 * 745 * If we encounter any of the forms above in arg, the @, / or \ 746 * separator is replaced by \0 and the username and domain pointers 747 * are changed to point to the appropriate components (in arg). 748 * 749 * If none of the separators are encountered, the username and domain 750 * pointers remain unchanged. 751 */ 752 static void 753 smbadm_extract_domain(char *arg, char **username, char **domain) 754 { 755 char *p; 756 757 if ((p = strpbrk(arg, "/\\@")) != NULL) { 758 if (*p == '@') { 759 *p = '\0'; 760 ++p; 761 762 if (strchr(arg, '+') != NULL) 763 return; 764 765 *domain = p; 766 *username = arg; 767 } else { 768 *p = '\0'; 769 ++p; 770 *username = p; 771 *domain = arg; 772 } 773 } 774 } 775 776 /* 777 * smbadm_list 778 * 779 * Displays current security mode and domain/workgroup name. 780 */ 781 /*ARGSUSED*/ 782 static int 783 smbadm_list(int argc, char **argv) 784 { 785 char domain[MAXHOSTNAMELEN]; 786 char fqdn[MAXHOSTNAMELEN]; 787 char srvname[MAXHOSTNAMELEN]; 788 char modename[16]; 789 int rc; 790 smb_inaddr_t srvipaddr; 791 char ipstr[INET6_ADDRSTRLEN]; 792 793 rc = smb_config_getstr(SMB_CI_SECURITY, modename, sizeof (modename)); 794 if (rc != SMBD_SMF_OK) { 795 (void) fprintf(stderr, 796 gettext("cannot determine the operational mode\n")); 797 return (1); 798 } 799 800 if (smb_getdomainname(domain, sizeof (domain)) != 0) { 801 (void) fprintf(stderr, gettext("failed to get the %s name\n"), 802 modename); 803 return (1); 804 } 805 806 if (strcmp(modename, "workgroup") == 0) { 807 (void) printf(gettext("[*] [%s]\n"), domain); 808 return (0); 809 } 810 811 (void) printf(gettext("[*] [%s]\n"), domain); 812 if ((smb_getfqdomainname(fqdn, sizeof (fqdn)) == 0) && (*fqdn != '\0')) 813 (void) printf(gettext("[*] [%s]\n"), fqdn); 814 815 if ((smb_get_dcinfo(srvname, MAXHOSTNAMELEN, &srvipaddr) 816 == NT_STATUS_SUCCESS) && (*srvname != '\0') && 817 (!smb_inet_iszero(&srvipaddr))) { 818 (void) smb_inet_ntop(&srvipaddr, ipstr, 819 SMB_IPSTRLEN(srvipaddr.a_family)); 820 (void) printf(gettext("\t[+%s] [%s]\n"), 821 srvname, ipstr); 822 } 823 824 /* Print the local and domain SID. */ 825 smb_domain_show(); 826 return (0); 827 } 828 829 /* 830 * smbadm_lookup 831 * 832 * Lookup the SID for a given account (user or group) 833 */ 834 static int 835 smbadm_lookup(int argc, char **argv) 836 { 837 int i; 838 839 if (argc < 2) { 840 (void) fprintf(stderr, gettext("missing account name\n")); 841 smbadm_usage(B_FALSE); 842 } 843 844 for (i = 1; i < argc; i++) { 845 if (strncmp(argv[i], "S-1-", 4) == 0) 846 smbadm_lookup_sid(argv[i]); 847 else 848 smbadm_lookup_name(argv[i]); 849 } 850 return (0); 851 } 852 853 static void 854 smbadm_lookup_name(char *name) 855 { 856 lsa_account_t acct; 857 int rc; 858 859 if ((rc = smb_lookup_name(name, SidTypeUnknown, &acct)) != 0) { 860 (void) fprintf(stderr, gettext( 861 "\t\t%s: lookup name failed, rc=%d\n"), 862 name, rc); 863 return; 864 } 865 if (acct.a_status != NT_STATUS_SUCCESS) { 866 (void) fprintf(stderr, gettext("\t\t%s [%s]\n"), 867 name, xlate_nt_status(acct.a_status)); 868 return; 869 } 870 (void) printf("\t%s\n", acct.a_sid); 871 } 872 873 static void 874 smbadm_lookup_sid(char *sidstr) 875 { 876 lsa_account_t acct; 877 int rc; 878 879 if ((rc = smb_lookup_sid(sidstr, &acct)) != 0) { 880 (void) fprintf(stderr, gettext( 881 "\t\t%s: lookup SID failed, rc=%d\n"), 882 sidstr, rc); 883 return; 884 } 885 if (acct.a_status != NT_STATUS_SUCCESS) { 886 (void) fprintf(stderr, gettext("\t\t%s [%s]\n"), 887 sidstr, xlate_nt_status(acct.a_status)); 888 return; 889 } 890 (void) printf("\t%s\\%s\n", acct.a_domain, acct.a_name); 891 } 892 893 /* 894 * smbadm_group_create 895 * 896 * Creates a local SMB group 897 */ 898 static int 899 smbadm_group_create(int argc, char **argv) 900 { 901 char *gname = NULL; 902 char *desc = NULL; 903 char option; 904 int status; 905 906 while ((option = getopt(argc, argv, "d:")) != -1) { 907 switch (option) { 908 case 'd': 909 desc = optarg; 910 break; 911 912 default: 913 smbadm_usage(B_FALSE); 914 } 915 } 916 917 gname = argv[optind]; 918 if (optind >= argc || gname == NULL || *gname == '\0') { 919 (void) fprintf(stderr, gettext("missing group name\n")); 920 smbadm_usage(B_FALSE); 921 } 922 923 status = smb_lgrp_add(gname, desc); 924 if (status != SMB_LGRP_SUCCESS) { 925 (void) fprintf(stderr, 926 gettext("failed to create %s (%s)\n"), gname, 927 smb_lgrp_strerror(status)); 928 } else { 929 (void) printf(gettext("%s created\n"), gname); 930 } 931 932 return (status); 933 } 934 935 /* 936 * smbadm_group_dump_members 937 * 938 * Dump group members details. 939 */ 940 static void 941 smbadm_group_dump_members(smb_gsid_t *members, int num) 942 { 943 char sidstr[SMB_SID_STRSZ]; 944 lsa_account_t acct; 945 int i; 946 947 if (num == 0) { 948 (void) printf(gettext("\tNo members\n")); 949 return; 950 } 951 952 (void) printf(gettext("\tMembers:\n")); 953 for (i = 0; i < num; i++) { 954 smb_sid_tostr(members[i].gs_sid, sidstr); 955 956 if (smb_lookup_sid(sidstr, &acct) == 0) { 957 if (acct.a_status == NT_STATUS_SUCCESS) 958 smbadm_group_show_name(acct.a_domain, 959 acct.a_name); 960 else 961 (void) printf(gettext("\t\t%s [%s]\n"), 962 sidstr, xlate_nt_status(acct.a_status)); 963 } else { 964 (void) printf(gettext("\t\t%s\n"), sidstr); 965 } 966 } 967 } 968 969 static void 970 smbadm_group_show_name(const char *domain, const char *name) 971 { 972 if (strchr(domain, '.') != NULL) 973 (void) printf("\t\t%s@%s\n", name, domain); 974 else 975 (void) printf("\t\t%s\\%s\n", domain, name); 976 } 977 978 /* 979 * smbadm_group_dump_privs 980 * 981 * Dump group privilege details. 982 */ 983 static void 984 smbadm_group_dump_privs(smb_privset_t *privs) 985 { 986 smb_privinfo_t *pinfo; 987 char *pstatus; 988 int i; 989 990 (void) printf(gettext("\tPrivileges: \n")); 991 992 for (i = 0; i < privs->priv_cnt; i++) { 993 pinfo = smb_priv_getbyvalue(privs->priv[i].luid.lo_part); 994 if ((pinfo == NULL) || (pinfo->flags & PF_PRESENTABLE) == 0) 995 continue; 996 997 switch (privs->priv[i].attrs) { 998 case SE_PRIVILEGE_ENABLED: 999 pstatus = "On"; 1000 break; 1001 case SE_PRIVILEGE_DISABLED: 1002 pstatus = "Off"; 1003 break; 1004 default: 1005 pstatus = "Unknown"; 1006 break; 1007 } 1008 (void) printf(gettext("\t\t%s: %s\n"), pinfo->name, pstatus); 1009 } 1010 1011 if (privs->priv_cnt == 0) 1012 (void) printf(gettext("\t\tNo privileges\n")); 1013 } 1014 1015 /* 1016 * smbadm_group_dump 1017 * 1018 * Dump group details. 1019 */ 1020 static void 1021 smbadm_group_dump(smb_group_t *grp, boolean_t show_mem, boolean_t show_privs) 1022 { 1023 char sidstr[SMB_SID_STRSZ]; 1024 1025 (void) printf(gettext("%s (%s)\n"), grp->sg_name, grp->sg_cmnt); 1026 1027 smb_sid_tostr(grp->sg_id.gs_sid, sidstr); 1028 (void) printf(gettext("\tSID: %s\n"), sidstr); 1029 1030 if (show_privs) 1031 smbadm_group_dump_privs(grp->sg_privs); 1032 1033 if (show_mem) 1034 smbadm_group_dump_members(grp->sg_members, grp->sg_nmembers); 1035 } 1036 1037 /* 1038 * smbadm_group_show 1039 * 1040 */ 1041 static int 1042 smbadm_group_show(int argc, char **argv) 1043 { 1044 char *gname = NULL; 1045 boolean_t show_privs; 1046 boolean_t show_members; 1047 char option; 1048 int status; 1049 smb_group_t grp; 1050 smb_giter_t gi; 1051 1052 show_privs = show_members = B_FALSE; 1053 1054 while ((option = getopt(argc, argv, "mp")) != -1) { 1055 switch (option) { 1056 case 'm': 1057 show_members = B_TRUE; 1058 break; 1059 case 'p': 1060 show_privs = B_TRUE; 1061 break; 1062 1063 default: 1064 smbadm_usage(B_FALSE); 1065 } 1066 } 1067 1068 gname = argv[optind]; 1069 if (optind >= argc || gname == NULL || *gname == '\0') 1070 gname = "*"; 1071 1072 if (strcmp(gname, "*")) { 1073 status = smb_lgrp_getbyname(gname, &grp); 1074 if (status == SMB_LGRP_SUCCESS) { 1075 smbadm_group_dump(&grp, show_members, show_privs); 1076 smb_lgrp_free(&grp); 1077 } else { 1078 (void) fprintf(stderr, 1079 gettext("failed to find %s (%s)\n"), 1080 gname, smb_lgrp_strerror(status)); 1081 } 1082 return (status); 1083 } 1084 1085 if ((status = smb_lgrp_iteropen(&gi)) != SMB_LGRP_SUCCESS) { 1086 (void) fprintf(stderr, gettext("failed to list groups (%s)\n"), 1087 smb_lgrp_strerror(status)); 1088 return (status); 1089 } 1090 1091 while ((status = smb_lgrp_iterate(&gi, &grp)) == SMB_LGRP_SUCCESS) { 1092 smbadm_group_dump(&grp, show_members, show_privs); 1093 smb_lgrp_free(&grp); 1094 } 1095 1096 smb_lgrp_iterclose(&gi); 1097 1098 if ((status != SMB_LGRP_NO_MORE) || smb_lgrp_itererror(&gi)) { 1099 if (status != SMB_LGRP_NO_MORE) 1100 smb_syslog(LOG_ERR, "smb_lgrp_iterate: %s", 1101 smb_lgrp_strerror(status)); 1102 1103 (void) fprintf(stderr, 1104 gettext("\nAn error occurred while retrieving group data.\n" 1105 "Check the system log for more information.\n")); 1106 return (status); 1107 } 1108 1109 return (0); 1110 } 1111 1112 /* 1113 * smbadm_group_delete 1114 */ 1115 static int 1116 smbadm_group_delete(int argc, char **argv) 1117 { 1118 char *gname = NULL; 1119 int status; 1120 1121 gname = argv[optind]; 1122 if (optind >= argc || gname == NULL || *gname == '\0') { 1123 (void) fprintf(stderr, gettext("missing group name\n")); 1124 smbadm_usage(B_FALSE); 1125 } 1126 1127 status = smb_lgrp_delete(gname); 1128 if (status != SMB_LGRP_SUCCESS) { 1129 (void) fprintf(stderr, 1130 gettext("failed to delete %s (%s)\n"), gname, 1131 smb_lgrp_strerror(status)); 1132 } else { 1133 (void) printf(gettext("%s deleted\n"), gname); 1134 } 1135 1136 return (status); 1137 } 1138 1139 /* 1140 * smbadm_group_rename 1141 */ 1142 static int 1143 smbadm_group_rename(int argc, char **argv) 1144 { 1145 char *gname = NULL; 1146 char *ngname = NULL; 1147 int status; 1148 1149 gname = argv[optind]; 1150 if (optind++ >= argc || gname == NULL || *gname == '\0') { 1151 (void) fprintf(stderr, gettext("missing group name\n")); 1152 smbadm_usage(B_FALSE); 1153 } 1154 1155 ngname = argv[optind]; 1156 if (optind >= argc || ngname == NULL || *ngname == '\0') { 1157 (void) fprintf(stderr, gettext("missing new group name\n")); 1158 smbadm_usage(B_FALSE); 1159 } 1160 1161 status = smb_lgrp_rename(gname, ngname); 1162 if (status != SMB_LGRP_SUCCESS) { 1163 if (status == SMB_LGRP_EXISTS) 1164 (void) fprintf(stderr, 1165 gettext("failed to rename '%s' (%s already " 1166 "exists)\n"), gname, ngname); 1167 else 1168 (void) fprintf(stderr, 1169 gettext("failed to rename '%s' (%s)\n"), gname, 1170 smb_lgrp_strerror(status)); 1171 } else { 1172 (void) printf(gettext("'%s' renamed to '%s'\n"), gname, ngname); 1173 } 1174 1175 return (status); 1176 } 1177 1178 /* 1179 * smbadm_group_setprop 1180 * 1181 * Set the group properties. 1182 */ 1183 static int 1184 smbadm_group_setprop(int argc, char **argv) 1185 { 1186 char *gname = NULL; 1187 smbadm_prop_t props[SMBADM_NPROP]; 1188 smbadm_prop_handle_t *phandle; 1189 char option; 1190 int pcnt = 0; 1191 int ret = 0; 1192 int p; 1193 1194 bzero(props, SMBADM_NPROP * sizeof (smbadm_prop_t)); 1195 1196 while ((option = getopt(argc, argv, "p:")) != -1) { 1197 switch (option) { 1198 case 'p': 1199 if (pcnt >= SMBADM_NPROP) { 1200 (void) fprintf(stderr, 1201 gettext("exceeded number of supported" 1202 " properties\n")); 1203 smbadm_usage(B_FALSE); 1204 } 1205 1206 if (smbadm_prop_parse(optarg, &props[pcnt++]) != 0) 1207 smbadm_usage(B_FALSE); 1208 break; 1209 1210 default: 1211 smbadm_usage(B_FALSE); 1212 } 1213 } 1214 1215 if (pcnt == 0) { 1216 (void) fprintf(stderr, 1217 gettext("missing property=value argument\n")); 1218 smbadm_usage(B_FALSE); 1219 } 1220 1221 gname = argv[optind]; 1222 if (optind >= argc || gname == NULL || *gname == '\0') { 1223 (void) fprintf(stderr, gettext("missing group name\n")); 1224 smbadm_usage(B_FALSE); 1225 } 1226 1227 for (p = 0; p < pcnt; p++) { 1228 phandle = smbadm_prop_gethandle(props[p].p_name); 1229 if (phandle) { 1230 if (phandle->p_setfn(gname, &props[p]) != 0) 1231 ret = 1; 1232 } 1233 } 1234 1235 return (ret); 1236 } 1237 1238 /* 1239 * smbadm_group_getprop 1240 * 1241 * Get the group properties. 1242 */ 1243 static int 1244 smbadm_group_getprop(int argc, char **argv) 1245 { 1246 char *gname = NULL; 1247 smbadm_prop_t props[SMBADM_NPROP]; 1248 smbadm_prop_handle_t *phandle; 1249 char option; 1250 int pcnt = 0; 1251 int ret = 0; 1252 int p; 1253 1254 bzero(props, SMBADM_NPROP * sizeof (smbadm_prop_t)); 1255 1256 while ((option = getopt(argc, argv, "p:")) != -1) { 1257 switch (option) { 1258 case 'p': 1259 if (pcnt >= SMBADM_NPROP) { 1260 (void) fprintf(stderr, 1261 gettext("exceeded number of supported" 1262 " properties\n")); 1263 smbadm_usage(B_FALSE); 1264 } 1265 1266 if (smbadm_prop_parse(optarg, &props[pcnt++]) != 0) 1267 smbadm_usage(B_FALSE); 1268 break; 1269 1270 default: 1271 smbadm_usage(B_FALSE); 1272 } 1273 } 1274 1275 gname = argv[optind]; 1276 if (optind >= argc || gname == NULL || *gname == '\0') { 1277 (void) fprintf(stderr, gettext("missing group name\n")); 1278 smbadm_usage(B_FALSE); 1279 } 1280 1281 if (pcnt == 0) { 1282 /* 1283 * If no property has be specified then get 1284 * all the properties. 1285 */ 1286 pcnt = SMBADM_NPROP; 1287 for (p = 0; p < pcnt; p++) 1288 props[p].p_name = smbadm_ptable[p].p_name; 1289 } 1290 1291 for (p = 0; p < pcnt; p++) { 1292 phandle = smbadm_prop_gethandle(props[p].p_name); 1293 if (phandle) { 1294 if (phandle->p_getfn(gname, &props[p]) != 0) 1295 ret = 1; 1296 } 1297 } 1298 1299 return (ret); 1300 } 1301 1302 /* 1303 * smbadm_group_addmember 1304 * 1305 */ 1306 static int 1307 smbadm_group_addmember(int argc, char **argv) 1308 { 1309 char *gname = NULL; 1310 char **mname; 1311 char option; 1312 int mcnt = 0; 1313 int ret = 0; 1314 int i; 1315 1316 1317 mname = (char **)malloc(argc * sizeof (char *)); 1318 if (mname == NULL) { 1319 warn(gettext("failed to add group member")); 1320 return (1); 1321 } 1322 bzero(mname, argc * sizeof (char *)); 1323 1324 while ((option = getopt(argc, argv, "m:")) != -1) { 1325 switch (option) { 1326 case 'm': 1327 mname[mcnt++] = optarg; 1328 break; 1329 1330 default: 1331 free(mname); 1332 smbadm_usage(B_FALSE); 1333 } 1334 } 1335 1336 if (mcnt == 0) { 1337 (void) fprintf(stderr, gettext("missing member name\n")); 1338 free(mname); 1339 smbadm_usage(B_FALSE); 1340 } 1341 1342 gname = argv[optind]; 1343 if (optind >= argc || gname == NULL || *gname == 0) { 1344 (void) fprintf(stderr, gettext("missing group name\n")); 1345 free(mname); 1346 smbadm_usage(B_FALSE); 1347 } 1348 1349 for (i = 0; i < mcnt; i++) { 1350 if (mname[i] == NULL) 1351 continue; 1352 ret |= smbadm_group_add_del_member( 1353 gname, mname[i], SMBADM_GRP_ADDMEMBER); 1354 } 1355 1356 free(mname); 1357 return (ret); 1358 } 1359 1360 /* 1361 * smbadm_group_delmember 1362 */ 1363 static int 1364 smbadm_group_delmember(int argc, char **argv) 1365 { 1366 char *gname = NULL; 1367 char **mname; 1368 char option; 1369 int mcnt = 0; 1370 int ret = 0; 1371 int i; 1372 1373 mname = (char **)malloc(argc * sizeof (char *)); 1374 if (mname == NULL) { 1375 warn(gettext("failed to delete group member")); 1376 return (1); 1377 } 1378 bzero(mname, argc * sizeof (char *)); 1379 1380 while ((option = getopt(argc, argv, "m:")) != -1) { 1381 switch (option) { 1382 case 'm': 1383 mname[mcnt++] = optarg; 1384 break; 1385 1386 default: 1387 free(mname); 1388 smbadm_usage(B_FALSE); 1389 } 1390 } 1391 1392 if (mcnt == 0) { 1393 (void) fprintf(stderr, gettext("missing member name\n")); 1394 free(mname); 1395 smbadm_usage(B_FALSE); 1396 } 1397 1398 gname = argv[optind]; 1399 if (optind >= argc || gname == NULL || *gname == 0) { 1400 (void) fprintf(stderr, gettext("missing group name\n")); 1401 free(mname); 1402 smbadm_usage(B_FALSE); 1403 } 1404 1405 1406 for (i = 0; i < mcnt; i++) { 1407 ret = 0; 1408 if (mname[i] == NULL) 1409 continue; 1410 ret |= smbadm_group_add_del_member( 1411 gname, mname[i], SMBADM_GRP_DELMEMBER); 1412 } 1413 1414 free(mname); 1415 return (ret); 1416 } 1417 1418 static int 1419 smbadm_group_add_del_member(char *gname, char *mname, 1420 smbadm_grp_action_t act) 1421 { 1422 lsa_account_t acct; 1423 smb_gsid_t msid; 1424 char *sidstr; 1425 char *act_str = NULL; 1426 int rc; 1427 1428 if (strncmp(mname, "S-1-", 4) == 0) { 1429 /* 1430 * We are given a SID. Just use it. 1431 * 1432 * We'd like the real account type if we can get it, 1433 * but don't want to error out if we can't get it. 1434 * Lacking other info, assume it's a group. 1435 */ 1436 sidstr = mname; 1437 rc = smb_lookup_sid(sidstr, &acct); 1438 if ((rc != 0) || (acct.a_status != NT_STATUS_SUCCESS)) 1439 acct.a_sidtype = SidTypeGroup; 1440 } else { 1441 rc = smb_lookup_name(mname, SidTypeUnknown, &acct); 1442 if ((rc != 0) || (acct.a_status != NT_STATUS_SUCCESS)) { 1443 (void) fprintf(stderr, 1444 gettext("%s: name lookup failed\n"), mname); 1445 return (1); 1446 } 1447 sidstr = acct.a_sid; 1448 } 1449 1450 msid.gs_type = acct.a_sidtype; 1451 if ((msid.gs_sid = smb_sid_fromstr(sidstr)) == NULL) { 1452 (void) fprintf(stderr, 1453 gettext("%s: no memory for SID\n"), sidstr); 1454 return (1); 1455 } 1456 1457 switch (act) { 1458 case SMBADM_GRP_ADDMEMBER: 1459 act_str = gettext("add"); 1460 rc = smb_lgrp_add_member(gname, 1461 msid.gs_sid, msid.gs_type); 1462 break; 1463 case SMBADM_GRP_DELMEMBER: 1464 act_str = gettext("remove"); 1465 rc = smb_lgrp_del_member(gname, 1466 msid.gs_sid, msid.gs_type); 1467 break; 1468 default: 1469 rc = SMB_LGRP_INTERNAL_ERROR; 1470 break; 1471 } 1472 1473 smb_sid_free(msid.gs_sid); 1474 1475 if (rc != SMB_LGRP_SUCCESS) { 1476 (void) fprintf(stderr, 1477 gettext("failed to %s %s (%s)\n"), 1478 act_str, mname, smb_lgrp_strerror(rc)); 1479 return (1); 1480 } 1481 return (0); 1482 } 1483 1484 static int 1485 smbadm_user_delete(int argc, char **argv) 1486 { 1487 int error; 1488 char *user = NULL; 1489 1490 user = argv[optind]; 1491 if (optind >= argc || user == NULL || *user == '\0') { 1492 (void) fprintf(stderr, gettext("missing user name\n")); 1493 smbadm_usage(B_FALSE); 1494 } 1495 1496 error = smb_pwd_setcntl(user, SMB_PWC_DELETE); 1497 if (error == SMB_PWE_SUCCESS) 1498 (void) printf(gettext("%s has been deleted.\n"), user); 1499 else 1500 (void) fprintf(stderr, "%s\n", smbadm_pwd_strerror(error)); 1501 1502 return (error); 1503 } 1504 1505 static int 1506 smbadm_user_disable(int argc, char **argv) 1507 { 1508 int error; 1509 char *user = NULL; 1510 1511 user = argv[optind]; 1512 if (optind >= argc || user == NULL || *user == '\0') { 1513 (void) fprintf(stderr, gettext("missing user name\n")); 1514 smbadm_usage(B_FALSE); 1515 } 1516 1517 error = smb_pwd_setcntl(user, SMB_PWC_DISABLE); 1518 if (error == SMB_PWE_SUCCESS) 1519 (void) printf(gettext("%s is disabled.\n"), user); 1520 else 1521 (void) fprintf(stderr, "%s\n", smbadm_pwd_strerror(error)); 1522 1523 return (error); 1524 } 1525 1526 static int 1527 smbadm_user_enable(int argc, char **argv) 1528 { 1529 int error; 1530 char *user = NULL; 1531 1532 user = argv[optind]; 1533 if (optind >= argc || user == NULL || *user == '\0') { 1534 (void) fprintf(stderr, gettext("missing user name\n")); 1535 smbadm_usage(B_FALSE); 1536 } 1537 1538 error = smb_pwd_setcntl(user, SMB_PWC_ENABLE); 1539 if (error == SMB_PWE_SUCCESS) 1540 (void) printf(gettext("%s is enabled.\n"), user); 1541 else 1542 (void) fprintf(stderr, "%s\n", smbadm_pwd_strerror(error)); 1543 1544 return (error); 1545 } 1546 1547 1548 int 1549 main(int argc, char **argv) 1550 { 1551 int ret; 1552 int i; 1553 1554 (void) setlocale(LC_ALL, ""); 1555 (void) textdomain(TEXT_DOMAIN); 1556 1557 (void) malloc(0); /* satisfy libumem dependency */ 1558 1559 progname = basename(argv[0]); 1560 1561 if (is_system_labeled()) { 1562 (void) fprintf(stderr, 1563 gettext("Trusted Extensions not supported\n")); 1564 return (1); 1565 } 1566 1567 if (argc < 2) { 1568 (void) fprintf(stderr, gettext("missing command\n")); 1569 smbadm_usage(B_FALSE); 1570 } 1571 1572 /* 1573 * Special case "cmd --help/-?" 1574 */ 1575 if (strcmp(argv[1], "-?") == 0 || 1576 strcmp(argv[1], "--help") == 0 || 1577 strcmp(argv[1], "-h") == 0) 1578 smbadm_usage(B_TRUE); 1579 1580 for (i = 0; i < SMBADM_NCMD; ++i) { 1581 curcmd = &smbadm_cmdtable[i]; 1582 if (strcasecmp(argv[1], curcmd->name) == 0) { 1583 if (argc > 2) { 1584 /* cmd subcmd --help/-? */ 1585 if (strcmp(argv[2], "-?") == 0 || 1586 strcmp(argv[2], "--help") == 0 || 1587 strcmp(argv[2], "-h") == 0) 1588 smbadm_usage(B_TRUE); 1589 } 1590 1591 if (!smbadm_checkauth(curcmd->auth)) { 1592 (void) fprintf(stderr, 1593 gettext("%s: %s: authorization denied\n"), 1594 progname, curcmd->name); 1595 return (1); 1596 } 1597 1598 if ((ret = smbadm_init()) != 0) 1599 return (ret); 1600 1601 ret = curcmd->func(argc - 1, &argv[1]); 1602 1603 smbadm_fini(); 1604 return (ret); 1605 } 1606 } 1607 1608 curcmd = NULL; 1609 (void) fprintf(stderr, gettext("unknown subcommand (%s)\n"), argv[1]); 1610 smbadm_usage(B_FALSE); 1611 return (2); 1612 } 1613 1614 static int 1615 smbadm_init(void) 1616 { 1617 int rc; 1618 1619 switch (curcmd->flags & SMBADM_CMDF_TYPEMASK) { 1620 case SMBADM_CMDF_GROUP: 1621 if ((rc = smb_lgrp_start()) != SMB_LGRP_SUCCESS) { 1622 (void) fprintf(stderr, 1623 gettext("failed to initialize (%s)\n"), 1624 smb_lgrp_strerror(rc)); 1625 return (1); 1626 } 1627 break; 1628 1629 case SMBADM_CMDF_USER: 1630 smb_pwd_init(B_FALSE); 1631 break; 1632 1633 default: 1634 break; 1635 } 1636 1637 return (0); 1638 } 1639 1640 static void 1641 smbadm_fini(void) 1642 { 1643 switch (curcmd->flags & SMBADM_CMDF_TYPEMASK) { 1644 case SMBADM_CMDF_GROUP: 1645 smb_lgrp_stop(); 1646 break; 1647 1648 case SMBADM_CMDF_USER: 1649 smb_pwd_fini(); 1650 break; 1651 1652 default: 1653 break; 1654 } 1655 } 1656 1657 static boolean_t 1658 smbadm_checkauth(const char *auth) 1659 { 1660 struct passwd *pw; 1661 1662 if ((pw = getpwuid(getuid())) == NULL) 1663 return (B_FALSE); 1664 1665 if (chkauthattr(auth, pw->pw_name) == 0) 1666 return (B_FALSE); 1667 1668 return (B_TRUE); 1669 } 1670 1671 static boolean_t 1672 smbadm_prop_validate(smbadm_prop_t *prop, boolean_t chkval) 1673 { 1674 smbadm_prop_handle_t *pinfo; 1675 int i; 1676 1677 for (i = 0; i < SMBADM_NPROP; i++) { 1678 pinfo = &smbadm_ptable[i]; 1679 if (strcmp(pinfo->p_name, prop->p_name) == 0) { 1680 if (pinfo->p_chkfn && chkval) 1681 return (pinfo->p_chkfn(prop)); 1682 1683 return (B_TRUE); 1684 } 1685 } 1686 1687 (void) fprintf(stderr, gettext("unrecognized property '%s'\n"), 1688 prop->p_name); 1689 1690 return (B_FALSE); 1691 } 1692 1693 static int 1694 smbadm_prop_parse(char *arg, smbadm_prop_t *prop) 1695 { 1696 boolean_t parse_value; 1697 char *equal; 1698 1699 if (arg == NULL) 1700 return (2); 1701 1702 prop->p_name = prop->p_value = NULL; 1703 1704 if (strcmp(curcmd->name, "set") == 0) 1705 parse_value = B_TRUE; 1706 else 1707 parse_value = B_FALSE; 1708 1709 prop->p_name = arg; 1710 1711 if (parse_value) { 1712 equal = strchr(arg, '='); 1713 if (equal == NULL) 1714 return (2); 1715 1716 *equal++ = '\0'; 1717 prop->p_value = equal; 1718 } 1719 1720 if (smbadm_prop_validate(prop, parse_value) == B_FALSE) 1721 return (2); 1722 1723 return (0); 1724 } 1725 1726 static smbadm_prop_handle_t * 1727 smbadm_prop_gethandle(char *pname) 1728 { 1729 int i; 1730 1731 for (i = 0; i < SMBADM_NPROP; i++) 1732 if (strcmp(pname, smbadm_ptable[i].p_name) == 0) 1733 return (&smbadm_ptable[i]); 1734 1735 return (NULL); 1736 } 1737 1738 static int 1739 smbadm_setprop_desc(char *gname, smbadm_prop_t *prop) 1740 { 1741 int status; 1742 1743 status = smb_lgrp_setcmnt(gname, prop->p_value); 1744 if (status != SMB_LGRP_SUCCESS) { 1745 (void) fprintf(stderr, 1746 gettext("failed to modify the group description (%s)\n"), 1747 smb_lgrp_strerror(status)); 1748 return (1); 1749 } 1750 1751 (void) printf(gettext("%s: description modified\n"), gname); 1752 return (0); 1753 } 1754 1755 static int 1756 smbadm_getprop_desc(char *gname, smbadm_prop_t *prop) 1757 { 1758 char *cmnt = NULL; 1759 int status; 1760 1761 status = smb_lgrp_getcmnt(gname, &cmnt); 1762 if (status != SMB_LGRP_SUCCESS) { 1763 (void) fprintf(stderr, 1764 gettext("failed to get the group description (%s)\n"), 1765 smb_lgrp_strerror(status)); 1766 return (1); 1767 } 1768 1769 (void) printf(gettext("\t%s: %s\n"), prop->p_name, cmnt); 1770 free(cmnt); 1771 return (0); 1772 } 1773 1774 static int 1775 smbadm_group_setpriv(char *gname, uint8_t priv_id, smbadm_prop_t *prop) 1776 { 1777 boolean_t enable; 1778 int status; 1779 int ret; 1780 1781 if (strcasecmp(prop->p_value, "on") == 0) { 1782 (void) printf(gettext("Enabling %s privilege "), prop->p_name); 1783 enable = B_TRUE; 1784 } else { 1785 (void) printf(gettext("Disabling %s privilege "), prop->p_name); 1786 enable = B_FALSE; 1787 } 1788 1789 status = smb_lgrp_setpriv(gname, priv_id, enable); 1790 if (status == SMB_LGRP_SUCCESS) { 1791 (void) printf(gettext("succeeded\n")); 1792 ret = 0; 1793 } else { 1794 (void) printf(gettext("failed: %s\n"), 1795 smb_lgrp_strerror(status)); 1796 ret = 1; 1797 } 1798 1799 return (ret); 1800 } 1801 1802 static int 1803 smbadm_group_getpriv(char *gname, uint8_t priv_id, smbadm_prop_t *prop) 1804 { 1805 boolean_t enable; 1806 int status; 1807 1808 status = smb_lgrp_getpriv(gname, priv_id, &enable); 1809 if (status != SMB_LGRP_SUCCESS) { 1810 (void) fprintf(stderr, gettext("failed to get %s (%s)\n"), 1811 prop->p_name, smb_lgrp_strerror(status)); 1812 return (1); 1813 } 1814 1815 (void) printf(gettext("\t%s: %s\n"), prop->p_name, 1816 (enable) ? "On" : "Off"); 1817 1818 return (0); 1819 } 1820 1821 static int 1822 smbadm_setprop_tkowner(char *gname, smbadm_prop_t *prop) 1823 { 1824 return (smbadm_group_setpriv(gname, SE_TAKE_OWNERSHIP_LUID, prop)); 1825 } 1826 1827 static int 1828 smbadm_getprop_tkowner(char *gname, smbadm_prop_t *prop) 1829 { 1830 return (smbadm_group_getpriv(gname, SE_TAKE_OWNERSHIP_LUID, prop)); 1831 } 1832 1833 static int 1834 smbadm_setprop_readfile(char *gname, smbadm_prop_t *prop) 1835 { 1836 return (smbadm_group_setpriv(gname, SE_READ_FILE_LUID, prop)); 1837 } 1838 1839 static int 1840 smbadm_getprop_readfile(char *gname, smbadm_prop_t *prop) 1841 { 1842 return (smbadm_group_getpriv(gname, SE_READ_FILE_LUID, prop)); 1843 } 1844 1845 static int 1846 smbadm_setprop_writefile(char *gname, smbadm_prop_t *prop) 1847 { 1848 return (smbadm_group_setpriv(gname, SE_WRITE_FILE_LUID, prop)); 1849 } 1850 1851 static int 1852 smbadm_getprop_writefile(char *gname, smbadm_prop_t *prop) 1853 { 1854 return (smbadm_group_getpriv(gname, SE_WRITE_FILE_LUID, prop)); 1855 } 1856 1857 static int 1858 smbadm_setprop_backup(char *gname, smbadm_prop_t *prop) 1859 { 1860 return (smbadm_group_setpriv(gname, SE_BACKUP_LUID, prop)); 1861 } 1862 1863 static int 1864 smbadm_getprop_backup(char *gname, smbadm_prop_t *prop) 1865 { 1866 return (smbadm_group_getpriv(gname, SE_BACKUP_LUID, prop)); 1867 } 1868 1869 static int 1870 smbadm_setprop_restore(char *gname, smbadm_prop_t *prop) 1871 { 1872 return (smbadm_group_setpriv(gname, SE_RESTORE_LUID, prop)); 1873 } 1874 1875 static int 1876 smbadm_getprop_restore(char *gname, smbadm_prop_t *prop) 1877 { 1878 return (smbadm_group_getpriv(gname, SE_RESTORE_LUID, prop)); 1879 } 1880 1881 static boolean_t 1882 smbadm_chkprop_priv(smbadm_prop_t *prop) 1883 { 1884 if (prop->p_value == NULL || *prop->p_value == '\0') { 1885 (void) fprintf(stderr, 1886 gettext("missing value for '%s'\n"), prop->p_name); 1887 return (B_FALSE); 1888 } 1889 1890 if (strcasecmp(prop->p_value, "on") == 0) 1891 return (B_TRUE); 1892 1893 if (strcasecmp(prop->p_value, "off") == 0) 1894 return (B_TRUE); 1895 1896 (void) fprintf(stderr, 1897 gettext("%s: unrecognized value for '%s' property\n"), 1898 prop->p_value, prop->p_name); 1899 1900 return (B_FALSE); 1901 } 1902 1903 static const char * 1904 smbadm_pwd_strerror(int error) 1905 { 1906 switch (error) { 1907 case SMB_PWE_SUCCESS: 1908 return (gettext("Success.")); 1909 1910 case SMB_PWE_USER_UNKNOWN: 1911 return (gettext("User does not exist.")); 1912 1913 case SMB_PWE_USER_DISABLE: 1914 return (gettext("User is disabled.")); 1915 1916 case SMB_PWE_CLOSE_FAILED: 1917 case SMB_PWE_OPEN_FAILED: 1918 case SMB_PWE_WRITE_FAILED: 1919 case SMB_PWE_UPDATE_FAILED: 1920 return (gettext("Unexpected failure. " 1921 "SMB password database unchanged.")); 1922 1923 case SMB_PWE_STAT_FAILED: 1924 return (gettext("stat of SMB password file failed.")); 1925 1926 case SMB_PWE_BUSY: 1927 return (gettext("SMB password database busy. " 1928 "Try again later.")); 1929 1930 case SMB_PWE_DENIED: 1931 return (gettext("Operation not permitted.")); 1932 1933 case SMB_PWE_SYSTEM_ERROR: 1934 return (gettext("System error.")); 1935 1936 default: 1937 break; 1938 } 1939 1940 return (gettext("Unknown error code.")); 1941 } 1942 1943 /* 1944 * Enable libumem debugging by default on DEBUG builds. 1945 */ 1946 #ifdef DEBUG 1947 const char * 1948 _umem_debug_init(void) 1949 { 1950 return ("default,verbose"); /* $UMEM_DEBUG setting */ 1951 } 1952 1953 const char * 1954 _umem_logging_init(void) 1955 { 1956 return ("fail,contents"); /* $UMEM_LOGGING setting */ 1957 } 1958 #endif 1959