/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* mod_auth_gss module
*
* Wyllys Ingersoll <wyllys.ingersoll@sun.com>
*
* Based on work by
* Daniel Kouril <kouril@users.sourceforge.net>
* James E. Robinson, III <james@ncstate.net>
* Daniel Henninger <daniel@ncsu.edu>
* Ludek Sulak <xsulak@fi.muni.cz>
*/
/*
*/
#include <strings.h>
#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
#include "http_log.h"
#include "http_protocol.h"
#include "http_request.h"
#include "ap_config.h"
#include "apr_base64.h"
#include "apr_lib.h"
#include "apr_time.h"
#include "apr_errno.h"
#include "apr_global_mutex.h"
#include "apr_strings.h"
#include "ap_compat.h"
#include <gssapi/gssapi_ext.h>
static void *gss_create_dir_config(apr_pool_t *, char *);
int gss_authenticate(request_rec *);
typedef struct {
char *gss_service_name;
char *keytab_file;
int gss_debug;
const char *name)
{
return NULL;
}
const char *file)
{
return NULL;
}
const char *debugflag)
{
return NULL;
}
OR_AUTHCFG, "Service name used for authentication."),
"Location of Kerberos V5 keytab file."),
"Enable debug logging in error_log"),
{ NULL }
};
static void
{
}
gss_create_dir_config, /* dir config creater */
NULL, /* dir merger --- default is to override */
NULL, /* server config */
NULL, /* merge server config */
gss_auth_cmds, /* command apr_table_t */
gss_register_hooks /* register hooks */
};
typedef struct {
static void *
{
return rec;
}
const request_rec *r, const char *fmt, ...)
{
}
/*********************************************************************
* GSSAPI Authentication
********************************************************************/
static const char *
{
do {
&msg);
break;
NULL);
&msg);
}
return (err_msg);
}
static int
{
return 0;
(void) gss_delete_sec_context(&minor_status,
}
}
return 0;
}
static int
{
int ret = 0;
"acquire_server_creds for %s", buf);
&server_name);
if (GSS_ERROR(major_status)) {
"gss_import_name() failed"));
return (HTTP_INTERNAL_SERVER_ERROR);
}
if (GSS_ERROR(major_status)) {
"gss_acquire_cred() failed"));
}
return (ret);
}
static int
const char *auth_line, char **negotiate_ret_value)
{
int ret = 0;
"authenticate_user_gss called");
*negotiate_ret_value = (char *)"";
if (gss_connection == NULL) {
if (gss_connection == NULL) {
"apr_pcalloc() failed (not enough memory)");
goto end;
}
}
if (conf->keytab_file) {
char *ktname;
/*
* We don't use the ap_* calls here, since the string
* passed to putenv() will become part of the enviroment
* and shouldn't be free()ed by apache.
*/
"malloc() failed: not enough memory");
goto end;
}
/*
* Put the keytab name in the environment so that Kerberos
* knows where to look later.
*/
}
/* ap_getword() shifts parameter */
if (auth_param == NULL) {
"No Authorization parameter in request from client");
goto end;
}
"apr_pcalloc() failed (not enough memory)");
goto end;
}
}
mechstr = "<unknown>";
}
"Client wants GSS mech: %s", mechstr);
/* Get creds using the mechanism that the client requested */
if (ret)
goto end;
}
/*
* Try to display the server creds information.
*/
if (major_status == GSS_S_COMPLETE) {
}
if (major_status == GSS_S_COMPLETE) {
"got server creds for: %.*s",
}
}
NULL,
NULL,
NULL,
if (output_token.length) {
"apr_pcalloc() failed (not enough memory)");
goto end;
}
}
if (GSS_ERROR(major_status)) {
"gss_accept_sec_context() failed"));
/* Don't offer the Negotiate method again if call to GSS layer failed */
goto end;
}
if (major_status == GSS_S_CONTINUE_NEEDED) {
/*
* Some GSSAPI mechanisms may require multiple iterations to
* establish authentication. Most notably, when MUTUAL_AUTHENTICATION
* flag is used, multiple round trips are needed.
*/
goto end;
}
if (client_name != GSS_C_NO_NAME) {
&name_token, NULL);
if (GSS_ERROR(major_status)) {
"gss_export_name() failed"));
goto end;
}
if (name_token.length) {
}
"Authenticated user: %s",
}
r->ap_auth_type = "Negotiate";
end:
if (delegated_cred)
if (output_token.length)
if (client_name != GSS_C_NO_NAME)
return ret;
}
static int
{
return 0;
}
static void
char *negotiate_ret_value)
{
int set_basic = 0;
char *negoauth_param;
/* get the user realm specified in .htaccess */
auth_name = ap_auth_name(r);
"note_gss_auth_failure: auth_name = %s",
if (negotiate_ret_value != NULL) {
}
}
int
{
int ret;
char *negotiate_ret_value;
/* get the type specified in .htaccess */
type = ap_auth_type(r);
"gss_authenticate: type = %s", type);
return DECLINED;
}
/* get what the user sent us in the HTTP header */
if (!auth_line) {
"No authentication data found");
return HTTP_UNAUTHORIZED;
}
if (already_succeeded(r))
return last_return;
} else {
}
if (ret == HTTP_UNAUTHORIZED) {
"Authentication failed.");
}
last_return = ret;
return ret;
}