Don't use crossRef records to find our own domain
[obnox/samba/samba-obnox.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 "librpc/gen_ndr/ndr_netlogon.h"
24 #include "system/time.h"
25 #include "lib/ldb/include/ldb.h"
26 #include "../lib/util/util_ldb.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 "libcli/security/security.h"
33 #include "libcli/ldap/ldap_ndr.h"
34 #include "param/param.h"
35
36 extern const char *user_attrs[];
37 extern const char *domain_ref_attrs[];
38
39 /****************************************************************************
40  Look for the specified user in the sam, return ldb result structures
41 ****************************************************************************/
42
43 static NTSTATUS authsam_search_account(TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx,
44                                        const char *account_name,
45                                        struct ldb_dn *domain_dn,
46                                        struct ldb_message ***ret_msgs)
47 {
48         struct ldb_message **msgs;
49
50         int ret;
51
52         /* pull the user attributes */
53         ret = gendb_search(sam_ctx, mem_ctx, domain_dn, &msgs, user_attrs,
54                            "(&(sAMAccountName=%s)(objectclass=user))", 
55                            ldb_binary_encode_string(mem_ctx, account_name));
56         if (ret == -1) {
57                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
58         }
59
60         if (ret == 0) {
61                 DEBUG(3,("sam_search_user: Couldn't find user [%s] in samdb, under %s\n", 
62                          account_name, ldb_dn_get_linearized(domain_dn)));
63                 return NT_STATUS_NO_SUCH_USER;
64         }
65
66         if (ret > 1) {
67                 DEBUG(0,("Found %d records matching user [%s]\n", ret, account_name));
68                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
69         }
70
71         *ret_msgs = msgs;
72         
73         return NT_STATUS_OK;
74 }
75
76 /****************************************************************************
77  Do a specific test for an smb password being correct, given a smb_password and
78  the lanman and NT responses.
79 ****************************************************************************/
80 static NTSTATUS authsam_password_ok(struct auth_context *auth_context,
81                                     TALLOC_CTX *mem_ctx,
82                                     uint16_t acct_flags,
83                                     const struct samr_Password *lm_pwd, 
84                                     const struct samr_Password *nt_pwd,
85                                     const struct auth_usersupplied_info *user_info, 
86                                     DATA_BLOB *user_sess_key, 
87                                     DATA_BLOB *lm_sess_key)
88 {
89         NTSTATUS status;
90
91         switch (user_info->password_state) {
92         case AUTH_PASSWORD_PLAIN: 
93         {
94                 const struct auth_usersupplied_info *user_info_temp;    
95                 status = encrypt_user_info(mem_ctx, auth_context, 
96                                            AUTH_PASSWORD_HASH, 
97                                            user_info, &user_info_temp);
98                 if (!NT_STATUS_IS_OK(status)) {
99                         DEBUG(1, ("Failed to convert plaintext password to password HASH: %s\n", nt_errstr(status)));
100                         return status;
101                 }
102                 user_info = user_info_temp;
103
104                 /*fall through*/
105         }
106         case AUTH_PASSWORD_HASH:
107                 *lm_sess_key = data_blob(NULL, 0);
108                 *user_sess_key = data_blob(NULL, 0);
109                 status = hash_password_check(mem_ctx, 
110                                              lp_lanman_auth(auth_context->lp_ctx),
111                                              user_info->password.hash.lanman,
112                                              user_info->password.hash.nt,
113                                              user_info->mapped.account_name,
114                                              lm_pwd, nt_pwd);
115                 NT_STATUS_NOT_OK_RETURN(status);
116                 break;
117                 
118         case AUTH_PASSWORD_RESPONSE:
119                 status = ntlm_password_check(mem_ctx, 
120                                              lp_lanman_auth(auth_context->lp_ctx),
121                                                  lp_ntlm_auth(auth_context->lp_ctx),
122                                              user_info->logon_parameters, 
123                                              &auth_context->challenge.data, 
124                                              &user_info->password.response.lanman, 
125                                              &user_info->password.response.nt,
126                                              user_info->mapped.account_name,
127                                              user_info->client.account_name, 
128                                              user_info->client.domain_name, 
129                                              lm_pwd, nt_pwd,
130                                              user_sess_key, lm_sess_key);
131                 NT_STATUS_NOT_OK_RETURN(status);
132                 break;
133         }
134
135         if (user_sess_key && user_sess_key->data) {
136                 talloc_steal(auth_context, user_sess_key->data);
137         }
138         if (lm_sess_key && lm_sess_key->data) {
139                 talloc_steal(auth_context, lm_sess_key->data);
140         }
141
142         return NT_STATUS_OK;
143 }
144
145
146
147 static NTSTATUS authsam_authenticate(struct auth_context *auth_context, 
148                                      TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx, 
149                                      struct ldb_dn *domain_dn,
150                                      struct ldb_message **msgs,
151                                      const struct auth_usersupplied_info *user_info, 
152                                      DATA_BLOB *user_sess_key, DATA_BLOB *lm_sess_key) 
153 {
154         struct samr_Password *lm_pwd, *nt_pwd;
155         NTSTATUS nt_status;
156
157         uint16_t acct_flags = samdb_result_acct_flags(sam_ctx, mem_ctx, msgs[0], domain_dn);
158         
159         /* Quit if the account was locked out. */
160         if (acct_flags & ACB_AUTOLOCK) {
161                 DEBUG(3,("check_sam_security: Account for user %s was locked out.\n", 
162                          user_info->mapped.account_name));
163                 return NT_STATUS_ACCOUNT_LOCKED_OUT;
164         }
165
166         /* You can only do an interactive login to normal accounts */
167         if (user_info->flags & USER_INFO_INTERACTIVE_LOGON) {
168                 if (!(acct_flags & ACB_NORMAL)) {
169                         return NT_STATUS_NO_SUCH_USER;
170                 }
171         }
172
173         nt_status = samdb_result_passwords(mem_ctx, auth_context->lp_ctx, msgs[0], &lm_pwd, &nt_pwd);
174         NT_STATUS_NOT_OK_RETURN(nt_status);
175
176         nt_status = authsam_password_ok(auth_context, mem_ctx, 
177                                         acct_flags, lm_pwd, nt_pwd,
178                                         user_info, user_sess_key, lm_sess_key);
179         NT_STATUS_NOT_OK_RETURN(nt_status);
180
181         nt_status = authsam_account_ok(mem_ctx, sam_ctx, 
182                                        user_info->logon_parameters,
183                                        domain_dn,
184                                        msgs[0],
185                                        user_info->workstation_name,
186                                        user_info->mapped.account_name,
187                                        false);
188
189         return nt_status;
190 }
191
192
193
194 static NTSTATUS authsam_check_password_internals(struct auth_method_context *ctx,
195                                                  TALLOC_CTX *mem_ctx,
196                                                  const struct auth_usersupplied_info *user_info, 
197                                                  struct auth_serversupplied_info **server_info)
198 {
199         NTSTATUS nt_status;
200         const char *account_name = user_info->mapped.account_name;
201         struct ldb_message **msgs;
202         struct ldb_context *sam_ctx;
203         struct ldb_dn *domain_dn;
204         DATA_BLOB user_sess_key, lm_sess_key;
205         TALLOC_CTX *tmp_ctx;
206
207         if (!account_name || !*account_name) {
208                 /* 'not for me' */
209                 return NT_STATUS_NOT_IMPLEMENTED;
210         }
211
212         tmp_ctx = talloc_new(mem_ctx);
213         if (!tmp_ctx) {
214                 return NT_STATUS_NO_MEMORY;
215         }
216
217         sam_ctx = samdb_connect(tmp_ctx, ctx->auth_ctx->event_ctx, ctx->auth_ctx->lp_ctx, system_session(mem_ctx, ctx->auth_ctx->lp_ctx));
218         if (sam_ctx == NULL) {
219                 talloc_free(tmp_ctx);
220                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
221         }
222
223         domain_dn = ldb_get_default_basedn(sam_ctx);
224         if (domain_dn == NULL) {
225                 talloc_free(tmp_ctx);
226                 return NT_STATUS_NO_SUCH_DOMAIN;
227         }
228
229         nt_status = authsam_search_account(tmp_ctx, sam_ctx, account_name, domain_dn, &msgs);
230         if (!NT_STATUS_IS_OK(nt_status)) {
231                 talloc_free(tmp_ctx);
232                 return nt_status;
233         }
234
235         nt_status = authsam_authenticate(ctx->auth_ctx, tmp_ctx, sam_ctx, domain_dn, msgs, user_info,
236                                          &user_sess_key, &lm_sess_key);
237         if (!NT_STATUS_IS_OK(nt_status)) {
238                 talloc_free(tmp_ctx);
239                 return nt_status;
240         }
241
242         nt_status = authsam_make_server_info(tmp_ctx, sam_ctx, lp_netbios_name(ctx->auth_ctx->lp_ctx), 
243                                              lp_sam_name(ctx->auth_ctx->lp_ctx),
244                                              domain_dn,
245                                              msgs[0],
246                                              user_sess_key, lm_sess_key,
247                                              server_info);
248         if (!NT_STATUS_IS_OK(nt_status)) {
249                 talloc_free(tmp_ctx);
250                 return nt_status;
251         }
252
253         talloc_steal(mem_ctx, *server_info);
254         talloc_free(tmp_ctx);
255
256         return NT_STATUS_OK;
257 }
258
259 static NTSTATUS authsam_ignoredomain_want_check(struct auth_method_context *ctx,
260                                                 TALLOC_CTX *mem_ctx,
261                                                 const struct auth_usersupplied_info *user_info)
262 {
263         if (!user_info->mapped.account_name || !*user_info->mapped.account_name) {
264                 return NT_STATUS_NOT_IMPLEMENTED;
265         }
266
267         return NT_STATUS_OK;
268 }
269
270 /****************************************************************************
271 Check SAM security (above) but with a few extra checks.
272 ****************************************************************************/
273 static NTSTATUS authsam_want_check(struct auth_method_context *ctx,
274                                    TALLOC_CTX *mem_ctx,
275                                    const struct auth_usersupplied_info *user_info)
276 {
277         bool is_local_name, is_my_domain;
278
279         if (!user_info->mapped.account_name || !*user_info->mapped.account_name) {
280                 return NT_STATUS_NOT_IMPLEMENTED;
281         }
282
283         is_local_name = lp_is_myname(ctx->auth_ctx->lp_ctx, 
284                                   user_info->mapped.domain_name);
285         is_my_domain  = lp_is_mydomain(ctx->auth_ctx->lp_ctx, 
286                                        user_info->mapped.domain_name); 
287
288         /* check whether or not we service this domain/workgroup name */
289         switch (lp_server_role(ctx->auth_ctx->lp_ctx)) {
290                 case ROLE_STANDALONE:
291                         return NT_STATUS_OK;
292
293                 case ROLE_DOMAIN_MEMBER:
294                         if (!is_local_name) {
295                                 DEBUG(6,("authsam_check_password: %s is not one of my local names (DOMAIN_MEMBER)\n",
296                                         user_info->mapped.domain_name));
297                                 return NT_STATUS_NOT_IMPLEMENTED;
298                         }
299                         return NT_STATUS_OK;
300
301                 case ROLE_DOMAIN_CONTROLLER:
302                         if (!is_local_name && !is_my_domain) {
303                                 DEBUG(6,("authsam_check_password: %s is not one of my local names or domain name (DC)\n",
304                                         user_info->mapped.domain_name));
305                                 return NT_STATUS_NOT_IMPLEMENTED;
306                         }
307                         return NT_STATUS_OK;
308         }
309
310         DEBUG(6,("authsam_check_password: lp_server_role() has an undefined value\n"));
311         return NT_STATUS_NOT_IMPLEMENTED;
312 }
313
314                                    
315 /* Used in the gensec_gssapi and gensec_krb5 server-side code, where the PAC isn't available */
316 NTSTATUS authsam_get_server_info_principal(TALLOC_CTX *mem_ctx, 
317                                            struct auth_context *auth_context,
318                                            const char *principal,
319                                            struct auth_serversupplied_info **server_info)
320 {
321         NTSTATUS nt_status;
322         DATA_BLOB user_sess_key = data_blob(NULL, 0);
323         DATA_BLOB lm_sess_key = data_blob(NULL, 0);
324
325         struct ldb_message **msgs;
326         struct ldb_context *sam_ctx;
327         struct ldb_dn *domain_dn;
328         
329         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
330         if (!tmp_ctx) {
331                 return NT_STATUS_NO_MEMORY;
332         }
333
334         sam_ctx = samdb_connect(tmp_ctx, auth_context->event_ctx, auth_context->lp_ctx, 
335                                 system_session(tmp_ctx, auth_context->lp_ctx));
336         if (sam_ctx == NULL) {
337                 talloc_free(tmp_ctx);
338                 return NT_STATUS_INVALID_SYSTEM_SERVICE;
339         }
340
341         nt_status = sam_get_results_principal(sam_ctx, tmp_ctx, principal, 
342                                               &domain_dn, &msgs);
343         if (!NT_STATUS_IS_OK(nt_status)) {
344                 return nt_status;
345         }
346
347         nt_status = authsam_make_server_info(tmp_ctx, sam_ctx, 
348                                              lp_netbios_name(auth_context->lp_ctx),
349                                              lp_workgroup(auth_context->lp_ctx),
350                                              domain_dn, 
351                                              msgs[0],
352                                              user_sess_key, lm_sess_key,
353                                              server_info);
354         if (NT_STATUS_IS_OK(nt_status)) {
355                 talloc_steal(mem_ctx, *server_info);
356         }
357         talloc_free(tmp_ctx);
358         return nt_status;
359 }
360
361 static const struct auth_operations sam_ignoredomain_ops = {
362         .name                      = "sam_ignoredomain",
363         .get_challenge             = auth_get_challenge_not_implemented,
364         .want_check                = authsam_ignoredomain_want_check,
365         .check_password            = authsam_check_password_internals,
366         .get_server_info_principal = authsam_get_server_info_principal
367 };
368
369 static const struct auth_operations sam_ops = {
370         .name                      = "sam",
371         .get_challenge             = auth_get_challenge_not_implemented,
372         .want_check                = authsam_want_check,
373         .check_password            = authsam_check_password_internals,
374         .get_server_info_principal = authsam_get_server_info_principal
375 };
376
377 _PUBLIC_ NTSTATUS auth_sam_init(void)
378 {
379         NTSTATUS ret;
380
381         ret = auth_register(&sam_ops);
382         if (!NT_STATUS_IS_OK(ret)) {
383                 DEBUG(0,("Failed to register 'sam' auth backend!\n"));
384                 return ret;
385         }
386
387         ret = auth_register(&sam_ignoredomain_ops);
388         if (!NT_STATUS_IS_OK(ret)) {
389                 DEBUG(0,("Failed to register 'sam_ignoredomain' auth backend!\n"));
390                 return ret;
391         }
392
393         return ret;
394 }