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 2015 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'e 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 */ 1412 sidstr = mname; 1413 rc = smb_lookup_sid(sidstr, &acct); 1414 if ((rc != 0) || (acct.a_status != NT_STATUS_SUCCESS)) 1415 acct.a_sidtype = SidTypeUnknown; 1416 } else { 1417 rc = smb_lookup_name(mname, SidTypeUnknown, &acct); 1418 if ((rc != 0) || (acct.a_status != NT_STATUS_SUCCESS)) { 1419 (void) fprintf(stderr, 1420 gettext("%s: name lookup failed\n"), mname); 1421 return (1); 1422 } 1423 sidstr = acct.a_sid; 1424 } 1425 1426 msid.gs_type = acct.a_sidtype; 1427 if ((msid.gs_sid = smb_sid_fromstr(sidstr)) == NULL) { 1428 (void) fprintf(stderr, 1429 gettext("%s: no memory for SID\n"), sidstr); 1430 return (1); 1431 } 1432 1433 switch (act) { 1434 case SMBADM_GRP_ADDMEMBER: 1435 act_str = gettext("add"); 1436 rc = smb_lgrp_add_member(gname, 1437 msid.gs_sid, msid.gs_type); 1438 break; 1439 case SMBADM_GRP_DELMEMBER: 1440 act_str = gettext("remove"); 1441 rc = smb_lgrp_del_member(gname, 1442 msid.gs_sid, msid.gs_type); 1443 break; 1444 default: 1445 rc = SMB_LGRP_INTERNAL_ERROR; 1446 break; 1447 } 1448 1449 smb_sid_free(msid.gs_sid); 1450 1451 if (rc != SMB_LGRP_SUCCESS) { 1452 (void) fprintf(stderr, 1453 gettext("failed to %s %s (%s)\n"), 1454 act_str, mname, smb_lgrp_strerror(rc)); 1455 return (1); 1456 } 1457 return (0); 1458 } 1459 1460 static int 1461 smbadm_user_disable(int argc, char **argv) 1462 { 1463 int error; 1464 char *user = NULL; 1465 1466 user = argv[optind]; 1467 if (optind >= argc || user == NULL || *user == '\0') { 1468 (void) fprintf(stderr, gettext("missing user name\n")); 1469 smbadm_usage(B_FALSE); 1470 } 1471 1472 error = smb_pwd_setcntl(user, SMB_PWC_DISABLE); 1473 if (error == SMB_PWE_SUCCESS) 1474 (void) printf(gettext("%s is disabled.\n"), user); 1475 else 1476 (void) fprintf(stderr, "%s\n", smbadm_pwd_strerror(error)); 1477 1478 return (error); 1479 } 1480 1481 static int 1482 smbadm_user_enable(int argc, char **argv) 1483 { 1484 int error; 1485 char *user = NULL; 1486 1487 user = argv[optind]; 1488 if (optind >= argc || user == NULL || *user == '\0') { 1489 (void) fprintf(stderr, gettext("missing user name\n")); 1490 smbadm_usage(B_FALSE); 1491 } 1492 1493 error = smb_pwd_setcntl(user, SMB_PWC_ENABLE); 1494 if (error == SMB_PWE_SUCCESS) 1495 (void) printf(gettext("%s is enabled.\n"), user); 1496 else 1497 (void) fprintf(stderr, "%s\n", smbadm_pwd_strerror(error)); 1498 1499 return (error); 1500 } 1501 1502 1503 int 1504 main(int argc, char **argv) 1505 { 1506 int ret; 1507 int i; 1508 1509 (void) setlocale(LC_ALL, ""); 1510 (void) textdomain(TEXT_DOMAIN); 1511 1512 (void) malloc(0); /* satisfy libumem dependency */ 1513 1514 progname = basename(argv[0]); 1515 1516 if (is_system_labeled()) { 1517 (void) fprintf(stderr, 1518 gettext("Trusted Extensions not supported\n")); 1519 return (1); 1520 } 1521 1522 if (argc < 2) { 1523 (void) fprintf(stderr, gettext("missing command\n")); 1524 smbadm_usage(B_FALSE); 1525 } 1526 1527 /* 1528 * Special case "cmd --help/-?" 1529 */ 1530 if (strcmp(argv[1], "-?") == 0 || 1531 strcmp(argv[1], "--help") == 0 || 1532 strcmp(argv[1], "-h") == 0) 1533 smbadm_usage(B_TRUE); 1534 1535 for (i = 0; i < SMBADM_NCMD; ++i) { 1536 curcmd = &smbadm_cmdtable[i]; 1537 if (strcasecmp(argv[1], curcmd->name) == 0) { 1538 if (argc > 2) { 1539 /* cmd subcmd --help/-? */ 1540 if (strcmp(argv[2], "-?") == 0 || 1541 strcmp(argv[2], "--help") == 0 || 1542 strcmp(argv[2], "-h") == 0) 1543 smbadm_usage(B_TRUE); 1544 } 1545 1546 if (!smbadm_checkauth(curcmd->auth)) { 1547 (void) fprintf(stderr, 1548 gettext("%s: %s: authorization denied\n"), 1549 progname, curcmd->name); 1550 return (1); 1551 } 1552 1553 if ((ret = smbadm_init()) != 0) 1554 return (ret); 1555 1556 ret = curcmd->func(argc - 1, &argv[1]); 1557 1558 smbadm_fini(); 1559 return (ret); 1560 } 1561 } 1562 1563 curcmd = NULL; 1564 (void) fprintf(stderr, gettext("unknown subcommand (%s)\n"), argv[1]); 1565 smbadm_usage(B_FALSE); 1566 return (2); 1567 } 1568 1569 static int 1570 smbadm_init(void) 1571 { 1572 int rc; 1573 1574 switch (curcmd->flags & SMBADM_CMDF_TYPEMASK) { 1575 case SMBADM_CMDF_GROUP: 1576 if ((rc = smb_lgrp_start()) != SMB_LGRP_SUCCESS) { 1577 (void) fprintf(stderr, 1578 gettext("failed to initialize (%s)\n"), 1579 smb_lgrp_strerror(rc)); 1580 return (1); 1581 } 1582 break; 1583 1584 case SMBADM_CMDF_USER: 1585 smb_pwd_init(B_FALSE); 1586 break; 1587 1588 default: 1589 break; 1590 } 1591 1592 return (0); 1593 } 1594 1595 static void 1596 smbadm_fini(void) 1597 { 1598 switch (curcmd->flags & SMBADM_CMDF_TYPEMASK) { 1599 case SMBADM_CMDF_GROUP: 1600 smb_lgrp_stop(); 1601 break; 1602 1603 case SMBADM_CMDF_USER: 1604 smb_pwd_fini(); 1605 break; 1606 1607 default: 1608 break; 1609 } 1610 } 1611 1612 static boolean_t 1613 smbadm_checkauth(const char *auth) 1614 { 1615 struct passwd *pw; 1616 1617 if ((pw = getpwuid(getuid())) == NULL) 1618 return (B_FALSE); 1619 1620 if (chkauthattr(auth, pw->pw_name) == 0) 1621 return (B_FALSE); 1622 1623 return (B_TRUE); 1624 } 1625 1626 static boolean_t 1627 smbadm_prop_validate(smbadm_prop_t *prop, boolean_t chkval) 1628 { 1629 smbadm_prop_handle_t *pinfo; 1630 int i; 1631 1632 for (i = 0; i < SMBADM_NPROP; i++) { 1633 pinfo = &smbadm_ptable[i]; 1634 if (strcmp(pinfo->p_name, prop->p_name) == 0) { 1635 if (pinfo->p_chkfn && chkval) 1636 return (pinfo->p_chkfn(prop)); 1637 1638 return (B_TRUE); 1639 } 1640 } 1641 1642 (void) fprintf(stderr, gettext("unrecognized property '%s'\n"), 1643 prop->p_name); 1644 1645 return (B_FALSE); 1646 } 1647 1648 static int 1649 smbadm_prop_parse(char *arg, smbadm_prop_t *prop) 1650 { 1651 boolean_t parse_value; 1652 char *equal; 1653 1654 if (arg == NULL) 1655 return (2); 1656 1657 prop->p_name = prop->p_value = NULL; 1658 1659 if (strcmp(curcmd->name, "set") == 0) 1660 parse_value = B_TRUE; 1661 else 1662 parse_value = B_FALSE; 1663 1664 prop->p_name = arg; 1665 1666 if (parse_value) { 1667 equal = strchr(arg, '='); 1668 if (equal == NULL) 1669 return (2); 1670 1671 *equal++ = '\0'; 1672 prop->p_value = equal; 1673 } 1674 1675 if (smbadm_prop_validate(prop, parse_value) == B_FALSE) 1676 return (2); 1677 1678 return (0); 1679 } 1680 1681 static smbadm_prop_handle_t * 1682 smbadm_prop_gethandle(char *pname) 1683 { 1684 int i; 1685 1686 for (i = 0; i < SMBADM_NPROP; i++) 1687 if (strcmp(pname, smbadm_ptable[i].p_name) == 0) 1688 return (&smbadm_ptable[i]); 1689 1690 return (NULL); 1691 } 1692 1693 static int 1694 smbadm_setprop_desc(char *gname, smbadm_prop_t *prop) 1695 { 1696 int status; 1697 1698 status = smb_lgrp_setcmnt(gname, prop->p_value); 1699 if (status != SMB_LGRP_SUCCESS) { 1700 (void) fprintf(stderr, 1701 gettext("failed to modify the group description (%s)\n"), 1702 smb_lgrp_strerror(status)); 1703 return (1); 1704 } 1705 1706 (void) printf(gettext("%s: description modified\n"), gname); 1707 return (0); 1708 } 1709 1710 static int 1711 smbadm_getprop_desc(char *gname, smbadm_prop_t *prop) 1712 { 1713 char *cmnt = NULL; 1714 int status; 1715 1716 status = smb_lgrp_getcmnt(gname, &cmnt); 1717 if (status != SMB_LGRP_SUCCESS) { 1718 (void) fprintf(stderr, 1719 gettext("failed to get the group description (%s)\n"), 1720 smb_lgrp_strerror(status)); 1721 return (1); 1722 } 1723 1724 (void) printf(gettext("\t%s: %s\n"), prop->p_name, cmnt); 1725 free(cmnt); 1726 return (0); 1727 } 1728 1729 static int 1730 smbadm_group_setpriv(char *gname, uint8_t priv_id, smbadm_prop_t *prop) 1731 { 1732 boolean_t enable; 1733 int status; 1734 int ret; 1735 1736 if (strcasecmp(prop->p_value, "on") == 0) { 1737 (void) printf(gettext("Enabling %s privilege "), prop->p_name); 1738 enable = B_TRUE; 1739 } else { 1740 (void) printf(gettext("Disabling %s privilege "), prop->p_name); 1741 enable = B_FALSE; 1742 } 1743 1744 status = smb_lgrp_setpriv(gname, priv_id, enable); 1745 if (status == SMB_LGRP_SUCCESS) { 1746 (void) printf(gettext("succeeded\n")); 1747 ret = 0; 1748 } else { 1749 (void) printf(gettext("failed: %s\n"), 1750 smb_lgrp_strerror(status)); 1751 ret = 1; 1752 } 1753 1754 return (ret); 1755 } 1756 1757 static int 1758 smbadm_group_getpriv(char *gname, uint8_t priv_id, smbadm_prop_t *prop) 1759 { 1760 boolean_t enable; 1761 int status; 1762 1763 status = smb_lgrp_getpriv(gname, priv_id, &enable); 1764 if (status != SMB_LGRP_SUCCESS) { 1765 (void) fprintf(stderr, gettext("failed to get %s (%s)\n"), 1766 prop->p_name, smb_lgrp_strerror(status)); 1767 return (1); 1768 } 1769 1770 (void) printf(gettext("\t%s: %s\n"), prop->p_name, 1771 (enable) ? "On" : "Off"); 1772 1773 return (0); 1774 } 1775 1776 static int 1777 smbadm_setprop_tkowner(char *gname, smbadm_prop_t *prop) 1778 { 1779 return (smbadm_group_setpriv(gname, SE_TAKE_OWNERSHIP_LUID, prop)); 1780 } 1781 1782 static int 1783 smbadm_getprop_tkowner(char *gname, smbadm_prop_t *prop) 1784 { 1785 return (smbadm_group_getpriv(gname, SE_TAKE_OWNERSHIP_LUID, prop)); 1786 } 1787 1788 static int 1789 smbadm_setprop_backup(char *gname, smbadm_prop_t *prop) 1790 { 1791 return (smbadm_group_setpriv(gname, SE_BACKUP_LUID, prop)); 1792 } 1793 1794 static int 1795 smbadm_getprop_backup(char *gname, smbadm_prop_t *prop) 1796 { 1797 return (smbadm_group_getpriv(gname, SE_BACKUP_LUID, prop)); 1798 } 1799 1800 static int 1801 smbadm_setprop_restore(char *gname, smbadm_prop_t *prop) 1802 { 1803 return (smbadm_group_setpriv(gname, SE_RESTORE_LUID, prop)); 1804 } 1805 1806 static int 1807 smbadm_getprop_restore(char *gname, smbadm_prop_t *prop) 1808 { 1809 return (smbadm_group_getpriv(gname, SE_RESTORE_LUID, prop)); 1810 } 1811 1812 static boolean_t 1813 smbadm_chkprop_priv(smbadm_prop_t *prop) 1814 { 1815 if (prop->p_value == NULL || *prop->p_value == '\0') { 1816 (void) fprintf(stderr, 1817 gettext("missing value for '%s'\n"), prop->p_name); 1818 return (B_FALSE); 1819 } 1820 1821 if (strcasecmp(prop->p_value, "on") == 0) 1822 return (B_TRUE); 1823 1824 if (strcasecmp(prop->p_value, "off") == 0) 1825 return (B_TRUE); 1826 1827 (void) fprintf(stderr, 1828 gettext("%s: unrecognized value for '%s' property\n"), 1829 prop->p_value, prop->p_name); 1830 1831 return (B_FALSE); 1832 } 1833 1834 static const char * 1835 smbadm_pwd_strerror(int error) 1836 { 1837 switch (error) { 1838 case SMB_PWE_SUCCESS: 1839 return (gettext("Success.")); 1840 1841 case SMB_PWE_USER_UNKNOWN: 1842 return (gettext("User does not exist.")); 1843 1844 case SMB_PWE_USER_DISABLE: 1845 return (gettext("User is disabled.")); 1846 1847 case SMB_PWE_CLOSE_FAILED: 1848 case SMB_PWE_OPEN_FAILED: 1849 case SMB_PWE_WRITE_FAILED: 1850 case SMB_PWE_UPDATE_FAILED: 1851 return (gettext("Unexpected failure. " 1852 "SMB password database unchanged.")); 1853 1854 case SMB_PWE_STAT_FAILED: 1855 return (gettext("stat of SMB password file failed.")); 1856 1857 case SMB_PWE_BUSY: 1858 return (gettext("SMB password database busy. " 1859 "Try again later.")); 1860 1861 case SMB_PWE_DENIED: 1862 return (gettext("Operation not permitted.")); 1863 1864 case SMB_PWE_SYSTEM_ERROR: 1865 return (gettext("System error.")); 1866 1867 default: 1868 break; 1869 } 1870 1871 return (gettext("Unknown error code.")); 1872 } 1873 1874 /* 1875 * Enable libumem debugging by default on DEBUG builds. 1876 */ 1877 #ifdef DEBUG 1878 const char * 1879 _umem_debug_init(void) 1880 { 1881 return ("default,verbose"); /* $UMEM_DEBUG setting */ 1882 } 1883 1884 const char * 1885 _umem_logging_init(void) 1886 { 1887 return ("fail,contents"); /* $UMEM_LOGGING setting */ 1888 } 1889 #endif 1890