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 2018 Nexenta Systems, Inc.  All rights reserved.
  24  */
  25 
  26 /*
  27  * CIFS configuration management library
  28  */
  29 
  30 #include <stdio.h>
  31 #include <stdlib.h>
  32 #include <unistd.h>
  33 #include <synch.h>
  34 #include <string.h>
  35 #include <strings.h>
  36 #include <syslog.h>
  37 #include <netdb.h>
  38 #include <ctype.h>
  39 #include <sys/types.h>
  40 #include <libscf.h>
  41 #include <assert.h>
  42 #include <uuid/uuid.h>
  43 #include <smbsrv/libsmb.h>
  44 
  45 typedef struct smb_cfg_param {
  46         smb_cfg_id_t sc_id;
  47         char *sc_name;
  48         int sc_type;
  49         uint32_t sc_flags;
  50 } smb_cfg_param_t;
  51 
  52 struct str_val {
  53         char *str;
  54         uint32_t val;
  55 };
  56 
  57 /*
  58  * config parameter flags
  59  */
  60 #define SMB_CF_PROTECTED        0x01
  61 #define SMB_CF_EXEC             0x02
  62 
  63 /* idmap SMF fmri and Property Group */
  64 #define IDMAP_FMRI_PREFIX               "system/idmap"
  65 #define MACHINE_SID                     "machine_sid"
  66 #define MACHINE_UUID                    "machine_uuid"
  67 #define IDMAP_DOMAIN                    "domain_name"
  68 #define IDMAP_PREF_DC                   "preferred_dc"
  69 #define IDMAP_SITE_NAME                 "site_name"
  70 #define IDMAP_PG_NAME                   "config"
  71 
  72 #define SMB_SECMODE_WORKGRP_STR         "workgroup"
  73 #define SMB_SECMODE_DOMAIN_STR          "domain"
  74 
  75 #define SMB_ENC_LEN     1024
  76 #define SMB_DEC_LEN     256
  77 
  78 static char *b64_data =
  79         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  80 
  81 static smb_cfg_param_t smb_cfg_table[] =
  82 {
  83         {SMB_CI_VERSION, "sv_version", SCF_TYPE_ASTRING, 0},
  84 
  85         /* Oplock configuration, Kernel Only */
  86         {SMB_CI_OPLOCK_ENABLE, "oplock_enable", SCF_TYPE_BOOLEAN, 0},
  87 
  88         /* Autohome configuration */
  89         {SMB_CI_AUTOHOME_MAP, "autohome_map", SCF_TYPE_ASTRING, 0},
  90 
  91         /* Domain/PDC configuration */
  92         {SMB_CI_DOMAIN_SID, "domain_sid", SCF_TYPE_ASTRING, 0},
  93         {SMB_CI_DOMAIN_MEMB, "domain_member", SCF_TYPE_BOOLEAN, 0},
  94         {SMB_CI_DOMAIN_NAME, "domain_name", SCF_TYPE_ASTRING, 0},
  95         {SMB_CI_DOMAIN_FQDN, "fqdn", SCF_TYPE_ASTRING, 0},
  96         {SMB_CI_DOMAIN_FOREST, "forest", SCF_TYPE_ASTRING, 0},
  97         {SMB_CI_DOMAIN_GUID, "domain_guid", SCF_TYPE_ASTRING, 0},
  98         {SMB_CI_DOMAIN_SRV, "pdc", SCF_TYPE_ASTRING, 0},
  99 
 100         /* WINS configuration */
 101         {SMB_CI_WINS_SRV1, "wins_server_1", SCF_TYPE_ASTRING, 0},
 102         {SMB_CI_WINS_SRV2, "wins_server_2", SCF_TYPE_ASTRING, 0},
 103         {SMB_CI_WINS_EXCL, "wins_exclude", SCF_TYPE_ASTRING, 0},
 104 
 105         /* Kmod specific configuration */
 106         {SMB_CI_MAX_WORKERS, "max_workers", SCF_TYPE_INTEGER, 0},
 107         {SMB_CI_MAX_CONNECTIONS, "max_connections", SCF_TYPE_INTEGER, 0},
 108         {SMB_CI_KEEPALIVE, "keep_alive", SCF_TYPE_INTEGER, 0},
 109         {SMB_CI_RESTRICT_ANON, "restrict_anonymous", SCF_TYPE_BOOLEAN, 0},
 110 
 111         {SMB_CI_SIGNING_ENABLE, "signing_enabled", SCF_TYPE_BOOLEAN, 0},
 112         {SMB_CI_SIGNING_REQD, "signing_required", SCF_TYPE_BOOLEAN, 0},
 113 
 114         /* Kmod tuning configuration */
 115         {SMB_CI_SYNC_ENABLE, "sync_enable", SCF_TYPE_BOOLEAN, 0},
 116 
 117         /* SMBd configuration */
 118         {SMB_CI_SECURITY, "security", SCF_TYPE_ASTRING, 0},
 119         {SMB_CI_NETBIOS_ENABLE, "netbios_enable", SCF_TYPE_BOOLEAN, 0},
 120         {SMB_CI_NBSCOPE, "netbios_scope", SCF_TYPE_ASTRING, 0},
 121         {SMB_CI_SYS_CMNT, "system_comment", SCF_TYPE_ASTRING, 0},
 122         {SMB_CI_LM_LEVEL, "lmauth_level", SCF_TYPE_INTEGER, 0},
 123 
 124         /* ADS Configuration */
 125         {SMB_CI_ADS_SITE, "ads_site", SCF_TYPE_ASTRING, 0},
 126 
 127         /* Dynamic DNS */
 128         {SMB_CI_DYNDNS_ENABLE, "ddns_enable", SCF_TYPE_BOOLEAN, 0},
 129 
 130         {SMB_CI_MACHINE_PASSWD, "machine_passwd", SCF_TYPE_ASTRING,
 131             SMB_CF_PROTECTED},
 132 
 133         {SMB_CI_MACHINE_UUID, "machine_uuid", SCF_TYPE_ASTRING, 0},
 134         {SMB_CI_KPASSWD_SRV, "kpasswd_server", SCF_TYPE_ASTRING, 0},
 135         {SMB_CI_KPASSWD_DOMAIN, "kpasswd_domain", SCF_TYPE_ASTRING, 0},
 136         {SMB_CI_KPASSWD_SEQNUM, "kpasswd_seqnum", SCF_TYPE_INTEGER, 0},
 137         {SMB_CI_NETLOGON_SEQNUM, "netlogon_seqnum", SCF_TYPE_INTEGER, 0},
 138         {SMB_CI_IPV6_ENABLE, "ipv6_enable", SCF_TYPE_BOOLEAN, 0},
 139         {SMB_CI_PRINT_ENABLE, "print_enable", SCF_TYPE_BOOLEAN, 0},
 140         {SMB_CI_MAP, "map", SCF_TYPE_ASTRING, SMB_CF_EXEC},
 141         {SMB_CI_UNMAP, "unmap", SCF_TYPE_ASTRING, SMB_CF_EXEC},
 142         {SMB_CI_DISPOSITION, "disposition", SCF_TYPE_ASTRING, SMB_CF_EXEC},
 143         {SMB_CI_DFS_STDROOT_NUM, "dfs_stdroot_num", SCF_TYPE_INTEGER, 0},
 144         {SMB_CI_TRAVERSE_MOUNTS, "traverse_mounts", SCF_TYPE_BOOLEAN, 0},
 145         {SMB_CI_SMB2_ENABLE_OLD, "smb2_enable", SCF_TYPE_BOOLEAN, 0},
 146         {SMB_CI_INITIAL_CREDITS, "initial_credits", SCF_TYPE_INTEGER, 0},
 147         {SMB_CI_MAXIMUM_CREDITS, "maximum_credits", SCF_TYPE_INTEGER, 0},
 148         {SMB_CI_MAX_PROTOCOL, "max_protocol", SCF_TYPE_ASTRING, 0},
 149         {SMB_CI_ENCRYPT, "encrypt", SCF_TYPE_ASTRING, 0},
 150         {SMB_CI_MIN_PROTOCOL, "min_protocol", SCF_TYPE_ASTRING, 0},
 151         {SMB_CI_BYPASS_TRAVERSE_CHECKING,
 152             "bypass_traverse_checking", SCF_TYPE_BOOLEAN, 0},
 153 
 154         /* SMB_CI_MAX */
 155 };
 156 
 157 /*
 158  * We store the max SMB protocol version in SMF as a string,
 159  * (for convenience of svccfg etc) but the programmatic get/set
 160  * interfaces use the numeric form.
 161  *
 162  * The numeric values are as defined in the [MS-SMB2] spec.
 163  * except for how we represent "1" (for SMB1) which is an
 164  * arbitrary value below SMB2_VERS_BASE.
 165  */
 166 static struct str_val
 167 smb_versions[] = {
 168         { "3.02",       SMB_VERS_3_02 },
 169         { "3.0",        SMB_VERS_3_0 },
 170         { "2.1",        SMB_VERS_2_1 },
 171         { "2.002",      SMB_VERS_2_002 },
 172         { "1",          SMB_VERS_1 },
 173         { NULL,         0 }
 174 };
 175 
 176 static smb_cfg_param_t *smb_config_getent(smb_cfg_id_t);
 177 
 178 static boolean_t smb_is_base64(unsigned char c);
 179 static char *smb_base64_encode(char *str_to_encode);
 180 static char *smb_base64_decode(char *encoded_str);
 181 static int smb_config_get_idmap_preferred_dc(char *, int);
 182 static int smb_config_set_idmap_preferred_dc(char *);
 183 static int smb_config_get_idmap_site_name(char *, int);
 184 static int smb_config_set_idmap_site_name(char *);
 185 
 186 static uint32_t
 187 smb_convert_version_str(const char *version)
 188 {
 189         uint32_t dialect = 0;
 190         int i;
 191 
 192         for (i = 0; smb_versions[i].str != NULL; i++) {
 193                 if (strcmp(version, smb_versions[i].str) == 0)
 194                         dialect = smb_versions[i].val;
 195         }
 196 
 197         return (dialect);
 198 }
 199 
 200 char *
 201 smb_config_getname(smb_cfg_id_t id)
 202 {
 203         smb_cfg_param_t *cfg;
 204         cfg = smb_config_getent(id);
 205         return (cfg->sc_name);
 206 }
 207 
 208 static boolean_t
 209 smb_is_base64(unsigned char c)
 210 {
 211         return (isalnum(c) || (c == '+') || (c == '/'));
 212 }
 213 
 214 /*
 215  * smb_base64_encode
 216  *
 217  * Encode a string using base64 algorithm.
 218  * Caller should free the returned buffer when done.
 219  */
 220 static char *
 221 smb_base64_encode(char *str_to_encode)
 222 {
 223         int ret_cnt = 0;
 224         int i = 0, j = 0;
 225         char arr_3[3], arr_4[4];
 226         int len = strlen(str_to_encode);
 227         char *ret = malloc(SMB_ENC_LEN);
 228 
 229         if (ret == NULL) {
 230                 return (NULL);
 231         }
 232 
 233         while (len--) {
 234                 arr_3[i++] = *(str_to_encode++);
 235                 if (i == 3) {
 236                         arr_4[0] = (arr_3[0] & 0xfc) >> 2;
 237                         arr_4[1] = ((arr_3[0] & 0x03) << 4) +
 238                             ((arr_3[1] & 0xf0) >> 4);
 239                         arr_4[2] = ((arr_3[1] & 0x0f) << 2) +
 240                             ((arr_3[2] & 0xc0) >> 6);
 241                         arr_4[3] = arr_3[2] & 0x3f;
 242 
 243                         for (i = 0; i < 4; i++)
 244                                 ret[ret_cnt++] = b64_data[arr_4[i]];
 245                         i = 0;
 246                 }
 247         }
 248 
 249         if (i) {
 250                 for (j = i; j < 3; j++)
 251                         arr_3[j] = '\0';
 252 
 253                 arr_4[0] = (arr_3[0] & 0xfc) >> 2;
 254                 arr_4[1] = ((arr_3[0] & 0x03) << 4) +
 255                     ((arr_3[1] & 0xf0) >> 4);
 256                 arr_4[2] = ((arr_3[1] & 0x0f) << 2) +
 257                     ((arr_3[2] & 0xc0) >> 6);
 258                 arr_4[3] = arr_3[2] & 0x3f;
 259 
 260                 for (j = 0; j < (i + 1); j++)
 261                         ret[ret_cnt++] = b64_data[arr_4[j]];
 262 
 263                 while (i++ < 3)
 264                         ret[ret_cnt++] = '=';
 265         }
 266 
 267         ret[ret_cnt++] = '\0';
 268         return (ret);
 269 }
 270 
 271 /*
 272  * smb_base64_decode
 273  *
 274  * Decode using base64 algorithm.
 275  * Caller should free the returned buffer when done.
 276  */
 277 static char *
 278 smb_base64_decode(char *encoded_str)
 279 {
 280         int len = strlen(encoded_str);
 281         int i = 0, j = 0;
 282         int en_ind = 0;
 283         char arr_4[4], arr_3[3];
 284         int ret_cnt = 0;
 285         char *ret = malloc(SMB_DEC_LEN);
 286         char *p;
 287 
 288         if (ret == NULL) {
 289                 return (NULL);
 290         }
 291 
 292         while (len-- && (encoded_str[en_ind] != '=') &&
 293             smb_is_base64(encoded_str[en_ind])) {
 294                 arr_4[i++] = encoded_str[en_ind];
 295                 en_ind++;
 296                 if (i == 4) {
 297                         for (i = 0; i < 4; i++) {
 298                                 if ((p = strchr(b64_data, arr_4[i])) == NULL)
 299                                         return (NULL);
 300 
 301                                 arr_4[i] = (int)(p - b64_data);
 302                         }
 303 
 304                         arr_3[0] = (arr_4[0] << 2) +
 305                             ((arr_4[1] & 0x30) >> 4);
 306                         arr_3[1] = ((arr_4[1] & 0xf) << 4) +
 307                             ((arr_4[2] & 0x3c) >> 2);
 308                         arr_3[2] = ((arr_4[2] & 0x3) << 6) +
 309                             arr_4[3];
 310 
 311                         for (i = 0; i < 3; i++)
 312                                 ret[ret_cnt++] = arr_3[i];
 313 
 314                         i = 0;
 315                 }
 316         }
 317 
 318         if (i) {
 319                 for (j = i; j < 4; j++)
 320                         arr_4[j] = 0;
 321 
 322                 for (j = 0; j < 4; j++) {
 323                         if ((p = strchr(b64_data, arr_4[j])) == NULL)
 324                                 return (NULL);
 325 
 326                         arr_4[j] = (int)(p - b64_data);
 327                 }
 328                 arr_3[0] = (arr_4[0] << 2) +
 329                     ((arr_4[1] & 0x30) >> 4);
 330                 arr_3[1] = ((arr_4[1] & 0xf) << 4) +
 331                     ((arr_4[2] & 0x3c) >> 2);
 332                 arr_3[2] = ((arr_4[2] & 0x3) << 6) +
 333                     arr_4[3];
 334                 for (j = 0; j < (i - 1); j++)
 335                         ret[ret_cnt++] = arr_3[j];
 336         }
 337 
 338         ret[ret_cnt++] = '\0';
 339         return (ret);
 340 }
 341 
 342 static char *
 343 smb_config_getenv_generic(char *name, char *svc_fmri_prefix, char *svc_propgrp)
 344 {
 345         smb_scfhandle_t *handle;
 346         char *value;
 347 
 348         if ((value = malloc(MAX_VALUE_BUFLEN * sizeof (char))) == NULL)
 349                 return (NULL);
 350 
 351         handle = smb_smf_scf_init(svc_fmri_prefix);
 352         if (handle == NULL) {
 353                 free(value);
 354                 return (NULL);
 355         }
 356 
 357         (void) smb_smf_create_service_pgroup(handle, svc_propgrp);
 358 
 359         if (smb_smf_get_string_property(handle, name, value,
 360             sizeof (char) * MAX_VALUE_BUFLEN) != 0) {
 361                 smb_smf_scf_fini(handle);
 362                 free(value);
 363                 return (NULL);
 364         }
 365 
 366         smb_smf_scf_fini(handle);
 367         return (value);
 368 
 369 }
 370 
 371 static int
 372 smb_config_setenv_generic(char *svc_fmri_prefix, char *svc_propgrp,
 373     char *name, char *value)
 374 {
 375         smb_scfhandle_t *handle = NULL;
 376         int rc = 0;
 377 
 378 
 379         handle = smb_smf_scf_init(svc_fmri_prefix);
 380         if (handle == NULL) {
 381                 return (1);
 382         }
 383 
 384         (void) smb_smf_create_service_pgroup(handle, svc_propgrp);
 385 
 386         if (smb_smf_start_transaction(handle) != SMBD_SMF_OK) {
 387                 smb_smf_scf_fini(handle);
 388                 return (1);
 389         }
 390 
 391         if (smb_smf_set_string_property(handle, name, value) != SMBD_SMF_OK)
 392                 rc = 1;
 393 
 394         if (smb_smf_end_transaction(handle) != SMBD_SMF_OK)
 395                 rc = 1;
 396 
 397         smb_smf_scf_fini(handle);
 398         return (rc);
 399 }
 400 
 401 /*
 402  * smb_config_getstr
 403  *
 404  * Fetch the specified string configuration item from SMF
 405  */
 406 int
 407 smb_config_getstr(smb_cfg_id_t id, char *cbuf, int bufsz)
 408 {
 409         smb_scfhandle_t *handle;
 410         smb_cfg_param_t *cfg;
 411         int rc = SMBD_SMF_OK;
 412         char *pg;
 413         char protbuf[SMB_ENC_LEN];
 414         char *tmp;
 415 
 416         *cbuf = '\0';
 417         cfg = smb_config_getent(id);
 418         assert(cfg->sc_type == SCF_TYPE_ASTRING);
 419 
 420         if (id == SMB_CI_ADS_SITE)
 421                 return (smb_config_get_idmap_site_name(cbuf, bufsz));
 422         if (id == SMB_CI_DOMAIN_SRV)
 423                 return (smb_config_get_idmap_preferred_dc(cbuf, bufsz));
 424 
 425         handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
 426         if (handle == NULL)
 427                 return (SMBD_SMF_SYSTEM_ERR);
 428 
 429         if (cfg->sc_flags & SMB_CF_PROTECTED) {
 430                 if ((rc = smb_smf_create_service_pgroup(handle,
 431                     SMBD_PROTECTED_PG_NAME)) != SMBD_SMF_OK)
 432                         goto error;
 433 
 434                 if ((rc = smb_smf_get_string_property(handle, cfg->sc_name,
 435                     protbuf, sizeof (protbuf))) != SMBD_SMF_OK)
 436                         goto error;
 437 
 438                 if (*protbuf != '\0') {
 439                         tmp = smb_base64_decode(protbuf);
 440                         (void) strlcpy(cbuf, tmp, bufsz);
 441                         free(tmp);
 442                 }
 443         } else {
 444                 pg = (cfg->sc_flags & SMB_CF_EXEC) ? SMBD_EXEC_PG_NAME :
 445                     SMBD_PG_NAME;
 446                 rc = smb_smf_create_service_pgroup(handle, pg);
 447                 if (rc == SMBD_SMF_OK)
 448                         rc = smb_smf_get_string_property(handle, cfg->sc_name,
 449                             cbuf, bufsz);
 450         }
 451 
 452 error:
 453         smb_smf_scf_fini(handle);
 454         return (rc);
 455 }
 456 
 457 /*
 458  * Translate the value of an astring SMF property into a binary
 459  * IP address. If the value is neither a valid IPv4 nor IPv6
 460  * address, attempt to look it up as a hostname using the
 461  * configured address type.
 462  */
 463 int
 464 smb_config_getip(smb_cfg_id_t sc_id, smb_inaddr_t *ipaddr)
 465 {
 466         int rc, error;
 467         int a_family;
 468         char ipstr[MAXHOSTNAMELEN];
 469         struct hostent *h;
 470         smb_cfg_param_t *cfg;
 471 
 472         if (ipaddr == NULL)
 473                 return (SMBD_SMF_INVALID_ARG);
 474 
 475         bzero(ipaddr, sizeof (smb_inaddr_t));
 476         rc = smb_config_getstr(sc_id, ipstr, sizeof (ipstr));
 477         if (rc == SMBD_SMF_OK) {
 478                 if (*ipstr == '\0')
 479                         return (SMBD_SMF_INVALID_ARG);
 480 
 481                 if (inet_pton(AF_INET, ipstr, &ipaddr->a_ipv4) == 1) {
 482                         ipaddr->a_family = AF_INET;
 483                         return (SMBD_SMF_OK);
 484                 }
 485 
 486                 if (inet_pton(AF_INET6, ipstr, &ipaddr->a_ipv6) == 1) {
 487                         ipaddr->a_family = AF_INET6;
 488                         return (SMBD_SMF_OK);
 489                 }
 490 
 491                 /*
 492                  * The value is neither an IPv4 nor IPv6 address;
 493                  * so check if it's a hostname.
 494                  */
 495                 a_family = smb_config_getbool(SMB_CI_IPV6_ENABLE) ?
 496                     AF_INET6 : AF_INET;
 497                 h = getipnodebyname(ipstr, a_family, AI_DEFAULT,
 498                     &error);
 499                 if (h != NULL) {
 500                         bcopy(*(h->h_addr_list), &ipaddr->a_ip,
 501                             h->h_length);
 502                         ipaddr->a_family = a_family;
 503                         freehostent(h);
 504                         rc = SMBD_SMF_OK;
 505                 } else {
 506                         cfg = smb_config_getent(sc_id);
 507                         syslog(LOG_ERR, "smbd/%s: %s unable to get %s "
 508                             "address: %d", cfg->sc_name, ipstr,
 509                             a_family == AF_INET ?  "IPv4" : "IPv6", error);
 510                         rc = SMBD_SMF_INVALID_ARG;
 511                 }
 512         }
 513 
 514         return (rc);
 515 }
 516 
 517 /*
 518  * smb_config_getnum
 519  *
 520  * Returns the value of a numeric config param.
 521  */
 522 int
 523 smb_config_getnum(smb_cfg_id_t id, int64_t *cint)
 524 {
 525         smb_scfhandle_t *handle;
 526         smb_cfg_param_t *cfg;
 527         int rc = SMBD_SMF_OK;
 528 
 529         *cint = 0;
 530         cfg = smb_config_getent(id);
 531         assert(cfg->sc_type == SCF_TYPE_INTEGER);
 532 
 533         handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
 534         if (handle == NULL)
 535                 return (SMBD_SMF_SYSTEM_ERR);
 536 
 537         rc = smb_smf_create_service_pgroup(handle, SMBD_PG_NAME);
 538         if (rc == SMBD_SMF_OK)
 539                 rc = smb_smf_get_integer_property(handle, cfg->sc_name, cint);
 540         smb_smf_scf_fini(handle);
 541 
 542         return (rc);
 543 }
 544 
 545 /*
 546  * smb_config_getbool
 547  *
 548  * Returns the value of a boolean config param.
 549  */
 550 boolean_t
 551 smb_config_getbool(smb_cfg_id_t id)
 552 {
 553         smb_scfhandle_t *handle;
 554         smb_cfg_param_t *cfg;
 555         int rc = SMBD_SMF_OK;
 556         uint8_t vbool;
 557 
 558         cfg = smb_config_getent(id);
 559         assert(cfg->sc_type == SCF_TYPE_BOOLEAN);
 560 
 561         handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
 562         if (handle == NULL)
 563                 return (B_FALSE);
 564 
 565         rc = smb_smf_create_service_pgroup(handle, SMBD_PG_NAME);
 566         if (rc == SMBD_SMF_OK)
 567                 rc = smb_smf_get_boolean_property(handle, cfg->sc_name, &vbool);
 568         smb_smf_scf_fini(handle);
 569 
 570         return ((rc == SMBD_SMF_OK) ? (vbool == 1) : B_FALSE);
 571 }
 572 
 573 /*
 574  * smb_config_get
 575  *
 576  * This function returns the value of the requested config
 577  * iterm regardless of its type in string format. This should
 578  * be used when the config item type is not known by the caller.
 579  */
 580 int
 581 smb_config_get(smb_cfg_id_t id, char *cbuf, int bufsz)
 582 {
 583         smb_cfg_param_t *cfg;
 584         int64_t cint;
 585         int rc;
 586 
 587         cfg = smb_config_getent(id);
 588         switch (cfg->sc_type) {
 589         case SCF_TYPE_ASTRING:
 590                 return (smb_config_getstr(id, cbuf, bufsz));
 591 
 592         case SCF_TYPE_INTEGER:
 593                 rc = smb_config_getnum(id, &cint);
 594                 if (rc == SMBD_SMF_OK)
 595                         (void) snprintf(cbuf, bufsz, "%lld", cint);
 596                 return (rc);
 597 
 598         case SCF_TYPE_BOOLEAN:
 599                 if (smb_config_getbool(id))
 600                         (void) strlcpy(cbuf, "true", bufsz);
 601                 else
 602                         (void) strlcpy(cbuf, "false", bufsz);
 603                 return (SMBD_SMF_OK);
 604         }
 605 
 606         return (SMBD_SMF_INVALID_ARG);
 607 }
 608 
 609 /*
 610  * smb_config_setstr
 611  *
 612  * Set the specified config param with the given
 613  * value.
 614  */
 615 int
 616 smb_config_setstr(smb_cfg_id_t id, char *value)
 617 {
 618         smb_scfhandle_t *handle;
 619         smb_cfg_param_t *cfg;
 620         int rc = SMBD_SMF_OK;
 621         boolean_t protected;
 622         char *tmp = NULL;
 623         char *pg;
 624 
 625         cfg = smb_config_getent(id);
 626         assert(cfg->sc_type == SCF_TYPE_ASTRING);
 627 
 628         if (id == SMB_CI_ADS_SITE)
 629                 return (smb_config_set_idmap_site_name(value));
 630         if (id == SMB_CI_DOMAIN_SRV)
 631                 return (smb_config_set_idmap_preferred_dc(value));
 632 
 633         protected = B_FALSE;
 634 
 635         switch (cfg->sc_flags) {
 636         case SMB_CF_PROTECTED:
 637                 protected = B_TRUE;
 638                 pg = SMBD_PROTECTED_PG_NAME;
 639                 break;
 640         case SMB_CF_EXEC:
 641                 pg = SMBD_EXEC_PG_NAME;
 642                 break;
 643         default:
 644                 pg = SMBD_PG_NAME;
 645                 break;
 646         }
 647 
 648         handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
 649         if (handle == NULL)
 650                 return (SMBD_SMF_SYSTEM_ERR);
 651 
 652         rc = smb_smf_create_service_pgroup(handle, pg);
 653         if (rc == SMBD_SMF_OK)
 654                 rc = smb_smf_start_transaction(handle);
 655 
 656         if (rc != SMBD_SMF_OK) {
 657                 smb_smf_scf_fini(handle);
 658                 return (rc);
 659         }
 660 
 661         if (protected && value && (*value != '\0')) {
 662                 if ((tmp = smb_base64_encode(value)) == NULL) {
 663                         (void) smb_smf_end_transaction(handle);
 664                         smb_smf_scf_fini(handle);
 665                         return (SMBD_SMF_NO_MEMORY);
 666                 }
 667 
 668                 value = tmp;
 669         }
 670 
 671         /*
 672          * We don't want people who care enough about protecting their data
 673          * by requiring encryption to accidentally expose their data
 674          * by lowering the protocol, so prevent them from going below 3.0
 675          * if encryption is required.
 676          * Also, ensure that max_protocol >= min_protocol.
 677          */
 678         if (id == SMB_CI_MAX_PROTOCOL) {
 679                 smb_cfg_val_t encrypt;
 680                 uint32_t min;
 681                 uint32_t val;
 682 
 683                 encrypt = smb_config_get_require(SMB_CI_ENCRYPT);
 684                 min = smb_config_get_min_protocol();
 685                 val = smb_convert_version_str(value);
 686 
 687                 if (encrypt == SMB_CONFIG_REQUIRED &&
 688                     val < SMB_VERS_3_0) {
 689                         syslog(LOG_ERR, "Cannot set smbd/max_protocol below 3.0"
 690                             " while smbd/encrypt == required.");
 691                         rc = SMBD_SMF_INVALID_ARG;
 692                 } else if (val < min) {
 693                         syslog(LOG_ERR, "Cannot set smbd/max_protocol to less"
 694                             " than smbd/min_protocol.");
 695                         rc = SMBD_SMF_INVALID_ARG;
 696                 }
 697         } else if (id == SMB_CI_MIN_PROTOCOL) {
 698                 uint32_t max;
 699                 uint32_t val;
 700 
 701                 max = smb_config_get_max_protocol();
 702                 val = smb_convert_version_str(value);
 703 
 704                 if (val > max) {
 705                         syslog(LOG_ERR, "Cannot set smbd/min_protocol to more"
 706                             " than smbd/max_protocol.");
 707                         rc = SMBD_SMF_INVALID_ARG;
 708                 }
 709         }
 710 
 711         if (rc == SMBD_SMF_OK) {
 712                 rc = smb_smf_set_string_property(handle, cfg->sc_name, value);
 713         }
 714 
 715         free(tmp);
 716         (void) smb_smf_end_transaction(handle);
 717         smb_smf_scf_fini(handle);
 718         return (rc);
 719 }
 720 
 721 /*
 722  * smb_config_setnum
 723  *
 724  * Sets a numeric configuration iterm
 725  */
 726 int
 727 smb_config_setnum(smb_cfg_id_t id, int64_t value)
 728 {
 729         smb_scfhandle_t *handle;
 730         smb_cfg_param_t *cfg;
 731         int rc = SMBD_SMF_OK;
 732 
 733         cfg = smb_config_getent(id);
 734         assert(cfg->sc_type == SCF_TYPE_INTEGER);
 735 
 736         handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
 737         if (handle == NULL)
 738                 return (SMBD_SMF_SYSTEM_ERR);
 739 
 740         rc = smb_smf_create_service_pgroup(handle, SMBD_PG_NAME);
 741         if (rc == SMBD_SMF_OK)
 742                 rc = smb_smf_start_transaction(handle);
 743 
 744         if (rc != SMBD_SMF_OK) {
 745                 smb_smf_scf_fini(handle);
 746                 return (rc);
 747         }
 748 
 749         rc = smb_smf_set_integer_property(handle, cfg->sc_name, value);
 750 
 751         (void) smb_smf_end_transaction(handle);
 752         smb_smf_scf_fini(handle);
 753         return (rc);
 754 }
 755 
 756 /*
 757  * smb_config_setbool
 758  *
 759  * Sets a boolean configuration iterm
 760  */
 761 int
 762 smb_config_setbool(smb_cfg_id_t id, boolean_t value)
 763 {
 764         smb_scfhandle_t *handle;
 765         smb_cfg_param_t *cfg;
 766         int rc = SMBD_SMF_OK;
 767 
 768         cfg = smb_config_getent(id);
 769         assert(cfg->sc_type == SCF_TYPE_BOOLEAN);
 770 
 771         handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
 772         if (handle == NULL)
 773                 return (SMBD_SMF_SYSTEM_ERR);
 774 
 775         rc = smb_smf_create_service_pgroup(handle, SMBD_PG_NAME);
 776         if (rc == SMBD_SMF_OK)
 777                 rc = smb_smf_start_transaction(handle);
 778 
 779         if (rc != SMBD_SMF_OK) {
 780                 smb_smf_scf_fini(handle);
 781                 return (rc);
 782         }
 783 
 784         rc = smb_smf_set_boolean_property(handle, cfg->sc_name, value);
 785 
 786         (void) smb_smf_end_transaction(handle);
 787         smb_smf_scf_fini(handle);
 788         return (rc);
 789 }
 790 
 791 /*
 792  * smb_config_set
 793  *
 794  * This function sets the value of the specified config
 795  * iterm regardless of its type in string format. This should
 796  * be used when the config item type is not known by the caller.
 797  */
 798 int
 799 smb_config_set(smb_cfg_id_t id, char *value)
 800 {
 801         smb_cfg_param_t *cfg;
 802         int64_t cint;
 803 
 804         cfg = smb_config_getent(id);
 805         switch (cfg->sc_type) {
 806         case SCF_TYPE_ASTRING:
 807                 return (smb_config_setstr(id, value));
 808 
 809         case SCF_TYPE_INTEGER:
 810                 cint = atoi(value);
 811                 return (smb_config_setnum(id, cint));
 812 
 813         case SCF_TYPE_BOOLEAN:
 814                 return (smb_config_setbool(id, strcasecmp(value, "true") == 0));
 815         }
 816 
 817         return (SMBD_SMF_INVALID_ARG);
 818 }
 819 
 820 int
 821 smb_config_get_debug()
 822 {
 823         int64_t val64;
 824         int val = 0;    /* default */
 825         smb_scfhandle_t *handle = NULL;
 826 
 827         handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
 828         if (handle == NULL) {
 829                 return (val);
 830         }
 831 
 832         if (smb_smf_create_service_pgroup(handle,
 833             SMBD_PG_NAME) != SMBD_SMF_OK) {
 834                 smb_smf_scf_fini(handle);
 835                 return (val);
 836         }
 837 
 838         if (smb_smf_get_integer_property(handle, "debug", &val64) != 0) {
 839                 smb_smf_scf_fini(handle);
 840                 return (val);
 841         }
 842         val = (int)val64;
 843 
 844         smb_smf_scf_fini(handle);
 845 
 846         return (val);
 847 }
 848 
 849 uint8_t
 850 smb_config_get_fg_flag()
 851 {
 852         uint8_t run_fg = 0; /* Default is to run in daemon mode */
 853         smb_scfhandle_t *handle = NULL;
 854 
 855         handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
 856         if (handle == NULL) {
 857                 return (run_fg);
 858         }
 859 
 860         if (smb_smf_create_service_pgroup(handle,
 861             SMBD_PG_NAME) != SMBD_SMF_OK) {
 862                 smb_smf_scf_fini(handle);
 863                 return (run_fg);
 864         }
 865 
 866         if (smb_smf_get_boolean_property(handle, "run_fg", &run_fg) != 0) {
 867                 smb_smf_scf_fini(handle);
 868                 return (run_fg);
 869         }
 870 
 871         smb_smf_scf_fini(handle);
 872 
 873         return (run_fg);
 874 }
 875 
 876 /*
 877  * smb_config_get_ads_enable
 878  *
 879  * Returns value of the "config/use_ads" parameter
 880  * from the IDMAP SMF configuration repository.
 881  *
 882  */
 883 boolean_t
 884 smb_config_get_ads_enable(void)
 885 {
 886         smb_scfhandle_t *handle = NULL;
 887         uint8_t vbool;
 888         int rc = 0;
 889 
 890         handle = smb_smf_scf_init(IDMAP_FMRI_PREFIX);
 891         if (handle == NULL)
 892                 return (B_FALSE);
 893 
 894         rc = smb_smf_create_service_pgroup(handle, IDMAP_PG_NAME);
 895         if (rc == SMBD_SMF_OK)
 896                 rc = smb_smf_get_boolean_property(handle, "use_ads", &vbool);
 897         smb_smf_scf_fini(handle);
 898 
 899         return ((rc == SMBD_SMF_OK) ? (vbool == 1) : B_TRUE);
 900 }
 901 
 902 /*
 903  * smb_config_get_localsid
 904  *
 905  * Returns value of the "config/machine_sid" parameter
 906  * from the IDMAP SMF configuration repository.
 907  * Result is allocated; caller should free.
 908  */
 909 char *
 910 smb_config_get_localsid(void)
 911 {
 912         return (smb_config_getenv_generic(MACHINE_SID, IDMAP_FMRI_PREFIX,
 913             IDMAP_PG_NAME));
 914 }
 915 
 916 /*
 917  * smb_config_get_localuuid
 918  *
 919  * Returns value of the "config/machine_uuid" parameter
 920  * from the IDMAP SMF configuration repository.
 921  *
 922  */
 923 int
 924 smb_config_get_localuuid(uuid_t uu)
 925 {
 926         char *s;
 927 
 928         uuid_clear(uu);
 929         s = smb_config_getenv_generic(MACHINE_UUID, IDMAP_FMRI_PREFIX,
 930             IDMAP_PG_NAME);
 931         if (s == NULL)
 932                 return (-1);
 933 
 934         if (uuid_parse(s, uu) < 0) {
 935                 free(s);
 936                 return (-1);
 937         }
 938 
 939         return (0);
 940 }
 941 
 942 static int
 943 smb_config_get_idmap_preferred_dc(char *cbuf, int bufsz)
 944 {
 945         char *s;
 946         int len, rc = -1;
 947 
 948         s = smb_config_getenv_generic(IDMAP_PREF_DC,
 949             IDMAP_FMRI_PREFIX, IDMAP_PG_NAME);
 950         if (s != NULL) {
 951                 len = strlcpy(cbuf, s, bufsz);
 952                 if (len < bufsz)
 953                         rc = 0;
 954                 free(s);
 955         }
 956         return (rc);
 957 }
 958 
 959 static int
 960 smb_config_set_idmap_preferred_dc(char *value)
 961 {
 962         return (smb_config_setenv_generic(IDMAP_FMRI_PREFIX, IDMAP_PG_NAME,
 963             IDMAP_PREF_DC, value));
 964 }
 965 
 966 static int
 967 smb_config_get_idmap_site_name(char *cbuf, int bufsz)
 968 {
 969         char *s;
 970         int len, rc = -1;
 971 
 972         s = smb_config_getenv_generic(IDMAP_SITE_NAME,
 973             IDMAP_FMRI_PREFIX, IDMAP_PG_NAME);
 974         if (s != NULL) {
 975                 len = strlcpy(cbuf, s, bufsz);
 976                 if (len < bufsz)
 977                         rc = 0;
 978                 free(s);
 979         }
 980         return (rc);
 981 }
 982 
 983 static int
 984 smb_config_set_idmap_site_name(char *value)
 985 {
 986         return (smb_config_setenv_generic(IDMAP_FMRI_PREFIX, IDMAP_PG_NAME,
 987             IDMAP_SITE_NAME, value));
 988 }
 989 
 990 /*
 991  * smb_config_set_idmap_domain
 992  *
 993  * Set the "config/domain_name" parameter from IDMAP SMF repository.
 994  */
 995 int
 996 smb_config_set_idmap_domain(char *value)
 997 {
 998         return (smb_config_setenv_generic(IDMAP_FMRI_PREFIX, IDMAP_PG_NAME,
 999             IDMAP_DOMAIN, value));
1000 }
1001 
1002 /*
1003  * smb_config_refresh_idmap
1004  *
1005  * Refresh IDMAP SMF service after making changes to its configuration.
1006  */
1007 int
1008 smb_config_refresh_idmap(void)
1009 {
1010         char instance[32];
1011 
1012         (void) snprintf(instance, sizeof (instance), "%s:default",
1013             IDMAP_FMRI_PREFIX);
1014         return (smf_refresh_instance(instance));
1015 }
1016 
1017 int
1018 smb_config_secmode_fromstr(char *secmode)
1019 {
1020         if (secmode == NULL)
1021                 return (SMB_SECMODE_WORKGRP);
1022 
1023         if (strcasecmp(secmode, SMB_SECMODE_DOMAIN_STR) == 0)
1024                 return (SMB_SECMODE_DOMAIN);
1025 
1026         return (SMB_SECMODE_WORKGRP);
1027 }
1028 
1029 char *
1030 smb_config_secmode_tostr(int secmode)
1031 {
1032         if (secmode == SMB_SECMODE_DOMAIN)
1033                 return (SMB_SECMODE_DOMAIN_STR);
1034 
1035         return (SMB_SECMODE_WORKGRP_STR);
1036 }
1037 
1038 int
1039 smb_config_get_secmode()
1040 {
1041         char p[16];
1042 
1043         (void) smb_config_getstr(SMB_CI_SECURITY, p, sizeof (p));
1044         return (smb_config_secmode_fromstr(p));
1045 }
1046 
1047 int
1048 smb_config_set_secmode(int secmode)
1049 {
1050         char *p;
1051 
1052         p = smb_config_secmode_tostr(secmode);
1053         return (smb_config_setstr(SMB_CI_SECURITY, p));
1054 }
1055 
1056 void
1057 smb_config_getdomaininfo(char *domain, char *fqdn, char *sid, char *forest,
1058     char *guid)
1059 {
1060         if (domain)
1061                 (void) smb_config_getstr(SMB_CI_DOMAIN_NAME, domain,
1062                     NETBIOS_NAME_SZ);
1063 
1064         if (fqdn)
1065                 (void) smb_config_getstr(SMB_CI_DOMAIN_FQDN, fqdn,
1066                     MAXHOSTNAMELEN);
1067 
1068         if (sid)
1069                 (void) smb_config_getstr(SMB_CI_DOMAIN_SID, sid,
1070                     SMB_SID_STRSZ);
1071 
1072         if (forest)
1073                 (void) smb_config_getstr(SMB_CI_DOMAIN_FOREST, forest,
1074                     MAXHOSTNAMELEN);
1075 
1076         if (guid)
1077                 (void) smb_config_getstr(SMB_CI_DOMAIN_GUID, guid,
1078                     UUID_PRINTABLE_STRING_LENGTH);
1079 }
1080 
1081 void
1082 smb_config_setdomaininfo(char *domain, char *fqdn, char *sid, char *forest,
1083     char *guid)
1084 {
1085         if (domain)
1086                 (void) smb_config_setstr(SMB_CI_DOMAIN_NAME, domain);
1087         if (fqdn)
1088                 (void) smb_config_setstr(SMB_CI_DOMAIN_FQDN, fqdn);
1089         if (sid)
1090                 (void) smb_config_setstr(SMB_CI_DOMAIN_SID, sid);
1091         if (forest)
1092                 (void) smb_config_setstr(SMB_CI_DOMAIN_FOREST, forest);
1093         if (guid)
1094                 (void) smb_config_setstr(SMB_CI_DOMAIN_GUID, guid);
1095 }
1096 
1097 /*
1098  * The version stored in SMF in string format as N.N where
1099  * N is a number defined by Microsoft. The first number represents
1100  * the major version and the second number is the minor version.
1101  * Current defined values can be found here in 'ver_table'.
1102  *
1103  * This function reads the SMF string value and converts it to
1104  * two numbers returned in the given 'version' structure.
1105  * Current default version number is 5.0 which is for Windows 2000.
1106  */
1107 void
1108 smb_config_get_version(smb_version_t *version)
1109 {
1110         smb_version_t tmpver;
1111         char verstr[SMB_VERSTR_LEN];
1112         char *p;
1113         int rc, i;
1114         static smb_version_t ver_table [] = {
1115                 { 0, SMB_MAJOR_NT,      SMB_MINOR_NT,           1381,   0 },
1116                 { 0, SMB_MAJOR_2000,    SMB_MINOR_2000,         2195,   0 },
1117                 { 0, SMB_MAJOR_XP,      SMB_MINOR_XP,           2196,   0 },
1118                 { 0, SMB_MAJOR_2003,    SMB_MINOR_2003,         2196,   0 },
1119                 { 0, SMB_MAJOR_VISTA,   SMB_MINOR_VISTA,        6000,   0 },
1120                 { 0, SMB_MAJOR_2008,    SMB_MINOR_2008,         6000,   0 },
1121                 { 0, SMB_MAJOR_2008R2,  SMB_MINOR_2008R2,       7007,   0 },
1122                 { 0, SMB_MAJOR_7,       SMB_MINOR_7,            7007,   0 }
1123         };
1124 
1125         *version = ver_table[1];
1126         version->sv_size = sizeof (smb_version_t);
1127 
1128         rc = smb_config_getstr(SMB_CI_VERSION, verstr, sizeof (verstr));
1129         if (rc != SMBD_SMF_OK)
1130                 return;
1131 
1132         if ((p = strchr(verstr, '.')) == NULL)
1133                 return;
1134 
1135         *p = '\0';
1136         tmpver.sv_major = (uint8_t)atoi(verstr);
1137         tmpver.sv_minor = (uint8_t)atoi(p + 1);
1138 
1139         for (i = 0; i < sizeof (ver_table)/sizeof (ver_table[0]); ++i) {
1140                 if ((tmpver.sv_major == ver_table[i].sv_major) &&
1141                     (tmpver.sv_minor == ver_table[i].sv_minor)) {
1142                         *version = ver_table[i];
1143                         version->sv_size = sizeof (smb_version_t);
1144                         break;
1145                 }
1146         }
1147 }
1148 
1149 /*
1150  * Reads share exec script properties
1151  */
1152 uint32_t
1153 smb_config_get_execinfo(char *map, char *unmap, size_t bufsz)
1154 {
1155         char buf[MAXPATHLEN];
1156         uint32_t flags = 0;
1157 
1158         if (map == NULL) {
1159                 map = buf;
1160                 bufsz = MAXPATHLEN;
1161         }
1162 
1163         *map = '\0';
1164         (void) smb_config_getstr(SMB_CI_MAP, map, bufsz);
1165         if (*map != '\0')
1166                 flags |= SMB_EXEC_MAP;
1167 
1168         if (unmap == NULL) {
1169                 unmap = buf;
1170                 bufsz = MAXPATHLEN;
1171         }
1172 
1173         *unmap = '\0';
1174         (void) smb_config_getstr(SMB_CI_UNMAP, unmap, bufsz);
1175         if (*unmap != '\0')
1176                 flags |= SMB_EXEC_UNMAP;
1177 
1178         *buf = '\0';
1179         (void) smb_config_getstr(SMB_CI_DISPOSITION, buf, sizeof (buf));
1180         if (*buf != '\0')
1181                 if (strcasecmp(buf, SMB_EXEC_DISP_TERMINATE) == 0)
1182                         flags |= SMB_EXEC_TERM;
1183 
1184         return (flags);
1185 }
1186 
1187 static smb_cfg_param_t *
1188 smb_config_getent(smb_cfg_id_t id)
1189 {
1190         int i;
1191 
1192         for (i = 0; i < SMB_CI_MAX; i++)
1193                 if (smb_cfg_table[i].sc_id == id)
1194                         return (&smb_cfg_table[id]);
1195 
1196         assert(0);
1197         return (NULL);
1198 }
1199 
1200 static uint32_t
1201 smb_config_get_protocol(smb_cfg_id_t id, char *name, uint32_t default_val)
1202 {
1203         char str[SMB_VERSTR_LEN];
1204         int rc;
1205         uint32_t val;
1206 
1207         rc = smb_config_getstr(id, str, sizeof (str));
1208         if (rc == SMBD_SMF_OK) {
1209                 val = smb_convert_version_str(str);
1210                 if (val != 0)
1211                         return (val);
1212                 if (str[0] != '\0') {
1213                         syslog(LOG_ERR, "smbd/%s value invalid: %s", name, str);
1214                 }
1215         }
1216 
1217         return (default_val);
1218 }
1219 
1220 /*
1221  * The service manifest has empty values by default for min_protocol and
1222  * max_protocol. The expectation is that when those values are empty, we don't
1223  * constrain the range of supported protocol versions (and allow use of the
1224  * whole range that we implement). For that reason, this should usually be the
1225  * highest protocol version we implement.
1226  */
1227 uint32_t max_protocol_default = SMB_VERS_3_02;
1228 
1229 uint32_t
1230 smb_config_get_max_protocol(void)
1231 {
1232         uint32_t max;
1233 
1234         max = smb_config_get_protocol(SMB_CI_MAX_PROTOCOL, "max_protocol",
1235             max_protocol_default);
1236 
1237         return (max);
1238 }
1239 
1240 /*
1241  * This should eventually be SMB_VERS_2_BASE
1242  */
1243 uint32_t min_protocol_default = SMB_VERS_1;
1244 
1245 uint32_t
1246 smb_config_get_min_protocol(void)
1247 {
1248         uint32_t min;
1249 
1250         min = smb_config_get_protocol(SMB_CI_MIN_PROTOCOL, "min_protocol",
1251             min_protocol_default);
1252 
1253         return (min);
1254 }
1255 
1256 int
1257 smb_config_check_protocol(char *value)
1258 {
1259         if (smb_convert_version_str(value) != 0)
1260                 return (0);
1261 
1262         return (-1);
1263 }
1264 
1265 /*
1266  * If smb2_enable is present and max_protocol is empty,
1267  * set max_protocol.  Delete smb2_enable.
1268  */
1269 static void
1270 upgrade_smb2_enable()
1271 {
1272         smb_scfhandle_t *handle;
1273         char *s2e_name = "smb2_enable";
1274         char *s2e_sval;
1275         uint8_t s2e_bval;
1276         char *maxp_name = "max_protocol";
1277         char *maxp_sval;
1278         char verstr[SMB_VERSTR_LEN];
1279         int rc;
1280 
1281         handle = smb_smf_scf_init(SMBD_FMRI_PREFIX);
1282         if (handle == NULL)
1283                 return;
1284         rc = smb_smf_create_service_pgroup(handle, SMBD_PG_NAME);
1285         if (rc != SMBD_SMF_OK)
1286                 goto out;
1287 
1288         /* Is there an "smb2_enable" property? */
1289         rc = smb_smf_get_boolean_property(handle, s2e_name, &s2e_bval);
1290         if (rc != SMBD_SMF_OK) {
1291                 syslog(LOG_DEBUG, "upgrade: smb2_enable not found");
1292                 goto out;
1293         }
1294 
1295         /*
1296          * We will try to delete the smb2_enable property, so we need
1297          * the transaction to start now, before we modify max_protocol
1298          */
1299         if ((rc = smb_smf_start_transaction(handle)) != 0) {
1300                 syslog(LOG_DEBUG, "upgrade_smb2_enable: start trans (%d)", rc);
1301                 goto out;
1302         }
1303 
1304         /*
1305          * Old (smb2_enable) property exists.
1306          * Does the new one? (max_protocol)
1307          */
1308         rc = smb_smf_get_string_property(handle, maxp_name,
1309             verstr, sizeof (verstr));
1310         if (rc == SMBD_SMF_OK && !smb_config_check_protocol(verstr)) {
1311                 syslog(LOG_DEBUG, "upgrade: found %s = %s",
1312                     maxp_name, verstr);
1313                 /* Leave existing max_protocol as we found it. */
1314         } else {
1315                 /*
1316                  * New property missing or invalid.
1317                  * Upgrade from "smb2_enable".
1318                  */
1319                 if (s2e_bval == 0) {
1320                         s2e_sval = "false";
1321                         maxp_sval = "1";
1322                 } else {
1323                         s2e_sval = "true";
1324                         maxp_sval = "2.1";
1325                 }
1326                 /*
1327                  * Note: Need this in the same transaction as the
1328                  * delete of smb2_enable below.
1329                  */
1330                 rc = smb_smf_set_string_property(handle, maxp_name, maxp_sval);
1331                 if (rc != SMBD_SMF_OK) {
1332                         syslog(LOG_ERR, "failed to set smbd/%d (%d)",
1333                             maxp_name, rc);
1334                         goto out;
1335                 }
1336                 syslog(LOG_INFO, "upgrade smbd/smb2_enable=%s "
1337                     "converted to smbd/max_protocol=%s",
1338                     s2e_sval, maxp_sval);
1339         }
1340 
1341         /*
1342          * Delete the old smb2_enable property.
1343          */
1344         if ((rc = smb_smf_delete_property(handle, s2e_name)) != 0) {
1345                 syslog(LOG_DEBUG, "upgrade_smb2_enable: delete prop (%d)", rc);
1346         } else if ((rc = smb_smf_end_transaction(handle)) != 0) {
1347                 syslog(LOG_DEBUG, "upgrade_smb2_enable: end trans (%d)", rc);
1348         }
1349         if (rc != 0) {
1350                 syslog(LOG_ERR, "failed to delete property smbd/%d (%d)",
1351                     s2e_name, rc);
1352         }
1353 
1354 out:
1355         (void) smb_smf_end_transaction(handle);
1356         smb_smf_scf_fini(handle);
1357 }
1358 
1359 
1360 /*
1361  * Run once at startup convert old SMF settings to current.
1362  */
1363 void
1364 smb_config_upgrade(void)
1365 {
1366         upgrade_smb2_enable();
1367 }
1368 
1369 smb_cfg_val_t
1370 smb_config_get_require(smb_cfg_id_t id)
1371 {
1372         int rc;
1373         char str[sizeof ("required")];
1374 
1375         rc = smb_config_getstr(id, str, sizeof (str));
1376         if (rc != SMBD_SMF_OK)
1377                 return (SMB_CONFIG_DISABLED);
1378 
1379         if (strncmp(str, "required", sizeof (str)) == 0)
1380                 return (SMB_CONFIG_REQUIRED);
1381         if (strncmp(str, "enabled", sizeof (str)) == 0)
1382                 return (SMB_CONFIG_ENABLED);
1383 
1384         return (SMB_CONFIG_DISABLED);
1385 }