The branch, v4-8-stable has been updated via 5a9d09f VERSION: Bump version up to 4.8.0... via 9c2a215 WHATSNEW: Add release notes for Samba 4.8.0. via 03e63dd CVE-2018-1050: s3: RPC: spoolss server. Protect against null pointer derefs. via 87b10d3 CVE-2018-1057: s4:dsdb/acl: changing dBCSPwd is only allowed with a control via 5c957af CVE-2018-1057: s4:dsdb: use DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID via 6335660 CVE-2018-1057: s4:dsdb/samdb: define DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID control via f8ff72d CVE-2018-1057: s4:dsdb/acl: run password checking only once via 4e30547 CVE-2018-1057: s4/dsdb: correctly detect password resets via bd39608 CVE-2018-1057: s4:dsdb/acl: add a NULL check for talloc_new() in acl_check_password_rights() via b152db9 CVE-2018-1057: s4:dsdb/acl: add check for DSDB_CONTROL_PASSWORD_HASH_VALUES_OID control via 93e11c7 CVE-2018-1057: s4:dsdb/acl: check for internal controls before other checks via 9e7dc49 CVE-2018-1057: s4:dsdb/acl: remove unused else branches in acl_check_password_rights() via be3c583 CVE-2018-1057: s4:dsdb/acl: only call dsdb_acl_debug() if we checked the acl in acl_check_password_rights() via 9a3f754 CVE-2018-1057: s4:dsdb/password_hash: add a helper variable for passwordAttr->num_values via 231ed98 CVE-2018-1057: s4:dsdb/password_hash: add a helper variable for LDB_FLAG_MOD_TYPE via ccb38e9 CVE-2018-1057: s4:dsdb/tests: add a test for password change with empty delete via 60c7969 WHATSNEW: Domain member setups require winbindd via e73deca nsswitch: fix wbinfo -m --verbose trust type "Local" via d6753a1 libsmb: Use smb2 tcon if conn_protocol >= SMB2_02 via e176cab s3:smbd: Do not crash if we fail to init the session table via efaf354 VERSION: Bump version up to 4.8.0rc5... from 562b385 VERSION: Disable GIT_SNAPSHOT for the 4.8.0rc4 release.
https://git.samba.org/?p=samba.git;a=shortlog;h=v4-8-stable - Log ----------------------------------------------------------------- ----------------------------------------------------------------------- Summary of changes: VERSION | 2 +- WHATSNEW.txt | 47 ++++++-- nsswitch/libwbclient/wbc_util.c | 4 +- source3/libsmb/clientgen.c | 2 +- source3/rpc_server/spoolss/srv_spoolss_nt.c | 13 +++ source3/smbd/negprot.c | 23 +++- source4/dsdb/samdb/ldb_modules/acl.c | 146 ++++++++++++++++++++++--- source4/dsdb/samdb/ldb_modules/password_hash.c | 45 ++++++-- source4/dsdb/samdb/samdb.h | 9 ++ source4/dsdb/tests/python/passwords.py | 49 +++++++++ source4/libcli/ldap/ldap_controls.c | 1 + source4/setup/schema_samba4.ldif | 1 + 12 files changed, 301 insertions(+), 41 deletions(-) Changeset truncated at 500 lines: diff --git a/VERSION b/VERSION index d3ed508..2f7a2d1 100644 --- a/VERSION +++ b/VERSION @@ -87,7 +87,7 @@ SAMBA_VERSION_PRE_RELEASE= # e.g. SAMBA_VERSION_RC_RELEASE=1 # # -> "3.0.0rc1" # ######################################################## -SAMBA_VERSION_RC_RELEASE=4 +SAMBA_VERSION_RC_RELEASE= ######################################################## # To mark SVN snapshots this should be set to 'yes' # diff --git a/WHATSNEW.txt b/WHATSNEW.txt index 5151564..cea642b 100644 --- a/WHATSNEW.txt +++ b/WHATSNEW.txt @@ -1,12 +1,11 @@ -Release Announcements -===================== + ============================= + Release Notes for Samba 4.8.0 + March 13, 2018 + ============================= -This is the fourth release candidate of Samba 4.8. This is *not* -intended for production environments and is designed for testing -purposes only. Please report any defects via the Samba bug reporting -system at https://bugzilla.samba.org/. -Samba 4.8 will be the next version of the Samba suite. +This is the first stable release of the Samba 4.8 release series. +Please read the release notes carefully before upgrading. UPGRADING @@ -22,6 +21,13 @@ Unlike in previous releases a transparent downgrade is not possible. If you wish to downgrade such a DB to a Samba 4.7 or earlier version, please run the source4/scripting/bin/sambaundoguididx script first. +Domain member setups require winbindd +------------------------------------- + +Setups with "security = domain" or "security = ads" require a +running 'winbindd' now. The fallback that smbd directly contacts +domain controllers is gone. + smbclient reparse point symlink parameters reversed --------------------------------------------------- @@ -143,7 +149,6 @@ dot or xdot, this shows the network as a graph with DCs as vertices and connections edges. Certain types of degenerate edges are shown in different colours or line-styles. - smbclient reparse point symlink parameters reversed --------------------------------------------------- @@ -314,8 +319,8 @@ smb.conf changes map untrusted to domain Removed oplock contention limit Removed prefork children New 1 - mdns name New netbios - fruit:time machine New false + mdns name New netbios + fruit:time machine New false profile acls Removed use spnego Removed server schannel Default changed/ yes @@ -325,6 +330,28 @@ smb.conf changes winbind trusted domains only Removed +CHANGES SINCE 4.8.0rc4 +====================== + +o Jeremy Allison <j...@samba.org> + * BUG 11343: CVE-2018-1050: Codenomicon crashes in spoolss server code. + +o Ralph Boehme <s...@samba.org> + * BUG 13272: CVE-2018-1057: Unprivileged user can change any user (and admin) + password. + * BUG 13313: nsswitch: Fix wbinfo -m --verbose trust type "Local". + +o Stefan Metzmacher <me...@samba.org> + * BUG 13272: CVE-2018-1057: Unprivileged user can change any user (and admin) + password. + +o Dan Robertson <drobert...@tripwire.com> + * BUG 13310: libsmb: Use smb2 tcon if conn_protocol >= SMB2_02. + +o Andreas Schneider <a...@samba.org> + * BUG 13315: s3:smbd: Do not crash if we fail to init the session table. + + CHANGES SINCE 4.8.0rc3 ====================== diff --git a/nsswitch/libwbclient/wbc_util.c b/nsswitch/libwbclient/wbc_util.c index ecfcaa0..fc6a840 100644 --- a/nsswitch/libwbclient/wbc_util.c +++ b/nsswitch/libwbclient/wbc_util.c @@ -455,9 +455,7 @@ static wbcErr process_domain_info_string(struct wbcDomainInfo *info, *s = '\0'; s++; - if (strcmp(r, "Local") == 0) { - info->trust_type = WBC_DOMINFO_TRUSTTYPE_NONE; - } else if (strncmp(r, "Routed", strlen("Routed")) == 0) { + if (strncmp(r, "Routed", strlen("Routed")) == 0) { info->trust_type = WBC_DOMINFO_TRUSTTYPE_NONE; info->trust_routing = strdup(r); BAIL_ON_PTR_ERROR(info->trust_routing, wbc_status); diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c index 44afee1..2e4dd15 100644 --- a/source3/libsmb/clientgen.c +++ b/source3/libsmb/clientgen.c @@ -371,7 +371,7 @@ uint32_t cli_state_set_tid(struct cli_state *cli, uint32_t tid) uint32_t ret; if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { ret = smb2cli_tcon_current_id(cli->smb2.tcon); - smb2cli_tcon_set_id(cli->smb1.tcon, tid); + smb2cli_tcon_set_id(cli->smb2.tcon, tid); } else { ret = smb1cli_tcon_current_id(cli->smb1.tcon); smb1cli_tcon_set_id(cli->smb1.tcon, tid); diff --git a/source3/rpc_server/spoolss/srv_spoolss_nt.c b/source3/rpc_server/spoolss/srv_spoolss_nt.c index f0226ba..f6e680e 100644 --- a/source3/rpc_server/spoolss/srv_spoolss_nt.c +++ b/source3/rpc_server/spoolss/srv_spoolss_nt.c @@ -142,6 +142,11 @@ static void prune_printername_cache(void); static const char *canon_servername(const char *servername) { const char *pservername = servername; + + if (servername == NULL) { + return ""; + } + while (*pservername == '\\') { pservername++; } @@ -2042,6 +2047,10 @@ WERROR _spoolss_DeletePrinterDriver(struct pipes_struct *p, return WERR_ACCESS_DENIED; } + if (r->in.architecture == NULL || r->in.driver == NULL) { + return WERR_INVALID_ENVIRONMENT; + } + /* check that we have a valid driver name first */ if ((version = get_version_id(r->in.architecture)) == -1) { @@ -2181,6 +2190,10 @@ WERROR _spoolss_DeletePrinterDriverEx(struct pipes_struct *p, return WERR_ACCESS_DENIED; } + if (r->in.architecture == NULL || r->in.driver == NULL) { + return WERR_INVALID_ENVIRONMENT; + } + /* check that we have a valid driver name first */ if (get_version_id(r->in.architecture) == -1) { /* this is what NT returns */ diff --git a/source3/smbd/negprot.c b/source3/smbd/negprot.c index 3a9363d..a36822e 100644 --- a/source3/smbd/negprot.c +++ b/source3/smbd/negprot.c @@ -65,6 +65,8 @@ static void reply_lanman1(struct smb_request *req, uint16_t choice) time_t t = time(NULL); struct smbXsrv_connection *xconn = req->xconn; uint16_t raw; + NTSTATUS status; + if (lp_async_smb_echo_handler()) { raw = 0; } else { @@ -88,7 +90,11 @@ static void reply_lanman1(struct smb_request *req, uint16_t choice) SSVAL(req->outbuf,smb_vwv11, 8); } - smbXsrv_connection_init_tables(xconn, PROTOCOL_LANMAN1); + status = smbXsrv_connection_init_tables(xconn, PROTOCOL_LANMAN1); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + return; + } /* Reply, SMBlockread, SMBwritelock supported. */ SCVAL(req->outbuf,smb_flg, FLAG_REPLY|FLAG_SUPPORT_LOCKREAD); @@ -115,6 +121,8 @@ static void reply_lanman2(struct smb_request *req, uint16_t choice) time_t t = time(NULL); struct smbXsrv_connection *xconn = req->xconn; uint16_t raw; + NTSTATUS status; + if (lp_async_smb_echo_handler()) { raw = 0; } else { @@ -140,7 +148,11 @@ static void reply_lanman2(struct smb_request *req, uint16_t choice) SSVAL(req->outbuf,smb_vwv11, 8); } - smbXsrv_connection_init_tables(xconn, PROTOCOL_LANMAN2); + status = smbXsrv_connection_init_tables(xconn, PROTOCOL_LANMAN2); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + return; + } /* Reply, SMBlockread, SMBwritelock supported. */ SCVAL(req->outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD); @@ -260,6 +272,7 @@ static void reply_nt1(struct smb_request *req, uint16_t choice) struct smbXsrv_connection *xconn = req->xconn; bool signing_desired = false; bool signing_required = false; + NTSTATUS status; xconn->smb1.negprot.encrypted_passwords = lp_encrypt_passwords(); @@ -336,7 +349,11 @@ static void reply_nt1(struct smb_request *req, uint16_t choice) SSVAL(req->outbuf,smb_vwv0,choice); SCVAL(req->outbuf,smb_vwv1,secword); - smbXsrv_connection_init_tables(xconn, PROTOCOL_NT1); + status = smbXsrv_connection_init_tables(xconn, PROTOCOL_NT1); + if (!NT_STATUS_IS_OK(status)) { + reply_nterror(req, status); + return; + } SSVAL(req->outbuf,smb_vwv1+1, lp_max_mux()); /* maxmpx */ SSVAL(req->outbuf,smb_vwv2+1, 1); /* num vcs */ diff --git a/source4/dsdb/samdb/ldb_modules/acl.c b/source4/dsdb/samdb/ldb_modules/acl.c index 27d4e76..d750362 100644 --- a/source4/dsdb/samdb/ldb_modules/acl.c +++ b/source4/dsdb/samdb/ldb_modules/acl.c @@ -966,11 +966,79 @@ static int acl_check_password_rights(TALLOC_CTX *mem_ctx, { int ret = LDB_SUCCESS; unsigned int del_attr_cnt = 0, add_attr_cnt = 0, rep_attr_cnt = 0; + unsigned int del_val_cnt = 0, add_val_cnt = 0, rep_val_cnt = 0; struct ldb_message_element *el; struct ldb_message *msg; + struct ldb_control *c = NULL; const char *passwordAttrs[] = { "userPassword", "clearTextPassword", - "unicodePwd", "dBCSPwd", NULL }, **l; + "unicodePwd", NULL }, **l; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + struct dsdb_control_password_acl_validation *pav = NULL; + + if (tmp_ctx == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + + pav = talloc_zero(req, struct dsdb_control_password_acl_validation); + if (pav == NULL) { + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + c = ldb_request_get_control(req, DSDB_CONTROL_PASSWORD_CHANGE_OID); + if (c != NULL) { + pav->pwd_reset = false; + + /* + * The "DSDB_CONTROL_PASSWORD_CHANGE_OID" control means that we + * have a user password change and not a set as the message + * looks like. In it's value blob it contains the NT and/or LM + * hash of the old password specified by the user. This control + * is used by the SAMR and "kpasswd" password change mechanisms. + * + * This control can't be used by real LDAP clients, + * the only caller is samdb_set_password_internal(), + * so we don't have to strict verification of the input. + */ + ret = acl_check_extended_right(tmp_ctx, + sd, + acl_user_token(module), + GUID_DRS_USER_CHANGE_PASSWORD, + SEC_ADS_CONTROL_ACCESS, + sid); + goto checked; + } + + c = ldb_request_get_control(req, DSDB_CONTROL_PASSWORD_HASH_VALUES_OID); + if (c != NULL) { + pav->pwd_reset = true; + + /* + * The "DSDB_CONTROL_PASSWORD_HASH_VALUES_OID" control, without + * "DSDB_CONTROL_PASSWORD_CHANGE_OID" control means that we + * have a force password set. + * This control is used by the SAMR/NETLOGON/LSA password + * reset mechanisms. + * + * This control can't be used by real LDAP clients, + * the only caller is samdb_set_password_internal(), + * so we don't have to strict verification of the input. + */ + ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module), + GUID_DRS_FORCE_CHANGE_PASSWORD, + SEC_ADS_CONTROL_ACCESS, + sid); + goto checked; + } + + el = ldb_msg_find_element(req->op.mod.message, "dBCSPwd"); + if (el != NULL) { + /* + * dBCSPwd is only allowed with a control. + */ + talloc_free(tmp_ctx); + return LDB_ERR_UNWILLING_TO_PERFORM; + } msg = ldb_msg_copy_shallow(tmp_ctx, req->op.mod.message); if (msg == NULL) { @@ -984,12 +1052,15 @@ static int acl_check_password_rights(TALLOC_CTX *mem_ctx, while ((el = ldb_msg_find_element(msg, *l)) != NULL) { if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) { ++del_attr_cnt; + del_val_cnt += el->num_values; } if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD) { ++add_attr_cnt; + add_val_cnt += el->num_values; } if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) { ++rep_attr_cnt; + rep_val_cnt += el->num_values; } ldb_msg_remove_element(msg, el); } @@ -1002,26 +1073,30 @@ static int acl_check_password_rights(TALLOC_CTX *mem_ctx, return LDB_SUCCESS; } - if (ldb_request_get_control(req, - DSDB_CONTROL_PASSWORD_CHANGE_OID) != NULL) { - /* The "DSDB_CONTROL_PASSWORD_CHANGE_OID" control means that we - * have a user password change and not a set as the message - * looks like. In it's value blob it contains the NT and/or LM - * hash of the old password specified by the user. - * This control is used by the SAMR and "kpasswd" password - * change mechanisms. */ + + if (rep_attr_cnt > 0) { + pav->pwd_reset = true; + ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module), - GUID_DRS_USER_CHANGE_PASSWORD, + GUID_DRS_FORCE_CHANGE_PASSWORD, SEC_ADS_CONTROL_ACCESS, sid); + goto checked; } - else if (rep_attr_cnt > 0 || (add_attr_cnt != del_attr_cnt)) { + + if (add_attr_cnt != del_attr_cnt) { + pav->pwd_reset = true; + ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module), GUID_DRS_FORCE_CHANGE_PASSWORD, SEC_ADS_CONTROL_ACCESS, sid); + goto checked; } - else if (add_attr_cnt == 1 && del_attr_cnt == 1) { + + if (add_val_cnt == 1 && del_val_cnt == 1) { + pav->pwd_reset = false; + ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module), GUID_DRS_USER_CHANGE_PASSWORD, SEC_ADS_CONTROL_ACCESS, @@ -1030,17 +1105,53 @@ static int acl_check_password_rights(TALLOC_CTX *mem_ctx, if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) { ret = LDB_ERR_CONSTRAINT_VIOLATION; } + goto checked; + } + + if (add_val_cnt == 1 && del_val_cnt == 0) { + pav->pwd_reset = true; + + ret = acl_check_extended_right(tmp_ctx, sd, acl_user_token(module), + GUID_DRS_FORCE_CHANGE_PASSWORD, + SEC_ADS_CONTROL_ACCESS, + sid); + /* Very strange, but we get constraint violation in this case */ + if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) { + ret = LDB_ERR_CONSTRAINT_VIOLATION; + } + goto checked; } + + /* + * Everything else is handled by the password_hash module where it will + * fail, but with the correct error code when the module is again + * checking the attributes. As the change request will lack the + * DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID control, we can be sure that + * any modification attempt that went this way will be rejected. + */ + + talloc_free(tmp_ctx); + return LDB_SUCCESS; + +checked: if (ret != LDB_SUCCESS) { dsdb_acl_debug(sd, acl_user_token(module), req->op.mod.message->dn, true, 10); + talloc_free(tmp_ctx); + return ret; } - talloc_free(tmp_ctx); - return ret; -} + ret = ldb_request_add_control(req, + DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID, false, pav); + if (ret != LDB_SUCCESS) { + ldb_debug(ldb_module_get_ctx(module), LDB_DEBUG_ERROR, + "Unable to register ACL validation control!\n"); + return ret; + } + return LDB_SUCCESS; +} static int acl_modify(struct ldb_module *module, struct ldb_request *req) { @@ -1055,6 +1166,7 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req) struct ldb_control *as_system; struct ldb_control *is_undelete; bool userPassword; + bool password_rights_checked = false; TALLOC_CTX *tmp_ctx; const struct ldb_message *msg = req->op.mod.message; static const char *acl_attrs[] = { @@ -1200,6 +1312,9 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req) } else if (ldb_attr_cmp("unicodePwd", el->name) == 0 || (userPassword && ldb_attr_cmp("userPassword", el->name) == 0) || ldb_attr_cmp("clearTextPassword", el->name) == 0) { + if (password_rights_checked) { + continue; + } ret = acl_check_password_rights(tmp_ctx, module, req, @@ -1210,6 +1325,7 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req) if (ret != LDB_SUCCESS) { goto fail; } + password_rights_checked = true; } else if (ldb_attr_cmp("servicePrincipalName", el->name) == 0) { ret = acl_check_spn(tmp_ctx, module, diff --git a/source4/dsdb/samdb/ldb_modules/password_hash.c b/source4/dsdb/samdb/ldb_modules/password_hash.c index c428ff7..1ddafb3 100644 --- a/source4/dsdb/samdb/ldb_modules/password_hash.c +++ b/source4/dsdb/samdb/ldb_modules/password_hash.c @@ -3512,7 +3512,35 @@ static int setup_io(struct ph_context *ac, /* On "add" we have only "password reset" */ ac->pwd_reset = true; } else if (ac->req->operation == LDB_MODIFY) { - if (io->og.cleartext_utf8 || io->og.cleartext_utf16 + struct ldb_control *pav_ctrl = NULL; + struct dsdb_control_password_acl_validation *pav = NULL; + + pav_ctrl = ldb_request_get_control(ac->req, + DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID); + if (pav_ctrl != NULL) { + pav = talloc_get_type_abort(pav_ctrl->data, + struct dsdb_control_password_acl_validation); + } + + if (pav == NULL && ac->update_password) { + bool ok; + + /* + * If the DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID + * control is missing, we require system access! + */ + ok = dsdb_module_am_system(ac->module); + if (!ok) { + return ldb_module_operr(ac->module); + } + } + + if (pav != NULL) { + /* + * We assume what the acl module has validated. + */ + ac->pwd_reset = pav->pwd_reset; + } else if (io->og.cleartext_utf8 || io->og.cleartext_utf16 || io->og.nt_hash || io->og.lm_hash) { /* If we have an old password specified then for sure it * is a user "password change" */ -- Samba Shared Repository