/**************************************************************************** Do a specific test for an smb password being correct, given a smb_password and the lanman and NT responses. ****************************************************************************/ static NTSTATUS authsam_password_ok(struct auth4_context *auth_context, TALLOC_CTX *mem_ctx, uint16_t acct_flags, const struct samr_Password *lm_pwd, const struct samr_Password *nt_pwd, const struct auth_usersupplied_info *user_info, DATA_BLOB *user_sess_key, DATA_BLOB *lm_sess_key) { NTSTATUS status; switch (user_info->password_state) { case AUTH_PASSWORD_PLAIN: { const struct auth_usersupplied_info *user_info_temp; status = encrypt_user_info(mem_ctx, auth_context, AUTH_PASSWORD_HASH, user_info, &user_info_temp); if (!NT_STATUS_IS_OK(status)) { DEBUG(1, ("Failed to convert plaintext password to password HASH: %s\n", nt_errstr(status))); return status; } user_info = user_info_temp; FALL_THROUGH; } case AUTH_PASSWORD_HASH: *lm_sess_key = data_blob(NULL, 0); *user_sess_key = data_blob(NULL, 0); status = hash_password_check(mem_ctx, lpcfg_lanman_auth(auth_context->lp_ctx), user_info->password.hash.lanman, user_info->password.hash.nt, user_info->mapped.account_name, lm_pwd, nt_pwd); NT_STATUS_NOT_OK_RETURN(status); break; case AUTH_PASSWORD_RESPONSE: status = ntlm_password_check(mem_ctx, lpcfg_lanman_auth(auth_context->lp_ctx), lpcfg_ntlm_auth(auth_context->lp_ctx), user_info->logon_parameters, &auth_context->challenge.data, &user_info->password.response.lanman, &user_info->password.response.nt, user_info->mapped.account_name, user_info->client.account_name, user_info->client.domain_name, lm_pwd, nt_pwd, user_sess_key, lm_sess_key); NT_STATUS_NOT_OK_RETURN(status); break; } return NT_STATUS_OK; }
/** * Start NTLMSSP on the server side * */ NTSTATUS gensec_ntlmssp_server_start(struct gensec_security *gensec_security) { NTSTATUS nt_status; struct ntlmssp_state *ntlmssp_state; struct gensec_ntlmssp_context *gensec_ntlmssp; const char *netbios_name; const char *netbios_domain; const char *dns_name; const char *dns_domain; enum server_role role; role = lpcfg_server_role(gensec_security->settings->lp_ctx); nt_status = gensec_ntlmssp_start(gensec_security); NT_STATUS_NOT_OK_RETURN(nt_status); gensec_ntlmssp = talloc_get_type_abort(gensec_security->private_data, struct gensec_ntlmssp_context); ntlmssp_state = talloc_zero(gensec_ntlmssp, struct ntlmssp_state); if (!ntlmssp_state) { return NT_STATUS_NO_MEMORY; } gensec_ntlmssp->ntlmssp_state = ntlmssp_state; ntlmssp_state->role = NTLMSSP_SERVER; ntlmssp_state->expected_state = NTLMSSP_NEGOTIATE; ntlmssp_state->allow_lm_response = lpcfg_lanman_auth(gensec_security->settings->lp_ctx); if (ntlmssp_state->allow_lm_response && gensec_setting_bool(gensec_security->settings, "ntlmssp_server", "allow_lm_key", false)) { ntlmssp_state->allow_lm_key = true; } ntlmssp_state->force_old_spnego = false; if (gensec_setting_bool(gensec_security->settings, "ntlmssp_server", "force_old_spnego", false)) { /* * For testing Windows 2000 mode */ ntlmssp_state->force_old_spnego = true; } ntlmssp_state->neg_flags = NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_VERSION; if (gensec_setting_bool(gensec_security->settings, "ntlmssp_server", "128bit", true)) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_128; } if (gensec_setting_bool(gensec_security->settings, "ntlmssp_server", "56bit", true)) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_56; } if (gensec_setting_bool(gensec_security->settings, "ntlmssp_server", "keyexchange", true)) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_KEY_EXCH; } if (gensec_setting_bool(gensec_security->settings, "ntlmssp_server", "alwayssign", true)) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; } if (gensec_setting_bool(gensec_security->settings, "ntlmssp_server", "ntlm2", true)) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2; } if (ntlmssp_state->allow_lm_key) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_LM_KEY; } /* * We always allow NTLMSSP_NEGOTIATE_SIGN and NTLMSSP_NEGOTIATE_SEAL. * * These will be removed if the client doesn't want them. */ ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL; if (gensec_security->want_features & GENSEC_FEATURE_SESSION_KEY) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; } if (gensec_security->want_features & GENSEC_FEATURE_SIGN) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; if (gensec_security->want_features & GENSEC_FEATURE_LDAP_STYLE) { /* * We need to handle NTLMSSP_NEGOTIATE_SIGN as * NTLMSSP_NEGOTIATE_SEAL if GENSEC_FEATURE_LDAP_STYLE * is requested. */ ntlmssp_state->force_wrap_seal = true; } } if (gensec_security->want_features & GENSEC_FEATURE_SEAL) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL; } if (role == ROLE_STANDALONE) { ntlmssp_state->server.is_standalone = true; } else { ntlmssp_state->server.is_standalone = false; } if (gensec_security->settings->server_netbios_name) { netbios_name = gensec_security->settings->server_netbios_name; } else { netbios_name = lpcfg_netbios_name(gensec_security->settings->lp_ctx); } if (gensec_security->settings->server_netbios_domain) { netbios_domain = gensec_security->settings->server_netbios_domain; } else { netbios_domain = lpcfg_workgroup(gensec_security->settings->lp_ctx); } if (gensec_security->settings->server_dns_name) { dns_name = gensec_security->settings->server_dns_name; } else { const char *dnsdomain = lpcfg_dnsdomain(gensec_security->settings->lp_ctx); char *lower_netbiosname; lower_netbiosname = strlower_talloc(ntlmssp_state, netbios_name); NT_STATUS_HAVE_NO_MEMORY(lower_netbiosname); /* Find out the DNS host name */ if (dnsdomain && dnsdomain[0] != '\0') { dns_name = talloc_asprintf(ntlmssp_state, "%s.%s", lower_netbiosname, dnsdomain); talloc_free(lower_netbiosname); NT_STATUS_HAVE_NO_MEMORY(dns_name); } else { dns_name = lower_netbiosname; } } if (gensec_security->settings->server_dns_domain) { dns_domain = gensec_security->settings->server_dns_domain; } else { dns_domain = lpcfg_dnsdomain(gensec_security->settings->lp_ctx); } ntlmssp_state->server.netbios_name = talloc_strdup(ntlmssp_state, netbios_name); NT_STATUS_HAVE_NO_MEMORY(ntlmssp_state->server.netbios_name); ntlmssp_state->server.netbios_domain = talloc_strdup(ntlmssp_state, netbios_domain); NT_STATUS_HAVE_NO_MEMORY(ntlmssp_state->server.netbios_domain); ntlmssp_state->server.dns_name = talloc_strdup(ntlmssp_state, dns_name); NT_STATUS_HAVE_NO_MEMORY(ntlmssp_state->server.dns_name); ntlmssp_state->server.dns_domain = talloc_strdup(ntlmssp_state, dns_domain); NT_STATUS_HAVE_NO_MEMORY(ntlmssp_state->server.dns_domain); ntlmssp_state->neg_flags |= ntlmssp_state->required_flags; ntlmssp_state->conf_flags = ntlmssp_state->neg_flags; return NT_STATUS_OK; }
static NTSTATUS local_pw_check_specified(struct loadparm_context *lp_ctx, const char *username, const char *domain, const char *workstation, const DATA_BLOB *challenge, const DATA_BLOB *lm_response, const DATA_BLOB *nt_response, uint32_t flags, DATA_BLOB *lm_session_key, DATA_BLOB *user_session_key, char **error_string, char **unix_name) { NTSTATUS nt_status; struct samr_Password lm_pw, nt_pw; struct samr_Password *lm_pwd, *nt_pwd; TALLOC_CTX *mem_ctx = talloc_init("local_pw_check_specified"); if (!mem_ctx) { nt_status = NT_STATUS_NO_MEMORY; } else { E_md4hash(opt_password, nt_pw.hash); if (E_deshash(opt_password, lm_pw.hash)) { lm_pwd = &lm_pw; } else { lm_pwd = NULL; } nt_pwd = &nt_pw; nt_status = ntlm_password_check(mem_ctx, lpcfg_lanman_auth(lp_ctx), lpcfg_ntlm_auth(lp_ctx), MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT, challenge, lm_response, nt_response, username, username, domain, lm_pwd, nt_pwd, user_session_key, lm_session_key); if (NT_STATUS_IS_OK(nt_status)) { if (unix_name) { if (asprintf(unix_name, "%s%c%s", domain, *lpcfg_winbind_separator(lp_ctx), username) < 0) { nt_status = NT_STATUS_NO_MEMORY; } } } else { DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n", domain, username, workstation, nt_errstr(nt_status))); } talloc_free(mem_ctx); } if (error_string) { *error_string = strdup(nt_errstr(nt_status)); } return nt_status; }
/* samr_OemChangePasswordUser2 */ NTSTATUS dcesrv_samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct samr_OemChangePasswordUser2 *r) { NTSTATUS status; DATA_BLOB new_password, new_unicode_password; char *new_pass; struct samr_CryptPassword *pwbuf = r->in.password; struct ldb_context *sam_ctx; struct ldb_dn *user_dn; int ret; struct ldb_message **res; const char * const attrs[] = { "objectSid", "dBCSPwd", NULL }; struct samr_Password *lm_pwd; DATA_BLOB lm_pwd_blob; uint8_t new_lm_hash[16]; struct samr_Password lm_verifier; size_t unicode_pw_len; if (pwbuf == NULL) { return NT_STATUS_INVALID_PARAMETER; } if (r->in.hash == NULL) { return NT_STATUS_INVALID_PARAMETER; } /* this call can only work with lanman auth */ if (!lpcfg_lanman_auth(dce_call->conn->dce_ctx->lp_ctx)) { return NT_STATUS_WRONG_PASSWORD; } /* Connect to a SAMDB with system privileges for fetching the old pw * hashes. */ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(dce_call->conn->dce_ctx->lp_ctx), 0); if (sam_ctx == NULL) { return NT_STATUS_INVALID_SYSTEM_SERVICE; } /* we need the users dn and the domain dn (derived from the user SID). We also need the current lm password hash in order to decrypt the incoming password */ ret = gendb_search(sam_ctx, mem_ctx, NULL, &res, attrs, "(&(sAMAccountName=%s)(objectclass=user))", r->in.account->string); if (ret != 1) { /* Don't give the game away: (don't allow anonymous users to prove the existance of usernames) */ return NT_STATUS_WRONG_PASSWORD; } user_dn = res[0]->dn; status = samdb_result_passwords(mem_ctx, dce_call->conn->dce_ctx->lp_ctx, res[0], &lm_pwd, NULL); if (!NT_STATUS_IS_OK(status) || !lm_pwd) { return NT_STATUS_WRONG_PASSWORD; } /* decrypt the password we have been given */ lm_pwd_blob = data_blob(lm_pwd->hash, sizeof(lm_pwd->hash)); arcfour_crypt_blob(pwbuf->data, 516, &lm_pwd_blob); data_blob_free(&lm_pwd_blob); if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) { DEBUG(3,("samr: failed to decode password buffer\n")); return NT_STATUS_WRONG_PASSWORD; } if (!convert_string_talloc_convenience(mem_ctx, lpcfg_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx), CH_DOS, CH_UNIX, (const char *)new_password.data, new_password.length, (void **)&new_pass, NULL, false)) { DEBUG(3,("samr: failed to convert incoming password buffer to unix charset\n")); return NT_STATUS_WRONG_PASSWORD; } if (!convert_string_talloc_convenience(mem_ctx, lpcfg_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx), CH_DOS, CH_UTF16, (const char *)new_password.data, new_password.length, (void **)&new_unicode_password.data, &unicode_pw_len, false)) { DEBUG(3,("samr: failed to convert incoming password buffer to UTF16 charset\n")); return NT_STATUS_WRONG_PASSWORD; } new_unicode_password.length = unicode_pw_len; E_deshash(new_pass, new_lm_hash); E_old_pw_hash(new_lm_hash, lm_pwd->hash, lm_verifier.hash); if (memcmp(lm_verifier.hash, r->in.hash->hash, 16) != 0) { return NT_STATUS_WRONG_PASSWORD; } /* Connect to a SAMDB with user privileges for the password change */ sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, dce_call->conn->auth_state.session_info, 0); if (sam_ctx == NULL) { return NT_STATUS_INVALID_SYSTEM_SERVICE; } /* Start transaction */ ret = ldb_transaction_start(sam_ctx); if (ret != LDB_SUCCESS) { DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx))); return NT_STATUS_TRANSACTION_ABORTED; } /* Performs the password modification. We pass the old hashes read out * from the database since they were already checked against the user- * provided ones. */ status = samdb_set_password(sam_ctx, mem_ctx, user_dn, NULL, &new_unicode_password, NULL, NULL, lm_pwd, NULL, /* this is a user password change */ NULL, NULL); if (!NT_STATUS_IS_OK(status)) { ldb_transaction_cancel(sam_ctx); return status; } /* And this confirms it in a transaction commit */ ret = ldb_transaction_commit(sam_ctx); if (ret != LDB_SUCCESS) { DEBUG(1,("Failed to commit transaction to change password on %s: %s\n", ldb_dn_get_linearized(user_dn), ldb_errstring(sam_ctx))); return NT_STATUS_TRANSACTION_ABORTED; } return NT_STATUS_OK; }
/** * Start NTLMSSP on the server side * */ NTSTATUS gensec_ntlmssp_server_start(struct gensec_security *gensec_security) { NTSTATUS nt_status; struct ntlmssp_state *ntlmssp_state; struct gensec_ntlmssp_context *gensec_ntlmssp; nt_status = gensec_ntlmssp_start(gensec_security); NT_STATUS_NOT_OK_RETURN(nt_status); gensec_ntlmssp = talloc_get_type_abort(gensec_security->private_data, struct gensec_ntlmssp_context); ntlmssp_state = gensec_ntlmssp->ntlmssp_state; ntlmssp_state->role = NTLMSSP_SERVER; ntlmssp_state->expected_state = NTLMSSP_NEGOTIATE; ntlmssp_state->allow_lm_key = (lpcfg_lanman_auth(gensec_security->settings->lp_ctx) && gensec_setting_bool(gensec_security->settings, "ntlmssp_server", "allow_lm_key", false)); ntlmssp_state->neg_flags = NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_VERSION; ntlmssp_state->lm_resp = data_blob(NULL, 0); ntlmssp_state->nt_resp = data_blob(NULL, 0); if (gensec_setting_bool(gensec_security->settings, "ntlmssp_server", "128bit", true)) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_128; } if (gensec_setting_bool(gensec_security->settings, "ntlmssp_server", "56bit", true)) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_56; } if (gensec_setting_bool(gensec_security->settings, "ntlmssp_server", "keyexchange", true)) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_KEY_EXCH; } if (gensec_setting_bool(gensec_security->settings, "ntlmssp_server", "alwayssign", true)) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; } if (gensec_setting_bool(gensec_security->settings, "ntlmssp_server", "ntlm2", true)) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_NTLM2; } if (gensec_security->want_features & GENSEC_FEATURE_SIGN) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SIGN; } if (gensec_security->want_features & GENSEC_FEATURE_SEAL) { ntlmssp_state->neg_flags |= NTLMSSP_NEGOTIATE_SEAL; } ntlmssp_state->get_challenge = auth_ntlmssp_get_challenge; ntlmssp_state->may_set_challenge = auth_ntlmssp_may_set_challenge; ntlmssp_state->set_challenge = auth_ntlmssp_set_challenge; ntlmssp_state->check_password = auth_ntlmssp_check_password; if (lpcfg_server_role(gensec_security->settings->lp_ctx) == ROLE_STANDALONE) { ntlmssp_state->server.is_standalone = true; } else { ntlmssp_state->server.is_standalone = false; } ntlmssp_state->server.netbios_name = lpcfg_netbios_name(gensec_security->settings->lp_ctx); ntlmssp_state->server.netbios_domain = lpcfg_workgroup(gensec_security->settings->lp_ctx); { const char *dnsdomain = lpcfg_dnsdomain(gensec_security->settings->lp_ctx); char *dnsname, *lower_netbiosname; lower_netbiosname = strlower_talloc(ntlmssp_state, ntlmssp_state->server.netbios_name); /* Find out the DNS host name */ if (dnsdomain && dnsdomain[0] != '\0') { dnsname = talloc_asprintf(ntlmssp_state, "%s.%s", lower_netbiosname, dnsdomain); talloc_free(lower_netbiosname); ntlmssp_state->server.dns_name = dnsname; } else { ntlmssp_state->server.dns_name = lower_netbiosname; } NT_STATUS_HAVE_NO_MEMORY(ntlmssp_state->server.dns_name); ntlmssp_state->server.dns_domain = talloc_strdup(ntlmssp_state, lpcfg_dnsdomain(gensec_security->settings->lp_ctx)); NT_STATUS_HAVE_NO_MEMORY(ntlmssp_state->server.dns_domain); } return NT_STATUS_OK; }