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