|
From: <co...@us...> - 2008-05-16 00:27:11
|
Update of /cvsroot/aolserver/knspnego/src In directory sc8-pr-cvs11.sourceforge.net:/tmp/cvs-serv7639/src Added Files: decode.c knspnego.cpp mod_spnego.cpp unix-env.cpp win32-env.cpp Log Message: First version of port of Apache's "mod_spnego" to AOLServer. Works, but is difficult to configure (relies on environment variables the way Apache does, instead of ns_section/ns_param) and needs some work for integration into the AOLServer "configure" environment. --- NEW FILE: decode.c --- /* base64 encoder/decoder. Originally part of main/util.c * but moved here so that support/ab and apr_sha1.c could * use it. This meant removing the apr_palloc()s and adding * ugly 'len' functions, which is quite a nasty cost. */ #include "base64.h" #if APR_CHARSET_EBCDIC #include "apr_xlate.h" #endif /* APR_CHARSET_EBCDIC */ static const unsigned char pr2six[256] = { //AMX #if !APR_CHARSET_EBCDIC /* ASCII table */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 }; /* #if 0 #else /*APR_CHARSET_EBCDIC /* EBCDIC table 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 63, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 64, 64, 64, 64, 64, 64, 64, 35, 36, 37, 38, 39, 40, 41, 42, 43, 64, 64, 64, 64, 64, 64, 64, 64, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 64, 64, 64, 64, 64, 64, 64, 9, 10, 11, 12, 13, 14, 15, 16, 17, 64, 64, 64, 64, 64, 64, 64, 64, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, 64, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64 }; #endif /*APR_CHARSET_EBCDIC*/ #if APR_CHARSET_EBCDIC static apr_xlate_t *xlate_to_ebcdic; static unsigned char os_toascii[256]; APU_DECLARE(apr_status_t) base64init_ebcdic(apr_xlate_t *to_ascii, DEBUG_BREAK apr_xlate_t *to_ebcdic) { int i; apr_size_t inbytes_left, outbytes_left; apr_status_t rv; int onoff; /* Only single-byte conversion is supported. */ rv = apr_xlate_sb_get(to_ascii, &onoff); if (rv) { return rv; } if (!onoff) { /* If conversion is not single-byte-only */ return APR_EINVAL; } rv = apr_xlate_sb_get(to_ebcdic, &onoff); if (rv) { return rv; } if (!onoff) { /* If conversion is not single-byte-only */ return APR_EINVAL; } xlate_to_ebcdic = to_ebcdic; for (i = 0; i < sizeof(os_toascii); i++) { os_toascii[i] = i; } inbytes_left = outbytes_left = sizeof(os_toascii); apr_xlate_conv_buffer(to_ascii, os_toascii, &inbytes_left, os_toascii, &outbytes_left); return APR_SUCCESS; } #endif /*APR_CHARSET_EBCDIC*/ int base64_decode_len(const char *bufcoded) { int nbytesdecoded; register const unsigned char *bufin; register int nprbytes; bufin = (const unsigned char *) bufcoded; while (pr2six[*(bufin++)] <= 63); nprbytes = (bufin - (const unsigned char *) bufcoded) - 1; nbytesdecoded = ((nprbytes + 3) / 4) * 3; return nbytesdecoded + 1; } int base64_decode(char *bufplain, const char *bufcoded) { //#if APR_CHARSET_EBCDIC // apr_size_t inbytes_left, outbytes_left; //#endif /* APR_CHARSET_EBCDIC */ int len; len = base64_decode_binary((unsigned char *) bufplain, bufcoded); #if 0 #if APR_CHARSET_EBCDIC inbytes_left = outbytes_left = len; apr_xlate_conv_buffer(xlate_to_ebcdic, bufplain, &inbytes_left, bufplain, &outbytes_left); #endif /* APR_CHARSET_EBCDIC */ #endif bufplain[len] = '\0'; return len; } /* This is the same as base64_decode() except on EBCDIC machines, where * the conversion of the output to ebcdic is left out. */ int base64_decode_binary(unsigned char *bufplain, const char *bufcoded) { int nbytesdecoded; register const unsigned char *bufin; register unsigned char *bufout; register int nprbytes; bufin = (const unsigned char *) bufcoded; while (pr2six[*(bufin++)] <= 63); nprbytes = (bufin - (const unsigned char *) bufcoded) - 1; nbytesdecoded = ((nprbytes + 3) / 4) * 3; bufout = (unsigned char *) bufplain; bufin = (const unsigned char *) bufcoded; while (nprbytes > 4) { *(bufout++) = (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4); *(bufout++) = (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2); *(bufout++) = (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]); bufin += 4; nprbytes -= 4; } /* Note: (nprbytes == 1) would be an error, so just ingore that case */ if (nprbytes > 1) { *(bufout++) = (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4); } if (nprbytes > 2) { *(bufout++) = (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2); } if (nprbytes > 3) { *(bufout++) = (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]); } nbytesdecoded -= (4 - nprbytes) & 3; return nbytesdecoded; } static const char basis_64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; int base64_encode_len(int len) { return ((len + 2) / 3 * 4) + 1; } int base64_encode(char *encoded, const char *string, int len) { #if !APR_CHARSET_EBCDIC return base64_encode_binary(encoded, (const unsigned char *) string, len); #else /* APR_CHARSET_EBCDIC */ int i; char *p; p = encoded; for (i = 0; i < len - 2; i += 3) { *p++ = basis_64[(os_toascii[string[i]] >> 2) & 0x3F]; *p++ = basis_64[((os_toascii[string[i]] & 0x3) << 4) | ((int) (os_toascii[string[i + 1]] & 0xF0) >> 4)]; *p++ = basis_64[((os_toascii[string[i + 1]] & 0xF) << 2) | ((int) (os_toascii[string[i + 2]] & 0xC0) >> 6)]; *p++ = basis_64[os_toascii[string[i + 2]] & 0x3F]; } if (i < len) { *p++ = basis_64[(os_toascii[string[i]] >> 2) & 0x3F]; if (i == (len - 1)) { *p++ = basis_64[((os_toascii[string[i]] & 0x3) << 4)]; *p++ = '='; } else { *p++ = basis_64[((os_toascii[string[i]] & 0x3) << 4) | ((int) (os_toascii[string[i + 1]] & 0xF0) >> 4)]; *p++ = basis_64[((os_toascii[string[i + 1]] & 0xF) << 2)]; } *p++ = '='; } *p++ = '\0'; return p - encoded; #endif /* APR_CHARSET_EBCDIC */ } /* This is the same as base64_encode() except on EBCDIC machines, where * the conversion of the input to ascii is left out. */ int base64_encode_binary(char *encoded, const unsigned char *string, int len) { int i; char *p; p = encoded; for (i = 0; i < len - 2; i += 3) { *p++ = basis_64[(string[i] >> 2) & 0x3F]; *p++ = basis_64[((string[i] & 0x3) << 4) | ((int) (string[i + 1] & 0xF0) >> 4)]; *p++ = basis_64[((string[i + 1] & 0xF) << 2) | ((int) (string[i + 2] & 0xC0) >> 6)]; *p++ = basis_64[string[i + 2] & 0x3F]; } if (i < len) { *p++ = basis_64[(string[i] >> 2) & 0x3F]; if (i == (len - 1)) { *p++ = basis_64[((string[i] & 0x3) << 4)]; *p++ = '='; } else { *p++ = basis_64[((string[i] & 0x3) << 4) | ((int) (string[i + 1] & 0xF0) >> 4)]; *p++ = basis_64[((string[i + 1] & 0xF) << 2)]; } *p++ = '='; } *p++ = '\0'; return p - encoded; } --- NEW FILE: knspnego.cpp --- /* /** * (c) Copyright 2008 KnowNow, Inc., Sunnyvale CA * * @KNOWNOW_LICENSE_START@ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The name "KnowNow" is a trademark of KnowNow, Inc. and may not * be used to endorse or promote any product without prior written * permission from KnowNow, Inc. * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL KNOWNOW, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * @KNOWNOW_LICENSE_END@ **/ * */ #include "knexportlibraryknspnegomodule.h" #include "ns.h" #include "spnegoconfig.h" #include <string.h> #include <fcntl.h> #include <sys/stat.h> #include <time.h> #define bzero(dst,len) memset(dst,0,len) #define bcopy(src,dst,len) memcpy(dst,src,len) extern "C" { //NS_EXPORT int Ns_ModuleVersion = 1; EXPORT_LIBRARY_KNSPNEGO int KnSpnego_ModInit(char *server, char *module); } #define b64_sizeof(x) (((sizeof(x) + 2) / 3) * 4) #define b64_size(x) (((x + 2) / 3) * 4) #define BADARGS(nl,nh,example) \ if ((argc<(nl)) || (argc>(nh))) { \ Tcl_AppendResult(interp,"wrong # args: should be \"",argv[0], \ (example),"\"",NULL); \ return NS_ERROR; \ // } #define ENC_HEADER_LEN 128 #define MIN_ENCODED_STR_LEN 59 int authenticateUser (char** authUser, const char *authToken); SPNEGO_CONFIG *spConfig = NULL; static Ns_Callback ModuleCleanup; static int spnegoInterpInit(Tcl_Interp * interp, void *context); static int kn_spnego(ClientData context, Tcl_Interp * interp, int argc, char **argv); /* *---------------------------------------------------------------------- * * KnSpnego_ModInit -- * * This is the knspnego module's entry point. AOLserver runs * this function right after the module is loaded. It is used to * read configuration data, initialize data structures, kick off * the Tcl initialization function (if any), and do other things * at startup. * * Results: * NS_OK or NS_ERROR * *---------------------------------------------------------------------- */ EXPORT_LIBRARY_KNSPNEGO int KnSpnego_ModInit(char *hServer, char * hModule) { FILE *fd = NULL; Ns_DString ds; char *publickeyfile = NULL; char *privatekeyfile = NULL; char *path = NULL; Ns_Log(Notice, "KN_SPNEGO_*****_ nit(): serv = %s module = %s", hServer, hModule ); Ns_DStringInit(&ds); SPNEGO_CONFIG *spConfig = (SPNEGO_CONFIG *)ns_malloc(sizeof(SPNEGO_CONFIG)); spConfig->directoryConfig = (DIRECTORY_CONFIG *)ns_malloc(sizeof(DIRECTORY_CONFIG)); spConfig->serverConfig = (SERVER_CONFIG *)ns_malloc(sizeof(SERVER_CONFIG)); path = Ns_ConfigGetPath(hServer, hModule, NULL); if (path) { spConfig->directoryConfig->setKrb5ServiceName( Ns_ConfigGet(path, "Krb5ServiceName")); spConfig->directoryConfig->setKrb5KeyTabFile (Ns_ConfigGet(path, "Krb5KeyTabFile")); spConfig->setAuthType(Ns_ConfigGet(path, "AuthType")); } return (Ns_TclInitInterps(hServer, spnegoInterpInit, NULL)); } /* *---------------------------------------------------------------------- * * ModuleCleanup -- * * Deallocates allocated resources. * * Results: * None * *---------------------------------------------------------------------- */ static void ModuleCleanup(void *ignored) { } /* *---------------------------------------------------------------------- * * spnegoInterpInit -- * * Register new commands with the Tcl interpreter. * * Results: * NS_OK or NS_ERROR * *---------------------------------------------------------------------- */ static int spnegoInterpInit(Tcl_Interp * interp, void *context) { Tcl_CreateCommand(interp, "kn_spnego", kn_spnego, NULL, NULL); return NS_OK; } /* *---------------------------------------------------------------------- * * kn_spnego -- * * Gets the authentication token and calls the authenticateUser() * function. Send the authentication results back to the tcl filter. * * Results: * NS_OK * *---------------------------------------------------------------------- */ static int kn_spnego(ClientData context, Tcl_Interp * interp, int argc, char **argv) { FILE *fd = NULL; int keybits = 0; int firstarg = 1; char *token = NULL; Ns_Log(Notice, "KN_SPNEGO_**********_ kn_spneg(): argsnmb = %d", argc ); // DebugBreak(); token = argv[firstarg]; char *authUser =NULL; authenticateUser (/*connPtr,*/&authUser, (const char *)token); Ns_Log(Notice, "knspnego - ***AUTHENTICATED USER Before sending IS %s", authUser); Tcl_AppendResult(interp, authUser, NULL); if(authUser) { ns_free(authUser); } return TCL_OK; } --- NEW FILE: mod_spnego.cpp --- /* ----------------------------------------------------------------------------- * mod_spnego.cpp - is modified version of mod_spnego.c to support * authentication for AOLServer, via the RFC 2478 SPNEGO GSS-API mechanism. * * Original mod_spnego.c was supporting GSS-API authentication mechanism for * Apache web server * * Assumes use from a TCL-based pre-auth filter. * * Author: Avet Mnatsakanian * Authors of original module: Frank Balluffi and Markus Moeller * */ /* Copyright 2000-2005 The Apache Software Foundation or its licensors, as * applicable. * * Licensed 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 * * http://www.apache.org/licenses/LICENSE-2.0 * * 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. */ #include "ns.h" #include "string.h" #undef strcasecmp #undef strncasecmp #ifdef HEIMDAL #include <gssapi.h> #define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE #elif defined(SEAM) #include <gssapi/gssapi.h> #define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE #else #include <gssapi_generic.h> #endif #include "spnegohelp.h" #include "krb5help.h" #include "spnegoconfig.h" #include "base64.h" #include <errno.h> static char * connectionUser; DIRECTORY_CONFIG* SPNEGO_CONFIG::directoryConfig = NULL; SERVER_CONFIG* SPNEGO_CONFIG::serverConfig = NULL; const char *SPNEGO_CONFIG::authType=NULL; static int handleKerberosToken (char **authUser, const unsigned char * inputKerberosToken, size_t inputKerberosTokenLength, unsigned char ** outputKerberosToken, size_t * outputKerberosTokenLength) { gss_buffer_desc buffer = GSS_C_EMPTY_BUFFER; gss_buffer_desc serviceBuffer = GSS_C_EMPTY_BUFFER; gss_name_t clientName = GSS_C_NO_NAME; gss_ctx_id_t context = GSS_C_NO_CONTEXT; gss_cred_id_t credential = GSS_C_NO_CREDENTIAL; gss_buffer_desc inputToken = GSS_C_EMPTY_BUFFER; OM_uint32 majorStatus; OM_uint32 minorStatus1; OM_uint32 minorStatus2; gss_buffer_desc outputToken = GSS_C_EMPTY_BUFFER; int rc = TCL_OK; gss_name_t serverName = GSS_C_NO_NAME; char * ServiceName = NULL; char * Krb5ServiceName = NULL; const char * Krb5KeyTabFile = NULL; errno = 0; Krb5ServiceName = (char *)(SPNEGO_CONFIG::getDirConfig())->getKrb5ServiceName(); ServiceName = strtok(Krb5ServiceName," "); while ( ServiceName != NULL ) { serviceBuffer.value = ns_strdup(ServiceName); serviceBuffer.length = sizeof (serviceBuffer.value) ; Ns_Log(Notice, "mod_SPNEGO - handleKerberosToken_1 ServiceName=%s",ServiceName); if (strchr(ServiceName,'/')) { Ns_Log(Notice, "mod_SPNEGO - handleKerberosToken_2 "); majorStatus = gss_import_name (&minorStatus1, &serviceBuffer, (gss_OID) GSS_C_NULL_OID, &serverName); } else { Ns_Log(Notice, "mod_SPNEGO - handleKerberosToken_3 gss_nt_service_name=%s",gss_nt_service_name); Ns_Log(Notice, "mod_SPNEGO - handleKerberosToken_3 gss_nt_service_name=%s",(char *)&serverName); majorStatus = gss_import_name (&minorStatus1, &serviceBuffer, (gss_OID) gss_nt_service_name, &serverName); } ServiceName = strtok(NULL," "); if (majorStatus != GSS_S_COMPLETE) { Ns_Log(Notice, "mod_SPNEGO - handleKerberosToken_4;GSS_S_COMPLETE - not"); return HTTP_INTERNAL_SERVER_ERROR; } /* Optionally, set environment variable KRB5_KTNAME. */ Krb5KeyTabFile = (const char *)(SPNEGO_CONFIG::getDirConfig())->getKrb5KeyTabFile(); //#ifdef _WINDOWS if (Krb5KeyTabFile) { if(apr_env_set("KRB5_KTNAME", Krb5KeyTabFile ) != APR_SUCCESS) { Ns_Log(Error, "mod_SPNEGO_*******handleKerberosToken unable to set KRB5_KTNAME to %s", Krb5KeyTabFile); } else #ifdef HEIMDAL gsskrb5_register_acceptor_identity(Krb5KeyTabFile); #endif Ns_Log(Notice, "mod_SPNEGO_*******handleKerberosToken set KRB5_KTNAME to %s", Krb5KeyTabFile); ; } //#endif majorStatus = gss_acquire_cred (&minorStatus1, serverName, 0, GSS_C_NULL_OID_SET, GSS_C_ACCEPT, &credential, NULL, NULL); if (serverName != GSS_C_NO_NAME) { Ns_Log(Notice, "mod_SPNEGO - handleKerberosToken_5;GSS_C_NO_NAME - not"); gss_release_name (&minorStatus2, &serverName); serverName = GSS_C_NO_NAME; } Ns_Log(Notice, "mod_SPNEGO - handleKerberosToken_1xx majorStatus_acquire_cred=%u",majorStatus); if (majorStatus != GSS_S_COMPLETE) { // logGssApiError (APLOG_MARK, APLOG_ERR, r, "mod_spnego: gss_acquire_cred failed", majorStatus, minorStatus1); Ns_Log(Notice, "mod_SPNEGO - handleKerberosToken_6;GSS_S_COMPLETE - not"); rc = HTTP_INTERNAL_SERVER_ERROR; continue; } /* Normally, gss_accept_sec_context returns GSS_S_CONTINUE_NEEDED if it needs to be called again. In this context, gss_accept_sec_context should not return GSS_S_CONTINUE_NEEDED. If gss_accept_sec_context returns GSS_S_CONTINUE_NEEDED, the decision to release clientName is based on it's value (GSS_C_NO_NAME or not GSS_C_NO_NAME) and outputToken is delegated to gss_release_buffer -- RFC 2744 is not clear about this case. */ inputToken.value = (unsigned char *) inputKerberosToken; inputToken.length = inputKerberosTokenLength; majorStatus = gss_accept_sec_context (&minorStatus1, &context, credential, &inputToken, GSS_C_NO_CHANNEL_BINDINGS, &clientName, NULL, &outputToken, NULL, NULL, NULL); if (credential != GSS_C_NO_CREDENTIAL) { Ns_Log(Notice, "mod_SPNEGO - handleKerberosToken_7 GSS_C_NO_CREDENTIAL"); gss_release_cred (&minorStatus2, &credential); credential = GSS_C_NO_CREDENTIAL; } if (context != GSS_C_NO_CONTEXT) { Ns_Log(Notice, "mod_SPNEGO - handleKerberosToken_8 GSS_C_NO_CONTEXT"); gss_delete_sec_context (&minorStatus2, &context, GSS_C_NO_BUFFER); context = GSS_C_NO_CONTEXT; } if (majorStatus != GSS_S_COMPLETE) { // logGssApiError (APLOG_MARK, APLOG_ERR, r, "mod_spnego: gss_accept_sec_context failed", majorStatus, minorStatus1); Ns_Log(Notice, "mod_SPNEGO - handleKerberosToken_9 GSS_C_NO_CONTEXT"); rc = HTTP_INTERNAL_SERVER_ERROR; continue; } /* Pass client (or user) name to authorization hook. */ Ns_Log(Notice, "mod_SPNEGO - handleKerberosToken buffe_10r is %s", buffer); majorStatus = gss_display_name (&minorStatus1, clientName, &buffer, NULL); if (majorStatus != GSS_S_COMPLETE) { // logGssApiError (APLOG_MARK, APLOG_ERR, r, "mod_spnego: gss_display_name failed", majorStatus, minorStatus1); rc = HTTP_INTERNAL_SERVER_ERROR; goto cleanup; } /* http://httpd.apache.org/docs/misc/API.html says, "You can also see how some bugs have manifested themself, such as setting connection->user to a value from r->pool -- in this case connection exists for the lifetime of ptrans, which is longer than r->pool (especially if r->pool is a subrequest!). So the correct thing to do is to allocate from connection->pool." Apache 1.3 stores user in connection substructure of request_rec. Apache 2.0 stores user in request_rec. */ // connPtr->authUser = ns_strdup((const char*)buffer.value); *authUser = ns_strdup((const char*)buffer.value); Ns_Log(Notice, "mod_SPNEGO_*******AUTHENTICATED USER IS %s", *authUser); gss_release_buffer (&minorStatus1, &buffer); if (outputToken.length) { *outputKerberosToken = (unsigned char*)ns_malloc (outputToken.length); if (!*outputKerberosToken) { rc = HTTP_INTERNAL_SERVER_ERROR; goto cleanup; } memcpy (*outputKerberosToken, outputToken.value, outputToken.length); *outputKerberosTokenLength = outputToken.length; } rc = APR_SUCCESS;// rc = OK; goto cleanup; } ns_free(serviceBuffer.value); cleanup: if (clientName != GSS_C_NO_NAME) { gss_release_name (&minorStatus1, &clientName); clientName = GSS_C_NO_NAME; } gss_release_buffer (&minorStatus1, &outputToken); return rc; } /* ----------------------------------------------------------------------------- * handleSpnegoToken handles an RFC 2478 SPNEGO GSS-API token. * * If handleSpnegoToken is successful, call free (outputSpnegoToken), where * outputSpnegoToken is of type unsigned char *, to free the memory allocated by * handleSpnegoToken. * * Returns an Apache response code. * ----------------------------------------------------------------------------- */ static int handleSpnegoToken (/*Conn *connPtr,*/ char** authUser, const unsigned char * inputSpnegoToken, size_t inputSpnegoTokenLength, unsigned char ** outputSpnegoToken, size_t * outputSpnegoTokenLength) { /* Patch by Frank Taylor */ int brokenOID = 0; unsigned char * inputKerberosToken = NULL; size_t inputKerberosTokenLength = 0; long negResult; unsigned char * outputKerberosToken = NULL; size_t outputKerberosTokenLength = 0; int rc; errno = 0; #ifdef _DEBUG DebugBreak(); #endif if (!parseSpnegoInitialToken (inputSpnegoToken, inputSpnegoTokenLength, &krb5GssApi, &inputKerberosToken, &inputKerberosTokenLength)) { Ns_Log(Notice, "mod_SPNEGO_**********parseSpnegoInitialToken failed for 1.2.840.113554.1.2.2"); /* The correct mechanism OID does not work, let's just check the broken MS one in case this is an old W2K client. - Frank Taylor */ if (inputKerberosToken) ns_free ((void *)inputKerberosToken); inputKerberosToken = NULL; if (!parseSpnegoInitialToken (inputSpnegoToken, inputSpnegoTokenLength, &msKrb5GssApiLegacy, &inputKerberosToken, &inputKerberosTokenLength)) { Ns_Log(Notice, "mod_SPNEGO_**********parseSpnegoInitialToken failed for 1.2.840.48018.1.2.2"); /* Ideally, handleKerberosToken should be called by authenticateUser, not by handleSpnegoToken. For more information, see comment in authenticateUser. */ rc = handleKerberosToken (authUser, inputSpnegoToken, inputSpnegoTokenLength, outputSpnegoToken, outputSpnegoTokenLength); Ns_Log(Notice, "mod_SPNEGO_********** After -1 calling handleKerberosToken"); if (inputKerberosToken) ns_free ((void *)inputKerberosToken); inputKerberosToken = NULL; return rc; } //AMX: repl by NS_Log ap_log_rerror (APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: parseSpnegoInitialToken succeeded for 1.2.840.48018.1.2.2 -- probably Windows 2000 client"); brokenOID = 1; } Ns_Log(Notice, "mod_SPNEGO_********** before -2 calling handleKerberosToken"); rc = handleKerberosToken (authUser, inputKerberosToken, inputKerberosTokenLength, &outputKerberosToken, &outputKerberosTokenLength); Ns_Log(Notice, "mod_SPNEGO_********** After -2 calling handleKerberosToken outputKerberosToken=%s",&outputKerberosToken); if (inputKerberosToken) free ((void *)inputKerberosToken); negResult = 0; if (!makeSpnegoTargetToken (&negResult, /* Frank Taylor */ (brokenOID ? &msKrb5GssApiLegacy : &krb5GssApi), outputKerberosToken, outputKerberosTokenLength, NULL, 0, outputSpnegoToken, outputSpnegoTokenLength)) { Ns_Log(Notice, "mod_SPNEGO_********** After -3 calling makeSpnegoTargetToken outputSpnegoToken=%s",&outputSpnegoToken); return HTTP_INTERNAL_SERVER_ERROR; } return rc; } /* ----------------------------------------------------------------------------- * authenticateUser authenticates a user (or Apache client). * * Returns an Apache response code. * ----------------------------------------------------------------------------- */ //static int authenticateUser (Conn * conPtr) int authenticateUser (char **authUser, const char *authToken) { static unsigned char ntlmProtocol [] = {'N', 'T', 'L', 'M', 'S', 'S', 'P', 0}; const char * authType = NULL; unsigned char * inputToken = NULL; size_t inputTokenLength = NULL; //sizeof (authToken); //AMX: auth token already decoded in tcl; unsigned char * outputToken = NULL; size_t outputTokenLength = 0; int rc; char * string = NULL; errno = 0; /* Get AuthType. */ authType = SPNEGO_CONFIG::getAuthType(); //getting authType from config params if (!authType || strcasecmp (authType, "SPNEGO")) { //AMX: repl by NS_Log ap_log_rerror (APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: unrecognized AuthType \'%s\'", authType ? authType : "NULL"); return -1;// DECLINED; } //AMX: The request for already authenticatedUser (!!?). So just ret OK /*AMX TEMP if (!(SPNEGO_CONFIG::getServerConfig())->getKrb5AuthEachReq() && connectionUser) { //AMX: repl by NS_Log ap_log_rerror (APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: setting request user to %s", connectionUser); connPtr->authUser = ns_strdup(connectionUser); return APR_SUCCESS; //OK } */ //#endif //This part is done in kn_spnego_filer // authValue = apr_table_get (r->headers_in, "Authorization"); //AMX-TODO: For now we may drop this function assuming that only kn_spengo_filter // is the only caller of autUser func. And the not only authToken (Negotiate + sec_token), // but the token itself is retrieved in tcl and passed as an arg to AuthenticateUser() function //So authValue presumably is not zero if the function was called /* if (!authValue) { //AMX: repl by NS_Log ap_log_rerror (APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: sending 401 and \"WWW-Authenticate: Negotiate\""); apr_table_add (r->err_headers_out, "WWW-Authenticate", "Negotiate"); return HTTP_UNAUTHORIZED; } */ //AMX if (!strncasecmp (string, "Negotiate", 9)) //AMX { //AMX string = ap_getword_white (r->pool, &authValue); //AMX if (!string) //AMX return HTTP_UNAUTHORIZED; //AMX: all decodin is done in kn_spnego_filter by utilizing // the base64::decode library function; SO all this part is gone /************** */ //We already got the Token from tcl - so we don't need the above lines */ // inputTokenLength = base64_decode_len (string); inputTokenLength = base64_decode_len (authToken); inputToken = (unsigned char*)ns_malloc(inputTokenLength); //#endif if (!inputToken) { return HTTP_INTERNAL_SERVER_ERROR; } inputTokenLength = base64_decode ((char *)inputToken, authToken); string = NULL; /* Check if NTLM token. */ Ns_Log(Notice, "MOD_SPNEGO_*****_ authorizeUser(): Client respond to Negotiate challenge with %s auth. mechanism", &inputToken ); if (inputTokenLength >= sizeof ntlmProtocol + 1) if (!memcmp (inputToken, ntlmProtocol, sizeof ntlmProtocol)) { //AMX: repl by NS_Log ap_log_rerror (APLOG_MARK, PORTABLE_APLOG_ERR, r, "mod_spnego: received type %d NTLM token", (int) *(inputToken + sizeof ntlmProtocol)); Ns_Log(Notice, "MOD_SPNEGO_*****_ authorizeUser(): Client respond to Negotiate challenge with %s auth. mechanism", &inputToken ); return HTTP_UNAUTHORIZED; } /* Ideally, authenticateUser should parse RFC 2743 InitialContextTokens, look at mechType element and call handleSpnegoToken or handleKerberosToken. Because d2i_GSSAPI_INITIAL_CONTEXT_TOKEN fails to parse RFC 1964 Kerberos tokens (they contain non-DER token IDs after mechType element), handleSpnegoToken passes input tokens to handleKerberosToken if parseSpnegoInitialToken fails. */ Ns_Log(Notice, "MOD_SPNEGO_*****_ authenticateUser(): Before calling handleSpnegoToken" ); rc = handleSpnegoToken (/*connPtr, */authUser, inputToken, inputTokenLength, &outputToken, &outputTokenLength); Ns_Log(Notice, "MOD_SPNEGO_*****_ authenticateUser(): After calling handleSpnegoToken" ); int len = base64_encode_len ((int) outputTokenLength); string = ( char *)ns_malloc(size_t(len)); if (!string) { //AMX: repl by NS_Log ap_log_rerror (APLOG_MARK, PORTABLE_APLOG_ERR, r, "mod_spnego: apr_pcalloc failed"); if (outputToken) ns_free (outputToken); return HTTP_INTERNAL_SERVER_ERROR; } Ns_Log(Notice, "MOD_SPNEGO_*****_ authenticateUser(): outputToken = %s", outputToken ); base64_encode (string, (const char*)outputToken, (int) outputTokenLength); if (outputToken) ns_free (outputToken); /* Does apr_table_set copy string? */ //AMX: Is this mistake ? shoulddn't we see the the returning of 200 OK msg /*AMX FIND OUT WHY WE SHOULD PUT IN HEADERS apr_table_set (r->err_headers_out, "WWW-Authenticate", apr_pstrcat (r->pool, "Negotiate ", string, NULL)); //AMX: repl by NS_Log ap_log_rerror (APLOG_MARK, PORTABLE_APLOG_INFO, r, "mod_spnego: authenticateUser returning %d", rc); */ if(string) ns_free(string); return rc; } /* ----------------------------------------------------------------------------- * logGssApiError writes GSS-API messages to Apache's error log. * * Returns nothing. * ----------------------------------------------------------------------------- */ /* static void logGssApiError (const char * file, int line, int level, const request_rec * r, char * s, OM_uint32 maj_stat, OM_uint32 min_stat) { OM_uint32 gmaj_stat; OM_uint32 gmin_stat; gss_buffer_desc msg; OM_uint32 msg_ctx = 0; while (!msg_ctx) { gmaj_stat = gss_display_status (&gmin_stat, maj_stat, GSS_C_GSS_CODE, GSS_C_NULL_OID, &msg_ctx, &msg); if (gmaj_stat == GSS_S_COMPLETE) { #ifdef APACHE13 //AMX: repl by NS_Log ap_log_rerror (file, line, level, r, "%s; GSS-API: %s)", s, (char *) msg.value); #else //AMX: repl by NS_Log ap_log_rerror (file, line, level, 0, r, "%s; GSS-API: %s)", s, (char *) msg.value); #endif gss_release_buffer (&gmin_stat, &msg); break; } gss_release_buffer (&gmin_stat, &msg); } msg_ctx = 0; while (!msg_ctx) { gmaj_stat = gss_display_status (&gmin_stat, min_stat, GSS_C_MECH_CODE, GSS_C_NULL_OID, &msg_ctx, &msg); if (gmaj_stat == GSS_S_COMPLETE) { #ifdef APACHE13 //AMX: repl by NS_Log ap_log_rerror (file, line, level, r, "%s; GSS-API mechanism: %s)", s, (char *) msg.value); #else //AMX: repl by NS_Log ap_log_rerror (file, line, level, 0, r, "%s; GSS-API mechanism: %s)", s, (char *) msg.value); #endif Ns_Log(Notice, "%s: Loaded private key file: %s", hModule, privatekeyfile); gss_release_buffer (&gmin_stat, &msg); break; } gss_release_buffer (&gmin_stat, &msg); } } */ /* ----------------------------------------------------------------------------- * handlePoolCleanup handles pool cleanup. * * Is registered by calling apr_pool_cleanup_register. Is called by Apache. * * Returns an Apache status code. * ----------------------------------------------------------------------------- */ /* #ifndef APACHE13 static apr_status_t handlePoolCleanup (void * data) { connectionUser = NULL; return APR_SUCCESS; } #endif */ /* ----------------------------------------------------------------------------- * handleKerberosToken handles an RFC 1964 Kerberos GSS-API token. * * Returns an Apache response code. * ----------------------------------------------------------------------------- */ --- NEW FILE: unix-env.cpp --- /* unix-env.c */ /* Frank Balluffi modified the following code from Apache 2.0. */ /* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2000-2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact ap...@ap.... * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ //#ifdef APACHE13 // #include "httpd.h" //#define APR_DECLARE(rc) rc //#define APR_ENOMEM 1 //#define APR_ENOTIMPL 1 //#define APR_SUCCESS 0 //#define apr_palloc ap_palloc //#define apr_pool_t pool #ifndef _WINDOWS #define HAVE_SETENV typedef int apr_status_t; //typedef size_t apr_size_t; //APR_DECLARE(apr_status_t) apr_env_set(const char *envvar, // const char *value//, // /*apr_pool_t *pool*/) #include "spnegoconfig.h" int apr_env_set(const char *envvar, const char *value) { #if defined(HAVE_SETENV) if (0 > setenv(envvar, value, 1)) return 1; // APR_ENOMEM; return 0; //APR_SUCCESS; #elif defined(HAVE_PUTENV) apr_size_t elen = strlen(envvar); apr_size_t vlen = strlen(value); char *env = apr_palloc(pool, elen + vlen + 2); char *p = env + elen; memcpy(env, envvar, elen); *p++ = '='; memcpy(p, value, vlen); p[vlen] = '\0'; if (0 > putenv(env)) return APR_ENOMEM; return APR_SUCCESS; #else return APR_ENOTIMPL; #endif } #endif --- NEW FILE: win32-env.cpp --- /* win32-env.c */ /* Frank Balluffi modified the following code from Apache 2.0. */ /* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2000-2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact ap...@ap.... * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ //#include "httpd.h" /* For now, force apr_env_set to call call SetEnvironmentVariableA. */ #ifdef _WINDOWS #include "spnegoconfig.h" #define ELSE_WIN_OS_IS_ANSI #define IF_WIN_OS_IS_UNICODE int apr_env_set(const char *envvar, const char *value /*, pool *pool */) { #if APR_HAS_UNICODE_FS IF_WIN_OS_IS_UNICODE { apr_wchar_t wenvvar[APR_PATH_MAX]; apr_wchar_t *wvalue; apr_size_t inchars, outchars; apr_status_t status; status = widen_envvar_name(wenvvar, APR_PATH_MAX, envvar); if (status) return status; outchars = inchars = strlen(value) + 1; wvalue = apr_palloc(pool, outchars * sizeof(*wvalue)); status = apr_conv_utf8_to_ucs2(value, &inchars, wvalue, &outchars); if (status) return status; if (!SetEnvironmentVariableW(wenvvar, wvalue)) return apr_get_os_error(); } #endif #if APR_HAS_ANSI_FS ELSE_WIN_OS_IS_ANSI { /* If SetEnvironmentVariableA fails, return 1 -- do not call apr_get_os_error. */ if (!SetEnvironmentVariableA(envvar, value)) /* return apr_get_os_error(); */ return 1; } #endif return APR_SUCCESS; } #endif |