CVE-2013-4496:samr: Remove ChangePasswordUser
[Samba.git] / source4 / rpc_server / samr / samr_password.c
blobde2a67c7bdd4908976f64dd64b01b136ede6c524
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);
146 /* Connect to a SAMDB with user privileges for the password change */
147 sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
148 dce_call->conn->dce_ctx->lp_ctx,
149 dce_call->conn->auth_state.session_info, 0);
150 if (sam_ctx == NULL) {
151 return NT_STATUS_INVALID_SYSTEM_SERVICE;
154 /* Start transaction */
155 ret = ldb_transaction_start(sam_ctx);
156 if (ret != LDB_SUCCESS) {
157 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
158 return NT_STATUS_TRANSACTION_ABORTED;
161 /* Performs the password modification. We pass the old hashes read out
162 * from the database since they were already checked against the user-
163 * provided ones. */
164 status = samdb_set_password(sam_ctx, mem_ctx,
165 user_dn, NULL,
166 &new_unicode_password,
167 NULL, NULL,
168 lm_pwd, NULL, /* this is a user password change */
169 NULL,
170 NULL);
171 if (!NT_STATUS_IS_OK(status)) {
172 ldb_transaction_cancel(sam_ctx);
173 return status;
176 if (memcmp(lm_verifier.hash, r->in.hash->hash, 16) != 0) {
177 ldb_transaction_cancel(sam_ctx);
178 return NT_STATUS_WRONG_PASSWORD;
181 /* And this confirms it in a transaction commit */
182 ret = ldb_transaction_commit(sam_ctx);
183 if (ret != LDB_SUCCESS) {
184 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
185 ldb_dn_get_linearized(user_dn),
186 ldb_errstring(sam_ctx)));
187 return NT_STATUS_TRANSACTION_ABORTED;
190 return NT_STATUS_OK;
195 samr_ChangePasswordUser3
197 NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call,
198 TALLOC_CTX *mem_ctx,
199 struct samr_ChangePasswordUser3 *r)
201 NTSTATUS status;
202 DATA_BLOB new_password;
203 struct ldb_context *sam_ctx = NULL;
204 struct ldb_dn *user_dn;
205 int ret;
206 struct ldb_message **res;
207 const char * const attrs[] = { "unicodePwd", "dBCSPwd", NULL };
208 struct samr_Password *nt_pwd, *lm_pwd;
209 DATA_BLOB nt_pwd_blob;
210 struct samr_DomInfo1 *dominfo = NULL;
211 struct userPwdChangeFailureInformation *reject = NULL;
212 enum samPwdChangeReason reason = SAM_PWD_CHANGE_NO_ERROR;
213 uint8_t new_nt_hash[16], new_lm_hash[16];
214 struct samr_Password nt_verifier, lm_verifier;
216 *r->out.dominfo = NULL;
217 *r->out.reject = NULL;
219 if (r->in.nt_password == NULL ||
220 r->in.nt_verifier == NULL) {
221 return NT_STATUS_INVALID_PARAMETER;
224 /* Connect to a SAMDB with system privileges for fetching the old pw
225 * hashes. */
226 sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
227 dce_call->conn->dce_ctx->lp_ctx,
228 system_session(dce_call->conn->dce_ctx->lp_ctx), 0);
229 if (sam_ctx == NULL) {
230 return NT_STATUS_INVALID_SYSTEM_SERVICE;
233 /* we need the users dn and the domain dn (derived from the
234 user SID). We also need the current lm and nt password hashes
235 in order to decrypt the incoming passwords */
236 ret = gendb_search(sam_ctx,
237 mem_ctx, NULL, &res, attrs,
238 "(&(sAMAccountName=%s)(objectclass=user))",
239 r->in.account->string);
240 if (ret != 1) {
241 /* Don't give the game away: (don't allow anonymous users to prove the existance of usernames) */
242 status = NT_STATUS_WRONG_PASSWORD;
243 goto failed;
246 user_dn = res[0]->dn;
248 status = samdb_result_passwords(mem_ctx, dce_call->conn->dce_ctx->lp_ctx,
249 res[0], &lm_pwd, &nt_pwd);
250 if (!NT_STATUS_IS_OK(status) ) {
251 goto failed;
254 if (!nt_pwd) {
255 status = NT_STATUS_WRONG_PASSWORD;
256 goto failed;
259 /* decrypt the password we have been given */
260 nt_pwd_blob = data_blob(nt_pwd->hash, sizeof(nt_pwd->hash));
261 arcfour_crypt_blob(r->in.nt_password->data, 516, &nt_pwd_blob);
262 data_blob_free(&nt_pwd_blob);
264 if (!extract_pw_from_buffer(mem_ctx, r->in.nt_password->data, &new_password)) {
265 DEBUG(3,("samr: failed to decode password buffer\n"));
266 status = NT_STATUS_WRONG_PASSWORD;
267 goto failed;
270 /* Connect to a SAMDB with user privileges for the password change */
271 sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
272 dce_call->conn->dce_ctx->lp_ctx,
273 dce_call->conn->auth_state.session_info, 0);
274 if (sam_ctx == NULL) {
275 return NT_STATUS_INVALID_SYSTEM_SERVICE;
278 ret = ldb_transaction_start(sam_ctx);
279 if (ret != LDB_SUCCESS) {
280 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
281 return NT_STATUS_TRANSACTION_ABORTED;
284 /* Performs the password modification. We pass the old hashes read out
285 * from the database since they were already checked against the user-
286 * provided ones. */
287 status = samdb_set_password(sam_ctx, mem_ctx,
288 user_dn, NULL,
289 &new_password,
290 NULL, NULL,
291 lm_pwd, nt_pwd, /* this is a user password change */
292 &reason,
293 &dominfo);
295 if (!NT_STATUS_IS_OK(status)) {
296 ldb_transaction_cancel(sam_ctx);
297 goto failed;
300 /* check NT verifier */
301 mdfour(new_nt_hash, new_password.data, new_password.length);
303 E_old_pw_hash(new_nt_hash, nt_pwd->hash, nt_verifier.hash);
304 if (memcmp(nt_verifier.hash, r->in.nt_verifier->hash, 16) != 0) {
305 ldb_transaction_cancel(sam_ctx);
306 status = NT_STATUS_WRONG_PASSWORD;
307 goto failed;
310 /* check LM verifier (really not needed as we just checked the
311 * much stronger NT hash, but the RPC-SAMR test checks for
312 * this) */
313 if (lm_pwd && r->in.lm_verifier != NULL) {
314 char *new_pass;
315 size_t converted_size = 0;
317 if (!convert_string_talloc_handle(mem_ctx, lpcfg_iconv_handle(dce_call->conn->dce_ctx->lp_ctx),
318 CH_UTF16, CH_UNIX,
319 (const char *)new_password.data,
320 new_password.length,
321 (void **)&new_pass, &converted_size)) {
322 E_deshash(new_pass, new_lm_hash);
323 E_old_pw_hash(new_nt_hash, lm_pwd->hash, lm_verifier.hash);
324 if (memcmp(lm_verifier.hash, r->in.lm_verifier->hash, 16) != 0) {
325 ldb_transaction_cancel(sam_ctx);
326 status = NT_STATUS_WRONG_PASSWORD;
327 goto failed;
332 /* And this confirms it in a transaction commit */
333 ret = ldb_transaction_commit(sam_ctx);
334 if (ret != LDB_SUCCESS) {
335 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
336 ldb_dn_get_linearized(user_dn),
337 ldb_errstring(sam_ctx)));
338 status = NT_STATUS_TRANSACTION_ABORTED;
339 goto failed;
342 return NT_STATUS_OK;
344 failed:
345 reject = talloc_zero(mem_ctx, struct userPwdChangeFailureInformation);
346 if (reject != NULL) {
347 reject->extendedFailureReason = reason;
349 *r->out.reject = reject;
352 *r->out.dominfo = dominfo;
354 return status;
359 samr_ChangePasswordUser2
361 easy - just a subset of samr_ChangePasswordUser3
363 NTSTATUS dcesrv_samr_ChangePasswordUser2(struct dcesrv_call_state *dce_call,
364 TALLOC_CTX *mem_ctx,
365 struct samr_ChangePasswordUser2 *r)
367 struct samr_ChangePasswordUser3 r2;
368 struct samr_DomInfo1 *dominfo = NULL;
369 struct userPwdChangeFailureInformation *reject = NULL;
371 r2.in.server = r->in.server;
372 r2.in.account = r->in.account;
373 r2.in.nt_password = r->in.nt_password;
374 r2.in.nt_verifier = r->in.nt_verifier;
375 r2.in.lm_change = r->in.lm_change;
376 r2.in.lm_password = r->in.lm_password;
377 r2.in.lm_verifier = r->in.lm_verifier;
378 r2.in.password3 = NULL;
379 r2.out.dominfo = &dominfo;
380 r2.out.reject = &reject;
382 return dcesrv_samr_ChangePasswordUser3(dce_call, mem_ctx, &r2);
387 set password via a samr_CryptPassword buffer
389 NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call,
390 struct ldb_context *sam_ctx,
391 struct ldb_dn *account_dn, struct ldb_dn *domain_dn,
392 TALLOC_CTX *mem_ctx,
393 struct samr_CryptPassword *pwbuf)
395 NTSTATUS nt_status;
396 DATA_BLOB new_password;
397 DATA_BLOB session_key = data_blob(NULL, 0);
399 nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
400 if (!NT_STATUS_IS_OK(nt_status)) {
401 return nt_status;
404 arcfour_crypt_blob(pwbuf->data, 516, &session_key);
406 if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
407 DEBUG(3,("samr: failed to decode password buffer\n"));
408 return NT_STATUS_WRONG_PASSWORD;
411 /* set the password - samdb needs to know both the domain and user DNs,
412 so the domain password policy can be used */
413 return samdb_set_password(sam_ctx, mem_ctx,
414 account_dn, domain_dn,
415 &new_password,
416 NULL, NULL,
417 NULL, NULL, /* This is a password set, not change */
418 NULL, NULL);
423 set password via a samr_CryptPasswordEx buffer
425 NTSTATUS samr_set_password_ex(struct dcesrv_call_state *dce_call,
426 struct ldb_context *sam_ctx,
427 struct ldb_dn *account_dn,
428 struct ldb_dn *domain_dn,
429 TALLOC_CTX *mem_ctx,
430 struct samr_CryptPasswordEx *pwbuf)
432 NTSTATUS nt_status;
433 DATA_BLOB new_password;
434 DATA_BLOB co_session_key;
435 DATA_BLOB session_key = data_blob(NULL, 0);
436 struct MD5Context ctx;
438 nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
439 if (!NT_STATUS_IS_OK(nt_status)) {
440 return nt_status;
443 co_session_key = data_blob_talloc(mem_ctx, NULL, 16);
444 if (!co_session_key.data) {
445 return NT_STATUS_NO_MEMORY;
448 MD5Init(&ctx);
449 MD5Update(&ctx, &pwbuf->data[516], 16);
450 MD5Update(&ctx, session_key.data, session_key.length);
451 MD5Final(co_session_key.data, &ctx);
453 arcfour_crypt_blob(pwbuf->data, 516, &co_session_key);
455 if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
456 DEBUG(3,("samr: failed to decode password buffer\n"));
457 return NT_STATUS_WRONG_PASSWORD;
460 /* set the password - samdb needs to know both the domain and user DNs,
461 so the domain password policy can be used */
462 return samdb_set_password(sam_ctx, mem_ctx,
463 account_dn, domain_dn,
464 &new_password,
465 NULL, NULL,
466 NULL, NULL, /* This is a password set, not change */
467 NULL, NULL);
471 set password via encrypted NT and LM hash buffers
473 NTSTATUS samr_set_password_buffers(struct dcesrv_call_state *dce_call,
474 struct ldb_context *sam_ctx,
475 struct ldb_dn *account_dn,
476 struct ldb_dn *domain_dn,
477 TALLOC_CTX *mem_ctx,
478 const uint8_t *lm_pwd_hash,
479 const uint8_t *nt_pwd_hash)
481 struct samr_Password *d_lm_pwd_hash = NULL, *d_nt_pwd_hash = NULL;
482 DATA_BLOB session_key = data_blob(NULL, 0);
483 DATA_BLOB in, out;
484 NTSTATUS nt_status = NT_STATUS_OK;
486 nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
487 if (!NT_STATUS_IS_OK(nt_status)) {
488 return nt_status;
491 if (lm_pwd_hash != NULL) {
492 in = data_blob_const(lm_pwd_hash, 16);
493 out = data_blob_talloc_zero(mem_ctx, 16);
495 sess_crypt_blob(&out, &in, &session_key, false);
497 d_lm_pwd_hash = (struct samr_Password *) out.data;
499 if (nt_pwd_hash != NULL) {
500 in = data_blob_const(nt_pwd_hash, 16);
501 out = data_blob_talloc_zero(mem_ctx, 16);
503 sess_crypt_blob(&out, &in, &session_key, false);
505 d_nt_pwd_hash = (struct samr_Password *) out.data;
508 if ((d_lm_pwd_hash != NULL) || (d_nt_pwd_hash != NULL)) {
509 nt_status = samdb_set_password(sam_ctx, mem_ctx, account_dn,
510 domain_dn, NULL,
511 d_lm_pwd_hash, d_nt_pwd_hash,
512 NULL, NULL, /* this is a password set */
513 NULL, NULL);
516 return nt_status;