⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mod_cas.c

📁 cas 客户端文件
💻 C
📖 第 1 页 / 共 3 页
字号:
 * intersection.  For instance, "Require user bayern; Require group foo" * means "let anyone if if they're either user bayern or in group foo."   * All user authentication proceeds through CAS; group authentication maps * a CAS-authenticated username against the machine's local groups. * (In the future, this could change to support a more generalized * framework for group discovery.) * * Operates only if the AuthType is CAS, returning DECLINED otherwise on * the chance that another module will validate the request if we can't. * On success, we return OK, which solves the "authorization" question * for the entire request -- on OK, other modules should not be called. * If the AuthType is CAS, though, and the user isn't authorized as far * as we're concerned, we're going to take the initiative and return * HTTP_FORBIDDEN directly (rather than just DECLINED; that is, we're * not going to give any other module a chance to authorize anyone if the * AuthType is CAS).  We return HTTP_FORBIDDEN rather than * HTTP_UNAUTHORIZED because we don't want the browser to think it's * just temporarily failed and conduct a Basic Authentication dialog with * the user. */static int authorize(request_rec *r){    const apr_array_header_t *requirements_array;    const char *auth_type = ap_auth_type(r);    const char *authenticated_user = r->user;    const char *req_line, *req_word;    require_line *requirements;    int i, method;    LOG("in authorize()\n");    /* Someone else has to pick up the torch if "CAS" isn't our AuthType. */    if (auth_type && strcmp(auth_type, "CAS"))      return DECLINED;    LOG("-> AuthType CAS detected\n");    if (authenticated_user) {      LOG("-> authenticated username: "); LOG(authenticated_user); LOG("\n");    } else {      LOG("-> ... but no authenticated user!  (Shouldn't happen.)\n");    }    /* Some design considerations here were informed by mod_auth_kerb */    requirements_array = ap_requires(r);    if (!requirements_array)	return OK;				// no restriction    requirements = (require_line *) requirements_array->elts;    method = r->method_number;    for (i = 0; i < requirements_array->nelts; i++) {	// if our method isn't covered by the requirements line, ignore it	if (!(requirements[i].method_mask & (1 << method))) {	    continue;	}	req_line = requirements[i].requirement;		// full line	req_word = ap_getword(r->pool, &req_line, ' ');	// individual word	/*	 * If the requirements simply call for a "valid user," we can	 * simply return success, because if we're called, it means that	 * CAS authentication performed in an earlier callback DIDN'T	 * redirect back to CAS, so we have a valid user already, either	 * by virtue of a ticket or of having stored authenticated status	 * earlier.	 */	if (!strcmp(req_word, "valid-user"))	    return OK;	else if (!strcmp(req_word, "user")) {	    // the rest of the words are individual user names, so see	    // if our authenticated user matches	    while (*req_line) {		req_word = ap_getword_conf(r->pool, &req_line);		if (!strcmp(req_word, authenticated_user))		    return OK;	    }	} else if (!strcmp(req_word, "group")) {	    // the rest of the words are individual group names	    while (*req_line) {		req_word = ap_getword_conf(r->pool, &req_line);		if (is_user_in_group(authenticated_user, req_word, r->pool))		    return OK;	    }	}    }    // For now, no other sorts of requirements are supported    // For the moment, fail cleanly if we get something like    // "Require group foo" so that configuration files don't    // need to be changed; the relevant line can just be ignored,    // and we failed "closed."    return HTTP_FORBIDDEN;}/* Utility function definitions *//* * Fills buf with the 'service' portion of the URL requested.  This will * be the entire URL minus any trailing '&ticket=', if present. * The URL is determined here, heuristically, from the request record. * If buf isn't large enough to fit the entire URL, NULL is returned. */static char *get_service(request_rec *r, char *buf, int buflen) {    int l;    char portstr[6];    char *path = r->uri, *p;    mod_cas_conf *c = (mod_cas_conf *) ap_get_module_config(	r->server->module_config, &cas_module);    // /*     //  * For the server name, use the "Host" header if it exists; otherwise,    //  * consult the 'server' record.  Note that our 'server' string includes    //  * the server's name and an optional ':port'.    //  */    // const char *server = apr_table_get(r->headers_in, "Host");    // char *query = r->args;    // char *scheme = "http://";    // if (!server)    //	  server = r->server->server_hostname;    // if (!query)    //	  query = "";    /* Avoid using untrusted "Host" header. */    const char *server = r->server->server_hostname;    char *query = r->args;    char *scheme = "http://";    if (!query)      query = "";    if (!(c->CASLocalCacheInsecure))	scheme = "https://";    /* convert the port number to a string in case we need it */    snprintf(portstr, 6*sizeof(char), "%d", r->connection->local_addr->port);    LOG("portstr: ");    LOG(portstr);    LOG("\n");    if ((l = strlen(scheme) + strlen(server) + strlen(":") 	+ strlen(portstr) + strlen(path) + strlen(query) + 1) > buflen)	return NULL;    strcpy(buf, scheme);    strcat(buf, server);    /* add the port number if it's non-standard */    if(c->CASLocalCacheInsecure && r->connection->local_addr->port != 80	|| !c->CASLocalCacheInsecure && r->connection->local_addr->port != 443) {	strcat(buf, ":");	strcat(buf, portstr);    }    strcat(buf, path);    if (query && *query != '\0') {	strcat(buf, "%3F");             /* "?" */        for (p = query; *p; p++) {            if (*p == '=')                strcat(buf, "%3D");            else if (*p == '?')                strcat(buf, "%3F");            else if (*p == '&')                strcat(buf, "%26");	/* rewrite later to be more complete */            else {		char t[2];                t[0] = *p;                t[1] = '\0';		strcat(buf, t);            }        }    }    /* eliminate the ticket */    if ((p = strstr(buf, "%3Fticket%3D")))	*p = '\0';    if ((p = strstr(buf, "%26ticket%3D")))	*p = '\0';    return buf;}/* * Returns the 'ticket' portion of the URL requested.  This consists * of everything following '&ticket=' in the logical full URL.  If no "ticket" * parameter was specified, we return NULL. */static char *get_ticket(request_rec *r) {    char *ticket = NULL;    if (r->args && *(r->args) != '\0') {	/* if the query starts with "ticket=", then use the whole query */	if (r->args == strstr(r->args, "ticket="))	    ticket = r->args + strlen("ticket=");	else {	    /* otherwise, we need an "&" */	    ticket = strstr(r->args, "&ticket=");	    if (ticket)		ticket += strlen("&ticket=");	}    }    if (!ticket || *ticket == '\0')	return NULL;    return ticket;}static int is_parameter_true(request_rec *r, char *param) {    char *temp;    char *p;    if(r->args && *(r->args) != '\0') {	temp = alloca(strlen(param) + strlen("=true") + 1);	strcpy(temp, param);	strcat(temp, "=true");	if((p = strstr(r->args,temp)) && (p[strlen(temp)] == '&'	    || (p[strlen(temp)] == '\0'))) {	    return 1;	}    }    return 0;}/* Functions for handling the ticket cache. *//* * Add an entry to the ticket cache.  Values are copied from the TicketEntry, * which need not persist after the call terminates. */static void cache_put(TicketEntry te) {    int next;    char *last_slot = ticket_cache + ticket_cache_size - sizeof(TicketEntry);    if (!ticket_cache)	return;			// alas, nothing to do    LOG("in cache_put()\n");    // get an advisory, exclusive lock on the ticket cache file    write_lock(ticket_cache_fd);    LOG("-> got lock\n");    // the first int of the ticket cache stores the next slot    memcpy(&next, ticket_cache, sizeof(int));    LOG("-> first memcpy() done\n");    // wrap around if necessary    if (ticket_cache + sizeof(int) + next * sizeof(TicketEntry) > last_slot)	next = 0;    memcpy(ticket_cache + sizeof(int) + next * sizeof(TicketEntry),	&te, sizeof(TicketEntry));    msync(ticket_cache + sizeof(int) + next * sizeof(TicketEntry),	sizeof(TicketEntry), MS_SYNC | MS_INVALIDATE);    LOG("-> second memcpy() done\n");    // increment next, letting our successor handle wraparound    next++;    memcpy(ticket_cache, &next, sizeof(int));    msync(ticket_cache, sizeof(int), MS_SYNC | MS_INVALIDATE);    // release our lock    un_lock(ticket_cache_fd);    LOG("-> released lock\n");}/* * Marks the given ticket as invalid, effectively logging the user out * of Apache.  Hopefully. */static void cache_invalidate(char *ticket) {    char *last_slot = ticket_cache + ticket_cache_size - sizeof(TicketEntry);    char *p;    TicketEntry t;    LOG("in cache_invalidate()\n");    if(!ticket_cache) {	LOG("-> no ticket cache, returning\n");	return;    }    // get an advisory, shared file lock on the ticket cache file    read_lock(ticket_cache_fd);    for (p = ticket_cache + sizeof(int);	    p <= last_slot;	    p += sizeof(TicketEntry)) {	memcpy(&t, p, sizeof(TicketEntry));	if (!strcmp(t.ticket, ticket)) {	    LOG("-> found ticket entry, invalidating it\n");	    t.valid = 0;	    write_lock(ticket_cache_fd);	    memcpy(p, &t, sizeof(TicketEntry));	    msync(p, sizeof(TicketEntry), MS_SYNC | MS_INVALIDATE);	    un_lock(ticket_cache_fd);	    return;	}    }    un_lock(ticket_cache_fd);    LOG("-> never found the ticket... going home broke and hungry\n");}/* * Retrieves the NetID for a given ticket, storing it in the buffer * provided.  Returns 1 if the ticket was found and valid, 0 otherwise. * The 'insecure' parameter stores our current CASLocalCacheInsecure * status. */static int cache_get(char *ticket, char *buf, int buflen, char insecure) {    char *p;    char *last_slot = ticket_cache + ticket_cache_size - sizeof(TicketEntry);    TicketEntry t;    LOG("in cache_get()\n");    // get an advisory, shared file lock on the ticket cache file    read_lock(ticket_cache_fd);    // the first few bytes of the ticket array form an integer we don't    // care about    for (p = ticket_cache + sizeof(int); 	    p <= last_slot;	    p += sizeof(TicketEntry)) {	memcpy(&t, p, sizeof(TicketEntry));	if (t.valid 		&& t.secure == !insecure		&& time(NULL) < t.expiration		&& !strcmp(t.ticket, ticket)) {	    if (strlen(t.netid) + 1 > buflen)		return 0;	    strcpy(buf, t.netid);	    un_lock(ticket_cache_fd);			// release the lock	    return 1;	}    }    un_lock(ticket_cache_fd);				// release the lock    return 0;}/* * Constructs a random ticket value and stores it in the buffer provided. * The buffer is terminated with '\0'.  On unexpected failure, return 0; * otherwise, return 1. */static int random_ticket(char *buf, int buflen, char *egdfile) {    int fd;    char *pool =        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"        "abcdefghijklmnopqrstuvwxyz"        "01234567890";    LOG("in random_ticket()\n");    if (egdfile == NULL) {	LOG("using /dev/urandom\n");        /* Get our randomness from /dev/urandom. */        if ((fd = open("/dev/urandom", O_RDONLY)) < 0) {            LOG("ERROR!  Couldn't open /dev/urandom.  Do not deploy!");            return 0;	} else if (read(fd, buf, buflen - 1) < 0) {            close(fd);            LOG("ERROR!  Couldn't open /dev/urandom.  Do not deploy!");            return 0;        } else {            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.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -