5215bffc0a66104977e91cedaebfb507ed9dd442
[abartlet/samba.git/.git] / source4 / s3compat / s3compat_authenticate.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Implement a hook into the Samba4 auth subsystem
5
6    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2010
7    Copyright (C) Stefan Metzmacher <metze@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 "auth/auth.h"
25 #include "auth/auth_sam_reply.h"
26 #include "s3compat.h"
27 #include "s3compat_globals.h"
28 #include "s3compat_authenticate.h"
29 #include "auth/credentials/credentials.h"
30 #include "auth/gensec/gensec.h"
31 #include "libcli/security/dom_sid.h"
32
33 NTSTATUS s3compat_authenticate(TALLOC_CTX *mem_ctx, uint8_t chall[8], const struct auth_usersupplied_info *user_info, struct netr_SamInfo3 **info3) 
34 {
35         struct auth_context *auth_context;
36         struct auth_serversupplied_info *server_info;
37         NTSTATUS nt_status;
38
39         nt_status = auth_context_create(mem_ctx,
40                                         s3compat_get_tevent_ctx(), s3compat_get_msg_ctx(), s3compat_get_lp_ctx(),
41                                         &auth_context);
42         NT_STATUS_NOT_OK_RETURN(nt_status);
43                 
44         nt_status = auth_context_set_challenge(auth_context, chall, "s3compat");
45         NT_STATUS_NOT_OK_RETURN_AND_FREE(nt_status, auth_context);
46
47         nt_status = auth_check_password(auth_context, auth_context, user_info, &server_info);
48         NT_STATUS_NOT_OK_RETURN_AND_FREE(nt_status, auth_context);
49         
50         nt_status = auth_convert_server_info_saminfo3(mem_ctx,
51                                                       server_info,
52                                                       info3);
53         if (NT_STATUS_IS_OK(nt_status)) {
54                 /* We need the strings from the server_info to be valid as long as the info3 is around */
55                 talloc_steal(*info3, server_info);
56         }
57         talloc_free(auth_context);
58         return nt_status;
59 }
60
61 /* NOTE:  This interface implementation does not honour:
62  - realm
63  - time_offset
64  - use_replay_cache
65 */
66 _PUBLIC_ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx,
67                                     const char *realm,
68                                     time_t time_offset,
69                                     const DATA_BLOB *ticket,
70                                     char **principal,
71                                     struct PAC_LOGON_INFO **logon_info,
72                                     DATA_BLOB *ap_rep,
73                                     DATA_BLOB *session_key,
74                                     bool use_replay_cache)
75 {
76         struct cli_credentials *server_credentials;
77         struct auth_session_info *session_info;
78         struct gensec_security *gensec_server_context;
79         struct netr_SamInfo3 *info3;
80         struct loadparm_context *lp_ctx = s3compat_get_lp_ctx();
81         NTSTATUS nt_status;
82
83         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
84         NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
85         
86         /* Get the keytab from the credentials subsystem */
87         server_credentials = cli_credentials_init(tmp_ctx);
88         NT_STATUS_HAVE_NO_MEMORY_AND_FREE(server_credentials, tmp_ctx);
89         
90         cli_credentials_set_conf(server_credentials, lp_ctx);
91         nt_status = cli_credentials_set_machine_account(server_credentials, lp_ctx);
92         if (!NT_STATUS_IS_OK(nt_status)) {
93                 DEBUG(1, ("Failed to obtain server credentials, can not validate a Kerberos ticket: %s\n", nt_errstr(nt_status)));
94                 talloc_free(tmp_ctx);
95                 return nt_status;
96         }
97
98         /* Start up GENSEC in the same way a native Samba4 task would */
99         nt_status = samba_server_gensec_start(tmp_ctx,
100                                               s3compat_get_tevent_ctx(),
101                                               s3compat_get_msg_ctx(),
102                                               lp_ctx,
103                                               server_credentials,
104                                               "host",
105                                               &gensec_server_context);
106         if (!NT_STATUS_IS_OK(nt_status)) {
107                 DEBUG(1, (__location__ "Failed to start server-side GENSEC for to validate a Kerberos ticket: %s\n", nt_errstr(nt_status)));
108                 talloc_free(tmp_ctx);
109                 return nt_status;
110         }
111
112         /* This authentication is by 'raw' krb5 because the layers
113          * above us have stripped it of it's SPNEGO and GSSAPI
114          * wrapping already */
115         nt_status = gensec_start_mech_by_name(gensec_server_context, "krb5");
116         NT_STATUS_NOT_OK_RETURN_AND_FREE(nt_status, tmp_ctx);
117
118         /* Do a client-server update dance */
119         nt_status = gensec_update(gensec_server_context, tmp_ctx, *ticket, ap_rep);
120         if (!NT_STATUS_IS_OK(nt_status)) {
121                 DEBUG(1, ("Client requested a Kerberos option that requires more processing.  Not supported in s3compat"));
122                 NT_STATUS_NOT_OK_RETURN_AND_FREE(nt_status, tmp_ctx);
123         }
124
125         /* Now return the session key and PAC information to the callers */
126         nt_status = gensec_session_key(gensec_server_context, session_key);
127         NT_STATUS_NOT_OK_RETURN_AND_FREE(nt_status, tmp_ctx);
128
129         nt_status = gensec_session_info(gensec_server_context, &session_info);
130         NT_STATUS_NOT_OK_RETURN_AND_FREE(nt_status, tmp_ctx);
131         
132         *logon_info = talloc_zero(tmp_ctx, struct PAC_LOGON_INFO);
133         NT_STATUS_HAVE_NO_MEMORY_AND_FREE(*logon_info, tmp_ctx);
134         nt_status = auth_convert_server_info_saminfo3(*logon_info,
135                                                       session_info->server_info,
136                                                       &info3);
137         NT_STATUS_NOT_OK_RETURN_AND_FREE(nt_status, tmp_ctx);
138
139         *principal = talloc_asprintf(mem_ctx, "%s@%s", info3->base.account_name.string, info3->base.domain.string);
140         NT_STATUS_HAVE_NO_MEMORY_AND_FREE(*principal, tmp_ctx);
141
142         /* I know this structure assignment sucks, but at least the talloc tree is reasonable, as logon_info is used as the talloc context */
143         (*logon_info)->info3 = *info3;
144
145         talloc_steal(mem_ctx, tmp_ctx);
146
147         return NT_STATUS_OK;
148 }
149
150 /****************************************************************
151 Given a username, password and other details, return the
152 PAC_LOGON_INFO (the structure containing the important user
153 information such as groups).
154 ****************************************************************/
155
156 _PUBLIC_ NTSTATUS kerberos_return_pac(TALLOC_CTX *mem_ctx,
157                                       const char *name,
158                                       const char *pass,
159                                       time_t time_offset,
160                                       time_t *expire_time,
161                                       time_t *renew_till_time,
162                                       const char *cache_name,
163                                       bool request_pac,
164                                       bool add_netbios_addr,
165                                       time_t renewable_time,
166                                       const char *impersonate_princ_s,
167                                       struct PAC_LOGON_INFO **logon_info)
168 {
169         DATA_BLOB server_to_client, ticket, ap_rep, session_key;
170         struct cli_credentials *server_credentials, *client_credentials;
171         struct gensec_security *gensec_client_context;
172         struct loadparm_context *lp_ctx = s3compat_get_lp_ctx();
173         struct tevent_context *ev_ctx = s3compat_get_tevent_ctx();
174         const char *error_string;
175         char *principal;
176         NTSTATUS status;
177         int ret;
178
179         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
180         NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
181         
182         server_credentials = cli_credentials_init(tmp_ctx);
183         NT_STATUS_HAVE_NO_MEMORY_AND_FREE(server_credentials, tmp_ctx);
184         
185         cli_credentials_set_conf(server_credentials, lp_ctx);
186         status = cli_credentials_set_machine_account(server_credentials, lp_ctx);
187         if (!NT_STATUS_IS_OK(status)) {
188                 DEBUG(1, ("Failed to obtain server credentials, can not validate a Kerberos ticket: %s\n", nt_errstr(status)));
189                 talloc_free(tmp_ctx);
190                 return status;
191         }
192
193         client_credentials = cli_credentials_init(tmp_ctx);
194         NT_STATUS_HAVE_NO_MEMORY_AND_FREE(client_credentials, tmp_ctx);
195         
196         cli_credentials_set_conf(client_credentials, lp_ctx);
197         if (cache_name) {
198                 ret = cli_credentials_set_ccache(client_credentials, ev_ctx, lp_ctx, cache_name, CRED_SPECIFIED, &error_string);
199                 if (ret != 0) {
200                         DEBUG(2, ("Could not set credentialse cache to %s: %s", cache_name, error_string));
201                         talloc_free(tmp_ctx);
202                         return NT_STATUS_INTERNAL_ERROR;
203                 }
204         }
205
206         if (impersonate_princ_s) {
207                 cli_credentials_set_impersonate_principal(client_credentials, impersonate_princ_s);
208         }
209         cli_credentials_set_principal(client_credentials, name, CRED_SPECIFIED);
210         cli_credentials_set_password(client_credentials, pass, CRED_SPECIFIED);
211
212         status = gensec_client_start(tmp_ctx, &gensec_client_context, ev_ctx, 
213                                      lp_gensec_settings(tmp_ctx, lp_ctx));
214         NT_STATUS_NOT_OK_RETURN_AND_FREE(status, tmp_ctx);
215         
216         status = gensec_set_target_principal(gensec_client_context, cli_credentials_get_principal(server_credentials, tmp_ctx));
217         NT_STATUS_NOT_OK_RETURN_AND_FREE(status, tmp_ctx);
218         
219         status = gensec_set_credentials(gensec_client_context, client_credentials);
220         NT_STATUS_NOT_OK_RETURN_AND_FREE(status, tmp_ctx);
221         
222         status = gensec_start_mech_by_name(gensec_client_context, "krb5");
223         NT_STATUS_NOT_OK_RETURN_AND_FREE(status, tmp_ctx);
224         
225         server_to_client = data_blob(NULL, 0);
226         
227         status = gensec_update(gensec_client_context, tmp_ctx, server_to_client, &ticket);
228         if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {;
229                 if (NT_STATUS_IS_OK(status)) {
230                         DEBUG(0, ("gensec_update for krb5 returned NT_STATUS_OK, should return NT_STATUS_MORE_PROCESSING_REQUIRED every time"));
231                         return NT_STATUS_INTERNAL_ERROR;
232                 }
233                 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
234                         DEBUG(0, ("gensec_update for krb5 returned NT_STATUS_INVALID_PARAMETER, perhaps we can't reach the KDC?"));
235                         return NT_STATUS_INTERNAL_ERROR;
236                 }
237                 return status;
238         }
239         
240         status = ads_verify_ticket(mem_ctx, lp_realm(lp_ctx),
241                                    0, &ticket,
242                                    &principal,
243                                    logon_info, 
244                                    &ap_rep, &session_key, false);
245         talloc_free(tmp_ctx);
246         return status;
247 }