2 Unix SMB/CIFS implementation.
4 Implement a hook into the Samba4 auth subsystem
6 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2010
7 Copyright (C) Stefan Metzmacher <metze@samba.org> 2005
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.
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.
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/>.
24 #include "auth/auth.h"
25 #include "auth/auth_sam_reply.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"
33 NTSTATUS s3compat_authenticate(TALLOC_CTX *mem_ctx, uint8_t chall[8], const struct auth_usersupplied_info *user_info, struct netr_SamInfo3 **info3)
35 struct auth_context *auth_context;
36 struct auth_serversupplied_info *server_info;
39 nt_status = auth_context_create(mem_ctx,
40 s3compat_get_tevent_ctx(), s3compat_get_msg_ctx(), s3compat_get_lp_ctx(),
42 NT_STATUS_NOT_OK_RETURN(nt_status);
44 nt_status = auth_context_set_challenge(auth_context, chall, "s3compat");
45 NT_STATUS_NOT_OK_RETURN_AND_FREE(nt_status, auth_context);
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);
50 nt_status = auth_convert_server_info_saminfo3(mem_ctx,
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);
57 talloc_free(auth_context);
61 /* NOTE: This interface implementation does not honour:
66 _PUBLIC_ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx,
69 const DATA_BLOB *ticket,
71 struct PAC_LOGON_INFO **logon_info,
73 DATA_BLOB *session_key,
74 bool use_replay_cache)
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();
83 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
84 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
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);
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)));
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(),
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);
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);
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);
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);
129 nt_status = gensec_session_info(gensec_server_context, &session_info);
130 NT_STATUS_NOT_OK_RETURN_AND_FREE(nt_status, tmp_ctx);
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,
137 NT_STATUS_NOT_OK_RETURN_AND_FREE(nt_status, tmp_ctx);
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);
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;
145 talloc_steal(mem_ctx, tmp_ctx);
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 ****************************************************************/
156 _PUBLIC_ NTSTATUS kerberos_return_pac(TALLOC_CTX *mem_ctx,
161 time_t *renew_till_time,
162 const char *cache_name,
164 bool add_netbios_addr,
165 time_t renewable_time,
166 const char *impersonate_princ_s,
167 struct PAC_LOGON_INFO **logon_info)
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;
179 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
180 NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);
182 server_credentials = cli_credentials_init(tmp_ctx);
183 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(server_credentials, tmp_ctx);
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);
193 client_credentials = cli_credentials_init(tmp_ctx);
194 NT_STATUS_HAVE_NO_MEMORY_AND_FREE(client_credentials, tmp_ctx);
196 cli_credentials_set_conf(client_credentials, lp_ctx);
198 ret = cli_credentials_set_ccache(client_credentials, ev_ctx, lp_ctx, cache_name, CRED_SPECIFIED, &error_string);
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;
206 if (impersonate_princ_s) {
207 cli_credentials_set_impersonate_principal(client_credentials, impersonate_princ_s);
209 cli_credentials_set_principal(client_credentials, name, CRED_SPECIFIED);
210 cli_credentials_set_password(client_credentials, pass, CRED_SPECIFIED);
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);
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);
219 status = gensec_set_credentials(gensec_client_context, client_credentials);
220 NT_STATUS_NOT_OK_RETURN_AND_FREE(status, tmp_ctx);
222 status = gensec_start_mech_by_name(gensec_client_context, "krb5");
223 NT_STATUS_NOT_OK_RETURN_AND_FREE(status, tmp_ctx);
225 server_to_client = data_blob(NULL, 0);
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;
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;
240 status = ads_verify_ticket(mem_ctx, lp_realm(lp_ctx),
244 &ap_rep, &session_key, false);
245 talloc_free(tmp_ctx);