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