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