ctdb-scripts: Support storing statd-callout state in cluster filesystem
[samba4-gss.git] / auth / gensec / gensec_util.c
blob0c7688d33d2d891df1329e9d6dff449733471fd5
1 /*
2 Unix SMB/CIFS implementation.
4 Generic Authentication Interface
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2006
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/>.
23 #include "includes.h"
24 #include "auth/gensec/gensec.h"
25 #include "auth/gensec/gensec_internal.h"
26 #include "auth/credentials/credentials.h"
27 #include "auth/common_auth.h"
28 #include "../lib/util/asn1.h"
29 #include "param/param.h"
30 #include "libds/common/roles.h"
31 #include "lib/util/util_net.h"
33 #undef strcasecmp
35 #undef DBGC_CLASS
36 #define DBGC_CLASS DBGC_AUTH
38 NTSTATUS gensec_generate_session_info_pac(TALLOC_CTX *mem_ctx,
39 struct gensec_security *gensec_security,
40 struct smb_krb5_context *smb_krb5_context,
41 DATA_BLOB *pac_blob,
42 const char *principal_string,
43 const struct tsocket_address *remote_address,
44 struct auth_session_info **session_info)
46 uint32_t session_info_flags = 0;
47 struct auth4_context *auth_context = NULL;
48 NTSTATUS status;
50 if (gensec_security->want_features & GENSEC_FEATURE_UNIX_TOKEN) {
51 session_info_flags |= AUTH_SESSION_INFO_UNIX_TOKEN;
54 session_info_flags |= AUTH_SESSION_INFO_DEFAULT_GROUPS;
56 if (!pac_blob) {
57 enum server_role server_role =
58 lpcfg_server_role(gensec_security->settings->lp_ctx);
61 * For any domain setup (DC or member) we require having
62 * a PAC, as the service ticket comes from an AD DC,
63 * which will always provide a PAC, unless
64 * UF_NO_AUTH_DATA_REQUIRED is configured for our
65 * account, but that's just an invalid configuration,
66 * the admin configured for us!
68 * As a legacy case, we still allow kerberos tickets from an MIT
69 * realm, but only in standalone mode. In that mode we'll only
70 * ever accept a kerberos authentication with a keytab file
71 * being explicitly configured via the 'keytab method' option.
73 if (server_role != ROLE_STANDALONE) {
74 DBG_WARNING("Unable to find PAC in ticket from %s, "
75 "failing to allow access\n",
76 principal_string);
77 return NT_STATUS_NO_IMPERSONATION_TOKEN;
79 DBG_NOTICE("Unable to find PAC for %s, resorting to local "
80 "user lookup\n", principal_string);
83 auth_context = gensec_security->auth_context;
85 if ((auth_context == NULL) ||
86 (auth_context->generate_session_info_pac == NULL)) {
87 DBG_ERR("Cannot generate a session_info without "
88 "the auth_context\n");
89 return NT_STATUS_INTERNAL_ERROR;
92 status = auth_context->generate_session_info_pac(
93 auth_context,
94 mem_ctx,
95 smb_krb5_context,
96 pac_blob,
97 principal_string,
98 remote_address,
99 session_info_flags,
100 session_info);
101 return status;
105 magic check a GSS-API wrapper packet for an Kerberos OID
107 static bool gensec_gssapi_check_oid(const DATA_BLOB *blob, const char *oid)
109 bool ret = false;
110 struct asn1_data *data = asn1_init(NULL, ASN1_MAX_TREE_DEPTH);
112 if (!data) return false;
114 if (!asn1_load(data, *blob)) goto err;
115 if (!asn1_start_tag(data, ASN1_APPLICATION(0))) goto err;
116 if (!asn1_check_OID(data, oid)) goto err;
118 ret = !asn1_has_error(data);
120 err:
122 asn1_free(data);
123 return ret;
127 * Check if the packet is one for the KRB5 mechanism
129 * NOTE: This is a helper that can be employed by multiple mechanisms, do
130 * not make assumptions about the private_data
132 * @param gensec_security GENSEC state, unused
133 * @param in The request, as a DATA_BLOB
134 * @return Error, INVALID_PARAMETER if it's not a packet for us
135 * or NT_STATUS_OK if the packet is ok.
138 NTSTATUS gensec_magic_check_krb5_oid(struct gensec_security *unused,
139 const DATA_BLOB *blob)
141 if (gensec_gssapi_check_oid(blob, GENSEC_OID_KERBEROS5)) {
142 return NT_STATUS_OK;
143 } else {
144 return NT_STATUS_INVALID_PARAMETER;
148 void gensec_child_want_feature(struct gensec_security *gensec_security,
149 uint32_t feature)
151 struct gensec_security *child_security = gensec_security->child_security;
153 gensec_security->want_features |= feature;
154 if (child_security == NULL) {
155 return;
157 gensec_want_feature(child_security, feature);
160 bool gensec_child_have_feature(struct gensec_security *gensec_security,
161 uint32_t feature)
163 struct gensec_security *child_security = gensec_security->child_security;
165 if (feature & GENSEC_FEATURE_SIGN_PKT_HEADER) {
167 * All mechs with sub (child) mechs need to provide DCERPC
168 * header signing! This is required because the negotiation
169 * of header signing is done before the authentication
170 * is completed.
172 return true;
175 if (child_security == NULL) {
176 return false;
179 return gensec_have_feature(child_security, feature);
182 NTSTATUS gensec_child_unseal_packet(struct gensec_security *gensec_security,
183 uint8_t *data, size_t length,
184 const uint8_t *whole_pdu, size_t pdu_length,
185 const DATA_BLOB *sig)
187 if (gensec_security->child_security == NULL) {
188 return NT_STATUS_INVALID_PARAMETER;
191 return gensec_unseal_packet(gensec_security->child_security,
192 data, length,
193 whole_pdu, pdu_length,
194 sig);
197 NTSTATUS gensec_child_check_packet(struct gensec_security *gensec_security,
198 const uint8_t *data, size_t length,
199 const uint8_t *whole_pdu, size_t pdu_length,
200 const DATA_BLOB *sig)
202 if (gensec_security->child_security == NULL) {
203 return NT_STATUS_INVALID_PARAMETER;
206 return gensec_check_packet(gensec_security->child_security,
207 data, length,
208 whole_pdu, pdu_length,
209 sig);
212 NTSTATUS gensec_child_seal_packet(struct gensec_security *gensec_security,
213 TALLOC_CTX *mem_ctx,
214 uint8_t *data, size_t length,
215 const uint8_t *whole_pdu, size_t pdu_length,
216 DATA_BLOB *sig)
218 if (gensec_security->child_security == NULL) {
219 return NT_STATUS_INVALID_PARAMETER;
222 return gensec_seal_packet(gensec_security->child_security,
223 mem_ctx,
224 data, length,
225 whole_pdu, pdu_length,
226 sig);
229 NTSTATUS gensec_child_sign_packet(struct gensec_security *gensec_security,
230 TALLOC_CTX *mem_ctx,
231 const uint8_t *data, size_t length,
232 const uint8_t *whole_pdu, size_t pdu_length,
233 DATA_BLOB *sig)
235 if (gensec_security->child_security == NULL) {
236 return NT_STATUS_INVALID_PARAMETER;
239 return gensec_sign_packet(gensec_security->child_security,
240 mem_ctx,
241 data, length,
242 whole_pdu, pdu_length,
243 sig);
246 NTSTATUS gensec_child_wrap(struct gensec_security *gensec_security,
247 TALLOC_CTX *mem_ctx,
248 const DATA_BLOB *in,
249 DATA_BLOB *out)
251 if (gensec_security->child_security == NULL) {
252 return NT_STATUS_INVALID_PARAMETER;
255 return gensec_wrap(gensec_security->child_security,
256 mem_ctx, in, out);
259 NTSTATUS gensec_child_unwrap(struct gensec_security *gensec_security,
260 TALLOC_CTX *mem_ctx,
261 const DATA_BLOB *in,
262 DATA_BLOB *out)
264 if (gensec_security->child_security == NULL) {
265 return NT_STATUS_INVALID_PARAMETER;
268 return gensec_unwrap(gensec_security->child_security,
269 mem_ctx, in, out);
272 size_t gensec_child_sig_size(struct gensec_security *gensec_security,
273 size_t data_size)
275 if (gensec_security->child_security == NULL) {
276 return 0;
279 return gensec_sig_size(gensec_security->child_security, data_size);
282 size_t gensec_child_max_input_size(struct gensec_security *gensec_security)
284 if (gensec_security->child_security == NULL) {
285 return 0;
288 return gensec_max_input_size(gensec_security->child_security);
291 size_t gensec_child_max_wrapped_size(struct gensec_security *gensec_security)
293 if (gensec_security->child_security == NULL) {
294 return 0;
297 return gensec_max_wrapped_size(gensec_security->child_security);
300 NTSTATUS gensec_child_session_key(struct gensec_security *gensec_security,
301 TALLOC_CTX *mem_ctx,
302 DATA_BLOB *session_key)
304 if (gensec_security->child_security == NULL) {
305 return NT_STATUS_INVALID_PARAMETER;
308 return gensec_session_key(gensec_security->child_security,
309 mem_ctx,
310 session_key);
313 NTSTATUS gensec_child_session_info(struct gensec_security *gensec_security,
314 TALLOC_CTX *mem_ctx,
315 struct auth_session_info **session_info)
317 if (gensec_security->child_security == NULL) {
318 return NT_STATUS_INVALID_PARAMETER;
321 return gensec_session_info(gensec_security->child_security,
322 mem_ctx,
323 session_info);
326 NTTIME gensec_child_expire_time(struct gensec_security *gensec_security)
328 if (gensec_security->child_security == NULL) {
329 return GENSEC_EXPIRE_TIME_INFINITY;
332 return gensec_expire_time(gensec_security->child_security);
335 const char *gensec_child_final_auth_type(struct gensec_security *gensec_security)
337 if (gensec_security->child_security == NULL) {
338 return "NONE";
341 return gensec_final_auth_type(gensec_security->child_security);
344 char *gensec_get_unparsed_target_principal(struct gensec_security *gensec_security,
345 TALLOC_CTX *mem_ctx)
347 const char *target_principal = gensec_get_target_principal(gensec_security);
348 const char *service = gensec_get_target_service(gensec_security);
349 const char *hostname = gensec_get_target_hostname(gensec_security);
351 if (target_principal != NULL) {
352 return talloc_strdup(mem_ctx, target_principal);
353 } else if (service != NULL && hostname != NULL) {
354 return talloc_asprintf(mem_ctx, "%s/%s", service, hostname);
355 } else if (hostname != NULL) {
356 return talloc_strdup(mem_ctx, target_principal);
359 return NULL;
362 NTSTATUS gensec_kerberos_possible(struct gensec_security *gensec_security)
364 struct cli_credentials *creds = gensec_get_credentials(gensec_security);
365 bool auth_requested = cli_credentials_authentication_requested(creds);
366 enum credentials_use_kerberos krb5_state =
367 cli_credentials_get_kerberos_state(creds);
368 char *user_principal = NULL;
369 const char *client_realm = cli_credentials_get_realm(creds);
370 const char *target_principal = gensec_get_target_principal(gensec_security);
371 const char *hostname = gensec_get_target_hostname(gensec_security);
373 if (!auth_requested) {
374 return NT_STATUS_INVALID_PARAMETER;
377 if (krb5_state == CRED_USE_KERBEROS_DISABLED) {
378 return NT_STATUS_INVALID_PARAMETER;
381 errno = 0;
382 user_principal = cli_credentials_get_principal(creds, gensec_security);
383 if (errno != 0) {
384 TALLOC_FREE(user_principal);
385 return NT_STATUS_NO_MEMORY;
388 if (user_principal == NULL) {
389 return NT_STATUS_INVALID_PARAMETER;
391 TALLOC_FREE(user_principal);
393 if (target_principal != NULL) {
394 return NT_STATUS_OK;
397 if (client_realm == NULL) {
398 return NT_STATUS_INVALID_PARAMETER;
401 if (hostname == NULL) {
402 return NT_STATUS_INVALID_PARAMETER;
405 if (strcasecmp(hostname, "localhost") == 0) {
406 return NT_STATUS_INVALID_PARAMETER;
409 #define STAR_SMBSERVER "*SMBSERVER"
410 if (strcmp(hostname, STAR_SMBSERVER) == 0) {
411 return NT_STATUS_INVALID_PARAMETER;
414 if (is_ipaddress(hostname)) {
415 return NT_STATUS_INVALID_PARAMETER;
418 return NT_STATUS_OK;