CVE-2013-4496:Revert remainder of ce895609b04380bfc41e4f8fddc84bd2f9324340
[Samba.git] / source4 / rpc_server / samr / samr_password.c
blobac7d473378a7188a2ec93704b26e16fe56fd6d17
1 /*
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/>.
23 #include "includes.h"
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"
32 #include "rpc_server/samr/proto.h"
35 samr_ChangePasswordUser
37 So old it is just not worth implementing
38 because it does not supply a plaintext and so we can't do password
39 complexity checking and cannot update all the other password hashes.
42 NTSTATUS dcesrv_samr_ChangePasswordUser(struct dcesrv_call_state *dce_call,
43 TALLOC_CTX *mem_ctx,
44 struct samr_ChangePasswordUser *r)
46 return NT_STATUS_NOT_IMPLEMENTED;
50 samr_OemChangePasswordUser2
52 NTSTATUS dcesrv_samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call,
53 TALLOC_CTX *mem_ctx,
54 struct samr_OemChangePasswordUser2 *r)
56 NTSTATUS status;
57 DATA_BLOB new_password, new_unicode_password;
58 char *new_pass;
59 struct samr_CryptPassword *pwbuf = r->in.password;
60 struct ldb_context *sam_ctx;
61 struct ldb_dn *user_dn;
62 int ret;
63 struct ldb_message **res;
64 const char * const attrs[] = { "objectSid", "dBCSPwd", NULL };
65 struct samr_Password *lm_pwd;
66 DATA_BLOB lm_pwd_blob;
67 uint8_t new_lm_hash[16];
68 struct samr_Password lm_verifier;
69 size_t unicode_pw_len;
70 size_t converted_size = 0;
72 if (pwbuf == NULL) {
73 return NT_STATUS_INVALID_PARAMETER;
76 if (r->in.hash == NULL) {
77 return NT_STATUS_INVALID_PARAMETER;
80 /* this call can only work with lanman auth */
81 if (!lpcfg_lanman_auth(dce_call->conn->dce_ctx->lp_ctx)) {
82 return NT_STATUS_WRONG_PASSWORD;
85 /* Connect to a SAMDB with system privileges for fetching the old pw
86 * hashes. */
87 sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
88 dce_call->conn->dce_ctx->lp_ctx,
89 system_session(dce_call->conn->dce_ctx->lp_ctx), 0);
90 if (sam_ctx == NULL) {
91 return NT_STATUS_INVALID_SYSTEM_SERVICE;
94 /* we need the users dn and the domain dn (derived from the
95 user SID). We also need the current lm password hash in
96 order to decrypt the incoming password */
97 ret = gendb_search(sam_ctx,
98 mem_ctx, NULL, &res, attrs,
99 "(&(sAMAccountName=%s)(objectclass=user))",
100 r->in.account->string);
101 if (ret != 1) {
102 /* Don't give the game away: (don't allow anonymous users to prove the existance of usernames) */
103 return NT_STATUS_WRONG_PASSWORD;
106 user_dn = res[0]->dn;
108 status = samdb_result_passwords(mem_ctx, dce_call->conn->dce_ctx->lp_ctx,
109 res[0], &lm_pwd, NULL);
110 if (!NT_STATUS_IS_OK(status) || !lm_pwd) {
111 return NT_STATUS_WRONG_PASSWORD;
114 /* decrypt the password we have been given */
115 lm_pwd_blob = data_blob(lm_pwd->hash, sizeof(lm_pwd->hash));
116 arcfour_crypt_blob(pwbuf->data, 516, &lm_pwd_blob);
117 data_blob_free(&lm_pwd_blob);
119 if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
120 DEBUG(3,("samr: failed to decode password buffer\n"));
121 return NT_STATUS_WRONG_PASSWORD;
124 if (!convert_string_talloc_handle(mem_ctx, lpcfg_iconv_handle(dce_call->conn->dce_ctx->lp_ctx),
125 CH_DOS, CH_UNIX,
126 (const char *)new_password.data,
127 new_password.length,
128 (void **)&new_pass, &converted_size)) {
129 DEBUG(3,("samr: failed to convert incoming password buffer to unix charset\n"));
130 return NT_STATUS_WRONG_PASSWORD;
133 if (!convert_string_talloc_handle(mem_ctx, lpcfg_iconv_handle(dce_call->conn->dce_ctx->lp_ctx),
134 CH_DOS, CH_UTF16,
135 (const char *)new_password.data,
136 new_password.length,
137 (void **)&new_unicode_password.data, &unicode_pw_len)) {
138 DEBUG(3,("samr: failed to convert incoming password buffer to UTF16 charset\n"));
139 return NT_STATUS_WRONG_PASSWORD;
141 new_unicode_password.length = unicode_pw_len;
143 E_deshash(new_pass, new_lm_hash);
144 E_old_pw_hash(new_lm_hash, lm_pwd->hash, lm_verifier.hash);
145 if (memcmp(lm_verifier.hash, r->in.hash->hash, 16) != 0) {
146 return NT_STATUS_WRONG_PASSWORD;
149 /* Connect to a SAMDB with user privileges for the password change */
150 sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
151 dce_call->conn->dce_ctx->lp_ctx,
152 dce_call->conn->auth_state.session_info, 0);
153 if (sam_ctx == NULL) {
154 return NT_STATUS_INVALID_SYSTEM_SERVICE;
157 /* Start transaction */
158 ret = ldb_transaction_start(sam_ctx);
159 if (ret != LDB_SUCCESS) {
160 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
161 return NT_STATUS_TRANSACTION_ABORTED;
164 /* Performs the password modification. We pass the old hashes read out
165 * from the database since they were already checked against the user-
166 * provided ones. */
167 status = samdb_set_password(sam_ctx, mem_ctx,
168 user_dn, NULL,
169 &new_unicode_password,
170 NULL, NULL,
171 lm_pwd, NULL, /* this is a user password change */
172 NULL,
173 NULL);
174 if (!NT_STATUS_IS_OK(status)) {
175 ldb_transaction_cancel(sam_ctx);
176 return status;
179 /* And this confirms it in a transaction commit */
180 ret = ldb_transaction_commit(sam_ctx);
181 if (ret != LDB_SUCCESS) {
182 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
183 ldb_dn_get_linearized(user_dn),
184 ldb_errstring(sam_ctx)));
185 return NT_STATUS_TRANSACTION_ABORTED;
188 return NT_STATUS_OK;
193 samr_ChangePasswordUser3
195 NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call,
196 TALLOC_CTX *mem_ctx,
197 struct samr_ChangePasswordUser3 *r)
199 NTSTATUS status;
200 DATA_BLOB new_password;
201 struct ldb_context *sam_ctx = NULL;
202 struct ldb_dn *user_dn;
203 int ret;
204 struct ldb_message **res;
205 const char * const attrs[] = { "unicodePwd", "dBCSPwd", NULL };
206 struct samr_Password *nt_pwd, *lm_pwd;
207 DATA_BLOB nt_pwd_blob;
208 struct samr_DomInfo1 *dominfo = NULL;
209 struct userPwdChangeFailureInformation *reject = NULL;
210 enum samPwdChangeReason reason = SAM_PWD_CHANGE_NO_ERROR;
211 uint8_t new_nt_hash[16], new_lm_hash[16];
212 struct samr_Password nt_verifier, lm_verifier;
214 *r->out.dominfo = NULL;
215 *r->out.reject = NULL;
217 if (r->in.nt_password == NULL ||
218 r->in.nt_verifier == NULL) {
219 return NT_STATUS_INVALID_PARAMETER;
222 /* Connect to a SAMDB with system privileges for fetching the old pw
223 * hashes. */
224 sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
225 dce_call->conn->dce_ctx->lp_ctx,
226 system_session(dce_call->conn->dce_ctx->lp_ctx), 0);
227 if (sam_ctx == NULL) {
228 return NT_STATUS_INVALID_SYSTEM_SERVICE;
231 /* we need the users dn and the domain dn (derived from the
232 user SID). We also need the current lm and nt password hashes
233 in order to decrypt the incoming passwords */
234 ret = gendb_search(sam_ctx,
235 mem_ctx, NULL, &res, attrs,
236 "(&(sAMAccountName=%s)(objectclass=user))",
237 r->in.account->string);
238 if (ret != 1) {
239 /* Don't give the game away: (don't allow anonymous users to prove the existance of usernames) */
240 status = NT_STATUS_WRONG_PASSWORD;
241 goto failed;
244 user_dn = res[0]->dn;
246 status = samdb_result_passwords(mem_ctx, dce_call->conn->dce_ctx->lp_ctx,
247 res[0], &lm_pwd, &nt_pwd);
248 if (!NT_STATUS_IS_OK(status) ) {
249 goto failed;
252 if (!nt_pwd) {
253 status = NT_STATUS_WRONG_PASSWORD;
254 goto failed;
257 /* decrypt the password we have been given */
258 nt_pwd_blob = data_blob(nt_pwd->hash, sizeof(nt_pwd->hash));
259 arcfour_crypt_blob(r->in.nt_password->data, 516, &nt_pwd_blob);
260 data_blob_free(&nt_pwd_blob);
262 if (!extract_pw_from_buffer(mem_ctx, r->in.nt_password->data, &new_password)) {
263 DEBUG(3,("samr: failed to decode password buffer\n"));
264 status = NT_STATUS_WRONG_PASSWORD;
265 goto failed;
268 if (r->in.nt_verifier == NULL) {
269 status = NT_STATUS_WRONG_PASSWORD;
270 goto failed;
273 /* check NT verifier */
274 mdfour(new_nt_hash, new_password.data, new_password.length);
276 E_old_pw_hash(new_nt_hash, nt_pwd->hash, nt_verifier.hash);
277 if (memcmp(nt_verifier.hash, r->in.nt_verifier->hash, 16) != 0) {
278 status = NT_STATUS_WRONG_PASSWORD;
279 goto failed;
282 /* check LM verifier (really not needed as we just checked the
283 * much stronger NT hash, but the RPC-SAMR test checks for
284 * this) */
285 if (lm_pwd && r->in.lm_verifier != NULL) {
286 char *new_pass;
287 size_t converted_size = 0;
289 if (!convert_string_talloc_handle(mem_ctx, lpcfg_iconv_handle(dce_call->conn->dce_ctx->lp_ctx),
290 CH_UTF16, CH_UNIX,
291 (const char *)new_password.data,
292 new_password.length,
293 (void **)&new_pass, &converted_size)) {
294 E_deshash(new_pass, new_lm_hash);
295 E_old_pw_hash(new_nt_hash, lm_pwd->hash, lm_verifier.hash);
296 if (memcmp(lm_verifier.hash, r->in.lm_verifier->hash, 16) != 0) {
297 status = NT_STATUS_WRONG_PASSWORD;
298 goto failed;
303 /* Connect to a SAMDB with user privileges for the password change */
304 sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
305 dce_call->conn->dce_ctx->lp_ctx,
306 dce_call->conn->auth_state.session_info, 0);
307 if (sam_ctx == NULL) {
308 return NT_STATUS_INVALID_SYSTEM_SERVICE;
311 ret = ldb_transaction_start(sam_ctx);
312 if (ret != LDB_SUCCESS) {
313 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
314 return NT_STATUS_TRANSACTION_ABORTED;
317 /* Performs the password modification. We pass the old hashes read out
318 * from the database since they were already checked against the user-
319 * provided ones. */
320 status = samdb_set_password(sam_ctx, mem_ctx,
321 user_dn, NULL,
322 &new_password,
323 NULL, NULL,
324 lm_pwd, nt_pwd, /* this is a user password change */
325 &reason,
326 &dominfo);
328 if (!NT_STATUS_IS_OK(status)) {
329 ldb_transaction_cancel(sam_ctx);
330 goto failed;
333 /* And this confirms it in a transaction commit */
334 ret = ldb_transaction_commit(sam_ctx);
335 if (ret != LDB_SUCCESS) {
336 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
337 ldb_dn_get_linearized(user_dn),
338 ldb_errstring(sam_ctx)));
339 status = NT_STATUS_TRANSACTION_ABORTED;
340 goto failed;
343 return NT_STATUS_OK;
345 failed:
346 reject = talloc_zero(mem_ctx, struct userPwdChangeFailureInformation);
347 if (reject != NULL) {
348 reject->extendedFailureReason = reason;
350 *r->out.reject = reject;
353 *r->out.dominfo = dominfo;
355 return status;
360 samr_ChangePasswordUser2
362 easy - just a subset of samr_ChangePasswordUser3
364 NTSTATUS dcesrv_samr_ChangePasswordUser2(struct dcesrv_call_state *dce_call,
365 TALLOC_CTX *mem_ctx,
366 struct samr_ChangePasswordUser2 *r)
368 struct samr_ChangePasswordUser3 r2;
369 struct samr_DomInfo1 *dominfo = NULL;
370 struct userPwdChangeFailureInformation *reject = NULL;
372 r2.in.server = r->in.server;
373 r2.in.account = r->in.account;
374 r2.in.nt_password = r->in.nt_password;
375 r2.in.nt_verifier = r->in.nt_verifier;
376 r2.in.lm_change = r->in.lm_change;
377 r2.in.lm_password = r->in.lm_password;
378 r2.in.lm_verifier = r->in.lm_verifier;
379 r2.in.password3 = NULL;
380 r2.out.dominfo = &dominfo;
381 r2.out.reject = &reject;
383 return dcesrv_samr_ChangePasswordUser3(dce_call, mem_ctx, &r2);
388 set password via a samr_CryptPassword buffer
390 NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call,
391 struct ldb_context *sam_ctx,
392 struct ldb_dn *account_dn, struct ldb_dn *domain_dn,
393 TALLOC_CTX *mem_ctx,
394 struct samr_CryptPassword *pwbuf)
396 NTSTATUS nt_status;
397 DATA_BLOB new_password;
398 DATA_BLOB session_key = data_blob(NULL, 0);
400 nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
401 if (!NT_STATUS_IS_OK(nt_status)) {
402 return nt_status;
405 arcfour_crypt_blob(pwbuf->data, 516, &session_key);
407 if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
408 DEBUG(3,("samr: failed to decode password buffer\n"));
409 return NT_STATUS_WRONG_PASSWORD;
412 /* set the password - samdb needs to know both the domain and user DNs,
413 so the domain password policy can be used */
414 return samdb_set_password(sam_ctx, mem_ctx,
415 account_dn, domain_dn,
416 &new_password,
417 NULL, NULL,
418 NULL, NULL, /* This is a password set, not change */
419 NULL, NULL);
424 set password via a samr_CryptPasswordEx buffer
426 NTSTATUS samr_set_password_ex(struct dcesrv_call_state *dce_call,
427 struct ldb_context *sam_ctx,
428 struct ldb_dn *account_dn,
429 struct ldb_dn *domain_dn,
430 TALLOC_CTX *mem_ctx,
431 struct samr_CryptPasswordEx *pwbuf)
433 NTSTATUS nt_status;
434 DATA_BLOB new_password;
435 DATA_BLOB co_session_key;
436 DATA_BLOB session_key = data_blob(NULL, 0);
437 struct MD5Context ctx;
439 nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
440 if (!NT_STATUS_IS_OK(nt_status)) {
441 return nt_status;
444 co_session_key = data_blob_talloc(mem_ctx, NULL, 16);
445 if (!co_session_key.data) {
446 return NT_STATUS_NO_MEMORY;
449 MD5Init(&ctx);
450 MD5Update(&ctx, &pwbuf->data[516], 16);
451 MD5Update(&ctx, session_key.data, session_key.length);
452 MD5Final(co_session_key.data, &ctx);
454 arcfour_crypt_blob(pwbuf->data, 516, &co_session_key);
456 if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
457 DEBUG(3,("samr: failed to decode password buffer\n"));
458 return NT_STATUS_WRONG_PASSWORD;
461 /* set the password - samdb needs to know both the domain and user DNs,
462 so the domain password policy can be used */
463 return samdb_set_password(sam_ctx, mem_ctx,
464 account_dn, domain_dn,
465 &new_password,
466 NULL, NULL,
467 NULL, NULL, /* This is a password set, not change */
468 NULL, NULL);
472 set password via encrypted NT and LM hash buffers
474 NTSTATUS samr_set_password_buffers(struct dcesrv_call_state *dce_call,
475 struct ldb_context *sam_ctx,
476 struct ldb_dn *account_dn,
477 struct ldb_dn *domain_dn,
478 TALLOC_CTX *mem_ctx,
479 const uint8_t *lm_pwd_hash,
480 const uint8_t *nt_pwd_hash)
482 struct samr_Password *d_lm_pwd_hash = NULL, *d_nt_pwd_hash = NULL;
483 DATA_BLOB session_key = data_blob(NULL, 0);
484 DATA_BLOB in, out;
485 NTSTATUS nt_status = NT_STATUS_OK;
487 nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
488 if (!NT_STATUS_IS_OK(nt_status)) {
489 return nt_status;
492 if (lm_pwd_hash != NULL) {
493 in = data_blob_const(lm_pwd_hash, 16);
494 out = data_blob_talloc_zero(mem_ctx, 16);
496 sess_crypt_blob(&out, &in, &session_key, false);
498 d_lm_pwd_hash = (struct samr_Password *) out.data;
500 if (nt_pwd_hash != NULL) {
501 in = data_blob_const(nt_pwd_hash, 16);
502 out = data_blob_talloc_zero(mem_ctx, 16);
504 sess_crypt_blob(&out, &in, &session_key, false);
506 d_nt_pwd_hash = (struct samr_Password *) out.data;
509 if ((d_lm_pwd_hash != NULL) || (d_nt_pwd_hash != NULL)) {
510 nt_status = samdb_set_password(sam_ctx, mem_ctx, account_dn,
511 domain_dn, NULL,
512 d_lm_pwd_hash, d_nt_pwd_hash,
513 NULL, NULL, /* this is a password set */
514 NULL, NULL);
517 return nt_status;