8#include <gssapi/gssapi.h>
9#include <gssapi/gssapi_krb5.h>
10#if __has_include(<krb5/krb5.h>)
21#define GUARD_NULL(var, return_var) \
26 return_var = O_KRB5_EXPECTED_NULL; \
32#define GUARD_NOT_NULL(var, return_var) \
37 return_var = O_KRB5_EXPECTED_NOT_NULL; \
43#define ALLOCATE_AND_CHECK(var, type, n, return_var) \
46 var = (type *) calloc (n, sizeof (type)); \
49 return_var = O_KRB5_NOMEM; \
55#define SKIP_WS(line, line_len, start, i) \
58 for (i = start; i < line_len; i++) \
60 if (line[i] != ' ' && line[i] != '\t') \
68#define IS_STR_EQUAL(line, line_len, start, cmp, cmp_len) \
69 ((line_len - start < cmp_len) ? 0 \
70 : (line_len == 0 && cmp_len == 0) \
72 : (memcmp (line + start, cmp, cmp_len) == 0))
74#define GSS_KRB5_INQ_SSPI_SESSION_KEY_OID_LENGTH 11
76#define GSS_KRB5_INQ_SSPI_SESSION_KEY_OID \
77 "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x05\x05"
79#ifndef gss_mech_spnego
81#define gss_mech_spnego (&spnego_mech_oid_desc)
84#define ARRAY_SIZE(a) (sizeof (a) / sizeof (a[0]))
86#define MAX_LINE_LENGTH 1024
109 line[strcspn (line,
"\n")] = 0;
110 last_element = strlen (line) - 1;
111 SKIP_WS (line, last_element, 0, i);
112 if (line[i] ==
'[' && line[last_element] ==
']')
119 if (
IS_STR_EQUAL (line, last_element + 1, i,
"[realms]", 8) == 1)
126 if (line[i] ==
'}' || line[last_element] ==
'}')
132 for (j = i; j <= last_element; j++)
134 if (line[j] != ((
char *) creds->
realm.
data)[j - i])
153 SKIP_WS (line, last_element, i + 3, i);
156 SKIP_WS (line, last_element, i + 1, i);
159 for (j = i; j <= last_element; j++)
161 (*kdc)[j - i] = line[j];
180#define CHECK_FPRINTF(result, writer, fmt, ...) \
183 if (fprintf (writer, fmt, __VA_ARGS__) < 0) \
185 result = O_KRB5_UNABLE_TO_WRITE; \
191#define CHECK_FPRINT(result, writer, fmt) \
194 if (fprintf (writer, fmt) < 0) \
196 result = O_KRB5_UNABLE_TO_WRITE; \
207 while (start < end && isspace ((
unsigned char) *start))
209 while (end > start && isspace ((
unsigned char) *(end - 1)))
223 const char *kdc_delimiter = strchr (kdc,
',');
224 const char *kdc_start = kdc;
225 const char *kdc_first_start = kdc_start;
226 const char *kdc_first_end =
227 kdc_delimiter != NULL ? kdc_delimiter : kdc + strlen (kdc);
230 if (kdc_delimiter != NULL)
232 kdc_start = kdc_delimiter + 1;
233 while ((kdc_delimiter = strchr (kdc_start,
',')) != NULL)
236 kdc_start = kdc_delimiter + 1;
254 FILE *file = NULL, *tmp = NULL;
260 if ((file = fopen (cp,
"r")) == NULL)
262 if ((file = fopen (cp,
"w")) == NULL)
272 if ((tmp = fopen (tmpfn,
"w")) == NULL)
293 if (rename (tmpfn, cp) != 0)
329#define CHECK_MAJOR_STAT() \
330 if (maj_stat != GSS_S_COMPLETE) \
332 result = O_KRB5_ERROR + maj_stat; \
335 char *user_principal;
338 size_t user_principal_cap = user_principal_len + 1;
342 snprintf (user_principal, user_principal_cap,
"%s@%s",
345 gss_name_t gss_username = GSS_C_NO_NAME;
349 gss_buffer_desc userbuf = {
350 .value = user_principal,
351 .length = user_principal_len,
353 gss_buffer_desc pwbuf = {
357 gss_OID_desc elements[] = {
364 gss_OID_set_desc creds_mechs = {
365 .elements = elements,
368 gss_OID_set_desc spnego_mechs = {
369 .elements = elements,
372 gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
375 gss_import_name (&min_stat, &userbuf, GSS_C_NT_USER_NAME, &gss_username);
378 maj_stat = gss_acquire_cred_with_password (&min_stat, gss_username, &pwbuf, 0,
379 &creds_mechs, GSS_C_INITIATE,
382 (void) gss_release_name (&min_stat, &gss_username);
386 maj_stat = gss_set_neg_mechs (&min_stat, cred, &spnego_mechs);
390 if (user_principal != NULL)
391 free (user_principal);
403 context->
gss_creds = GSS_C_NO_CREDENTIAL;
404 context->
gss_ctx = GSS_C_NO_CONTEXT;
414 if (context->
gss_creds != GSS_C_NO_CREDENTIAL)
416 gss_release_cred (&min_stat, &context->
gss_creds);
418 if (context->
gss_ctx != GSS_C_NO_CONTEXT)
420 gss_delete_sec_context (&min_stat, &context->
gss_ctx,
425 gss_release_name (&min_stat, &context->
gss_target);
429 gss_release_oid (&min_stat, &context->
gss_mech);
435 gss_release_buffer (&min_stat,
437 gss_release_buffer (&min_stat,
453 char *target_principal_str = NULL;
459 gss_buffer_desc targetbuf = GSS_C_EMPTY_BUFFER;
462 if (gss_context->
gss_creds == GSS_C_NO_CREDENTIAL)
476 snprintf (target_principal_str,
479 "%.*s/%.*s/%.*s@%.*s", (
int) target->
service.
len,
491 snprintf (target_principal_str,
500 targetbuf = (gss_buffer_desc) {
501 .value = target_principal_str,
502 .length = strlen (target_principal_str),
505 maj_stat = gss_import_name (&min_stat, &targetbuf,
508 GSS_C_NT_USER_NAME, &gss_target);
509 if (maj_stat != GSS_S_COMPLETE)
517 gss_context->
gss_want_flags = GSS_C_MUTUAL_FLAG | GSS_C_DELEG_POLICY_FLAG
518 | GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG
519 | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG;
526 if (target_principal_str != NULL)
527 free (target_principal_str);
540 gss_buffer_desc in_buf = {
541 .length = in_data->
len,
542 .value = in_data->
data,
544 gss_buffer_desc out_buf = GSS_C_EMPTY_BUFFER;
546 maj_stat = gss_init_sec_context (
552 if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
560 gss_release_buffer (&min_stat, &out_buf);
566 (*out_data)->data = out_buf.value;
567 (*out_data)->len = out_buf.length;
569 *more = maj_stat == GSS_S_CONTINUE_NEEDED;
581 gss_OID_desc gse_sesskey_inq_oid = {
585 gss_buffer_set_t set = GSS_C_NO_BUFFER_SET;
587 maj_stat = gss_inquire_sec_context_by_oid (&min_stat, gss_context->
gss_ctx,
588 &gse_sesskey_inq_oid, &set);
589 if (maj_stat != GSS_S_COMPLETE)
595 if ((set == GSS_C_NO_BUFFER_SET) || (set->count == 0)
596 || (set->elements[0].length == 0))
602 *out = calloc (1,
sizeof (
struct OKrb5Slice));
603 (*out)->data =
malloc (set->elements[0].length);
604 memcpy ((*out)->data, set->elements[0].value, set->elements[0].length);
605 (*out)->len = set->elements[0].length;
606 gss_release_buffer_set (&min_stat, &set);
614#define HEAP_STRING(var, s) \
617 var = calloc (1, strlen (s) + 1); \
618 snprintf (var, strlen (s) + 1, s); \
652 OM_uint32 msg_ctx = 0;
654 (void) gss_display_status (&min_stat, maj_stat, GSS_C_GSS_CODE,
655 GSS_C_NULL_OID, &msg_ctx, &msg);
static void prefix(int n, int i)
#define IS_STR_EQUAL(line, line_len, start, cmp, cmp_len)
#define CHECK_FPRINTF(result, writer, fmt,...)
#define GSS_KRB5_INQ_SSPI_SESSION_KEY_OID_LENGTH
#define CHECK_MAJOR_STAT()
char * okrb5_error_code_to_string(const OKrb5ErrorCode code)
static OKrb5ErrorCode okrb5_gss_authenticate(const OKrb5Credential *creds, struct OKrb5GSSContext *gss_creds)
void okrb5_gss_free_context(struct OKrb5GSSContext *context)
#define GSS_KRB5_INQ_SSPI_SESSION_KEY_OID
#define HEAP_STRING(var, s)
OKrb5ErrorCode o_krb5_add_realm(const OKrb5Credential *creds, const char *kdc)
OKrb5ErrorCode o_krb5_find_kdc(const OKrb5Credential *creds, char **kdc)
#define GUARD_NULL(var, return_var)
OKrb5ErrorCode o_krb5_gss_prepare_context(const OKrb5Credential *creds, struct OKrb5GSSContext *gss_context)
OKrb5ErrorCode o_krb5_gss_session_key_context(struct OKrb5GSSContext *gss_context, struct OKrb5Slice **out)
#define CHECK_FPRINT(result, writer, fmt)
gss_OID_desc spnego_mech_oid_desc
#define SKIP_WS(line, line_len, start, i)
struct OKrb5GSSContext * okrb5_gss_init_context(void)
static OKrb5ErrorCode o_krb5_write_trimmed(FILE *file, const char *prefix, const char *start, const char *end)
static OKrb5ErrorCode o_krb5_write_realm(FILE *file, const OKrb5Credential *creds, const char *kdc)
OKrb5ErrorCode o_krb5_gss_update_context(struct OKrb5GSSContext *gss_context, const struct OKrb5Slice *in_data, struct OKrb5Slice **out_data, bool *more)
#define ALLOCATE_AND_CHECK(var, type, n, return_var)
@ O_KRB5_EXPECTED_NOT_NULL
@ O_KRB5_CONF_NOT_CREATED
@ O_KRB5_TMP_CONF_NOT_MOVED
@ O_KRB5_TMP_CONF_NOT_CREATED
struct OKrb5Target target
struct OKrb5Slice config_path
gss_channel_bindings_t gss_channel_bindings
gss_OID gss_actual_mech_type
struct OKrb5Slice service
struct OKrb5Slice host_name