📄 mod_cas.c
字号:
*/static void send_cookie(char *ticket, request_rec *r) { mod_cas_conf *c = (mod_cas_conf *) ap_get_module_config( r->server->module_config, &cas_module); char *cookie = apr_pstrcat(r->pool, (c->CASLocalCacheInsecure ? COOKIENAME : COOKIENAME_SECURE), "=", ticket, (c->CASLocalCacheInsecure ? "" : ";Secure"), ";Path=", COOKIEPATH, NULL); LOG("in send_cookie()\n"); LOG("-> sending cookie '"); LOG(cookie); LOG("'\n"); apr_table_add(r->headers_out, "Set-Cookie", cookie);}/* * Walks through the given request's headers, reading all cookies that * can correspond to tickets and checking them against our ticket cache. * If a valid NetID is found, we stop immediately and return it; * otherwise, if no valid NetID is ever found, we return NULL. */static char *get_netid_from_cookies(request_rec *r) { // msg_buf is used as a two-way message buffer between apr_table_do // and the function we have it call here. // as input to check_individual_cookie: // -- its first byte is our config's value of CASLocalCacheInsecure // as output from check_individual_cookie: // -- it stores a NUL-terminated string representing the found // NetID, or is equivalent to "" if no NetID was found. char msg_buf[USERBUFSIZE]; mod_cas_conf *c; c = (mod_cas_conf *) ap_get_module_config( r->server->module_config, &cas_module); msg_buf[0] = c->CASLocalCacheInsecure; // initialize input msg_buf[1] = '\0'; // fail trivially if there's no ticket cache if (!ticket_cache) return NULL; // the following call ends up with a valid netid or NULL in 'preauth_netid' apr_table_do( (int (*)()) check_individual_cookie, msg_buf, r->headers_in, "Cookie", NULL); if (msg_buf[0] == c->CASLocalCacheInsecure && msg_buf[1] == '\0') // the buffer is unchanged, meaning nobody wrote a NetID to it return NULL; else return apr_pstrdup(r->pool, msg_buf);}/* * A support function for get_netid_from_cookies, used by apr_table_do * to handle individual cookies. (There may be multiple "Cookie" headers * in the request that we receive, so we can't just use ap_table_get.) */static int check_individual_cookie(void *msg_buf, char *key, char *value) { char *ticket, *p; char netid_buf[USERBUFSIZE]; LOG("in check_individual_cookie()\n"); // we're looking for whatever's between COOKIENAME= and ';' // (or the end), ignoring optional quotation marks at the beginning or // the end ticket = alloca(strlen(value) + 1); strcpy(ticket, value); // msg_buf[0] stores our "insecure" status if (*((char *) msg_buf)) { ticket = strstr(ticket, COOKIENAME "="); // find key if (!ticket) return 1; ticket += strlen(COOKIENAME "="); // skip key and '=' } else { ticket = strstr(ticket, COOKIENAME_SECURE "="); // find key if (!ticket) return 1; ticket += strlen(COOKIENAME_SECURE "="); // skip key and '=' } if (*ticket == '"') ticket++; // if it starts with '"', skip '"' p = strchr(ticket, ';'); if (p) *p = '\0'; // end the string at ';' if it's there p = ticket + strlen(ticket); if (*p == '"') *p = '\0'; // if we ended with '"', delete it // now, we have the ticket from the cookie. // let's see what it buys us. // (msg_buf[0] stores our current CASLocalCacheInsecure status) if (cache_get(ticket, netid_buf, sizeof(netid_buf), *((char *) msg_buf))) { // copy the netid back out // the 'msg_buf' parameter is a char[] of size USERBUFSIZE, // so it can just take the NetID we found, byte for byte strcpy((char *) msg_buf, netid_buf); LOG("-> check_individual_cookie succeeded; found "); LOG(netid_buf); LOG("\n"); return 0; // stop processing in apr_table_do } return 1; // continue process in apr_table_do}static void logout(request_rec *r) { char *ticket; LOG("in logout()\n"); // if there's no ticket cache, there's nothing to do if(!ticket_cache) { LOG("-> no ticket cache... don't need to logout\n"); return; } ticket = get_ticket_from_cookies(r); cache_invalidate(ticket); return;} static char *get_ticket_from_cookies(request_rec *r) { // msg_buf is used as a two-way message buffer between apr_table_do // and the function we have it call here. // as input to check_individual_cookie: // -- its first byte is our config's value of CASLocalCacheInsecure // as output from check_individual_cookie: // -- it stores a NUL-terminated string representing the found // NetID, or is equivalent to "" if no NetID was found. char msg_buf[TICKETBUFSIZE]; mod_cas_conf *c; c = (mod_cas_conf *) ap_get_module_config( r->server->module_config, &cas_module); msg_buf[0] = c->CASLocalCacheInsecure; // initialize input msg_buf[1] = '\0'; // fail trivially if there's no ticket cache if (!ticket_cache) return NULL; // the following call ends up with a valid netid or NULL in 'preauth_netid' apr_table_do( (int (*)()) check_individual_cookie_for_ticket, msg_buf, r->headers_in, "Cookie", NULL); if (msg_buf[0] == c->CASLocalCacheInsecure && msg_buf[1] == '\0') // the buffer is unchanged, meaning nobody wrote a ticket to it return NULL; else return apr_pstrdup(r->pool, msg_buf);}/* * A support function for get_netid_from_cookies, used by apr_table_do * to handle individual cookies. (There may be multiple "Cookie" headers * in the request that we receive, so we can't just use ap_table_get.) */static int check_individual_cookie_for_ticket(void *msg_buf, char *key, char *value) { char *ticket, *p; LOG("in check_individual_cookie_for_ticket()\n"); // we're looking for whatever's between COOKIENAME= and ';' // (or the end), ignoring optional quotation marks at the beginning or // the end ticket = alloca(strlen(value) + 1); strcpy(ticket, value); // msg_buf[0] stores our "insecure" status if (*((char *) msg_buf)) { ticket = strstr(ticket, COOKIENAME "="); // find key if (!ticket) return 1; ticket += strlen(COOKIENAME "="); // skip key and '=' } else { ticket = strstr(ticket, COOKIENAME_SECURE "="); // find key if (!ticket) return 1; ticket += strlen(COOKIENAME_SECURE "="); // skip key and '=' } if (*ticket == '"') ticket++; // if it starts with '"', skip '"' p = strchr(ticket, ';'); if (p) *p = '\0'; // end the string at ';' if it's there p = ticket + strlen(ticket); if (*p == '"') *p = '\0'; // if we ended with '"', delete it strcpy((char *) msg_buf, ticket); LOG("-> check_individual_cookie_for_ticket succeeded; found "); LOG(ticket); LOG("\n"); return 0; // stop processing in apr_table_do}/* * Creates and sends a cookie holding a new ticket, which we add to * the ticket cache under the appropriate NetID. */static void create_and_send_new_ticket(request_rec *r) { mod_cas_conf *c; TicketEntry t; LOG("in create_and_send_new_ticket()\n"); c = (mod_cas_conf *) ap_get_module_config( r->server->module_config, &cas_module); // don't do anything if we're not supposed to have a ticket cache, // or if the ticket cache doesn't exist if (!c->CASLocalCacheFile || !ticket_cache) return; // set up the TicketEntry t.valid = 1; t.secure = !(c->CASLocalCacheInsecure); strcpy(t.netid, r->user); if (random_ticket(t.ticket, sizeof(t.ticket), c->CASEGDFile)) { LOG("random_ticket successful: ticket = "); LOG(t.ticket); LOG("\n"); t.expiration = time(NULL) + c->CASLocalCacheTimeout; cache_put(t); send_cookie(t.ticket, r); }}/* Returns 1 if 'user' is in 'group', 0 otherwise. */static int is_user_in_group(const char *user, const char *group, apr_pool_t *p) { // TODO: cache here for performance? (it's cleaner to cache in nscd) char *gn; char **t; struct group *g; struct passwd *u; // this isn't thread-safe, but the current APR doesn't support generalized // access to getgrnam() or getpwnam() if (!(g = getgrnam(group))) return 0; for (t = g->gr_mem; t && *t; t++) { LOG("checking "); LOG(user); LOG(" against"); LOG(*t); LOG("\n"); if (!strcmp(*t, user)) return 1; } if (!(u = getpwnam(user))) return 0; if (apr_group_name_get(&gn, u->pw_gid, p) != APR_SUCCESS) return 0; if (!strcmp(gn, group)) return 1; else return 0;}static void write_lock(int fd) { /* prepare for writelock on (or unlock of) entire file */ struct flock lock; lock.l_type = F_WRLCK; lock.l_whence = 0; lock.l_start = 0L; lock.l_len = 0L; /* block until we can get a shared lock */ fcntl(fd, F_SETLKW, &lock);}static void read_lock(int fd) { /* prepare for writelock on (or unlock of) entire file */ struct flock lock; lock.l_type = F_RDLCK; lock.l_whence = 0; lock.l_start = 0L; lock.l_len = 0L; /* block until we can get a shared lock */ fcntl(fd, F_SETLKW, &lock);}static void un_lock(int fd) { /* prepare for writelock on (or unlock of) entire file */ struct flock lock; lock.l_type = F_UNLCK; lock.l_whence = 0; lock.l_start = 0L; lock.l_len = 0L; /* block until we can get a shared lock */ fcntl(fd, F_SETLKW, &lock);}/* For debugging... */static void log(const char *msg) { static FILE *fp; if (!fp) fp = fopen("/tmp/log", "a"); fputs(msg, fp); fflush(fp);}/* Table of supported configuration directives */static const command_rec cas_directives[] = { AP_INIT_TAKE1( "CASLocalCacheFile", /* name */ read_CASLocalCacheFile, /* handler */ NULL, /* handler's argument */ RSRC_CONF, /* availability */ "Path to local cache in support of mod_cas" /* description */ ), AP_INIT_TAKE1( "CASLogoutParameter", /* name */ read_CASLogoutParameter, /* handler */ NULL, /* handler's argument */ RSRC_CONF, /* availability */ "GET parameter used to indicate logout is desired" /* description */ ), AP_INIT_TAKE1( "CASLogoutLocalURL", /* name */ read_CASLogoutLocalURL, /* handler */ NULL, /* handler's argument */ RSRC_CONF, /* availability */ "Local URL to redirect to after logout is performed" /* description */ ), AP_INIT_TAKE1( "CASEGDFile", /* name */ read_CASEGDFile, /* handler */ NULL, /* handler's argument */ RSRC_CONF, /* availability */ "If specified, use EGD based on given file; " "otherwise, use /dev/urandom" /* description */ ), AP_INIT_TAKE1( "CASLocalCacheSize", /* name */ read_CASLocalCacheSize, /* handler */ NULL, /* handler's argument */ RSRC_CONF, /* availability */ "Size of local cache in support of mod_cas" /* description */ ), AP_INIT_TAKE1( "CASLocalCacheTimeout", /* name */ read_CASLocalCacheTimeout, /* handler */ NULL, /* handler's argument */ RSRC_CONF, /* availability */ "Cookie usefulness timeout in local cache in support of mod_cas" /* description */ ), AP_INIT_FLAG( "CASLocalCacheInsecure", /* name */ read_CASLocalCacheInsecure, /* handler */ NULL, /* handler's argument */ RSRC_CONF, /* availability */ "Cookie restriction for local cache in support of mod_cas" /* description */ ), {NULL}};/* Apache 2.0-style hook registration */static void cas_register_hooks(apr_pool_t *p) { ap_hook_check_user_id(do_cas, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_auth_checker(authorize, NULL, NULL, APR_HOOK_MIDDLE); ap_hook_child_init(init_child, NULL, NULL, APR_HOOK_MIDDLE);}/* Our actual module structure */module AP_MODULE_DECLARE_DATA cas_module ={ STANDARD20_MODULE_STUFF, /* header */ NULL, /* per-directory init */ NULL, /* per-directory merge */ init_server_config, /* per-server init */ NULL, /* per-server merge */ cas_directives, /* command handler */ cas_register_hooks /* hook registration */};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -