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 (void) fprintf(stderr, gettext("Please refer to the system log" 607 " for more information.\n")); 608 bzero(&jdi, sizeof (jdi)); 609 return (1); 610 } 611 } 612 613 /* 614 * We want to process the user and domain names as separate strings. 615 * Check for names of the forms below and separate the components as 616 * required. 617 * 618 * name@domain 619 * domain\name 620 * domain/name 621 * 622 * If we encounter any of the forms above in arg, the @, / or \ 623 * separator is replaced by \0 and the username and domain pointers 624 * are changed to point to the appropriate components (in arg). 625 * 626 * If none of the separators are encountered, the username and domain 627 * pointers remain unchanged. 628 */ 629 static void 630 smbadm_extract_domain(char *arg, char **username, char **domain) 631 { 632 char *p; 633 634 if ((p = strpbrk(arg, "/\\@")) != NULL) { 635 if (*p == '@') { 636 *p = '\0'; 637 ++p; 638 639 if (strchr(arg, '+') != NULL) 640 return; 641 642 *domain = p; 643 *username = arg; 644 } else { 645 *p = '\0'; 646 ++p; 647 *username = p; 648 *domain = arg; 649 } 650 } 651 } 652 653 /* 654 * Check a domain name for RFC 1035 and 1123 compliance. Domain names may 655 * contain alphanumeric characters, hyphens and dots. The first and last 656 * character of a label must be alphanumeric. Interior characters may be 657 * alphanumeric or hypens. 658 * 659 * Domain names should not contain underscores but we allow them because 660 * Windows names are often in non-compliance with this rule. 661 */ 662 static boolean_t 663 smbadm_valid_domainname(const char *domain) 664 { 665 boolean_t new_label = B_TRUE; 666 const char *p; 667 char label_terminator; 668 669 if (domain == NULL || *domain == '\0') 670 return (B_FALSE); 671 672 label_terminator = *domain; 673 674 for (p = domain; *p != '\0'; ++p) { 675 if (new_label) { 676 if (!isalnum(*p)) 677 return (B_FALSE); 678 new_label = B_FALSE; 679 label_terminator = *p; 680 continue; 681 } 682 683 if (*p == '.') { 684 if (!isalnum(label_terminator)) 685 return (B_FALSE); 686 new_label = B_TRUE; 687 label_terminator = *p; 688 continue; 689 } 690 691 label_terminator = *p; 692 693 if (isalnum(*p) || *p == '-' || *p == '_') 694 continue; 695 696 return (B_FALSE); 697 } 698 699 if (!isalnum(label_terminator)) 700 return (B_FALSE); 701 return (B_TRUE); 702 } 703 704 /* 705 * Windows user names cannot contain the following characters 706 * or control characters. 707 * 708 * " / \ [ ] < > + ; , ? * = @ 709 */ 710 static boolean_t 711 smbadm_valid_username(const char *username) 712 { 713 const char *invalid = "\"/\\[]<>+;,?*=@"; 714 const char *p; 715 716 if (username == NULL) 717 return (B_FALSE); 718 719 if (strpbrk(username, invalid)) 720 return (B_FALSE); 721 722 for (p = username; *p != '\0'; p++) { 723 if (iscntrl(*p)) 724 return (B_FALSE); 725 } 726 727 return (B_TRUE); 728 } 729 730 /* 731 * A workgroup name can contain 1 to 15 characters but cannot be the same 732 * as the NetBIOS name. The name must begin with a letter or number. 733 * 734 * The name cannot consist entirely of spaces or dots, which is covered 735 * by the requirement that the name must begin with an alphanumeric 736 * character. 737 * 738 * The name must not contain any of the following characters or control 739 * characters. 740 * 741 * " / \ [ ] : | < > + = ; , ? 742 */ 743 static boolean_t 744 smbadm_valid_workgroup(const char *workgroup) 745 { 746 char netbiosname[NETBIOS_NAME_SZ]; 747 const char *invalid = "\"/\\[]:|<>+=;,?"; 748 const char *p; 749 750 if (workgroup == NULL || *workgroup == '\0' || (!isalnum(*workgroup))) 751 return (B_FALSE); 752 753 if (strlen(workgroup) >= NETBIOS_NAME_SZ) 754 return (B_FALSE); 755 756 if (smb_getnetbiosname(netbiosname, NETBIOS_NAME_SZ) == 0) { 757 if (utf8_strcasecmp(workgroup, netbiosname) == 0) 758 return (B_FALSE); 759 } 760 761 if (strpbrk(workgroup, invalid)) 762 return (B_FALSE); 763 764 for (p = workgroup; *p != '\0'; p++) { 765 if (iscntrl(*p)) 766 return (B_FALSE); 767 } 768 769 return (B_TRUE); 770 } 771 772 /* 773 * smbadm_list 774 * 775 * Displays current security mode and domain/workgroup name. 776 */ 777 /*ARGSUSED*/ 778 static int 779 smbadm_list(int argc, char **argv) 780 { 781 char domain[MAXHOSTNAMELEN]; 782 char fqdn[MAXHOSTNAMELEN]; 783 char srvname[MAXHOSTNAMELEN]; 784 char modename[16]; 785 int rc; 786 smb_inaddr_t srvipaddr; 787 char ipstr[INET6_ADDRSTRLEN]; 788 789 rc = smb_config_getstr(SMB_CI_SECURITY, modename, sizeof (modename)); 790 if (rc != SMBD_SMF_OK) { 791 (void) fprintf(stderr, 792 gettext("cannot determine the operational mode\n")); 793 return (1); 794 } 795 796 if (smb_getdomainname(domain, sizeof (domain)) != 0) { 797 (void) fprintf(stderr, gettext("failed to get the %s name\n"), 798 modename); 799 return (1); 800 } 801 802 if (strcmp(modename, "workgroup") == 0) { 803 (void) printf(gettext("[*] [%s]\n"), domain); 804 return (0); 805 } 806 807 (void) printf(gettext("[*] [%s]\n"), domain); 808 if ((smb_getfqdomainname(fqdn, sizeof (fqdn)) == 0) && (*fqdn != '\0')) 809 (void) printf(gettext("[*] [%s]\n"), fqdn); 810 811 if ((smb_get_dcinfo(srvname, MAXHOSTNAMELEN, &srvipaddr) 812 == NT_STATUS_SUCCESS) && (*srvname != '\0') && 813 (!smb_inet_iszero(&srvipaddr))) { 814 (void) smb_inet_ntop(&srvipaddr, ipstr, 815 SMB_IPSTRLEN(srvipaddr.a_family)); 816 (void) printf(gettext("\t[+%s.%s] [%s]\n"), 817 srvname, fqdn, ipstr); 818 } 819 820 smb_domain_show(); 821 return (0); 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 if (getgrnam(gname) == NULL) { 855 (void) fprintf(stderr, 856 gettext("failed to get the Solaris group '%s'\n"), gname); 857 (void) fprintf(stderr, 858 gettext("use 'groupadd' to add '%s'\n"), gname); 859 return (1); 860 } 861 862 status = smb_lgrp_add(gname, desc); 863 if (status != SMB_LGRP_SUCCESS) { 864 (void) fprintf(stderr, 865 gettext("failed to create the group (%s)\n"), 866 smb_lgrp_strerror(status)); 867 } else { 868 (void) printf(gettext("'%s' created.\n"), 869 gname); 870 } 871 872 return (status); 873 } 874 875 /* 876 * smbadm_group_dump_members 877 * 878 * Dump group members details. 879 */ 880 static void 881 smbadm_group_dump_members(smb_gsid_t *members, int num) 882 { 883 char sidstr[SMB_SID_STRSZ]; 884 int i; 885 886 if (num == 0) { 887 (void) printf(gettext("\tNo members\n")); 888 return; 889 } 890 891 (void) printf(gettext("\tMembers:\n")); 892 for (i = 0; i < num; i++) { 893 *sidstr = '\0'; 894 if (smb_lookup_sid(members[i].gs_sid, sidstr, 895 sizeof (sidstr)) == NT_STATUS_SUCCESS) 896 (void) printf(gettext("\t\t%s\n"), sidstr); 897 else 898 (void) printf(gettext("\t\tinvalid SID\n")); 899 } 900 } 901 902 /* 903 * smbadm_group_dump_privs 904 * 905 * Dump group privilege details. 906 */ 907 static void 908 smbadm_group_dump_privs(smb_privset_t *privs) 909 { 910 smb_privinfo_t *pinfo; 911 char *pstatus; 912 int i; 913 914 (void) printf(gettext("\tPrivileges: \n")); 915 916 for (i = 0; i < privs->priv_cnt; i++) { 917 pinfo = smb_priv_getbyvalue(privs->priv[i].luid.lo_part); 918 if ((pinfo == NULL) || (pinfo->flags & PF_PRESENTABLE) == 0) 919 continue; 920 921 switch (privs->priv[i].attrs) { 922 case SE_PRIVILEGE_ENABLED: 923 pstatus = "On"; 924 break; 925 case SE_PRIVILEGE_DISABLED: 926 pstatus = "Off"; 927 break; 928 default: 929 pstatus = "Unknown"; 930 break; 931 } 932 (void) printf(gettext("\t\t%s: %s\n"), pinfo->name, pstatus); 933 } 934 935 if (privs->priv_cnt == 0) 936 (void) printf(gettext("\t\tNo privileges\n")); 937 } 938 939 /* 940 * smbadm_group_dump 941 * 942 * Dump group details. 943 */ 944 static void 945 smbadm_group_dump(smb_group_t *grp, boolean_t show_mem, boolean_t show_privs) 946 { 947 char sidstr[SMB_SID_STRSZ]; 948 949 (void) printf(gettext("%s (%s)\n"), grp->sg_name, grp->sg_cmnt); 950 951 smb_sid_tostr(grp->sg_id.gs_sid, sidstr); 952 (void) printf(gettext("\tSID: %s\n"), sidstr); 953 954 if (show_privs) 955 smbadm_group_dump_privs(grp->sg_privs); 956 957 if (show_mem) 958 smbadm_group_dump_members(grp->sg_members, grp->sg_nmembers); 959 } 960 961 /* 962 * smbadm_group_show 963 * 964 */ 965 static int 966 smbadm_group_show(int argc, char **argv) 967 { 968 char *gname = NULL; 969 boolean_t show_privs; 970 boolean_t show_members; 971 char option; 972 int status; 973 smb_group_t grp; 974 smb_giter_t gi; 975 976 show_privs = show_members = B_FALSE; 977 978 while ((option = getopt(argc, argv, "mp")) != -1) { 979 switch (option) { 980 case 'm': 981 show_members = B_TRUE; 982 break; 983 case 'p': 984 show_privs = B_TRUE; 985 break; 986 987 default: 988 smbadm_usage(B_FALSE); 989 } 990 } 991 992 gname = argv[optind]; 993 if (optind >= argc || gname == NULL || *gname == '\0') 994 gname = "*"; 995 996 if (strcmp(gname, "*")) { 997 status = smb_lgrp_getbyname(gname, &grp); 998 if (status == SMB_LGRP_SUCCESS) { 999 smbadm_group_dump(&grp, show_members, show_privs); 1000 smb_lgrp_free(&grp); 1001 } else { 1002 (void) fprintf(stderr, 1003 gettext("failed to find %s (%s)\n"), 1004 gname, smb_lgrp_strerror(status)); 1005 } 1006 return (status); 1007 } 1008 1009 if ((status = smb_lgrp_iteropen(&gi)) != SMB_LGRP_SUCCESS) { 1010 (void) fprintf(stderr, gettext("failed to list groups (%s)\n"), 1011 smb_lgrp_strerror(status)); 1012 return (status); 1013 } 1014 1015 while ((status = smb_lgrp_iterate(&gi, &grp)) == SMB_LGRP_SUCCESS) { 1016 smbadm_group_dump(&grp, show_members, show_privs); 1017 smb_lgrp_free(&grp); 1018 } 1019 1020 smb_lgrp_iterclose(&gi); 1021 1022 if (status != SMB_LGRP_NO_MORE) { 1023 (void) fprintf(stderr, 1024 gettext("failed to get all the groups (%s)\n"), 1025 smb_lgrp_strerror(status)); 1026 return (status); 1027 } 1028 1029 return (0); 1030 } 1031 1032 /* 1033 * smbadm_group_delete 1034 */ 1035 static int 1036 smbadm_group_delete(int argc, char **argv) 1037 { 1038 char *gname = NULL; 1039 int status; 1040 1041 gname = argv[optind]; 1042 if (optind >= argc || gname == NULL || *gname == '\0') { 1043 (void) fprintf(stderr, gettext("missing group name\n")); 1044 smbadm_usage(B_FALSE); 1045 } 1046 1047 status = smb_lgrp_delete(gname); 1048 if (status != SMB_LGRP_SUCCESS) { 1049 (void) fprintf(stderr, 1050 gettext("failed to delete %s (%s)\n"), gname, 1051 smb_lgrp_strerror(status)); 1052 } else { 1053 (void) printf(gettext("%s deleted.\n"), gname); 1054 } 1055 1056 return (status); 1057 } 1058 1059 /* 1060 * smbadm_group_rename 1061 */ 1062 static int 1063 smbadm_group_rename(int argc, char **argv) 1064 { 1065 char *gname = NULL; 1066 char *ngname = NULL; 1067 int status; 1068 1069 gname = argv[optind]; 1070 if (optind++ >= argc || gname == NULL || *gname == '\0') { 1071 (void) fprintf(stderr, gettext("missing group name\n")); 1072 smbadm_usage(B_FALSE); 1073 } 1074 1075 ngname = argv[optind]; 1076 if (optind >= argc || ngname == NULL || *ngname == '\0') { 1077 (void) fprintf(stderr, gettext("missing new group name\n")); 1078 smbadm_usage(B_FALSE); 1079 } 1080 1081 if (getgrnam(ngname) == NULL) { 1082 (void) fprintf(stderr, 1083 gettext("failed to get the Solaris group '%s'\n"), ngname); 1084 (void) fprintf(stderr, 1085 gettext("use 'groupadd' to add '%s'\n"), ngname); 1086 return (1); 1087 } 1088 1089 status = smb_lgrp_rename(gname, ngname); 1090 if (status != SMB_LGRP_SUCCESS) { 1091 if (status == SMB_LGRP_EXISTS) 1092 (void) fprintf(stderr, 1093 gettext("failed to rename '%s' (%s already " 1094 "exists)\n"), gname, ngname); 1095 else 1096 (void) fprintf(stderr, 1097 gettext("failed to rename '%s' (%s)\n"), gname, 1098 smb_lgrp_strerror(status)); 1099 } else { 1100 (void) printf(gettext("'%s' renamed to '%s'\n"), gname, ngname); 1101 } 1102 1103 return (status); 1104 } 1105 1106 /* 1107 * smbadm_group_setprop 1108 * 1109 * Set the group properties. 1110 */ 1111 static int 1112 smbadm_group_setprop(int argc, char **argv) 1113 { 1114 char *gname = NULL; 1115 smbadm_prop_t props[SMBADM_NPROP]; 1116 smbadm_prop_handle_t *phandle; 1117 char option; 1118 int pcnt = 0; 1119 int ret; 1120 int p; 1121 1122 bzero(props, SMBADM_NPROP * sizeof (smbadm_prop_t)); 1123 1124 while ((option = getopt(argc, argv, "p:")) != -1) { 1125 switch (option) { 1126 case 'p': 1127 if (pcnt >= SMBADM_NPROP) { 1128 (void) fprintf(stderr, 1129 gettext("exceeded number of supported" 1130 " properties\n")); 1131 smbadm_usage(B_FALSE); 1132 } 1133 1134 if (smbadm_prop_parse(optarg, &props[pcnt++]) != 0) 1135 smbadm_usage(B_FALSE); 1136 break; 1137 1138 default: 1139 smbadm_usage(B_FALSE); 1140 } 1141 } 1142 1143 if (pcnt == 0) { 1144 (void) fprintf(stderr, 1145 gettext("missing property=value argument\n")); 1146 smbadm_usage(B_FALSE); 1147 } 1148 1149 gname = argv[optind]; 1150 if (optind >= argc || gname == NULL || *gname == '\0') { 1151 (void) fprintf(stderr, gettext("missing group name\n")); 1152 smbadm_usage(B_FALSE); 1153 } 1154 1155 for (p = 0; p < pcnt; p++) { 1156 phandle = smbadm_prop_gethandle(props[p].p_name); 1157 if (phandle) { 1158 if (phandle->p_setfn(gname, &props[p]) != 0) 1159 ret = 1; 1160 } 1161 } 1162 1163 return (ret); 1164 } 1165 1166 /* 1167 * smbadm_group_getprop 1168 * 1169 * Get the group properties. 1170 */ 1171 static int 1172 smbadm_group_getprop(int argc, char **argv) 1173 { 1174 char *gname = NULL; 1175 smbadm_prop_t props[SMBADM_NPROP]; 1176 smbadm_prop_handle_t *phandle; 1177 char option; 1178 int pcnt = 0; 1179 int ret; 1180 int p; 1181 1182 bzero(props, SMBADM_NPROP * sizeof (smbadm_prop_t)); 1183 1184 while ((option = getopt(argc, argv, "p:")) != -1) { 1185 switch (option) { 1186 case 'p': 1187 if (pcnt >= SMBADM_NPROP) { 1188 (void) fprintf(stderr, 1189 gettext("exceeded number of supported" 1190 " properties\n")); 1191 smbadm_usage(B_FALSE); 1192 } 1193 1194 if (smbadm_prop_parse(optarg, &props[pcnt++]) != 0) 1195 smbadm_usage(B_FALSE); 1196 break; 1197 1198 default: 1199 smbadm_usage(B_FALSE); 1200 } 1201 } 1202 1203 gname = argv[optind]; 1204 if (optind >= argc || gname == NULL || *gname == '\0') { 1205 (void) fprintf(stderr, gettext("missing group name\n")); 1206 smbadm_usage(B_FALSE); 1207 } 1208 1209 if (pcnt == 0) { 1210 /* 1211 * If no property has be specified then get 1212 * all the properties. 1213 */ 1214 pcnt = SMBADM_NPROP; 1215 for (p = 0; p < pcnt; p++) 1216 props[p].p_name = smbadm_ptable[p].p_name; 1217 } 1218 1219 for (p = 0; p < pcnt; p++) { 1220 phandle = smbadm_prop_gethandle(props[p].p_name); 1221 if (phandle) { 1222 if (phandle->p_getfn(gname, &props[p]) != 0) 1223 ret = 1; 1224 } 1225 } 1226 1227 return (ret); 1228 } 1229 1230 /* 1231 * smbadm_group_addmember 1232 * 1233 */ 1234 static int 1235 smbadm_group_addmember(int argc, char **argv) 1236 { 1237 char *gname = NULL; 1238 char **mname; 1239 char option; 1240 smb_gsid_t msid; 1241 int status; 1242 int mcnt = 0; 1243 int ret = 0; 1244 int i; 1245 1246 1247 mname = (char **)malloc(argc * sizeof (char *)); 1248 if (mname == NULL) { 1249 warn(gettext("failed to add group member")); 1250 return (1); 1251 } 1252 bzero(mname, argc * sizeof (char *)); 1253 1254 while ((option = getopt(argc, argv, "m:")) != -1) { 1255 switch (option) { 1256 case 'm': 1257 mname[mcnt++] = optarg; 1258 break; 1259 1260 default: 1261 free(mname); 1262 smbadm_usage(B_FALSE); 1263 } 1264 } 1265 1266 if (mcnt == 0) { 1267 (void) fprintf(stderr, gettext("missing member name\n")); 1268 free(mname); 1269 smbadm_usage(B_FALSE); 1270 } 1271 1272 gname = argv[optind]; 1273 if (optind >= argc || gname == NULL || *gname == 0) { 1274 (void) fprintf(stderr, gettext("missing group name\n")); 1275 free(mname); 1276 smbadm_usage(B_FALSE); 1277 } 1278 1279 1280 for (i = 0; i < mcnt; i++) { 1281 if (mname[i] == NULL) 1282 continue; 1283 1284 if (smb_lookup_name(mname[i], &msid) != NT_STATUS_SUCCESS) { 1285 (void) fprintf(stderr, 1286 gettext("failed to add %s: unable to obtain SID\n"), 1287 mname[i]); 1288 continue; 1289 } 1290 1291 status = smb_lgrp_add_member(gname, msid.gs_sid, msid.gs_type); 1292 free(msid.gs_sid); 1293 if (status != SMB_LGRP_SUCCESS) { 1294 (void) fprintf(stderr, 1295 gettext("failed to add %s (%s)\n"), 1296 mname[i], smb_lgrp_strerror(status)); 1297 ret = 1; 1298 } else { 1299 (void) printf(gettext("'%s' is now a member of '%s'\n"), 1300 mname[i], gname); 1301 } 1302 } 1303 1304 free(mname); 1305 return (ret); 1306 } 1307 1308 /* 1309 * smbadm_group_delmember 1310 */ 1311 static int 1312 smbadm_group_delmember(int argc, char **argv) 1313 { 1314 char *gname = NULL; 1315 char **mname; 1316 char option; 1317 smb_gsid_t msid; 1318 int status; 1319 int mcnt = 0; 1320 int ret = 0; 1321 int i; 1322 1323 mname = (char **)malloc(argc * sizeof (char *)); 1324 if (mname == NULL) { 1325 warn(gettext("failed to delete group member")); 1326 return (1); 1327 } 1328 bzero(mname, argc * sizeof (char *)); 1329 1330 while ((option = getopt(argc, argv, "m:")) != -1) { 1331 switch (option) { 1332 case 'm': 1333 mname[mcnt++] = optarg; 1334 break; 1335 1336 default: 1337 free(mname); 1338 smbadm_usage(B_FALSE); 1339 } 1340 } 1341 1342 if (mcnt == 0) { 1343 (void) fprintf(stderr, gettext("missing member name\n")); 1344 free(mname); 1345 smbadm_usage(B_FALSE); 1346 } 1347 1348 gname = argv[optind]; 1349 if (optind >= argc || gname == NULL || *gname == 0) { 1350 (void) fprintf(stderr, gettext("missing group name\n")); 1351 free(mname); 1352 smbadm_usage(B_FALSE); 1353 } 1354 1355 1356 for (i = 0; i < mcnt; i++) { 1357 if (mname[i] == NULL) 1358 continue; 1359 1360 if (smb_lookup_name(mname[i], &msid) != NT_STATUS_SUCCESS) { 1361 (void) fprintf(stderr, 1362 gettext("failed to remove %s: " 1363 "unable to obtain SID\n"), 1364 mname[i]); 1365 continue; 1366 } 1367 1368 status = smb_lgrp_del_member(gname, msid.gs_sid, msid.gs_type); 1369 free(msid.gs_sid); 1370 if (status != SMB_LGRP_SUCCESS) { 1371 (void) fprintf(stderr, 1372 gettext("failed to remove %s (%s)\n"), 1373 mname[i], smb_lgrp_strerror(status)); 1374 ret = 1; 1375 } else { 1376 (void) printf( 1377 gettext("'%s' has been removed from %s\n"), 1378 mname[i], gname); 1379 } 1380 } 1381 1382 return (ret); 1383 } 1384 1385 static int 1386 smbadm_user_disable(int argc, char **argv) 1387 { 1388 int error; 1389 char *user = NULL; 1390 1391 user = argv[optind]; 1392 if (optind >= argc || user == NULL || *user == '\0') { 1393 (void) fprintf(stderr, gettext("missing user name\n")); 1394 smbadm_usage(B_FALSE); 1395 } 1396 1397 error = smb_pwd_setcntl(user, SMB_PWC_DISABLE); 1398 if (error == SMB_PWE_SUCCESS) 1399 (void) printf(gettext("%s is disabled.\n"), user); 1400 else 1401 (void) fprintf(stderr, "%s\n", smbadm_pwd_strerror(error)); 1402 1403 return (error); 1404 } 1405 1406 static int 1407 smbadm_user_enable(int argc, char **argv) 1408 { 1409 int error; 1410 char *user = NULL; 1411 1412 user = argv[optind]; 1413 if (optind >= argc || user == NULL || *user == '\0') { 1414 (void) fprintf(stderr, gettext("missing user name\n")); 1415 smbadm_usage(B_FALSE); 1416 } 1417 1418 error = smb_pwd_setcntl(user, SMB_PWC_ENABLE); 1419 if (error == SMB_PWE_SUCCESS) 1420 (void) printf(gettext("%s is enabled.\n"), user); 1421 else 1422 (void) fprintf(stderr, "%s\n", smbadm_pwd_strerror(error)); 1423 1424 return (error); 1425 } 1426 1427 1428 int 1429 main(int argc, char **argv) 1430 { 1431 int ret; 1432 int i; 1433 1434 (void) malloc(0); /* satisfy libumem dependency */ 1435 1436 progname = basename(argv[0]); 1437 1438 if (getzoneid() != GLOBAL_ZONEID) { 1439 (void) fprintf(stderr, 1440 gettext("cannot execute in non-global zone\n")); 1441 return (0); 1442 } 1443 1444 if (is_system_labeled()) { 1445 (void) fprintf(stderr, 1446 gettext("Trusted Extensions not supported\n")); 1447 return (0); 1448 } 1449 1450 if (argc < 2) { 1451 (void) fprintf(stderr, gettext("missing command\n")); 1452 smbadm_usage(B_FALSE); 1453 } 1454 1455 /* 1456 * Special case "cmd --help/-?" 1457 */ 1458 if (strcmp(argv[1], "-?") == 0 || 1459 strcmp(argv[1], "--help") == 0 || 1460 strcmp(argv[1], "-h") == 0) 1461 smbadm_usage(B_TRUE); 1462 1463 for (i = 0; i < SMBADM_NCMD; ++i) { 1464 curcmd = &smbadm_cmdtable[i]; 1465 if (strcasecmp(argv[1], curcmd->name) == 0) { 1466 if (argc > 2) { 1467 /* cmd subcmd --help/-? */ 1468 if (strcmp(argv[2], "-?") == 0 || 1469 strcmp(argv[2], "--help") == 0 || 1470 strcmp(argv[2], "-h") == 0) 1471 smbadm_usage(B_TRUE); 1472 } 1473 1474 if ((ret = smbadm_init()) != 0) 1475 return (ret); 1476 1477 ret = curcmd->func(argc - 1, &argv[1]); 1478 1479 smbadm_fini(); 1480 return (ret); 1481 } 1482 } 1483 1484 curcmd = NULL; 1485 (void) fprintf(stderr, gettext("unknown subcommand (%s)\n"), argv[1]); 1486 smbadm_usage(B_FALSE); 1487 return (2); 1488 } 1489 1490 static int 1491 smbadm_init(void) 1492 { 1493 int rc; 1494 1495 switch (curcmd->flags & SMBADM_CMDF_TYPEMASK) { 1496 case SMBADM_CMDF_GROUP: 1497 if (smb_idmap_start() != 0) { 1498 (void) fprintf(stderr, 1499 gettext("failed to contact idmap service\n")); 1500 return (1); 1501 } 1502 1503 if ((rc = smb_lgrp_start()) != SMB_LGRP_SUCCESS) { 1504 (void) fprintf(stderr, 1505 gettext("failed to initialize (%s)\n"), 1506 smb_lgrp_strerror(rc)); 1507 smb_idmap_stop(); 1508 return (1); 1509 } 1510 break; 1511 1512 case SMBADM_CMDF_USER: 1513 smb_pwd_init(B_FALSE); 1514 break; 1515 1516 default: 1517 break; 1518 } 1519 1520 return (0); 1521 } 1522 1523 static void 1524 smbadm_fini(void) 1525 { 1526 switch (curcmd->flags & SMBADM_CMDF_TYPEMASK) { 1527 case SMBADM_CMDF_GROUP: 1528 smb_lgrp_stop(); 1529 smb_idmap_stop(); 1530 break; 1531 1532 case SMBADM_CMDF_USER: 1533 smb_pwd_fini(); 1534 break; 1535 1536 default: 1537 break; 1538 } 1539 } 1540 1541 static boolean_t 1542 smbadm_prop_validate(smbadm_prop_t *prop, boolean_t chkval) 1543 { 1544 smbadm_prop_handle_t *pinfo; 1545 int i; 1546 1547 for (i = 0; i < SMBADM_NPROP; i++) { 1548 pinfo = &smbadm_ptable[i]; 1549 if (strcmp(pinfo->p_name, prop->p_name) == 0) { 1550 if (pinfo->p_chkfn && chkval) 1551 return (pinfo->p_chkfn(prop)); 1552 1553 return (B_TRUE); 1554 } 1555 } 1556 1557 (void) fprintf(stderr, gettext("unrecognized property '%s'\n"), 1558 prop->p_name); 1559 1560 return (B_FALSE); 1561 } 1562 1563 static int 1564 smbadm_prop_parse(char *arg, smbadm_prop_t *prop) 1565 { 1566 boolean_t parse_value; 1567 char *equal; 1568 1569 if (arg == NULL) 1570 return (2); 1571 1572 prop->p_name = prop->p_value = NULL; 1573 1574 if (strcmp(curcmd->name, "set") == 0) 1575 parse_value = B_TRUE; 1576 else 1577 parse_value = B_FALSE; 1578 1579 prop->p_name = arg; 1580 1581 if (parse_value) { 1582 equal = strchr(arg, '='); 1583 if (equal == NULL) 1584 return (2); 1585 1586 *equal++ = '\0'; 1587 prop->p_value = equal; 1588 } 1589 1590 if (smbadm_prop_validate(prop, parse_value) == B_FALSE) 1591 return (2); 1592 1593 return (0); 1594 } 1595 1596 static smbadm_prop_handle_t * 1597 smbadm_prop_gethandle(char *pname) 1598 { 1599 int i; 1600 1601 for (i = 0; i < SMBADM_NPROP; i++) 1602 if (strcmp(pname, smbadm_ptable[i].p_name) == 0) 1603 return (&smbadm_ptable[i]); 1604 1605 return (NULL); 1606 } 1607 1608 static int 1609 smbadm_setprop_desc(char *gname, smbadm_prop_t *prop) 1610 { 1611 int status; 1612 1613 status = smb_lgrp_setcmnt(gname, prop->p_value); 1614 if (status != SMB_LGRP_SUCCESS) { 1615 (void) fprintf(stderr, 1616 gettext("failed to modify the group description (%s)\n"), 1617 smb_lgrp_strerror(status)); 1618 return (1); 1619 } 1620 1621 (void) printf(gettext("%s: description modified\n"), gname); 1622 return (0); 1623 } 1624 1625 static int 1626 smbadm_getprop_desc(char *gname, smbadm_prop_t *prop) 1627 { 1628 char *cmnt = NULL; 1629 int status; 1630 1631 status = smb_lgrp_getcmnt(gname, &cmnt); 1632 if (status != SMB_LGRP_SUCCESS) { 1633 (void) fprintf(stderr, 1634 gettext("failed to get the group description (%s)\n"), 1635 smb_lgrp_strerror(status)); 1636 return (1); 1637 } 1638 1639 (void) printf(gettext("\t%s: %s\n"), prop->p_name, cmnt); 1640 free(cmnt); 1641 return (0); 1642 } 1643 1644 static int 1645 smbadm_group_setpriv(char *gname, uint8_t priv_id, smbadm_prop_t *prop) 1646 { 1647 boolean_t enable; 1648 int status; 1649 int ret; 1650 1651 if (strcasecmp(prop->p_value, "on") == 0) { 1652 (void) printf(gettext("Enabling %s privilege "), prop->p_name); 1653 enable = B_TRUE; 1654 } else { 1655 (void) printf(gettext("Disabling %s privilege "), prop->p_name); 1656 enable = B_FALSE; 1657 } 1658 1659 status = smb_lgrp_setpriv(gname, priv_id, enable); 1660 if (status == SMB_LGRP_SUCCESS) { 1661 (void) printf(gettext("succeeded\n")); 1662 ret = 0; 1663 } else { 1664 (void) printf(gettext("failed: %s\n"), 1665 smb_lgrp_strerror(status)); 1666 ret = 1; 1667 } 1668 1669 return (ret); 1670 } 1671 1672 static int 1673 smbadm_group_getpriv(char *gname, uint8_t priv_id, smbadm_prop_t *prop) 1674 { 1675 boolean_t enable; 1676 int status; 1677 1678 status = smb_lgrp_getpriv(gname, priv_id, &enable); 1679 if (status != SMB_LGRP_SUCCESS) { 1680 (void) fprintf(stderr, gettext("failed to get %s (%s)\n"), 1681 prop->p_name, smb_lgrp_strerror(status)); 1682 return (1); 1683 } 1684 1685 (void) printf(gettext("\t%s: %s\n"), prop->p_name, 1686 (enable) ? "On" : "Off"); 1687 1688 return (0); 1689 } 1690 1691 static int 1692 smbadm_setprop_tkowner(char *gname, smbadm_prop_t *prop) 1693 { 1694 return (smbadm_group_setpriv(gname, SE_TAKE_OWNERSHIP_LUID, prop)); 1695 } 1696 1697 static int 1698 smbadm_getprop_tkowner(char *gname, smbadm_prop_t *prop) 1699 { 1700 return (smbadm_group_getpriv(gname, SE_TAKE_OWNERSHIP_LUID, prop)); 1701 } 1702 1703 static int 1704 smbadm_setprop_backup(char *gname, smbadm_prop_t *prop) 1705 { 1706 return (smbadm_group_setpriv(gname, SE_BACKUP_LUID, prop)); 1707 } 1708 1709 static int 1710 smbadm_getprop_backup(char *gname, smbadm_prop_t *prop) 1711 { 1712 return (smbadm_group_getpriv(gname, SE_BACKUP_LUID, prop)); 1713 } 1714 1715 static int 1716 smbadm_setprop_restore(char *gname, smbadm_prop_t *prop) 1717 { 1718 return (smbadm_group_setpriv(gname, SE_RESTORE_LUID, prop)); 1719 } 1720 1721 static int 1722 smbadm_getprop_restore(char *gname, smbadm_prop_t *prop) 1723 { 1724 return (smbadm_group_getpriv(gname, SE_RESTORE_LUID, prop)); 1725 } 1726 1727 static boolean_t 1728 smbadm_chkprop_priv(smbadm_prop_t *prop) 1729 { 1730 if (prop->p_value == NULL || *prop->p_value == '\0') { 1731 (void) fprintf(stderr, 1732 gettext("missing value for '%s'\n"), prop->p_name); 1733 return (B_FALSE); 1734 } 1735 1736 if (strcasecmp(prop->p_value, "on") == 0) 1737 return (B_TRUE); 1738 1739 if (strcasecmp(prop->p_value, "off") == 0) 1740 return (B_TRUE); 1741 1742 (void) fprintf(stderr, 1743 gettext("%s: unrecognized value for '%s' property\n"), 1744 prop->p_value, prop->p_name); 1745 1746 return (B_FALSE); 1747 } 1748 1749 static const char * 1750 smbadm_pwd_strerror(int error) 1751 { 1752 switch (error) { 1753 case SMB_PWE_SUCCESS: 1754 return (gettext("Success.")); 1755 1756 case SMB_PWE_USER_UNKNOWN: 1757 return (gettext("User does not exist.")); 1758 1759 case SMB_PWE_USER_DISABLE: 1760 return (gettext("User is disabled.")); 1761 1762 case SMB_PWE_CLOSE_FAILED: 1763 case SMB_PWE_OPEN_FAILED: 1764 case SMB_PWE_WRITE_FAILED: 1765 case SMB_PWE_UPDATE_FAILED: 1766 return (gettext("Unexpected failure. " 1767 "SMB password database unchanged.")); 1768 1769 case SMB_PWE_STAT_FAILED: 1770 return (gettext("stat of SMB password file failed.")); 1771 1772 case SMB_PWE_BUSY: 1773 return (gettext("SMB password database busy. " 1774 "Try again later.")); 1775 1776 case SMB_PWE_DENIED: 1777 return (gettext("Operation not permitted.")); 1778 1779 case SMB_PWE_SYSTEM_ERROR: 1780 return (gettext("System error.")); 1781 1782 default: 1783 break; 1784 } 1785 1786 return (gettext("Unknown error code.")); 1787 } 1788 1789 /* 1790 * Enable libumem debugging by default on DEBUG builds. 1791 */ 1792 #ifdef DEBUG 1793 const char * 1794 _umem_debug_init(void) 1795 { 1796 return ("default,verbose"); /* $UMEM_DEBUG setting */ 1797 } 1798 1799 const char * 1800 _umem_logging_init(void) 1801 { 1802 return ("fail,contents"); /* $UMEM_LOGGING setting */ 1803 } 1804 #endif 1805