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