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"
38 samr_ChangePasswordUser
40 NTSTATUS dcesrv_samr_ChangePasswordUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
41 struct samr_ChangePasswordUser *r)
43 struct dcesrv_handle *h;
44 struct samr_account_state *a_state;
45 struct ldb_context *sam_ctx;
46 struct ldb_message **res, *msg;
48 struct samr_Password new_lmPwdHash, new_ntPwdHash, checkHash;
49 struct samr_Password *lm_pwd, *nt_pwd;
50 NTSTATUS status = NT_STATUS_OK;
51 const char * const attrs[] = { "dBCSPwd", "unicodePwd" , NULL };
53 DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
57 /* basic sanity checking on parameters. Do this before any database ops */
58 if (!r->in.lm_present || !r->in.nt_present ||
59 !r->in.old_lm_crypted || !r->in.new_lm_crypted ||
60 !r->in.old_nt_crypted || !r->in.new_nt_crypted) {
61 /* we should really handle a change with lm not
63 return NT_STATUS_INVALID_PARAMETER_MIX;
66 /* To change a password we need to open as system */
67 sam_ctx = samdb_connect(mem_ctx, system_session(mem_ctx));
68 if (sam_ctx == NULL) {
69 return NT_STATUS_INVALID_SYSTEM_SERVICE;
72 ret = ldb_transaction_start(sam_ctx);
74 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
75 return NT_STATUS_TRANSACTION_ABORTED;
78 /* fetch the old hashes */
79 ret = gendb_search_dn(sam_ctx, mem_ctx,
80 a_state->account_dn, &res, attrs);
82 ldb_transaction_cancel(sam_ctx);
83 return NT_STATUS_WRONG_PASSWORD;
87 status = samdb_result_passwords(mem_ctx, msg, &lm_pwd, &nt_pwd);
88 if (!NT_STATUS_IS_OK(status) || !lm_pwd || !nt_pwd) {
89 ldb_transaction_cancel(sam_ctx);
90 return NT_STATUS_WRONG_PASSWORD;
93 /* decrypt and check the new lm hash */
94 D_P16(lm_pwd->hash, r->in.new_lm_crypted->hash, new_lmPwdHash.hash);
95 D_P16(new_lmPwdHash.hash, r->in.old_lm_crypted->hash, checkHash.hash);
96 if (memcmp(checkHash.hash, lm_pwd, 16) != 0) {
97 ldb_transaction_cancel(sam_ctx);
98 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) {
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) {
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 msg = ldb_msg_new(mem_ctx);
131 ldb_transaction_cancel(sam_ctx);
132 return NT_STATUS_NO_MEMORY;
135 msg->dn = ldb_dn_copy(msg, a_state->account_dn);
137 ldb_transaction_cancel(sam_ctx);
138 return NT_STATUS_NO_MEMORY;
141 /* setup password modify mods on the user DN specified. This may fail
142 * due to password policies. */
143 status = samdb_set_password(sam_ctx, mem_ctx,
144 a_state->account_dn, a_state->domain_state->domain_dn,
145 msg, NULL, &new_lmPwdHash, &new_ntPwdHash,
146 True, /* this is a user password change */
149 if (!NT_STATUS_IS_OK(status)) {
150 ldb_transaction_cancel(sam_ctx);
154 /* The above call only setup the modifications, this actually
155 * makes the write to the database. */
156 ret = samdb_replace(sam_ctx, mem_ctx, msg);
158 DEBUG(2,("Failed to modify record to change password on %s: %s\n",
159 ldb_dn_get_linearized(a_state->account_dn),
160 ldb_errstring(sam_ctx)));
161 ldb_transaction_cancel(sam_ctx);
162 return NT_STATUS_INTERNAL_DB_CORRUPTION;
165 /* And this confirms it in a transaction commit */
166 ret = ldb_transaction_commit(sam_ctx);
168 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
169 ldb_dn_get_linearized(a_state->account_dn),
170 ldb_errstring(sam_ctx)));
171 return NT_STATUS_TRANSACTION_ABORTED;
178 samr_OemChangePasswordUser2
180 NTSTATUS dcesrv_samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
181 struct samr_OemChangePasswordUser2 *r)
185 uint32_t new_pass_len;
186 struct samr_CryptPassword *pwbuf = r->in.password;
187 struct ldb_context *sam_ctx;
188 struct ldb_dn *user_dn;
190 struct ldb_message **res, *mod;
191 const char * const attrs[] = { "objectSid", "dBCSPwd", NULL };
192 struct samr_Password *lm_pwd;
193 DATA_BLOB lm_pwd_blob;
194 uint8_t new_lm_hash[16];
195 struct samr_Password lm_verifier;
198 return NT_STATUS_INVALID_PARAMETER;
201 if (r->in.hash == NULL) {
202 return NT_STATUS_INVALID_PARAMETER;
205 /* To change a password we need to open as system */
206 sam_ctx = samdb_connect(mem_ctx, system_session(mem_ctx));
207 if (sam_ctx == NULL) {
208 return NT_STATUS_INVALID_SYSTEM_SERVICE;
211 ret = ldb_transaction_start(sam_ctx);
213 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
214 return NT_STATUS_TRANSACTION_ABORTED;
217 /* we need the users dn and the domain dn (derived from the
218 user SID). We also need the current lm password hash in
219 order to decrypt the incoming password */
220 ret = gendb_search(sam_ctx,
221 mem_ctx, NULL, &res, attrs,
222 "(&(sAMAccountName=%s)(objectclass=user))",
223 r->in.account->string);
225 ldb_transaction_cancel(sam_ctx);
226 /* Don't give the game away: (don't allow anonymous users to prove the existance of usernames) */
227 return NT_STATUS_WRONG_PASSWORD;
230 user_dn = res[0]->dn;
232 status = samdb_result_passwords(mem_ctx, res[0], &lm_pwd, NULL);
233 if (!NT_STATUS_IS_OK(status) || !lm_pwd) {
234 ldb_transaction_cancel(sam_ctx);
235 return NT_STATUS_WRONG_PASSWORD;
238 /* decrypt the password we have been given */
239 lm_pwd_blob = data_blob(lm_pwd->hash, sizeof(lm_pwd->hash));
240 arcfour_crypt_blob(pwbuf->data, 516, &lm_pwd_blob);
241 data_blob_free(&lm_pwd_blob);
243 if (!decode_pw_buffer(pwbuf->data, new_pass, sizeof(new_pass),
244 &new_pass_len, STR_ASCII)) {
245 ldb_transaction_cancel(sam_ctx);
246 DEBUG(3,("samr: failed to decode password buffer\n"));
247 return NT_STATUS_WRONG_PASSWORD;
250 /* check LM verifier */
251 if (lm_pwd == NULL) {
252 ldb_transaction_cancel(sam_ctx);
253 return NT_STATUS_WRONG_PASSWORD;
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 mod = ldb_msg_new(mem_ctx);
265 ldb_transaction_cancel(sam_ctx);
266 return NT_STATUS_NO_MEMORY;
269 mod->dn = ldb_dn_copy(mod, user_dn);
271 ldb_transaction_cancel(sam_ctx);
272 return NT_STATUS_NO_MEMORY;
275 /* set the password on the user DN specified. This may fail
276 * due to password policies */
277 status = samdb_set_password(sam_ctx, mem_ctx,
281 True, /* this is a user password change */
284 if (!NT_STATUS_IS_OK(status)) {
285 ldb_transaction_cancel(sam_ctx);
289 /* The above call only setup the modifications, this actually
290 * makes the write to the database. */
291 ret = samdb_replace(sam_ctx, mem_ctx, mod);
293 DEBUG(2,("Failed to modify record to change password on %s: %s\n",
294 ldb_dn_get_linearized(user_dn),
295 ldb_errstring(sam_ctx)));
296 ldb_transaction_cancel(sam_ctx);
297 return NT_STATUS_INTERNAL_DB_CORRUPTION;
300 /* And this confirms it in a transaction commit */
301 ret = ldb_transaction_commit(sam_ctx);
303 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
304 ldb_dn_get_linearized(user_dn),
305 ldb_errstring(sam_ctx)));
306 return NT_STATUS_TRANSACTION_ABORTED;
314 samr_ChangePasswordUser3
316 NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call,
318 struct samr_ChangePasswordUser3 *r)
322 uint32_t new_pass_len;
323 struct ldb_context *sam_ctx = NULL;
324 struct ldb_dn *user_dn;
326 struct ldb_message **res, *mod;
327 const char * const attrs[] = { "unicodePwd", "dBCSPwd", NULL };
328 struct samr_Password *nt_pwd, *lm_pwd;
329 DATA_BLOB nt_pwd_blob;
330 struct samr_DomInfo1 *dominfo = NULL;
331 struct samr_ChangeReject *reject = NULL;
332 enum samr_RejectReason reason = SAMR_REJECT_OTHER;
333 uint8_t new_nt_hash[16], new_lm_hash[16];
334 struct samr_Password nt_verifier, lm_verifier;
338 if (r->in.nt_password == NULL ||
339 r->in.nt_verifier == NULL) {
340 return NT_STATUS_INVALID_PARAMETER;
343 /* To change a password we need to open as system */
344 sam_ctx = samdb_connect(mem_ctx, system_session(mem_ctx));
345 if (sam_ctx == NULL) {
346 return NT_STATUS_INVALID_SYSTEM_SERVICE;
349 ret = ldb_transaction_start(sam_ctx);
351 talloc_free(sam_ctx);
352 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
353 return NT_STATUS_TRANSACTION_ABORTED;
356 /* we need the users dn and the domain dn (derived from the
357 user SID). We also need the current lm and nt password hashes
358 in order to decrypt the incoming passwords */
359 ret = gendb_search(sam_ctx,
360 mem_ctx, NULL, &res, attrs,
361 "(&(sAMAccountName=%s)(objectclass=user))",
362 r->in.account->string);
364 /* Don't give the game away: (don't allow anonymous users to prove the existance of usernames) */
365 status = NT_STATUS_WRONG_PASSWORD;
369 user_dn = res[0]->dn;
371 status = samdb_result_passwords(mem_ctx, res[0], &lm_pwd, &nt_pwd);
372 if (!NT_STATUS_IS_OK(status) ) {
377 status = NT_STATUS_WRONG_PASSWORD;
381 /* decrypt the password we have been given */
382 nt_pwd_blob = data_blob(nt_pwd->hash, sizeof(nt_pwd->hash));
383 arcfour_crypt_blob(r->in.nt_password->data, 516, &nt_pwd_blob);
384 data_blob_free(&nt_pwd_blob);
386 if (!decode_pw_buffer(r->in.nt_password->data, new_pass, sizeof(new_pass),
387 &new_pass_len, STR_UNICODE)) {
388 DEBUG(3,("samr: failed to decode password buffer\n"));
389 status = NT_STATUS_WRONG_PASSWORD;
393 if (r->in.nt_verifier == NULL) {
394 status = NT_STATUS_WRONG_PASSWORD;
398 /* check NT verifier */
399 E_md4hash(new_pass, new_nt_hash);
400 E_old_pw_hash(new_nt_hash, nt_pwd->hash, nt_verifier.hash);
401 if (memcmp(nt_verifier.hash, r->in.nt_verifier->hash, 16) != 0) {
402 status = NT_STATUS_WRONG_PASSWORD;
406 /* check LM verifier */
407 if (lm_pwd && r->in.lm_verifier != NULL) {
408 E_deshash(new_pass, new_lm_hash);
409 E_old_pw_hash(new_nt_hash, lm_pwd->hash, lm_verifier.hash);
410 if (memcmp(lm_verifier.hash, r->in.lm_verifier->hash, 16) != 0) {
411 status = NT_STATUS_WRONG_PASSWORD;
417 mod = ldb_msg_new(mem_ctx);
419 return NT_STATUS_NO_MEMORY;
422 mod->dn = ldb_dn_copy(mod, user_dn);
424 status = NT_STATUS_NO_MEMORY;
428 /* set the password on the user DN specified. This may fail
429 * due to password policies */
430 status = samdb_set_password(sam_ctx, mem_ctx,
434 True, /* this is a user password change */
437 if (!NT_STATUS_IS_OK(status)) {
441 /* The above call only setup the modifications, this actually
442 * makes the write to the database. */
443 ret = samdb_replace(sam_ctx, mem_ctx, mod);
445 DEBUG(2,("samdb_replace failed to change password for %s: %s\n",
446 ldb_dn_get_linearized(user_dn),
447 ldb_errstring(sam_ctx)));
448 status = NT_STATUS_UNSUCCESSFUL;
452 /* And this confirms it in a transaction commit */
453 ret = ldb_transaction_commit(sam_ctx);
455 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
456 ldb_dn_get_linearized(user_dn),
457 ldb_errstring(sam_ctx)));
458 status = NT_STATUS_TRANSACTION_ABORTED;
465 ldb_transaction_cancel(sam_ctx);
466 talloc_free(sam_ctx);
468 reject = talloc(mem_ctx, struct samr_ChangeReject);
469 r->out.dominfo = dominfo;
470 r->out.reject = reject;
472 if (reject == NULL) {
475 ZERO_STRUCTP(reject);
477 reject->reason = reason;
484 samr_ChangePasswordUser2
486 easy - just a subset of samr_ChangePasswordUser3
488 NTSTATUS dcesrv_samr_ChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
489 struct samr_ChangePasswordUser2 *r)
491 struct samr_ChangePasswordUser3 r2;
493 r2.in.server = r->in.server;
494 r2.in.account = r->in.account;
495 r2.in.nt_password = r->in.nt_password;
496 r2.in.nt_verifier = r->in.nt_verifier;
497 r2.in.lm_change = r->in.lm_change;
498 r2.in.lm_password = r->in.lm_password;
499 r2.in.lm_verifier = r->in.lm_verifier;
500 r2.in.password3 = NULL;
502 return dcesrv_samr_ChangePasswordUser3(dce_call, mem_ctx, &r2);
507 set password via a samr_CryptPassword buffer
508 this will in the 'msg' with modify operations that will update the user
509 password when applied
511 NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call,
513 struct ldb_dn *account_dn, struct ldb_dn *domain_dn,
515 struct ldb_message *msg,
516 struct samr_CryptPassword *pwbuf)
520 uint32_t new_pass_len;
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),
531 &new_pass_len, STR_UNICODE)) {
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),
584 &new_pass_len, STR_UNICODE)) {
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 */