r25026: Move param/param.h out of includes.h
[kai/samba-autobuild/.git] / source4 / rpc_server / samr / samr_password.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    samr server password set/change handling
5
6    Copyright (C) Andrew Tridgell 2004
7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "rpc_server/dcerpc_server.h"
25 #include "rpc_server/common/common.h"
26 #include "rpc_server/samr/dcesrv_samr.h"
27 #include "system/time.h"
28 #include "lib/crypto/crypto.h"
29 #include "dsdb/common/flags.h"
30 #include "libcli/ldap/ldap.h"
31 #include "dsdb/samdb/samdb.h"
32 #include "auth/auth.h"
33 #include "rpc_server/samr/proto.h"
34 #include "libcli/auth/libcli_auth.h"
35 #include "db_wrap.h"
36
37 /* 
38   samr_ChangePasswordUser 
39 */
40 NTSTATUS dcesrv_samr_ChangePasswordUser(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
41                                  struct samr_ChangePasswordUser *r)
42 {
43         struct dcesrv_handle *h;
44         struct samr_account_state *a_state;
45         struct ldb_context *sam_ctx;
46         struct ldb_message **res, *msg;
47         int ret;
48         struct samr_Password new_lmPwdHash, new_ntPwdHash, checkHash;
49         struct samr_Password *lm_pwd, *nt_pwd;
50         NTSTATUS status = NT_STATUS_OK;
51         const char * const attrs[] = { "dBCSPwd", "unicodePwd" , NULL };
52
53         DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);
54
55         a_state = h->data;
56
57         /* basic sanity checking on parameters.  Do this before any database ops */
58         if (!r->in.lm_present || !r->in.nt_present ||
59             !r->in.old_lm_crypted || !r->in.new_lm_crypted ||
60             !r->in.old_nt_crypted || !r->in.new_nt_crypted) {
61                 /* we should really handle a change with lm not
62                    present */
63                 return NT_STATUS_INVALID_PARAMETER_MIX;
64         }
65
66         /* To change a password we need to open as system */
67         sam_ctx = samdb_connect(mem_ctx, system_session(mem_ctx));
68         if (sam_ctx == NULL) {
69                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
70         }
71
72         ret = ldb_transaction_start(sam_ctx);
73         if (ret) {
74                 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
75                 return NT_STATUS_TRANSACTION_ABORTED;
76         }
77
78         /* fetch the old hashes */
79         ret = gendb_search_dn(sam_ctx, mem_ctx,
80                               a_state->account_dn, &res, attrs);
81         if (ret != 1) {
82                 ldb_transaction_cancel(sam_ctx);
83                 return NT_STATUS_WRONG_PASSWORD;
84         }
85         msg = res[0];
86
87         status = samdb_result_passwords(mem_ctx, msg, &lm_pwd, &nt_pwd);
88         if (!NT_STATUS_IS_OK(status) || !lm_pwd || !nt_pwd) {
89                 ldb_transaction_cancel(sam_ctx);
90                 return NT_STATUS_WRONG_PASSWORD;
91         }
92
93         /* decrypt and check the new lm hash */
94         D_P16(lm_pwd->hash, r->in.new_lm_crypted->hash, new_lmPwdHash.hash);
95         D_P16(new_lmPwdHash.hash, r->in.old_lm_crypted->hash, checkHash.hash);
96         if (memcmp(checkHash.hash, lm_pwd, 16) != 0) {
97                 ldb_transaction_cancel(sam_ctx);
98                 return NT_STATUS_WRONG_PASSWORD;
99         }
100
101         /* decrypt and check the new nt hash */
102         D_P16(nt_pwd->hash, r->in.new_nt_crypted->hash, new_ntPwdHash.hash);
103         D_P16(new_ntPwdHash.hash, r->in.old_nt_crypted->hash, checkHash.hash);
104         if (memcmp(checkHash.hash, nt_pwd, 16) != 0) {
105                 ldb_transaction_cancel(sam_ctx);
106                 return NT_STATUS_WRONG_PASSWORD;
107         }
108         
109         /* The NT Cross is not required by Win2k3 R2, but if present
110            check the nt cross hash */
111         if (r->in.cross1_present && r->in.nt_cross) {
112                 D_P16(lm_pwd->hash, r->in.nt_cross->hash, checkHash.hash);
113                 if (memcmp(checkHash.hash, new_ntPwdHash.hash, 16) != 0) {
114                         ldb_transaction_cancel(sam_ctx);
115                         return NT_STATUS_WRONG_PASSWORD;
116                 }
117         }
118
119         /* The LM Cross is not required by Win2k3 R2, but if present
120            check the lm cross hash */
121         if (r->in.cross2_present && r->in.lm_cross) {
122                 D_P16(nt_pwd->hash, r->in.lm_cross->hash, checkHash.hash);
123                 if (memcmp(checkHash.hash, new_lmPwdHash.hash, 16) != 0) {
124                         ldb_transaction_cancel(sam_ctx);
125                         return NT_STATUS_WRONG_PASSWORD;
126                 }
127         }
128
129         msg = ldb_msg_new(mem_ctx);
130         if (msg == NULL) {
131                 ldb_transaction_cancel(sam_ctx);
132                 return NT_STATUS_NO_MEMORY;
133         }
134
135         msg->dn = ldb_dn_copy(msg, a_state->account_dn);
136         if (!msg->dn) {
137                 ldb_transaction_cancel(sam_ctx);
138                 return NT_STATUS_NO_MEMORY;
139         }
140
141         /* setup password modify mods on the user DN specified.  This may fail
142          * due to password policies.  */
143         status = samdb_set_password(sam_ctx, mem_ctx,
144                                     a_state->account_dn, a_state->domain_state->domain_dn,
145                                     msg, NULL, &new_lmPwdHash, &new_ntPwdHash, 
146                                     True, /* this is a user password change */
147                                     NULL,
148                                     NULL);
149         if (!NT_STATUS_IS_OK(status)) {
150                 ldb_transaction_cancel(sam_ctx);
151                 return status;
152         }
153
154         /* The above call only setup the modifications, this actually
155          * makes the write to the database. */
156         ret = samdb_replace(sam_ctx, mem_ctx, msg);
157         if (ret != 0) {
158                 DEBUG(2,("Failed to modify record to change password on %s: %s\n",
159                          ldb_dn_get_linearized(a_state->account_dn),
160                          ldb_errstring(sam_ctx)));
161                 ldb_transaction_cancel(sam_ctx);
162                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
163         }
164
165         /* And this confirms it in a transaction commit */
166         ret = ldb_transaction_commit(sam_ctx);
167         if (ret != 0) {
168                 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
169                          ldb_dn_get_linearized(a_state->account_dn),
170                          ldb_errstring(sam_ctx)));
171                 return NT_STATUS_TRANSACTION_ABORTED;
172         }
173
174         return NT_STATUS_OK;
175 }
176
177 /* 
178   samr_OemChangePasswordUser2 
179 */
180 NTSTATUS dcesrv_samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
181                                      struct samr_OemChangePasswordUser2 *r)
182 {
183         NTSTATUS status;
184         char new_pass[512];
185         uint32_t new_pass_len;
186         struct samr_CryptPassword *pwbuf = r->in.password;
187         struct ldb_context *sam_ctx;
188         struct ldb_dn *user_dn;
189         int ret;
190         struct ldb_message **res, *mod;
191         const char * const attrs[] = { "objectSid", "dBCSPwd", NULL };
192         struct samr_Password *lm_pwd;
193         DATA_BLOB lm_pwd_blob;
194         uint8_t new_lm_hash[16];
195         struct samr_Password lm_verifier;
196
197         if (pwbuf == NULL) {
198                 return NT_STATUS_INVALID_PARAMETER;
199         }
200
201         if (r->in.hash == NULL) {
202                 return NT_STATUS_INVALID_PARAMETER;
203         }
204
205         /* To change a password we need to open as system */
206         sam_ctx = samdb_connect(mem_ctx, system_session(mem_ctx));
207         if (sam_ctx == NULL) {
208                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
209         }
210
211         ret = ldb_transaction_start(sam_ctx);
212         if (ret) {
213                 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
214                 return NT_STATUS_TRANSACTION_ABORTED;
215         }
216
217         /* we need the users dn and the domain dn (derived from the
218            user SID). We also need the current lm password hash in
219            order to decrypt the incoming password */
220         ret = gendb_search(sam_ctx, 
221                            mem_ctx, NULL, &res, attrs,
222                            "(&(sAMAccountName=%s)(objectclass=user))",
223                            r->in.account->string);
224         if (ret != 1) {
225                 ldb_transaction_cancel(sam_ctx);
226                 /* Don't give the game away:  (don't allow anonymous users to prove the existance of usernames) */
227                 return NT_STATUS_WRONG_PASSWORD;
228         }
229
230         user_dn = res[0]->dn;
231
232         status = samdb_result_passwords(mem_ctx, res[0], &lm_pwd, NULL);
233         if (!NT_STATUS_IS_OK(status) || !lm_pwd) {
234                 ldb_transaction_cancel(sam_ctx);
235                 return NT_STATUS_WRONG_PASSWORD;
236         }
237
238         /* decrypt the password we have been given */
239         lm_pwd_blob = data_blob(lm_pwd->hash, sizeof(lm_pwd->hash)); 
240         arcfour_crypt_blob(pwbuf->data, 516, &lm_pwd_blob);
241         data_blob_free(&lm_pwd_blob);
242         
243         if (!decode_pw_buffer(pwbuf->data, new_pass, sizeof(new_pass),
244                               &new_pass_len, STR_ASCII)) {
245                 ldb_transaction_cancel(sam_ctx);
246                 DEBUG(3,("samr: failed to decode password buffer\n"));
247                 return NT_STATUS_WRONG_PASSWORD;
248         }
249
250         /* check LM verifier */
251         if (lm_pwd == NULL) {
252                 ldb_transaction_cancel(sam_ctx);
253                 return NT_STATUS_WRONG_PASSWORD;
254         }
255
256         E_deshash(new_pass, new_lm_hash);
257         E_old_pw_hash(new_lm_hash, lm_pwd->hash, lm_verifier.hash);
258         if (memcmp(lm_verifier.hash, r->in.hash->hash, 16) != 0) {
259                 ldb_transaction_cancel(sam_ctx);
260                 return NT_STATUS_WRONG_PASSWORD;
261         }
262
263         mod = ldb_msg_new(mem_ctx);
264         if (mod == NULL) {
265                 ldb_transaction_cancel(sam_ctx);
266                 return NT_STATUS_NO_MEMORY;
267         }
268
269         mod->dn = ldb_dn_copy(mod, user_dn);
270         if (!mod->dn) {
271                 ldb_transaction_cancel(sam_ctx);
272                 return NT_STATUS_NO_MEMORY;
273         }
274
275         /* set the password on the user DN specified.  This may fail
276          * due to password policies */
277         status = samdb_set_password(sam_ctx, mem_ctx,
278                                     user_dn, NULL, 
279                                     mod, new_pass, 
280                                     NULL, NULL,
281                                     True, /* this is a user password change */
282                                     NULL, 
283                                     NULL);
284         if (!NT_STATUS_IS_OK(status)) {
285                 ldb_transaction_cancel(sam_ctx);
286                 return status;
287         }
288
289         /* The above call only setup the modifications, this actually
290          * makes the write to the database. */
291         ret = samdb_replace(sam_ctx, mem_ctx, mod);
292         if (ret != 0) {
293                 DEBUG(2,("Failed to modify record to change password on %s: %s\n",
294                          ldb_dn_get_linearized(user_dn),
295                          ldb_errstring(sam_ctx)));
296                 ldb_transaction_cancel(sam_ctx);
297                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
298         }
299
300         /* And this confirms it in a transaction commit */
301         ret = ldb_transaction_commit(sam_ctx);
302         if (ret != 0) {
303                 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
304                          ldb_dn_get_linearized(user_dn),
305                          ldb_errstring(sam_ctx)));
306                 return NT_STATUS_TRANSACTION_ABORTED;
307         }
308
309         return NT_STATUS_OK;
310 }
311
312
313 /* 
314   samr_ChangePasswordUser3 
315 */
316 NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call, 
317                                   TALLOC_CTX *mem_ctx,
318                                   struct samr_ChangePasswordUser3 *r)
319 {       
320         NTSTATUS status;
321         char new_pass[512];
322         uint32_t new_pass_len;
323         struct ldb_context *sam_ctx = NULL;
324         struct ldb_dn *user_dn;
325         int ret;
326         struct ldb_message **res, *mod;
327         const char * const attrs[] = { "unicodePwd", "dBCSPwd", NULL };
328         struct samr_Password *nt_pwd, *lm_pwd;
329         DATA_BLOB nt_pwd_blob;
330         struct samr_DomInfo1 *dominfo = NULL;
331         struct samr_ChangeReject *reject = NULL;
332         enum samr_RejectReason reason = SAMR_REJECT_OTHER;
333         uint8_t new_nt_hash[16], new_lm_hash[16];
334         struct samr_Password nt_verifier, lm_verifier;
335
336         ZERO_STRUCT(r->out);
337
338         if (r->in.nt_password == NULL ||
339             r->in.nt_verifier == NULL) {
340                 return NT_STATUS_INVALID_PARAMETER;
341         }
342
343         /* To change a password we need to open as system */
344         sam_ctx = samdb_connect(mem_ctx, system_session(mem_ctx));
345         if (sam_ctx == NULL) {
346                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
347         }
348
349         ret = ldb_transaction_start(sam_ctx);
350         if (ret) {
351                 talloc_free(sam_ctx);
352                 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
353                 return NT_STATUS_TRANSACTION_ABORTED;
354         }
355
356         /* we need the users dn and the domain dn (derived from the
357            user SID). We also need the current lm and nt password hashes
358            in order to decrypt the incoming passwords */
359         ret = gendb_search(sam_ctx, 
360                            mem_ctx, NULL, &res, attrs,
361                            "(&(sAMAccountName=%s)(objectclass=user))",
362                            r->in.account->string);
363         if (ret != 1) {
364                 /* Don't give the game away:  (don't allow anonymous users to prove the existance of usernames) */
365                 status = NT_STATUS_WRONG_PASSWORD;
366                 goto failed;
367         }
368
369         user_dn = res[0]->dn;
370
371         status = samdb_result_passwords(mem_ctx, res[0], &lm_pwd, &nt_pwd);
372         if (!NT_STATUS_IS_OK(status) ) {
373                 goto failed;
374         }
375
376         if (!nt_pwd) {
377                 status = NT_STATUS_WRONG_PASSWORD;
378                 goto failed;
379         }
380
381         /* decrypt the password we have been given */
382         nt_pwd_blob = data_blob(nt_pwd->hash, sizeof(nt_pwd->hash));
383         arcfour_crypt_blob(r->in.nt_password->data, 516, &nt_pwd_blob);
384         data_blob_free(&nt_pwd_blob);
385
386         if (!decode_pw_buffer(r->in.nt_password->data, new_pass, sizeof(new_pass),
387                               &new_pass_len, STR_UNICODE)) {
388                 DEBUG(3,("samr: failed to decode password buffer\n"));
389                 status = NT_STATUS_WRONG_PASSWORD;
390                 goto failed;
391         }
392
393         if (r->in.nt_verifier == NULL) {
394                 status = NT_STATUS_WRONG_PASSWORD;
395                 goto failed;
396         }
397
398         /* check NT verifier */
399         E_md4hash(new_pass, new_nt_hash);
400         E_old_pw_hash(new_nt_hash, nt_pwd->hash, nt_verifier.hash);
401         if (memcmp(nt_verifier.hash, r->in.nt_verifier->hash, 16) != 0) {
402                 status = NT_STATUS_WRONG_PASSWORD;
403                 goto failed;
404         }
405
406         /* check LM verifier */
407         if (lm_pwd && r->in.lm_verifier != NULL) {
408                 E_deshash(new_pass, new_lm_hash);
409                 E_old_pw_hash(new_nt_hash, lm_pwd->hash, lm_verifier.hash);
410                 if (memcmp(lm_verifier.hash, r->in.lm_verifier->hash, 16) != 0) {
411                         status = NT_STATUS_WRONG_PASSWORD;
412                         goto failed;
413                 }
414         }
415
416
417         mod = ldb_msg_new(mem_ctx);
418         if (mod == NULL) {
419                 return NT_STATUS_NO_MEMORY;
420         }
421
422         mod->dn = ldb_dn_copy(mod, user_dn);
423         if (!mod->dn) {
424                 status = NT_STATUS_NO_MEMORY;
425                 goto failed;
426         }
427
428         /* set the password on the user DN specified.  This may fail
429          * due to password policies */
430         status = samdb_set_password(sam_ctx, mem_ctx,
431                                     user_dn, NULL, 
432                                     mod, new_pass, 
433                                     NULL, NULL,
434                                     True, /* this is a user password change */
435                                     &reason, 
436                                     &dominfo);
437         if (!NT_STATUS_IS_OK(status)) {
438                 goto failed;
439         }
440
441         /* The above call only setup the modifications, this actually
442          * makes the write to the database. */
443         ret = samdb_replace(sam_ctx, mem_ctx, mod);
444         if (ret != 0) {
445                 DEBUG(2,("samdb_replace failed to change password for %s: %s\n",
446                          ldb_dn_get_linearized(user_dn),
447                          ldb_errstring(sam_ctx)));
448                 status = NT_STATUS_UNSUCCESSFUL;
449                 goto failed;
450         }
451
452         /* And this confirms it in a transaction commit */
453         ret = ldb_transaction_commit(sam_ctx);
454         if (ret != 0) {
455                 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
456                          ldb_dn_get_linearized(user_dn),
457                          ldb_errstring(sam_ctx)));
458                 status = NT_STATUS_TRANSACTION_ABORTED;
459                 goto failed;
460         }
461
462         return NT_STATUS_OK;
463
464 failed:
465         ldb_transaction_cancel(sam_ctx);
466         talloc_free(sam_ctx);
467
468         reject = talloc(mem_ctx, struct samr_ChangeReject);
469         r->out.dominfo = dominfo;
470         r->out.reject = reject;
471
472         if (reject == NULL) {
473                 return status;
474         }
475         ZERO_STRUCTP(reject);
476
477         reject->reason = reason;
478
479         return status;
480 }
481
482
483 /* 
484   samr_ChangePasswordUser2 
485
486   easy - just a subset of samr_ChangePasswordUser3
487 */
488 NTSTATUS dcesrv_samr_ChangePasswordUser2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
489                                   struct samr_ChangePasswordUser2 *r)
490 {
491         struct samr_ChangePasswordUser3 r2;
492
493         r2.in.server = r->in.server;
494         r2.in.account = r->in.account;
495         r2.in.nt_password = r->in.nt_password;
496         r2.in.nt_verifier = r->in.nt_verifier;
497         r2.in.lm_change = r->in.lm_change;
498         r2.in.lm_password = r->in.lm_password;
499         r2.in.lm_verifier = r->in.lm_verifier;
500         r2.in.password3 = NULL;
501
502         return dcesrv_samr_ChangePasswordUser3(dce_call, mem_ctx, &r2);
503 }
504
505
506 /*
507   set password via a samr_CryptPassword buffer
508   this will in the 'msg' with modify operations that will update the user
509   password when applied
510 */
511 NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call,
512                            void *sam_ctx,
513                            struct ldb_dn *account_dn, struct ldb_dn *domain_dn,
514                            TALLOC_CTX *mem_ctx,
515                            struct ldb_message *msg, 
516                            struct samr_CryptPassword *pwbuf)
517 {
518         NTSTATUS nt_status;
519         char new_pass[512];
520         uint32_t new_pass_len;
521         DATA_BLOB session_key = data_blob(NULL, 0);
522
523         nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
524         if (!NT_STATUS_IS_OK(nt_status)) {
525                 return nt_status;
526         }
527
528         arcfour_crypt_blob(pwbuf->data, 516, &session_key);
529
530         if (!decode_pw_buffer(pwbuf->data, new_pass, sizeof(new_pass),
531                               &new_pass_len, STR_UNICODE)) {
532                 DEBUG(3,("samr: failed to decode password buffer\n"));
533                 return NT_STATUS_WRONG_PASSWORD;
534         }
535
536         /* set the password - samdb needs to know both the domain and user DNs,
537            so the domain password policy can be used */
538         return samdb_set_password(sam_ctx, mem_ctx,
539                                   account_dn, domain_dn, 
540                                   msg, new_pass, 
541                                   NULL, NULL,
542                                   False, /* This is a password set, not change */
543                                   NULL, NULL);
544 }
545
546
547 /*
548   set password via a samr_CryptPasswordEx buffer
549   this will in the 'msg' with modify operations that will update the user
550   password when applied
551 */
552 NTSTATUS samr_set_password_ex(struct dcesrv_call_state *dce_call,
553                               struct ldb_context *sam_ctx,
554                               struct ldb_dn *account_dn, struct ldb_dn *domain_dn,
555                               TALLOC_CTX *mem_ctx,
556                               struct ldb_message *msg, 
557                               struct samr_CryptPasswordEx *pwbuf)
558 {
559         NTSTATUS nt_status;
560         char new_pass[512];
561         uint32_t new_pass_len;
562         DATA_BLOB co_session_key;
563         DATA_BLOB session_key = data_blob(NULL, 0);
564         struct MD5Context ctx;
565
566         nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
567         if (!NT_STATUS_IS_OK(nt_status)) {
568                 return nt_status;
569         }
570
571         co_session_key = data_blob_talloc(mem_ctx, NULL, 16);
572         if (!co_session_key.data) {
573                 return NT_STATUS_NO_MEMORY;
574         }
575
576         MD5Init(&ctx);
577         MD5Update(&ctx, &pwbuf->data[516], 16);
578         MD5Update(&ctx, session_key.data, session_key.length);
579         MD5Final(co_session_key.data, &ctx);
580         
581         arcfour_crypt_blob(pwbuf->data, 516, &co_session_key);
582
583         if (!decode_pw_buffer(pwbuf->data, new_pass, sizeof(new_pass),
584                               &new_pass_len, STR_UNICODE)) {
585                 DEBUG(3,("samr: failed to decode password buffer\n"));
586                 return NT_STATUS_WRONG_PASSWORD;
587         }
588
589         /* set the password - samdb needs to know both the domain and user DNs,
590            so the domain password policy can be used */
591         return samdb_set_password(sam_ctx, mem_ctx,
592                                   account_dn, domain_dn, 
593                                   msg, new_pass, 
594                                   NULL, NULL,
595                                   False, /* This is a password set, not change */
596                                   NULL, NULL);
597 }
598
599