Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 104 additions & 60 deletions src/mod_auth_gssapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@

#include "mod_auth_gssapi.h"

const gss_OID_desc gss_mech_spnego = {
6, "\x2b\x06\x01\x05\x05\x02"
};

const gss_OID_desc gss_mech_ntlmssp = {
GSS_NTLMSSP_OID_LENGTH, GSS_NTLMSSP_OID_STRING
};
Expand Down Expand Up @@ -336,7 +340,6 @@ static bool mag_auth_basic(request_rec *req,
struct mag_config *cfg,
gss_buffer_desc ba_user,
gss_buffer_desc ba_pwd,
gss_cred_id_t acquired_cred,
gss_cred_usage_t cred_usage,
gss_name_t *client,
gss_OID *mech_type,
Expand All @@ -357,6 +360,9 @@ static bool mag_auth_basic(request_rec *req,
gss_ctx_id_t server_ctx = GSS_C_NO_CONTEXT;
gss_buffer_desc input = GSS_C_EMPTY_BUFFER;
gss_buffer_desc output = GSS_C_EMPTY_BUFFER;
gss_OID_set allowed_mechs = GSS_C_NO_OID_SET;
gss_OID_set_desc all_mechs_desc;
gss_OID_set actual_mechs = GSS_C_NO_OID_SET;
uint32_t init_flags = 0;
uint32_t maj, min;
bool ret = false;
Expand Down Expand Up @@ -389,11 +395,17 @@ static bool mag_auth_basic(request_rec *req,
goto done;
}

if (cfg->allowed_mechs && cfg->allowed_mechs->count > 1) {
all_mechs_desc.count = cfg->allowed_mechs->count - 1;
all_mechs_desc.elements = &cfg->allowed_mechs->elements[1];
allowed_mechs = &all_mechs_desc;
}

maj = gss_acquire_cred_with_password(&min, user, &ba_pwd,
GSS_C_INDEFINITE,
cfg->allowed_mechs,
allowed_mechs,
GSS_C_INITIATE,
&user_cred, NULL, NULL);
&user_cred, &actual_mechs, NULL);
if (GSS_ERROR(maj)) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
"In Basic Auth, %s",
Expand All @@ -402,73 +414,96 @@ static bool mag_auth_basic(request_rec *req,
goto done;
}

if (cred_usage == GSS_C_BOTH) {
/* If GSS_C_BOTH is used then inquire_cred will return the client
* name instead of the SPN of the server credentials. Therefore we
* need to acquire a different set of credential setting
* GSS_C_ACCEPT explicitly */
if (!mag_acquire_creds(req, cfg, cfg->allowed_mechs,
GSS_C_ACCEPT, &server_cred, NULL)) {
goto done;
}
} else {
server_cred = acquired_cred;
}
maj = gss_inquire_cred(&min, server_cred, &server,
NULL, NULL, NULL);
if (GSS_ERROR(maj)) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
"%s", mag_error(req, "gss_inquired_cred_() "
"failed", maj, min));
goto done;
}

#ifdef HAVE_CRED_STORE
if (cfg->deleg_ccache_dir) {
/* delegate ourselves credentials so we store them as requested */
init_flags |= GSS_C_DELEG_FLAG;
}
#endif

do {
/* output and input are inverted here, this is intentional */
maj = gss_init_sec_context(&min, user_cred, &user_ctx, server,
GSS_C_NO_OID, init_flags, 300,
GSS_C_NO_CHANNEL_BINDINGS, &output,
NULL, &input, NULL, NULL);
if (GSS_ERROR(maj)) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
"%s", mag_error(req, "gss_init_sec_context() "
"failed", maj, min));
goto done;
for (int i = 0; i < actual_mechs->count; i++) {

/* skip spnego if present (it is usually present when
* cfg->allowed_mechs is not set) */
if (gss_oid_equal(&actual_mechs->elements[i],
&gss_mech_spnego)) {
continue;
}

/* free these if looping */
gss_release_buffer(&min, &output);
maj = gss_accept_sec_context(&min, &server_ctx, acquired_cred,
&input, GSS_C_NO_CHANNEL_BINDINGS,
client, mech_type, &output, NULL,
vtime, delegated_cred);
gss_release_buffer(&min, &input);
gss_release_name(&min, &server);
gss_release_cred(&min, &server_cred);

all_mechs_desc.count = 1;
all_mechs_desc.elements = &actual_mechs->elements[i];

/* must acquire with GSS_C_ACCEPT to get the server name */
if (!mag_acquire_creds(req, cfg, allowed_mechs,
GSS_C_ACCEPT, &server_cred, NULL)) {
continue;
}
maj = gss_inquire_cred(&min, server_cred, &server,
NULL, NULL, NULL);
if (GSS_ERROR(maj)) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
"%s", mag_error(req, "gss_accept_sec_context()"
" failed", maj, min));
goto done;
"%s", mag_error(req, "gss_inquired_cred_() "
"failed", maj, min));
continue;
}
gss_release_buffer(&min, &input);
} while (maj == GSS_S_CONTINUE_NEEDED);

ret = true;
if (cred_usage == GSS_C_BOTH) {
/* reacquire server creds in order to allow delegation */
gss_release_cred(&min, &server_cred);
if (!mag_acquire_creds(req, cfg, allowed_mechs,
GSS_C_BOTH, &server_cred, NULL)) {
continue;
}
}

