2 Unix SMB/CIFS implementation.
4 samr server password set/change handling
6 Copyright (C) Andrew Tridgell 2004
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "rpc_server/dcerpc_server.h"
25 #include "rpc_server/samr/dcesrv_samr.h"
26 #include "system/time.h"
27 #include "../lib/crypto/crypto.h"
28 #include "dsdb/samdb/samdb.h"
29 #include "auth/auth.h"
30 #include "libcli/auth/libcli_auth.h"
31 #include "../lib/util/util_ldb.h"
34 samr_ChangePasswordUser
36 NTSTATUS dcesrv_samr_ChangePasswordUser(struct dcesrv_call_state *dce_call,
38 struct samr_ChangePasswordUser *r)
40 struct dcesrv_handle *h;
41 struct samr_account_state *a_state;
42 struct ldb_context *sam_ctx;
43 struct ldb_message **res;
45 struct samr_Password new_lmPwdHash, new_ntPwdHash, checkHash;
46 struct samr_Password *lm_pwd, *nt_pwd;
47 NTSTATUS status = NT_STATUS_OK;
48 const char * const attrs[] = { "dBCSPwd", "unicodePwd" , NULL };
50 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
54 /* basic sanity checking on parameters. Do this before any database ops */
55 if (!r->in.lm_present || !r->in.nt_present ||
56 !r->in.old_lm_crypted || !r->in.new_lm_crypted ||
57 !r->in.old_nt_crypted || !r->in.new_nt_crypted) {
58 /* we should really handle a change with lm not
60 return NT_STATUS_INVALID_PARAMETER_MIX;
63 /* To change a password we need to open as system */
64 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));
65 if (sam_ctx == NULL) {
66 return NT_STATUS_INVALID_SYSTEM_SERVICE;
69 ret = ldb_transaction_start(sam_ctx);
70 if (ret != LDB_SUCCESS) {
71 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
72 return NT_STATUS_TRANSACTION_ABORTED;
75 /* fetch the old hashes */
76 ret = gendb_search_dn(sam_ctx, mem_ctx,
77 a_state->account_dn, &res, attrs);
79 ldb_transaction_cancel(sam_ctx);
80 return NT_STATUS_WRONG_PASSWORD;
83 status = samdb_result_passwords(mem_ctx,
84 dce_call->conn->dce_ctx->lp_ctx,
85 res[0], &lm_pwd, &nt_pwd);
86 if (!NT_STATUS_IS_OK(status) || !nt_pwd) {
87 ldb_transaction_cancel(sam_ctx);
88 return NT_STATUS_WRONG_PASSWORD;
91 /* decrypt and check the new lm hash */
93 D_P16(lm_pwd->hash, r->in.new_lm_crypted->hash, new_lmPwdHash.hash);
94 D_P16(new_lmPwdHash.hash, r->in.old_lm_crypted->hash, checkHash.hash);
95 if (memcmp(checkHash.hash, lm_pwd, 16) != 0) {
96 ldb_transaction_cancel(sam_ctx);
97 return NT_STATUS_WRONG_PASSWORD;
101 /* decrypt and check the new nt hash */
102 D_P16(nt_pwd->hash, r->in.new_nt_crypted->hash, new_ntPwdHash.hash);
103 D_P16(new_ntPwdHash.hash, r->in.old_nt_crypted->hash, checkHash.hash);
104 if (memcmp(checkHash.hash, nt_pwd, 16) != 0) {
105 ldb_transaction_cancel(sam_ctx);
106 return NT_STATUS_WRONG_PASSWORD;
109 /* The NT Cross is not required by Win2k3 R2, but if present
110 check the nt cross hash */
111 if (r->in.cross1_present && r->in.nt_cross && lm_pwd) {
112 D_P16(lm_pwd->hash, r->in.nt_cross->hash, checkHash.hash);
113 if (memcmp(checkHash.hash, new_ntPwdHash.hash, 16) != 0) {
114 ldb_transaction_cancel(sam_ctx);
115 return NT_STATUS_WRONG_PASSWORD;
119 /* The LM Cross is not required by Win2k3 R2, but if present
120 check the lm cross hash */
121 if (r->in.cross2_present && r->in.lm_cross && lm_pwd) {
122 D_P16(nt_pwd->hash, r->in.lm_cross->hash, checkHash.hash);
123 if (memcmp(checkHash.hash, new_lmPwdHash.hash, 16) != 0) {
124 ldb_transaction_cancel(sam_ctx);
125 return NT_STATUS_WRONG_PASSWORD;
129 /* setup password modify mods on the user DN specified. This may fail
130 * due to password policies. */
131 status = samdb_set_password(sam_ctx, mem_ctx,
133 a_state->domain_state->domain_dn,
134 NULL, &new_lmPwdHash, &new_ntPwdHash,
135 true, /* this is a user password change */
138 if (!NT_STATUS_IS_OK(status)) {
139 ldb_transaction_cancel(sam_ctx);
143 /* And this confirms it in a transaction commit */
144 ret = ldb_transaction_commit(sam_ctx);
145 if (ret != LDB_SUCCESS) {
146 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
147 ldb_dn_get_linearized(a_state->account_dn),
148 ldb_errstring(sam_ctx)));
149 return NT_STATUS_TRANSACTION_ABORTED;
156 samr_OemChangePasswordUser2
158 NTSTATUS dcesrv_samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call,
160 struct samr_OemChangePasswordUser2 *r)
163 DATA_BLOB new_password, new_unicode_password;
165 struct samr_CryptPassword *pwbuf = r->in.password;
166 struct ldb_context *sam_ctx;
167 struct ldb_dn *user_dn;
169 struct ldb_message **res;
170 const char * const attrs[] = { "objectSid", "dBCSPwd", NULL };
171 struct samr_Password *lm_pwd;
172 DATA_BLOB lm_pwd_blob;
173 uint8_t new_lm_hash[16];
174 struct samr_Password lm_verifier;
175 size_t unicode_pw_len;
178 return NT_STATUS_INVALID_PARAMETER;
181 if (r->in.hash == NULL) {
182 return NT_STATUS_INVALID_PARAMETER;
185 /* this call can only work with lanman auth */
186 if (!lpcfg_lanman_auth(dce_call->conn->dce_ctx->lp_ctx)) {
187 return NT_STATUS_WRONG_PASSWORD;
190 /* To change a password we need to open as system */
191 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));
192 if (sam_ctx == NULL) {
193 return NT_STATUS_INVALID_SYSTEM_SERVICE;
196 ret = ldb_transaction_start(sam_ctx);
197 if (ret != LDB_SUCCESS) {
198 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
199 return NT_STATUS_TRANSACTION_ABORTED;
202 /* we need the users dn and the domain dn (derived from the
203 user SID). We also need the current lm password hash in
204 order to decrypt the incoming password */
205 ret = gendb_search(sam_ctx,
206 mem_ctx, NULL, &res, attrs,
207 "(&(sAMAccountName=%s)(objectclass=user))",
208 r->in.account->string);
210 ldb_transaction_cancel(sam_ctx);
211 /* Don't give the game away: (don't allow anonymous users to prove the existance of usernames) */
212 return NT_STATUS_WRONG_PASSWORD;
215 user_dn = res[0]->dn;
217 status = samdb_result_passwords(mem_ctx, dce_call->conn->dce_ctx->lp_ctx,
218 res[0], &lm_pwd, NULL);
219 if (!NT_STATUS_IS_OK(status) || !lm_pwd) {
220 ldb_transaction_cancel(sam_ctx);
221 return NT_STATUS_WRONG_PASSWORD;
224 /* decrypt the password we have been given */
225 lm_pwd_blob = data_blob(lm_pwd->hash, sizeof(lm_pwd->hash));
226 arcfour_crypt_blob(pwbuf->data, 516, &lm_pwd_blob);
227 data_blob_free(&lm_pwd_blob);
229 if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
230 ldb_transaction_cancel(sam_ctx);
231 DEBUG(3,("samr: failed to decode password buffer\n"));
232 return NT_STATUS_WRONG_PASSWORD;
235 if (!convert_string_talloc_convenience(mem_ctx, lpcfg_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx),
237 (const char *)new_password.data,
239 (void **)&new_pass, NULL, false)) {
240 DEBUG(3,("samr: failed to convert incoming password buffer to unix charset\n"));
241 ldb_transaction_cancel(sam_ctx);
242 return NT_STATUS_WRONG_PASSWORD;
245 if (!convert_string_talloc_convenience(mem_ctx, lpcfg_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx),
247 (const char *)new_password.data,
249 (void **)&new_unicode_password.data, &unicode_pw_len, false)) {
250 DEBUG(3,("samr: failed to convert incoming password buffer to UTF16 charset\n"));
251 ldb_transaction_cancel(sam_ctx);
252 return NT_STATUS_WRONG_PASSWORD;
254 new_unicode_password.length = unicode_pw_len;
256 E_deshash(new_pass, new_lm_hash);
257 E_old_pw_hash(new_lm_hash, lm_pwd->hash, lm_verifier.hash);
258 if (memcmp(lm_verifier.hash, r->in.hash->hash, 16) != 0) {
259 ldb_transaction_cancel(sam_ctx);
260 return NT_STATUS_WRONG_PASSWORD;
263 /* set the password on the user DN specified. This may fail
264 * due to password policies */
265 status = samdb_set_password(sam_ctx, mem_ctx,
267 &new_unicode_password,
269 true, /* this is a user password change */
272 if (!NT_STATUS_IS_OK(status)) {
273 ldb_transaction_cancel(sam_ctx);
277 /* And this confirms it in a transaction commit */
278 ret = ldb_transaction_commit(sam_ctx);
279 if (ret != LDB_SUCCESS) {
280 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
281 ldb_dn_get_linearized(user_dn),
282 ldb_errstring(sam_ctx)));
283 return NT_STATUS_TRANSACTION_ABORTED;
291 samr_ChangePasswordUser3
293 NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call,
295 struct samr_ChangePasswordUser3 *r)
298 DATA_BLOB new_password;
299 struct ldb_context *sam_ctx = NULL;
300 struct ldb_dn *user_dn;
302 struct ldb_message **res;
303 const char * const attrs[] = { "unicodePwd", "dBCSPwd", NULL };
304 struct samr_Password *nt_pwd, *lm_pwd;
305 DATA_BLOB nt_pwd_blob;
306 struct samr_DomInfo1 *dominfo = NULL;
307 struct userPwdChangeFailureInformation *reject = NULL;
308 enum samPwdChangeReason reason = SAM_PWD_CHANGE_NO_ERROR;
309 uint8_t new_nt_hash[16], new_lm_hash[16];
310 struct samr_Password nt_verifier, lm_verifier;
312 *r->out.dominfo = NULL;
313 *r->out.reject = NULL;
315 if (r->in.nt_password == NULL ||
316 r->in.nt_verifier == NULL) {
317 return NT_STATUS_INVALID_PARAMETER;
320 /* To change a password we need to open as system */
321 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));
322 if (sam_ctx == NULL) {
323 return NT_STATUS_INVALID_SYSTEM_SERVICE;
326 ret = ldb_transaction_start(sam_ctx);
327 if (ret != LDB_SUCCESS) {
328 talloc_free(sam_ctx);
329 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
330 return NT_STATUS_TRANSACTION_ABORTED;
333 /* we need the users dn and the domain dn (derived from the
334 user SID). We also need the current lm and nt password hashes
335 in order to decrypt the incoming passwords */
336 ret = gendb_search(sam_ctx,
337 mem_ctx, NULL, &res, attrs,
338 "(&(sAMAccountName=%s)(objectclass=user))",
339 r->in.account->string);
341 /* Don't give the game away: (don't allow anonymous users to prove the existance of usernames) */
342 status = NT_STATUS_WRONG_PASSWORD;
346 user_dn = res[0]->dn;
348 status = samdb_result_passwords(mem_ctx, dce_call->conn->dce_ctx->lp_ctx,
349 res[0], &lm_pwd, &nt_pwd);
350 if (!NT_STATUS_IS_OK(status) ) {
355 status = NT_STATUS_WRONG_PASSWORD;
359 /* decrypt the password we have been given */
360 nt_pwd_blob = data_blob(nt_pwd->hash, sizeof(nt_pwd->hash));
361 arcfour_crypt_blob(r->in.nt_password->data, 516, &nt_pwd_blob);
362 data_blob_free(&nt_pwd_blob);
364 if (!extract_pw_from_buffer(mem_ctx, r->in.nt_password->data, &new_password)) {
365 ldb_transaction_cancel(sam_ctx);
366 DEBUG(3,("samr: failed to decode password buffer\n"));
367 return NT_STATUS_WRONG_PASSWORD;
370 if (r->in.nt_verifier == NULL) {
371 status = NT_STATUS_WRONG_PASSWORD;
375 /* check NT verifier */
376 mdfour(new_nt_hash, new_password.data, new_password.length);
378 E_old_pw_hash(new_nt_hash, nt_pwd->hash, nt_verifier.hash);
379 if (memcmp(nt_verifier.hash, r->in.nt_verifier->hash, 16) != 0) {
380 status = NT_STATUS_WRONG_PASSWORD;
384 /* check LM verifier (really not needed as we just checked the
385 * much stronger NT hash, but the RPC-SAMR test checks for
387 if (lm_pwd && r->in.lm_verifier != NULL) {
389 if (!convert_string_talloc_convenience(mem_ctx, lpcfg_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx),
391 (const char *)new_password.data,
393 (void **)&new_pass, NULL, false)) {
394 E_deshash(new_pass, new_lm_hash);
395 E_old_pw_hash(new_nt_hash, lm_pwd->hash, lm_verifier.hash);
396 if (memcmp(lm_verifier.hash, r->in.lm_verifier->hash, 16) != 0) {
397 status = NT_STATUS_WRONG_PASSWORD;
403 /* set the password on the user DN specified. This may fail
404 * due to password policies */
405 status = samdb_set_password(sam_ctx, mem_ctx,
409 true, /* this is a user password change */
413 if (!NT_STATUS_IS_OK(status)) {
417 /* And this confirms it in a transaction commit */
418 ret = ldb_transaction_commit(sam_ctx);
419 if (ret != LDB_SUCCESS) {
420 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
421 ldb_dn_get_linearized(user_dn),
422 ldb_errstring(sam_ctx)));
423 status = NT_STATUS_TRANSACTION_ABORTED;
430 ldb_transaction_cancel(sam_ctx);
432 reject = talloc_zero(mem_ctx, struct userPwdChangeFailureInformation);
433 if (reject != NULL) {
434 reject->extendedFailureReason = reason;
436 *r->out.reject = reject;
439 *r->out.dominfo = dominfo;
446 samr_ChangePasswordUser2
448 easy - just a subset of samr_ChangePasswordUser3
450 NTSTATUS dcesrv_samr_ChangePasswordUser2(struct dcesrv_call_state *dce_call,
452 struct samr_ChangePasswordUser2 *r)
454 struct samr_ChangePasswordUser3 r2;
455 struct samr_DomInfo1 *dominfo = NULL;
456 struct userPwdChangeFailureInformation *reject = NULL;
458 r2.in.server = r->in.server;
459 r2.in.account = r->in.account;
460 r2.in.nt_password = r->in.nt_password;
461 r2.in.nt_verifier = r->in.nt_verifier;
462 r2.in.lm_change = r->in.lm_change;
463 r2.in.lm_password = r->in.lm_password;
464 r2.in.lm_verifier = r->in.lm_verifier;
465 r2.in.password3 = NULL;
466 r2.out.dominfo = &dominfo;
467 r2.out.reject = &reject;
469 return dcesrv_samr_ChangePasswordUser3(dce_call, mem_ctx, &r2);
474 set password via a samr_CryptPassword buffer
476 NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call,
477 struct ldb_context *sam_ctx,
478 struct ldb_dn *account_dn, struct ldb_dn *domain_dn,
480 struct samr_CryptPassword *pwbuf)
483 DATA_BLOB new_password;
484 DATA_BLOB session_key = data_blob(NULL, 0);
486 nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
487 if (!NT_STATUS_IS_OK(nt_status)) {
491 arcfour_crypt_blob(pwbuf->data, 516, &session_key);
493 if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
494 DEBUG(3,("samr: failed to decode password buffer\n"));
495 return NT_STATUS_WRONG_PASSWORD;
498 /* set the password - samdb needs to know both the domain and user DNs,
499 so the domain password policy can be used */
500 return samdb_set_password(sam_ctx, mem_ctx,
501 account_dn, domain_dn,
504 false, /* This is a password set, not change */
510 set password via a samr_CryptPasswordEx buffer
512 NTSTATUS samr_set_password_ex(struct dcesrv_call_state *dce_call,
513 struct ldb_context *sam_ctx,
514 struct ldb_dn *account_dn,
515 struct ldb_dn *domain_dn,
517 struct samr_CryptPasswordEx *pwbuf)
520 DATA_BLOB new_password;
521 DATA_BLOB co_session_key;
522 DATA_BLOB session_key = data_blob(NULL, 0);
523 struct MD5Context ctx;
525 nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
526 if (!NT_STATUS_IS_OK(nt_status)) {
530 co_session_key = data_blob_talloc(mem_ctx, NULL, 16);
531 if (!co_session_key.data) {
532 return NT_STATUS_NO_MEMORY;
536 MD5Update(&ctx, &pwbuf->data[516], 16);
537 MD5Update(&ctx, session_key.data, session_key.length);
538 MD5Final(co_session_key.data, &ctx);
540 arcfour_crypt_blob(pwbuf->data, 516, &co_session_key);
542 if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
543 DEBUG(3,("samr: failed to decode password buffer\n"));
544 return NT_STATUS_WRONG_PASSWORD;
547 /* set the password - samdb needs to know both the domain and user DNs,
548 so the domain password policy can be used */
549 return samdb_set_password(sam_ctx, mem_ctx,
550 account_dn, domain_dn,
553 false, /* This is a password set, not change */
558 set password via encrypted NT and LM hash buffers
560 NTSTATUS samr_set_password_buffers(struct dcesrv_call_state *dce_call,
561 struct ldb_context *sam_ctx,
562 struct ldb_dn *account_dn,
563 struct ldb_dn *domain_dn,
565 const uint8_t *lm_pwd_hash,
566 const uint8_t *nt_pwd_hash)
568 struct samr_Password *d_lm_pwd_hash = NULL, *d_nt_pwd_hash = NULL;
569 DATA_BLOB session_key = data_blob(NULL, 0);
571 NTSTATUS nt_status = NT_STATUS_OK;
573 nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
574 if (!NT_STATUS_IS_OK(nt_status)) {
578 if (lm_pwd_hash != NULL) {
579 in = data_blob_const(lm_pwd_hash, 16);
580 out = data_blob_talloc_zero(mem_ctx, 16);
582 sess_crypt_blob(&out, &in, &session_key, false);
584 d_lm_pwd_hash = (struct samr_Password *) out.data;
586 if (nt_pwd_hash != NULL) {
587 in = data_blob_const(nt_pwd_hash, 16);
588 out = data_blob_talloc_zero(mem_ctx, 16);
590 sess_crypt_blob(&out, &in, &session_key, false);
592 d_nt_pwd_hash = (struct samr_Password *) out.data;
595 if ((d_lm_pwd_hash != NULL) || (d_nt_pwd_hash != NULL)) {
596 nt_status = samdb_set_password(sam_ctx, mem_ctx, account_dn,
598 d_lm_pwd_hash, d_nt_pwd_hash,
599 false, /* this is a password set */