383fce1223f8473c29c7685a6f22df68c32cb157
[sfrench/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/samr/dcesrv_samr.h"
26 #include "system/time.h"
27 #include "../lib/crypto/crypto.h"
28 #include "dsdb/samdb/samdb.h"
29 #include "auth/auth.h"
30 #include "libcli/auth/libcli_auth.h"
31 #include "../lib/util/util_ldb.h"
32 #include "rpc_server/samr/proto.h"
33 #include "auth/auth_sam.h"
34
35 /*
36   samr_ChangePasswordUser
37
38   So old it is just not worth implementing
39   because it does not supply a plaintext and so we can't do password
40   complexity checking and cannot update all the other password hashes.
41
42 */
43 NTSTATUS dcesrv_samr_ChangePasswordUser(struct dcesrv_call_state *dce_call,
44                                         TALLOC_CTX *mem_ctx,
45                                         struct samr_ChangePasswordUser *r)
46 {
47         return NT_STATUS_NOT_IMPLEMENTED;
48 }
49
50 /*
51   samr_OemChangePasswordUser2
52 */
53 NTSTATUS dcesrv_samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call,
54                                             TALLOC_CTX *mem_ctx,
55                                             struct samr_OemChangePasswordUser2 *r)
56 {
57         NTSTATUS status;
58         DATA_BLOB new_password, new_unicode_password;
59         char *new_pass;
60         struct samr_CryptPassword *pwbuf = r->in.password;
61         struct ldb_context *sam_ctx;
62         struct ldb_dn *user_dn;
63         int ret;
64         struct ldb_message **res;
65         const char * const attrs[] = { "objectSid", "dBCSPwd",
66                                        "userAccountControl",
67                                        "msDS-User-Account-Control-Computed",
68                                        "badPwdCount", "badPasswordTime",
69                                        NULL };
70         struct samr_Password *lm_pwd;
71         DATA_BLOB lm_pwd_blob;
72         uint8_t new_lm_hash[16];
73         struct samr_Password lm_verifier;
74         size_t unicode_pw_len;
75         size_t converted_size = 0;
76
77         if (pwbuf == NULL) {
78                 return NT_STATUS_INVALID_PARAMETER;
79         }
80
81         if (r->in.hash == NULL) {
82                 return NT_STATUS_INVALID_PARAMETER;
83         }
84
85         /* this call can only work with lanman auth */
86         if (!lpcfg_lanman_auth(dce_call->conn->dce_ctx->lp_ctx)) {
87                 return NT_STATUS_WRONG_PASSWORD;
88         }
89
90         /* Connect to a SAMDB with system privileges for fetching the old pw
91          * hashes. */
92         sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
93                                 dce_call->conn->dce_ctx->lp_ctx,
94                                 system_session(dce_call->conn->dce_ctx->lp_ctx), 0);
95         if (sam_ctx == NULL) {
96                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
97         }
98
99         /* we need the users dn and the domain dn (derived from the
100            user SID). We also need the current lm password hash in
101            order to decrypt the incoming password */
102         ret = gendb_search(sam_ctx,
103                            mem_ctx, NULL, &res, attrs,
104                            "(&(sAMAccountName=%s)(objectclass=user))",
105                            r->in.account->string);
106         if (ret != 1) {
107                 /* Don't give the game away:  (don't allow anonymous users to prove the existance of usernames) */
108                 return NT_STATUS_WRONG_PASSWORD;
109         }
110
111         user_dn = res[0]->dn;
112
113         status = samdb_result_passwords(mem_ctx, dce_call->conn->dce_ctx->lp_ctx,
114                                         res[0], &lm_pwd, NULL);
115         if (!NT_STATUS_IS_OK(status)) {
116                 return status;
117         } else if (!lm_pwd) {
118                 return NT_STATUS_WRONG_PASSWORD;
119         }
120
121         /* decrypt the password we have been given */
122         lm_pwd_blob = data_blob(lm_pwd->hash, sizeof(lm_pwd->hash));
123         arcfour_crypt_blob(pwbuf->data, 516, &lm_pwd_blob);
124         data_blob_free(&lm_pwd_blob);
125
126         if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
127                 DEBUG(3,("samr: failed to decode password buffer\n"));
128                 authsam_update_bad_pwd_count(sam_ctx, res[0], ldb_get_default_basedn(sam_ctx));
129                 return NT_STATUS_WRONG_PASSWORD;
130         }
131
132         if (!convert_string_talloc_handle(mem_ctx, lpcfg_iconv_handle(dce_call->conn->dce_ctx->lp_ctx),
133                                   CH_DOS, CH_UNIX,
134                                   (const char *)new_password.data,
135                                   new_password.length,
136                                   (void **)&new_pass, &converted_size)) {
137                 DEBUG(3,("samr: failed to convert incoming password buffer to unix charset\n"));
138                 authsam_update_bad_pwd_count(sam_ctx, res[0], ldb_get_default_basedn(sam_ctx));
139                 return NT_STATUS_WRONG_PASSWORD;
140         }
141
142         if (!convert_string_talloc_handle(mem_ctx, lpcfg_iconv_handle(dce_call->conn->dce_ctx->lp_ctx),
143                                                CH_DOS, CH_UTF16,
144                                                (const char *)new_password.data,
145                                                new_password.length,
146                                                (void **)&new_unicode_password.data, &unicode_pw_len)) {
147                 DEBUG(3,("samr: failed to convert incoming password buffer to UTF16 charset\n"));
148                 authsam_update_bad_pwd_count(sam_ctx, res[0], ldb_get_default_basedn(sam_ctx));
149                 return NT_STATUS_WRONG_PASSWORD;
150         }
151         new_unicode_password.length = unicode_pw_len;
152
153         E_deshash(new_pass, new_lm_hash);
154         E_old_pw_hash(new_lm_hash, lm_pwd->hash, lm_verifier.hash);
155         if (memcmp(lm_verifier.hash, r->in.hash->hash, 16) != 0) {
156                 authsam_update_bad_pwd_count(sam_ctx, res[0], ldb_get_default_basedn(sam_ctx));
157                 return NT_STATUS_WRONG_PASSWORD;
158         }
159
160         /* Connect to a SAMDB with user privileges for the password change */
161         sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
162                                 dce_call->conn->dce_ctx->lp_ctx,
163                                 dce_call->conn->auth_state.session_info, 0);
164         if (sam_ctx == NULL) {
165                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
166         }
167
168         /* Start transaction */
169         ret = ldb_transaction_start(sam_ctx);
170         if (ret != LDB_SUCCESS) {
171                 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
172                 return NT_STATUS_TRANSACTION_ABORTED;
173         }
174
175         /* Performs the password modification. We pass the old hashes read out
176          * from the database since they were already checked against the user-
177          * provided ones. */
178         status = samdb_set_password(sam_ctx, mem_ctx,
179                                     user_dn, NULL,
180                                     &new_unicode_password,
181                                     NULL, NULL,
182                                     lm_pwd, NULL, /* this is a user password change */
183                                     NULL,
184                                     NULL);
185         if (!NT_STATUS_IS_OK(status)) {
186                 ldb_transaction_cancel(sam_ctx);
187                 return status;
188         }
189
190         /* And this confirms it in a transaction commit */
191         ret = ldb_transaction_commit(sam_ctx);
192         if (ret != LDB_SUCCESS) {
193                 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
194                          ldb_dn_get_linearized(user_dn),
195                          ldb_errstring(sam_ctx)));
196                 return NT_STATUS_TRANSACTION_ABORTED;
197         }
198
199         return NT_STATUS_OK;
200 }
201
202
203 /*
204   samr_ChangePasswordUser3
205 */
206 NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call,
207                                          TALLOC_CTX *mem_ctx,
208                                          struct samr_ChangePasswordUser3 *r)
209 {
210         NTSTATUS status;
211         DATA_BLOB new_password;
212         struct ldb_context *sam_ctx = NULL;
213         struct ldb_dn *user_dn = NULL;
214         int ret;
215         struct ldb_message **res;
216         const char * const attrs[] = { "unicodePwd", "dBCSPwd",
217                                        "userAccountControl",
218                                        "msDS-User-Account-Control-Computed",
219                                        "badPwdCount", "badPasswordTime",
220                                        "objectSid", NULL };
221         struct samr_Password *nt_pwd, *lm_pwd;
222         DATA_BLOB nt_pwd_blob;
223         struct samr_DomInfo1 *dominfo = NULL;
224         struct userPwdChangeFailureInformation *reject = NULL;
225         enum samPwdChangeReason reason = SAM_PWD_CHANGE_NO_ERROR;
226         uint8_t new_nt_hash[16], new_lm_hash[16];
227         struct samr_Password nt_verifier, lm_verifier;
228
229         *r->out.dominfo = NULL;
230         *r->out.reject = NULL;
231
232         if (r->in.nt_password == NULL ||
233             r->in.nt_verifier == NULL) {
234                 return NT_STATUS_INVALID_PARAMETER;
235         }
236
237         /* Connect to a SAMDB with system privileges for fetching the old pw
238          * hashes. */
239         sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
240                                 dce_call->conn->dce_ctx->lp_ctx,
241                                 system_session(dce_call->conn->dce_ctx->lp_ctx), 0);
242         if (sam_ctx == NULL) {
243                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
244         }
245
246         /* we need the users dn and the domain dn (derived from the
247            user SID). We also need the current lm and nt password hashes
248            in order to decrypt the incoming passwords */
249         ret = gendb_search(sam_ctx,
250                            mem_ctx, NULL, &res, attrs,
251                            "(&(sAMAccountName=%s)(objectclass=user))",
252                            r->in.account->string);
253         if (ret != 1) {
254                 /* Don't give the game away:  (don't allow anonymous users to prove the existance of usernames) */
255                 status = NT_STATUS_WRONG_PASSWORD;
256                 goto failed;
257         }
258
259         user_dn = res[0]->dn;
260
261         status = samdb_result_passwords(mem_ctx, dce_call->conn->dce_ctx->lp_ctx,
262                                         res[0], &lm_pwd, &nt_pwd);
263         if (!NT_STATUS_IS_OK(status) ) {
264                 goto failed;
265         }
266
267         if (!nt_pwd) {
268                 status = NT_STATUS_WRONG_PASSWORD;
269                 goto failed;
270         }
271
272         /* decrypt the password we have been given */
273         nt_pwd_blob = data_blob(nt_pwd->hash, sizeof(nt_pwd->hash));
274         arcfour_crypt_blob(r->in.nt_password->data, 516, &nt_pwd_blob);
275         data_blob_free(&nt_pwd_blob);
276
277         if (!extract_pw_from_buffer(mem_ctx, r->in.nt_password->data, &new_password)) {
278                 DEBUG(3,("samr: failed to decode password buffer\n"));
279                 status =  NT_STATUS_WRONG_PASSWORD;
280                 goto failed;
281         }
282
283         if (r->in.nt_verifier == NULL) {
284                 status = NT_STATUS_WRONG_PASSWORD;
285                 goto failed;
286         }
287
288         /* check NT verifier */
289         mdfour(new_nt_hash, new_password.data, new_password.length);
290
291         E_old_pw_hash(new_nt_hash, nt_pwd->hash, nt_verifier.hash);
292         if (memcmp(nt_verifier.hash, r->in.nt_verifier->hash, 16) != 0) {
293                 status = NT_STATUS_WRONG_PASSWORD;
294                 goto failed;
295         }
296
297         /* check LM verifier (really not needed as we just checked the
298          * much stronger NT hash, but the RPC-SAMR test checks for
299          * this) */
300         if (lm_pwd && r->in.lm_verifier != NULL) {
301                 char *new_pass;
302                 size_t converted_size = 0;
303
304                 if (!convert_string_talloc_handle(mem_ctx, lpcfg_iconv_handle(dce_call->conn->dce_ctx->lp_ctx),
305                                           CH_UTF16, CH_UNIX,
306                                           (const char *)new_password.data,
307                                           new_password.length,
308                                           (void **)&new_pass, &converted_size)) {
309                         E_deshash(new_pass, new_lm_hash);
310                         E_old_pw_hash(new_nt_hash, lm_pwd->hash, lm_verifier.hash);
311                         if (memcmp(lm_verifier.hash, r->in.lm_verifier->hash, 16) != 0) {
312                                 status = NT_STATUS_WRONG_PASSWORD;
313                                 goto failed;
314                         }
315                 }
316         }
317
318         /* Connect to a SAMDB with user privileges for the password change */
319         sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
320                                 dce_call->conn->dce_ctx->lp_ctx,
321                                 dce_call->conn->auth_state.session_info, 0);
322         if (sam_ctx == NULL) {
323                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
324         }
325
326         ret = ldb_transaction_start(sam_ctx);
327         if (ret != LDB_SUCCESS) {
328                 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
329                 return NT_STATUS_TRANSACTION_ABORTED;
330         }
331
332         /* Performs the password modification. We pass the old hashes read out
333          * from the database since they were already checked against the user-
334          * provided ones. */
335         status = samdb_set_password(sam_ctx, mem_ctx,
336                                     user_dn, NULL,
337                                     &new_password,
338                                     NULL, NULL,
339                                     lm_pwd, nt_pwd, /* this is a user password change */
340                                     &reason,
341                                     &dominfo);
342
343         if (!NT_STATUS_IS_OK(status)) {
344                 ldb_transaction_cancel(sam_ctx);
345                 goto failed;
346         }
347
348         /* And this confirms it in a transaction commit */
349         ret = ldb_transaction_commit(sam_ctx);
350         if (ret != LDB_SUCCESS) {
351                 DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
352                          ldb_dn_get_linearized(user_dn),
353                          ldb_errstring(sam_ctx)));
354                 status = NT_STATUS_TRANSACTION_ABORTED;
355                 goto failed;
356         }
357
358         return NT_STATUS_OK;
359
360 failed:
361         /* Only update the badPwdCount if we found the user */
362         if (user_dn != NULL && NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
363                 authsam_update_bad_pwd_count(sam_ctx, res[0], ldb_get_default_basedn(sam_ctx));
364         }
365
366         reject = talloc_zero(mem_ctx, struct userPwdChangeFailureInformation);
367         if (reject != NULL) {
368                 reject->extendedFailureReason = reason;
369
370                 *r->out.reject = reject;
371         }
372
373         *r->out.dominfo = dominfo;
374
375         return status;
376 }
377
378
379 /*
380   samr_ChangePasswordUser2
381
382   easy - just a subset of samr_ChangePasswordUser3
383 */
384 NTSTATUS dcesrv_samr_ChangePasswordUser2(struct dcesrv_call_state *dce_call,
385                                          TALLOC_CTX *mem_ctx,
386                                          struct samr_ChangePasswordUser2 *r)
387 {
388         struct samr_ChangePasswordUser3 r2;
389         struct samr_DomInfo1 *dominfo = NULL;
390         struct userPwdChangeFailureInformation *reject = NULL;
391
392         r2.in.server = r->in.server;
393         r2.in.account = r->in.account;
394         r2.in.nt_password = r->in.nt_password;
395         r2.in.nt_verifier = r->in.nt_verifier;
396         r2.in.lm_change = r->in.lm_change;
397         r2.in.lm_password = r->in.lm_password;
398         r2.in.lm_verifier = r->in.lm_verifier;
399         r2.in.password3 = NULL;
400         r2.out.dominfo = &dominfo;
401         r2.out.reject = &reject;
402
403         return dcesrv_samr_ChangePasswordUser3(dce_call, mem_ctx, &r2);
404 }
405
406
407 /*
408   set password via a samr_CryptPassword buffer
409 */
410 NTSTATUS samr_set_password(struct dcesrv_call_state *dce_call,
411                            struct ldb_context *sam_ctx,
412                            struct ldb_dn *account_dn, struct ldb_dn *domain_dn,
413                            TALLOC_CTX *mem_ctx,
414                            struct samr_CryptPassword *pwbuf)
415 {
416         NTSTATUS nt_status;
417         DATA_BLOB new_password;
418         DATA_BLOB session_key = data_blob(NULL, 0);
419
420         nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
421         if (!NT_STATUS_IS_OK(nt_status)) {
422                 return nt_status;
423         }
424
425         arcfour_crypt_blob(pwbuf->data, 516, &session_key);
426
427         if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
428                 DEBUG(3,("samr: failed to decode password buffer\n"));
429                 return NT_STATUS_WRONG_PASSWORD;
430         }
431
432         /* set the password - samdb needs to know both the domain and user DNs,
433            so the domain password policy can be used */
434         return samdb_set_password(sam_ctx, mem_ctx,
435                                   account_dn, domain_dn,
436                                   &new_password,
437                                   NULL, NULL,
438                                   NULL, NULL, /* This is a password set, not change */
439                                   NULL, NULL);
440 }
441
442
443 /*
444   set password via a samr_CryptPasswordEx buffer
445 */
446 NTSTATUS samr_set_password_ex(struct dcesrv_call_state *dce_call,
447                               struct ldb_context *sam_ctx,
448                               struct ldb_dn *account_dn,
449                               struct ldb_dn *domain_dn,
450                               TALLOC_CTX *mem_ctx,
451                               struct samr_CryptPasswordEx *pwbuf)
452 {
453         NTSTATUS nt_status;
454         DATA_BLOB new_password;
455         DATA_BLOB co_session_key;
456         DATA_BLOB session_key = data_blob(NULL, 0);
457         MD5_CTX ctx;
458
459         nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
460         if (!NT_STATUS_IS_OK(nt_status)) {
461                 return nt_status;
462         }
463
464         co_session_key = data_blob_talloc(mem_ctx, NULL, 16);
465         if (!co_session_key.data) {
466                 return NT_STATUS_NO_MEMORY;
467         }
468
469         MD5Init(&ctx);
470         MD5Update(&ctx, &pwbuf->data[516], 16);
471         MD5Update(&ctx, session_key.data, session_key.length);
472         MD5Final(co_session_key.data, &ctx);
473
474         arcfour_crypt_blob(pwbuf->data, 516, &co_session_key);
475
476         if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
477                 DEBUG(3,("samr: failed to decode password buffer\n"));
478                 return NT_STATUS_WRONG_PASSWORD;
479         }
480
481         /* set the password - samdb needs to know both the domain and user DNs,
482            so the domain password policy can be used */
483         return samdb_set_password(sam_ctx, mem_ctx,
484                                   account_dn, domain_dn,
485                                   &new_password,
486                                   NULL, NULL,
487                                   NULL, NULL, /* This is a password set, not change */
488                                   NULL, NULL);
489 }
490
491 /*
492   set password via encrypted NT and LM hash buffers
493 */
494 NTSTATUS samr_set_password_buffers(struct dcesrv_call_state *dce_call,
495                                    struct ldb_context *sam_ctx,
496                                    struct ldb_dn *account_dn,
497                                    struct ldb_dn *domain_dn,
498                                    TALLOC_CTX *mem_ctx,
499                                    const uint8_t *lm_pwd_hash,
500                                    const uint8_t *nt_pwd_hash)
501 {
502         struct samr_Password *d_lm_pwd_hash = NULL, *d_nt_pwd_hash = NULL;
503         DATA_BLOB session_key = data_blob(NULL, 0);
504         DATA_BLOB in, out;
505         NTSTATUS nt_status = NT_STATUS_OK;
506
507         nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
508         if (!NT_STATUS_IS_OK(nt_status)) {
509                 return nt_status;
510         }
511
512         if (lm_pwd_hash != NULL) {
513                 in = data_blob_const(lm_pwd_hash, 16);
514                 out = data_blob_talloc_zero(mem_ctx, 16);
515
516                 sess_crypt_blob(&out, &in, &session_key, false);
517
518                 d_lm_pwd_hash = (struct samr_Password *) out.data;
519         }
520         if (nt_pwd_hash != NULL) {
521                 in = data_blob_const(nt_pwd_hash, 16);
522                 out = data_blob_talloc_zero(mem_ctx, 16);
523
524                 sess_crypt_blob(&out, &in, &session_key, false);
525
526                 d_nt_pwd_hash = (struct samr_Password *) out.data;
527         }
528
529         if ((d_lm_pwd_hash != NULL) || (d_nt_pwd_hash != NULL)) {
530                 nt_status = samdb_set_password(sam_ctx, mem_ctx, account_dn,
531                                                domain_dn, NULL,
532                                                d_lm_pwd_hash, d_nt_pwd_hash,
533                                                NULL, NULL, /* this is a password set */
534                                                NULL, NULL);
535         }
536
537         return nt_status;
538 }