do {
/* output and input are inverted here, this is intentional */
maj = gss_init_sec_context(&min, user_cred, &user_ctx, server,
&actual_mechs->elements[i], init_flags,
300, GSS_C_NO_CHANNEL_BINDINGS, &output,
NULL, &input, NULL, NULL);
if (GSS_ERROR(maj)) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
"%s", mag_error(req, "gss_init_sec_context() "
"failed", maj, min));
break;
}
gss_release_buffer(&min, &output);
maj = gss_accept_sec_context(&min, &server_ctx, server_cred,
&input, GSS_C_NO_CHANNEL_BINDINGS,
client, mech_type, &output, NULL,
vtime, delegated_cred);
if (GSS_ERROR(maj)) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
"%s", mag_error(req, "gss_accept_sec_context()"
" failed", maj, min));
break;
}
gss_release_buffer(&min, &input);
} while (maj == GSS_S_CONTINUE_NEEDED);

if (maj == GSS_S_COMPLETE) {
ret = true;
break;
}
}

done:
gss_release_buffer(&min, &output);
gss_release_buffer(&min, &input);
gss_release_name(&min, &server);
if (server_cred != acquired_cred) {
gss_release_cred(&min, &server_cred);
}
gss_release_cred(&min, &server_cred);
gss_delete_sec_context(&min, &server_ctx, GSS_C_NO_BUFFER);
gss_release_name(&min, &user);
gss_release_cred(&min, &user_cred);
gss_delete_sec_context(&min, &user_ctx, GSS_C_NO_BUFFER);
gss_release_oid_set(&min, &actual_mechs);
#ifdef HAVE_GSS_KRB5_CCACHE_NAME
if (user_ccache != NULL) {
maj = gss_krb5_ccache_name(&min, orig_ccache, NULL);
Expand Down Expand Up @@ -510,6 +545,7 @@ static int mag_auth(request_rec *req)
char *clientname;
gss_OID mech_type = GSS_C_NO_OID;
gss_OID_set desired_mechs = GSS_C_NO_OID_SET;
gss_OID_set indicated_mechs = GSS_C_NO_OID_SET;
gss_buffer_desc lname = GSS_C_EMPTY_BUFFER;
struct mag_conn *mc = NULL;
time_t expiration;
Expand All @@ -522,12 +558,17 @@ static int mag_auth(request_rec *req)

cfg = ap_get_module_config(req->per_dir_config, &auth_gssapi_module);

if (!cfg->allowed_mechs) {
if (cfg->allowed_mechs) {
desired_mechs = cfg->allowed_mechs;
} else {
/* Try to fetch the default set if not explicitly configured */
gss_cred_id_t server_cred = GSS_C_NO_CREDENTIAL;
(void)mag_acquire_creds(req, cfg, GSS_C_NO_OID_SET, GSS_C_ACCEPT,
&server_cred, &cfg->allowed_mechs);
(void)gss_release_cred(&min, &server_cred);
maj = gss_indicate_mechs(&min, &indicated_mechs);
if (maj != GSS_S_COMPLETE) {
ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, req, "%s",
mag_error(req, "gss_indicate_mechs() failed",
maj, min));
}
desired_mechs = indicated_mechs;
}

/* implicit auth for subrequests if main auth already happened */
Expand Down Expand Up @@ -682,21 +723,20 @@ static int mag_auth(request_rec *req)
cred_usage = GSS_C_BOTH;
}
#endif
if (!mag_acquire_creds(req, cfg, desired_mechs,
cred_usage, &acquired_cred, NULL)) {
goto done;
}

if (auth_type == AUTH_TYPE_BASIC) {
if (mag_auth_basic(req, cfg, ba_user, ba_pwd,
acquired_cred, cred_usage,
&client, &mech_type,
cred_usage, &client, &mech_type,
&delegated_cred, &vtime)) {
goto complete;
}
goto done;
}

if (!mag_acquire_creds(req, cfg, desired_mechs,
cred_usage, &acquired_cred, NULL)) {
goto done;
}

if (auth_type == AUTH_TYPE_NEGOTIATE &&
cfg->allowed_mechs != GSS_C_NO_OID_SET) {
maj = gss_set_neg_mechs(&min, acquired_cred, cfg->allowed_mechs);
Expand Down Expand Up @@ -821,6 +861,7 @@ static int mag_auth(request_rec *req)
ap_auth_name(req)));
}
}
gss_release_oid_set(&min, &indicated_mechs);
if (ctx != GSS_C_NO_CONTEXT)
gss_delete_sec_context(&min, &ctx, GSS_C_NO_BUFFER);
gss_release_cred(&min, &acquired_cred);
Expand Down Expand Up @@ -1009,6 +1050,9 @@ static const char *mag_allow_mech(cmd_parms *parms, void *mconfig,
sizeof(gss_OID_set_desc));
size = sizeof(gss_OID) * MAX_ALLOWED_MECHS;
cfg->allowed_mechs->elements = apr_palloc(parms->pool, size);

cfg->allowed_mechs->elements[0] = gss_mech_spnego;
cfg->allowed_mechs->count++;
}

if (strcmp(w, "krb5") == 0) {
Expand Down