📄 auth_negotiate.c
字号:
/* * $Id: auth_negotiate.c,v 1.5 2006/07/30 23:27:04 hno Exp $ * * DEBUG: section 29 Negotiate Authenticator * AUTHOR: Robert Collins * * SQUID Web Proxy Cache http://www.squid-cache.org/ * ---------------------------------------------------------- * * Squid is the result of efforts by numerous individuals from * the Internet community; see the CONTRIBUTORS file for full * details. Many organizations have provided support for Squid's * development; see the SPONSORS file for full details. Squid is * Copyrighted (C) 2001 by the Regents of the University of * California; see the COPYRIGHT file for full details. Squid * incorporates software developed and/or copyrighted by other * sources; see the CREDITS file for full details. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * *//* The functions in this file handle authentication. * They DO NOT perform access control or auditing. * See acl.c for access control and client_side.c for auditing */#include "squid.h"#include "auth_negotiate.h"extern AUTHSSETUP authSchemeSetup_negotiate;static voidauthenticateStateFree(authenticateStateData * r){ authenticateAuthUserRequestUnlock(r->auth_user_request); r->auth_user_request = NULL; cbdataFree(r);}/* Negotiate Scheme */static HLPSCB authenticateNegotiateHandleReply;static AUTHSACTIVE authenticateNegotiateActive;static AUTHSAUTHED authNegotiateAuthenticated;static AUTHSAUTHUSER authenticateNegotiateAuthenticateUser;static AUTHSCONFIGURED authNegotiateConfigured;static AUTHSFIXERR authenticateNegotiateFixErrorHeader;static AUTHSADDHEADER authNegotiateAddHeader;static AUTHSFREE authenticateNegotiateFreeUser;static AUTHSDIRECTION authenticateNegotiateDirection;static AUTHSDECODE authenticateDecodeNegotiateAuth;static AUTHSDUMP authNegotiateCfgDump;static AUTHSFREECONFIG authNegotiateFreeConfig;static AUTHSINIT authNegotiateInit;static AUTHSONCLOSEC authenticateNegotiateOnCloseConnection;static AUTHSUSERNAME authenticateNegotiateUsername;static AUTHSREQFREE authNegotiateAURequestFree;static AUTHSPARSE authNegotiateParse;static AUTHSCHECKCONFIG authNegotiateCheckConfig;static AUTHSSTART authenticateNegotiateStart;static AUTHSSTATS authenticateNegotiateStats;static AUTHSSHUTDOWN authNegotiateDone;static statefulhelper *negotiateauthenticators = NULL;CBDATA_TYPE(authenticateStateData);static int authnegotiate_initialised = 0;static MemPool *negotiate_user_pool = NULL;static MemPool *negotiate_request_pool = NULL;static auth_negotiate_config *negotiateConfig = NULL;static void authenticateNegotiateReleaseServer(negotiate_request_t * negotiate_request);/* * * Private Functions * */static voidauthNegotiateDone(void){ debug(29, 2) ("authNegotiateDone: shutting down Negotiate authentication.\n"); if (negotiateauthenticators) helperStatefulShutdown(negotiateauthenticators); authnegotiate_initialised = 0; if (!shutting_down) return; if (negotiateauthenticators) helperStatefulFree(negotiateauthenticators); negotiateauthenticators = NULL; if (negotiate_request_pool) { assert(memPoolInUseCount(negotiate_request_pool) == 0); memPoolDestroy(negotiate_request_pool); negotiate_request_pool = NULL; } if (negotiate_user_pool) { assert(memPoolInUseCount(negotiate_user_pool) == 0); memPoolDestroy(negotiate_user_pool); negotiate_user_pool = NULL; } debug(29, 2) ("authNegotiateDone: Negotiate authentication Shutdown.\n");}/* free any allocated configuration details */static voidauthNegotiateFreeConfig(authScheme * scheme){ if (negotiateConfig == NULL) return; assert(negotiateConfig == scheme->scheme_data); if (negotiateConfig->authenticate) wordlistDestroy(&negotiateConfig->authenticate); safe_free(negotiateConfig); scheme->scheme_data = NULL;}static voidauthNegotiateCfgDump(StoreEntry * entry, const char *name, authScheme * scheme){ auth_negotiate_config *config = scheme->scheme_data; wordlist *list = config->authenticate; storeAppendPrintf(entry, "%s %s program", name, "negotiate"); while (list != NULL) { storeAppendPrintf(entry, " %s", list->key); list = list->next; } storeAppendPrintf(entry, "\n"); storeAppendPrintf(entry, "%s %s children %d\n", name, "negotiate", config->authenticateChildren); storeAppendPrintf(entry, "%s %s keep_alive %s\n", name, "negotiate", config->keep_alive ? "on" : "off");}static voidauthNegotiateParse(authScheme * scheme, int n_configured, char *param_str){ if (scheme->scheme_data == NULL) { assert(negotiateConfig == NULL); /* this is the first param to be found */ scheme->scheme_data = xmalloc(sizeof(auth_negotiate_config)); memset(scheme->scheme_data, 0, sizeof(auth_negotiate_config)); negotiateConfig = scheme->scheme_data; negotiateConfig->authenticateChildren = 5; negotiateConfig->keep_alive = 1; } negotiateConfig = scheme->scheme_data; if (strcasecmp(param_str, "program") == 0) { if (negotiateConfig->authenticate) wordlistDestroy(&negotiateConfig->authenticate); parse_wordlist(&negotiateConfig->authenticate); } else if (strcasecmp(param_str, "children") == 0) { parse_int(&negotiateConfig->authenticateChildren); } else if (strcasecmp(param_str, "keep_alive") == 0) { parse_onoff(&negotiateConfig->keep_alive); } else { debug(29, 0) ("unrecognised negotiate auth scheme parameter '%s'\n", param_str); }}static voidauthNegotiateCheckConfig(authScheme * scheme){ auth_negotiate_config *config = scheme->scheme_data; requirePathnameExists("authparam negotiate program", config->authenticate->key);}voidauthSchemeSetup_negotiate(authscheme_entry_t * authscheme){ assert(!authnegotiate_initialised); authscheme->Active = authenticateNegotiateActive; authscheme->configured = authNegotiateConfigured; authscheme->parse = authNegotiateParse; authscheme->checkconfig = authNegotiateCheckConfig; authscheme->dump = authNegotiateCfgDump; authscheme->requestFree = authNegotiateAURequestFree; authscheme->freeconfig = authNegotiateFreeConfig; authscheme->init = authNegotiateInit; authscheme->authAuthenticate = authenticateNegotiateAuthenticateUser; authscheme->authenticated = authNegotiateAuthenticated; authscheme->authFixHeader = authenticateNegotiateFixErrorHeader; authscheme->AddHeader = authNegotiateAddHeader; authscheme->FreeUser = authenticateNegotiateFreeUser; authscheme->authStart = authenticateNegotiateStart; authscheme->authStats = authenticateNegotiateStats; authscheme->authUserUsername = authenticateNegotiateUsername; authscheme->getdirection = authenticateNegotiateDirection; authscheme->decodeauth = authenticateDecodeNegotiateAuth; authscheme->donefunc = authNegotiateDone; authscheme->oncloseconnection = authenticateNegotiateOnCloseConnection;}/* Initialize helpers and the like for this auth scheme. Called AFTER parsing the * config file */static voidauthNegotiateInit(authScheme * scheme){ static int negotiateinit = 0; if (negotiateConfig->authenticate) { /* * disable client side request pipelining. There is a race with * Negotiate when the client sends a second request on an Negotiate * connection before the authenticate challenge is sent. With * this patch, the client may fail to authenticate, but squid's * state will be preserved. Caveats: this should be a post-parse * test, but that can wait for the modular parser to be integrated. */ if (negotiateConfig->authenticate && Config.onoff.pipeline_prefetch != 0) { debug(29, 1) ("pipeline prefetching incompatile with Negotiate authentication. Disabling pipeline_prefetch\n"); Config.onoff.pipeline_prefetch = 0; } if (!negotiate_user_pool) negotiate_user_pool = memPoolCreate("Negotiate Scheme User Data", sizeof(negotiate_user_t)); if (!negotiate_request_pool) negotiate_request_pool = memPoolCreate("Negotiate Scheme Request Data", sizeof(negotiate_request_t)); authnegotiate_initialised = 1; if (negotiateauthenticators == NULL) negotiateauthenticators = helperStatefulCreate("negotiateauthenticator"); negotiateauthenticators->cmdline = negotiateConfig->authenticate; negotiateauthenticators->n_to_start = negotiateConfig->authenticateChildren; negotiateauthenticators->ipc_type = IPC_STREAM; helperStatefulOpenServers(negotiateauthenticators); if (!negotiateinit) { cachemgrRegister("negotiateauthenticator", "Negotiate User Authenticator Stats", authenticateNegotiateStats, 0, 1); negotiateinit++; } CBDATA_INIT_TYPE(authenticateStateData); }}static intauthenticateNegotiateActive(){ return (authnegotiate_initialised == 1) ? 1 : 0;}static intauthNegotiateConfigured(){ if (negotiateConfig == NULL) { debug(29, 9) ("authNegotiateConfigured: not configured\n"); return 0; } if (negotiateConfig->authenticate == NULL) { debug(29, 9) ("authNegotiateConfigured: no helper\n"); return 0; } if (negotiateConfig->authenticateChildren == 0) { debug(29, 9) ("authNegotiateConfigured: no helper children\n"); return 0; } debug(29, 9) ("authNegotiateConfigured: returning configured\n"); return 1;}/* Negotiate Scheme */static intauthenticateNegotiateDirection(auth_user_request_t * auth_user_request){ negotiate_request_t *negotiate_request = auth_user_request->scheme_data; /* null auth_user is checked for by authenticateDirection */ if (negotiate_request->waiting || negotiate_request->client_blob) return -1; /* Need helper response to continue */ switch (negotiate_request->auth_state) { case AUTHENTICATE_STATE_NONE: /* no progress at all. */ debug(29, 1) ("authenticateNegotiateDirection: called before Negotiate Authenticate!. Report a bug to squid-dev. au %p\n", auth_user_request); return -2; case AUTHENTICATE_STATE_NEGOTIATE: /* send to client */ assert(negotiate_request->server_blob); return 1; case AUTHENTICATE_STATE_FAILED: return -2; case AUTHENTICATE_STATE_FINISHED: /* do nothing.. */ case AUTHENTICATE_STATE_DONE: /* do nothing.. */ return 0; case AUTHENTICATE_STATE_INITIAL: debug(29, 1) ("authenticateNegotiateDirection: Unexpected AUTHENTICATE_STATE_INITIAL\n"); return -2; } return -2;}/* * Send the authenticate error header(s). Note: IE has a bug and the Negotiate header * must be first. To ensure that, the configure use --enable-auth=negotiate, anything * else. */static voidauthenticateNegotiateFixErrorHeader(auth_user_request_t * auth_user_request, HttpReply * rep, http_hdr_type type, request_t * request){ negotiate_request_t *negotiate_request; if (!request->flags.proxy_keepalive) return; if (!negotiateConfig->authenticate) return; /* New request, no user details */ if (auth_user_request == NULL) { debug(29, 9) ("authenticateNegotiateFixErrorHeader: Sending type:%d header: 'Negotiate'\n", type); httpHeaderPutStrf(&rep->header, type, "Negotiate"); if (!negotiateConfig->keep_alive) { /* drop the connection */ httpHeaderDelByName(&rep->header, "keep-alive"); request->flags.proxy_keepalive = 0; } return; } negotiate_request = auth_user_request->scheme_data; switch (negotiate_request->auth_state) { case AUTHENTICATE_STATE_NONE: case AUTHENTICATE_STATE_FAILED: debug(29, 9) ("authenticateNegotiateFixErrorHeader: Sending type:%d header: 'Negotiate'\n", type); httpHeaderPutStrf(&rep->header, type, "Negotiate"); /* drop the connection */ httpHeaderDelByName(&rep->header, "keep-alive"); request->flags.proxy_keepalive = 0; break; case AUTHENTICATE_STATE_NEGOTIATE: /* we are 'waiting' for a response from the client */ /* pass the blob to the client */ debug(29, 9) ("authenticateNegotiateFixErrorHeader: Sending type:%d header: 'Negotiate %s'\n", type, negotiate_request->server_blob); httpHeaderPutStrf(&rep->header, type, "Negotiate %s", negotiate_request->server_blob); safe_free(negotiate_request->server_blob); request->flags.must_keepalive = 1; break; case AUTHENTICATE_STATE_FINISHED: /* Special case when authentication finished, but not allowed by ACL */ if (negotiate_request->server_blob) { debug(29, 9) ("authenticateNegotiateFixErrorHeader: Sending type:%d header: 'Negotiate %s'\n", type, negotiate_request->server_blob); httpHeaderPutStrf(&rep->header, type, "Negotiate %s", negotiate_request->server_blob); safe_free(negotiate_request->server_blob); } else { debug(29, 9) ("authenticateNegotiateFixErrorHeader: Connection authenticated\n"); } break; default: debug(29, 0) ("authenticateNegotiateFixErrorHeader: state %d.\n", negotiate_request->auth_state); fatal("unexpected state in AuthenticateNegotiateFixErrorHeader.\n"); }}/* add the [proxy]authorisation header */static voidauthNegotiateAddHeader(auth_user_request_t * auth_user_request, HttpReply * rep, int accel){ int type; negotiate_request_t *negotiate_request; if (!auth_user_request) return; negotiate_request = auth_user_request->scheme_data; if (!negotiate_request->server_blob) return; type = accel ? HDR_WWW_AUTHENTICATE : HDR_PROXY_AUTHENTICATE; debug(29, 9) ("authenticateNegotiateFixErrorHeader: Sending type:%d header: 'Negotiate %s'\n", type, negotiate_request->server_blob); httpHeaderPutStrf(&rep->header, type, "Negotiate %s", negotiate_request->server_blob); safe_free(negotiate_request->server_blob);}static voidauthNegotiateRequestFree(negotiate_request_t * negotiate_request){ if (!negotiate_request) return; safe_free(negotiate_request->server_blob); safe_free(negotiate_request->client_blob); if (negotiate_request->authserver != NULL) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -