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