5d4504f7bf01608f1dcb26f8d522eeeee08832b7
[samba.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                            ldb_binary_encode_string(mem_ctx, r->in.account->string));
106         if (ret != 1) {
107                 /* Don't give the game away:  (don't allow anonymous users to prove the existence 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                            ldb_binary_encode_string(mem_ctx, r->in.account->string));
253         if (ret != 1) {
254                 /* Don't give the game away:  (don't allow anonymous users to prove the existence 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                 DEBUG(3,("samr: failed to get session key: %s "
423                          "=> NT_STATUS_WRONG_PASSWORD\n",
424                         nt_errstr(nt_status)));
425                 return NT_STATUS_WRONG_PASSWORD;
426         }
427
428         arcfour_crypt_blob(pwbuf->data, 516, &session_key);
429
430         if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
431                 DEBUG(3,("samr: failed to decode password buffer\n"));
432                 return NT_STATUS_WRONG_PASSWORD;
433         }
434
435         /* set the password - samdb needs to know both the domain and user DNs,
436            so the domain password policy can be used */
437         return samdb_set_password(sam_ctx, mem_ctx,
438                                   account_dn, domain_dn,
439                                   &new_password,
440                                   NULL, NULL,
441                                   NULL, NULL, /* This is a password set, not change */
442                                   NULL, NULL);
443 }
444
445
446 /*
447   set password via a samr_CryptPasswordEx buffer
448 */
449 NTSTATUS samr_set_password_ex(struct dcesrv_call_state *dce_call,
450                               struct ldb_context *sam_ctx,
451                               struct ldb_dn *account_dn,
452                               struct ldb_dn *domain_dn,
453                               TALLOC_CTX *mem_ctx,
454                               struct samr_CryptPasswordEx *pwbuf)
455 {
456         NTSTATUS nt_status;
457         DATA_BLOB new_password;
458         DATA_BLOB co_session_key;
459         DATA_BLOB session_key = data_blob(NULL, 0);
460         MD5_CTX ctx;
461
462         nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
463         if (!NT_STATUS_IS_OK(nt_status)) {
464                 DEBUG(3,("samr: failed to get session key: %s "
465                          "=> NT_STATUS_WRONG_PASSWORD\n",
466                         nt_errstr(nt_status)));
467                 return NT_STATUS_WRONG_PASSWORD;
468         }
469
470         co_session_key = data_blob_talloc(mem_ctx, NULL, 16);
471         if (!co_session_key.data) {
472                 return NT_STATUS_NO_MEMORY;
473         }
474
475         MD5Init(&ctx);
476         MD5Update(&ctx, &pwbuf->data[516], 16);
477         MD5Update(&ctx, session_key.data, session_key.length);
478         MD5Final(co_session_key.data, &ctx);
479
480         arcfour_crypt_blob(pwbuf->data, 516, &co_session_key);
481
482         if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
483                 DEBUG(3,("samr: failed to decode password buffer\n"));
484                 return NT_STATUS_WRONG_PASSWORD;
485         }
486
487         /* set the password - samdb needs to know both the domain and user DNs,
488            so the domain password policy can be used */
489         return samdb_set_password(sam_ctx, mem_ctx,
490                                   account_dn, domain_dn,
491                                   &new_password,
492                                   NULL, NULL,
493                                   NULL, NULL, /* This is a password set, not change */
494                                   NULL, NULL);
495 }
496
497 /*
498   set password via encrypted NT and LM hash buffers
499 */
500 NTSTATUS samr_set_password_buffers(struct dcesrv_call_state *dce_call,
501                                    struct ldb_context *sam_ctx,
502                                    struct ldb_dn *account_dn,
503                                    struct ldb_dn *domain_dn,
504                                    TALLOC_CTX *mem_ctx,
505                                    const uint8_t *lm_pwd_hash,
506                                    const uint8_t *nt_pwd_hash)
507 {
508         struct samr_Password *d_lm_pwd_hash = NULL, *d_nt_pwd_hash = NULL;
509         uint8_t random_session_key[16] = { 0, };
510         DATA_BLOB session_key = data_blob(NULL, 0);
511         DATA_BLOB in, out;
512         NTSTATUS nt_status = NT_STATUS_OK;
513
514         nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
515         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_USER_SESSION_KEY)) {
516                 DEBUG(3,("samr: failed to get session key: %s "
517                          "=> use a random session key\n",
518                          nt_errstr(nt_status)));
519
520                 /*
521                  * Windows just uses a random key
522                  */
523                 generate_random_buffer(random_session_key,
524                                        sizeof(random_session_key));
525                 session_key = data_blob_const(random_session_key,
526                                               sizeof(random_session_key));
527                 nt_status = NT_STATUS_OK;
528         }
529         if (!NT_STATUS_IS_OK(nt_status)) {
530                 return nt_status;
531         }
532
533         if (lm_pwd_hash != NULL) {
534                 in = data_blob_const(lm_pwd_hash, 16);
535                 out = data_blob_talloc_zero(mem_ctx, 16);
536
537                 sess_crypt_blob(&out, &in, &session_key, false);
538
539                 d_lm_pwd_hash = (struct samr_Password *) out.data;
540         }
541         if (nt_pwd_hash != NULL) {
542                 in = data_blob_const(nt_pwd_hash, 16);
543                 out = data_blob_talloc_zero(mem_ctx, 16);
544
545                 sess_crypt_blob(&out, &in, &session_key, false);
546
547                 d_nt_pwd_hash = (struct samr_Password *) out.data;
548         }
549
550         if ((d_lm_pwd_hash != NULL) || (d_nt_pwd_hash != NULL)) {
551                 nt_status = samdb_set_password(sam_ctx, mem_ctx, account_dn,
552                                                domain_dn, NULL,
553                                                d_lm_pwd_hash, d_nt_pwd_hash,
554                                                NULL, NULL, /* this is a password set */
555                                                NULL, NULL);
556         }
557
558         return nt_status;
559 }