s3:utils: let smbstatus report anonymous signing/encryption explicitly
[samba.git] / source4 / libnet / libnet_passwd.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Copyright (C) Stefan Metzmacher      2004
5    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "libnet/libnet.h"
23 #include "libcli/auth/libcli_auth.h"
24 #include "librpc/gen_ndr/ndr_samr_c.h"
25 #include "source4/librpc/rpc/dcerpc.h"
26 #include "auth/credentials/credentials.h"
27 #include "libcli/smb/smb_constants.h"
28 #include "librpc/rpc/dcerpc_samr.h"
29 #include "source3/rpc_client/init_samr.h"
30 #include "lib/param/loadparm.h"
31 #include "lib/param/param.h"
32
33 #include "lib/crypto/gnutls_helpers.h"
34 #include <gnutls/gnutls.h>
35 #include <gnutls/crypto.h>
36
37 static NTSTATUS libnet_ChangePassword_samr_aes(TALLOC_CTX *mem_ctx,
38                                                struct dcerpc_binding_handle *h,
39                                                struct lsa_String *server,
40                                                struct lsa_String *account,
41                                                const char *old_password,
42                                                const char *new_password,
43                                                const char **error_string)
44 {
45         struct samr_ChangePasswordUser4 r;
46         uint8_t old_nt_key_data[16] = {0};
47         gnutls_datum_t old_nt_key = {
48                 .data = old_nt_key_data,
49                 .size = sizeof(old_nt_key_data),
50         };
51         uint8_t cek_data[16] = {0};
52         DATA_BLOB cek = {
53                 .data = cek_data,
54                 .length = sizeof(cek_data),
55         };
56         struct samr_EncryptedPasswordAES pwd_buf = {
57                 .cipher_len = 0
58         };
59         DATA_BLOB salt = {
60                 .data = pwd_buf.salt,
61                 .length = sizeof(pwd_buf.salt),
62         };
63         gnutls_datum_t salt_datum = {
64                 .data = pwd_buf.salt,
65                 .size = sizeof(pwd_buf.salt),
66         };
67         uint64_t pbkdf2_iterations = generate_random_u64_range(5000, 1000000);
68         NTSTATUS status;
69         int rc;
70
71         E_md4hash(old_password, old_nt_key_data);
72
73         generate_nonce_buffer(salt.data, salt.length);
74
75         rc = gnutls_pbkdf2(GNUTLS_MAC_SHA512,
76                            &old_nt_key,
77                            &salt_datum,
78                            pbkdf2_iterations,
79                            cek.data,
80                            cek.length);
81         BURN_DATA(old_nt_key_data);
82         if (rc < 0) {
83                 status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
84                 if (!NT_STATUS_IS_OK(status)) {
85                         goto done;
86                 }
87         }
88
89         status = init_samr_CryptPasswordAES(mem_ctx,
90                                             new_password,
91                                             &salt,
92                                             &cek,
93                                             &pwd_buf);
94         data_blob_clear(&cek);
95         if (!NT_STATUS_IS_OK(status)) {
96                 goto done;
97         }
98
99         pwd_buf.PBKDF2Iterations = pbkdf2_iterations;
100
101         r.in.server = server;
102         r.in.account = account;
103         r.in.password = &pwd_buf;
104
105         status = dcerpc_samr_ChangePasswordUser4_r(h, mem_ctx, &r);
106         if (!NT_STATUS_IS_OK(status)) {
107                 goto done;
108         }
109         if (!NT_STATUS_IS_OK(r.out.result)) {
110                 status = r.out.result;
111                 *error_string = talloc_asprintf(mem_ctx,
112                                                 "samr_ChangePasswordUser4 for "
113                                                 "'%s\\%s' failed: %s",
114                                                 server->string,
115                                                 account->string,
116                                                 nt_errstr(status));
117                 goto done;
118         }
119
120 done:
121         BURN_DATA(pwd_buf);
122
123         return status;
124 }
125
126 static NTSTATUS libnet_ChangePassword_samr_rc4(TALLOC_CTX *mem_ctx,
127                                                struct dcerpc_binding_handle *h,
128                                                struct lsa_String *server,
129                                                struct lsa_String *account,
130                                                const char *old_password,
131                                                const char *new_password,
132                                                const char **error_string)
133 {
134         struct samr_OemChangePasswordUser2 oe2;
135         struct samr_ChangePasswordUser2 pw2;
136         struct samr_ChangePasswordUser3 pw3;
137         struct samr_CryptPassword nt_pass, lm_pass;
138         uint8_t old_nt_hash[16], new_nt_hash[16];
139         uint8_t old_lm_hash[16], new_lm_hash[16];
140         struct samr_Password nt_verifier, lm_verifier;
141         struct lsa_AsciiString a_server, a_account;
142         gnutls_cipher_hd_t cipher_hnd = NULL;
143         gnutls_datum_t nt_session_key = {
144                 .data = old_nt_hash,
145                 .size = sizeof(old_nt_hash),
146         };
147         gnutls_datum_t lm_session_key = {
148                 .data = old_lm_hash,
149                 .size = sizeof(old_lm_hash),
150         };
151         struct samr_DomInfo1 *dominfo = NULL;
152         struct userPwdChangeFailureInformation *reject = NULL;
153         NTSTATUS status;
154         int rc;
155
156         E_md4hash(old_password, old_nt_hash);
157         E_md4hash(new_password, new_nt_hash);
158
159         E_deshash(old_password, old_lm_hash);
160         E_deshash(new_password, new_lm_hash);
161
162         /* prepare samr_ChangePasswordUser3 */
163         encode_pw_buffer(lm_pass.data, new_password, STR_UNICODE);
164
165         rc = gnutls_cipher_init(&cipher_hnd,
166                                 GNUTLS_CIPHER_ARCFOUR_128,
167                                 &nt_session_key,
168                                 NULL);
169         if (rc < 0) {
170                 status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
171                 goto done;
172         }
173
174         rc = gnutls_cipher_encrypt(cipher_hnd,
175                                    lm_pass.data,
176                                    516);
177         gnutls_cipher_deinit(cipher_hnd);
178         if (rc < 0) {
179                 status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
180                 goto done;
181         }
182
183         rc = E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash);
184         if (rc != 0) {
185                 status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
186                 goto done;
187         }
188
189         encode_pw_buffer(nt_pass.data, new_password, STR_UNICODE);
190
191         rc = gnutls_cipher_init(&cipher_hnd,
192                                 GNUTLS_CIPHER_ARCFOUR_128,
193                                 &nt_session_key,
194                                 NULL);
195         if (rc < 0) {
196                 status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
197                 goto done;
198         }
199
200         rc = gnutls_cipher_encrypt(cipher_hnd,
201                                    nt_pass.data,
202                                    516);
203         gnutls_cipher_deinit(cipher_hnd);
204         if (rc < 0) {
205                 status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
206                 goto done;
207         }
208
209         rc = E_old_pw_hash(new_nt_hash, old_nt_hash, nt_verifier.hash);
210         if (rc != 0) {
211                 status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
212                 goto done;
213         }
214
215         pw3.in.server = server;
216         pw3.in.account = account;
217         pw3.in.nt_password = &nt_pass;
218         pw3.in.nt_verifier = &nt_verifier;
219         pw3.in.lm_change = 1;
220         pw3.in.lm_password = &lm_pass;
221         pw3.in.lm_verifier = &lm_verifier;
222         pw3.in.password3 = NULL;
223         pw3.out.dominfo = &dominfo;
224         pw3.out.reject = &reject;
225
226         /* 2. try samr_ChangePasswordUser3 */
227         status = dcerpc_samr_ChangePasswordUser3_r(h, mem_ctx, &pw3);
228         if (!NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
229                 if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(pw3.out.result)) {
230                         status = pw3.out.result;
231                 }
232                 if (!NT_STATUS_IS_OK(status)) {
233                         *error_string = talloc_asprintf(
234                                 mem_ctx,
235                                 "samr_ChangePasswordUser3 failed: %s",
236                                 nt_errstr(status));
237                         *error_string =
238                                 talloc_asprintf(mem_ctx,
239                                                 "samr_ChangePasswordUser3 for "
240                                                 "'%s\\%s' failed: %s",
241                                                 server->string,
242                                                 account->string,
243                                                 nt_errstr(status));
244                 }
245                 goto done;
246         }
247
248         /* prepare samr_ChangePasswordUser2 */
249         encode_pw_buffer(lm_pass.data, new_password, STR_ASCII | STR_TERMINATE);
250
251         rc = gnutls_cipher_init(&cipher_hnd,
252                                 GNUTLS_CIPHER_ARCFOUR_128,
253                                 &lm_session_key,
254                                 NULL);
255         if (rc < 0) {
256                 status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
257                 goto done;
258         }
259
260         rc = gnutls_cipher_encrypt(cipher_hnd,
261                                    lm_pass.data,
262                                    516);
263         gnutls_cipher_deinit(cipher_hnd);
264         if (rc < 0) {
265                 status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
266                 goto done;
267         }
268
269         rc = E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash);
270         if (rc != 0) {
271                 status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
272                 goto done;
273         }
274
275         encode_pw_buffer(nt_pass.data, new_password, STR_UNICODE);
276
277         rc = gnutls_cipher_init(&cipher_hnd,
278                                 GNUTLS_CIPHER_ARCFOUR_128,
279                                 &nt_session_key,
280                                 NULL);
281         if (rc < 0) {
282                 status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
283                 goto done;
284         }
285         rc = gnutls_cipher_encrypt(cipher_hnd,
286                                    nt_pass.data,
287                                    516);
288         gnutls_cipher_deinit(cipher_hnd);
289         if (rc < 0) {
290                 status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
291                 goto done;
292         }
293
294         rc = E_old_pw_hash(new_nt_hash, old_nt_hash, nt_verifier.hash);
295         if (rc != 0) {
296                 status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
297                 goto done;
298         }
299
300         pw2.in.server = server;
301         pw2.in.account = account;
302         pw2.in.nt_password = &nt_pass;
303         pw2.in.nt_verifier = &nt_verifier;
304         pw2.in.lm_change = 1;
305         pw2.in.lm_password = &lm_pass;
306         pw2.in.lm_verifier = &lm_verifier;
307
308         /* 3. try samr_ChangePasswordUser2 */
309         status = dcerpc_samr_ChangePasswordUser2_r(h, mem_ctx, &pw2);
310         if (!NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
311                 if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(pw2.out.result)) {
312                         status = pw2.out.result;
313                 }
314                 if (!NT_STATUS_IS_OK(status)) {
315                         *error_string =
316                                 talloc_asprintf(mem_ctx,
317                                                 "samr_ChangePasswordUser2 for "
318                                                 "'%s\\%s' failed: %s",
319                                                 server->string,
320                                                 account->string,
321                                                 nt_errstr(status));
322                 }
323                 goto done;
324         }
325
326
327         /* prepare samr_OemChangePasswordUser2 */
328         a_server.string = server->string;
329         a_account.string = account->string;
330
331         encode_pw_buffer(lm_pass.data, new_password, STR_ASCII);
332
333         rc = gnutls_cipher_init(&cipher_hnd,
334                                 GNUTLS_CIPHER_ARCFOUR_128,
335                                 &lm_session_key,
336                                 NULL);
337         if (rc < 0) {
338                 status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
339                 goto done;
340         }
341
342         rc = gnutls_cipher_encrypt(cipher_hnd,
343                                    lm_pass.data,
344                                    516);
345         gnutls_cipher_deinit(cipher_hnd);
346         if (rc < 0) {
347                 status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
348                 goto done;
349         }
350
351         rc = E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash);
352         if (rc != 0) {
353                 status = gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
354                 goto done;
355         }
356
357         oe2.in.server = &a_server;
358         oe2.in.account = &a_account;
359         oe2.in.password = &lm_pass;
360         oe2.in.hash = &lm_verifier;
361
362         /* 4. try samr_OemChangePasswordUser2 */
363         status = dcerpc_samr_OemChangePasswordUser2_r(h, mem_ctx, &oe2);
364         if (!NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
365                 if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(oe2.out.result)) {
366                         status = oe2.out.result;
367                 }
368                 if (!NT_STATUS_IS_OK(oe2.out.result)) {
369                         *error_string =
370                                 talloc_asprintf(mem_ctx,
371                                                 "samr_OemChangePasswordUser2 "
372                                                 "for '%s\\%s' failed: %s",
373                                                 server->string,
374                                                 account->string,
375                                                 nt_errstr(status));
376                 }
377                 goto done;
378         }
379
380         status = NT_STATUS_OK;
381 done:
382         return status;
383 }
384
385 /*
386  * do a password change using DCERPC/SAMR calls
387  * 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation)
388  * 2. try samr_ChangePasswordUser3
389  * 3. try samr_ChangePasswordUser2
390  * 4. try samr_OemChangePasswordUser2
391  */
392 static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_ChangePassword *r)
393 {
394         NTSTATUS status;
395         struct libnet_RpcConnect c;
396         struct lsa_String server, account;
397
398         ZERO_STRUCT(c);
399
400         /* prepare connect to the SAMR pipe of the users domain PDC */
401         c.level                    = LIBNET_RPC_CONNECT_PDC;
402         c.in.name                  = r->samr.in.domain_name;
403         c.in.dcerpc_iface          = &ndr_table_samr;
404         c.in.dcerpc_flags          = DCERPC_ANON_FALLBACK;
405
406         /* 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) */
407         status = libnet_RpcConnect(ctx, mem_ctx, &c);
408         if (!NT_STATUS_IS_OK(status)) {
409                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
410                                                 "Connection to SAMR pipe of PDC of domain '%s' failed: %s",
411                                                 r->samr.in.domain_name, nt_errstr(status));
412                 return status;
413         }
414
415         /* prepare password change for account */
416         server.string = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(c.out.dcerpc_pipe));
417         account.string = r->samr.in.account_name;
418
419         status = libnet_ChangePassword_samr_aes(
420                 mem_ctx,
421                 c.out.dcerpc_pipe->binding_handle,
422                 &server,
423                 &account,
424                 r->samr.in.oldpassword,
425                 r->samr.in.newpassword,
426                 &(r->samr.out.error_string));
427         if (NT_STATUS_IS_OK(status)) {
428                 goto disconnect;
429         } else if (NT_STATUS_EQUAL(status,
430                                    NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE) ||
431                    NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED) ||
432                    NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
433                 /*
434                  * Don't fallback to RC4 based SAMR if weak crypto is not
435                  * allowed.
436                  */
437                 if (lpcfg_weak_crypto(ctx->lp_ctx) ==
438                     SAMBA_WEAK_CRYPTO_DISALLOWED) {
439                         goto disconnect;
440                 }
441         } else {
442                 /* libnet_ChangePassword_samr_aes is implemented and failed */
443                 goto disconnect;
444         }
445
446         status = libnet_ChangePassword_samr_rc4(
447                 mem_ctx,
448                 c.out.dcerpc_pipe->binding_handle,
449                 &server,
450                 &account,
451                 r->samr.in.oldpassword,
452                 r->samr.in.newpassword,
453                 &(r->samr.out.error_string));
454         if (!NT_STATUS_IS_OK(status)) {
455                 goto disconnect;
456         }
457
458 disconnect:
459         /* close connection */
460         talloc_unlink(ctx, c.out.dcerpc_pipe);
461
462         return status;
463 }
464
465 static NTSTATUS libnet_ChangePassword_generic(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_ChangePassword *r)
466 {
467         NTSTATUS status;
468         union libnet_ChangePassword r2;
469
470         r2.samr.level           = LIBNET_CHANGE_PASSWORD_SAMR;
471         r2.samr.in.account_name = r->generic.in.account_name;
472         r2.samr.in.domain_name  = r->generic.in.domain_name;
473         r2.samr.in.oldpassword  = r->generic.in.oldpassword;
474         r2.samr.in.newpassword  = r->generic.in.newpassword;
475
476         status = libnet_ChangePassword(ctx, mem_ctx, &r2);
477
478         r->generic.out.error_string = r2.samr.out.error_string;
479
480         return status;
481 }
482
483 NTSTATUS libnet_ChangePassword(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_ChangePassword *r)
484 {
485         switch (r->generic.level) {
486                 case LIBNET_CHANGE_PASSWORD_GENERIC:
487                         return libnet_ChangePassword_generic(ctx, mem_ctx, r);
488                 case LIBNET_CHANGE_PASSWORD_SAMR:
489                         return libnet_ChangePassword_samr(ctx, mem_ctx, r);
490                 case LIBNET_CHANGE_PASSWORD_KRB5:
491                         return NT_STATUS_NOT_IMPLEMENTED;
492                 case LIBNET_CHANGE_PASSWORD_LDAP:
493                         return NT_STATUS_NOT_IMPLEMENTED;
494                 case LIBNET_CHANGE_PASSWORD_RAP:
495                         return NT_STATUS_NOT_IMPLEMENTED;
496         }
497
498         return NT_STATUS_INVALID_LEVEL;
499 }
500
501 static NTSTATUS libnet_SetPassword_samr_handle_26(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
502 {
503         NTSTATUS status;
504         struct samr_SetUserInfo2 sui;
505         union samr_UserInfo u_info;
506         DATA_BLOB session_key;
507
508         if (r->samr_handle.in.info21) {
509                 return NT_STATUS_INVALID_PARAMETER_MIX;
510         }
511
512         /* prepare samr_SetUserInfo2 level 26 */
513         ZERO_STRUCT(u_info);
514         u_info.info26.password_expired = 0;
515
516         status = dcerpc_fetch_session_key(r->samr_handle.in.dcerpc_pipe, &session_key);
517         if (!NT_STATUS_IS_OK(status)) {
518                 r->samr_handle.out.error_string = talloc_asprintf(mem_ctx,
519                                                                   "dcerpc_fetch_session_key failed: %s",
520                                                                   nt_errstr(status));
521                 return status;
522         }
523
524         status = encode_rc4_passwd_buffer(r->samr_handle.in.newpassword,
525                                           &session_key,
526                                           &u_info.info26.password);
527         if (!NT_STATUS_IS_OK(status)) {
528                 r->samr_handle.out.error_string =
529                         talloc_asprintf(mem_ctx,
530                                         "encode_rc4_passwd_buffer failed: %s",
531                                         nt_errstr(status));
532                 return status;
533         }
534
535         sui.in.user_handle = r->samr_handle.in.user_handle;
536         sui.in.info = &u_info;
537         sui.in.level = 26;
538
539         /* 7. try samr_SetUserInfo2 level 26 to set the password */
540         status = dcerpc_samr_SetUserInfo2_r(r->samr_handle.in.dcerpc_pipe->binding_handle, mem_ctx, &sui);
541         /* check result of samr_SetUserInfo2 level 26 */
542         if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(sui.out.result)) {
543                 status = sui.out.result;
544         }
545         if (!NT_STATUS_IS_OK(status)) {
546                 r->samr_handle.out.error_string
547                         = talloc_asprintf(mem_ctx,
548                                           "SetUserInfo2 level 26 for [%s] failed: %s",
549                                           r->samr_handle.in.account_name, nt_errstr(status));
550         }
551
552         return status;
553 }
554
555 static NTSTATUS libnet_SetPassword_samr_handle_25(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
556 {
557         NTSTATUS status;
558         struct samr_SetUserInfo2 sui;
559         union samr_UserInfo u_info;
560         DATA_BLOB session_key;
561
562         if (!r->samr_handle.in.info21) {
563                 return NT_STATUS_INVALID_PARAMETER_MIX;
564         }
565
566         /* prepare samr_SetUserInfo2 level 25 */
567         ZERO_STRUCT(u_info);
568         u_info.info25.info = *r->samr_handle.in.info21;
569         u_info.info25.info.fields_present |= SAMR_FIELD_NT_PASSWORD_PRESENT;
570
571         status = dcerpc_fetch_session_key(r->samr_handle.in.dcerpc_pipe, &session_key);
572         if (!NT_STATUS_IS_OK(status)) {
573                 r->samr_handle.out.error_string = talloc_asprintf(mem_ctx,
574                                                 "dcerpc_fetch_session_key failed: %s",
575                                                 nt_errstr(status));
576                 return status;
577         }
578
579         status = encode_rc4_passwd_buffer(r->samr_handle.in.newpassword,
580                                           &session_key,
581                                           &u_info.info25.password);
582         if (!NT_STATUS_IS_OK(status)) {
583                 r->samr_handle.out.error_string =
584                         talloc_asprintf(mem_ctx,
585                                         "encode_rc4_passwd_buffer failed: %s",
586                                         nt_errstr(status));
587                 return status;
588         }
589
590
591         sui.in.user_handle = r->samr_handle.in.user_handle;
592         sui.in.info = &u_info;
593         sui.in.level = 25;
594
595         /* 8. try samr_SetUserInfo2 level 25 to set the password */
596         status = dcerpc_samr_SetUserInfo2_r(r->samr_handle.in.dcerpc_pipe->binding_handle, mem_ctx, &sui);
597         if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(sui.out.result)) {
598                 status = sui.out.result;
599         }
600         if (!NT_STATUS_IS_OK(status)) {
601                 r->samr_handle.out.error_string
602                         = talloc_asprintf(mem_ctx,
603                                           "SetUserInfo2 level 25 for [%s] failed: %s",
604                                           r->samr_handle.in.account_name, nt_errstr(status));
605         }
606
607         return status;
608 }
609
610 static NTSTATUS libnet_SetPassword_samr_handle_24(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
611 {
612         NTSTATUS status;
613         struct samr_SetUserInfo2 sui;
614         union samr_UserInfo u_info;
615         DATA_BLOB session_key;
616         gnutls_cipher_hd_t cipher_hnd = NULL;
617         gnutls_datum_t enc_session_key;
618         int rc;
619
620         if (r->samr_handle.in.info21) {
621                 return NT_STATUS_INVALID_PARAMETER_MIX;
622         }
623
624         /* prepare samr_SetUserInfo2 level 24 */
625         ZERO_STRUCT(u_info);
626         encode_pw_buffer(u_info.info24.password.data, r->samr_handle.in.newpassword, STR_UNICODE);
627         u_info.info24.password_expired = 0;
628
629         status = dcerpc_fetch_session_key(r->samr_handle.in.dcerpc_pipe, &session_key);
630         if (!NT_STATUS_IS_OK(status)) {
631                 r->samr_handle.out.error_string = talloc_asprintf(mem_ctx,
632                                                 "dcerpc_fetch_session_key failed: %s",
633                                                 nt_errstr(status));
634                 return status;
635         }
636
637         enc_session_key = (gnutls_datum_t) {
638                 .data = session_key.data,
639                 .size = session_key.length,
640         };
641
642         rc = gnutls_cipher_init(&cipher_hnd,
643                                 GNUTLS_CIPHER_ARCFOUR_128,
644                                 &enc_session_key,
645                                 NULL);
646         if (rc < 0) {
647                 status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
648                 goto out;
649         }
650
651         rc = gnutls_cipher_encrypt(cipher_hnd,
652                                    u_info.info24.password.data,
653                                    516);
654         gnutls_cipher_deinit(cipher_hnd);
655         if (rc < 0) {
656                 status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
657                 goto out;
658         }
659
660         sui.in.user_handle = r->samr_handle.in.user_handle;
661         sui.in.info = &u_info;
662         sui.in.level = 24;
663
664         /* 9. try samr_SetUserInfo2 level 24 to set the password */
665         status = dcerpc_samr_SetUserInfo2_r(r->samr_handle.in.dcerpc_pipe->binding_handle, mem_ctx, &sui);
666         if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(sui.out.result)) {
667                 status = sui.out.result;
668         }
669         if (!NT_STATUS_IS_OK(status)) {
670                 r->samr_handle.out.error_string
671                         = talloc_asprintf(mem_ctx,
672                                           "SetUserInfo2 level 24 for [%s] failed: %s",
673                                           r->samr_handle.in.account_name, nt_errstr(status));
674         }
675
676 out:
677         data_blob_clear(&session_key);
678         return status;
679 }
680
681 static NTSTATUS libnet_SetPassword_samr_handle_23(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
682 {
683         NTSTATUS status;
684         struct samr_SetUserInfo2 sui;
685         union samr_UserInfo u_info;
686         DATA_BLOB session_key;
687         gnutls_cipher_hd_t cipher_hnd = NULL;
688         gnutls_datum_t _session_key;
689         int rc;
690
691         if (!r->samr_handle.in.info21) {
692                 return NT_STATUS_INVALID_PARAMETER_MIX;
693         }
694
695         /* prepare samr_SetUserInfo2 level 23 */
696         ZERO_STRUCT(u_info);
697         u_info.info23.info = *r->samr_handle.in.info21;
698         u_info.info23.info.fields_present |= SAMR_FIELD_NT_PASSWORD_PRESENT;
699         encode_pw_buffer(u_info.info23.password.data, r->samr_handle.in.newpassword, STR_UNICODE);
700
701         status = dcerpc_fetch_session_key(r->samr_handle.in.dcerpc_pipe, &session_key);
702         if (!NT_STATUS_IS_OK(status)) {
703                 r->samr_handle.out.error_string
704                         = talloc_asprintf(mem_ctx,
705                                           "dcerpc_fetch_session_key failed: %s",
706                                           nt_errstr(status));
707                 return status;
708         }
709
710         _session_key = (gnutls_datum_t) {
711                 .data = session_key.data,
712                 .size = session_key.length,
713         };
714
715         rc = gnutls_cipher_init(&cipher_hnd,
716                                 GNUTLS_CIPHER_ARCFOUR_128,
717                                 &_session_key,
718                                 NULL);
719         if (rc < 0) {
720                 status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
721                 goto out;
722         }
723
724         rc = gnutls_cipher_encrypt(cipher_hnd,
725                                    u_info.info23.password.data,
726                                    516);
727         data_blob_clear_free(&session_key);
728         gnutls_cipher_deinit(cipher_hnd);
729         if (rc < 0) {
730                 status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
731                 goto out;
732         }
733
734         sui.in.user_handle = r->samr_handle.in.user_handle;
735         sui.in.info = &u_info;
736         sui.in.level = 23;
737
738         /* 10. try samr_SetUserInfo2 level 23 to set the password */
739         status = dcerpc_samr_SetUserInfo2_r(r->samr_handle.in.dcerpc_pipe->binding_handle, mem_ctx, &sui);
740         if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(sui.out.result)) {
741                 status = sui.out.result;
742         }
743         if (!NT_STATUS_IS_OK(status)) {
744                 r->samr_handle.out.error_string
745                         = talloc_asprintf(mem_ctx,
746                                           "SetUserInfo2 level 23 for [%s] failed: %s",
747                                           r->samr_handle.in.account_name, nt_errstr(status));
748         }
749
750 out:
751         return status;
752 }
753
754 static NTSTATUS libnet_SetPassword_samr_handle_18(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
755 {
756         NTSTATUS status;
757         struct samr_SetUserInfo2 sui;
758         union samr_UserInfo u_info;
759         struct samr_Password ntpwd;
760         DATA_BLOB ntpwd_in;
761         DATA_BLOB ntpwd_out;
762         DATA_BLOB session_key;
763         int rc;
764
765         if (r->samr_handle.in.info21) {
766                 return NT_STATUS_INVALID_PARAMETER_MIX;
767         }
768
769         /* prepare samr_SetUserInfo2 level 18 (nt_hash) */
770         ZERO_STRUCT(u_info);
771         E_md4hash(r->samr_handle.in.newpassword, ntpwd.hash);
772         ntpwd_in = data_blob_const(ntpwd.hash, sizeof(ntpwd.hash));
773         ntpwd_out = data_blob_const(u_info.info18.nt_pwd.hash,
774                                     sizeof(u_info.info18.nt_pwd.hash));
775         u_info.info18.nt_pwd_active = 1;
776         u_info.info18.password_expired = 0;
777
778         status = dcerpc_fetch_session_key(r->samr_handle.in.dcerpc_pipe, &session_key);
779         if (!NT_STATUS_IS_OK(status)) {
780                 r->samr_handle.out.error_string = talloc_asprintf(mem_ctx,
781                                                 "dcerpc_fetch_session_key failed: %s",
782                                                 nt_errstr(status));
783                 return status;
784         }
785
786         rc = sess_crypt_blob(&ntpwd_out, &ntpwd_in,
787                              &session_key, SAMBA_GNUTLS_ENCRYPT);
788         if (rc < 0) {
789                 status = gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
790                 goto out;
791         }
792
793         sui.in.user_handle = r->samr_handle.in.user_handle;
794         sui.in.info = &u_info;
795         sui.in.level = 18;
796
797         /* 9. try samr_SetUserInfo2 level 18 to set the password */
798         status = dcerpc_samr_SetUserInfo2_r(r->samr_handle.in.dcerpc_pipe->binding_handle, mem_ctx, &sui);
799         if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(sui.out.result)) {
800                 status = sui.out.result;
801         }
802         if (!NT_STATUS_IS_OK(status)) {
803                 r->samr_handle.out.error_string
804                         = talloc_asprintf(mem_ctx,
805                                           "SetUserInfo2 level 18 for [%s] failed: %s",
806                                           r->samr_handle.in.account_name, nt_errstr(status));
807         }
808
809 out:
810         data_blob_clear(&session_key);
811         return status;
812 }
813
814 /*
815  * 1. try samr_SetUserInfo2 level 26 to set the password
816  * 2. try samr_SetUserInfo2 level 25 to set the password
817  * 3. try samr_SetUserInfo2 level 24 to set the password
818  * 4. try samr_SetUserInfo2 level 23 to set the password
819 */
820 static NTSTATUS libnet_SetPassword_samr_handle(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
821 {
822
823         NTSTATUS status;
824         enum libnet_SetPassword_level levels[] = {
825                 LIBNET_SET_PASSWORD_SAMR_HANDLE_26,
826                 LIBNET_SET_PASSWORD_SAMR_HANDLE_25,
827                 LIBNET_SET_PASSWORD_SAMR_HANDLE_24,
828                 LIBNET_SET_PASSWORD_SAMR_HANDLE_23,
829         };
830         unsigned int i;
831
832         if (r->samr_handle.samr_level != 0) {
833                 r->generic.level = r->samr_handle.samr_level;
834                 return libnet_SetPassword(ctx, mem_ctx, r);
835         }
836
837         for (i=0; i < ARRAY_SIZE(levels); i++) {
838                 r->generic.level = levels[i];
839                 status = libnet_SetPassword(ctx, mem_ctx, r);
840                 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_INFO_CLASS)
841                     || NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER_MIX)
842                     || NT_STATUS_EQUAL(status, NT_STATUS_RPC_ENUM_VALUE_OUT_OF_RANGE)) {
843                         /* Try another password set mechanism */
844                         continue;
845                 }
846                 break;
847         }
848
849         return status;
850 }
851 /*
852  * set a password with DCERPC/SAMR calls
853  * 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation)
854  *    is it correct to contact the the pdc of the domain of the user who's password should be set?
855  * 2. do a samr_Connect to get a policy handle
856  * 3. do a samr_LookupDomain to get the domain sid
857  * 4. do a samr_OpenDomain to get a domain handle
858  * 5. do a samr_LookupNames to get the users rid
859  * 6. do a samr_OpenUser to get a user handle
860  * 7  call libnet_SetPassword_samr_handle to set the password
861  */
862 static NTSTATUS libnet_SetPassword_samr(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
863 {
864         NTSTATUS status;
865         struct libnet_RpcConnect c;
866         struct samr_Connect sc;
867         struct policy_handle p_handle;
868         struct samr_LookupDomain ld;
869         struct dom_sid2 *sid = NULL;
870         struct lsa_String d_name;
871         struct samr_OpenDomain od;
872         struct policy_handle d_handle;
873         struct samr_LookupNames ln;
874         struct samr_Ids rids, types;
875         struct samr_OpenUser ou;
876         struct policy_handle u_handle;
877         union libnet_SetPassword r2;
878
879         ZERO_STRUCT(c);
880         /* prepare connect to the SAMR pipe of users domain PDC */
881         c.level               = LIBNET_RPC_CONNECT_PDC;
882         c.in.name             = r->samr.in.domain_name;
883         c.in.dcerpc_iface     = &ndr_table_samr;
884
885         /* 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) */
886         status = libnet_RpcConnect(ctx, mem_ctx, &c);
887         if (!NT_STATUS_IS_OK(status)) {
888                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
889                                                            "Connection to SAMR pipe of PDC of domain '%s' failed: %s",
890                                                            r->samr.in.domain_name, nt_errstr(status));
891                 return status;
892         }
893
894         /* prepare samr_Connect */
895         ZERO_STRUCT(p_handle);
896         sc.in.system_name = NULL;
897         sc.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
898         sc.out.connect_handle = &p_handle;
899
900         /* 2. do a samr_Connect to get a policy handle */
901         status = dcerpc_samr_Connect_r(c.out.dcerpc_pipe->binding_handle, mem_ctx, &sc);
902         if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(sc.out.result)) {
903                 status = sc.out.result;
904         }
905         if (!NT_STATUS_IS_OK(status)) {
906                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
907                                                 "samr_Connect failed: %s",
908                                                 nt_errstr(status));
909                 goto disconnect;
910         }
911
912         /* prepare samr_LookupDomain */
913         d_name.string = r->samr.in.domain_name;
914         ld.in.connect_handle = &p_handle;
915         ld.in.domain_name = &d_name;
916         ld.out.sid = &sid;
917
918         /* 3. do a samr_LookupDomain to get the domain sid */
919         status = dcerpc_samr_LookupDomain_r(c.out.dcerpc_pipe->binding_handle, mem_ctx, &ld);
920         if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(ld.out.result)) {
921                 status = ld.out.result;
922         }
923         if (!NT_STATUS_IS_OK(status)) {
924                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
925                                                 "samr_LookupDomain for [%s] failed: %s",
926                                                 r->samr.in.domain_name, nt_errstr(status));
927                 goto disconnect;
928         }
929
930         /* prepare samr_OpenDomain */
931         ZERO_STRUCT(d_handle);
932         od.in.connect_handle = &p_handle;
933         od.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
934         od.in.sid = *ld.out.sid;
935         od.out.domain_handle = &d_handle;
936
937         /* 4. do a samr_OpenDomain to get a domain handle */
938         status = dcerpc_samr_OpenDomain_r(c.out.dcerpc_pipe->binding_handle, mem_ctx, &od);
939         if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(od.out.result)) {
940                 status = od.out.result;
941         }
942         if (!NT_STATUS_IS_OK(status)) {
943                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
944                                                 "samr_OpenDomain for [%s] failed: %s",
945                                                 r->samr.in.domain_name, nt_errstr(status));
946                 goto disconnect;
947         }
948
949         /* prepare samr_LookupNames */
950         ln.in.domain_handle = &d_handle;
951         ln.in.num_names = 1;
952         ln.in.names = talloc_array(mem_ctx, struct lsa_String, 1);
953         ln.out.rids = &rids;
954         ln.out.types = &types;
955         if (!ln.in.names) {
956                 r->samr.out.error_string = "Out of Memory";
957                 return NT_STATUS_NO_MEMORY;
958         }
959         ln.in.names[0].string = r->samr.in.account_name;
960
961         /* 5. do a samr_LookupNames to get the users rid */
962         status = dcerpc_samr_LookupNames_r(c.out.dcerpc_pipe->binding_handle, mem_ctx, &ln);
963         if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(ln.out.result)) {
964                 status = ln.out.result;
965         }
966         if (!NT_STATUS_IS_OK(status)) {
967                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
968                                                 "samr_LookupNames for [%s] failed: %s",
969                                                 r->samr.in.account_name, nt_errstr(status));
970                 goto disconnect;
971         }
972
973         /* check if we got one RID for the user */
974         if (ln.out.rids->count != 1) {
975                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
976                                                 "samr_LookupNames for [%s] returns %d RIDs",
977                                                 r->samr.in.account_name, ln.out.rids->count);
978                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
979                 goto disconnect;
980         }
981
982         if (ln.out.types->count != 1) {
983                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
984                                                 "samr_LookupNames for [%s] returns %d RID TYPEs",
985                                                 r->samr.in.account_name, ln.out.types->count);
986                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
987                 goto disconnect;
988         }
989
990         /* prepare samr_OpenUser */
991         ZERO_STRUCT(u_handle);
992         ou.in.domain_handle = &d_handle;
993         ou.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
994         ou.in.rid = ln.out.rids->ids[0];
995         ou.out.user_handle = &u_handle;
996
997         /* 6. do a samr_OpenUser to get a user handle */
998         status = dcerpc_samr_OpenUser_r(c.out.dcerpc_pipe->binding_handle, mem_ctx, &ou);
999         if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(ou.out.result)) {
1000                 status = ou.out.result;
1001         }
1002         if (!NT_STATUS_IS_OK(status)) {
1003                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
1004                                                 "samr_OpenUser for [%s] failed: %s",
1005                                                 r->samr.in.account_name, nt_errstr(status));
1006                 goto disconnect;
1007         }
1008
1009         ZERO_STRUCT(r2);
1010         r2.samr_handle.level            = LIBNET_SET_PASSWORD_SAMR_HANDLE;
1011         r2.samr_handle.samr_level       = r->samr.samr_level;
1012         r2.samr_handle.in.account_name  = r->samr.in.account_name;
1013         r2.samr_handle.in.newpassword   = r->samr.in.newpassword;
1014         r2.samr_handle.in.user_handle   = &u_handle;
1015         r2.samr_handle.in.dcerpc_pipe   = c.out.dcerpc_pipe;
1016         r2.samr_handle.in.info21        = NULL;
1017
1018         status = libnet_SetPassword(ctx, mem_ctx, &r2);
1019
1020         r->generic.out.error_string = r2.samr_handle.out.error_string;
1021
1022 disconnect:
1023         /* close connection */
1024         talloc_unlink(ctx, c.out.dcerpc_pipe);
1025
1026         return status;
1027 }
1028
1029 static NTSTATUS libnet_SetPassword_generic(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
1030 {
1031         NTSTATUS status;
1032         union libnet_SetPassword r2;
1033
1034         ZERO_STRUCT(r2);
1035         r2.samr.level           = LIBNET_SET_PASSWORD_SAMR;
1036         r2.samr.samr_level      = r->generic.samr_level;
1037         r2.samr.in.account_name = r->generic.in.account_name;
1038         r2.samr.in.domain_name  = r->generic.in.domain_name;
1039         r2.samr.in.newpassword  = r->generic.in.newpassword;
1040
1041         r->generic.out.error_string = "Unknown Error";
1042         status = libnet_SetPassword(ctx, mem_ctx, &r2);
1043
1044         r->generic.out.error_string = r2.samr.out.error_string;
1045
1046         return status;
1047 }
1048
1049 NTSTATUS libnet_SetPassword(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
1050 {
1051         enum smb_encryption_setting encryption_state =
1052                 cli_credentials_get_smb_encryption(ctx->cred);
1053         NTSTATUS status =  NT_STATUS_INVALID_LEVEL;
1054
1055         switch (r->generic.level) {
1056                 case LIBNET_SET_PASSWORD_GENERIC:
1057                         status = libnet_SetPassword_generic(ctx, mem_ctx, r);
1058                         break;
1059                 case LIBNET_SET_PASSWORD_SAMR:
1060                         status = libnet_SetPassword_samr(ctx, mem_ctx, r);
1061                         break;
1062                 case LIBNET_SET_PASSWORD_SAMR_HANDLE:
1063                         status = libnet_SetPassword_samr_handle(ctx, mem_ctx, r);
1064                         break;
1065                 case LIBNET_SET_PASSWORD_SAMR_HANDLE_26:
1066                         if (encryption_state == SMB_ENCRYPTION_REQUIRED) {
1067                                 GNUTLS_FIPS140_SET_LAX_MODE();
1068                         }
1069                         status = libnet_SetPassword_samr_handle_26(ctx, mem_ctx, r);
1070                         break;
1071                 case LIBNET_SET_PASSWORD_SAMR_HANDLE_25:
1072                         if (encryption_state == SMB_ENCRYPTION_REQUIRED) {
1073                                 GNUTLS_FIPS140_SET_LAX_MODE();
1074                         }
1075                         status = libnet_SetPassword_samr_handle_25(ctx, mem_ctx, r);
1076                         break;
1077                 case LIBNET_SET_PASSWORD_SAMR_HANDLE_24:
1078                         if (encryption_state == SMB_ENCRYPTION_REQUIRED) {
1079                                 GNUTLS_FIPS140_SET_LAX_MODE();
1080                         }
1081                         status = libnet_SetPassword_samr_handle_24(ctx, mem_ctx, r);
1082                         break;
1083                 case LIBNET_SET_PASSWORD_SAMR_HANDLE_23:
1084                         if (encryption_state == SMB_ENCRYPTION_REQUIRED) {
1085                                 GNUTLS_FIPS140_SET_LAX_MODE();
1086                         }
1087                         status = libnet_SetPassword_samr_handle_23(ctx, mem_ctx, r);
1088                         break;
1089                 case LIBNET_SET_PASSWORD_SAMR_HANDLE_18:
1090                         if (encryption_state == SMB_ENCRYPTION_REQUIRED) {
1091                                 GNUTLS_FIPS140_SET_LAX_MODE();
1092                         }
1093                         status = libnet_SetPassword_samr_handle_18(ctx, mem_ctx, r);
1094                         break;
1095                 case LIBNET_SET_PASSWORD_KRB5:
1096                         status = NT_STATUS_NOT_IMPLEMENTED;
1097                         break;
1098                 case LIBNET_SET_PASSWORD_LDAP:
1099                         status = NT_STATUS_NOT_IMPLEMENTED;
1100                         break;
1101                 case LIBNET_SET_PASSWORD_RAP:
1102                         status = NT_STATUS_NOT_IMPLEMENTED;
1103                         break;
1104         }
1105
1106         GNUTLS_FIPS140_SET_STRICT_MODE();
1107         return status;
1108 }