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