diff options
author | Jerry Jelinek <jerry.jelinek@joyent.com> | 2019-06-11 11:11:22 +0000 |
---|---|---|
committer | Jerry Jelinek <jerry.jelinek@joyent.com> | 2019-06-11 11:11:22 +0000 |
commit | cbb330f03aa8f580120280a310063f06befd0333 (patch) | |
tree | 5bea6dc6c737f2461ee710fb82bf9085d7932412 /usr/src | |
parent | e68253c14d11e4fca612757ffc9b8826eca30f37 (diff) | |
parent | 807b45f18e924af3195f2516242af310f774528c (diff) | |
download | illumos-joyent-cbb330f03aa8f580120280a310063f06befd0333.tar.gz |
[illumos-gate merge]
commit 807b45f18e924af3195f2516242af310f774528c
11093 libsocket: NULL pointer errors
commit 5419c0309c3a28f6bfee2e35aefebca2200d046d
11019 Enable SMB3 server by default
commit 1160dcf7283d2485f2b9c32da573db0275558d9b
11018 SMB3 Encryption
commit 0ab6f5190f1236c6d1d0e14df5129e0694b77426
11204 smatch issue in zlib/deflate.c
Diffstat (limited to 'usr/src')
45 files changed, 1678 insertions, 198 deletions
diff --git a/usr/src/cmd/smbsrv/smbd/server.xml b/usr/src/cmd/smbsrv/smbd/server.xml index 7eea0b877b..d6c445f137 100644 --- a/usr/src/cmd/smbsrv/smbd/server.xml +++ b/usr/src/cmd/smbsrv/smbd/server.xml @@ -22,7 +22,7 @@ information: Portions Copyright [yyyy] [name of copyright owner] CDDL HEADER END Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. -Copyright 2015 Nexenta Systems, Inc. All rights reserved. +Copyright 2016 Nexenta Systems, Inc. All rights reserved. Copyright 2016 Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org> NOTE: This service manifest is not editable; its contents will @@ -229,6 +229,8 @@ file. value='true' override='true'/> <propval name='max_protocol' type='astring' value='' override='true'/> + <propval name='encrypt' type='astring' + value='disabled' override='true'/> <propval name='initial_credits' type='integer' value='20' override='true'/> <propval name='maximum_credits' type='integer' diff --git a/usr/src/common/smbsrv/smb_cfg_util.c b/usr/src/common/smbsrv/smb_cfg_util.c new file mode 100644 index 0000000000..461945895a --- /dev/null +++ b/usr/src/common/smbsrv/smb_cfg_util.c @@ -0,0 +1,37 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2017 Nexenta Systems, Inc. All rights reserved. + */ + +#if !defined(_KERNEL) && !defined(_FAKE_KERNEL) +#include <string.h> +#else +#include <sys/sunddi.h> +#endif +#include <smbsrv/smbinfo.h> + +void +smb_cfg_set_require(const char *value, smb_cfg_val_t *cfg) +{ + if (value == NULL) { + *cfg = SMB_CONFIG_DISABLED; + return; + } + + if (strcmp(value, "required") == 0) + *cfg = SMB_CONFIG_REQUIRED; + else if (strcmp(value, "enabled") == 0) + *cfg = SMB_CONFIG_ENABLED; + else + *cfg = SMB_CONFIG_DISABLED; +} diff --git a/usr/src/contrib/zlib/deflate.c b/usr/src/contrib/zlib/deflate.c index 5cdb078df6..771aad0ec2 100644 --- a/usr/src/contrib/zlib/deflate.c +++ b/usr/src/contrib/zlib/deflate.c @@ -188,8 +188,11 @@ local const config configuration_table[10] = { * prev[] will be initialized on the fly. */ #define CLEAR_HASH(s) \ - s->head[s->hash_size-1] = NIL; \ - zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + do { \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((Bytef *)s->head, \ + (unsigned)(s->hash_size-1)*sizeof(*s->head)); \ + } while (0) /* =========================================================================== * Slide the hash table when sliding the window down (could be avoided with 32 diff --git a/usr/src/lib/libshare/smb/Makefile.com b/usr/src/lib/libshare/smb/Makefile.com index 386ffc35de..c0e735cda7 100644 --- a/usr/src/lib/libshare/smb/Makefile.com +++ b/usr/src/lib/libshare/smb/Makefile.com @@ -22,7 +22,7 @@ # Copyright 2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# Copyright 2013 Nexenta Systems, Inc. All rights reserved. +# Copyright 2017 Nexenta Systems, Inc. All rights reserved. # # Copyright (c) 2018, Joyent, Inc. @@ -33,7 +33,7 @@ SMBBASE_DIR = $(SRC)/lib/smbsrv/libsmb/common SMBCOMMON_DIR = $(SRC)/common/smbsrv LIBOBJS = libshare_smb.o smb_share_doorclnt.o -SMBCOMMON_OBJ = smb_door_legacy.o +SMBCOMMON_OBJ = smb_door_legacy.o smb_cfg_util.o SMBBASE_OBJ = smb_cfg.o smb_scfutil.o OBJECTS = $(LIBOBJS) $(SMBCOMMON_OBJ) $(SMBBASE_OBJ) @@ -56,7 +56,7 @@ CERRWARN += -_gcc=-Wno-switch SMATCH=off CPPFLAGS += -D_REENTRANT -I$(ADJUNCT_PROTO)/usr/include/libxml2 \ - -I$(SRCDIR)/../common + -I$(SRCDIR)/../common $(ENABLE_SMB_PRINTING) CPPFLAGS += -DHAVE_CUPS .KEEP_STATE: @@ -75,6 +75,10 @@ pics/smb_door_legacy.o: $(SMBCOMMON_DIR)/smb_door_legacy.c $(COMPILE.c) -o $@ $(SMBCOMMON_DIR)/smb_door_legacy.c $(POST_PROCESS_O) +pics/smb_cfg_util.o: $(SMBCOMMON_DIR)/smb_cfg_util.c + $(COMPILE.c) -o $@ $(SMBCOMMON_DIR)/smb_cfg_util.c + $(POST_PROCESS_O) + pics/smb_cfg.o: $(SMBBASE_DIR)/smb_cfg.c $(COMPILE.c) -o $@ $(SMBBASE_DIR)/smb_cfg.c $(POST_PROCESS_O) diff --git a/usr/src/lib/libshare/smb/libshare_smb.c b/usr/src/lib/libshare/smb/libshare_smb.c index 5bb4890da2..0429edca77 100644 --- a/usr/src/lib/libshare/smb/libshare_smb.c +++ b/usr/src/lib/libshare/smb/libshare_smb.c @@ -21,7 +21,7 @@ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2015 Nexenta Systems, Inc. All rights reserved. + * Copyright 2017 Nexenta Systems, Inc. All rights reserved. */ /* @@ -85,6 +85,7 @@ static int path_validator(int, char *); static int cmd_validator(int, char *); static int disposition_validator(int, char *); static int max_protocol_validator(int, char *); +static int require_validator(int, char *); static int smb_enable_resource(sa_resource_t); static int smb_disable_resource(sa_resource_t); @@ -180,6 +181,7 @@ struct option_defs optdefs[] = { { SHOPT_DESCRIPTION, OPT_TYPE_STRING }, { SHOPT_FSO, OPT_TYPE_BOOLEAN }, { SHOPT_QUOTAS, OPT_TYPE_BOOLEAN }, + { SHOPT_ENCRYPT, OPT_TYPE_STRING }, { NULL, NULL } }; @@ -918,6 +920,8 @@ struct smb_proto_option_defs { disposition_validator, SMB_REFRESH_REFRESH }, { SMB_CI_MAX_PROTOCOL, 0, MAX_VALUE_BUFLEN, max_protocol_validator, SMB_REFRESH_REFRESH }, + { SMB_CI_ENCRYPT, 0, MAX_VALUE_BUFLEN, require_validator, + SMB_REFRESH_REFRESH }, { SMB_CI_OPLOCK_ENABLE, 0, 0, true_false_validator, SMB_REFRESH_REFRESH }, }; @@ -925,6 +929,24 @@ struct smb_proto_option_defs { #define SMB_OPT_NUM \ (sizeof (smb_proto_options) / sizeof (smb_proto_options[0])) +static int +require_validator(int index, char *value) +{ + if (string_length_check_validator(index, value) != SA_OK) + return (SA_BAD_VALUE); + + if (strcmp(value, "required") == 0) + return (SA_OK); + + if (strcmp(value, "disabled") == 0) + return (SA_OK); + + if (strcmp(value, "enabled") == 0) + return (SA_OK); + + return (SA_BAD_VALUE); +} + /* * Check the range of value as int range. */ @@ -1538,7 +1560,11 @@ smb_set_proto_prop(sa_property_t prop) opt = &smb_proto_options[index]; /* Save to SMF */ - (void) smb_config_set(opt->smb_index, value); + if (smb_config_set(opt->smb_index, + value) != 0) { + ret = SA_BAD_VALUE; + goto out; + } /* * Specialized refresh mechanisms can * be flagged in the proto_options and @@ -1554,6 +1580,7 @@ smb_set_proto_prop(sa_property_t prop) } } +out: if (name != NULL) sa_free_attr_string(name); if (value != NULL) @@ -1941,7 +1968,7 @@ smb_parse_optstring(sa_group_t group, char *options) static void smb_sprint_option(char **rbuff, size_t *rbuffsize, size_t incr, - sa_property_t prop, int sep) + sa_property_t prop, int sep) { char *name; char *value; @@ -2119,6 +2146,7 @@ smb_build_shareinfo(sa_share_t share, sa_resource_t resource, smb_share_t *si) char *rname; char *val = NULL; char csc_value[SMB_CSC_BUFSZ]; + char strbuf[sizeof ("required")]; bzero(si, sizeof (smb_share_t)); @@ -2167,9 +2195,11 @@ smb_build_shareinfo(sa_share_t share, sa_resource_t resource, smb_share_t *si) si->shr_flags |= SMB_SHRF_FSO; /* Quotas are enabled by default. */ - si->shr_flags |= SMB_SHRF_QUOTAS; - if (!smb_saprop_getbool(opts, SHOPT_QUOTAS, B_TRUE)) - si->shr_flags &= ~SMB_SHRF_QUOTAS; + if (smb_saprop_getbool(opts, SHOPT_QUOTAS, B_TRUE)) + si->shr_flags |= SMB_SHRF_QUOTAS; + + if (smb_saprop_getstr(opts, SHOPT_ENCRYPT, strbuf, sizeof (strbuf))) + smb_cfg_set_require(strbuf, &si->shr_encrypt); (void) smb_saprop_getstr(opts, SHOPT_AD_CONTAINER, si->shr_container, sizeof (si->shr_container)); diff --git a/usr/src/lib/libsocket/inet/rcmd.c b/usr/src/lib/libsocket/inet/rcmd.c index d1fdcd2418..8e95f9f00f 100644 --- a/usr/src/lib/libsocket/inet/rcmd.c +++ b/usr/src/lib/libsocket/inet/rcmd.c @@ -25,7 +25,7 @@ */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ -/* All Rights Reserved */ +/* All Rights Reserved */ /* * University Copyright- Copyright (c) 1982, 1986, 1988 @@ -799,8 +799,8 @@ _checkhost(char *rhost, char *lhost, int len) nodomain = 1; return (0); } - ldomain[MAXHOSTNAMELEN] = NULL; - if ((domainp = index(ldomain, '.')) == (char *)NULL) { + ldomain[MAXHOSTNAMELEN] = '\0'; + if ((domainp = index(ldomain, '.')) == NULL) { nodomain = 1; return (0); } diff --git a/usr/src/lib/smbsrv/libfksmbsrv/Makefile.com b/usr/src/lib/smbsrv/libfksmbsrv/Makefile.com index 723a4924ec..c8020ed722 100644 --- a/usr/src/lib/smbsrv/libfksmbsrv/Makefile.com +++ b/usr/src/lib/smbsrv/libfksmbsrv/Makefile.com @@ -31,6 +31,7 @@ VERS = .1 OBJS_LOCAL = \ fksmb_cred.o \ + fksmb_encrypt_pkcs.o \ fksmb_fem.o \ fksmb_idmap.o \ fksmb_init.o \ @@ -155,12 +156,15 @@ OBJS_FS_SMBSRV = \ smb2_signing.o \ smb2_tree_connect.o \ smb2_tree_disconn.o \ - smb2_write.o + smb2_write.o \ + \ + smb3_encrypt.o # Can't just link with -lsmb because of user vs kernel API # i.e. can't call free with mem from kmem_alloc, which is # what happens if we just link with -lsmb OBJS_CMN_SMBSRV = \ + smb_cfg_util.o \ smb_inet.o \ smb_match.o \ smb_msgbuf.o \ diff --git a/usr/src/lib/smbsrv/libfksmbsrv/common/fksmb_encrypt_pkcs.c b/usr/src/lib/smbsrv/libfksmbsrv/common/fksmb_encrypt_pkcs.c new file mode 100644 index 0000000000..54f6709e8d --- /dev/null +++ b/usr/src/lib/smbsrv/libfksmbsrv/common/fksmb_encrypt_pkcs.c @@ -0,0 +1,115 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. + */ + +/* + * Helper functions for SMB3 encryption using PKCS#11 + * + * There are two implementations of these functions: + * This one (for user space) and another for kernel. + * See: uts/common/fs/smbsrv/smb3_encrypt_kcf.c + * + * NOTE: CCM is not implemented in PKCS yet, so these are just stubs. + */ + +#include <smbsrv/smb_kcrypt.h> +#include <smbsrv/smb2_kproto.h> + +/* + * SMB3 encryption helpers: + * (getmech, init, update, final) + */ + +/* ARGSUSED */ +int +smb3_encrypt_getmech(smb_crypto_mech_t *mech) +{ + cmn_err(CE_NOTE, "fksmbsrv does not support SMB3 Encryption"); + return (-1); +} + +/* ARGSUSED */ +void +smb3_crypto_init_param(smb3_crypto_param_t *param, + uint8_t *nonce, size_t noncesize, uint8_t *auth, size_t authsize, + size_t datasize) +{ +} + +/* + * Start the KCF session, load the key + */ + +/* ARGSUSED */ +static int +smb3_crypto_init(smb3_enc_ctx_t *ctxp, smb_crypto_mech_t *mech, + uint8_t *key, size_t key_len, smb3_crypto_param_t *param, + boolean_t is_encrypt) +{ + return (-1); +} + +/* ARGSUSED */ +int +smb3_encrypt_init(smb3_enc_ctx_t *ctxp, smb_crypto_mech_t *mech, + smb3_crypto_param_t *param, uint8_t *key, size_t keylen, + uint8_t *buf, size_t buflen) +{ + return (smb3_crypto_init(ctxp, mech, key, keylen, param, B_TRUE)); +} + +int +smb3_decrypt_init(smb3_enc_ctx_t *ctxp, smb_crypto_mech_t *mech, + smb3_crypto_param_t *param, uint8_t *key, size_t keylen) +{ + return (smb3_crypto_init(ctxp, mech, key, keylen, param, B_FALSE)); +} + +/* + * Digest one segment + */ + +/* ARGSUSED */ +int +smb3_encrypt_update(smb3_enc_ctx_t *ctxp, uint8_t *in, size_t len) +{ + return (-1); +} + +/* ARGSUSED */ +int +smb3_decrypt_update(smb3_enc_ctx_t *ctxp, uint8_t *in, size_t len) +{ + return (-1); +} + +/* ARGSUSED */ +int +smb3_encrypt_final(smb3_enc_ctx_t *ctxp, uint8_t *digest16) +{ + return (-1); +} + +/* ARGSUSED */ +int +smb3_decrypt_final(smb3_enc_ctx_t *ctxp, uint8_t *buf, size_t buflen) +{ + return (-1); +} + +/* ARGSUSED */ +void +smb3_encrypt_cancel(smb3_enc_ctx_t *ctxp) +{ +} diff --git a/usr/src/lib/smbsrv/libfksmbsrv/common/fksmb_sign_pkcs.c b/usr/src/lib/smbsrv/libfksmbsrv/common/fksmb_sign_pkcs.c index 07e1529434..e018c6eb0c 100644 --- a/usr/src/lib/smbsrv/libfksmbsrv/common/fksmb_sign_pkcs.c +++ b/usr/src/lib/smbsrv/libfksmbsrv/common/fksmb_sign_pkcs.c @@ -23,7 +23,7 @@ #include <stdlib.h> #include <smbsrv/smb_kproto.h> -#include <smbsrv/smb_signing.h> +#include <smbsrv/smb_kcrypt.h> #include <security/cryptoki.h> #include <security/pkcs11.h> @@ -31,7 +31,7 @@ * Common function to see if a mech is available. */ static int -find_mech(smb_sign_mech_t *mech, ulong_t mid) +find_mech(smb_crypto_mech_t *mech, ulong_t mid) { CK_SESSION_HANDLE hdl; CK_RV rv; @@ -59,7 +59,7 @@ find_mech(smb_sign_mech_t *mech, ulong_t mid) * Find out if we have this mech. */ int -smb_md5_getmech(smb_sign_mech_t *mech) +smb_md5_getmech(smb_crypto_mech_t *mech) { return (find_mech(mech, CKM_MD5)); } @@ -68,7 +68,7 @@ smb_md5_getmech(smb_sign_mech_t *mech) * Start PKCS#11 session. */ int -smb_md5_init(smb_sign_ctx_t *ctxp, smb_sign_mech_t *mech) +smb_md5_init(smb_sign_ctx_t *ctxp, smb_crypto_mech_t *mech) { CK_RV rv; @@ -120,7 +120,7 @@ smb_md5_final(smb_sign_ctx_t ctx, uint8_t *digest16) * Find out if we have this mech. */ int -smb2_hmac_getmech(smb_sign_mech_t *mech) +smb2_hmac_getmech(smb_crypto_mech_t *mech) { return (find_mech(mech, CKM_SHA256_HMAC)); } @@ -129,7 +129,7 @@ smb2_hmac_getmech(smb_sign_mech_t *mech) * Start PKCS#11 session, load the key. */ int -smb2_hmac_init(smb_sign_ctx_t *ctxp, smb_sign_mech_t *mech, +smb2_hmac_init(smb_sign_ctx_t *ctxp, smb_crypto_mech_t *mech, uint8_t *key, size_t key_len) { CK_OBJECT_HANDLE hkey = 0; @@ -194,7 +194,7 @@ smb2_hmac_final(smb_sign_ctx_t ctx, uint8_t *digest16) * Find out if we have this mech. */ int -smb3_cmac_getmech(smb_sign_mech_t *mech) +smb3_cmac_getmech(smb_crypto_mech_t *mech) { return (find_mech(mech, CKM_AES_CMAC)); } @@ -203,7 +203,7 @@ smb3_cmac_getmech(smb_sign_mech_t *mech) * Start PKCS#11 session, load the key. */ int -smb3_cmac_init(smb_sign_ctx_t *ctxp, smb_sign_mech_t *mech, +smb3_cmac_init(smb_sign_ctx_t *ctxp, smb_crypto_mech_t *mech, uint8_t *key, size_t key_len) { CK_OBJECT_HANDLE hkey = 0; diff --git a/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c b/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c index 1ab3ba640e..a34544ba2e 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c @@ -19,7 +19,7 @@ * CDDL HEADER END * * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2016 Nexenta Systems, Inc. All rights reserved. + * Copyright 2017 Nexenta Systems, Inc. All rights reserved. */ /* @@ -788,6 +788,8 @@ smb_shr_modify(smb_share_t *new_si) si->shr_flags &= ~SMB_SHRF_ACC_ALL; si->shr_flags |= access; + si->shr_encrypt = new_si->shr_encrypt; + if (access & SMB_SHRF_ACC_NONE) (void) strlcpy(si->shr_access_none, new_si->shr_access_none, sizeof (si->shr_access_none)); @@ -1789,6 +1791,12 @@ smb_shr_sa_get(sa_share_t share, sa_resource_t resource, smb_share_t *si) si->shr_flags |= SMB_SHRF_QUOTAS; } + val = smb_shr_sa_getprop(opts, SHOPT_ENCRYPT); + if (val != NULL) { + smb_cfg_set_require(val, &si->shr_encrypt); + free(val); + } + val = smb_shr_sa_getprop(opts, SHOPT_CSC); if (val != NULL) { smb_shr_sa_csc_option(val, si); @@ -2561,6 +2569,13 @@ smb_shr_encode(smb_share_t *si, nvlist_t **nvlist) if ((si->shr_flags & SMB_SHRF_QUOTAS) != 0) rc |= nvlist_add_string(smb, SHOPT_QUOTAS, "true"); + if (si->shr_encrypt == SMB_CONFIG_REQUIRED) + rc |= nvlist_add_string(smb, SHOPT_ENCRYPT, "required"); + else if (si->shr_encrypt == SMB_CONFIG_ENABLED) + rc |= nvlist_add_string(smb, SHOPT_ENCRYPT, "enabled"); + else + rc |= nvlist_add_string(smb, SHOPT_ENCRYPT, "disabled"); + if ((si->shr_flags & SMB_SHRF_AUTOHOME) != 0) { rc |= nvlist_add_string(smb, SHOPT_AUTOHOME, "true"); rc |= nvlist_add_uint32(smb, "uid", si->shr_uid); diff --git a/usr/src/lib/smbsrv/libsmb/Makefile.com b/usr/src/lib/smbsrv/libsmb/Makefile.com index fd685fc2f9..fc3c4e0b6b 100644 --- a/usr/src/lib/smbsrv/libsmb/Makefile.com +++ b/usr/src/lib/smbsrv/libsmb/Makefile.com @@ -20,7 +20,7 @@ # # # Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. -# Copyright 2014 Nexenta Systems, Inc. All rights reserved. +# Copyright 2017 Nexenta Systems, Inc. All rights reserved. # # Copyright (c) 2018, Joyent, Inc. @@ -28,6 +28,7 @@ LIBRARY= libsmb.a VERS= .1 OBJS_SHARED = \ + smb_cfg_util.o \ smb_door_legacy.o \ smb_inet.o \ smb_msgbuf.o \ diff --git a/usr/src/lib/smbsrv/libsmb/common/libsmb.h b/usr/src/lib/smbsrv/libsmb/common/libsmb.h index 06c072e70f..3c60630327 100644 --- a/usr/src/lib/smbsrv/libsmb/common/libsmb.h +++ b/usr/src/lib/smbsrv/libsmb/common/libsmb.h @@ -21,7 +21,7 @@ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2015 Nexenta Systems, Inc. All rights reserved. + * Copyright 2016 Nexenta Systems, Inc. All rights reserved. */ #ifndef _LIBSMB_H @@ -157,6 +157,7 @@ typedef enum { SMB_CI_INITIAL_CREDITS, SMB_CI_MAXIMUM_CREDITS, SMB_CI_MAX_PROTOCOL, + SMB_CI_ENCRYPT, SMB_CI_MAX } smb_cfg_id_t; @@ -217,6 +218,8 @@ extern int smb_config_check_protocol(char *); extern uint32_t smb_config_get_max_protocol(void); extern void smb_config_upgrade(void); +extern smb_cfg_val_t smb_config_get_require(smb_cfg_id_t); + extern void smb_load_kconfig(smb_kmod_cfg_t *kcfg); extern uint32_t smb_crc_gen(uint8_t *, size_t); diff --git a/usr/src/lib/smbsrv/libsmb/common/mapfile-vers b/usr/src/lib/smbsrv/libsmb/common/mapfile-vers index 37b8272be4..507165ade8 100644 --- a/usr/src/lib/smbsrv/libsmb/common/mapfile-vers +++ b/usr/src/lib/smbsrv/libsmb/common/mapfile-vers @@ -19,7 +19,7 @@ # # # Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. -# Copyright 2015 Nexenta Systems, Inc. All rights reserved. +# Copyright 2017 Nexenta Systems, Inc. All rights reserved. # # @@ -93,6 +93,7 @@ SYMBOL_VERSION SUNWprivate { smb_cache_ready; smb_cache_refreshing; smb_cache_remove; + smb_cfg_set_require; smb_chk_hostaccess; smb_codepage_init; smb_common_decode; diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c b/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c index 0bc13e4a3c..3a82584c03 100644 --- a/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c +++ b/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c @@ -20,7 +20,7 @@ */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2015 Nexenta Systems, Inc. All rights reserved. + * Copyright 2016 Nexenta Systems, Inc. All rights reserved. */ /* @@ -146,10 +146,29 @@ static smb_cfg_param_t smb_cfg_table[] = {SMB_CI_INITIAL_CREDITS, "initial_credits", SCF_TYPE_INTEGER, 0}, {SMB_CI_MAXIMUM_CREDITS, "maximum_credits", SCF_TYPE_INTEGER, 0}, {SMB_CI_MAX_PROTOCOL, "max_protocol", SCF_TYPE_ASTRING, 0}, + {SMB_CI_ENCRYPT, "encrypt", SCF_TYPE_ASTRING, 0}, /* SMB_CI_MAX */ }; +/* + * We store the max SMB protocol version in SMF as a string, + * (for convenience of svccfg etc) but the programmatic get/set + * interfaces use the numeric form. + * + * The numeric values are as defined in the [MS-SMB2] spec. + * except for how we represent "1" (for SMB1) which is an + * arbitrary value below SMB2_VERS_BASE. + */ +static struct str_val +smb_versions[] = { + { "3.0", SMB_VERS_3_0 }, + { "2.1", SMB_VERS_2_1 }, + { "2.002", SMB_VERS_2_002 }, + { "1", SMB_VERS_1 }, + { NULL, 0 } +}; + static smb_cfg_param_t *smb_config_getent(smb_cfg_id_t); static boolean_t smb_is_base64(unsigned char c); @@ -160,6 +179,20 @@ static int smb_config_set_idmap_preferred_dc(char *); static int smb_config_get_idmap_site_name(char *, int); static int smb_config_set_idmap_site_name(char *); +static uint32_t +smb_convert_version_str(const char *version) +{ + uint32_t dialect = 0; + int i; + + for (i = 0; smb_versions[i].str != NULL; i++) { + if (strcmp(version, smb_versions[i].str) == 0) + dialect = smb_versions[i].val; + } + + return (dialect); +} + char * smb_config_getname(smb_cfg_id_t id) { @@ -631,7 +664,22 @@ smb_config_setstr(smb_cfg_id_t id, char *value) value = tmp; } - rc = smb_smf_set_string_property(handle, cfg->sc_name, value); + /* + * We don't want people who care enough about protecting their data + * by requiring encryption to accidentally expose their data + * by lowering the protocol, so prevent them from going below 3.0 + * if encryption is required. + */ + if (id == SMB_CI_MAX_PROTOCOL && + smb_config_get_require(SMB_CI_ENCRYPT) == SMB_CONFIG_REQUIRED && + smb_config_get_max_protocol() >= SMB_VERS_3_0 && + smb_convert_version_str(value) < SMB_VERS_3_0) { + syslog(LOG_ERR, "Cannot set smbd/max_protocol below 3.0" + " while smbd/encrypt == required."); + rc = SMBD_SMF_INVALID_ARG; + } else { + rc = smb_smf_set_string_property(handle, cfg->sc_name, value); + } free(tmp); (void) smb_smf_end_transaction(handle); @@ -1118,43 +1166,27 @@ smb_config_getent(smb_cfg_id_t id) return (NULL); } - /* - * We store the max SMB protocol version in SMF as a string, - * (for convenience of svccfg etc) but the programmatic get/set - * interfaces use the numeric form. - * - * The numeric values are as defined in the [MS-SMB2] spec. - * except for how we represent "1" (for SMB1) which is an - * arbitrary value below SMB2_VERS_BASE. + * The service manifest has empty values by default for min_protocol and + * max_protocol. The expectation is that when those values are empty, we don't + * constrain the range of supported protocol versions (and allow use of the + * whole range that we implement). For that reason, this should usually be the + * highest protocol version we implement. */ -static struct str_val -smb_versions[] = { - { "3.0", SMB_VERS_3_0 }, - { "2.1", SMB_VERS_2_1 }, - { "2.002", SMB_VERS_2_002 }, - { "1", SMB_VERS_1 }, - { NULL, 0 } -}; - -/* - * This really should be the latest (SMB_VERS_3_0) - * but we're being cautious with SMB3 for a while. - */ -uint32_t max_protocol_default = SMB_VERS_2_1; +uint32_t max_protocol_default = SMB_VERS_3_0; uint32_t smb_config_get_max_protocol(void) { char str[SMB_VERSTR_LEN]; - int i, rc; + int rc; + uint32_t max; rc = smb_config_getstr(SMB_CI_MAX_PROTOCOL, str, sizeof (str)); if (rc == SMBD_SMF_OK) { - for (i = 0; smb_versions[i].str != NULL; i++) { - if (strcmp(str, smb_versions[i].str) == 0) - return (smb_versions[i].val); - } + max = smb_convert_version_str(str); + if (max != 0) + return (max); if (str[0] != '\0') { syslog(LOG_ERR, "smbd/max_protocol value invalid"); } @@ -1166,12 +1198,8 @@ smb_config_get_max_protocol(void) int smb_config_check_protocol(char *value) { - int i; - - for (i = 0; smb_versions[i].str != NULL; i++) { - if (strcmp(value, smb_versions[i].str) == 0) - return (0); - } + if (smb_convert_version_str(value) != 0) + return (0); return (-1); } @@ -1279,3 +1307,21 @@ smb_config_upgrade(void) { upgrade_smb2_enable(); } + +smb_cfg_val_t +smb_config_get_require(smb_cfg_id_t id) +{ + int rc; + char str[sizeof ("required")]; + + rc = smb_config_getstr(id, str, sizeof (str)); + if (rc != SMBD_SMF_OK) + return (SMB_CONFIG_DISABLED); + + if (strncmp(str, "required", sizeof (str)) == 0) + return (SMB_CONFIG_REQUIRED); + if (strncmp(str, "enabled", sizeof (str)) == 0) + return (SMB_CONFIG_ENABLED); + + return (SMB_CONFIG_DISABLED); +} diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_info.c b/usr/src/lib/smbsrv/libsmb/common/smb_info.c index e3e2ab15d9..870a667444 100644 --- a/usr/src/lib/smbsrv/libsmb/common/smb_info.c +++ b/usr/src/lib/smbsrv/libsmb/common/smb_info.c @@ -20,7 +20,7 @@ */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2015 Nexenta Systems, Inc. All rights reserved. + * Copyright 2016 Nexenta Systems, Inc. All rights reserved. */ #include <sys/types.h> @@ -158,6 +158,7 @@ smb_load_kconfig(smb_kmod_cfg_t *kcfg) kcfg->skc_traverse_mounts = smb_config_getbool(SMB_CI_TRAVERSE_MOUNTS); kcfg->skc_max_protocol = smb_config_get_max_protocol(); kcfg->skc_secmode = smb_config_get_secmode(); + kcfg->skc_encrypt = smb_config_get_require(SMB_CI_ENCRYPT); (void) smb_getdomainname(kcfg->skc_nbdomain, sizeof (kcfg->skc_nbdomain)); diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_kmod.c b/usr/src/lib/smbsrv/libsmb/common/smb_kmod.c index 3fa1da2a9d..28638b538b 100644 --- a/usr/src/lib/smbsrv/libsmb/common/smb_kmod.c +++ b/usr/src/lib/smbsrv/libsmb/common/smb_kmod.c @@ -20,7 +20,7 @@ */ /* * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2015 Nexenta Systems, Inc. All rights reserved. + * Copyright 2016 Nexenta Systems, Inc. All rights reserved. * Copyright 2017 Joyent, Inc. */ @@ -94,6 +94,7 @@ smb_kmod_setcfg(smb_kmod_cfg_t *cfg) ioc.version = cfg->skc_version; ioc.initial_credits = cfg->skc_initial_credits; ioc.maximum_credits = cfg->skc_maximum_credits; + ioc.encrypt = cfg->skc_encrypt; (void) memcpy(ioc.machine_uuid, cfg->skc_machine_uuid, sizeof (uuid_t)); (void) memcpy(ioc.negtok, cfg->skc_negtok, sizeof (ioc.negtok)); diff --git a/usr/src/man/man1m/sharemgr.1m b/usr/src/man/man1m/sharemgr.1m index 54cfc69a88..e7e86f4961 100644 --- a/usr/src/man/man1m/sharemgr.1m +++ b/usr/src/man/man1m/sharemgr.1m @@ -1,5 +1,6 @@ '\" te .\" Copyright (c) 2008, Sun Microsystems, Inc. All Rights Reserved +.\" Copyright 2016 Nexenta Systems, Inc. All rights reserved. .\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. .\" See the License for the specific language governing permissions and limitations under the License. When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with .\" the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner] @@ -1068,6 +1069,33 @@ The general properties supported for SMB are: .sp .ne 2 .na +\fB\fBencrypt=\fR\fIstring\fR\fR +.ad +.sp .6 +.RS 4n +Controls SMB3 per-share encryption. This is similar to the global smbd/encrypt +option. For requests on a particular share, the server's behavior is controlled +by the stricter of this option and smbd/encrypt. +.sp +When set to \fBdisabled\fR, the server will not ask clients to encrypt requests. +When set to \fBenabled\fR, the server will ask clients to encrypt requests, +but will not require that they do so. Any message than can be encrypted +will be encrypted. +When set to \fBrequired\fR, the server will deny access to or disconnect +any client that does not support encryption or fails to encrypt requests +that they should. +.sp +In other words, the \fBenabled\fR behavior is that any message that CAN +be encrypted SHOULD be encrypted, while the \fBrequired\fR behavior is that any +message that CAN be encrypted MUST be encrypted. +.sp +This property is not defined by default. +.sp +.RE + +.sp +.ne 2 +.na \fB\fBro=\fIaccess-list\fR\fR\fR .ad .sp .6 diff --git a/usr/src/man/man4/smb.4 b/usr/src/man/man4/smb.4 index 5fbc3fca3c..d22d6f969c 100644 --- a/usr/src/man/man4/smb.4 +++ b/usr/src/man/man4/smb.4 @@ -1,10 +1,22 @@ '\" te .\" Copyright (c) 2009, Sun Microsystems, Inc. All Rights Reserved. -.\" Copyright 2011, Nexenta Systems, Inc. All Rights Reserved. -.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. -.\" See the License for the specific language governing permissions and limitations under the License. When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the -.\" fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner] -.TH SMB 4 "Sep 25, 2009" +.\" Copyright 2016, Nexenta Systems, Inc. All Rights Reserved. +.\" The contents of this file are subject to the terms of the +.\" Common Development and Distribution License (the "License"). +.\" You may not use this file except in compliance with the License. +.\" +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +.\" or http://www.opensolaris.org/os/licensing. +.\" See the License for the specific language governing permissions +.\" and limitations under the License. +.\" +.\" When distributing Covered Code, include this CDDL HEADER in each +.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE. +.\" If applicable, add the following below this CDDL HEADER, with the +.\" fields enclosed by brackets "[]" replaced with your own identifying +.\" information: Portions Copyright [yyyy] [name of copyright owner] +.\" +.TH SMB 4 "Apr 23, 2015" .SH NAME smb \- configuration properties for Solaris CIFS server .SH DESCRIPTION @@ -100,7 +112,31 @@ value is \fBfalse\fR. .sp .ne 2 .na -\fB\fBipv6_enabled\fR\fR +\fB\fBencrypt\fR\fR +.ad +.sp .6 +.RS 4n +Controls SMB3 Encryption. For requests on a particular share, the server's +behavior is controlled by the stricter of this option and the per-share +"encrypt" option. +.sp +When set to \fBdisabled\fR, the server will not ask clients to encrypt requests. +When set to \fBenabled\fR, the server will ask clients to encrypt requests, +but will not require that they do so. Any message that can be encrypted +will be encrypted. +When set to \fBrequired\fR, the server will deny access to or disconnect +any client that does not support encryption or fails to encrypt requests +that they should. +.sp +In other words, the \fBenabled\fR behavior is that any message that CAN +be encrypted SHOULD be encrypted, while the \fBrequired\fR behavior is that any +message that CAN be encrypted MUST be encrypted. +.RE + +.sp +.ne 2 +.na +\fB\fBipv6_enable\fR\fR .ad .sp .6 .RS 4n diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files index 5c69fd02d1..96798ba288 100644 --- a/usr/src/uts/common/Makefile.files +++ b/usr/src/uts/common/Makefile.files @@ -1131,6 +1131,7 @@ NFSSRV_OBJS += nfs_server.o nfs_srv.o nfs3_srv.o \ nfs4_deleg_ops.o nfs4_srv_readdir.o nfs4_dispatch.o SMBSRV_SHARED_OBJS += \ + smb_cfg_util.o \ smb_door_legacy.o \ smb_inet.o \ smb_match.o \ @@ -1259,7 +1260,10 @@ SMBSRV_OBJS += $(SMBSRV_SHARED_OBJS) \ smb2_signing.o \ smb2_tree_connect.o \ smb2_tree_disconn.o \ - smb2_write.o + smb2_write.o \ + \ + smb3_encrypt.o \ + smb3_encrypt_kcf.o PCFS_OBJS += pc_alloc.o pc_dir.o pc_node.o pc_subr.o \ pc_vfsops.o pc_vnops.o diff --git a/usr/src/uts/common/fs/smbsrv/smb2_dispatch.c b/usr/src/uts/common/fs/smbsrv/smb2_dispatch.c index 7c0fcea968..b592dc4c5f 100644 --- a/usr/src/uts/common/fs/smbsrv/smb2_dispatch.c +++ b/usr/src/uts/common/fs/smbsrv/smb2_dispatch.c @@ -10,7 +10,7 @@ */ /* - * Copyright 2016 Nexenta Systems, Inc. All rights reserved. + * Copyright 2017 Nexenta Systems, Inc. All rights reserved. */ @@ -23,6 +23,7 @@ smb_sdrc_t smb2_invalid_cmd(smb_request_t *); static void smb2_tq_work(void *); static void smb2sr_run_postwork(smb_request_t *); +static int smb3_decrypt_msg(smb_request_t *); static const smb_disp_entry_t smb2_disp_table[SMB2__NCMDS] = { @@ -132,6 +133,18 @@ smb2sr_newrq(smb_request_t *sr) if (smb_mbc_peek(mbc, 0, "l", &magic) != 0) goto drop; + /* 0xFD S M B */ + if (magic == SMB3_ENCRYPTED_MAGIC) { + if (smb3_decrypt_msg(sr) != 0) + goto drop; + /* + * Should now be looking at an un-encrypted + * SMB2 message header. + */ + if (smb_mbc_peek(mbc, 0, "l", &magic) != 0) + goto drop; + } + if (magic != SMB2_PROTOCOL_MAGIC) goto drop; @@ -243,6 +256,39 @@ smb2_tq_work(void *arg) smb_srqueue_runq_exit(srq); } +static int +smb3_decrypt_msg(smb_request_t *sr) +{ + int save_offset; + + if (sr->session->dialect < SMB_VERS_3_0) { + cmn_err(CE_WARN, "encrypted message in SMB 2.x"); + return (-1); + } + + sr->encrypted = B_TRUE; + save_offset = sr->command.chain_offset; + if (smb3_decode_tform_header(sr) != 0) { + cmn_err(CE_WARN, "bad transform header"); + return (-1); + } + sr->command.chain_offset = save_offset; + + sr->tform_ssn = smb_session_lookup_ssnid(sr->session, + sr->smb3_tform_ssnid); + if (sr->tform_ssn == NULL) { + cmn_err(CE_WARN, "transform header: session not found"); + return (-1); + } + + if (smb3_decrypt_sr(sr) != 0) { + cmn_err(CE_WARN, "smb3 decryption failed"); + return (-1); + } + + return (0); +} + /* * SMB2 credits determine how many simultaneous commands the * client may issue, and bounds the range of message IDs those @@ -610,6 +656,24 @@ cmd_start: * [MS-SMB2] 3.3.5.2 Verifying the Session */ ASSERT(sr->uid_user == NULL); + /* + * [MS-SMB2] 3.3.5.2.7 Handling Compounded Requests + * + * If this is an encrypted compound request, + * ensure that the ssnid in the request + * is the same as the tform ssnid if this + * message is not related. + * + * The reasons this is done seem to apply equally + * to uncompounded requests, so we apply it to all. + */ + + if (sr->encrypted && + sr->smb2_ssnid != sr->smb3_tform_ssnid) { + disconnect = B_TRUE; + goto cleanup; /* just do this for now */ + } + sr->uid_user = smb_session_lookup_ssnid(session, sr->smb2_ssnid); if (sr->uid_user == NULL) { @@ -617,9 +681,45 @@ cmd_start: NT_STATUS_USER_SESSION_DELETED); goto cmd_done; } + + /* + * [MS-SMB2] 3.3.5.2.9 Verifying the Session + * + * If we're talking 3.x, + * RejectUnencryptedAccess is TRUE, + * Session.EncryptData is TRUE, + * and the message wasn't encrypted, + * return ACCESS_DENIED. + * + * Note that Session.EncryptData can only be TRUE when + * we're talking 3.x. + */ + + if (sr->uid_user->u_encrypt == + SMB_CONFIG_REQUIRED && + !sr->encrypted) { + smb2sr_put_error(sr, + NT_STATUS_ACCESS_DENIED); + goto cmd_done; + } + sr->user_cr = smb_user_getcred(sr->uid_user); } ASSERT(sr->uid_user != NULL); + + /* + * Encrypt if: + * - The cmd is not SESSION_SETUP or NEGOTIATE; AND + * - Session.EncryptData is TRUE + * + * Those commands suppress UID, so they can't be the cmd here. + */ + if (sr->uid_user->u_encrypt != SMB_CONFIG_DISABLED && + sr->tform_ssn == NULL) { + smb_user_hold_internal(sr->uid_user); + sr->tform_ssn = sr->uid_user; + sr->smb3_tform_ssnid = sr->smb2_ssnid; + } } if ((sdd->sdt_flags & SDDF_SUPPRESS_TID) == 0) { @@ -650,8 +750,49 @@ cmd_start: NT_STATUS_NETWORK_NAME_DELETED); goto cmd_done; } + + /* + * [MS-SMB2] 3.3.5.2.11 Verifying the Tree Connect + * + * If we support 3.x, RejectUnencryptedAccess is TRUE, + * if Tcon.EncryptData is TRUE or + * global EncryptData is TRUE and + * the message wasn't encrypted, or + * if Tcon.EncryptData is TRUE or + * global EncryptData is TRUE or + * the request was encrypted and + * the connection doesn't support encryption, + * return ACCESS_DENIED. + * + * If RejectUnencryptedAccess is TRUE, we force + * max_protocol to at least 3.0. Additionally, + * if the tree requires encryption, we don't care + * what we support, we still enforce encryption. + */ + if (sr->tid_tree->t_encrypt == SMB_CONFIG_REQUIRED && + (!sr->encrypted || + (session->srv_cap & SMB2_CAP_ENCRYPTION) == 0)) { + smb2sr_put_error(sr, + NT_STATUS_ACCESS_DENIED); + goto cmd_done; + } } ASSERT(sr->tid_tree != NULL); + + /* + * Encrypt if: + * - The cmd is not TREE_CONNECT; AND + * - Tree.EncryptData is TRUE + * + * TREE_CONNECT suppresses TID, so that can't be the cmd here. + * NOTE: assumes we can't have a tree without a user + */ + if (sr->tid_tree->t_encrypt != SMB_CONFIG_DISABLED && + sr->tform_ssn == NULL) { + smb_user_hold_internal(sr->uid_user); + sr->tform_ssn = sr->uid_user; + sr->smb3_tform_ssnid = sr->smb2_ssnid; + } } /* @@ -673,9 +814,14 @@ cmd_start: * The SDDF_SUPPRESS_UID dispatch is set for requests that * don't need a UID (user). These also don't require a * signature check here. + * + * [MS-SMB2] 3.3.5.2.4 Verifying the Signature + * + * If the packet was successfully decrypted, the message + * signature has already been verified, so we can skip this. */ if ((sdd->sdt_flags & SDDF_SUPPRESS_UID) == 0 && - sr->uid_user != NULL && + !sr->encrypted && sr->uid_user != NULL && (sr->uid_user->u_sign_flags & SMB_SIGNING_CHECK) != 0) { /* * This request type should be signed, and @@ -822,7 +968,9 @@ cmd_done: */ (void) smb2_encode_header(sr, B_TRUE); - if (sr->smb2_hdr_flags & SMB2_FLAGS_SIGNED) + /* Don't sign if we're going to encrypt */ + if (sr->tform_ssn == NULL && + (sr->smb2_hdr_flags & SMB2_FLAGS_SIGNED) != 0) smb2_sign_reply(sr); /* @@ -1141,6 +1289,64 @@ cleanup: } int +smb3_decode_tform_header(smb_request_t *sr) +{ + uint16_t flags; + int rc; + uint32_t protocolid; + + rc = smb_mbc_decodef( + &sr->command, "l16c16cl..wq", + &protocolid, /* l */ + sr->smb2_sig, /* 16c */ + sr->nonce, /* 16c */ + &sr->msgsize, /* l */ + /* reserved .. */ + &flags, /* w */ + &sr->smb3_tform_ssnid); /* q */ + if (rc) + return (rc); + + ASSERT3U(protocolid, ==, SMB3_ENCRYPTED_MAGIC); + + if (flags != 1) { +#ifdef DEBUG + cmn_err(CE_NOTE, "flags field not 1: %x", flags); +#endif + return (-1); + } + + /* + * MsgSize is the amount of data the client tell us to decrypt. + * Make sure this value is not too big and not too small. + */ + if (sr->msgsize < SMB2_HDR_SIZE || + sr->msgsize > sr->session->cmd_max_bytes || + sr->msgsize > sr->command.max_bytes - SMB3_TFORM_HDR_SIZE) + return (-1); + + return (rc); +} + +int +smb3_encode_tform_header(smb_request_t *sr, struct mbuf_chain *mbc) +{ + int rc; + + /* Signature and Nonce are added in smb3_encrypt_sr */ + rc = smb_mbc_encodef( + mbc, "l32.lwwq", + SMB3_ENCRYPTED_MAGIC, /* l */ + /* signature(16), nonce(16) 32. */ + sr->msgsize, /* l */ + 0, /* reserved w */ + 1, /* flags w */ + sr->smb3_tform_ssnid); /* q */ + + return (rc); +} + +int smb2_decode_header(smb_request_t *sr) { uint32_t pid, tid; @@ -1232,9 +1438,62 @@ smb2_encode_header(smb_request_t *sr, boolean_t overwrite) void smb2_send_reply(smb_request_t *sr) { + struct mbuf_chain enc_reply; + smb_session_t *session = sr->session; + void *tmpbuf; + size_t buflen; + struct mbuf_chain tmp; + + /* + * [MS-SMB2] 3.3.4.1.4 Encrypting the Message + * + * When the connection supports encryption and the dialect + * is 3.x, encrypt if: + * - The request was encrypted OR + * - The cmd is not SESSION_SETUP or NEGOTIATE AND + * -- Session.EncryptData is TRUE OR + * -- The cmd is not TREE_CONNECT AND + * --- Tree.EncryptData is TRUE + * + * This boils down to sr->tform_ssn != NULL, and the rest + * is enforced when tform_ssn is set. + */ + + if ((session->capabilities & SMB2_CAP_ENCRYPTION) == 0 || + sr->tform_ssn == NULL) { + if (smb_session_send(sr->session, 0, &sr->reply) == 0) + sr->reply.chain = 0; + return; + } + + sr->msgsize = sr->reply.chain_offset; + (void) MBC_SHADOW_CHAIN(&tmp, &sr->reply, + 0, sr->msgsize); + + buflen = SMB3_TFORM_HDR_SIZE + sr->msgsize; + + /* taken from smb_request_init_command_mbuf */ + tmpbuf = kmem_alloc(buflen, KM_SLEEP); + MBC_ATTACH_BUF(&enc_reply, tmpbuf, buflen); + enc_reply.flags = 0; + enc_reply.shadow_of = NULL; + + if (smb3_encode_tform_header(sr, &enc_reply) != 0) { + cmn_err(CE_WARN, "couldn't encode transform header"); + goto errout; + } + if (smb3_encrypt_sr(sr, &tmp, &enc_reply) != 0) { + cmn_err(CE_WARN, "smb3 encryption failed"); + goto errout; + } + + if (smb_session_send(sr->session, 0, &enc_reply) == 0) + enc_reply.chain = 0; + return; - if (smb_session_send(sr->session, 0, &sr->reply) == 0) - sr->reply.chain = 0; +errout: + kmem_free(tmpbuf, buflen); + smb_session_disconnect(sr->session); } /* diff --git a/usr/src/uts/common/fs/smbsrv/smb2_negotiate.c b/usr/src/uts/common/fs/smbsrv/smb2_negotiate.c index 4b3d30c066..d31abaa3e8 100644 --- a/usr/src/uts/common/fs/smbsrv/smb2_negotiate.c +++ b/usr/src/uts/common/fs/smbsrv/smb2_negotiate.c @@ -25,7 +25,8 @@ static int smb2_negotiate_common(smb_request_t *, uint16_t); uint32_t smb2srv_capabilities = SMB2_CAP_DFS | SMB2_CAP_LEASING | - SMB2_CAP_LARGE_MTU; + SMB2_CAP_LARGE_MTU | + SMB2_CAP_ENCRYPTION; /* * These are not intended as customer tunables, but dev. & test folks @@ -105,7 +106,6 @@ smb1_negotiate_smb2(smb_request_t *sr) smb_session_t *s = sr->session; smb_arg_negotiate_t *negprot = sr->sr_negprot; uint16_t smb2_version; - uint16_t secmode2; int rc; /* @@ -124,33 +124,31 @@ smb1_negotiate_smb2(smb_request_t *sr) s->s_state = SMB_SESSION_STATE_NEGOTIATED; /* Allow normal SMB2 requests now. */ s->newrq_func = smb2sr_newrq; - - /* - * Translate SMB1 sec. mode to SMB2. - */ - secmode2 = 0; - if (s->secmode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) - secmode2 |= SMB2_NEGOTIATE_SIGNING_ENABLED; - if (s->secmode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED) - secmode2 |= SMB2_NEGOTIATE_SIGNING_REQUIRED; - s->secmode = secmode2; break; case DIALECT_SMB2XXX: /* SMB 2.??? (wildcard vers) */ /* * Expecting an SMB2 negotiate next, so keep the - * initial s->newrq_func. Note that secmode is - * fiction good enough to pass the signing check - * in smb2_negotiate_common(). We'll check the - * real secmode when the 2nd negotiate comes. + * initial s->newrq_func. */ smb2_version = 0x2FF; - s->secmode = SMB2_NEGOTIATE_SIGNING_ENABLED; break; default: return (SDRC_DROP_VC); } /* + * Clients that negotiate SMB2 from SMB1 have not yet had the + * opportunity to provide us with a secmode. However, any + * client that negotiates SMB2 should support signing, so + * this should be fiction good enough to pass the signing + * check in smb2_negotiate_common(). Even if the client + * doesn't support signing and we require it, we'll fail them + * later when they fail to sign the packet. For 2.???, + * we'll check the real secmode when the 2nd negotiate comes. + */ + s->cli_secmode = SMB2_NEGOTIATE_SIGNING_ENABLED; + + /* * We did not decode an SMB2 header, so make sure * the SMB2 header fields are initialized. * (Most are zero from smb_request_alloc.) @@ -172,6 +170,21 @@ smb1_negotiate_smb2(smb_request_t *sr) return (SDRC_NO_REPLY); } +static uint16_t +smb2_find_best_dialect(smb_session_t *s, uint16_t cl_versions[], + uint16_t version_cnt) +{ + uint16_t best_version = 0; + int i; + + for (i = 0; i < version_cnt; i++) + if (smb2_supported_version(s, cl_versions[i]) && + best_version < cl_versions[i]) + best_version = cl_versions[i]; + + return (best_version); +} + /* * SMB2 Negotiate gets special handling. This is called directly by * the reader thread (see smbsr_newrq_initial) with what _should_ be @@ -193,7 +206,7 @@ int smb2_newrq_negotiate(smb_request_t *sr) { smb_session_t *s = sr->session; - int i, rc; + int rc; uint16_t struct_size; uint16_t best_version; uint16_t version_cnt; @@ -212,13 +225,13 @@ smb2_newrq_negotiate(smb_request_t *sr) * Decode SMB2 Negotiate (fixed-size part) */ rc = smb_mbc_decodef( - &sr->command, "www..l16.8.", + &sr->command, "www..l16c8.", &struct_size, /* w */ &version_cnt, /* w */ - &s->secmode, /* w */ + &s->cli_secmode, /* w */ /* reserved (..) */ - &s->capabilities); /* l */ - /* clnt_uuid 16. */ + &s->capabilities, /* l */ + s->clnt_uuid); /* 16c */ /* start_time 8. */ if (rc != 0) return (rc); @@ -240,11 +253,7 @@ smb2_newrq_negotiate(smb_request_t *sr) * supports, which we have decoded into cl_versions[]. * We walk the array and pick the highest supported. */ - best_version = 0; - for (i = 0; i < version_cnt; i++) - if (smb2_supported_version(s, cl_versions[i]) && - best_version < cl_versions[i]) - best_version = cl_versions[i]; + best_version = smb2_find_best_dialect(s, cl_versions, version_cnt); if (best_version == 0) return (SDRC_DROP_VC); s->dialect = best_version; @@ -285,19 +294,16 @@ smb2_negotiate_common(smb_request_t *sr, uint16_t version) /* * Negotiation itself. First the Security Mode. - * The caller stashed the client's secmode in s->secmode, - * which we validate, and then replace with the server's - * secmode, which is all we care about after this. */ secmode = SMB2_NEGOTIATE_SIGNING_ENABLED; if (sr->sr_cfg->skc_signing_required) { secmode |= SMB2_NEGOTIATE_SIGNING_REQUIRED; /* Make sure client at least enables signing. */ - if ((s->secmode & secmode) == 0) { + if ((s->cli_secmode & secmode) == 0) { sr->smb2_status = NT_STATUS_INVALID_PARAMETER; } } - s->secmode = secmode; + s->srv_secmode = secmode; s->cmd_max_bytes = smb2_tcp_bufsize; s->reply_max_bytes = smb2_tcp_bufsize; @@ -335,6 +341,20 @@ smb2_negotiate_common(smb_request_t *sr, uint16_t version) smb2_sign_init_mech(s); /* + * [MS-SMB2] 3.3.5.4 Receiving an SMB2 NEGOTIATE Request + * + * Only set CAP_ENCRYPTION if this is 3.0 or 3.0.2 and + * the client has it set. + */ + + if (s->dialect < SMB_VERS_3_0 || + !SMB3_CLIENT_ENCRYPTS(sr) || + smb3_encrypt_init_mech(s) != 0) + s->srv_cap = smb2srv_capabilities & ~SMB2_CAP_ENCRYPTION; + else + s->srv_cap = smb2srv_capabilities; + + /* * See notes above smb2_max_rwsize, smb2_old_rwsize */ if (s->capabilities & SMB2_CAP_LARGE_MTU) @@ -346,12 +366,12 @@ smb2_negotiate_common(smb_request_t *sr, uint16_t version) &sr->reply, "wwww#cllllTTwwl#c", 65, /* StructSize */ /* w */ - s->secmode, /* w */ + s->srv_secmode, /* w */ version, /* w */ 0, /* reserved */ /* w */ UUID_LEN, /* # */ &s->s_cfg.skc_machine_uuid, /* c */ - smb2srv_capabilities, /* l */ + s->srv_cap, /* l */ smb2_max_trans, /* l */ max_rwsize, /* l */ max_rwsize, /* l */ @@ -408,15 +428,50 @@ smb2_fsctl_vneginfo(smb_request_t *sr, smb_fsctl_t *fsctl) * If we don't the client closes the connection. */ + /* dialects[8] taken from cl_versions[8] in smb2_newrq_negotiate */ + uint32_t capabilities; + uint16_t secmode, num_dialects, dialects[8]; + uint8_t clnt_guid[16]; + + if (fsctl->InputCount < 24) + goto drop; + + (void) smb_mbc_decodef(fsctl->in_mbc, "l16cww", + &capabilities, /* l */ + &clnt_guid, /* 16c */ + &secmode, /* w */ + &num_dialects); /* w */ + + if (num_dialects == 0 || num_dialects > 8) + goto drop; + if (secmode != s->cli_secmode) + goto drop; + if (capabilities != s->capabilities) + goto drop; + if (memcmp(clnt_guid, s->clnt_uuid, sizeof (clnt_guid)) != 0) + goto drop; + + if (fsctl->InputCount < (24 + num_dialects * sizeof (*dialects))) + goto drop; + + rc = smb_mbc_decodef(fsctl->in_mbc, "#w", num_dialects, dialects); + if (rc != 0) + goto drop; + + if (smb2_find_best_dialect(s, dialects, num_dialects) != s->dialect) + goto drop; + rc = smb_mbc_encodef( fsctl->out_mbc, "l#cww", - smb2srv_capabilities, /* l */ + s->srv_cap, /* l */ UUID_LEN, /* # */ &s->s_cfg.skc_machine_uuid, /* c */ - s->secmode, /* w */ + s->srv_secmode, /* w */ s->dialect); /* w */ - if (rc) - return (NT_STATUS_INTERNAL_ERROR); + if (rc == 0) + return (rc); - return (0); +drop: + smb_session_disconnect(s); + return (NT_STATUS_ACCESS_DENIED); } diff --git a/usr/src/uts/common/fs/smbsrv/smb2_session_setup.c b/usr/src/uts/common/fs/smbsrv/smb2_session_setup.c index 4de814f378..0a258f1bf4 100644 --- a/usr/src/uts/common/fs/smbsrv/smb2_session_setup.c +++ b/usr/src/uts/common/fs/smbsrv/smb2_session_setup.c @@ -60,19 +60,6 @@ smb2_session_setup(smb_request_t *sr) return (SDRC_ERROR); /* - * SMB3 multi-channel features are not supported. - * Once they are, this will check the dialect and - * whether multi-channel was negotiated, i.e. - * if (sr->session->dialect < SMB_VERS_3_0 || - * s->IsMultiChannelCapable == False) - * return (error...) - */ - if (Flags & SMB2_SESSION_FLAG_BINDING) { - status = NT_STATUS_REQUEST_NOT_ACCEPTED; - goto errout; - } - - /* * We're normally positioned at the security buffer now, * but there could be some padding before it. */ @@ -100,6 +87,37 @@ smb2_session_setup(smb_request_t *sr) DTRACE_SMB2_START(op__SessionSetup, smb_request_t *, sr); /* + * [MS-SMB2] 3.3.5.5 Receiving an SMB2 SESSION_SETUP Request + * + * If we support 3.x, RejectUnencryptedAccess is TRUE, + * global EncryptData is TRUE, but we're not talking + * 3.x or the client doesn't support encryption, + * return ACCESS_DENIED. + * + * If RejectUnencryptedAccess is TRUE, we force max_protocol + * to at least 3.0. + */ + if (sr->sr_server->sv_cfg.skc_encrypt == SMB_CONFIG_REQUIRED && + (sr->session->dialect < SMB_VERS_3_0 || + !SMB3_CLIENT_ENCRYPTS(sr))) { + status = NT_STATUS_ACCESS_DENIED; + goto errout; + } + + /* + * SMB3 multi-channel features are not supported. + * Once they are, this will check the dialect and + * whether multi-channel was negotiated, i.e. + * if (sr->session->dialect < SMB_VERS_3_0 || + * s->IsMultiChannelCapable == False) + * return (error...) + */ + if (Flags & SMB2_SESSION_FLAG_BINDING) { + status = NT_STATUS_REQUEST_NOT_ACCEPTED; + goto errout; + } + + /* * The real auth. work happens in here. */ status = smb_authenticate_ext(sr); @@ -111,10 +129,12 @@ smb2_session_setup(smb_request_t *sr) switch (status) { case NT_STATUS_SUCCESS: /* Authenticated */ - if (sr->uid_user->u_flags & SMB_USER_FLAG_GUEST) + if ((sr->uid_user->u_flags & SMB_USER_FLAG_GUEST) != 0) SessionFlags |= SMB2_SESSION_FLAG_IS_GUEST; - if (sr->uid_user->u_flags & SMB_USER_FLAG_ANON) + if ((sr->uid_user->u_flags & SMB_USER_FLAG_ANON) != 0) SessionFlags |= SMB2_SESSION_FLAG_IS_NULL; + if (sr->uid_user->u_encrypt != SMB_CONFIG_DISABLED) + SessionFlags |= SMB2_SESSION_FLAG_ENCRYPT_DATA; smb2_ss_adjust_credits(sr); /* diff --git a/usr/src/uts/common/fs/smbsrv/smb2_signing.c b/usr/src/uts/common/fs/smbsrv/smb2_signing.c index ed19e6950e..704dfc652a 100644 --- a/usr/src/uts/common/fs/smbsrv/smb2_signing.c +++ b/usr/src/uts/common/fs/smbsrv/smb2_signing.c @@ -20,7 +20,7 @@ */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2017 Nexenta Systems, Inc. All rights reserved. + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. */ /* * These routines provide the SMB MAC signing for the SMB2 server. @@ -39,8 +39,8 @@ */ #include <sys/uio.h> -#include <smbsrv/smb_kproto.h> -#include <smbsrv/smb_signing.h> +#include <smbsrv/smb2_kproto.h> +#include <smbsrv/smb_kcrypt.h> #include <sys/isa_defs.h> #include <sys/byteorder.h> #include <sys/cmn_err.h> @@ -49,7 +49,7 @@ #define SMB2_SIG_SIZE 16 typedef struct mac_ops { - int (*mac_init)(smb_sign_ctx_t *, smb_sign_mech_t *, + int (*mac_init)(smb_sign_ctx_t *, smb_crypto_mech_t *, uint8_t *, size_t); int (*mac_update)(smb_sign_ctx_t, uint8_t *, size_t); int (*mac_final)(smb_sign_ctx_t, uint8_t *); @@ -58,8 +58,6 @@ typedef struct mac_ops { static int smb2_sign_calc_common(smb_request_t *, struct mbuf_chain *, uint8_t *, mac_ops_t *); -static int smb3_do_kdf(void *, void *, size_t, uint8_t *, uint32_t); - /* * SMB2 wrapper functions */ @@ -89,7 +87,7 @@ smb2_sign_calc(smb_request_t *sr, static void smb2_sign_fini(smb_session_t *s) { - smb_sign_mech_t *mech; + smb_crypto_mech_t *mech; if ((mech = s->sign_mech) != NULL) { kmem_free(mech, sizeof (*mech)); @@ -133,8 +131,8 @@ static uint8_t sign_kdf_input[29] = { void smb2_sign_init_mech(smb_session_t *s) { - smb_sign_mech_t *mech; - int (*get_mech)(smb_sign_mech_t *); + smb_crypto_mech_t *mech; + int (*get_mech)(smb_crypto_mech_t *); int (*sign_calc)(smb_request_t *, struct mbuf_chain *, uint8_t *); int rc; @@ -209,15 +207,16 @@ smb2_sign_begin(smb_request_t *sr, smb_token_t *token) * of the session key (truncated or padded with zeros). * [MS-SMB2] 3.2.5.3.1 */ - sign_key->len = SMB2_SIG_SIZE; + sign_key->len = SMB2_KEYLEN; bcopy(token->tkn_ssnkey.val, sign_key->key, MIN(token->tkn_ssnkey.len, sign_key->len)); } mutex_enter(&u->u_mutex); - if (s->secmode & SMB2_NEGOTIATE_SIGNING_ENABLED) + if ((s->srv_secmode & SMB2_NEGOTIATE_SIGNING_ENABLED) != 0) u->u_sign_flags |= SMB_SIGNING_ENABLED; - if (s->secmode & SMB2_NEGOTIATE_SIGNING_REQUIRED) + if ((s->srv_secmode & SMB2_NEGOTIATE_SIGNING_REQUIRED) != 0 || + (s->cli_secmode & SMB2_NEGOTIATE_SIGNING_REQUIRED) != 0) u->u_sign_flags |= SMB_SIGNING_ENABLED | SMB_SIGNING_CHECK; mutex_exit(&u->u_mutex); @@ -453,13 +452,22 @@ smb2_sign_reply(smb_request_t *sr) * - Session.SessionKey as K1 * - label = SMB2APP (size 8) * - context = SmbRpc (size 7) + * Session.EncryptionKey for encrypting server messages + * - Session.SessionKey as K1 + * - label = "SMB2AESCCM" (size 11) + * - context = "ServerOut" (size 10) + * Session.DecryptionKey for decrypting client requests + * - Session.SessionKey as K1 + * - label = "SMB2AESCCM" (size 11) + * - context = "ServerIn " (size 10) (Note the space) */ -static int + +int smb3_do_kdf(void *outbuf, void *input, size_t input_len, uint8_t *key, uint32_t key_len) { uint8_t digest32[SHA256_DIGEST_LENGTH]; - smb_sign_mech_t mech; + smb_crypto_mech_t mech; smb_sign_ctx_t hctx = 0; int rc; diff --git a/usr/src/uts/common/fs/smbsrv/smb2_tree_connect.c b/usr/src/uts/common/fs/smbsrv/smb2_tree_connect.c index 90a2c21466..e11a8855f7 100644 --- a/usr/src/uts/common/fs/smbsrv/smb2_tree_connect.c +++ b/usr/src/uts/common/fs/smbsrv/smb2_tree_connect.c @@ -68,6 +68,16 @@ smb2_tree_connect(smb_request_t *sr) DTRACE_SMB2_START(op__TreeConnect, smb_request_t *, sr); + /* + * [MS-SMB2] 3.3.5.7 Receiving an SMB2 TREE_CONNECT Request + * + * If RejectUnencryptedAccess is TRUE, + * global EncryptData or Share.EncryptData is TRUE, + * we support 3.x, and srv_cap doesn't indicate encryption support, + * return ACCESS_DENIED. + * + * This also applies to SMB1, so do it in smb_tree_connect_core. + */ status = smb_tree_connect(sr); sr->smb2_status = status; @@ -98,7 +108,11 @@ smb2_tree_connect(smb_request_t *sr) /* * XXX These need work.. */ - ShareFlags = 0; + if (tree->t_encrypt != SMB_CONFIG_DISABLED) + ShareFlags = SMB2_SHAREFLAG_ENCRYPT_DATA; + else + ShareFlags = 0; + Capabilities = 0; /* diff --git a/usr/src/uts/common/fs/smbsrv/smb3_encrypt.c b/usr/src/uts/common/fs/smbsrv/smb3_encrypt.c new file mode 100644 index 0000000000..fdbd49ef74 --- /dev/null +++ b/usr/src/uts/common/fs/smbsrv/smb3_encrypt.c @@ -0,0 +1,397 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2017 Nexenta Systems, Inc. All rights reserved. + */ + +/* + * Routines for smb3 encryption. + */ + +#include <smbsrv/smb2_kproto.h> +#include <smbsrv/smb_kcrypt.h> +#include <sys/random.h> +#include <sys/cmn_err.h> + +#define SMB3_NONCE_OFFS 20 +#define SMB3_SIG_OFFS 4 +#define SMB3_NONCE_SIZE 11 /* 12 for gcm later */ + +/* + * Inputs to KDF for EncryptionKey and DecryptionKey. + * See comment for smb3_do_kdf for content. + */ +static uint8_t encrypt_kdf_input[30] = { + 0, 0, 0, 1, 'S', 'M', 'B', '2', + 'A', 'E', 'S', 'C', 'C', 'M', 0, 0, + 'S', 'e', 'r', 'v', 'e', 'r', 'O', + 'u', 't', 0, 0, 0, 0, 0x80 }; + +static uint8_t decrypt_kdf_input[30] = { + 0, 0, 0, 1, 'S', 'M', 'B', '2', + 'A', 'E', 'S', 'C', 'C', 'M', 0, 0, + 'S', 'e', 'r', 'v', 'e', 'r', 'I', + 'n', ' ', 0, 0, 0, 0, 0x80 }; + +/* + * Arbitrary value used to prevent nonce reuse via overflow. Currently + * 2^64 - 2^32 - 1. Assumes we can't have (or are unlikely to have) + * 2^32 concurrent messages when we hit this number. + */ +static uint64_t smb3_max_nonce = 0xffffffff00000000ULL; + +/* + * Nonce generation based on draft-mcgrew-iv-gen-01 + * "Generation of Deterministic Initialization Vectors (IVs) and Nonces" + * + * Generate an 8-byte random salt and a 3-byte random 'fixed' value. + * then, nonce = (++counter ^ salt) || fixed + * + * This protects against nonce-reuse (8-byte counter), as well as known + * attacks on reusing nonces with different keys + */ + +void +smb3_encrypt_init_nonce(smb_user_t *user) +{ + user->u_nonce_cnt = 0; + (void) random_get_pseudo_bytes(user->u_nonce_fixed, + sizeof (user->u_nonce_fixed)); + (void) random_get_pseudo_bytes((uint8_t *)&user->u_salt, + sizeof (user->u_salt)); +} + +int +smb3_encrypt_gen_nonce(smb_user_t *user, uint8_t *buf, size_t len) +{ + uint64_t cnt = atomic_inc_64_nv(&user->u_nonce_cnt); + + /* + * Nonces must be unique per-key for the life of the key. + * Bail before we roll over to avoid breaking the crypto. + */ + + if (cnt > smb3_max_nonce) + return (-1); + + cnt ^= user->u_salt; + bcopy((uint8_t *)&cnt, buf, sizeof (cnt)); + + ASSERT(len > sizeof (cnt)); + bcopy(user->u_nonce_fixed, buf + sizeof (cnt), len - sizeof (cnt)); + return (0); +} + +int +smb3_encrypt_init_mech(smb_session_t *s) +{ + smb_crypto_mech_t *mech; + int rc; + + if (s->enc_mech != NULL) + return (0); + + mech = kmem_zalloc(sizeof (*mech), KM_SLEEP); + rc = smb3_encrypt_getmech(mech); + if (rc != 0) { + kmem_free(mech, sizeof (*mech)); + return (rc); + } + s->enc_mech = mech; + + return (0); +} + +/* + * Initializes keys/state required for SMB3 Encryption. + * Note: If a failure occurs here, don't fail the request. + * Instead, return an error when we attempt to encrypt/decrypt. + */ +void +smb3_encrypt_begin(smb_request_t *sr, smb_token_t *token) +{ + smb_session_t *s = sr->session; + smb_user_t *u = sr->uid_user; + struct smb_key *enc_key = &u->u_enc_key; + struct smb_key *dec_key = &u->u_dec_key; + + /* + * In order to enforce encryption, all users need to + * have Session.EncryptData properly set, even anon/guest. + */ + u->u_encrypt = s->s_server->sv_cfg.skc_encrypt; + enc_key->len = 0; + dec_key->len = 0; + + /* + * If we don't have a session key, we'll fail later when a + * request that requires (en/de)cryption can't be (en/de)crypted. + * Also don't bother initializing if we don't have a mechanism. + */ + if (token->tkn_ssnkey.val == NULL || token->tkn_ssnkey.len == 0 || + s->enc_mech == NULL) + return; + + /* + * Compute and store the encryption keys, which live in + * the user structure. + */ + + /* + * For SMB3, the encrypt/decrypt keys are derived from + * the session key using KDF in counter mode. + */ + if (smb3_do_kdf(enc_key->key, encrypt_kdf_input, + sizeof (encrypt_kdf_input), token->tkn_ssnkey.val, + token->tkn_ssnkey.len) != 0) + return; + + if (smb3_do_kdf(dec_key->key, decrypt_kdf_input, + sizeof (decrypt_kdf_input), token->tkn_ssnkey.val, + token->tkn_ssnkey.len) != 0) + return; + + smb3_encrypt_init_nonce(u); + + enc_key->len = SMB3_KEYLEN; + dec_key->len = SMB3_KEYLEN; +} + +/* + * Decrypt the request in sr->command. + * This decrypts "in place", though due to CCM's design, + * it processes all input before doing any output. + */ +int +smb3_decrypt_sr(smb_request_t *sr) +{ + struct mbuf_chain *mbc = &sr->command; + smb_session_t *s = sr->session; + smb_user_t *u = sr->tform_ssn; + uint8_t tmp_hdr[SMB2_HDR_SIZE]; + smb3_enc_ctx_t ctx; + struct smb_key *dec_key = &u->u_dec_key; + struct mbuf *mbuf; + int offset, resid, tlen, rc; + smb3_crypto_param_t param; + smb_crypto_mech_t mech; + + ASSERT(u != NULL); + if (s->enc_mech == NULL || dec_key->len != 16) { + return (-1); + } + + tlen = SMB3_TFORM_HDR_SIZE - SMB3_NONCE_OFFS; + offset = mbc->chain_offset + SMB3_NONCE_OFFS; + resid = mbc->max_bytes - offset; + + if (resid < (sr->msgsize + tlen)) { + cmn_err(CE_WARN, "too little data to decrypt"); + return (-1); + } + + if (smb_mbc_peek(mbc, offset, "#c", tlen, tmp_hdr) != 0) { + return (-1); + } + + offset += tlen; + resid -= tlen; + + /* + * The transform header, minus the PROTOCOL_ID and the + * SIGNATURE, is authenticated but not encrypted. + */ + smb3_crypto_init_param(¶m, sr->nonce, SMB3_NONCE_SIZE, + tmp_hdr, tlen, sr->msgsize + SMB2_SIG_SIZE); + + /* + * Unlike signing, which uses one global mech struct, + * encryption requires modifying the mech to add a + * per-use param struct. Thus, we need to make a copy. + */ + mech = *(smb_crypto_mech_t *)s->enc_mech; + rc = smb3_decrypt_init(&ctx, &mech, ¶m, + dec_key->key, dec_key->len); + if (rc != 0) { + return (rc); + } + + /* + * Digest the rest of the SMB packet, starting at the data + * just after the SMB header. + * + * Advance to the src mbuf where we start digesting. + */ + mbuf = mbc->chain; + while (mbuf != NULL && (offset >= mbuf->m_len)) { + offset -= mbuf->m_len; + mbuf = mbuf->m_next; + } + + if (mbuf == NULL) + return (-1); + + /* + * Digest the remainder of this mbuf, limited to the + * residual count, and starting at the current offset. + */ + tlen = mbuf->m_len - offset; + if (tlen > resid) + tlen = resid; + + rc = smb3_decrypt_update(&ctx, (uint8_t *)mbuf->m_data + offset, tlen); + if (rc != 0) { + return (rc); + } + resid -= tlen; + + /* + * Digest any more mbufs in the chain. + */ + while (resid > 0) { + mbuf = mbuf->m_next; + if (mbuf == NULL) { + smb3_encrypt_cancel(&ctx); + return (-1); + } + tlen = mbuf->m_len; + if (tlen > resid) + tlen = resid; + rc = smb3_decrypt_update(&ctx, (uint8_t *)mbuf->m_data, tlen); + if (rc != 0) { + return (rc); + } + resid -= tlen; + } + + /* + * AES_CCM processes the signature like normal data. + */ + rc = smb3_decrypt_update(&ctx, sr->smb2_sig, SMB2_SIG_SIZE); + + if (rc != 0) { + cmn_err(CE_WARN, "failed to process signature"); + return (rc); + } + /* + * smb3_decrypt_final will return an error + * if the signatures don't match. + */ + rc = smb3_decrypt_final(&ctx, sr->sr_request_buf, sr->sr_req_length); + + /* + * We had to decode TFORM_HDR_SIZE bytes before we got here, + * and we just peeked the first TFORM_HDR_SIZE bytes at the + * beginning of this function, so this can't underflow. + */ + ASSERT(sr->command.max_bytes > SMB3_TFORM_HDR_SIZE); + sr->command.max_bytes -= SMB3_TFORM_HDR_SIZE; + return (rc); +} + +/* + * Encrypt the response in in_mbc, and output + * an encrypted response in out_mbc. + * The data in in_mbc is preserved. + */ +int +smb3_encrypt_sr(smb_request_t *sr, struct mbuf_chain *in_mbc, + struct mbuf_chain *out_mbc) +{ + smb_session_t *s = sr->session; + smb_user_t *u = sr->tform_ssn; + uint8_t *buf = (uint8_t *)out_mbc->chain->m_data; + size_t buflen = out_mbc->max_bytes; + smb3_enc_ctx_t ctx; + struct smb_key *enc_key = &u->u_enc_key; + struct mbuf *mbuf; + int resid, tlen, rc; + smb3_crypto_param_t param; + smb_crypto_mech_t mech; + + ASSERT(u != NULL); + if (s->enc_mech == NULL || enc_key->len != 16) { + return (-1); + } + + rc = smb3_encrypt_gen_nonce(u, sr->nonce, SMB3_NONCE_SIZE); + + if (rc != 0) { + cmn_err(CE_WARN, "ran out of nonces"); + return (-1); + } + + (void) smb_mbc_poke(out_mbc, SMB3_NONCE_OFFS, "#c", + SMB3_NONCE_SIZE, sr->nonce); + + resid = in_mbc->max_bytes; + + /* + * The transform header, minus the PROTOCOL_ID and the + * SIGNATURE, is authenticated but not encrypted. + */ + smb3_crypto_init_param(¶m, + sr->nonce, SMB3_NONCE_SIZE, + buf + SMB3_NONCE_OFFS, SMB3_TFORM_HDR_SIZE - SMB3_NONCE_OFFS, + resid); + + /* + * Unlike signing, which uses one global mech struct, + * encryption requires modifying the mech to add a + * per-use param struct. Thus, we need to make a copy. + */ + mech = *(smb_crypto_mech_t *)s->enc_mech; + rc = smb3_encrypt_init(&ctx, &mech, ¶m, + enc_key->key, enc_key->len, buf + SMB3_TFORM_HDR_SIZE, + buflen - SMB3_TFORM_HDR_SIZE); + if (rc != 0) { + return (rc); + } + + /* + * Unlike signing and decryption, we're processing the entirety of the + * message here, so we don't skip anything. + */ + mbuf = in_mbc->chain; + while (resid > 0 && mbuf != NULL) { + tlen = mbuf->m_len; + if (tlen > resid) + tlen = resid; + rc = smb3_encrypt_update(&ctx, (uint8_t *)mbuf->m_data, tlen); + if (rc != 0) { + return (rc); + } + resid -= tlen; + mbuf = mbuf->m_next; + } + + if (mbuf == NULL && resid > 0) { + cmn_err(CE_WARN, "not enough data to encrypt"); + smb3_encrypt_cancel(&ctx); + return (-1); + } + + rc = smb3_encrypt_final(&ctx, buf + SMB3_SIG_OFFS); + + return (rc); +} + +void +smb3_encrypt_fini(smb_session_t *s) +{ + smb_crypto_mech_t *mech; + + if ((mech = s->enc_mech) != NULL) { + kmem_free(mech, sizeof (*mech)); + s->enc_mech = NULL; + } +} diff --git a/usr/src/uts/common/fs/smbsrv/smb3_encrypt_kcf.c b/usr/src/uts/common/fs/smbsrv/smb3_encrypt_kcf.c new file mode 100644 index 0000000000..690a2d792d --- /dev/null +++ b/usr/src/uts/common/fs/smbsrv/smb3_encrypt_kcf.c @@ -0,0 +1,235 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2018 Nexenta Systems, Inc. All rights reserved. + */ + +/* + * Helper functions for SMB3 encryption using the + * Kernel Cryptographic Framework (KCF) + * + * There are two implementations of these functions: + * This one (for kernel) and another for user space: + * See: lib/smbsrv/libfksmbsrv/common/fksmb_encrypt_pkcs.c + */ + +#include <sys/crypto/api.h> +#include <smbsrv/smb_kcrypt.h> +#include <smbsrv/smb2_kproto.h> +#include <sys/cmn_err.h> + +/* + * SMB3 encryption helpers: + * (getmech, init, update, final) + */ + +int +smb3_encrypt_getmech(smb_crypto_mech_t *mech) +{ + crypto_mech_type_t t; + + t = crypto_mech2id(SUN_CKM_AES_CCM); + if (t == CRYPTO_MECH_INVALID) { + cmn_err(CE_NOTE, "smb: no kcf mech: %s", SUN_CKM_AES_CCM); + return (-1); + } + mech->cm_type = t; + + return (0); +} + +void +smb3_crypto_init_param(smb3_crypto_param_t *param, + uint8_t *nonce, size_t noncesize, uint8_t *auth, size_t authsize, + size_t datasize) +{ + param->ulMACSize = SMB2_SIG_SIZE; + param->ulNonceSize = noncesize; + param->nonce = nonce; + param->ulDataSize = datasize; + param->ulAuthDataSize = authsize; + param->authData = auth; +} + +/* + * Start the KCF session, load the key + */ +static int +smb3_crypto_init(smb3_enc_ctx_t *ctxp, smb_crypto_mech_t *mech, + uint8_t *key, size_t key_len, smb3_crypto_param_t *param, + boolean_t is_encrypt) +{ + crypto_key_t ckey; + int rv; + + bzero(&ckey, sizeof (ckey)); + ckey.ck_format = CRYPTO_KEY_RAW; + ckey.ck_data = key; + ckey.ck_length = key_len * 8; /* in bits */ + + mech->cm_param = (caddr_t)param; + mech->cm_param_len = sizeof (*param); + + if (is_encrypt) + rv = crypto_encrypt_init(mech, &ckey, NULL, &ctxp->ctx, NULL); + else + rv = crypto_decrypt_init(mech, &ckey, NULL, &ctxp->ctx, NULL); + + if (rv != CRYPTO_SUCCESS) { + if (is_encrypt) + cmn_err(CE_WARN, + "crypto_encrypt_init failed: 0x%x", rv); + else + cmn_err(CE_WARN, + "crypto_decrypt_init failed: 0x%x", rv); + } + + return (rv == CRYPTO_SUCCESS ? 0 : -1); +} + +int +smb3_encrypt_init(smb3_enc_ctx_t *ctxp, smb_crypto_mech_t *mech, + smb3_crypto_param_t *param, uint8_t *key, size_t keylen, + uint8_t *buf, size_t buflen) +{ + + bzero(&ctxp->output, sizeof (ctxp->output)); + ctxp->output.cd_format = CRYPTO_DATA_RAW; + ctxp->output.cd_length = buflen; + ctxp->output.cd_raw.iov_len = buflen; + ctxp->output.cd_raw.iov_base = (void *)buf; + + return (smb3_crypto_init(ctxp, mech, key, keylen, + param, B_TRUE)); +} + +int +smb3_decrypt_init(smb3_enc_ctx_t *ctxp, smb_crypto_mech_t *mech, + smb3_crypto_param_t *param, uint8_t *key, size_t keylen) +{ + return (smb3_crypto_init(ctxp, mech, key, keylen, + param, B_FALSE)); +} + +/* + * Digest one segment + */ +int +smb3_encrypt_update(smb3_enc_ctx_t *ctxp, uint8_t *in, size_t len) +{ + crypto_data_t data; + int rv; + + bzero(&data, sizeof (data)); + data.cd_format = CRYPTO_DATA_RAW; + data.cd_length = len; + data.cd_raw.iov_base = (void *)in; + data.cd_raw.iov_len = len; + + rv = crypto_encrypt_update(ctxp->ctx, &data, &ctxp->output, NULL); + + if (rv != CRYPTO_SUCCESS) { + cmn_err(CE_WARN, "crypto_encrypt_update failed: 0x%x", rv); + crypto_cancel_ctx(ctxp->ctx); + return (-1); + } + + len = ctxp->output.cd_length; + ctxp->len -= len; + ctxp->output.cd_offset += len; + ctxp->output.cd_length = ctxp->len; + + return (0); +} + +int +smb3_decrypt_update(smb3_enc_ctx_t *ctxp, uint8_t *in, size_t len) +{ + crypto_data_t data; + int rv; + + bzero(&data, sizeof (data)); + data.cd_format = CRYPTO_DATA_RAW; + data.cd_length = len; + data.cd_raw.iov_base = (void *)in; + data.cd_raw.iov_len = len; + + /* + * AES_CCM does not output data until decrypt_final, + * and only does so if the signature matches. + */ + rv = crypto_decrypt_update(ctxp->ctx, &data, NULL, NULL); + + if (rv != CRYPTO_SUCCESS) { + cmn_err(CE_WARN, "crypto_decrypt_update failed: 0x%x", rv); + crypto_cancel_ctx(ctxp->ctx); + return (-1); + } + + return (0); +} + +int +smb3_encrypt_final(smb3_enc_ctx_t *ctxp, uint8_t *digest16) +{ + crypto_data_t out; + int rv; + uint8_t buf[SMB2_SIG_SIZE + 16] = {0}; + size_t outlen; + + bzero(&out, sizeof (out)); + out.cd_format = CRYPTO_DATA_RAW; + out.cd_length = sizeof (buf); + out.cd_raw.iov_len = sizeof (buf); + out.cd_raw.iov_base = (void *)buf; + + rv = crypto_encrypt_final(ctxp->ctx, &out, 0); + + if (rv != CRYPTO_SUCCESS) { + cmn_err(CE_WARN, "crypto_encrypt_final failed: 0x%x", rv); + return (-1); + } + + outlen = out.cd_offset - SMB2_SIG_SIZE; + if (outlen > 0) + bcopy(buf, ctxp->output.cd_raw.iov_base + + ctxp->output.cd_offset, outlen); + bcopy(buf + outlen, digest16, SMB2_SIG_SIZE); + + return (0); +} + +int +smb3_decrypt_final(smb3_enc_ctx_t *ctxp, uint8_t *buf, size_t buflen) +{ + crypto_data_t out; + int rv; + + bzero(&out, sizeof (out)); + out.cd_format = CRYPTO_DATA_RAW; + out.cd_length = buflen; + out.cd_raw.iov_len = buflen; + out.cd_raw.iov_base = (void *)buf; + + rv = crypto_decrypt_final(ctxp->ctx, &out, NULL); + + if (rv != CRYPTO_SUCCESS) + cmn_err(CE_WARN, "crypto_decrypt_final failed: 0x%x", rv); + + return (rv == CRYPTO_SUCCESS ? 0 : -1); +} + +void +smb3_encrypt_cancel(smb3_enc_ctx_t *ctxp) +{ + crypto_cancel_ctx(ctxp->ctx); +} diff --git a/usr/src/uts/common/fs/smbsrv/smb_authenticate.c b/usr/src/uts/common/fs/smbsrv/smb_authenticate.c index 72d06d4d33..a5d0bad335 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_authenticate.c +++ b/usr/src/uts/common/fs/smbsrv/smb_authenticate.c @@ -468,6 +468,22 @@ smb_auth_get_token(smb_request_t *sr) crfree(cr); /* + * Some basic processing for encryption needs to be done, + * even for anonymous/guest sessions. In particular, + * we need to set Session.EncryptData. + * + * Windows handling of anon/guest and encryption is strange. + * It allows these accounts to get through session setup, + * even when they provide no key material. + * Additionally, Windows somehow manages to have key material + * for anonymous accounts under unknown circumstances. + * As such, We set EncryptData on anon/guest to behave like Windows, + * at least through Session Setup. + */ + if (sr->session->dialect >= SMB_VERS_3_0) + smb3_encrypt_begin(sr, token); + + /* * Save the session key, and (maybe) enable signing, * but only for real logon (not ANON or GUEST). */ @@ -568,7 +584,7 @@ smb_authsock_cancel(smb_request_t *sr) */ static uint32_t smb_authsock_sendrecv(smb_request_t *sr, smb_lsa_msg_hdr_t *hdr, - void *sndbuf, void **recvbuf) + void *sndbuf, void **recvbuf) { smb_user_t *user = sr->uid_user; ksocket_t so; diff --git a/usr/src/uts/common/fs/smbsrv/smb_dispatch.c b/usr/src/uts/common/fs/smbsrv/smb_dispatch.c index a1e9e4c163..4599f97ce5 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_dispatch.c +++ b/usr/src/uts/common/fs/smbsrv/smb_dispatch.c @@ -906,19 +906,8 @@ reply_ready: smbsr_send_reply(sr); drop_connection: - if (disconnect) { - smb_rwx_rwenter(&session->s_lock, RW_WRITER); - switch (session->s_state) { - case SMB_SESSION_STATE_DISCONNECTED: - case SMB_SESSION_STATE_TERMINATED: - break; - default: - smb_soshutdown(session->sock); - session->s_state = SMB_SESSION_STATE_DISCONNECTED; - break; - } - smb_rwx_rwexit(&session->s_lock); - } + if (disconnect) + smb_session_disconnect(session); out: if (sr != NULL) { diff --git a/usr/src/uts/common/fs/smbsrv/smb_kshare.c b/usr/src/uts/common/fs/smbsrv/smb_kshare.c index f89a8106ee..a43c4af02a 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_kshare.c +++ b/usr/src/uts/common/fs/smbsrv/smb_kshare.c @@ -21,7 +21,7 @@ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2013 Nexenta Systems, Inc. All rights reserved. + * Copyright 2017 Nexenta Systems, Inc. All rights reserved. * Copyright 2017 Joyent, Inc. */ @@ -850,7 +850,7 @@ smb_kshare_decode(nvlist_t *share) smb_kshare_t tmp; smb_kshare_t *shr; nvlist_t *smb; - char *csc_name = NULL; + char *csc_name = NULL, *strbuf = NULL; int rc; ASSERT(share); @@ -906,6 +906,9 @@ smb_kshare_decode(nvlist_t *share) } } + (void) nvlist_lookup_string(smb, SHOPT_ENCRYPT, &strbuf); + smb_cfg_set_require(strbuf, &tmp.shr_encrypt); + (void) nvlist_lookup_string(smb, SHOPT_CSC, &csc_name); smb_kshare_csc_flags(&tmp, csc_name); @@ -931,6 +934,7 @@ smb_kshare_decode(nvlist_t *share) shr->shr_oemname = smb_kshare_oemname(shr->shr_name); shr->shr_flags = tmp.shr_flags | smb_kshare_is_admin(shr->shr_name); shr->shr_type = tmp.shr_type | smb_kshare_is_special(shr->shr_name); + shr->shr_encrypt = tmp.shr_encrypt; shr->shr_uid = tmp.shr_uid; shr->shr_gid = tmp.shr_gid; diff --git a/usr/src/uts/common/fs/smbsrv/smb_negotiate.c b/usr/src/uts/common/fs/smbsrv/smb_negotiate.c index ee04278e66..265bc227e3 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_negotiate.c +++ b/usr/src/uts/common/fs/smbsrv/smb_negotiate.c @@ -403,7 +403,7 @@ smb_post_negotiate(smb_request_t *sr) smb_sdrc_t smb_com_negotiate(smb_request_t *sr) { - smb_session_t *session = sr->session; + smb_session_t *session = sr->session; smb_arg_negotiate_t *negprot = sr->sr_negprot; uint16_t secmode; uint32_t sesskey; @@ -437,9 +437,9 @@ smb_com_negotiate(smb_request_t *sr) return (rc); } - session->secmode = NEGOTIATE_ENCRYPT_PASSWORDS | + session->srv_secmode = NEGOTIATE_ENCRYPT_PASSWORDS | NEGOTIATE_USER_SECURITY; - secmode = session->secmode; + secmode = session->srv_secmode; sesskey = session->sesskey; negprot->ni_servertime.tv_sec = gethrestime_sec(); @@ -532,7 +532,7 @@ smb_com_negotiate(smb_request_t *sr) secmode |= NEGOTIATE_SECURITY_SIGNATURES_REQUIRED; - session->secmode = secmode; + session->srv_secmode = secmode; } /* diff --git a/usr/src/uts/common/fs/smbsrv/smb_server.c b/usr/src/uts/common/fs/smbsrv/smb_server.c index b65500ce45..26f63334a5 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_server.c +++ b/usr/src/uts/common/fs/smbsrv/smb_server.c @@ -2046,6 +2046,13 @@ smb_server_store_cfg(smb_server_t *sv, smb_ioc_cfg_t *ioc) if (ioc->maxconnections == 0) ioc->maxconnections = 0xFFFFFFFF; + if (ioc->encrypt == SMB_CONFIG_REQUIRED && + ioc->max_protocol < SMB_VERS_3_0) { + cmn_err(CE_WARN, "Server set to require encryption; " + "forcing max_protocol to 3.0"); + ioc->max_protocol = SMB_VERS_3_0; + } + sv->sv_cfg.skc_maxworkers = ioc->maxworkers; sv->sv_cfg.skc_maxconnections = ioc->maxconnections; sv->sv_cfg.skc_keepalive = ioc->keepalive; @@ -2060,6 +2067,7 @@ smb_server_store_cfg(smb_server_t *sv, smb_ioc_cfg_t *ioc) sv->sv_cfg.skc_print_enable = ioc->print_enable; sv->sv_cfg.skc_traverse_mounts = ioc->traverse_mounts; sv->sv_cfg.skc_max_protocol = ioc->max_protocol; + sv->sv_cfg.skc_encrypt = ioc->encrypt; sv->sv_cfg.skc_execflags = ioc->exec_flags; sv->sv_cfg.skc_negtok_len = ioc->negtok_len; sv->sv_cfg.skc_version = ioc->version; diff --git a/usr/src/uts/common/fs/smbsrv/smb_session.c b/usr/src/uts/common/fs/smbsrv/smb_session.c index 1ed8563a1b..205c21179b 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_session.c +++ b/usr/src/uts/common/fs/smbsrv/smb_session.c @@ -817,6 +817,9 @@ smb_session_delete(smb_session_t *session) ASSERT(session->s_magic == SMB_SESSION_MAGIC); + if (session->enc_mech != NULL) + smb3_encrypt_fini(session); + if (session->sign_fini != NULL) session->sign_fini(session); @@ -1491,6 +1494,9 @@ smb_request_free(smb_request_t *sr) if (sr->uid_user != NULL) smb_user_release(sr->uid_user); + if (sr->tform_ssn != NULL) + smb_user_release(sr->tform_ssn); + /* * The above may have left work on the delete queues */ diff --git a/usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c b/usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c index ebeeab60bd..30831b1dcc 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c +++ b/usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c @@ -239,6 +239,13 @@ smb_com_session_setup_andx(smb_request_t *sr) sr->session->native_lm = sinfo->ssi_native_lm; } + /* RejectUnencryptedAccess precludes SMB1 access */ + if (sr->sr_server->sv_cfg.skc_encrypt == SMB_CONFIG_REQUIRED) { + smbsr_error(sr, NT_STATUS_ACCESS_DENIED, + ERRDOS, ERROR_ACCESS_DENIED); + return (SDRC_ERROR); + } + /* * The "meat" of authentication happens here. */ diff --git a/usr/src/uts/common/fs/smbsrv/smb_sign_kcf.c b/usr/src/uts/common/fs/smbsrv/smb_sign_kcf.c index f991eb44b5..55f4bc9d0e 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_sign_kcf.c +++ b/usr/src/uts/common/fs/smbsrv/smb_sign_kcf.c @@ -26,13 +26,13 @@ #include <sys/kmem.h> #include <sys/crypto/api.h> #include <smbsrv/smb_kproto.h> -#include <smbsrv/smb_signing.h> +#include <smbsrv/smb_kcrypt.h> /* * Common function to see if a mech is available. */ static int -find_mech(smb_sign_mech_t *mech, crypto_mech_name_t name) +find_mech(smb_crypto_mech_t *mech, crypto_mech_name_t name) { crypto_mech_type_t t; @@ -51,7 +51,7 @@ find_mech(smb_sign_mech_t *mech, crypto_mech_name_t name) */ int -smb_md5_getmech(smb_sign_mech_t *mech) +smb_md5_getmech(smb_crypto_mech_t *mech) { return (find_mech(mech, SUN_CKM_MD5)); } @@ -60,7 +60,7 @@ smb_md5_getmech(smb_sign_mech_t *mech) * Start the KCF session, load the key */ int -smb_md5_init(smb_sign_ctx_t *ctxp, smb_sign_mech_t *mech) +smb_md5_init(smb_sign_ctx_t *ctxp, smb_crypto_mech_t *mech) { int rv; @@ -120,7 +120,7 @@ smb_md5_final(smb_sign_ctx_t ctx, uint8_t *digest16) */ int -smb2_hmac_getmech(smb_sign_mech_t *mech) +smb2_hmac_getmech(smb_crypto_mech_t *mech) { return (find_mech(mech, SUN_CKM_SHA256_HMAC)); } @@ -129,7 +129,7 @@ smb2_hmac_getmech(smb_sign_mech_t *mech) * Start the KCF session, load the key */ int -smb2_hmac_init(smb_sign_ctx_t *ctxp, smb_sign_mech_t *mech, +smb2_hmac_init(smb_sign_ctx_t *ctxp, smb_crypto_mech_t *mech, uint8_t *key, size_t key_len) { crypto_key_t ckey; @@ -200,7 +200,7 @@ smb2_hmac_final(smb_sign_ctx_t ctx, uint8_t *digest16) */ int -smb3_cmac_getmech(smb_sign_mech_t *mech) +smb3_cmac_getmech(smb_crypto_mech_t *mech) { return (find_mech(mech, SUN_CKM_AES_CMAC)); } @@ -209,7 +209,7 @@ smb3_cmac_getmech(smb_sign_mech_t *mech) * Start the KCF session, load the key */ int -smb3_cmac_init(smb_sign_ctx_t *ctxp, smb_sign_mech_t *mech, +smb3_cmac_init(smb_sign_ctx_t *ctxp, smb_crypto_mech_t *mech, uint8_t *key, size_t key_len) { crypto_key_t ckey; diff --git a/usr/src/uts/common/fs/smbsrv/smb_signing.c b/usr/src/uts/common/fs/smbsrv/smb_signing.c index ea3ba9693d..3d9d9ddb23 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_signing.c +++ b/usr/src/uts/common/fs/smbsrv/smb_signing.c @@ -40,7 +40,7 @@ #include <sys/uio.h> #include <smbsrv/smb_kproto.h> -#include <smbsrv/smb_signing.h> +#include <smbsrv/smb_kcrypt.h> #include <sys/isa_defs.h> #include <sys/byteorder.h> @@ -104,7 +104,7 @@ found: static void smb_sign_fini(smb_session_t *s) { - smb_sign_mech_t *mech; + smb_crypto_mech_t *mech; if ((mech = s->sign_mech) != NULL) { kmem_free(mech, sizeof (*mech)); @@ -125,7 +125,7 @@ smb_sign_begin(smb_request_t *sr, smb_token_t *token) smb_arg_sessionsetup_t *sinfo = sr->sr_ssetup; smb_session_t *session = sr->session; struct smb_sign *sign = &session->signing; - smb_sign_mech_t *mech; + smb_crypto_mech_t *mech; int rc; /* @@ -187,9 +187,10 @@ smb_sign_begin(smb_request_t *sr, smb_token_t *token) sr->reply_seqnum = 1; sign->flags = 0; - if (session->secmode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) { + if (session->srv_secmode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) { sign->flags |= SMB_SIGNING_ENABLED; - if (session->secmode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED) + if (session->srv_secmode & + NEGOTIATE_SECURITY_SIGNATURES_REQUIRED) sign->flags |= SMB_SIGNING_CHECK; } diff --git a/usr/src/uts/common/fs/smbsrv/smb_tree.c b/usr/src/uts/common/fs/smbsrv/smb_tree.c index da7c2f7416..acdfb66eb9 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_tree.c +++ b/usr/src/uts/common/fs/smbsrv/smb_tree.c @@ -260,6 +260,25 @@ smb_tree_connect_core(smb_request_t *sr) tcon->name = name; sr->sr_tcon.si = si; + /* + * [MS-SMB2] 3.3.5.7 Receiving an SMB2 TREE_CONNECT Request + * + * If we support 3.x, RejectUnencryptedAccess is TRUE, + * if Tcon.EncryptData is TRUE or global EncryptData is TRUE, + * and the connection doesn't support encryption, + * return ACCESS_DENIED. + * + * If RejectUnencryptedAccess is TRUE, we force max_protocol + * to at least 3.0. Additionally, if the tree requires encryption, + * we don't care what we support, we still enforce encryption. + */ + if ((sr->sr_server->sv_cfg.skc_encrypt == SMB_CONFIG_REQUIRED || + si->shr_encrypt == SMB_CONFIG_REQUIRED) && + (sr->session->srv_cap & SMB2_CAP_ENCRYPTION) == 0) { + status = NT_STATUS_ACCESS_DENIED; + goto out; + } + switch (si->shr_type & STYPE_MASK) { case STYPE_DISKTREE: status = smb_tree_connect_disk(sr, &sr->sr_tcon); @@ -275,6 +294,7 @@ smb_tree_connect_core(smb_request_t *sr) break; } +out: smb_kshare_release(sr->sr_server, si); sr->sr_tcon.si = NULL; @@ -1079,6 +1099,7 @@ static int smb_tree_getattr(const smb_kshare_t *si, smb_node_t *node, smb_tree_t *tree) { vfs_t *vfsp = SMB_NODE_VFS(node); + smb_cfg_val_t srv_encrypt; ASSERT(vfsp); @@ -1088,6 +1109,19 @@ smb_tree_getattr(const smb_kshare_t *si, smb_node_t *node, smb_tree_t *tree) smb_tree_get_volname(vfsp, tree); smb_tree_get_flags(si, vfsp, tree); + srv_encrypt = tree->t_session->s_server->sv_cfg.skc_encrypt; + if (tree->t_session->dialect >= SMB_VERS_3_0) { + if (si->shr_encrypt == SMB_CONFIG_REQUIRED || + srv_encrypt == SMB_CONFIG_REQUIRED) + tree->t_encrypt = SMB_CONFIG_REQUIRED; + else if (si->shr_encrypt == SMB_CONFIG_ENABLED || + srv_encrypt == SMB_CONFIG_ENABLED) + tree->t_encrypt = SMB_CONFIG_ENABLED; + else + tree->t_encrypt = SMB_CONFIG_DISABLED; + } else + tree->t_encrypt = SMB_CONFIG_DISABLED; + VFS_RELE(vfsp); return (0); } diff --git a/usr/src/uts/common/smbsrv/Makefile b/usr/src/uts/common/smbsrv/Makefile index 8b000be80f..cf33050878 100644 --- a/usr/src/uts/common/smbsrv/Makefile +++ b/usr/src/uts/common/smbsrv/Makefile @@ -46,13 +46,13 @@ HDRS= alloc.h \ smb_idmap.h \ smb_inet.h \ smb_ioctl.h \ + smb_kcrypt.h \ smb_kproto.h \ smb_kstat.h \ smb_ktypes.h \ smb_oplock.h \ smb_privilege.h \ smb_share.h \ - smb_signing.h \ smb_token.h \ smb_vops.h \ smb_xdr.h \ diff --git a/usr/src/uts/common/smbsrv/smb2.h b/usr/src/uts/common/smbsrv/smb2.h index c52fee29b4..d58b3cbb0b 100644 --- a/usr/src/uts/common/smbsrv/smb2.h +++ b/usr/src/uts/common/smbsrv/smb2.h @@ -22,6 +22,13 @@ extern "C" { #define SMB2_PROTOCOL_ID { 0xFE, 'S', 'M', 'B' } #define SMB2_HDR_SIZE 64 +#define SMB3_TFORM_HDR_SIZE 52 + +/* + * Protocol ID as a 32-bit little-endian integer. + */ +#define SMB2_PROTOCOL_MAGIC 0x424d53fe +#define SMB3_ENCRYPTED_MAGIC 0x424d53fd /* * SMB2 header command codes. diff --git a/usr/src/uts/common/smbsrv/smb2_kproto.h b/usr/src/uts/common/smbsrv/smb2_kproto.h index 00eb2eac5c..cd397768d9 100644 --- a/usr/src/uts/common/smbsrv/smb2_kproto.h +++ b/usr/src/uts/common/smbsrv/smb2_kproto.h @@ -34,6 +34,9 @@ extern uint32_t smb2_res_def_timeout; extern uint32_t smb2_res_max_timeout; extern int smb2_enable_dh; +#define SMB3_CLIENT_ENCRYPTS(sr) \ + ((sr->session->capabilities & SMB2_CAP_ENCRYPTION) != 0) + void smb2_dispatch_stats_init(smb_server_t *); void smb2_dispatch_stats_fini(smb_server_t *); void smb2_dispatch_stats_update(smb_server_t *, @@ -46,6 +49,9 @@ void smb2sr_append_postwork(smb_request_t *, smb_request_t *); int smb2_decode_header(smb_request_t *); int smb2_encode_header(smb_request_t *, boolean_t); +int smb3_decode_tform_header(smb_request_t *); +int smb3_encode_tform_header(smb_request_t *, struct mbuf_chain *mbc); + void smb2_send_reply(smb_request_t *); void smb2sr_put_error(smb_request_t *, uint32_t); void smb2sr_put_error_data(smb_request_t *, uint32_t, mbuf_chain_t *); @@ -57,8 +63,12 @@ int smb2_sign_check_request(smb_request_t *); void smb2_sign_reply(smb_request_t *); void smb2_sign_init_mech(smb_session_t *); -uint32_t smb2_fsctl_vneginfo(smb_request_t *, smb_fsctl_t *); +int smb3_encrypt_sr(smb_request_t *, struct mbuf_chain *, struct mbuf_chain *); +int smb3_decrypt_sr(smb_request_t *); +int smb3_encrypt_init_mech(smb_session_t *s); + uint32_t smb2_fsctl_resiliency(smb_request_t *, smb_fsctl_t *); +uint32_t smb2_fsctl_vneginfo(smb_request_t *, smb_fsctl_t *); smb_sdrc_t smb2_negotiate(smb_request_t *); smb_sdrc_t smb2_session_setup(smb_request_t *); diff --git a/usr/src/uts/common/smbsrv/smb_ioctl.h b/usr/src/uts/common/smbsrv/smb_ioctl.h index ec71dbe4d0..343c0d549c 100644 --- a/usr/src/uts/common/smbsrv/smb_ioctl.h +++ b/usr/src/uts/common/smbsrv/smb_ioctl.h @@ -20,7 +20,7 @@ */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2015 Nexenta Systems, Inc. All rights reserved. + * Copyright 2016 Nexenta Systems, Inc. All rights reserved. * Copyright 2017 Joyent, Inc. */ @@ -70,7 +70,7 @@ typedef struct smb_ioc_spooldoc { typedef struct { smb_ioc_header_t hdr; - int32_t offset; + int32_t offset; } smb_ioc_gmt_t; typedef struct smb_ioc_share { @@ -172,6 +172,7 @@ typedef struct smb_ioc_cfg { int32_t print_enable; int32_t traverse_mounts; uint32_t max_protocol; + uint32_t encrypt; uint32_t exec_flags; uint32_t negtok_len; smb_version_t version; diff --git a/usr/src/uts/common/smbsrv/smb_signing.h b/usr/src/uts/common/smbsrv/smb_kcrypt.h index c83e8d1f09..8be53688c7 100644 --- a/usr/src/uts/common/smbsrv/smb_signing.h +++ b/usr/src/uts/common/smbsrv/smb_kcrypt.h @@ -10,11 +10,11 @@ */ /* - * Copyright 2015 Nexenta Systems, Inc. All rights reserved. + * Copyright 2017 Nexenta Systems, Inc. All rights reserved. */ -#ifndef _SMB_SIGNING_H_ -#define _SMB_SIGNING_H_ +#ifndef _SMB_KCRYPT_H_ +#define _SMB_KCRYPT_H_ /* * SMB signing routines used in {smb,smb2}_signing.c @@ -42,19 +42,37 @@ extern "C" { #ifdef _KERNEL /* KCF variant */ -typedef crypto_mechanism_t smb_sign_mech_t; +typedef crypto_mechanism_t smb_crypto_mech_t; typedef crypto_context_t smb_sign_ctx_t; +typedef struct smb3_enc_ctx { + crypto_context_t ctx; + crypto_data_t output; + size_t len; +} smb3_enc_ctx_t; +typedef CK_AES_CCM_PARAMS smb3_crypto_param_t; #else /* _KERNEL */ /* PKCS11 variant */ -typedef CK_MECHANISM smb_sign_mech_t; +typedef CK_MECHANISM smb_crypto_mech_t; typedef CK_SESSION_HANDLE smb_sign_ctx_t; +typedef struct smb_enc_ctx { + CK_SESSION_HANDLE ctx; + uint8_t *output; + CK_ULONG len; +} smb3_enc_ctx_t; +/* + * CCM in PKCS has not been implemented. + * We just need an opaque type with space to refer to. + */ +typedef struct pkcs_ccm_param { + uint8_t buf[100]; +} smb3_crypto_param_t; #endif /* _KERNEL */ /* * SMB signing routines used in smb_signing.c */ -int smb_md5_getmech(smb_sign_mech_t *); -int smb_md5_init(smb_sign_ctx_t *, smb_sign_mech_t *); +int smb_md5_getmech(smb_crypto_mech_t *); +int smb_md5_init(smb_sign_ctx_t *, smb_crypto_mech_t *); int smb_md5_update(smb_sign_ctx_t, void *, size_t); int smb_md5_final(smb_sign_ctx_t, uint8_t *); @@ -65,18 +83,35 @@ int smb_md5_final(smb_sign_ctx_t, uint8_t *); * lib/smbsrv/libfksmbsrv/common/fksmb_sign_pkcs.c */ -int smb2_hmac_getmech(smb_sign_mech_t *); -int smb2_hmac_init(smb_sign_ctx_t *, smb_sign_mech_t *, uint8_t *, size_t); +int smb2_hmac_getmech(smb_crypto_mech_t *); +int smb2_hmac_init(smb_sign_ctx_t *, smb_crypto_mech_t *, uint8_t *, size_t); int smb2_hmac_update(smb_sign_ctx_t, uint8_t *, size_t); int smb2_hmac_final(smb_sign_ctx_t, uint8_t *); -int smb3_cmac_getmech(smb_sign_mech_t *); -int smb3_cmac_init(smb_sign_ctx_t *, smb_sign_mech_t *, uint8_t *, size_t); +int smb3_cmac_getmech(smb_crypto_mech_t *); +int smb3_cmac_init(smb_sign_ctx_t *, smb_crypto_mech_t *, uint8_t *, size_t); int smb3_cmac_update(smb_sign_ctx_t, uint8_t *, size_t); int smb3_cmac_final(smb_sign_ctx_t, uint8_t *); +int smb3_do_kdf(void *, void *, size_t, uint8_t *, uint32_t); + +int smb3_encrypt_getmech(smb_crypto_mech_t *); +void smb3_crypto_init_param(smb3_crypto_param_t *, uint8_t *, size_t, + uint8_t *, size_t, size_t); + +int smb3_encrypt_init(smb3_enc_ctx_t *, smb_crypto_mech_t *, + smb3_crypto_param_t *, uint8_t *, size_t, uint8_t *, size_t); +int smb3_encrypt_update(smb3_enc_ctx_t *, uint8_t *, size_t); +int smb3_encrypt_final(smb3_enc_ctx_t *, uint8_t *); +void smb3_encrypt_cancel(smb3_enc_ctx_t *); + +int smb3_decrypt_init(smb3_enc_ctx_t *, smb_crypto_mech_t *, + smb3_crypto_param_t *, uint8_t *, size_t); +int smb3_decrypt_update(smb3_enc_ctx_t *, uint8_t *, size_t); +int smb3_decrypt_final(smb3_enc_ctx_t *, uint8_t *, size_t); + #ifdef __cplusplus } #endif -#endif /* _SMB_SIGNING_H_ */ +#endif /* _SMB_KCRYPT_H_ */ diff --git a/usr/src/uts/common/smbsrv/smb_kproto.h b/usr/src/uts/common/smbsrv/smb_kproto.h index fed5fd1493..8f84b7abb4 100644 --- a/usr/src/uts/common/smbsrv/smb_kproto.h +++ b/usr/src/uts/common/smbsrv/smb_kproto.h @@ -589,6 +589,8 @@ int smb_sign_check_secondary(smb_request_t *, unsigned int); void smb_sign_reply(smb_request_t *, mbuf_chain_t *); /* SMB2, but here because it's called from common code. */ void smb2_sign_begin(smb_request_t *, smb_token_t *); +void smb3_encrypt_begin(smb_request_t *, smb_token_t *); +void smb3_encrypt_fini(smb_session_t *); boolean_t smb_sattr_check(uint16_t, uint16_t); diff --git a/usr/src/uts/common/smbsrv/smb_ktypes.h b/usr/src/uts/common/smbsrv/smb_ktypes.h index ac9a01e642..00a4652b69 100644 --- a/usr/src/uts/common/smbsrv/smb_ktypes.h +++ b/usr/src/uts/common/smbsrv/smb_ktypes.h @@ -719,6 +719,7 @@ typedef struct smb_kshare { char *shr_access_rw; avl_node_t shr_link; kmutex_t shr_mutex; + smb_cfg_val_t shr_encrypt; /* Share.EncryptData */ } smb_kshare_t; @@ -938,9 +939,11 @@ typedef struct smb_session { uint16_t s_max_credits; uint32_t capabilities; + uint32_t srv_cap; struct smb_sign signing; /* SMB1 */ void *sign_mech; /* mechanism info */ + void *enc_mech; /* SMB2/SMB3 signing support */ int (*sign_calc)(struct smb_request *, @@ -961,7 +964,8 @@ typedef struct smb_session { volatile uint32_t s_file_cnt; volatile uint32_t s_dir_cnt; - uint16_t secmode; + uint16_t cli_secmode; + uint16_t srv_secmode; uint32_t sesskey; uint32_t challenge_len; unsigned char challenge_key[SMB_CHALLENGE_SZ]; @@ -994,6 +998,7 @@ typedef struct smb_session { #define SMB_USER_VALID(u) \ ASSERT(((u) != NULL) && ((u)->u_magic == SMB_USER_MAGIC)) +/* These flags are all <= 0x00000010 */ #define SMB_USER_FLAG_GUEST SMB_ATF_GUEST #define SMB_USER_FLAG_ANON SMB_ATF_ANON #define SMB_USER_FLAG_ADMIN SMB_ATF_ADMIN @@ -1053,6 +1058,13 @@ typedef struct smb_user { uint32_t u_sign_flags; struct smb_key u_sign_key; /* SMB2 signing */ + + struct smb_key u_enc_key; + struct smb_key u_dec_key; + volatile uint64_t u_nonce_cnt; + uint8_t u_nonce_fixed[4]; + uint64_t u_salt; + smb_cfg_val_t u_encrypt; } smb_user_t; #define SMB_TREE_MAGIC 0x54524545 /* 'TREE' */ @@ -1130,6 +1142,7 @@ typedef struct smb_tree { uint32_t t_execflags; time_t t_connect_time; volatile uint32_t t_open_files; + smb_cfg_val_t t_encrypt; /* Share.EncryptData */ } smb_tree_t; #define SMB_TREE_VFS(tree) ((tree)->t_snode->vp->v_vfsp) @@ -1841,6 +1854,16 @@ typedef struct smb_request { uint64_t smb2_ssnid; /* See u_ssnid */ uint8_t smb2_sig[16]; /* signature */ + /* + * SMB3 transform header fields. [MS-SMB2 2.2.41] + */ + uint64_t smb3_tform_ssnid; + smb_user_t *tform_ssn; + uint32_t msgsize; + uint8_t nonce[16]; + + boolean_t encrypted; + boolean_t smb2_async; uint64_t smb2_async_id; /* Parameters */ diff --git a/usr/src/uts/common/smbsrv/smb_share.h b/usr/src/uts/common/smbsrv/smb_share.h index 9df3e9e8e8..7c2219caad 100644 --- a/usr/src/uts/common/smbsrv/smb_share.h +++ b/usr/src/uts/common/smbsrv/smb_share.h @@ -34,6 +34,7 @@ #include <smbsrv/string.h> #include <smbsrv/smb_inet.h> #include <smbsrv/hash_table.h> +#include <smbsrv/smbinfo.h> #if !defined(_KERNEL) && !defined(_FAKE_KERNEL) #include <libshare.h> @@ -76,7 +77,13 @@ extern "C" { * * quotas SMB quotas presented & supported (T/F) * - * next three properties use access-list a al NFS + * encrypt Controls SMB3 encryption per-share. + * disabled Server does not tell the client to encrypt requests. + * enabled Server asks, but does not require, that the client + * encrypt its requests. + * required Server denies unencrypted share access. + * + * next three properties use access-list a la NFS * * ro list of hosts that will have read-only access * rw list of hosts that will have read/write access @@ -95,6 +102,7 @@ extern "C" { #define SHOPT_DESCRIPTION "description" #define SHOPT_QUOTAS "quotas" #define SHOPT_FSO "fso" /* Force Shared Oplocks */ +#define SHOPT_ENCRYPT "encrypt" #define SHOPT_AUTOHOME "Autohome" #define SMB_DEFAULT_SHARE_GROUP "smb" @@ -208,6 +216,7 @@ typedef struct smb_share { char shr_access_none[MAXPATHLEN]; char shr_access_ro[MAXPATHLEN]; char shr_access_rw[MAXPATHLEN]; + smb_cfg_val_t shr_encrypt; } smb_share_t; typedef struct smb_shriter { diff --git a/usr/src/uts/common/smbsrv/smbinfo.h b/usr/src/uts/common/smbsrv/smbinfo.h index e513eb5e43..213a1e8ced 100644 --- a/usr/src/uts/common/smbsrv/smbinfo.h +++ b/usr/src/uts/common/smbsrv/smbinfo.h @@ -20,7 +20,7 @@ */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2015 Nexenta Systems, Inc. All rights reserved. + * Copyright 2017 Nexenta Systems, Inc. All rights reserved. */ #ifndef _SMBSRV_SMBINFO_H @@ -131,6 +131,14 @@ typedef struct smb_version { uint32_t sv_platform_id; } smb_version_t; +typedef enum smb_cfg_val { + SMB_CONFIG_DISABLED = 0, + SMB_CONFIG_ENABLED = 1, + SMB_CONFIG_REQUIRED = 2 +} smb_cfg_val_t; + +void smb_cfg_set_require(const char *, smb_cfg_val_t *); + /* See also: smb_ioc_cfg_t */ typedef struct smb_kmod_cfg { uint32_t skc_maxworkers; @@ -147,6 +155,7 @@ typedef struct smb_kmod_cfg { int32_t skc_print_enable; int32_t skc_traverse_mounts; uint32_t skc_max_protocol; /* SMB_VERS_... */ + smb_cfg_val_t skc_encrypt; /* EncryptData and RejectUnencryptedAccess */ uint32_t skc_execflags; uint32_t skc_negtok_len; smb_version_t skc_version; |