f76057a6df1d793a549b6f32477c124c972aa507
[samba.git] / source4 / auth / ntlm / auth_sam.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Password and authentication handling
4    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2001-2009
5    Copyright (C) Gerald Carter                             2003
6    Copyright (C) Stefan Metzmacher                         2005
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "system/time.h"
24 #include <ldb.h>
25 #include "libcli/ldap/ldap_ndr.h"
26 #include "libcli/security/security.h"
27 #include "auth/auth.h"
28 #include "../libcli/auth/ntlm_check.h"
29 #include "auth/ntlm/auth_proto.h"
30 #include "auth/auth_sam.h"
31 #include "dsdb/samdb/samdb.h"
32 #include "dsdb/common/util.h"
33 #include "param/param.h"
34 #include "librpc/gen_ndr/ndr_irpc_c.h"
35 #include "lib/messaging/irpc.h"
36
37 NTSTATUS auth_sam_init(void);
38
39 extern const char *user_attrs[];
40 extern const char *domain_ref_attrs[];
41
42 /****************************************************************************
43  Look for the specified user in the sam, return ldb result structures
44 ****************************************************************************/
45
46 static NTSTATUS authsam_search_account(TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx,
47                                        const char *account_name,
48                                        struct ldb_dn *domain_dn,
49                                        struct ldb_message **ret_msg)
50 {
51         int ret;
52
53         /* pull the user attributes */
54         ret = dsdb_search_one(sam_ctx, mem_ctx, ret_msg, domain_dn, LDB_SCOPE_SUBTREE,
55                               user_attrs,
56                               DSDB_SEARCH_SHOW_EXTENDED_DN,
57                               "(&(sAMAccountName=%s)(objectclass=user))",
58                               ldb_binary_encode_string(mem_ctx, account_name));
59         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
60                 DEBUG(3,("sam_search_user: Couldn't find user [%s] in samdb, under %s\n", 
61                          account_name, ldb_dn_get_linearized(domain_dn)));
62                 return NT_STATUS_NO_SUCH_USER;          
63         }
64         if (ret != LDB_SUCCESS) {
65                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
66         }
67         
68         return NT_STATUS_OK;
69 }
70
71 /****************************************************************************
72  Do a specific test for an smb password being correct, given a smb_password and
73  the lanman and NT responses.
74 ****************************************************************************/
75 static NTSTATUS authsam_password_ok(struct auth_context *auth_context,
76                                     TALLOC_CTX *mem_ctx,
77                                     uint16_t acct_flags,
78                                     const struct samr_Password *lm_pwd, 
79                                     const struct samr_Password *nt_pwd,
80                                     const struct auth_usersupplied_info *user_info, 
81                                     DATA_BLOB *user_sess_key, 
82                                     DATA_BLOB *lm_sess_key)
83 {
84         NTSTATUS status;
85
86         switch (user_info->password_state) {
87         case AUTH_PASSWORD_PLAIN: 
88         {
89                 const struct auth_usersupplied_info *user_info_temp;    
90                 status = encrypt_user_info(mem_ctx, auth_context, 
91                                            AUTH_PASSWORD_HASH, 
92                                            user_info, &user_info_temp);
93                 if (!NT_STATUS_IS_OK(status)) {
94                         DEBUG(1, ("Failed to convert plaintext password to password HASH: %s\n", nt_errstr(status)));
95                         return status;
96                 }
97                 user_info = user_info_temp;
98
99                 /*fall through*/
100         }
101         case AUTH_PASSWORD_HASH:
102                 *lm_sess_key = data_blob(NULL, 0);
103                 *user_sess_key = data_blob(NULL, 0);
104                 status = hash_password_check(mem_ctx, 
105                                              lpcfg_lanman_auth(auth_context->lp_ctx),
106                                              user_info->password.hash.lanman,
107                                              user_info->password.hash.nt,
108                                              user_info->mapped.account_name,
109                                              lm_pwd, nt_pwd);
110                 NT_STATUS_NOT_OK_RETURN(status);
111                 break;
112                 
113         case AUTH_PASSWORD_RESPONSE:
114                 status = ntlm_password_check(mem_ctx, 
115                                              lpcfg_lanman_auth(auth_context->lp_ctx),
116                                                  lpcfg_ntlm_auth(auth_context->lp_ctx),
117                                              user_info->logon_parameters, 
118                                              &auth_context->challenge.data, 
119                                              &user_info->password.response.lanman, 
120                                              &user_info->password.response.nt,
121                                              user_info->mapped.account_name,
122                                              user_info->client.account_name, 
123                                              user_info->client.domain_name, 
124                                              lm_pwd, nt_pwd,
125                                              user_sess_key, lm_sess_key);
126                 NT_STATUS_NOT_OK_RETURN(status);
127                 break;
128         }
129
130         if (user_sess_key && user_sess_key->data) {
131                 talloc_steal(auth_context, user_sess_key->data);
132         }
133         if (lm_sess_key && lm_sess_key->data) {
134                 talloc_steal(auth_context, lm_sess_key->data);
135         }
136
137         return NT_STATUS_OK;
138 }
139
140
141 /*
142   send a message to the drepl server telling it to initiate a
143   REPL_SECRET getncchanges extended op to fetch the users secrets
144  */
145 static void auth_sam_trigger_repl_secret(TALLOC_CTX *mem_ctx, struct auth_context *auth_context,
146                                          struct ldb_dn *user_dn)
147 {
148         struct dcerpc_binding_handle *irpc_handle;
149         struct drepl_trigger_repl_secret r;
150         struct tevent_req *req;
151
152         irpc_handle = irpc_binding_handle_by_name(mem_ctx, auth_context->msg_ctx,
153                                                   "dreplsrv",
154                                                   &ndr_table_irpc);
155         if (irpc_handle == NULL) {
156                 DEBUG(1,(__location__ ": Unable to get binding handle for dreplsrv\n"));
157                 return;
158         }
159
160         r.in.user_dn = ldb_dn_get_linearized(user_dn);
161
162         req = dcerpc_drepl_trigger_repl_secret_r_send(mem_ctx,
163                                                       auth_context->event_ctx,
164                                                       irpc_handle,
165                                                       &r);
166
167         /* we aren't interested in a reply */
168         talloc_free(req);
169         talloc_free(irpc_handle);
170 }
171
172
173 static NTSTATUS authsam_authenticate(struct auth_context *auth_context, 
174                                      TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx, 
175                                      struct ldb_dn *domain_dn,
176                                      struct ldb_message *msg,
177                                      const struct auth_usersupplied_info *user_info, 
178                                      DATA_BLOB *user_sess_key, DATA_BLOB *lm_sess_key) 
179 {
180         struct samr_Password *lm_pwd, *nt_pwd;
181         NTSTATUS nt_status;
182
183         uint16_t acct_flags = samdb_result_acct_flags(auth_context->sam_ctx, mem_ctx, msg, domain_dn);
184         
185         /* Quit if the account was locked out. */
186         if (acct_flags & ACB_AUTOLOCK) {
187                 DEBUG(3,("check_sam_security: Account for user %s was locked out.\n", 
188                          user_info->mapped.account_name));
189                 return NT_STATUS_ACCOUNT_LOCKED_OUT;
190         }
191
192         /* You can only do an interactive login to normal accounts */
193         if (user_info->flags & USER_INFO_INTERACTIVE_LOGON) {
194                 if (!(acct_flags & ACB_NORMAL)) {
195                         return NT_STATUS_NO_SUCH_USER;
196                 }
197         }
198
199         nt_status = samdb_result_passwords(mem_ctx, auth_context->lp_ctx, msg, &lm_pwd, &nt_pwd);
200         NT_STATUS_NOT_OK_RETURN(nt_status);
201
202         if (lm_pwd == NULL && nt_pwd == NULL) {
203                 bool am_rodc;
204                 if (samdb_rodc(auth_context->sam_ctx, &am_rodc) == LDB_SUCCESS && am_rodc) {
205                         /* we don't have passwords for this
206                          * account. We are an RODC, and this account
207                          * may be one for which we either are denied
208                          * REPL_SECRET replication or we haven't yet
209                          * done the replication. We return
210                          * NT_STATUS_NOT_IMPLEMENTED which tells the
211                          * auth code to try the next authentication
212                          * mechanism. We also send a message to our
213                          * drepl server to tell it to try and
214                          * replicate the secrets for this account.
215                          */
216                         auth_sam_trigger_repl_secret(mem_ctx, auth_context, msg->dn);
217                         return NT_STATUS_NOT_IMPLEMENTED;
218                 }
219         }
220
221         nt_status = authsam_password_ok(auth_context, mem_ctx, 
222                                         acct_flags, lm_pwd, nt_pwd,
223                                         user_info, user_sess_key, lm_sess_key);
224         NT_STATUS_NOT_OK_RETURN(nt_status);
225
226         nt_status = authsam_account_ok(mem_ctx, auth_context->sam_ctx,
227                                        user_info->logon_parameters,
228                                        domain_dn,
229                                        msg,
230                                        user_info->workstation_name,
231                                        user_info->mapped.account_name,
232                                        false, false);
233
234         return nt_status;
235 }
236
237
238
239 static NTSTATUS authsam_check_password_internals(struct auth_method_context *ctx,
240                                                  TALLOC_CTX *mem_ctx,
241                                                  const struct auth_usersupplied_info *user_info, 
242                                                  struct auth_user_info_dc **user_info_dc)
243 {
244         NTSTATUS nt_status;
245         const char *account_name = user_info->mapped.account_name;
246         struct ldb_message *msg;
247         struct ldb_dn *domain_dn;
248         DATA_BLOB user_sess_key, lm_sess_key;
249         TALLOC_CTX *tmp_ctx;
250
251         if (ctx->auth_ctx->sam_ctx == NULL) {
252                 DEBUG(0, ("No SAM available, cannot log in users\n"));
253                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
254         }
255
256         if (!account_name || !*account_name) {
257                 /* 'not for me' */
258                 return NT_STATUS_NOT_IMPLEMENTED;
259         }
260
261         tmp_ctx = talloc_new(mem_ctx);
262         if (!tmp_ctx) {
263                 return NT_STATUS_NO_MEMORY;
264         }
265
266         domain_dn = ldb_get_default_basedn(ctx->auth_ctx->sam_ctx);
267         if (domain_dn == NULL) {
268                 talloc_free(tmp_ctx);
269                 return NT_STATUS_NO_SUCH_DOMAIN;
270         }
271
272         nt_status = authsam_search_account(tmp_ctx, ctx->auth_ctx->sam_ctx, account_name, domain_dn, &msg);
273         if (!NT_STATUS_IS_OK(nt_status)) {
274                 talloc_free(tmp_ctx);
275                 return nt_status;
276         }
277
278         nt_status = authsam_authenticate(ctx->auth_ctx, tmp_ctx, ctx->auth_ctx->sam_ctx, domain_dn, msg, user_info,
279                                          &user_sess_key, &lm_sess_key);
280         if (!NT_STATUS_IS_OK(nt_status)) {
281                 talloc_free(tmp_ctx);
282                 return nt_status;
283         }
284
285         nt_status = authsam_make_user_info_dc(tmp_ctx, ctx->auth_ctx->sam_ctx, lpcfg_netbios_name(ctx->auth_ctx->lp_ctx),
286                                              lpcfg_sam_name(ctx->auth_ctx->lp_ctx),
287                                              domain_dn,
288                                              msg,
289                                              user_sess_key, lm_sess_key,
290                                              user_info_dc);
291         if (!NT_STATUS_IS_OK(nt_status)) {
292                 talloc_free(tmp_ctx);
293                 return nt_status;
294         }
295
296         talloc_steal(mem_ctx, *user_info_dc);
297         talloc_free(tmp_ctx);
298
299         return NT_STATUS_OK;
300 }
301
302 static NTSTATUS authsam_ignoredomain_want_check(struct auth_method_context *ctx,
303                                                 TALLOC_CTX *mem_ctx,
304                                                 const struct auth_usersupplied_info *user_info)
305 {
306         if (!user_info->mapped.account_name || !*user_info->mapped.account_name) {
307                 return NT_STATUS_NOT_IMPLEMENTED;
308         }
309
310         return NT_STATUS_OK;
311 }
312
313 /****************************************************************************
314 Check SAM security (above) but with a few extra checks.
315 ****************************************************************************/
316 static NTSTATUS authsam_want_check(struct auth_method_context *ctx,
317                                    TALLOC_CTX *mem_ctx,
318                                    const struct auth_usersupplied_info *user_info)
319 {
320         bool is_local_name, is_my_domain;
321
322         if (!user_info->mapped.account_name || !*user_info->mapped.account_name) {
323                 return NT_STATUS_NOT_IMPLEMENTED;
324         }
325
326         is_local_name = lpcfg_is_myname(ctx->auth_ctx->lp_ctx,
327                                   user_info->mapped.domain_name);
328         is_my_domain  = lpcfg_is_mydomain(ctx->auth_ctx->lp_ctx,
329                                        user_info->mapped.domain_name); 
330
331         /* check whether or not we service this domain/workgroup name */
332         switch (lpcfg_server_role(ctx->auth_ctx->lp_ctx)) {
333                 case ROLE_STANDALONE:
334                         return NT_STATUS_OK;
335
336                 case ROLE_DOMAIN_MEMBER:
337                         if (!is_local_name) {
338                                 DEBUG(6,("authsam_check_password: %s is not one of my local names (DOMAIN_MEMBER)\n",
339                                         user_info->mapped.domain_name));
340                                 return NT_STATUS_NOT_IMPLEMENTED;
341                         }
342                         return NT_STATUS_OK;
343
344                 case ROLE_DOMAIN_CONTROLLER:
345                         if (!is_local_name && !is_my_domain) {
346                                 DEBUG(6,("authsam_check_password: %s is not one of my local names or domain name (DC)\n",
347                                         user_info->mapped.domain_name));
348                                 return NT_STATUS_NOT_IMPLEMENTED;
349                         }
350                         return NT_STATUS_OK;
351         }
352
353         DEBUG(6,("authsam_check_password: lpcfg_server_role() has an undefined value\n"));
354         return NT_STATUS_NOT_IMPLEMENTED;
355 }
356
357                                    
358 /* Wrapper for the auth subsystem pointer */
359 static NTSTATUS authsam_get_user_info_dc_principal_wrapper(TALLOC_CTX *mem_ctx,
360                                                           struct auth_context *auth_context,
361                                                           const char *principal,
362                                                           struct ldb_dn *user_dn,
363                                                           struct auth_user_info_dc **user_info_dc)
364 {
365         return authsam_get_user_info_dc_principal(mem_ctx, auth_context->lp_ctx, auth_context->sam_ctx,
366                                                  principal, user_dn, user_info_dc);
367 }
368 static const struct auth_operations sam_ignoredomain_ops = {
369         .name                      = "sam_ignoredomain",
370         .get_challenge             = auth_get_challenge_not_implemented,
371         .want_check                = authsam_ignoredomain_want_check,
372         .check_password            = authsam_check_password_internals,
373         .get_user_info_dc_principal = authsam_get_user_info_dc_principal_wrapper
374 };
375
376 static const struct auth_operations sam_ops = {
377         .name                      = "sam",
378         .get_challenge             = auth_get_challenge_not_implemented,
379         .want_check                = authsam_want_check,
380         .check_password            = authsam_check_password_internals,
381         .get_user_info_dc_principal = authsam_get_user_info_dc_principal_wrapper
382 };
383
384 _PUBLIC_ NTSTATUS auth_sam_init(void)
385 {
386         NTSTATUS ret;
387
388         ret = auth_register(&sam_ops);
389         if (!NT_STATUS_IS_OK(ret)) {
390                 DEBUG(0,("Failed to register 'sam' auth backend!\n"));
391                 return ret;
392         }
393
394         ret = auth_register(&sam_ignoredomain_ops);
395         if (!NT_STATUS_IS_OK(ret)) {
396                 DEBUG(0,("Failed to register 'sam_ignoredomain' auth backend!\n"));
397                 return ret;
398         }
399
400         return ret;
401 }