util:datablob: data_blob_pad checks its alignment assumption
[samba.git] / source3 / rpc_client / cli_samr.c
blobf5a6b173726e49b458cb96c50f23db98f03ba7fa
1 /*
2 Unix SMB/CIFS implementation.
3 RPC pipe client
4 Copyright (C) Tim Potter 2000-2001,
5 Copyright (C) Andrew Tridgell 1992-1997,2000,
6 Copyright (C) Rafal Szczesniak 2002.
7 Copyright (C) Jeremy Allison 2005.
8 Copyright (C) Guenther Deschner 2008.
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "includes.h"
25 #include "rpc_client/rpc_client.h"
26 #include "../libcli/auth/libcli_auth.h"
27 #include "../librpc/gen_ndr/ndr_samr_c.h"
28 #include "rpc_client/cli_samr.h"
29 #include "rpc_client/init_lsa.h"
30 #include "rpc_client/init_samr.h"
31 #include "librpc/rpc/dcerpc_samr.h"
32 #include "lib/crypto/gnutls_helpers.h"
33 #include <gnutls/gnutls.h>
34 #include <gnutls/crypto.h>
36 /* User change password */
38 NTSTATUS dcerpc_samr_chgpasswd_user(struct dcerpc_binding_handle *h,
39 TALLOC_CTX *mem_ctx,
40 struct policy_handle *user_handle,
41 const char *newpassword,
42 const char *oldpassword,
43 NTSTATUS *presult)
45 NTSTATUS status;
46 int rc;
47 struct samr_Password hash1, hash2, hash3, hash4, hash5, hash6;
49 uint8_t old_nt_hash[16] = {0};
50 uint8_t old_lm_hash[16] = {0};
51 uint8_t new_nt_hash[16] = {0};
52 uint8_t new_lm_hash[16] = {0};
54 DEBUG(10,("rpccli_samr_chgpasswd_user\n"));
56 E_md4hash(oldpassword, old_nt_hash);
57 E_md4hash(newpassword, new_nt_hash);
59 E_deshash(oldpassword, old_lm_hash);
60 E_deshash(newpassword, new_lm_hash);
62 rc = E_old_pw_hash(new_lm_hash, old_lm_hash, hash1.hash);
63 if (rc != 0) {
64 status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
65 goto done;
67 rc = E_old_pw_hash(old_lm_hash, new_lm_hash, hash2.hash);
68 if (rc != 0) {
69 status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
70 goto done;
72 rc = E_old_pw_hash(new_nt_hash, old_nt_hash, hash3.hash);
73 if (rc != 0) {
74 status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
75 goto done;
77 rc = E_old_pw_hash(old_nt_hash, new_nt_hash, hash4.hash);
78 if (rc != 0) {
79 status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
80 goto done;
82 rc = E_old_pw_hash(old_lm_hash, new_nt_hash, hash5.hash);
83 if (rc != 0) {
84 status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
85 goto done;
87 rc = E_old_pw_hash(old_nt_hash, new_lm_hash, hash6.hash);
88 if (rc != 0) {
89 status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
90 goto done;
93 status = dcerpc_samr_ChangePasswordUser(h,
94 mem_ctx,
95 user_handle,
96 true,
97 &hash1,
98 &hash2,
99 true,
100 &hash3,
101 &hash4,
102 true,
103 &hash5,
104 true,
105 &hash6,
106 presult);
108 done:
109 ZERO_ARRAY(old_nt_hash);
110 ZERO_ARRAY(old_lm_hash);
111 ZERO_ARRAY(new_nt_hash);
112 ZERO_ARRAY(new_lm_hash);
114 return status;
117 NTSTATUS rpccli_samr_chgpasswd_user(struct rpc_pipe_client *cli,
118 TALLOC_CTX *mem_ctx,
119 struct policy_handle *user_handle,
120 const char *newpassword,
121 const char *oldpassword)
123 NTSTATUS status;
124 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
126 status = dcerpc_samr_chgpasswd_user(cli->binding_handle,
127 mem_ctx,
128 user_handle,
129 newpassword,
130 oldpassword,
131 &result);
132 if (!NT_STATUS_IS_OK(status)) {
133 return status;
136 return result;
139 /* User change password */
141 NTSTATUS dcerpc_samr_chgpasswd_user2(struct dcerpc_binding_handle *h,
142 TALLOC_CTX *mem_ctx,
143 const char *srv_name_slash,
144 const char *username,
145 const char *newpassword,
146 const char *oldpassword,
147 NTSTATUS *presult)
149 NTSTATUS status;
150 int rc;
151 struct samr_CryptPassword new_nt_password;
152 struct samr_CryptPassword new_lm_password;
153 struct samr_Password old_nt_hash_enc;
154 struct samr_Password old_lanman_hash_enc;
156 uint8_t old_nt_hash[16] = { 0 };
157 uint8_t old_lanman_hash[16];
158 uint8_t new_nt_hash[16];
159 uint8_t new_lanman_hash[16];
160 struct lsa_String server, account;
162 DATA_BLOB session_key = data_blob_const(old_nt_hash, 16);
164 DEBUG(10,("rpccli_samr_chgpasswd_user2\n"));
166 init_lsa_String(&server, srv_name_slash);
167 init_lsa_String(&account, username);
169 /* Calculate the MD4 hash (NT compatible) of the password */
170 E_md4hash(oldpassword, old_nt_hash);
171 E_md4hash(newpassword, new_nt_hash);
173 if (lp_client_lanman_auth() &&
174 E_deshash(newpassword, new_lanman_hash) &&
175 E_deshash(oldpassword, old_lanman_hash)) {
176 /* E_deshash returns false for 'long' passwords (> 14
177 DOS chars). This allows us to match Win2k, which
178 does not store a LM hash for these passwords (which
179 would reduce the effective password length to 14) */
180 status = init_samr_CryptPassword(newpassword,
181 &session_key,
182 &new_lm_password);
183 if (!NT_STATUS_IS_OK(status)) {
184 return status;
187 rc = E_old_pw_hash(new_nt_hash, old_lanman_hash, old_lanman_hash_enc.hash);
188 if (rc != 0) {
189 status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
190 goto done;
192 } else {
193 ZERO_STRUCT(new_lm_password);
194 ZERO_STRUCT(old_lanman_hash_enc);
197 status = init_samr_CryptPassword(newpassword,
198 &session_key,
199 &new_nt_password);
200 if (!NT_STATUS_IS_OK(status)) {
201 return status;
203 rc = E_old_pw_hash(new_nt_hash, old_nt_hash, old_nt_hash_enc.hash);
204 if (rc != 0) {
205 status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
206 goto done;
209 status = dcerpc_samr_ChangePasswordUser2(h,
210 mem_ctx,
211 &server,
212 &account,
213 &new_nt_password,
214 &old_nt_hash_enc,
215 true,
216 &new_lm_password,
217 &old_lanman_hash_enc,
218 presult);
220 done:
221 ZERO_STRUCT(new_nt_password);
222 ZERO_STRUCT(new_lm_password);
223 ZERO_STRUCT(old_nt_hash_enc);
224 ZERO_STRUCT(old_lanman_hash_enc);
225 ZERO_ARRAY(new_nt_hash);
226 ZERO_ARRAY(new_lanman_hash);
227 ZERO_ARRAY(old_nt_hash);
228 ZERO_ARRAY(old_lanman_hash);
230 return status;
233 NTSTATUS rpccli_samr_chgpasswd_user2(struct rpc_pipe_client *cli,
234 TALLOC_CTX *mem_ctx,
235 const char *username,
236 const char *newpassword,
237 const char *oldpassword)
239 NTSTATUS status;
240 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
242 status = dcerpc_samr_chgpasswd_user2(cli->binding_handle,
243 mem_ctx,
244 cli->srv_name_slash,
245 username,
246 newpassword,
247 oldpassword,
248 &result);
249 if (!NT_STATUS_IS_OK(status)) {
250 return status;
253 return result;
256 /* User change password given blobs */
258 NTSTATUS dcerpc_samr_chng_pswd_auth_crap(struct dcerpc_binding_handle *h,
259 TALLOC_CTX *mem_ctx,
260 const char *srv_name_slash,
261 const char *username,
262 DATA_BLOB new_nt_password_blob,
263 DATA_BLOB old_nt_hash_enc_blob,
264 DATA_BLOB new_lm_password_blob,
265 DATA_BLOB old_lm_hash_enc_blob,
266 NTSTATUS *presult)
268 NTSTATUS status;
269 struct samr_CryptPassword new_nt_password;
270 struct samr_CryptPassword new_lm_password;
271 struct samr_Password old_nt_hash_enc;
272 struct samr_Password old_lm_hash_enc;
273 struct lsa_String server, account;
275 DEBUG(10,("rpccli_samr_chng_pswd_auth_crap\n"));
277 ZERO_STRUCT(new_nt_password);
278 ZERO_STRUCT(new_lm_password);
279 ZERO_STRUCT(old_nt_hash_enc);
280 ZERO_STRUCT(old_lm_hash_enc);
282 init_lsa_String(&server, srv_name_slash);
283 init_lsa_String(&account, username);
285 if (new_nt_password_blob.data && new_nt_password_blob.length >= 516) {
286 memcpy(&new_nt_password.data, new_nt_password_blob.data, 516);
289 if (new_lm_password_blob.data && new_lm_password_blob.length >= 516) {
290 memcpy(&new_lm_password.data, new_lm_password_blob.data, 516);
293 if (old_nt_hash_enc_blob.data && old_nt_hash_enc_blob.length >= 16) {
294 memcpy(&old_nt_hash_enc.hash, old_nt_hash_enc_blob.data, 16);
297 if (old_lm_hash_enc_blob.data && old_lm_hash_enc_blob.length >= 16) {
298 memcpy(&old_lm_hash_enc.hash, old_lm_hash_enc_blob.data, 16);
301 status = dcerpc_samr_ChangePasswordUser2(h,
302 mem_ctx,
303 &server,
304 &account,
305 &new_nt_password,
306 &old_nt_hash_enc,
307 true,
308 &new_lm_password,
309 &old_lm_hash_enc,
310 presult);
312 return status;
315 NTSTATUS rpccli_samr_chng_pswd_auth_crap(struct rpc_pipe_client *cli,
316 TALLOC_CTX *mem_ctx,
317 const char *username,
318 DATA_BLOB new_nt_password_blob,
319 DATA_BLOB old_nt_hash_enc_blob,
320 DATA_BLOB new_lm_password_blob,
321 DATA_BLOB old_lm_hash_enc_blob)
323 NTSTATUS status;
324 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
326 status = dcerpc_samr_chng_pswd_auth_crap(cli->binding_handle,
327 mem_ctx,
328 cli->srv_name_slash,
329 username,
330 new_nt_password_blob,
331 old_nt_hash_enc_blob,
332 new_lm_password_blob,
333 old_lm_hash_enc_blob,
334 &result);
335 if (!NT_STATUS_IS_OK(status)) {
336 return status;
339 return result;
342 /* change password 3 */
344 NTSTATUS dcerpc_samr_chgpasswd_user3(struct dcerpc_binding_handle *h,
345 TALLOC_CTX *mem_ctx,
346 const char *srv_name_slash,
347 const char *username,
348 const char *newpassword,
349 const char *oldpassword,
350 struct samr_DomInfo1 **dominfo1,
351 struct userPwdChangeFailureInformation **reject,
352 NTSTATUS *presult)
354 NTSTATUS status;
355 int rc;
357 struct samr_CryptPassword new_nt_password;
358 struct samr_CryptPassword new_lm_password;
359 struct samr_Password old_nt_hash_enc;
360 struct samr_Password old_lanman_hash_enc;
362 uint8_t old_nt_hash[16] = { 0 };
363 uint8_t old_lanman_hash[16];
364 uint8_t new_nt_hash[16];
365 uint8_t new_lanman_hash[16];
367 struct lsa_String server, account;
369 DATA_BLOB session_key = data_blob_const(old_nt_hash, 16);
371 DEBUG(10,("rpccli_samr_chgpasswd_user3\n"));
373 init_lsa_String(&server, srv_name_slash);
374 init_lsa_String(&account, username);
376 /* Calculate the MD4 hash (NT compatible) of the password */
377 E_md4hash(oldpassword, old_nt_hash);
378 E_md4hash(newpassword, new_nt_hash);
380 if (lp_client_lanman_auth() &&
381 E_deshash(newpassword, new_lanman_hash) &&
382 E_deshash(oldpassword, old_lanman_hash)) {
383 /* E_deshash returns false for 'long' passwords (> 14
384 DOS chars). This allows us to match Win2k, which
385 does not store a LM hash for these passwords (which
386 would reduce the effective password length to 14) */
387 status = init_samr_CryptPassword(newpassword,
388 &session_key,
389 &new_lm_password);
390 if (!NT_STATUS_IS_OK(status)) {
391 return status;
394 rc = E_old_pw_hash(new_nt_hash, old_lanman_hash, old_lanman_hash_enc.hash);
395 if (rc != 0) {
396 status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
397 goto done;
399 } else {
400 ZERO_STRUCT(new_lm_password);
401 ZERO_STRUCT(old_lanman_hash_enc);
404 status = init_samr_CryptPassword(newpassword,
405 &session_key,
406 &new_nt_password);
407 if (!NT_STATUS_IS_OK(status)) {
408 return status;
411 rc = E_old_pw_hash(new_nt_hash, old_nt_hash, old_nt_hash_enc.hash);
412 if (rc != 0) {
413 status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
414 goto done;
417 status = dcerpc_samr_ChangePasswordUser3(h,
418 mem_ctx,
419 &server,
420 &account,
421 &new_nt_password,
422 &old_nt_hash_enc,
423 true,
424 &new_lm_password,
425 &old_lanman_hash_enc,
426 NULL,
427 dominfo1,
428 reject,
429 presult);
431 done:
432 ZERO_STRUCT(new_nt_password);
433 ZERO_STRUCT(new_lm_password);
434 ZERO_STRUCT(old_nt_hash_enc);
435 ZERO_STRUCT(old_lanman_hash_enc);
436 ZERO_ARRAY(new_nt_hash);
437 ZERO_ARRAY(new_lanman_hash);
438 ZERO_ARRAY(old_nt_hash);
439 ZERO_ARRAY(old_lanman_hash);
441 return status;
444 NTSTATUS rpccli_samr_chgpasswd_user3(struct rpc_pipe_client *cli,
445 TALLOC_CTX *mem_ctx,
446 const char *username,
447 const char *newpassword,
448 const char *oldpassword,
449 struct samr_DomInfo1 **dominfo1,
450 struct userPwdChangeFailureInformation **reject)
452 NTSTATUS status;
453 NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
455 status = dcerpc_samr_chgpasswd_user3(cli->binding_handle,
456 mem_ctx,
457 cli->srv_name_slash,
458 username,
459 newpassword,
460 oldpassword,
461 dominfo1,
462 reject,
463 &result);
464 if (!NT_STATUS_IS_OK(status)) {
465 return status;
468 return result;
471 NTSTATUS dcerpc_samr_chgpasswd_user4(struct dcerpc_binding_handle *h,
472 TALLOC_CTX *mem_ctx,
473 const char *srv_name_slash,
474 const char *username,
475 const char *oldpassword,
476 const char *newpassword,
477 NTSTATUS *presult)
479 struct lsa_String server, user_account;
480 uint8_t old_nt_key_data[16] = {0};
481 gnutls_datum_t old_nt_key = {
482 .data = old_nt_key_data,
483 .size = sizeof(old_nt_key),
485 struct samr_EncryptedPasswordAES pwd_buf = {
486 .cipher_len = 0,
488 DATA_BLOB iv = {
489 .data = pwd_buf.salt,
490 .length = sizeof(pwd_buf.salt),
492 gnutls_datum_t iv_datum = {
493 .data = iv.data,
494 .size = iv.length,
496 uint8_t cek_data[16] = {0};
497 DATA_BLOB cek = {
498 .data = cek_data,
499 .length = sizeof(cek_data),
501 uint64_t pbkdf2_iterations = 0;
502 uint8_t pw_data[514] = {0};
503 DATA_BLOB plaintext = {
504 .data = pw_data,
505 .length = sizeof(pw_data),
507 DATA_BLOB ciphertext = data_blob_null;
508 NTSTATUS status;
509 bool ok;
510 int rc;
512 generate_nonce_buffer(iv.data, iv.length);
514 /* Calculate the MD4 hash (NT compatible) of the password */
515 E_md4hash(oldpassword, old_nt_key_data);
517 init_lsa_String(&server, srv_name_slash);
518 init_lsa_String(&user_account, username);
520 pbkdf2_iterations = generate_random_u64_range(5000, 1000000);
522 rc = gnutls_pbkdf2(GNUTLS_MAC_SHA512,
523 &old_nt_key,
524 &iv_datum,
525 pbkdf2_iterations,
526 cek.data,
527 cek.length);
528 BURN_DATA(old_nt_key_data);
529 if (rc < 0) {
530 status = gnutls_error_to_ntstatus(rc, NT_STATUS_WRONG_PASSWORD);
531 return status;
534 ok = encode_pwd_buffer514_from_str(pw_data, newpassword, STR_UNICODE);
535 if (!ok) {
536 return NT_STATUS_INTERNAL_ERROR;
539 status = samba_gnutls_aead_aes_256_cbc_hmac_sha512_encrypt(
540 mem_ctx,
541 &plaintext,
542 &cek,
543 &samr_aes256_enc_key_salt,
544 &samr_aes256_mac_key_salt,
545 &iv,
546 &ciphertext,
547 pwd_buf.auth_data);
548 BURN_DATA(pw_data);
549 BURN_DATA(cek_data);
550 if (!NT_STATUS_IS_OK(status)) {
551 return status;
554 pwd_buf.cipher_len = ciphertext.length;
555 pwd_buf.cipher = ciphertext.data;
556 pwd_buf.PBKDF2Iterations = pbkdf2_iterations;
558 status = dcerpc_samr_ChangePasswordUser4(h,
559 mem_ctx,
560 &server,
561 &user_account,
562 &pwd_buf,
563 presult);
564 data_blob_free(&ciphertext);
566 return status;
569 /* This function returns the bizarre set of (max_entries, max_size) required
570 for the QueryDisplayInfo RPC to actually work against a domain controller
571 with large (10k and higher) numbers of users. These values were
572 obtained by inspection using ethereal and NT4 running User Manager. */
574 void dcerpc_get_query_dispinfo_params(int loop_count,
575 uint32_t *max_entries,
576 uint32_t *max_size)
578 switch(loop_count) {
579 case 0:
580 *max_entries = 512;
581 *max_size = 16383;
582 break;
583 case 1:
584 *max_entries = 1024;
585 *max_size = 32766;
586 break;
587 case 2:
588 *max_entries = 2048;
589 *max_size = 65532;
590 break;
591 case 3:
592 *max_entries = 4096;
593 *max_size = 131064;
594 break;
595 default: /* loop_count >= 4 */
596 *max_entries = 4096;
597 *max_size = 131071;
598 break;
602 NTSTATUS dcerpc_try_samr_connects(struct dcerpc_binding_handle *h,
603 TALLOC_CTX *mem_ctx,
604 const char *srv_name_slash,
605 uint32_t access_mask,
606 struct policy_handle *connect_pol,
607 NTSTATUS *presult)
609 NTSTATUS status;
610 union samr_ConnectInfo info_in, info_out;
611 struct samr_ConnectInfo1 info1;
612 uint32_t lvl_out = 0;
614 ZERO_STRUCT(info1);
616 info1.client_version = SAMR_CONNECT_W2K;
617 info_in.info1 = info1;
619 status = dcerpc_samr_Connect5(h,
620 mem_ctx,
621 srv_name_slash,
622 access_mask,
624 &info_in,
625 &lvl_out,
626 &info_out,
627 connect_pol,
628 presult);
629 if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(*presult)) {
630 return status;
633 status = dcerpc_samr_Connect4(h,
634 mem_ctx,
635 srv_name_slash,
636 SAMR_CONNECT_W2K,
637 access_mask,
638 connect_pol,
639 presult);
640 if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(*presult)) {
641 return status;
644 status = dcerpc_samr_Connect2(h,
645 mem_ctx,
646 srv_name_slash,
647 access_mask,
648 connect_pol,
649 presult);
651 return status;
654 /* vim: set ts=8 sw=8 noet cindent: */