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