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