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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * This module contains smbadm CLI which offers smb configuration 30 * functionalities. 31 */ 32 #include <stdlib.h> 33 #include <stdio.h> 34 #include <syslog.h> 35 #include <strings.h> 36 #include <limits.h> 37 #include <getopt.h> 38 #include <libintl.h> 39 #include <zone.h> 40 #include <grp.h> 41 #include <libgen.h> 42 43 #include <smbsrv/libsmb.h> 44 45 typedef enum { 46 HELP_ADD_MEMBER, 47 HELP_CREATE, 48 HELP_DELETE, 49 HELP_DEL_MEMBER, 50 HELP_GET, 51 HELP_JOIN, 52 HELP_LIST, 53 HELP_RENAME, 54 HELP_SET, 55 HELP_SHOW, 56 HELP_UDISABLE, 57 HELP_UENABLE 58 } smbadm_help_t; 59 60 #define SMBADM_CMDF_GROUP 0x01 61 62 typedef struct smbadm_cmdinfo { 63 char *name; 64 int (*func)(int, char **); 65 smbadm_help_t usage; 66 uint32_t flags; 67 } smbadm_cmdinfo_t; 68 69 smbadm_cmdinfo_t *curcmd; 70 static char *progname; 71 72 static int smbadm_join(int, char **); 73 static int smbadm_list(int, char **); 74 static int smbadm_group_create(int, char **); 75 static int smbadm_group_delete(int, char **); 76 static int smbadm_group_rename(int, char **); 77 static int smbadm_group_show(int, char **); 78 static int smbadm_group_getprop(int, char **); 79 static int smbadm_group_setprop(int, char **); 80 static int smbadm_group_addmember(int, char **); 81 static int smbadm_group_delmember(int, char **); 82 static int smbadm_user_disable(int, char **); 83 static int smbadm_user_enable(int, char **); 84 85 static smbadm_cmdinfo_t smbadm_cmdtable[] = 86 { 87 { "add-member", smbadm_group_addmember, HELP_ADD_MEMBER, 88 SMBADM_CMDF_GROUP }, 89 { "create", smbadm_group_create, HELP_CREATE, 90 SMBADM_CMDF_GROUP }, 91 { "delete", smbadm_group_delete, HELP_DELETE, 92 SMBADM_CMDF_GROUP }, 93 { "disable-user", smbadm_user_disable, HELP_UDISABLE, 0 }, 94 { "enable-user", smbadm_user_enable, HELP_UENABLE, 0 }, 95 { "get", smbadm_group_getprop, HELP_GET, 96 SMBADM_CMDF_GROUP }, 97 { "join", smbadm_join, HELP_JOIN, 0 }, 98 { "list", smbadm_list, HELP_LIST, 0 }, 99 { "remove-member", smbadm_group_delmember, HELP_DEL_MEMBER, 100 SMBADM_CMDF_GROUP }, 101 { "rename", smbadm_group_rename, HELP_RENAME, 102 SMBADM_CMDF_GROUP }, 103 { "set", smbadm_group_setprop, HELP_SET, 104 SMBADM_CMDF_GROUP }, 105 { "show", smbadm_group_show, HELP_SHOW, 106 SMBADM_CMDF_GROUP }, 107 }; 108 109 #define SMBADM_NCMD (sizeof (smbadm_cmdtable) / sizeof (smbadm_cmdtable[0])) 110 111 typedef struct smbadm_prop { 112 char *p_name; 113 char *p_value; 114 } smbadm_prop_t; 115 116 typedef struct smbadm_prop_handle { 117 char *p_name; 118 char *p_dispvalue; 119 int (*p_setfn)(char *, smbadm_prop_t *); 120 int (*p_getfn)(char *, smbadm_prop_t *); 121 boolean_t (*p_chkfn)(smbadm_prop_t *); 122 } smbadm_prop_handle_t; 123 124 static boolean_t smbadm_prop_validate(smbadm_prop_t *prop, boolean_t chkval); 125 static int smbadm_prop_parse(char *arg, smbadm_prop_t *prop); 126 static smbadm_prop_handle_t *smbadm_prop_gethandle(char *pname); 127 128 static boolean_t smbadm_chkprop_priv(smbadm_prop_t *prop); 129 static int smbadm_setprop_tkowner(char *gname, smbadm_prop_t *prop); 130 static int smbadm_getprop_tkowner(char *gname, smbadm_prop_t *prop); 131 static int smbadm_setprop_backup(char *gname, smbadm_prop_t *prop); 132 static int smbadm_getprop_backup(char *gname, smbadm_prop_t *prop); 133 static int smbadm_setprop_restore(char *gname, smbadm_prop_t *prop); 134 static int smbadm_getprop_restore(char *gname, smbadm_prop_t *prop); 135 static int smbadm_setprop_desc(char *gname, smbadm_prop_t *prop); 136 static int smbadm_getprop_desc(char *gname, smbadm_prop_t *prop); 137 138 static smbadm_prop_handle_t smbadm_ptable[] = { 139 {"backup", "on | off", smbadm_setprop_backup, 140 smbadm_getprop_backup, smbadm_chkprop_priv }, 141 {"restore", "on | off", smbadm_setprop_restore, 142 smbadm_getprop_restore, smbadm_chkprop_priv }, 143 {"take-ownership", "on | off", smbadm_setprop_tkowner, 144 smbadm_getprop_tkowner, smbadm_chkprop_priv }, 145 {"description", "<string>", smbadm_setprop_desc, 146 smbadm_getprop_desc, NULL }, 147 }; 148 149 static int smbadm_grpcmd_init(void); 150 static void smbadm_grpcmd_fini(void); 151 static const char *smbadm_pwd_strerror(int error); 152 153 /* 154 * Number of supported properties 155 */ 156 #define SMBADM_NPROP (sizeof (smbadm_ptable) / sizeof (smbadm_ptable[0])) 157 158 static void 159 smbadm_cmdusage(FILE *fp, smbadm_cmdinfo_t *cmd) 160 { 161 switch (cmd->usage) { 162 case HELP_ADD_MEMBER: 163 (void) fprintf(fp, 164 gettext("\t%s -m member [[-m member] ...] group\n"), 165 cmd->name); 166 return; 167 168 case HELP_CREATE: 169 (void) fprintf(fp, gettext("\t%s [-d description] group\n"), 170 cmd->name); 171 return; 172 173 case HELP_DELETE: 174 (void) fprintf(fp, gettext("\t%s group\n"), cmd->name); 175 return; 176 177 case HELP_UDISABLE: 178 case HELP_UENABLE: 179 (void) fprintf(fp, gettext("\t%s user\n"), cmd->name); 180 return; 181 182 case HELP_GET: 183 (void) fprintf(fp, gettext("\t%s [[-p property] ...] group\n"), 184 cmd->name); 185 return; 186 187 case HELP_JOIN: 188 (void) fprintf(fp, gettext("\t%s -u username domain\n" 189 "\t%s -w workgroup\n"), cmd->name, cmd->name); 190 return; 191 192 case HELP_LIST: 193 (void) fprintf(fp, gettext("\t%s\n"), cmd->name); 194 return; 195 196 case HELP_DEL_MEMBER: 197 (void) fprintf(fp, 198 gettext("\t%s -m member [[-m member] ...] group\n"), 199 cmd->name); 200 return; 201 202 case HELP_RENAME: 203 (void) fprintf(fp, gettext("\t%s group new-group\n"), 204 cmd->name); 205 return; 206 207 case HELP_SET: 208 (void) fprintf(fp, gettext("\t%s -p property=value " 209 "[[-p property=value] ...] group\n"), cmd->name); 210 return; 211 212 case HELP_SHOW: 213 (void) fprintf(fp, gettext("\t%s [-m] [-p] [group]\n"), 214 cmd->name); 215 return; 216 217 } 218 219 abort(); 220 /* NOTREACHED */ 221 } 222 223 static void 224 smbadm_usage(boolean_t requested) 225 { 226 FILE *fp = requested ? stdout : stderr; 227 boolean_t show_props = B_FALSE; 228 int i; 229 230 if (curcmd == NULL) { 231 (void) fprintf(fp, 232 gettext("usage: %s [-h | <command> [options]]\n"), 233 progname); 234 (void) fprintf(fp, 235 gettext("where 'command' is one of the following:\n\n")); 236 237 for (i = 0; i < SMBADM_NCMD; i++) 238 smbadm_cmdusage(fp, &smbadm_cmdtable[i]); 239 240 (void) fprintf(fp, 241 gettext("\nFor property list, run %s %s|%s\n"), 242 progname, "get", "set"); 243 244 exit(requested ? 0 : 2); 245 } 246 247 (void) fprintf(fp, gettext("usage:\n")); 248 smbadm_cmdusage(fp, curcmd); 249 250 if (strcmp(curcmd->name, "get") == 0 || 251 strcmp(curcmd->name, "set") == 0) 252 show_props = B_TRUE; 253 254 if (show_props) { 255 (void) fprintf(fp, 256 gettext("\nThe following properties are supported:\n")); 257 258 (void) fprintf(fp, "\n\t%-16s %s\n\n", 259 "PROPERTY", "VALUES"); 260 261 for (i = 0; i < SMBADM_NPROP; i++) { 262 (void) fprintf(fp, "\t%-16s %s\n", 263 smbadm_ptable[i].p_name, 264 smbadm_ptable[i].p_dispvalue); 265 } 266 } 267 268 exit(requested ? 0 : 2); 269 } 270 271 /* 272 * smbadm_join 273 * 274 * Join the given domain/workgroup 275 */ 276 static int 277 smbadm_join(int argc, char **argv) 278 { 279 char option; 280 smb_joininfo_t jdi; 281 boolean_t join_w = B_FALSE; 282 boolean_t join_d = B_FALSE; 283 uint32_t status; 284 char curdom[MAXHOSTNAMELEN]; 285 286 bzero(&jdi, sizeof (jdi)); 287 288 while ((option = getopt(argc, argv, "u:w:")) != -1) { 289 switch (option) { 290 case 'w': 291 (void) strlcpy(jdi.domain_name, optarg, 292 sizeof (jdi.domain_name)); 293 jdi.mode = SMB_SECMODE_WORKGRP; 294 join_w = B_TRUE; 295 break; 296 297 case 'u': 298 /* admin username */ 299 (void) strlcpy(jdi.domain_username, optarg, 300 sizeof (jdi.domain_username)); 301 jdi.mode = SMB_SECMODE_DOMAIN; 302 join_d = B_TRUE; 303 break; 304 305 default: 306 smbadm_usage(B_FALSE); 307 } 308 } 309 310 if (join_w && join_d) { 311 (void) fprintf(stderr, 312 gettext("domain and workgroup " 313 "can not be specified together\n")); 314 smbadm_usage(B_FALSE); 315 } 316 317 if (join_d && (argv[optind] != NULL)) { 318 (void) strlcpy(jdi.domain_name, argv[optind], 319 sizeof (jdi.domain_name)); 320 } 321 322 if (*jdi.domain_name == '\0') { 323 (void) fprintf(stderr, gettext("missing %s name\n"), 324 (join_d) ? "domain" : "workgroup"); 325 smbadm_usage(B_FALSE); 326 } 327 328 if (join_d && *jdi.domain_username == '\0') { 329 (void) fprintf(stderr, gettext("missing username\n")); 330 smbadm_usage(B_FALSE); 331 } 332 333 if (join_w) { 334 status = smb_join(&jdi); 335 if (status == NT_STATUS_SUCCESS) { 336 (void) printf( 337 gettext("Successfully joined workgroup '%s'\n"), 338 jdi.domain_name); 339 return (0); 340 } 341 342 (void) fprintf(stderr, 343 gettext("failed to join workgroup '%s' (%s)\n"), 344 jdi.domain_name, xlate_nt_status(status)); 345 346 return (1); 347 } 348 349 if (smb_config_get_secmode() == SMB_SECMODE_DOMAIN) { 350 (void) smb_getdomainname(curdom, MAXHOSTNAMELEN); 351 if (*curdom != 0 && strncasecmp(curdom, jdi.domain_name, 352 strlen(curdom))) { 353 char reply[8]; 354 355 (void) printf(gettext("This system has already " 356 "joined to '%s' domain.\n" 357 "Would you like to join the new domain " 358 "[yes/no]? "), 359 curdom); 360 (void) scanf("%8s", reply); 361 (void) trim_whitespace(reply); 362 if (strncasecmp(reply, "yes", 3) != 0) 363 return (0); 364 } 365 } 366 367 /* Join the domain */ 368 if (*jdi.domain_passwd == '\0') { 369 char *p = NULL; 370 char *prompt = gettext("Enter domain password: "); 371 p = getpassphrase(prompt); 372 if (!p) { 373 (void) fprintf(stderr, gettext("missing password\n")); 374 smbadm_usage(B_FALSE); 375 } 376 377 (void) strlcpy(jdi.domain_passwd, p, 378 sizeof (jdi.domain_passwd)); 379 } 380 381 (void) printf(gettext("Joining '%s' ... this may take a minute ...\n"), 382 jdi.domain_name); 383 384 status = smb_join(&jdi); 385 386 switch (status) { 387 case NT_STATUS_SUCCESS: 388 (void) printf(gettext("Successfully joined domain '%s'\n"), 389 jdi.domain_name); 390 391 return (0); 392 393 case NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND: 394 (void) fprintf(stderr, gettext("failed to find " 395 "any domain controllers for '%s'\n"), 396 jdi.domain_name); 397 break; 398 399 default: 400 (void) fprintf(stderr, 401 gettext("failed to join domain '%s' (%s)\n"), 402 jdi.domain_name, xlate_nt_status(status)); 403 } 404 405 return (1); 406 } 407 408 /* 409 * smbadm_list 410 * 411 * Displays current security mode and domain/workgroup name. 412 */ 413 /*ARGSUSED*/ 414 static int 415 smbadm_list(int argc, char **argv) 416 { 417 char domain[MAXHOSTNAMELEN]; 418 char modename[16]; 419 int rc; 420 421 rc = smb_config_getstr(SMB_CI_SECURITY, modename, sizeof (modename)); 422 if (rc != SMBD_SMF_OK) { 423 (void) fprintf(stderr, 424 gettext("failed to get the security mode\n")); 425 return (1); 426 } 427 428 (void) printf(gettext("security mode: %s\n"), modename); 429 430 if (smb_getdomainname(domain, sizeof (domain)) != 0) { 431 (void) fprintf(stderr, gettext("failed to get the %s name\n"), 432 modename); 433 return (1); 434 } 435 436 (void) printf(gettext("%s name: %s\n"), modename, domain); 437 return (0); 438 } 439 440 /* 441 * smbadm_group_create 442 * 443 * Creates a local SMB group 444 */ 445 static int 446 smbadm_group_create(int argc, char **argv) 447 { 448 char *gname = NULL; 449 char *desc = NULL; 450 char option; 451 int status; 452 453 while ((option = getopt(argc, argv, "d:")) != -1) { 454 switch (option) { 455 case 'd': 456 desc = optarg; 457 break; 458 459 default: 460 smbadm_usage(B_FALSE); 461 } 462 } 463 464 gname = argv[optind]; 465 if (optind >= argc || gname == NULL || *gname == '\0') { 466 (void) fprintf(stderr, gettext("missing group name\n")); 467 smbadm_usage(B_FALSE); 468 } 469 470 if (getgrnam(gname) == NULL) { 471 (void) fprintf(stderr, 472 gettext("failed to get the Solaris group '%s'\n"), gname); 473 (void) fprintf(stderr, 474 gettext("use 'groupadd' to add '%s'\n"), gname); 475 return (1); 476 } 477 478 status = smb_lgrp_add(gname, desc); 479 if (status != SMB_LGRP_SUCCESS) { 480 (void) fprintf(stderr, 481 gettext("failed to create the group (%s)\n"), 482 smb_lgrp_strerror(status)); 483 } else { 484 (void) printf(gettext("'%s' created.\n"), 485 gname); 486 } 487 488 return (status); 489 } 490 491 /* 492 * smbadm_group_dump_members 493 * 494 * Dump group members details. 495 */ 496 static void 497 smbadm_group_dump_members(smb_gsid_t *members, int num) 498 { 499 char sidstr[SMB_SID_STRSZ]; 500 int i; 501 502 if (num == 0) { 503 (void) printf(gettext("\tNo members\n")); 504 return; 505 } 506 507 (void) printf(gettext("\tMembers:\n")); 508 for (i = 0; i < num; i++) { 509 *sidstr = '\0'; 510 if (smb_lookup_sid(members[i].gs_sid, sidstr, 511 sizeof (sidstr)) == NT_STATUS_SUCCESS) 512 (void) printf(gettext("\t\t%s\n"), sidstr); 513 else 514 (void) printf(gettext("\t\tERROR! Invalid SID\n")); 515 } 516 } 517 518 /* 519 * smbadm_group_dump_privs 520 * 521 * Dump group privilege details. 522 */ 523 static void 524 smbadm_group_dump_privs(smb_privset_t *privs) 525 { 526 smb_privinfo_t *pinfo; 527 char *pstatus; 528 int i; 529 530 (void) printf(gettext("\tPrivileges: \n")); 531 532 for (i = 0; i < privs->priv_cnt; i++) { 533 pinfo = smb_priv_getbyvalue(privs->priv[i].luid.lo_part); 534 if ((pinfo == NULL) || (pinfo->flags & PF_PRESENTABLE) == 0) 535 continue; 536 537 switch (privs->priv[i].attrs) { 538 case SE_PRIVILEGE_ENABLED: 539 pstatus = "On"; 540 break; 541 case SE_PRIVILEGE_DISABLED: 542 pstatus = "Off"; 543 break; 544 default: 545 pstatus = "Unknown"; 546 break; 547 } 548 (void) printf(gettext("\t\t%s: %s\n"), pinfo->name, pstatus); 549 } 550 551 if (privs->priv_cnt == 0) 552 (void) printf(gettext("\t\tNo privileges\n")); 553 } 554 555 /* 556 * smbadm_group_dump 557 * 558 * Dump group details. 559 */ 560 static void 561 smbadm_group_dump(smb_group_t *grp, boolean_t show_mem, boolean_t show_privs) 562 { 563 char sidstr[SMB_SID_STRSZ]; 564 565 (void) printf(gettext("%s (%s)\n"), grp->sg_name, grp->sg_cmnt); 566 567 smb_sid_tostr(grp->sg_id.gs_sid, sidstr); 568 (void) printf(gettext("\tSID: %s\n"), sidstr); 569 570 if (show_privs) 571 smbadm_group_dump_privs(grp->sg_privs); 572 573 if (show_mem) 574 smbadm_group_dump_members(grp->sg_members, grp->sg_nmembers); 575 } 576 577 /* 578 * smbadm_group_show 579 * 580 */ 581 static int 582 smbadm_group_show(int argc, char **argv) 583 { 584 char *gname = NULL; 585 boolean_t show_privs; 586 boolean_t show_members; 587 char option; 588 int status; 589 smb_group_t grp; 590 smb_giter_t gi; 591 592 show_privs = show_members = B_FALSE; 593 594 while ((option = getopt(argc, argv, "mp")) != -1) { 595 switch (option) { 596 case 'm': 597 show_members = B_TRUE; 598 break; 599 case 'p': 600 show_privs = B_TRUE; 601 break; 602 603 default: 604 smbadm_usage(B_FALSE); 605 } 606 } 607 608 gname = argv[optind]; 609 if (optind >= argc || gname == NULL || *gname == '\0') 610 gname = "*"; 611 612 if (strcmp(gname, "*")) { 613 status = smb_lgrp_getbyname(gname, &grp); 614 if (status == SMB_LGRP_SUCCESS) { 615 smbadm_group_dump(&grp, show_members, show_privs); 616 smb_lgrp_free(&grp); 617 } else { 618 (void) fprintf(stderr, 619 gettext("failed to find '%s' (%s)\n"), 620 gname, smb_lgrp_strerror(status)); 621 } 622 return (status); 623 } 624 625 if ((status = smb_lgrp_iteropen(&gi)) != SMB_LGRP_SUCCESS) { 626 (void) fprintf(stderr, 627 gettext("failed to list groups (%s)\n"), 628 smb_lgrp_strerror(status)); 629 return (status); 630 } 631 632 while ((status = smb_lgrp_iterate(&gi, &grp)) == SMB_LGRP_SUCCESS) { 633 smbadm_group_dump(&grp, show_members, show_privs); 634 smb_lgrp_free(&grp); 635 } 636 637 smb_lgrp_iterclose(&gi); 638 639 if (status != SMB_LGRP_NO_MORE) { 640 (void) fprintf(stderr, 641 gettext("failed to get all the groups (%s)\n"), 642 smb_lgrp_strerror(status)); 643 return (status); 644 } 645 646 return (0); 647 } 648 649 /* 650 * smbadm_group_delete 651 */ 652 static int 653 smbadm_group_delete(int argc, char **argv) 654 { 655 char *gname = NULL; 656 int status; 657 658 gname = argv[optind]; 659 if (optind >= argc || gname == NULL || *gname == '\0') { 660 (void) fprintf(stderr, gettext("missing group name\n")); 661 smbadm_usage(B_FALSE); 662 } 663 664 status = smb_lgrp_delete(gname); 665 if (status != SMB_LGRP_SUCCESS) { 666 (void) fprintf(stderr, 667 gettext("failed to delete the group (%s)\n"), 668 smb_lgrp_strerror(status)); 669 } else { 670 (void) printf(gettext("'%s' deleted.\n"), 671 gname); 672 } 673 674 return (status); 675 } 676 677 /* 678 * smbadm_group_rename 679 */ 680 static int 681 smbadm_group_rename(int argc, char **argv) 682 { 683 char *gname = NULL; 684 char *ngname = NULL; 685 int status; 686 687 gname = argv[optind]; 688 if (optind++ >= argc || gname == NULL || *gname == '\0') { 689 (void) fprintf(stderr, gettext("missing group name\n")); 690 smbadm_usage(B_FALSE); 691 } 692 693 ngname = argv[optind]; 694 if (optind >= argc || ngname == NULL || *ngname == '\0') { 695 (void) fprintf(stderr, gettext("missing new group name\n")); 696 smbadm_usage(B_FALSE); 697 } 698 699 if (getgrnam(ngname) == NULL) { 700 (void) fprintf(stderr, 701 gettext("failed to get the Solaris group '%s'\n"), ngname); 702 (void) fprintf(stderr, 703 gettext("use 'groupadd' to add '%s'\n"), ngname); 704 return (1); 705 } 706 707 status = smb_lgrp_rename(gname, ngname); 708 if (status != SMB_LGRP_SUCCESS) { 709 if (status == SMB_LGRP_EXISTS) 710 (void) fprintf(stderr, 711 gettext("failed to rename '%s' (%s already " 712 "exists)\n"), gname, ngname); 713 else 714 (void) fprintf(stderr, 715 gettext("failed to rename '%s' (%s)\n"), gname, 716 smb_lgrp_strerror(status)); 717 } else { 718 (void) printf(gettext("'%s' renamed to '%s'\n"), gname, ngname); 719 } 720 721 return (status); 722 } 723 724 /* 725 * smbadm_group_setprop 726 * 727 * Set the group properties. 728 */ 729 static int 730 smbadm_group_setprop(int argc, char **argv) 731 { 732 char *gname = NULL; 733 smbadm_prop_t props[SMBADM_NPROP]; 734 smbadm_prop_handle_t *phandle; 735 char option; 736 int pcnt = 0; 737 int ret; 738 int p; 739 740 bzero(props, SMBADM_NPROP * sizeof (smbadm_prop_t)); 741 742 while ((option = getopt(argc, argv, "p:")) != -1) { 743 switch (option) { 744 case 'p': 745 if (pcnt >= SMBADM_NPROP) { 746 (void) fprintf(stderr, 747 gettext("exceeded number of supported" 748 " properties\n")); 749 smbadm_usage(B_FALSE); 750 } 751 752 if (smbadm_prop_parse(optarg, &props[pcnt++]) != 0) 753 smbadm_usage(B_FALSE); 754 break; 755 756 default: 757 smbadm_usage(B_FALSE); 758 } 759 } 760 761 if (pcnt == 0) { 762 (void) fprintf(stderr, 763 gettext("missing property=value argument\n")); 764 smbadm_usage(B_FALSE); 765 } 766 767 gname = argv[optind]; 768 if (optind >= argc || gname == NULL || *gname == '\0') { 769 (void) fprintf(stderr, gettext("missing group name\n")); 770 smbadm_usage(B_FALSE); 771 } 772 773 for (p = 0; p < pcnt; p++) { 774 phandle = smbadm_prop_gethandle(props[p].p_name); 775 if (phandle) { 776 if (phandle->p_setfn(gname, &props[p]) != 0) 777 ret = 1; 778 } 779 } 780 781 return (ret); 782 } 783 784 /* 785 * smbadm_group_getprop 786 * 787 * Get the group properties. 788 */ 789 static int 790 smbadm_group_getprop(int argc, char **argv) 791 { 792 char *gname = NULL; 793 smbadm_prop_t props[SMBADM_NPROP]; 794 smbadm_prop_handle_t *phandle; 795 char option; 796 int pcnt = 0; 797 int ret; 798 int p; 799 800 bzero(props, SMBADM_NPROP * sizeof (smbadm_prop_t)); 801 802 while ((option = getopt(argc, argv, "p:")) != -1) { 803 switch (option) { 804 case 'p': 805 if (pcnt >= SMBADM_NPROP) { 806 (void) fprintf(stderr, 807 gettext("exceeded number of supported" 808 " properties\n")); 809 smbadm_usage(B_FALSE); 810 } 811 812 if (smbadm_prop_parse(optarg, &props[pcnt++]) != 0) 813 smbadm_usage(B_FALSE); 814 break; 815 816 default: 817 smbadm_usage(B_FALSE); 818 } 819 } 820 821 gname = argv[optind]; 822 if (optind >= argc || gname == NULL || *gname == '\0') { 823 (void) fprintf(stderr, gettext("missing group name\n")); 824 smbadm_usage(B_FALSE); 825 } 826 827 if (pcnt == 0) { 828 /* 829 * If no property has be specified then get 830 * all the properties. 831 */ 832 pcnt = SMBADM_NPROP; 833 for (p = 0; p < pcnt; p++) 834 props[p].p_name = smbadm_ptable[p].p_name; 835 } 836 837 for (p = 0; p < pcnt; p++) { 838 phandle = smbadm_prop_gethandle(props[p].p_name); 839 if (phandle) { 840 if (phandle->p_getfn(gname, &props[p]) != 0) 841 ret = 1; 842 } 843 } 844 845 return (ret); 846 } 847 848 /* 849 * smbadm_group_addmember 850 * 851 */ 852 static int 853 smbadm_group_addmember(int argc, char **argv) 854 { 855 char *gname = NULL; 856 char **mname; 857 char option; 858 smb_gsid_t msid; 859 int status; 860 int mcnt = 0; 861 int ret = 0; 862 int i; 863 864 865 mname = (char **)malloc(argc * sizeof (char *)); 866 if (mname == NULL) { 867 (void) fprintf(stderr, gettext("out of memory\n")); 868 return (1); 869 } 870 bzero(mname, argc * sizeof (char *)); 871 872 while ((option = getopt(argc, argv, "m:")) != -1) { 873 switch (option) { 874 case 'm': 875 mname[mcnt++] = optarg; 876 break; 877 878 default: 879 free(mname); 880 smbadm_usage(B_FALSE); 881 } 882 } 883 884 if (mcnt == 0) { 885 (void) fprintf(stderr, gettext("missing member name\n")); 886 free(mname); 887 smbadm_usage(B_FALSE); 888 } 889 890 gname = argv[optind]; 891 if (optind >= argc || gname == NULL || *gname == 0) { 892 (void) fprintf(stderr, gettext("missing group name\n")); 893 free(mname); 894 smbadm_usage(B_FALSE); 895 } 896 897 898 for (i = 0; i < mcnt; i++) { 899 if (mname[i] == NULL) 900 continue; 901 902 if (smb_lookup_name(mname[i], &msid) != NT_STATUS_SUCCESS) { 903 (void) fprintf(stderr, 904 gettext("failed to add %s " 905 "(could not obtain the SID)\n"), 906 mname[i]); 907 continue; 908 } 909 910 status = smb_lgrp_add_member(gname, msid.gs_sid, msid.gs_type); 911 free(msid.gs_sid); 912 if (status != SMB_LGRP_SUCCESS) { 913 (void) fprintf(stderr, 914 gettext("failed to add %s (%s)\n"), 915 mname[i], smb_lgrp_strerror(status)); 916 ret = 1; 917 } else { 918 (void) printf(gettext("'%s' is now a member of '%s'\n"), 919 mname[i], gname); 920 } 921 } 922 923 free(mname); 924 return (ret); 925 } 926 927 /* 928 * smbadm_group_delmember 929 */ 930 static int 931 smbadm_group_delmember(int argc, char **argv) 932 { 933 char *gname = NULL; 934 char **mname; 935 char option; 936 smb_gsid_t msid; 937 int status; 938 int mcnt = 0; 939 int ret = 0; 940 int i; 941 942 mname = (char **)malloc(argc * sizeof (char *)); 943 if (mname == NULL) { 944 (void) fprintf(stderr, gettext("out of memory\n")); 945 return (1); 946 } 947 bzero(mname, argc * sizeof (char *)); 948 949 while ((option = getopt(argc, argv, "m:")) != -1) { 950 switch (option) { 951 case 'm': 952 mname[mcnt++] = optarg; 953 break; 954 955 default: 956 free(mname); 957 smbadm_usage(B_FALSE); 958 } 959 } 960 961 if (mcnt == 0) { 962 (void) fprintf(stderr, gettext("missing member name\n")); 963 free(mname); 964 smbadm_usage(B_FALSE); 965 } 966 967 gname = argv[optind]; 968 if (optind >= argc || gname == NULL || *gname == 0) { 969 (void) fprintf(stderr, gettext("missing group name\n")); 970 free(mname); 971 smbadm_usage(B_FALSE); 972 } 973 974 975 for (i = 0; i < mcnt; i++) { 976 if (mname[i] == NULL) 977 continue; 978 979 if (smb_lookup_name(mname[i], &msid) != NT_STATUS_SUCCESS) { 980 (void) fprintf(stderr, 981 gettext("failed to remove %s " 982 "(could not obtain the SID)\n"), 983 mname[i]); 984 continue; 985 } 986 987 status = smb_lgrp_del_member(gname, msid.gs_sid, msid.gs_type); 988 free(msid.gs_sid); 989 if (status != SMB_LGRP_SUCCESS) { 990 (void) fprintf(stderr, 991 gettext("failed to remove %s (%s)\n"), 992 mname[i], smb_lgrp_strerror(status)); 993 ret = 1; 994 } else { 995 (void) printf( 996 gettext("'%s' has been removed from %s\n"), 997 mname[i], gname); 998 } 999 } 1000 1001 return (ret); 1002 } 1003 1004 static int 1005 smbadm_user_disable(int argc, char **argv) 1006 { 1007 int error; 1008 char *user = NULL; 1009 1010 user = argv[optind]; 1011 if (optind >= argc || user == NULL || *user == '\0') { 1012 (void) fprintf(stderr, gettext("missing user name\n")); 1013 smbadm_usage(B_FALSE); 1014 } 1015 1016 error = smb_pwd_setcntl(user, SMB_PWC_DISABLE); 1017 if (error == SMB_PWE_SUCCESS) 1018 (void) printf(gettext("%s is disabled.\n"), user); 1019 else 1020 (void) fprintf(stderr, "%s\n", smbadm_pwd_strerror(error)); 1021 1022 return (error); 1023 } 1024 1025 static int 1026 smbadm_user_enable(int argc, char **argv) 1027 { 1028 int error; 1029 char *user = NULL; 1030 1031 user = argv[optind]; 1032 if (optind >= argc || user == NULL || *user == '\0') { 1033 (void) fprintf(stderr, gettext("missing user name\n")); 1034 smbadm_usage(B_FALSE); 1035 } 1036 1037 error = smb_pwd_setcntl(user, SMB_PWC_ENABLE); 1038 if (error == SMB_PWE_SUCCESS) 1039 (void) printf(gettext("%s is enabled.\n"), user); 1040 else 1041 (void) fprintf(stderr, "%s\n", smbadm_pwd_strerror(error)); 1042 1043 return (error); 1044 } 1045 1046 1047 int 1048 main(int argc, char **argv) 1049 { 1050 int ret; 1051 int i; 1052 1053 (void) malloc(0); /* satisfy libumem dependency */ 1054 1055 progname = basename(argv[0]); 1056 1057 if (getzoneid() != GLOBAL_ZONEID) { 1058 (void) fprintf(stderr, 1059 gettext("cannot execute in non-global zone\n")); 1060 return (0); 1061 } 1062 1063 if (is_system_labeled()) { 1064 (void) fprintf(stderr, 1065 gettext("Trusted Extensions not supported\n")); 1066 return (0); 1067 } 1068 1069 if (argc < 2) { 1070 (void) fprintf(stderr, gettext("missing command\n")); 1071 smbadm_usage(B_FALSE); 1072 } 1073 1074 /* 1075 * Special case "cmd --help/-?" 1076 */ 1077 if (strcmp(argv[1], "-?") == 0 || 1078 strcmp(argv[1], "--help") == 0 || 1079 strcmp(argv[1], "-h") == 0) 1080 smbadm_usage(B_TRUE); 1081 1082 for (i = 0; i < SMBADM_NCMD; ++i) { 1083 curcmd = &smbadm_cmdtable[i]; 1084 if (strcasecmp(argv[1], curcmd->name) == 0) { 1085 if (argc > 2) { 1086 /* cmd subcmd --help/-? */ 1087 if (strcmp(argv[2], "-?") == 0 || 1088 strcmp(argv[2], "--help") == 0 || 1089 strcmp(argv[2], "-h") == 0) 1090 smbadm_usage(B_TRUE); 1091 } 1092 1093 if ((ret = smbadm_grpcmd_init()) != 0) 1094 return (ret); 1095 1096 ret = curcmd->func(argc - 1, &argv[1]); 1097 1098 smbadm_grpcmd_fini(); 1099 return (ret); 1100 } 1101 } 1102 1103 curcmd = NULL; 1104 (void) fprintf(stderr, gettext("unknown subcommand (%s)\n"), argv[1]); 1105 smbadm_usage(B_FALSE); 1106 return (2); 1107 } 1108 1109 static int 1110 smbadm_grpcmd_init(void) 1111 { 1112 int rc; 1113 1114 if (curcmd->flags & SMBADM_CMDF_GROUP) { 1115 if (smb_idmap_start() != 0) { 1116 (void) fprintf(stderr, 1117 gettext("failed to contact idmap service\n")); 1118 return (1); 1119 } 1120 1121 if ((rc = smb_lgrp_start()) != SMB_LGRP_SUCCESS) { 1122 (void) fprintf(stderr, 1123 gettext("failed to initialize (%s)\n"), 1124 smb_lgrp_strerror(rc)); 1125 smb_idmap_stop(); 1126 return (1); 1127 } 1128 } 1129 1130 return (0); 1131 } 1132 1133 static void 1134 smbadm_grpcmd_fini(void) 1135 { 1136 if (curcmd->flags & SMBADM_CMDF_GROUP) { 1137 smb_lgrp_stop(); 1138 smb_idmap_stop(); 1139 } 1140 } 1141 1142 static boolean_t 1143 smbadm_prop_validate(smbadm_prop_t *prop, boolean_t chkval) 1144 { 1145 smbadm_prop_handle_t *pinfo; 1146 int i; 1147 1148 for (i = 0; i < SMBADM_NPROP; i++) { 1149 pinfo = &smbadm_ptable[i]; 1150 if (strcmp(pinfo->p_name, prop->p_name) == 0) { 1151 if (pinfo->p_chkfn && chkval) 1152 return (pinfo->p_chkfn(prop)); 1153 1154 return (B_TRUE); 1155 } 1156 } 1157 1158 (void) fprintf(stderr, 1159 gettext("unrecognized property '%s'\n"), prop->p_name); 1160 1161 return (B_FALSE); 1162 } 1163 1164 static int 1165 smbadm_prop_parse(char *arg, smbadm_prop_t *prop) 1166 { 1167 boolean_t parse_value; 1168 char *equal; 1169 1170 if (arg == NULL) 1171 return (2); 1172 1173 prop->p_name = prop->p_value = NULL; 1174 1175 if (strcmp(curcmd->name, "set") == 0) 1176 parse_value = B_TRUE; 1177 else 1178 parse_value = B_FALSE; 1179 1180 prop->p_name = arg; 1181 1182 if (parse_value) { 1183 equal = strchr(arg, '='); 1184 if (equal == NULL) 1185 return (2); 1186 1187 *equal++ = '\0'; 1188 prop->p_value = equal; 1189 } 1190 1191 if (smbadm_prop_validate(prop, parse_value) == B_FALSE) 1192 return (2); 1193 1194 return (0); 1195 } 1196 1197 static smbadm_prop_handle_t * 1198 smbadm_prop_gethandle(char *pname) 1199 { 1200 int i; 1201 1202 for (i = 0; i < SMBADM_NPROP; i++) 1203 if (strcmp(pname, smbadm_ptable[i].p_name) == 0) 1204 return (&smbadm_ptable[i]); 1205 1206 return (NULL); 1207 } 1208 1209 static int 1210 smbadm_setprop_desc(char *gname, smbadm_prop_t *prop) 1211 { 1212 int status; 1213 1214 status = smb_lgrp_setcmnt(gname, prop->p_value); 1215 if (status != SMB_LGRP_SUCCESS) { 1216 (void) fprintf(stderr, 1217 gettext("failed to modify the group description (%s)\n"), 1218 smb_lgrp_strerror(status)); 1219 return (1); 1220 } 1221 1222 (void) printf(gettext("Successfully modified " 1223 "'%s' description\n"), gname); 1224 1225 return (0); 1226 } 1227 1228 static int 1229 smbadm_getprop_desc(char *gname, smbadm_prop_t *prop) 1230 { 1231 char *cmnt = NULL; 1232 int status; 1233 1234 status = smb_lgrp_getcmnt(gname, &cmnt); 1235 if (status != SMB_LGRP_SUCCESS) { 1236 (void) fprintf(stderr, 1237 gettext("failed to get the group description (%s)\n"), 1238 smb_lgrp_strerror(status)); 1239 return (1); 1240 } 1241 1242 (void) printf(gettext("\t%s: %s\n"), prop->p_name, cmnt); 1243 free(cmnt); 1244 return (0); 1245 } 1246 1247 static int 1248 smbadm_group_setpriv(char *gname, uint8_t priv_id, smbadm_prop_t *prop) 1249 { 1250 boolean_t enable; 1251 int status; 1252 int ret; 1253 1254 if (strcasecmp(prop->p_value, "on") == 0) { 1255 (void) printf(gettext("Enabling %s privilege "), prop->p_name); 1256 enable = B_TRUE; 1257 } else { 1258 (void) printf(gettext("Disabling %s privilege "), prop->p_name); 1259 enable = B_FALSE; 1260 } 1261 1262 status = smb_lgrp_setpriv(gname, priv_id, enable); 1263 if (status == SMB_LGRP_SUCCESS) { 1264 (void) printf(gettext("succeeded\n")); 1265 ret = 0; 1266 } else { 1267 (void) printf(gettext("failed: %s\n"), 1268 smb_lgrp_strerror(status)); 1269 ret = 1; 1270 } 1271 1272 return (ret); 1273 } 1274 1275 static int 1276 smbadm_group_getpriv(char *gname, uint8_t priv_id, smbadm_prop_t *prop) 1277 { 1278 boolean_t enable; 1279 int status; 1280 1281 status = smb_lgrp_getpriv(gname, priv_id, &enable); 1282 if (status != SMB_LGRP_SUCCESS) { 1283 (void) fprintf(stderr, gettext("failed to get %s (%s)\n"), 1284 prop->p_name, smb_lgrp_strerror(status)); 1285 return (1); 1286 } 1287 1288 (void) printf(gettext("\t%s: %s\n"), prop->p_name, 1289 (enable) ? "On" : "Off"); 1290 1291 return (0); 1292 } 1293 1294 static int 1295 smbadm_setprop_tkowner(char *gname, smbadm_prop_t *prop) 1296 { 1297 return (smbadm_group_setpriv(gname, SE_TAKE_OWNERSHIP_LUID, prop)); 1298 } 1299 1300 static int 1301 smbadm_getprop_tkowner(char *gname, smbadm_prop_t *prop) 1302 { 1303 return (smbadm_group_getpriv(gname, SE_TAKE_OWNERSHIP_LUID, prop)); 1304 } 1305 1306 static int 1307 smbadm_setprop_backup(char *gname, smbadm_prop_t *prop) 1308 { 1309 return (smbadm_group_setpriv(gname, SE_BACKUP_LUID, prop)); 1310 } 1311 1312 static int 1313 smbadm_getprop_backup(char *gname, smbadm_prop_t *prop) 1314 { 1315 return (smbadm_group_getpriv(gname, SE_BACKUP_LUID, prop)); 1316 } 1317 1318 static int 1319 smbadm_setprop_restore(char *gname, smbadm_prop_t *prop) 1320 { 1321 return (smbadm_group_setpriv(gname, SE_RESTORE_LUID, prop)); 1322 } 1323 1324 static int 1325 smbadm_getprop_restore(char *gname, smbadm_prop_t *prop) 1326 { 1327 return (smbadm_group_getpriv(gname, SE_RESTORE_LUID, prop)); 1328 } 1329 1330 static boolean_t 1331 smbadm_chkprop_priv(smbadm_prop_t *prop) 1332 { 1333 if (prop->p_value == NULL || *prop->p_value == '\0') { 1334 (void) fprintf(stderr, 1335 gettext("missing value for '%s'\n"), prop->p_name); 1336 return (B_FALSE); 1337 } 1338 1339 if (strcasecmp(prop->p_value, "on") == 0) 1340 return (B_TRUE); 1341 1342 if (strcasecmp(prop->p_value, "off") == 0) 1343 return (B_TRUE); 1344 1345 (void) fprintf(stderr, 1346 gettext("%s: unrecognized value for '%s' property\n"), 1347 prop->p_value, prop->p_name); 1348 1349 return (B_FALSE); 1350 } 1351 1352 static const char * 1353 smbadm_pwd_strerror(int error) 1354 { 1355 switch (error) { 1356 case SMB_PWE_SUCCESS: 1357 return (gettext("Success.")); 1358 1359 case SMB_PWE_USER_UNKNOWN: 1360 return (gettext("User does not exist.")); 1361 1362 case SMB_PWE_USER_DISABLE: 1363 return (gettext("User is disable.")); 1364 1365 case SMB_PWE_CLOSE_FAILED: 1366 case SMB_PWE_OPEN_FAILED: 1367 case SMB_PWE_WRITE_FAILED: 1368 case SMB_PWE_UPDATE_FAILED: 1369 return (gettext("Unexpected failure. " 1370 "SMB password database unchanged.")); 1371 1372 case SMB_PWE_STAT_FAILED: 1373 return (gettext("stat of SMB password file failed.")); 1374 1375 case SMB_PWE_BUSY: 1376 return (gettext("SMB password database busy. " 1377 "Try again later.")); 1378 1379 case SMB_PWE_DENIED: 1380 return (gettext("Operation not permitted.")); 1381 1382 case SMB_PWE_SYSTEM_ERROR: 1383 return (gettext("System error.")); 1384 } 1385 1386 return (gettext("Unknown error code.")); 1387 } 1388 1389 /* 1390 * Enable libumem debugging by default on DEBUG builds. 1391 */ 1392 #ifdef DEBUG 1393 const char * 1394 _umem_debug_init(void) 1395 { 1396 return ("default,verbose"); /* $UMEM_DEBUG setting */ 1397 } 1398 1399 const char * 1400 _umem_logging_init(void) 1401 { 1402 return ("fail,contents"); /* $UMEM_LOGGING setting */ 1403 } 1404 #endif 1405