NTSTATUS libnet_SamDump(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_SamDump *r) { NTSTATUS nt_status; struct libnet_SamSync r2; struct samdump_state *samdump_state = talloc(mem_ctx, struct samdump_state); struct samdump_trusted_domain *t; struct samdump_secret *s; if (!samdump_state) { return NT_STATUS_NO_MEMORY; } samdump_state->secrets = NULL; samdump_state->trusted_domains = NULL; r2.out.error_string = NULL; r2.in.binding_string = r->in.binding_string; r2.in.init_fn = NULL; r2.in.delta_fn = libnet_samdump_fn; r2.in.fn_ctx = samdump_state; r2.in.machine_account = r->in.machine_account; nt_status = libnet_SamSync_netlogon(ctx, samdump_state, &r2); r->out.error_string = r2.out.error_string; talloc_steal(mem_ctx, r->out.error_string); if (!NT_STATUS_IS_OK(nt_status)) { talloc_free(samdump_state); return nt_status; } printf("Trusted domains, sids and secrets:\n"); for (t=samdump_state->trusted_domains; t; t=t->next) { char *secret_name = talloc_asprintf(mem_ctx, "G$$%s", t->name); for (s=samdump_state->secrets; s; s=s->next) { size_t converted_size = 0; char *secret_string; if (strcasecmp_m(s->name, secret_name) != 0) { continue; } if (!convert_string_talloc_handle(mem_ctx, lpcfg_iconv_handle(ctx->lp_ctx), CH_UTF16, CH_UNIX, s->secret.data, s->secret.length, (void **)&secret_string, &converted_size)) { r->out.error_string = talloc_asprintf(mem_ctx, "Could not convert secret for domain %s to a string", t->name); talloc_free(samdump_state); return NT_STATUS_INVALID_PARAMETER; } printf("%s\t%s\t%s\n", t->name, dom_sid_string(mem_ctx, t->sid), secret_string); } } talloc_free(samdump_state); 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; size_t converted_size = 0; 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_handle(mem_ctx, lpcfg_iconv_handle(dce_call->conn->dce_ctx->lp_ctx), CH_DOS, CH_UNIX, (const char *)new_password.data, new_password.length, (void **)&new_pass, &converted_size)) { DEBUG(3,("samr: failed to convert incoming password buffer to unix charset\n")); return NT_STATUS_WRONG_PASSWORD; } if (!convert_string_talloc_handle(mem_ctx, lpcfg_iconv_handle(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)) { 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; }
static krb5_error_code kpasswd_set_password(struct kdc_server *kdc, TALLOC_CTX *mem_ctx, struct auth_session_info *session_info, DATA_BLOB *decoded_data, DATA_BLOB *kpasswd_reply, const char **error_string) { krb5_context context = kdc->smb_krb5_context->krb5_context; krb5_data k_dec_data; krb5_data *k_clear_data; krb5_principal target_principal; krb5_error_code code; DATA_BLOB password; char *target_realm = NULL; char *target_name = NULL; char *target_principal_string = NULL; bool is_service_principal = false; bool ok; size_t num_components; enum samPwdChangeReason reject_reason = SAM_PWD_CHANGE_NO_ERROR; struct samr_DomInfo1 *dominfo = NULL; NTSTATUS status; k_dec_data.length = decoded_data->length; k_dec_data.data = (char *)decoded_data->data; code = decode_krb5_setpw_req(&k_dec_data, &k_clear_data, &target_principal); if (code != 0) { DBG_WARNING("decode_krb5_setpw_req failed: %s\n", error_message(code)); ok = kpasswd_make_error_reply(mem_ctx, KRB5_KPASSWD_MALFORMED, "Failed to decode packet", kpasswd_reply); if (!ok) { *error_string = "Failed to create reply"; return KRB5_KPASSWD_HARDERROR; } return 0; } ok = convert_string_talloc_handle(mem_ctx, lpcfg_iconv_handle(kdc->task->lp_ctx), CH_UTF8, CH_UTF16, (const char *)k_clear_data->data, k_clear_data->length, (void **)&password.data, &password.length); krb5_free_data(context, k_clear_data); if (!ok) { DBG_WARNING("String conversion failed\n"); *error_string = "String conversion failed"; return KRB5_KPASSWD_HARDERROR; } target_realm = smb_krb5_principal_get_realm(context, target_principal); code = krb5_unparse_name_flags(context, target_principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &target_name); if (code != 0) { DBG_WARNING("Failed to parse principal\n"); *error_string = "String conversion failed"; return KRB5_KPASSWD_HARDERROR; } if ((target_name != NULL && target_realm == NULL) || (target_name == NULL && target_realm != NULL)) { krb5_free_principal(context, target_principal); SAFE_FREE(target_realm); SAFE_FREE(target_name); ok = kpasswd_make_error_reply(mem_ctx, KRB5_KPASSWD_MALFORMED, "Realm and principal must be " "both present, or neither " "present", kpasswd_reply); if (!ok) { *error_string = "Failed to create reply"; return KRB5_KPASSWD_HARDERROR; } return 0; } if (target_name != NULL && target_realm != NULL) { SAFE_FREE(target_realm); SAFE_FREE(target_name); } else { krb5_free_principal(context, target_principal); SAFE_FREE(target_realm); SAFE_FREE(target_name); return kpasswd_change_password(kdc, mem_ctx, session_info, &password, kpasswd_reply, error_string); } num_components = krb5_princ_size(context, target_principal); if (num_components >= 2) { is_service_principal = true; code = krb5_unparse_name_flags(context, target_principal, KRB5_PRINCIPAL_UNPARSE_SHORT, &target_principal_string); } else { code = krb5_unparse_name(context, target_principal, &target_principal_string); } krb5_free_principal(context, target_principal); if (code != 0) { ok = kpasswd_make_error_reply(mem_ctx, KRB5_KPASSWD_MALFORMED, "Failed to parse principal", kpasswd_reply); if (!ok) { *error_string = "Failed to create reply"; return KRB5_KPASSWD_HARDERROR; } } status = kpasswd_samdb_set_password(mem_ctx, kdc->task->event_ctx, kdc->task->lp_ctx, session_info, is_service_principal, target_principal_string, &password, &reject_reason, &dominfo); if (!NT_STATUS_IS_OK(status)) { DBG_ERR("kpasswd_samdb_set_password failed - %s\n", nt_errstr(status)); } ok = kpasswd_make_pwchange_reply(mem_ctx, status, reject_reason, dominfo, kpasswd_reply); if (!ok) { *error_string = "Failed to create reply"; return KRB5_KPASSWD_HARDERROR; } return 0; }
/* samr_ChangePasswordUser3 */ NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct samr_ChangePasswordUser3 *r) { NTSTATUS status; DATA_BLOB new_password; struct ldb_context *sam_ctx = NULL; struct ldb_dn *user_dn; int ret; struct ldb_message **res; const char * const attrs[] = { "unicodePwd", "dBCSPwd", NULL }; struct samr_Password *nt_pwd, *lm_pwd; DATA_BLOB nt_pwd_blob; struct samr_DomInfo1 *dominfo = NULL; struct userPwdChangeFailureInformation *reject = NULL; enum samPwdChangeReason reason = SAM_PWD_CHANGE_NO_ERROR; uint8_t new_nt_hash[16], new_lm_hash[16]; struct samr_Password nt_verifier, lm_verifier; *r->out.dominfo = NULL; *r->out.reject = NULL; if (r->in.nt_password == NULL || r->in.nt_verifier == NULL) { return NT_STATUS_INVALID_PARAMETER; } /* 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 and nt password hashes in order to decrypt the incoming passwords */ 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) */ status = NT_STATUS_WRONG_PASSWORD; goto failed; } user_dn = res[0]->dn; status = samdb_result_passwords(mem_ctx, dce_call->conn->dce_ctx->lp_ctx, res[0], &lm_pwd, &nt_pwd); if (!NT_STATUS_IS_OK(status) ) { goto failed; } if (!nt_pwd) { status = NT_STATUS_WRONG_PASSWORD; goto failed; } /* decrypt the password we have been given */ nt_pwd_blob = data_blob(nt_pwd->hash, sizeof(nt_pwd->hash)); arcfour_crypt_blob(r->in.nt_password->data, 516, &nt_pwd_blob); data_blob_free(&nt_pwd_blob); if (!extract_pw_from_buffer(mem_ctx, r->in.nt_password->data, &new_password)) { DEBUG(3,("samr: failed to decode password buffer\n")); status = NT_STATUS_WRONG_PASSWORD; goto failed; } if (r->in.nt_verifier == NULL) { status = NT_STATUS_WRONG_PASSWORD; goto failed; } /* check NT verifier */ mdfour(new_nt_hash, new_password.data, new_password.length); E_old_pw_hash(new_nt_hash, nt_pwd->hash, nt_verifier.hash); if (memcmp(nt_verifier.hash, r->in.nt_verifier->hash, 16) != 0) { status = NT_STATUS_WRONG_PASSWORD; goto failed; } /* check LM verifier (really not needed as we just checked the * much stronger NT hash, but the RPC-SAMR test checks for * this) */ if (lm_pwd && r->in.lm_verifier != NULL) { char *new_pass; size_t converted_size = 0; if (!convert_string_talloc_handle(mem_ctx, lpcfg_iconv_handle(dce_call->conn->dce_ctx->lp_ctx), CH_UTF16, CH_UNIX, (const char *)new_password.data, new_password.length, (void **)&new_pass, &converted_size)) { E_deshash(new_pass, new_lm_hash); E_old_pw_hash(new_nt_hash, lm_pwd->hash, lm_verifier.hash); if (memcmp(lm_verifier.hash, r->in.lm_verifier->hash, 16) != 0) { status = NT_STATUS_WRONG_PASSWORD; goto failed; } } } /* 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; } 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_password, NULL, NULL, lm_pwd, nt_pwd, /* this is a user password change */ &reason, &dominfo); if (!NT_STATUS_IS_OK(status)) { ldb_transaction_cancel(sam_ctx); goto failed; } /* 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))); status = NT_STATUS_TRANSACTION_ABORTED; goto failed; } return NT_STATUS_OK; failed: reject = talloc_zero(mem_ctx, struct userPwdChangeFailureInformation); if (reject != NULL) { reject->extendedFailureReason = reason; *r->out.reject = reject; } *r->out.dominfo = dominfo; return status; }
krb5_error_code kpasswd_handle_request(struct kdc_server *kdc, TALLOC_CTX *mem_ctx, struct gensec_security *gensec_security, uint16_t verno, DATA_BLOB *decoded_data, DATA_BLOB *kpasswd_reply, const char **error_string) { struct auth_session_info *session_info; NTSTATUS status; status = gensec_session_info(gensec_security, mem_ctx, &session_info); if (!NT_STATUS_IS_OK(status)) { *error_string = talloc_asprintf(mem_ctx, "gensec_session_info failed - " "%s", nt_errstr(status)); return KRB5_KPASSWD_HARDERROR; } switch(verno) { case 1: { DATA_BLOB password; bool ok; ok = convert_string_talloc_handle(mem_ctx, lpcfg_iconv_handle(kdc->task->lp_ctx), CH_UTF8, CH_UTF16, (const char *)decoded_data->data, decoded_data->length, (void **)&password.data, &password.length); if (!ok) { *error_string = "String conversion failed!"; DBG_WARNING("%s\n", *error_string); return KRB5_KPASSWD_HARDERROR; } return kpasswd_change_password(kdc, mem_ctx, session_info, &password, kpasswd_reply, error_string); } case RFC3244_VERSION: { return kpasswd_set_password(kdc, mem_ctx, session_info, decoded_data, kpasswd_reply, error_string); } default: return KRB5_KPASSWD_BAD_VERSION; } return 0; }