r1926: fallback to other SAMR ChangePasswordUser levels
[sfrench/samba-autobuild/.git] / source4 / libnet / libnet_passwd.c
1 /* 
2    Unix SMB/CIFS implementation.
3    
4    Copyright (C) Stefan Metzmacher      2004
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22
23 /*
24  * do a password change using DCERPC/SAMR calls
25  * 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation)
26  * 2. try samr_ChangePassword3
27  */
28 static NTSTATUS libnet_ChangePassword_rpc(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_ChangePassword *r)
29 {
30         NTSTATUS status;
31         union libnet_rpc_connect c;
32 #if 0
33         struct policy_handle user_handle;
34         struct samr_Password hash1, hash2, hash3, hash4, hash5, hash6;
35         struct samr_ChangePasswordUser pw;
36 #endif
37         struct samr_OemChangePasswordUser2 oe2;
38         struct samr_ChangePasswordUser2 pw2;
39         struct samr_ChangePasswordUser3 pw3;
40         struct samr_Name server, account;
41         struct samr_AsciiName a_server, a_account;
42         struct samr_CryptPassword nt_pass, lm_pass;
43         struct samr_Password nt_verifier, lm_verifier;
44         uint8_t old_nt_hash[16], new_nt_hash[16];
45         uint8_t old_lm_hash[16], new_lm_hash[16];
46
47         /* prepare connect to the SAMR pipe of the */
48         c.pdc.level                     = LIBNET_RPC_CONNECT_PDC;
49         c.pdc.in.domain_name            = r->rpc.in.domain_name;
50         c.pdc.in.dcerpc_iface_name      = DCERPC_SAMR_NAME;
51         c.pdc.in.dcerpc_iface_uuid      = DCERPC_SAMR_UUID;
52         c.pdc.in.dcerpc_iface_version   = DCERPC_SAMR_VERSION;
53
54         /* do connect to the SAMR pipe of the */
55         status = libnet_rpc_connect(ctx, mem_ctx, &c);
56         if (!NT_STATUS_IS_OK(status)) {
57                 r->rpc.out.error_string = talloc_asprintf(mem_ctx,
58                                                 "Connection to SAMR pipe of PDC of domain '%s' failed: %s\n",
59                                                 r->rpc.in.domain_name, nt_errstr(status));
60                 return status;
61         }
62
63         /* prepare password change for account */
64         server.name = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(c.pdc.out.dcerpc_pipe));
65         account.name = r->rpc.in.account_name;
66
67         E_md4hash(r->rpc.in.oldpassword, old_nt_hash);
68         E_md4hash(r->rpc.in.newpassword, new_nt_hash);
69
70         E_deshash(r->rpc.in.oldpassword, old_lm_hash);
71         E_deshash(r->rpc.in.newpassword, new_lm_hash);
72
73         encode_pw_buffer(lm_pass.data, r->rpc.in.newpassword, STR_UNICODE);
74         arcfour_crypt(lm_pass.data, old_nt_hash, 516);
75         E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash);
76
77         encode_pw_buffer(nt_pass.data,  r->rpc.in.newpassword, STR_UNICODE);
78         arcfour_crypt(nt_pass.data, old_nt_hash, 516);
79         E_old_pw_hash(new_nt_hash, old_nt_hash, nt_verifier.hash);
80
81         pw3.in.server = &server;
82         pw3.in.account = &account;
83         pw3.in.nt_password = &nt_pass;
84         pw3.in.nt_verifier = &nt_verifier;
85         pw3.in.lm_change = 1;
86         pw3.in.lm_password = &lm_pass;
87         pw3.in.lm_verifier = &lm_verifier;
88         pw3.in.password3 = NULL;
89
90         /* do password change for account */
91         status = dcerpc_samr_ChangePasswordUser3(c.pdc.out.dcerpc_pipe, mem_ctx, &pw3);
92         if (!NT_STATUS_IS_OK(status)) {
93                 r->rpc.out.error_string = talloc_asprintf(mem_ctx,
94                                                 "ChangePasswordUser3 failed: %s\n",nt_errstr(status));
95                 goto ChangePasswordUser2;
96         }
97
98         /* check result of password change */
99         if (!NT_STATUS_IS_OK(pw3.out.result)) {
100                 r->rpc.out.error_string = talloc_asprintf(mem_ctx,
101                                                 "ChangePasswordUser3 for '%s\\%s' failed: %s\n",
102                                                 r->rpc.in.domain_name, r->rpc.in.account_name, 
103                                                 nt_errstr(status));
104                                                 /* TODO: give the reason of the reject */
105                 goto ChangePasswordUser2;
106         }
107
108         goto disconnect;
109
110 ChangePasswordUser2:
111
112         encode_pw_buffer(lm_pass.data, r->rpc.in.newpassword, STR_ASCII|STR_TERMINATE);
113         arcfour_crypt(lm_pass.data, old_lm_hash, 516);
114         E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash);
115
116         encode_pw_buffer(nt_pass.data, r->rpc.in.newpassword, STR_UNICODE);
117         arcfour_crypt(nt_pass.data, old_nt_hash, 516);
118         E_old_pw_hash(new_nt_hash, old_nt_hash, nt_verifier.hash);
119
120         pw2.in.server = &server;
121         pw2.in.account = &account;
122         pw2.in.nt_password = &nt_pass;
123         pw2.in.nt_verifier = &nt_verifier;
124         pw2.in.lm_change = 1;
125         pw2.in.lm_password = &lm_pass;
126         pw2.in.lm_verifier = &lm_verifier;
127
128         status = dcerpc_samr_ChangePasswordUser2(c.pdc.out.dcerpc_pipe, mem_ctx, &pw2);
129         if (!NT_STATUS_IS_OK(status)) {
130                 r->rpc.out.error_string = talloc_asprintf(mem_ctx,
131                                                 "ChangePasswordUser2 failed: %s\n",nt_errstr(status));
132                 goto OemChangePasswordUser2;
133         }
134
135         /* check result of password change */
136         if (!NT_STATUS_IS_OK(pw2.out.result)) {
137                 r->rpc.out.error_string = talloc_asprintf(mem_ctx,
138                                                 "ChangePasswordUser2 for '%s\\%s' failed: %s\n",
139                                                 r->rpc.in.domain_name, r->rpc.in.account_name, 
140                                                 nt_errstr(status));
141                 goto OemChangePasswordUser2;
142         }
143
144         goto disconnect;
145
146 OemChangePasswordUser2:
147
148         a_server.name = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(c.pdc.out.dcerpc_pipe));
149         a_account.name = r->rpc.in.account_name;
150
151         encode_pw_buffer(lm_pass.data, r->rpc.in.newpassword, STR_ASCII);
152         arcfour_crypt(lm_pass.data, old_lm_hash, 516);
153         E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash);
154
155         oe2.in.server = &a_server;
156         oe2.in.account = &a_account;
157         oe2.in.password = &lm_pass;
158         oe2.in.hash = &lm_verifier;
159
160         status = dcerpc_samr_OemChangePasswordUser2(c.pdc.out.dcerpc_pipe, mem_ctx, &oe2);
161         if (!NT_STATUS_IS_OK(status)) {
162                 r->rpc.out.error_string = talloc_asprintf(mem_ctx,
163                                                 "OemChangePasswordUser2 failed: %s\n",nt_errstr(status));
164                 goto ChangePasswordUser;
165         }
166
167         /* check result of password change */
168         if (!NT_STATUS_IS_OK(pw2.out.result)) {
169                 r->rpc.out.error_string = talloc_asprintf(mem_ctx,
170                                                 "OemChangePasswordUser2 for '%s\\%s' failed: %s\n",
171                                                 r->rpc.in.domain_name, r->rpc.in.account_name, 
172                                                 nt_errstr(status));
173                 goto ChangePasswordUser;
174         }
175
176         goto disconnect;
177
178 ChangePasswordUser:
179 #if 0
180         E_old_pw_hash(new_lm_hash, old_lm_hash, hash1.hash);
181         E_old_pw_hash(old_lm_hash, new_lm_hash, hash2.hash);
182         E_old_pw_hash(new_nt_hash, old_nt_hash, hash3.hash);
183         E_old_pw_hash(old_nt_hash, new_nt_hash, hash4.hash);
184         E_old_pw_hash(old_lm_hash, new_nt_hash, hash5.hash);
185         E_old_pw_hash(old_nt_hash, new_lm_hash, hash6.hash);
186
187         /* TODO: ask for a user_handle */
188         pw.in.handle = &user_handle;
189         pw.in.lm_present = 1;
190         pw.in.old_lm_crypted = &hash1;
191         pw.in.new_lm_crypted = &hash2;
192         pw.in.nt_present = 1;
193         pw.in.old_nt_crypted = &hash3;
194         pw.in.new_nt_crypted = &hash4;
195         pw.in.cross1_present = 1;
196         pw.in.nt_cross = &hash5;
197         pw.in.cross2_present = 1;
198         pw.in.lm_cross = &hash6;
199
200         status = dcerpc_samr_ChangePasswordUser(c.pdc.out.dcerpc_pipe, mem_ctx, &pw);
201         if (!NT_STATUS_IS_OK(status)) {
202                 r->rpc.out.error_string = talloc_asprintf(mem_ctx,
203                                                 "ChangePasswordUser failed: %s\n",nt_errstr(status));
204                 goto disconnect;
205         }
206
207         /* check result of password change */
208         if (!NT_STATUS_IS_OK(pw2.out.result)) {
209                 r->rpc.out.error_string = talloc_asprintf(mem_ctx,
210                                                 "ChangePasswordUser for '%s\\%s' failed: %s\n",
211                                                 r->rpc.in.domain_name, r->rpc.in.account_name, 
212                                                 nt_errstr(status));
213                 goto disconnect;
214         }
215 #endif
216 disconnect:
217         /* close connection */
218         dcerpc_pipe_close(c.pdc.out.dcerpc_pipe);
219
220         return status;
221 }
222
223 static NTSTATUS libnet_ChangePassword_generic(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_ChangePassword *r)
224 {
225         NTSTATUS status;
226         union libnet_ChangePassword r2;
227
228         r2.rpc.level            = LIBNET_CHANGE_PASSWORD_RPC;
229         r2.rpc.in.account_name  = r->generic.in.account_name;
230         r2.rpc.in.domain_name   = r->generic.in.domain_name;
231         r2.rpc.in.oldpassword   = r->generic.in.oldpassword;
232         r2.rpc.in.newpassword   = r->generic.in.newpassword;
233
234         status = libnet_ChangePassword(ctx, mem_ctx, &r2);
235
236         r->generic.out.error_string = r2.rpc.out.error_string;
237
238         return status;
239 }
240
241 NTSTATUS libnet_ChangePassword(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_ChangePassword *r)
242 {
243         switch (r->generic.level) {
244                 case LIBNET_CHANGE_PASSWORD_GENERIC:
245                         return libnet_ChangePassword_generic(ctx, mem_ctx, r);
246                 case LIBNET_CHANGE_PASSWORD_RPC:
247                         return libnet_ChangePassword_rpc(ctx, mem_ctx, r);
248                 case LIBNET_CHANGE_PASSWORD_KRB5:
249                         return NT_STATUS_NOT_IMPLEMENTED;
250                 case LIBNET_CHANGE_PASSWORD_LDAP:
251                         return NT_STATUS_NOT_IMPLEMENTED;
252                 case LIBNET_CHANGE_PASSWORD_RAP:
253                         return NT_STATUS_NOT_IMPLEMENTED;
254         }
255
256         return NT_STATUS_INVALID_LEVEL;
257 }
258
259 /*
260  * set a password with DCERPC/SAMR calls
261  */
262 static NTSTATUS libnet_SetPassword_rpc(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
263 {
264         return NT_STATUS_NOT_IMPLEMENTED;
265 }
266
267 static NTSTATUS libnet_SetPassword_generic(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
268 {
269         return NT_STATUS_NOT_IMPLEMENTED;
270 }
271
272 NTSTATUS libnet_SetPassword(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
273 {
274         switch (r->generic.level) {
275                 case LIBNET_SET_PASSWORD_GENERIC:
276                         return libnet_SetPassword_generic(ctx, mem_ctx, r);
277                 case LIBNET_SET_PASSWORD_RPC:
278                         return libnet_SetPassword_rpc(ctx, mem_ctx, r);
279                 case LIBNET_SET_PASSWORD_KRB5:
280                         return NT_STATUS_NOT_IMPLEMENTED;
281                 case LIBNET_SET_PASSWORD_LDAP:
282                         return NT_STATUS_NOT_IMPLEMENTED;
283                 case LIBNET_SET_PASSWORD_RAP:
284                         return NT_STATUS_NOT_IMPLEMENTED;
285         }
286
287         return NT_STATUS_INVALID_LEVEL;
288 }