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/common/common.h"
26 #include "rpc_server/samr/dcesrv_samr.h"
27 #include "system/time.h"
28 #include "../lib/crypto/crypto.h"
29 #include "dsdb/common/flags.h"
30 #include "libcli/ldap/ldap.h"
31 #include "dsdb/samdb/samdb.h"
32 #include "auth/auth.h"
33 #include "rpc_server/samr/proto.h"
34 #include "libcli/auth/libcli_auth.h"
35 #include "../lib/util/util_ldb.h"
36 #include "param/param.h"
39 samr_ChangePasswordUser
41 NTSTATUS dcesrv_samr_ChangePasswordUser(struct dcesrv_call_state *dce_call,
43 struct samr_ChangePasswordUser *r)
45 struct dcesrv_handle *h;
46 struct samr_account_state *a_state;
47 struct ldb_context *sam_ctx;
48 struct ldb_message **res, *msg;
50 struct samr_Password new_lmPwdHash, new_ntPwdHash, checkHash;
51 struct samr_Password *lm_pwd, *nt_pwd;
52 NTSTATUS status = NT_STATUS_OK;
53 const char * const attrs[] = { "dBCSPwd", "unicodePwd" , NULL };
55 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
59 /* basic sanity checking on parameters. Do this before any database ops */
60 if (!r->in.lm_present || !r->in.nt_present ||
61 !r->in.old_lm_crypted || !r->in.new_lm_crypted ||
62 !r->in.old_nt_crypted || !r->in.new_nt_crypted) {
63 /* we should really handle a change with lm not
65 return NT_STATUS_INVALID_PARAMETER_MIX;
68 /* To change a password we need to open as system */
69 sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(mem_ctx, dce_call->conn->dce_ctx->lp_ctx));
70 if (sam_ctx == NULL) {
71 return NT_STATUS_INVALID_SYSTEM_SERVICE;
74 ret = ldb_transaction_start(sam_ctx);
76 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
77 return NT_STATUS_TRANSACTION_ABORTED;
80 /* fetch the old hashes */
81 ret = gendb_search_dn(sam_ctx, mem_ctx,
82 a_state->account_dn, &res, attrs);
84 ldb_transaction_cancel(sam_ctx);
85 return NT_STATUS_WRONG_PASSWORD;
89 status = samdb_result_passwords(mem_ctx, msg, &lm_pwd, &nt_pwd);
90 if (!NT_STATUS_IS_OK(status) || !lm_pwd || !nt_pwd) {
91 ldb_transaction_cancel(sam_ctx);
92 return NT_STATUS_WRONG_PASSWORD;
95 /* decrypt and check the new lm hash */
96 D_P16(lm_pwd->hash, r->in.new_lm_crypted->hash, new_lmPwdHash.hash);
97 D_P16(new_lmPwdHash.hash, r->in.old_lm_crypted->hash, checkHash.hash);
98 if (memcmp(checkHash.hash, lm_pwd, 16) != 0) {
99 ldb_transaction_cancel(sam_ctx);
100 return NT_STATUS_WRONG_PASSWORD;
103 /* decrypt and check the new nt hash */
104 D_P16(nt_pwd->hash, r->in.new_nt_crypted->hash, new_ntPwdHash.hash);
105 D_P16(new_ntPwdHash.hash, r->in.old_nt_crypted->hash, checkHash.hash);
106 if (memcmp(checkHash.hash, nt_pwd, 16) != 0) {
107 ldb_transaction_cancel(sam_ctx);
108 return NT_STATUS_WRONG_PASSWORD;
111 /* The NT Cross is not required by Win2k3 R2, but if present
112 check the nt cross hash */
113 if (r->in.cross1_present && r->in.nt_cross) {
114 D_P16(lm_pwd->hash, r->in.nt_cross->hash, checkHash.hash);
115 if (memcmp(checkHash.hash, new_ntPwdHash.hash, 16) != 0) {
116 ldb_transaction_cancel(sam_ctx);
117 return NT_STATUS_WRONG_PASSWORD;
121 /* The LM Cross is not required by Win2k3 R2, but if present
122 check the lm cross hash */
123 if (r->in.cross2_present && r->in.lm_cross) {
124 D_P16(nt_pwd->hash, r->in.lm_cross->hash, checkHash.hash);
125 if (memcmp(checkHash.hash, new_lmPwdHash.hash, 16) != 0) {
126 ldb_transaction_cancel(sam_ctx);
127 return NT_STATUS_WRONG_PASSWORD;
131 msg = ldb_msg_new(mem_ctx);
133 ldb_transaction_cancel(sam_ctx);
134 return NT_STATUS_NO_MEMORY;
137 msg->dn = ldb_dn_copy(msg, a_state->account_dn);
139 ldb_transaction_cancel(sam_ctx);
140 return NT_STATUS_NO_MEMORY;
143 /* setup password modify mods on the user DN specified. This may fail
144 * due to password policies. */
145 status = samdb_set_password(sam_ctx, mem_ctx,
146 a_state->account_dn, a_state->domain_state->domain_dn,
147 msg, NULL, &new_lmPwdHash, &new_ntPwdHash,
148 true, /* this is a user password change */
151 if (!NT_STATUS_IS_OK(status)) {
152 ldb_transaction_cancel(sam_ctx);
156 /* The above call only setup the modifications, this actually
157 * makes the write to the database. */
158 ret = samdb_replace(sam_ctx, mem_ctx, msg);
160 DEBUG(2,("Failed to modify record to change password on %s: %s\n",
161 ldb_dn_get_linearized(a_state->account_dn),
162 ldb_errstring(sam_ctx)));
163 ldb_transaction_cancel(sam_ctx);
164 return NT_STATUS_INTERNAL_DB_CORRUPTION;
167 /* And this confirms it in a transaction commit */
168 ret = ldb_transaction_commit(sam_ctx);
170 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
171 ldb_dn_get_linearized(a_state->account_dn),
172 ldb_errstring(sam_ctx)));
173 return NT_STATUS_TRANSACTION_ABORTED;
180 samr_OemChangePasswordUser2
182 NTSTATUS dcesrv_samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
183 struct samr_OemChangePasswordUser2 *r)
187 uint32_t new_pass_len;
188 struct samr_CryptPassword *pwbuf = r->in.password;
189 struct ldb_context *sam_ctx;
190 struct ldb_dn *user_dn;
192 struct ldb_message **res, *mod;
193 const char * const attrs[] = { "objectSid", "dBCSPwd", NULL };
194 struct samr_Password *lm_pwd;
195 DATA_BLOB lm_pwd_blob;
196 uint8_t new_lm_hash[16];
197 struct samr_Password lm_verifier;
200 return NT_STATUS_INVALID_PARAMETER;
203 if (r->in.hash == NULL) {
204 return NT_STATUS_INVALID_PARAMETER;
207 /* To change a password we need to open as system */
208 sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(mem_ctx, dce_call->conn->dce_ctx->lp_ctx));
209 if (sam_ctx == NULL) {
210 return NT_STATUS_INVALID_SYSTEM_SERVICE;
213 ret = ldb_transaction_start(sam_ctx);
215 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
216 return NT_STATUS_TRANSACTION_ABORTED;
219 /* we need the users dn and the domain dn (derived from the
220 user SID). We also need the current lm password hash in
221 order to decrypt the incoming password */
222 ret = gendb_search(sam_ctx,
223 mem_ctx, NULL, &res, attrs,
224 "(&(sAMAccountName=%s)(objectclass=user))",
225 r->in.account->string);
227 ldb_transaction_cancel(sam_ctx);
228 /* Don't give the game away: (don't allow anonymous users to prove the existance of usernames) */
229 return NT_STATUS_WRONG_PASSWORD;
232 user_dn = res[0]->dn;
234 status = samdb_result_passwords(mem_ctx, res[0], &lm_pwd, NULL);
235 if (!NT_STATUS_IS_OK(status) || !lm_pwd) {
236 ldb_transaction_cancel(sam_ctx);
237 return NT_STATUS_WRONG_PASSWORD;
240 /* decrypt the password we have been given */
241 lm_pwd_blob = data_blob(lm_pwd->hash, sizeof(lm_pwd->hash));
242 arcfour_crypt_blob(pwbuf->data, 516, &lm_pwd_blob);
243 data_blob_free(&lm_pwd_blob);
245 if (!decode_pw_buffer(pwbuf->data, new_pass, sizeof(new_pass),
247 ldb_transaction_cancel(sam_ctx);
248 DEBUG(3,("samr: failed to decode password buffer\n"));
249 return NT_STATUS_WRONG_PASSWORD;
252 /* check LM verifier */
253 if (lm_pwd == NULL) {
254 ldb_transaction_cancel(sam_ctx);
255 return NT_STATUS_WRONG_PASSWORD;
258 E_deshash(new_pass, new_lm_hash);
259 E_old_pw_hash(new_lm_hash, lm_pwd->hash, lm_verifier.hash);
260 if (memcmp(lm_verifier.hash, r->in.hash->hash, 16) != 0) {
261 ldb_transaction_cancel(sam_ctx);
262 return NT_STATUS_WRONG_PASSWORD;
265 mod = ldb_msg_new(mem_ctx);
267 ldb_transaction_cancel(sam_ctx);
268 return NT_STATUS_NO_MEMORY;
271 mod->dn = ldb_dn_copy(mod, user_dn);
273 ldb_transaction_cancel(sam_ctx);
274 return NT_STATUS_NO_MEMORY;
277 /* set the password on the user DN specified. This may fail
278 * due to password policies */
279 status = samdb_set_password(sam_ctx, mem_ctx,
283 true, /* this is a user password change */
286 if (!NT_STATUS_IS_OK(status)) {
287 ldb_transaction_cancel(sam_ctx);
291 /* The above call only setup the modifications, this actually
292 * makes the write to the database. */
293 ret = samdb_replace(sam_ctx, mem_ctx, mod);
295 DEBUG(2,("Failed to modify record to change password on %s: %s\n",
296 ldb_dn_get_linearized(user_dn),
297 ldb_errstring(sam_ctx)));
298 ldb_transaction_cancel(sam_ctx);
299 return NT_STATUS_INTERNAL_DB_CORRUPTION;
302 /* And this confirms it in a transaction commit */
303 ret = ldb_transaction_commit(sam_ctx);
305 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
306 ldb_dn_get_linearized(user_dn),
307 ldb_errstring(sam_ctx)));
308 return NT_STATUS_TRANSACTION_ABORTED;
316 samr_ChangePasswordUser3
318 NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call,
320 struct samr_ChangePasswordUser3 *r)
324 struct ldb_context *sam_ctx = NULL;
325 struct ldb_dn *user_dn;
327 struct ldb_message **res, *mod;
328 const char * const attrs[] = { "unicodePwd", "dBCSPwd", NULL };
329 struct samr_Password *nt_pwd, *lm_pwd;
330 DATA_BLOB nt_pwd_blob;
331 struct samr_DomInfo1 *dominfo = NULL;
332 struct samr_ChangeReject *reject = NULL;
333 enum samr_RejectReason reason = SAMR_REJECT_OTHER;
334 uint8_t new_nt_hash[16], new_lm_hash[16];
335 struct samr_Password nt_verifier, lm_verifier;
339 if (r->in.nt_password == NULL ||
340 r->in.nt_verifier == NULL) {
341 return NT_STATUS_INVALID_PARAMETER;
344 /* To change a password we need to open as system */
345 sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx, dce_call->conn->dce_ctx->lp_ctx, system_session(mem_ctx, dce_call->conn->dce_ctx->lp_ctx));
346 if (sam_ctx == NULL) {
347 return NT_STATUS_INVALID_SYSTEM_SERVICE;
350 ret = ldb_transaction_start(sam_ctx);
352 talloc_free(sam_ctx);
353 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
354 return NT_STATUS_TRANSACTION_ABORTED;
357 /* we need the users dn and the domain dn (derived from the
358 user SID). We also need the current lm and nt password hashes
359 in order to decrypt the incoming passwords */
360 ret = gendb_search(sam_ctx,
361 mem_ctx, NULL, &res, attrs,
362 "(&(sAMAccountName=%s)(objectclass=user))",
363 r->in.account->string);
365 /* Don't give the game away: (don't allow anonymous users to prove the existance of usernames) */
366 status = NT_STATUS_WRONG_PASSWORD;
370 user_dn = res[0]->dn;
372 status = samdb_result_passwords(mem_ctx, res[0], &lm_pwd, &nt_pwd);
373 if (!NT_STATUS_IS_OK(status) ) {
378 status = NT_STATUS_WRONG_PASSWORD;
382 /* decrypt the password we have been given */
383 nt_pwd_blob = data_blob(nt_pwd->hash, sizeof(nt_pwd->hash));
384 arcfour_crypt_blob(r->in.nt_password->data, 516, &nt_pwd_blob);
385 data_blob_free(&nt_pwd_blob);
387 if (!decode_pw_buffer(r->in.nt_password->data, new_pass, sizeof(new_pass),
389 DEBUG(3,("samr: failed to decode password buffer\n"));
390 status = NT_STATUS_WRONG_PASSWORD;
394 if (r->in.nt_verifier == NULL) {
395 status = NT_STATUS_WRONG_PASSWORD;
399 /* check NT verifier */
400 E_md4hash(new_pass, new_nt_hash);
401 E_old_pw_hash(new_nt_hash, nt_pwd->hash, nt_verifier.hash);
402 if (memcmp(nt_verifier.hash, r->in.nt_verifier->hash, 16) != 0) {
403 status = NT_STATUS_WRONG_PASSWORD;
407 /* check LM verifier */
408 if (lm_pwd && r->in.lm_verifier != NULL) {
409 E_deshash(new_pass, new_lm_hash);
410 E_old_pw_hash(new_nt_hash, lm_pwd->hash, lm_verifier.hash);
411 if (memcmp(lm_verifier.hash, r->in.lm_verifier->hash, 16) != 0) {
412 status = NT_STATUS_WRONG_PASSWORD;
418 mod = ldb_msg_new(mem_ctx);
420 return NT_STATUS_NO_MEMORY;
423 mod->dn = ldb_dn_copy(mod, user_dn);
425 status = NT_STATUS_NO_MEMORY;
429 /* set the password on the user DN specified. This may fail
430 * due to password policies */
431 status = samdb_set_password(sam_ctx, mem_ctx,
435 true, /* this is a user password change */
438 if (!NT_STATUS_IS_OK(status)) {
442 /* The above call only setup the modifications, this actually
443 * makes the write to the database. */
444 ret = samdb_replace(sam_ctx, mem_ctx, mod);
446 DEBUG(2,("samdb_replace failed to change password for %s: %s\n",
447 ldb_dn_get_linearized(user_dn),
448 ldb_errstring(sam_ctx)));
449 status = NT_STATUS_UNSUCCESSFUL;
453 /* And this confirms it in a transaction commit */
454 ret = ldb_transaction_commit(sam_ctx);
456 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
457 ldb_dn_get_linearized(user_dn),
458 ldb_errstring(sam_ctx)));
459 status = NT_STATUS_TRANSACTION_ABORTED;
466 ldb_transaction_cancel(sam_ctx);
467 talloc_free(sam_ctx);
469 reject = talloc(mem_ctx, struct samr_ChangeReject);
470 r->out.dominfo = dominfo;
471 r->out.reject = reject;
473 if (reject == NULL) {
476 ZERO_STRUCTP(reject);
478 reject->reason = reason;
485 samr_ChangePasswordUser2
487 easy - just a subset of samr_ChangePasswordUser3
489 NTSTATUS dcesrv_samr_ChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
490 struct samr_ChangePasswordUser2 *r)
492 struct samr_ChangePasswordUser3 r2;
494 r2.in.server = r->in.server;
495 r2.in.account = r->in.account;
496 r2.in.nt_password = r->in.nt_password;
497 r2.in.nt_verifier = r->in.nt_verifier;
498 r2.in.lm_change = r->in.lm_change;
499 r2.in.lm_password = r->in.lm_password;
500 r2.in.lm_verifier = r->in.lm_verifier;
501 r2.in.password3 = NULL;
503 return dcesrv_samr_ChangePasswordUser3(dce_call, mem_ctx, &r2);
508 set password via a samr_CryptPassword buffer
509 this will in the 'msg' with modify operations that will update the user
510 password when applied
512 NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call,
514 struct ldb_dn *account_dn, struct ldb_dn *domain_dn,
516 struct ldb_message *msg,
517 struct samr_CryptPassword *pwbuf)
521 DATA_BLOB session_key = data_blob(NULL, 0);
523 nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
524 if (!NT_STATUS_IS_OK(nt_status)) {
528 arcfour_crypt_blob(pwbuf->data, 516, &session_key);
530 if (!decode_pw_buffer(pwbuf->data, new_pass, sizeof(new_pass),
532 DEBUG(3,("samr: failed to decode password buffer\n"));
533 return NT_STATUS_WRONG_PASSWORD;
536 /* set the password - samdb needs to know both the domain and user DNs,
537 so the domain password policy can be used */
538 return samdb_set_password(sam_ctx, mem_ctx,
539 account_dn, domain_dn,
542 false, /* This is a password set, not change */
548 set password via a samr_CryptPasswordEx buffer
549 this will in the 'msg' with modify operations that will update the user
550 password when applied
552 NTSTATUS samr_set_password_ex(struct dcesrv_call_state *dce_call,
553 struct ldb_context *sam_ctx,
554 struct ldb_dn *account_dn, struct ldb_dn *domain_dn,
556 struct ldb_message *msg,
557 struct samr_CryptPasswordEx *pwbuf)
561 uint32_t new_pass_len;
562 DATA_BLOB co_session_key;
563 DATA_BLOB session_key = data_blob(NULL, 0);
564 struct MD5Context ctx;
566 nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
567 if (!NT_STATUS_IS_OK(nt_status)) {
571 co_session_key = data_blob_talloc(mem_ctx, NULL, 16);
572 if (!co_session_key.data) {
573 return NT_STATUS_NO_MEMORY;
577 MD5Update(&ctx, &pwbuf->data[516], 16);
578 MD5Update(&ctx, session_key.data, session_key.length);
579 MD5Final(co_session_key.data, &ctx);
581 arcfour_crypt_blob(pwbuf->data, 516, &co_session_key);
583 if (!decode_pw_buffer(pwbuf->data, new_pass, sizeof(new_pass),
585 DEBUG(3,("samr: failed to decode password buffer\n"));
586 return NT_STATUS_WRONG_PASSWORD;
589 /* set the password - samdb needs to know both the domain and user DNs,
590 so the domain password policy can be used */
591 return samdb_set_password(sam_ctx, mem_ctx,
592 account_dn, domain_dn,
595 false, /* This is a password set, not change */