📄 mod_cas.c
字号:
int i; LOG("processing randomness...\n"); close(fd); buf[buflen - 1] = '\0'; /* now, take each byte and convert it to a readable one */ for (i = 0; i < buflen - 1; i++) buf[i] = pool[ buf[i] % strlen(pool) ]; LOG("got random ticket: "); LOG(buf); LOG("\n"); return 1; } } else { int i; LOG("using EGD\n"); /** Draw entropy from the EGD if necessary. */ if (!RAND_status()) RAND_egd(egdfile); /** Now, use OpenSSL to produce random bytes. */ RAND_pseudo_bytes(buf, buflen -1); buf[buflen - 1] = '\0'; /* Convert each byte to a readable character. */ for (i = 0; i < buflen - 1; i++) buf[i] = pool[ buf[i] % strlen(pool) ]; return 1; }}/* * Sets a cookie corresponding to a particular ticket in the given * request's response headers. Uses the given configuration record * to determine whether the ticket can be sent back to non-SSL URLs. */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 = ap_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"); ap_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 ap_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' ap_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 ap_pstrdup(r->pool, msg_buf);}/* * A support function for get_netid_from_cookies, used by ap_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 ap_table_do } return 1; // continue process in ap_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->connection->user); if (random_ticket(t.ticket, sizeof(t.ticket), c->CASEGDFile)) { 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, pool *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 (!(g = getgrgid(u->pw_gid))) return 0; if (!strcmp(g->gr_name, group)) return 1; else return 0;}/* For debugging... */static void log(const char *msg) { static FILE *fp; if (!fp) fp = fopen("/tmp/log", "a"); fputs(msg, fp); fflush(fp);}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);}/* Table of supported configuration directives */static const command_rec cas_directives[] = { { "CASLocalCacheFile", /* name */ read_CASLocalCacheFile, /* handler */ NULL, /* handler's argument */ RSRC_CONF, /* availability */ TAKE1, /* directive arguments */ "Path to local cache in support of mod_cas" /* description */ }, { "CASLocalCacheSize", /* name */ read_CASLocalCacheSize, /* handler */ NULL, /* handler's argument */ RSRC_CONF, /* availability */ TAKE1, /* directive arguments */ "Size of local cache in support of mod_cas" /* description */ }, { "CASLocalCacheTimeout", /* name */ read_CASLocalCacheTimeout, /* handler */ NULL, /* handler's argument */ RSRC_CONF, /* availability */ TAKE1, /* directive arguments */ "Cookie usefulness timeout in local cache in support of mod_cas" /* description */ }, { "CASLocalCacheInsecure", /* name */ read_CASLocalCacheInsecure, /* handler */ NULL, /* handler's argument */ RSRC_CONF, /* availability */ FLAG, /* directive arguments */ "Cookie restriction for local cache in support of mod_cas" /* description */ }, { "CASEGDFile", /* name */ read_CASEGDFile, /* handler */ NULL, /* handler's argument */ RSRC_CONF, /* availability */ TAKE1, /* directive arguments */ "If specified, use EGD based on given file; " "otherwise, use /dev/urandom" /* description */ }, {NULL}};/* Our actual module structure */module MODULE_VAR_EXPORT cas_module ={ STANDARD_MODULE_STUFF, NULL, /* init */ NULL, /* create per-dir config */ NULL, /* merge per-dir config */ init_server_config, /* create server config */ NULL, /* merge server config */ cas_directives, /* command table */ NULL, /* handler table */ NULL, /* translation */ do_cas, /* check/set authenticated user */ authorize, /* decide whether user is authorized */ NULL, /* access control by arbitrary criteria */ NULL, /* type checker */ NULL, /* "fixup" */ NULL, /* log handler */#if MODULE_MAGIC_NUMBER >= 19970103 NULL, /* header parser */#endif#if MODULE_MAGIC_NUMBER >= 19970719 init_child, /* per-process initializer */#endif#if MODULE_MAGIC_NUMBER >= 19970728 cleanup_child, /* per-process exit/cleanup */#endif#if MODULE_MAGIC_NUMBER >= 19970902 NULL, /* post read_request handler */#endif};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -