Move source4/lib/crypto to lib/crypto.
[ira/wip.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 "../lib/crypto/crypto.h"
24 #include "libcli/auth/libcli_auth.h"
25 #include "librpc/gen_ndr/ndr_samr_c.h"
26
27 /*
28  * do a password change using DCERPC/SAMR calls
29  * 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation)
30  * 2. try samr_ChangePasswordUser3
31  * 3. try samr_ChangePasswordUser2
32  * 4. try samr_OemChangePasswordUser2
33  * (not yet: 5. try samr_ChangePasswordUser)
34  */
35 static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_ChangePassword *r)
36 {
37         NTSTATUS status;
38         struct libnet_RpcConnect c;
39 #if 0
40         struct policy_handle user_handle;
41         struct samr_Password hash1, hash2, hash3, hash4, hash5, hash6;
42         struct samr_ChangePasswordUser pw;
43 #endif
44         struct samr_OemChangePasswordUser2 oe2;
45         struct samr_ChangePasswordUser2 pw2;
46         struct samr_ChangePasswordUser3 pw3;
47         struct lsa_String server, account;
48         struct lsa_AsciiString a_server, a_account;
49         struct samr_CryptPassword nt_pass, lm_pass;
50         struct samr_Password nt_verifier, lm_verifier;
51         uint8_t old_nt_hash[16], new_nt_hash[16];
52         uint8_t old_lm_hash[16], new_lm_hash[16];
53
54         /* prepare connect to the SAMR pipe of the users domain PDC */
55         c.level                    = LIBNET_RPC_CONNECT_PDC;
56         c.in.name                  = r->samr.in.domain_name;
57         c.in.dcerpc_iface          = &ndr_table_samr;
58
59         /* 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) */
60         status = libnet_RpcConnect(ctx, mem_ctx, &c);
61         if (!NT_STATUS_IS_OK(status)) {
62                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
63                                                 "Connection to SAMR pipe of PDC of domain '%s' failed: %s",
64                                                 r->samr.in.domain_name, nt_errstr(status));
65                 return status;
66         }
67
68         /* prepare password change for account */
69         server.string = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(c.out.dcerpc_pipe));
70         account.string = r->samr.in.account_name;
71
72         E_md4hash(r->samr.in.oldpassword, old_nt_hash);
73         E_md4hash(r->samr.in.newpassword, new_nt_hash);
74
75         E_deshash(r->samr.in.oldpassword, old_lm_hash);
76         E_deshash(r->samr.in.newpassword, new_lm_hash);
77
78         /* prepare samr_ChangePasswordUser3 */
79         encode_pw_buffer(lm_pass.data, r->samr.in.newpassword, STR_UNICODE);
80         arcfour_crypt(lm_pass.data, old_nt_hash, 516);
81         E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash);
82
83         encode_pw_buffer(nt_pass.data,  r->samr.in.newpassword, STR_UNICODE);
84         arcfour_crypt(nt_pass.data, old_nt_hash, 516);
85         E_old_pw_hash(new_nt_hash, old_nt_hash, nt_verifier.hash);
86
87         pw3.in.server = &server;
88         pw3.in.account = &account;
89         pw3.in.nt_password = &nt_pass;
90         pw3.in.nt_verifier = &nt_verifier;
91         pw3.in.lm_change = 1;
92         pw3.in.lm_password = &lm_pass;
93         pw3.in.lm_verifier = &lm_verifier;
94         pw3.in.password3 = NULL;
95
96         /* 2. try samr_ChangePasswordUser3 */
97         status = dcerpc_samr_ChangePasswordUser3(c.out.dcerpc_pipe, mem_ctx, &pw3);
98         if (!NT_STATUS_IS_OK(status)) {
99                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
100                                                 "samr_ChangePasswordUser3 failed: %s",
101                                                 nt_errstr(status));
102                 goto ChangePasswordUser2;
103         }
104
105         /* check result of samr_ChangePasswordUser3 */
106         if (!NT_STATUS_IS_OK(pw3.out.result)) {
107                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
108                                                 "samr_ChangePasswordUser3 for '%s\\%s' failed: %s",
109                                                 r->samr.in.domain_name, r->samr.in.account_name, 
110                                                 nt_errstr(pw3.out.result));
111                                                 /* TODO: give the reason of the reject */
112                 if (NT_STATUS_EQUAL(pw3.out.result, NT_STATUS_PASSWORD_RESTRICTION)) {
113                         status = pw3.out.result;
114                         goto disconnect;
115                 }
116                 goto ChangePasswordUser2;
117         }
118
119         goto disconnect;
120
121 ChangePasswordUser2:
122         /* prepare samr_ChangePasswordUser2 */
123         encode_pw_buffer(lm_pass.data, r->samr.in.newpassword, STR_ASCII|STR_TERMINATE);
124         arcfour_crypt(lm_pass.data, old_lm_hash, 516);
125         E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash);
126
127         encode_pw_buffer(nt_pass.data, r->samr.in.newpassword, STR_UNICODE);
128         arcfour_crypt(nt_pass.data, old_nt_hash, 516);
129         E_old_pw_hash(new_nt_hash, old_nt_hash, nt_verifier.hash);
130
131         pw2.in.server = &server;
132         pw2.in.account = &account;
133         pw2.in.nt_password = &nt_pass;
134         pw2.in.nt_verifier = &nt_verifier;
135         pw2.in.lm_change = 1;
136         pw2.in.lm_password = &lm_pass;
137         pw2.in.lm_verifier = &lm_verifier;
138
139         /* 3. try samr_ChangePasswordUser2 */
140         status = dcerpc_samr_ChangePasswordUser2(c.out.dcerpc_pipe, mem_ctx, &pw2);
141         if (!NT_STATUS_IS_OK(status)) {
142                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
143                                                 "samr_ChangePasswordUser2 failed: %s",
144                                                 nt_errstr(status));
145                 goto OemChangePasswordUser2;
146         }
147
148         /* check result of samr_ChangePasswordUser2 */
149         if (!NT_STATUS_IS_OK(pw2.out.result)) {
150                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
151                                                 "samr_ChangePasswordUser2 for '%s\\%s' failed: %s",
152                                                 r->samr.in.domain_name, r->samr.in.account_name, 
153                                                 nt_errstr(pw2.out.result));
154                 if (NT_STATUS_EQUAL(pw2.out.result, NT_STATUS_PASSWORD_RESTRICTION)) {
155                         status = pw2.out.result;
156                         goto disconnect;
157                 }
158                 goto OemChangePasswordUser2;
159         }
160
161         goto disconnect;
162
163 OemChangePasswordUser2:
164         /* prepare samr_OemChangePasswordUser2 */
165         a_server.string = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(c.out.dcerpc_pipe));
166         a_account.string = r->samr.in.account_name;
167
168         encode_pw_buffer(lm_pass.data, r->samr.in.newpassword, STR_ASCII);
169         arcfour_crypt(lm_pass.data, old_lm_hash, 516);
170         E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash);
171
172         oe2.in.server = &a_server;
173         oe2.in.account = &a_account;
174         oe2.in.password = &lm_pass;
175         oe2.in.hash = &lm_verifier;
176
177         /* 4. try samr_OemChangePasswordUser2 */
178         status = dcerpc_samr_OemChangePasswordUser2(c.out.dcerpc_pipe, mem_ctx, &oe2);
179         if (!NT_STATUS_IS_OK(status)) {
180                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
181                                                 "samr_OemChangePasswordUser2 failed: %s",
182                                                 nt_errstr(status));
183                 goto ChangePasswordUser;
184         }
185
186         /* check result of samr_OemChangePasswordUser2 */
187         if (!NT_STATUS_IS_OK(oe2.out.result)) {
188                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
189                                                 "samr_OemChangePasswordUser2 for '%s\\%s' failed: %s",
190                                                 r->samr.in.domain_name, r->samr.in.account_name, 
191                                                 nt_errstr(oe2.out.result));
192                 if (NT_STATUS_EQUAL(oe2.out.result, NT_STATUS_PASSWORD_RESTRICTION)) {
193                         status = oe2.out.result;
194                         goto disconnect;
195                 }
196                 goto ChangePasswordUser;
197         }
198
199         goto disconnect;
200
201 ChangePasswordUser:
202 #if 0
203         /* prepare samr_ChangePasswordUser */
204         E_old_pw_hash(new_lm_hash, old_lm_hash, hash1.hash);
205         E_old_pw_hash(old_lm_hash, new_lm_hash, hash2.hash);
206         E_old_pw_hash(new_nt_hash, old_nt_hash, hash3.hash);
207         E_old_pw_hash(old_nt_hash, new_nt_hash, hash4.hash);
208         E_old_pw_hash(old_lm_hash, new_nt_hash, hash5.hash);
209         E_old_pw_hash(old_nt_hash, new_lm_hash, hash6.hash);
210
211         /* TODO: ask for a user_handle */
212         pw.in.handle = &user_handle;
213         pw.in.lm_present = 1;
214         pw.in.old_lm_crypted = &hash1;
215         pw.in.new_lm_crypted = &hash2;
216         pw.in.nt_present = 1;
217         pw.in.old_nt_crypted = &hash3;
218         pw.in.new_nt_crypted = &hash4;
219         pw.in.cross1_present = 1;
220         pw.in.nt_cross = &hash5;
221         pw.in.cross2_present = 1;
222         pw.in.lm_cross = &hash6;
223
224         /* 5. try samr_ChangePasswordUser */
225         status = dcerpc_samr_ChangePasswordUser(c.pdc.out.dcerpc_pipe, mem_ctx, &pw);
226         if (!NT_STATUS_IS_OK(status)) {
227                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
228                                                 "samr_ChangePasswordUser failed: %s",
229                                                 nt_errstr(status));
230                 goto disconnect;
231         }
232
233         /* check result of samr_ChangePasswordUser */
234         if (!NT_STATUS_IS_OK(pw.out.result)) {
235                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
236                                                 "samr_ChangePasswordUser for '%s\\%s' failed: %s",
237                                                 r->samr.in.domain_name, r->samr.in.account_name, 
238                                                 nt_errstr(pw.out.result));
239                 if (NT_STATUS_EQUAL(pw.out.result, NT_STATUS_PASSWORD_RESTRICTION)) {
240                         status = pw.out.result;
241                         goto disconnect;
242                 }
243                 goto disconnect;
244         }
245 #endif
246 disconnect:
247         /* close connection */
248         talloc_free(c.out.dcerpc_pipe);
249
250         return status;
251 }
252
253 static NTSTATUS libnet_ChangePassword_generic(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_ChangePassword *r)
254 {
255         NTSTATUS status;
256         union libnet_ChangePassword r2;
257
258         r2.samr.level           = LIBNET_CHANGE_PASSWORD_SAMR;
259         r2.samr.in.account_name = r->generic.in.account_name;
260         r2.samr.in.domain_name  = r->generic.in.domain_name;
261         r2.samr.in.oldpassword  = r->generic.in.oldpassword;
262         r2.samr.in.newpassword  = r->generic.in.newpassword;
263
264         status = libnet_ChangePassword(ctx, mem_ctx, &r2);
265
266         r->generic.out.error_string = r2.samr.out.error_string;
267
268         return status;
269 }
270
271 NTSTATUS libnet_ChangePassword(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_ChangePassword *r)
272 {
273         switch (r->generic.level) {
274                 case LIBNET_CHANGE_PASSWORD_GENERIC:
275                         return libnet_ChangePassword_generic(ctx, mem_ctx, r);
276                 case LIBNET_CHANGE_PASSWORD_SAMR:
277                         return libnet_ChangePassword_samr(ctx, mem_ctx, r);
278                 case LIBNET_CHANGE_PASSWORD_KRB5:
279                         return NT_STATUS_NOT_IMPLEMENTED;
280                 case LIBNET_CHANGE_PASSWORD_LDAP:
281                         return NT_STATUS_NOT_IMPLEMENTED;
282                 case LIBNET_CHANGE_PASSWORD_RAP:
283                         return NT_STATUS_NOT_IMPLEMENTED;
284         }
285
286         return NT_STATUS_INVALID_LEVEL;
287 }
288
289 static NTSTATUS libnet_SetPassword_samr_handle_26(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
290 {
291         NTSTATUS status;
292         struct samr_SetUserInfo2 sui;
293         union samr_UserInfo u_info;
294         DATA_BLOB session_key;
295         DATA_BLOB confounded_session_key = data_blob_talloc(mem_ctx, NULL, 16);
296         uint8_t confounder[16]; 
297         struct MD5Context md5;
298
299         if (r->samr_handle.in.info21) {
300                 return NT_STATUS_INVALID_PARAMETER_MIX;
301         }
302
303         /* prepare samr_SetUserInfo2 level 26 */
304         ZERO_STRUCT(u_info);
305         encode_pw_buffer(u_info.info26.password.data, r->samr_handle.in.newpassword, STR_UNICODE);
306         u_info.info26.pw_len = strlen(r->samr_handle.in.newpassword);
307         
308         status = dcerpc_fetch_session_key(r->samr_handle.in.dcerpc_pipe, &session_key);
309         if (!NT_STATUS_IS_OK(status)) {
310                 r->samr_handle.out.error_string = talloc_asprintf(mem_ctx,
311                                                                   "dcerpc_fetch_session_key failed: %s",
312                                                                   nt_errstr(status));
313                 return status;
314         }
315         
316         generate_random_buffer((uint8_t *)confounder, 16);
317         
318         MD5Init(&md5);
319         MD5Update(&md5, confounder, 16);
320         MD5Update(&md5, session_key.data, session_key.length);
321         MD5Final(confounded_session_key.data, &md5);
322         
323         arcfour_crypt_blob(u_info.info26.password.data, 516, &confounded_session_key);
324         memcpy(&u_info.info26.password.data[516], confounder, 16);
325         
326         sui.in.user_handle = r->samr_handle.in.user_handle;
327         sui.in.info = &u_info;
328         sui.in.level = 26;
329         
330         /* 7. try samr_SetUserInfo2 level 26 to set the password */
331         status = dcerpc_samr_SetUserInfo2(r->samr_handle.in.dcerpc_pipe, mem_ctx, &sui);
332         /* check result of samr_SetUserInfo2 level 26 */
333         if (!NT_STATUS_IS_OK(status)) {
334                 r->samr_handle.out.error_string
335                         = talloc_asprintf(mem_ctx,
336                                           "SetUserInfo2 level 26 for [%s] failed: %s",
337                                           r->samr_handle.in.account_name, nt_errstr(status));
338         }
339         return status;
340 }
341
342 static NTSTATUS libnet_SetPassword_samr_handle_25(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
343 {
344         NTSTATUS status;
345         struct samr_SetUserInfo2 sui;
346         union samr_UserInfo u_info;
347         DATA_BLOB session_key;
348         DATA_BLOB confounded_session_key = data_blob_talloc(mem_ctx, NULL, 16);
349         uint8_t confounder[16]; 
350         struct MD5Context md5;
351
352         if (!r->samr_handle.in.info21) {
353                 return NT_STATUS_INVALID_PARAMETER_MIX;
354         }
355
356         /* prepare samr_SetUserInfo2 level 25 */
357         ZERO_STRUCT(u_info);
358         u_info.info25.info = *r->samr_handle.in.info21;
359         u_info.info25.info.fields_present |= SAMR_FIELD_PASSWORD;
360         encode_pw_buffer(u_info.info25.password.data, r->samr_handle.in.newpassword, STR_UNICODE);
361
362         status = dcerpc_fetch_session_key(r->samr_handle.in.dcerpc_pipe, &session_key);
363         if (!NT_STATUS_IS_OK(status)) {
364                 r->samr_handle.out.error_string = talloc_asprintf(mem_ctx,
365                                                 "dcerpc_fetch_session_key failed: %s",
366                                                 nt_errstr(status));
367                 return status;
368         }
369
370         generate_random_buffer((uint8_t *)confounder, 16);
371
372         MD5Init(&md5);
373         MD5Update(&md5, confounder, 16);
374         MD5Update(&md5, session_key.data, session_key.length);
375         MD5Final(confounded_session_key.data, &md5);
376
377         arcfour_crypt_blob(u_info.info25.password.data, 516, &confounded_session_key);
378         memcpy(&u_info.info25.password.data[516], confounder, 16);
379
380         sui.in.user_handle = r->samr_handle.in.user_handle;
381         sui.in.info = &u_info;
382         sui.in.level = 25;
383
384         /* 8. try samr_SetUserInfo2 level 25 to set the password */
385         status = dcerpc_samr_SetUserInfo2(r->samr_handle.in.dcerpc_pipe, mem_ctx, &sui);
386         if (!NT_STATUS_IS_OK(status)) {
387                 r->samr_handle.out.error_string
388                         = talloc_asprintf(mem_ctx,
389                                           "SetUserInfo2 level 25 for [%s] failed: %s",
390                                           r->samr_handle.in.account_name, nt_errstr(status));
391         }
392         return status;
393 }
394
395 static NTSTATUS libnet_SetPassword_samr_handle_24(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
396 {
397         NTSTATUS status;
398         struct samr_SetUserInfo2 sui;
399         union samr_UserInfo u_info;
400         DATA_BLOB session_key;
401
402         if (r->samr_handle.in.info21) {
403                 return NT_STATUS_INVALID_PARAMETER_MIX;
404         }
405
406         /* prepare samr_SetUserInfo2 level 24 */
407         ZERO_STRUCT(u_info);
408         encode_pw_buffer(u_info.info24.password.data, r->samr_handle.in.newpassword, STR_UNICODE);
409         /* w2k3 ignores this length */
410         u_info.info24.pw_len = strlen_m(r->samr_handle.in.newpassword)*2;
411
412         status = dcerpc_fetch_session_key(r->samr_handle.in.dcerpc_pipe, &session_key);
413         if (!NT_STATUS_IS_OK(status)) {
414                 r->samr_handle.out.error_string = talloc_asprintf(mem_ctx,
415                                                 "dcerpc_fetch_session_key failed: %s",
416                                                 nt_errstr(status));
417                 return status;
418         }
419
420         arcfour_crypt_blob(u_info.info24.password.data, 516, &session_key);
421
422         sui.in.user_handle = r->samr_handle.in.user_handle;
423         sui.in.info = &u_info;
424         sui.in.level = 24;
425
426         /* 9. try samr_SetUserInfo2 level 24 to set the password */
427         status = dcerpc_samr_SetUserInfo2(r->samr_handle.in.dcerpc_pipe, mem_ctx, &sui);
428         if (!NT_STATUS_IS_OK(status)) {
429                 r->samr_handle.out.error_string
430                         = talloc_asprintf(mem_ctx,
431                                           "SetUserInfo2 level 24 for [%s] failed: %s",
432                                           r->samr_handle.in.account_name, nt_errstr(status));
433         }
434         return status;
435 }
436
437 static NTSTATUS libnet_SetPassword_samr_handle_23(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
438 {
439         NTSTATUS status;
440         struct samr_SetUserInfo2 sui;
441         union samr_UserInfo u_info;
442         DATA_BLOB session_key;
443
444         if (!r->samr_handle.in.info21) {
445                 return NT_STATUS_INVALID_PARAMETER_MIX;
446         }
447
448         /* prepare samr_SetUserInfo2 level 23 */
449         ZERO_STRUCT(u_info);
450         u_info.info23.info = *r->samr_handle.in.info21;
451         u_info.info23.info.fields_present |= SAMR_FIELD_PASSWORD;
452         encode_pw_buffer(u_info.info23.password.data, r->samr_handle.in.newpassword, STR_UNICODE);
453
454         status = dcerpc_fetch_session_key(r->samr_handle.in.dcerpc_pipe, &session_key);
455         if (!NT_STATUS_IS_OK(status)) {
456                 r->samr_handle.out.error_string
457                         = talloc_asprintf(mem_ctx,
458                                           "dcerpc_fetch_session_key failed: %s",
459                                           nt_errstr(status));
460                 return status;
461         }
462
463         arcfour_crypt_blob(u_info.info23.password.data, 516, &session_key);
464
465         sui.in.user_handle = r->samr_handle.in.user_handle;
466         sui.in.info = &u_info;
467         sui.in.level = 23;
468
469         /* 10. try samr_SetUserInfo2 level 23 to set the password */
470         status = dcerpc_samr_SetUserInfo2(r->samr_handle.in.dcerpc_pipe, mem_ctx, &sui);
471         if (!NT_STATUS_IS_OK(status)) {
472                 r->samr_handle.out.error_string
473                         = talloc_asprintf(mem_ctx,
474                                           "SetUserInfo2 level 23 for [%s] failed: %s",
475                                           r->samr_handle.in.account_name, nt_errstr(status));
476         }
477         return status;
478 }
479
480 /*
481  * 1. try samr_SetUserInfo2 level 26 to set the password
482  * 2. try samr_SetUserInfo2 level 25 to set the password
483  * 3. try samr_SetUserInfo2 level 24 to set the password
484  * 4. try samr_SetUserInfo2 level 23 to set the password
485 */
486 static NTSTATUS libnet_SetPassword_samr_handle(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
487 {
488
489         NTSTATUS status;
490         enum libnet_SetPassword_level levels[] = {
491                 LIBNET_SET_PASSWORD_SAMR_HANDLE_26,
492                 LIBNET_SET_PASSWORD_SAMR_HANDLE_25,
493                 LIBNET_SET_PASSWORD_SAMR_HANDLE_24,
494                 LIBNET_SET_PASSWORD_SAMR_HANDLE_23,
495         };
496         int i;
497
498         for (i=0; i < ARRAY_SIZE(levels); i++) {
499                 r->generic.level = levels[i];
500                 status = libnet_SetPassword(ctx, mem_ctx, r);
501                 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_INFO_CLASS)
502                     || NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER_MIX)
503                     || NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
504                         /* Try another password set mechanism */
505                         continue;
506                 }
507                 break;
508         }
509         
510         return status;
511 }
512 /*
513  * set a password with DCERPC/SAMR calls
514  * 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation)
515  *    is it correct to contact the the pdc of the domain of the user who's password should be set?
516  * 2. do a samr_Connect to get a policy handle
517  * 3. do a samr_LookupDomain to get the domain sid
518  * 4. do a samr_OpenDomain to get a domain handle
519  * 5. do a samr_LookupNames to get the users rid
520  * 6. do a samr_OpenUser to get a user handle
521  * 7  call libnet_SetPassword_samr_handle to set the password
522  */
523 static NTSTATUS libnet_SetPassword_samr(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
524 {
525         NTSTATUS status;
526         struct libnet_RpcConnect c;
527         struct samr_Connect sc;
528         struct policy_handle p_handle;
529         struct samr_LookupDomain ld;
530         struct lsa_String d_name;
531         struct samr_OpenDomain od;
532         struct policy_handle d_handle;
533         struct samr_LookupNames ln;
534         struct samr_OpenUser ou;
535         struct policy_handle u_handle;
536         union libnet_SetPassword r2;
537
538         /* prepare connect to the SAMR pipe of users domain PDC */
539         c.level               = LIBNET_RPC_CONNECT_PDC;
540         c.in.name             = r->samr.in.domain_name;
541         c.in.dcerpc_iface     = &ndr_table_samr;
542
543         /* 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) */
544         status = libnet_RpcConnect(ctx, mem_ctx, &c);
545         if (!NT_STATUS_IS_OK(status)) {
546                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
547                                                            "Connection to SAMR pipe of PDC of domain '%s' failed: %s",
548                                                            r->samr.in.domain_name, nt_errstr(status));
549                 return status;
550         }
551
552         /* prepare samr_Connect */
553         ZERO_STRUCT(p_handle);
554         sc.in.system_name = NULL;
555         sc.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
556         sc.out.connect_handle = &p_handle;
557
558         /* 2. do a samr_Connect to get a policy handle */
559         status = dcerpc_samr_Connect(c.out.dcerpc_pipe, mem_ctx, &sc);
560         if (!NT_STATUS_IS_OK(status)) {
561                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
562                                                 "samr_Connect failed: %s",
563                                                 nt_errstr(status));
564                 goto disconnect;
565         }
566
567         /* prepare samr_LookupDomain */
568         d_name.string = r->samr.in.domain_name;
569         ld.in.connect_handle = &p_handle;
570         ld.in.domain_name = &d_name;
571
572         /* 3. do a samr_LookupDomain to get the domain sid */
573         status = dcerpc_samr_LookupDomain(c.out.dcerpc_pipe, mem_ctx, &ld);
574         if (!NT_STATUS_IS_OK(status)) {
575                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
576                                                 "samr_LookupDomain for [%s] failed: %s",
577                                                 r->samr.in.domain_name, nt_errstr(status));
578                 goto disconnect;
579         }
580
581         /* prepare samr_OpenDomain */
582         ZERO_STRUCT(d_handle);
583         od.in.connect_handle = &p_handle;
584         od.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
585         od.in.sid = ld.out.sid;
586         od.out.domain_handle = &d_handle;
587
588         /* 4. do a samr_OpenDomain to get a domain handle */
589         status = dcerpc_samr_OpenDomain(c.out.dcerpc_pipe, mem_ctx, &od);
590         if (!NT_STATUS_IS_OK(status)) {
591                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
592                                                 "samr_OpenDomain for [%s] failed: %s",
593                                                 r->samr.in.domain_name, nt_errstr(status));
594                 goto disconnect;
595         }
596
597         /* prepare samr_LookupNames */
598         ln.in.domain_handle = &d_handle;
599         ln.in.num_names = 1;
600         ln.in.names = talloc_array(mem_ctx, struct lsa_String, 1);
601         if (!ln.in.names) {
602                 r->samr.out.error_string = "Out of Memory";
603                 return NT_STATUS_NO_MEMORY;
604         }
605         ln.in.names[0].string = r->samr.in.account_name;
606
607         /* 5. do a samr_LookupNames to get the users rid */
608         status = dcerpc_samr_LookupNames(c.out.dcerpc_pipe, mem_ctx, &ln);
609         if (!NT_STATUS_IS_OK(status)) {
610                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
611                                                 "samr_LookupNames for [%s] failed: %s",
612                                                 r->samr.in.account_name, nt_errstr(status));
613                 goto disconnect;
614         }
615
616         /* check if we got one RID for the user */
617         if (ln.out.rids.count != 1) {
618                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
619                                                 "samr_LookupNames for [%s] returns %d RIDs",
620                                                 r->samr.in.account_name, ln.out.rids.count);
621                 status = NT_STATUS_INVALID_PARAMETER;
622                 goto disconnect;        
623         }
624
625         /* prepare samr_OpenUser */
626         ZERO_STRUCT(u_handle);
627         ou.in.domain_handle = &d_handle;
628         ou.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
629         ou.in.rid = ln.out.rids.ids[0];
630         ou.out.user_handle = &u_handle;
631
632         /* 6. do a samr_OpenUser to get a user handle */
633         status = dcerpc_samr_OpenUser(c.out.dcerpc_pipe, mem_ctx, &ou);
634         if (!NT_STATUS_IS_OK(status)) {
635                 r->samr.out.error_string = talloc_asprintf(mem_ctx,
636                                                 "samr_OpenUser for [%s] failed: %s",
637                                                 r->samr.in.account_name, nt_errstr(status));
638                 goto disconnect;
639         }
640
641         r2.samr_handle.level            = LIBNET_SET_PASSWORD_SAMR_HANDLE;
642         r2.samr_handle.in.account_name  = r->samr.in.account_name;
643         r2.samr_handle.in.newpassword   = r->samr.in.newpassword;
644         r2.samr_handle.in.user_handle   = &u_handle;
645         r2.samr_handle.in.dcerpc_pipe   = c.out.dcerpc_pipe;
646         r2.samr_handle.in.info21        = NULL;
647
648         status = libnet_SetPassword(ctx, mem_ctx, &r2);
649
650         r->generic.out.error_string = r2.samr_handle.out.error_string;
651
652 disconnect:
653         /* close connection */
654         talloc_free(c.out.dcerpc_pipe);
655
656         return status;
657 }
658
659 static NTSTATUS libnet_SetPassword_generic(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
660 {
661         NTSTATUS status;
662         union libnet_SetPassword r2;
663
664         r2.samr.level           = LIBNET_SET_PASSWORD_SAMR;
665         r2.samr.in.account_name = r->generic.in.account_name;
666         r2.samr.in.domain_name  = r->generic.in.domain_name;
667         r2.samr.in.newpassword  = r->generic.in.newpassword;
668
669         r->generic.out.error_string = "Unknown Error";
670         status = libnet_SetPassword(ctx, mem_ctx, &r2);
671
672         r->generic.out.error_string = r2.samr.out.error_string;
673
674         return status;
675 }
676
677 NTSTATUS libnet_SetPassword(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
678 {
679         switch (r->generic.level) {
680                 case LIBNET_SET_PASSWORD_GENERIC:
681                         return libnet_SetPassword_generic(ctx, mem_ctx, r);
682                 case LIBNET_SET_PASSWORD_SAMR:
683                         return libnet_SetPassword_samr(ctx, mem_ctx, r);
684                 case LIBNET_SET_PASSWORD_SAMR_HANDLE:
685                         return libnet_SetPassword_samr_handle(ctx, mem_ctx, r);
686                 case LIBNET_SET_PASSWORD_SAMR_HANDLE_26:
687                         return libnet_SetPassword_samr_handle_26(ctx, mem_ctx, r);
688                 case LIBNET_SET_PASSWORD_SAMR_HANDLE_25:
689                         return libnet_SetPassword_samr_handle_25(ctx, mem_ctx, r);
690                 case LIBNET_SET_PASSWORD_SAMR_HANDLE_24:
691                         return libnet_SetPassword_samr_handle_24(ctx, mem_ctx, r);
692                 case LIBNET_SET_PASSWORD_SAMR_HANDLE_23:
693                         return libnet_SetPassword_samr_handle_23(ctx, mem_ctx, r);
694                 case LIBNET_SET_PASSWORD_KRB5:
695                         return NT_STATUS_NOT_IMPLEMENTED;
696                 case LIBNET_SET_PASSWORD_LDAP:
697                         return NT_STATUS_NOT_IMPLEMENTED;
698                 case LIBNET_SET_PASSWORD_RAP:
699                         return NT_STATUS_NOT_IMPLEMENTED;
700         }
701
702         return NT_STATUS_INVALID_LEVEL;
703 }