2929
3030#include <httpd.h>
3131#include <http_core.h>
32+ #include <http_connection.h>
3233#include <http_log.h>
3334#include <http_request.h>
3435#include <apr_strings.h>
@@ -39,6 +40,7 @@ module AP_MODULE_DECLARE_DATA auth_gssapi_module;
3940struct mag_config {
4041 bool ssl_only ;
4142 bool map_to_local ;
43+ bool gss_conn_ctx ;
4244 gss_key_value_set_desc cred_store ;
4345};
4446
@@ -83,6 +85,24 @@ static char *mag_error(request_rec *req, const char *msg,
8385 return apr_psprintf (req -> pool , "%s: [%s (%s)]" , msg , msg_maj , msg_min );
8486}
8587
88+ struct mag_conn {
89+ gss_ctx_id_t ctx ;
90+ bool established ;
91+ char * user_name ;
92+ char * gss_name ;
93+ };
94+
95+ static int mag_pre_connection (conn_rec * c , void * csd )
96+ {
97+ struct mag_conn * mc ;
98+
99+ mc = apr_pcalloc (c -> pool , sizeof (struct mag_conn ));
100+ if (!mc ) return DECLINED ;
101+
102+ ap_set_module_config (c -> conn_config , & auth_gssapi_module , (void * )mc );
103+ return OK ;
104+ }
105+
86106static int mag_auth (request_rec * req )
87107{
88108 const char * type ;
@@ -104,6 +124,7 @@ static int mag_auth(request_rec *req)
104124 char * clientname ;
105125 gss_OID mech_type = GSS_C_NO_OID ;
106126 gss_buffer_desc lname = GSS_C_EMPTY_BUFFER ;
127+ struct mag_conn * mc = NULL ;
107128
108129 type = ap_auth_type (req );
109130 if ((type == NULL ) || (strcasecmp (type , "GSSAPI" ) != 0 )) {
@@ -117,6 +138,26 @@ static int mag_auth(request_rec *req)
117138 "FIXME: check for ssl!" );
118139 }
119140
141+ if (cfg -> gss_conn_ctx ) {
142+ mc = (struct mag_conn * )ap_get_module_config (
143+ req -> connection -> conn_config ,
144+ & auth_gssapi_module );
145+ if (!mc ) {
146+ return DECLINED ;
147+ }
148+ if (mc -> established ) {
149+ ap_log_rerror (APLOG_MARK , APLOG_DEBUG |APLOG_NOERRNO , 0 , req ,
150+ "Connection bound pre-authentication found." );
151+ apr_table_set (req -> subprocess_env , "GSS_NAME" , mc -> gss_name );
152+ req -> ap_auth_type = apr_pstrdup (req -> pool , "Negotiate" );
153+ req -> user = apr_pstrdup (req -> pool , mc -> user_name );
154+ ret = OK ;
155+ goto done ;
156+ } else {
157+ ctx = mc -> ctx ;
158+ }
159+ }
160+
120161 auth_header = apr_table_get (req -> headers_in , "Authorization" );
121162 if (!auth_header ) goto done ;
122163
@@ -132,8 +173,6 @@ static int mag_auth(request_rec *req)
132173 if (!input .value ) goto done ;
133174 input .length = apr_base64_decode (input .value , auth_header_value );
134175
135- /* FIXME: this works only with "one-roundtrip" gssapi auth for now,
136- * should work with Krb, will fail with NTLMSSP */
137176 maj = gss_accept_sec_context (& min , & ctx , GSS_C_NO_CREDENTIAL ,
138177 & input , GSS_C_NO_CHANNEL_BINDINGS ,
139178 & client , & mech_type , & output , & flags , NULL ,
@@ -145,23 +184,12 @@ static int mag_auth(request_rec *req)
145184 goto done ;
146185 }
147186
148- if (output .length ) {
149- replen = apr_base64_encode_len (output .length ) + 1 ;
150- reply = apr_pcalloc (req -> pool , 10 + replen );
151- if (!reply ) goto done ;
152- memcpy (reply , "Negotiate " , 10 );
153- apr_base64_encode (& reply [10 ], output .value , output .length );
154- reply [replen ] = '\0' ;
155- apr_table_add (req -> err_headers_out , "WWW-Authenticate" , reply );
187+ if (mc ) {
188+ mc -> ctx = ctx ;
189+ ctx = GSS_C_NO_CONTEXT ;
156190 }
157191
158- maj = gss_display_name (& min , client , & name , NULL );
159- if (GSS_ERROR (maj )) {
160- ap_log_rerror (APLOG_MARK , APLOG_ERR |APLOG_NOERRNO , 0 , req ,
161- mag_error (req , "gss_accept_sec_context() failed" ,
162- maj , min ));
163- goto done ;
164- }
192+ if (maj == GSS_S_CONTINUE_NEEDED ) goto done ;
165193
166194#ifdef HAVE_GSS_STORE_CRED_INTO
167195 if (cfg -> cred_store && delegated_cred != GSS_C_NO_CREDENTIAL ) {
@@ -176,6 +204,13 @@ static int mag_auth(request_rec *req)
176204 req -> ap_auth_type = apr_pstrdup (req -> pool , "Negotiate" );
177205
178206 /* Always set the GSS name in an env var */
207+ maj = gss_display_name (& min , client , & name , NULL );
208+ if (GSS_ERROR (maj )) {
209+ ap_log_rerror (APLOG_MARK , APLOG_ERR |APLOG_NOERRNO , 0 , req ,
210+ mag_error (req , "gss_accept_sec_context() failed" ,
211+ maj , min ));
212+ goto done ;
213+ }
179214 clientname = apr_pstrndup (req -> pool , name .value , name .length );
180215 apr_table_set (req -> subprocess_env , "GSS_NAME" , clientname );
181216
@@ -190,11 +225,31 @@ static int mag_auth(request_rec *req)
190225 } else {
191226 req -> user = clientname ;
192227 }
228+
229+ if (mc ) {
230+ mc -> user_name = apr_pstrdup (req -> connection -> pool , req -> user );
231+ mc -> gss_name = apr_pstrdup (req -> connection -> pool , clientname );
232+ mc -> established = true;
233+ }
234+
193235 ret = OK ;
194236
195237done :
196238 if (ret == HTTP_UNAUTHORIZED ) {
197- apr_table_add (req -> err_headers_out , "WWW-Authenticate" , "Negotiate" );
239+ if (output .length != 0 ) {
240+ replen = apr_base64_encode_len (output .length ) + 1 ;
241+ reply = apr_pcalloc (req -> pool , 10 + replen );
242+ if (reply ) {
243+ memcpy (reply , "Negotiate " , 10 );
244+ apr_base64_encode (& reply [10 ], output .value , output .length );
245+ reply [replen ] = '\0' ;
246+ apr_table_add (req -> err_headers_out ,
247+ "WWW-Authenticate" , reply );
248+ }
249+ } else {
250+ apr_table_add (req -> err_headers_out ,
251+ "WWW-Authenticate" , "Negotiate" );
252+ }
198253 }
199254 gss_release_cred (& min , & delegated_cred );
200255 gss_release_buffer (& min , & output );
@@ -230,6 +285,13 @@ static const char *mag_map_to_local(cmd_parms *parms, void *mconfig, int on)
230285 return NULL ;
231286}
232287
288+ static const char * mag_conn_ctx (cmd_parms * parms , void * mconfig , int on )
289+ {
290+ struct mag_config * cfg = (struct mag_config * )mconfig ;
291+ cfg -> gss_conn_ctx = on ? true : false;
292+ return NULL ;
293+ }
294+
233295static const char * mag_cred_store (cmd_parms * parms , void * mconfig ,
234296 const char * w )
235297{
@@ -281,6 +343,8 @@ static const command_rec mag_commands[] = {
281343 "Work only if connection is SSL Secured" ),
282344 AP_INIT_FLAG ("GSSLocalName" , mag_map_to_local , NULL , OR_AUTHCFG ,
283345 "Work only if connection is SSL Secured" ),
346+ AP_INIT_FLAG ("GSSConnectionContext" , mag_conn_ctx , NULL , OR_AUTHCFG ,
347+ "Authentication is valid for the life of the connection" ),
284348 AP_INIT_ITERATE ("GSSCredStore" , mag_cred_store , NULL , OR_AUTHCFG ,
285349 "Credential Store" ),
286350 { NULL }
@@ -290,6 +354,7 @@ static void
290354mag_register_hooks (apr_pool_t * p )
291355{
292356 ap_hook_check_user_id (mag_auth , NULL , NULL , APR_HOOK_MIDDLE );
357+ ap_hook_pre_connection (mag_pre_connection , NULL , NULL , APR_HOOK_MIDDLE );
293358}
294359
295360module AP_MODULE_DECLARE_DATA auth_gssapi_module =
0 commit comments