auth: Fix CID 1615191 Uninitialized scalar variable
[samba.git] / source3 / rpc_client / cli_samr.c
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.
9
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.
14
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.
19
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/>.
22 */
23
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>
35
36 /* User change password */
37
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)
44 {
45         NTSTATUS status;
46         int rc;
47         struct samr_Password hash1, hash2, hash3, hash4, hash5, hash6;
48
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};
53
54         DEBUG(10,("rpccli_samr_chgpasswd_user\n"));
55
56         E_md4hash(oldpassword, old_nt_hash);
57         E_md4hash(newpassword, new_nt_hash);
58
59         E_deshash(oldpassword, old_lm_hash);
60         E_deshash(newpassword, new_lm_hash);
61
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;
66         }
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;
71         }
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;
76         }
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;
81         }
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;
86         }
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;
91         }
92
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);
107
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);
113
114         return status;
115 }
116
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)
122 {
123         NTSTATUS status;
124         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
125
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;
134         }
135
136         return result;
137 }
138
139 /* User change password */
140
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)
148 {
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;
155
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;
161
162         DATA_BLOB session_key = data_blob_const(old_nt_hash, 16);
163
164         DEBUG(10,("rpccli_samr_chgpasswd_user2\n"));
165
166         init_lsa_String(&server, srv_name_slash);
167         init_lsa_String(&account, username);
168
169         /* Calculate the MD4 hash (NT compatible) of the password */
170         E_md4hash(oldpassword, old_nt_hash);
171         E_md4hash(newpassword, new_nt_hash);
172
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;
185                 }
186
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;
191                 }
192         } else {
193                 ZERO_STRUCT(new_lm_password);
194                 ZERO_STRUCT(old_lanman_hash_enc);
195         }
196
197         status = init_samr_CryptPassword(newpassword,
198                                          &session_key,
199                                          &new_nt_password);
200         if (!NT_STATUS_IS_OK(status)) {
201                 return status;
202         }
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;
207         }
208
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);
219
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);
229
230         return status;
231 }
232
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)
238 {
239         NTSTATUS status;
240         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
241
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;
251         }
252
253         return result;
254 }
255
256 /* User change password given blobs */
257
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)
267 {
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;
274
275         DEBUG(10,("rpccli_samr_chng_pswd_auth_crap\n"));
276
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);
281
282         init_lsa_String(&server, srv_name_slash);
283         init_lsa_String(&account, username);
284
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);
287         }
288
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);
291         }
292
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);
295         }
296
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);
299         }
300
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);
311
312         return status;
313 }
314
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)
322 {
323         NTSTATUS status;
324         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
325
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;
337         }
338
339         return result;
340 }
341
342 /* change password 3 */
343
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)
353 {
354         NTSTATUS status;
355         int rc;
356
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;
361
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];
366
367         struct lsa_String server, account;
368
369         DATA_BLOB session_key = data_blob_const(old_nt_hash, 16);
370
371         DEBUG(10,("rpccli_samr_chgpasswd_user3\n"));
372
373         init_lsa_String(&server, srv_name_slash);
374         init_lsa_String(&account, username);
375
376         /* Calculate the MD4 hash (NT compatible) of the password */
377         E_md4hash(oldpassword, old_nt_hash);
378         E_md4hash(newpassword, new_nt_hash);
379
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;
392                 }
393
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;
398                 }
399         } else {
400                 ZERO_STRUCT(new_lm_password);
401                 ZERO_STRUCT(old_lanman_hash_enc);
402         }
403
404         status = init_samr_CryptPassword(newpassword,
405                                          &session_key,
406                                          &new_nt_password);
407         if (!NT_STATUS_IS_OK(status)) {
408                 return status;
409         }
410
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;
415         }
416
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);
430
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);
440
441         return status;
442 }
443
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)
451 {
452         NTSTATUS status;
453         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
454
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;
466         }
467
468         return result;
469 }
470
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)
478 {
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),
484         };
485         struct samr_EncryptedPasswordAES pwd_buf = {
486                 .cipher_len = 0,
487         };
488         DATA_BLOB iv = {
489                 .data = pwd_buf.salt,
490                 .length = sizeof(pwd_buf.salt),
491         };
492         gnutls_datum_t iv_datum = {
493                 .data = iv.data,
494                 .size = iv.length,
495         };
496         uint8_t cek_data[16] = {0};
497         DATA_BLOB cek = {
498                 .data = cek_data,
499                 .length = sizeof(cek_data),
500         };
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),
506         };
507         DATA_BLOB ciphertext = data_blob_null;
508         NTSTATUS status;
509         bool ok;
510         int rc;
511
512         generate_nonce_buffer(iv.data, iv.length);
513
514         /* Calculate the MD4 hash (NT compatible) of the password */
515         E_md4hash(oldpassword, old_nt_key_data);
516
517         init_lsa_String(&server, srv_name_slash);
518         init_lsa_String(&user_account, username);
519
520         pbkdf2_iterations = generate_random_u64_range(5000, 1000000);
521
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;
532         }
533
534         ok = encode_pwd_buffer514_from_str(pw_data, newpassword, STR_UNICODE);
535         if (!ok) {
536                 return NT_STATUS_INTERNAL_ERROR;
537         }
538
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;
552         }
553
554         pwd_buf.cipher_len = ciphertext.length;
555         pwd_buf.cipher = ciphertext.data;
556         pwd_buf.PBKDF2Iterations = pbkdf2_iterations;
557
558         status = dcerpc_samr_ChangePasswordUser4(h,
559                                                  mem_ctx,
560                                                  &server,
561                                                  &user_account,
562                                                  &pwd_buf,
563                                                  presult);
564         data_blob_free(&ciphertext);
565
566         return status;
567 }
568
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. */
573
574 void dcerpc_get_query_dispinfo_params(int loop_count,
575                                       uint32_t *max_entries,
576                                       uint32_t *max_size)
577 {
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;
599         }
600 }
601
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)
608 {
609         NTSTATUS status;
610         union samr_ConnectInfo info_in, info_out;
611         struct samr_ConnectInfo1 info1;
612         uint32_t lvl_out = 0;
613
614         ZERO_STRUCT(info1);
615
616         info1.client_version = SAMR_CONNECT_W2K;
617         info_in.info1 = info1;
618
619         status = dcerpc_samr_Connect5(h,
620                                       mem_ctx,
621                                       srv_name_slash,
622                                       access_mask,
623                                       1,
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;
631         }
632
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;
642         }
643
644         status = dcerpc_samr_Connect2(h,
645                                       mem_ctx,
646                                       srv_name_slash,
647                                       access_mask,
648                                       connect_pol,
649                                       presult);
650
651         return status;
652 }
653
654 /* vim: set ts=8 sw=8 noet cindent: */