Esempio n. 1
0
void
authenticateProxyUserCacheCleanup(void *datanotused)
{
    /*
     * We walk the hash by username as that is the unique key we use.
     * For big hashs we could consider stepping through the cache, 100/200
     * entries at a time. Lets see how it flys first.
     */
    auth_user_hash_pointer *usernamehash;
    auth_user_t *auth_user;
    char *username = NULL;
    debug(29, 3) ("authenticateProxyUserCacheCleanup: Cleaning the user cache now\n");
    debug(29, 3) ("authenticateProxyUserCacheCleanup: Current time: %ld\n", (long int) current_time.tv_sec);
    hash_first(proxy_auth_username_cache);
    while ((usernamehash = ((auth_user_hash_pointer *) hash_next(proxy_auth_username_cache)))) {
	auth_user = usernamehash->auth_user;
	username = authenticateUserUsername(auth_user);

	/* if we need to have inpedendent expiry clauses, insert a module call
	 * here */
	debug(29, 4) ("authenticateProxyUserCacheCleanup: Cache entry:\n\tType: %d\n\tUsername: %s\n\texpires: %ld\n\treferences: %ld\n", auth_user->auth_type, username, (long int) (auth_user->expiretime + Config.authenticateTTL), (long int) auth_user->references);
	if (auth_user->expiretime + Config.authenticateTTL <= current_time.tv_sec) {
	    debug(29, 5) ("authenticateProxyUserCacheCleanup: Removing user %s from cache due to timeout.\n", username);
	    /* the minus 1 accounts for the cache lock */
	    if ((authenticateAuthUserInuse(auth_user) - 1))
		debug(29, 4) ("authenticateProxyUserCacheCleanup: this cache entry has expired AND has a non-zero ref count.\n");
	    else
		authenticateAuthUserUnlock(auth_user);
	}
    }
    debug(29, 3) ("authenticateProxyUserCacheCleanup: Finished cleaning the user cache.\n");
    eventAdd("User Cache Maintenance", authenticateProxyUserCacheCleanup, NULL, Config.authenticateGCInterval, 1);
}
Esempio n. 2
0
/* authenticateUserRequestUsername: return a pointer to the username in the */
char *
authenticateUserRequestUsername(auth_user_request_t * auth_user_request)
{
    assert(auth_user_request != NULL);
    if (auth_user_request->auth_user)
	return authenticateUserUsername(auth_user_request->auth_user);
    else
	return NULL;
}
Esempio n. 3
0
/* UserNameCacheAdd: add a auth_user structure to the username cache */
void
authenticateUserNameCacheAdd(auth_user_t * auth_user)
{
    auth_user_hash_pointer *usernamehash;
    usernamehash = memAllocate(MEM_AUTH_USER_HASH);
    usernamehash->key = authenticateUserUsername(auth_user);
    usernamehash->auth_user = auth_user;
    hash_join(proxy_auth_username_cache, (hash_link *) usernamehash);
    auth_user->usernamehash = usernamehash;
    /* lock for presence in the cache */
    authenticateAuthUserLock(auth_user);
}
Esempio n. 4
0
void
authenticateUserCacheRestart(void)
{
    auth_user_hash_pointer *usernamehash;
    auth_user_t *auth_user;
    char *username = NULL;
    debug(29, 3) ("authenticateUserCacheRestart: Clearing config dependent cache data.\n");
    hash_first(proxy_auth_username_cache);
    while ((usernamehash = ((auth_user_hash_pointer *) hash_next(proxy_auth_username_cache)))) {
	auth_user = usernamehash->auth_user;
	username = authenticateUserUsername(auth_user);
	debug(29, 5) ("authenticateUserCacheRestat: Clearing cache ACL results for user: %s\n", username);
	aclCacheMatchFlush(&auth_user->proxy_match_cache);
    }

}
Esempio n. 5
0
char *
internalRedirectProcessURL(clientHttpRequest * req, rewritetoken * head)
{
    char *dev = NULL;
    size_t len = 0;
    debug(85, 5) ("internalRedirectProcessURL: start\n");
    for (; head != NULL; head = head->next) {
	const char *str = NULL;	/* string to append */
	size_t str_len = 0;
	int do_ulong = 0;
	unsigned long ulong = 0;
	const char *ulong_fmt = "%lu";
	debug(85, 5) ("internalRedirectProcessURL: token=%s str=%s urlEncode=%s\n",
	    tokenNames[head->type], head->str, head->urlEncode ? "true" : "false");
	switch (head->type) {
	case RFT_STRING:
	    str = head->str;
	    str_len = head->str_len;
	    break;
	case RFT_CLIENT_IPADDRESS:
	    str = inet_ntoa(req->conn->peer.sin_addr);
	    break;
	case RFT_LOCAL_IPADDRESS:
	    str = inet_ntoa(req->conn->me.sin_addr);
	    break;
	case RFT_LOCAL_PORT:
	    ulong = ntohs(req->conn->me.sin_port);
	    do_ulong = 1;
	    break;
	case RFT_EPOCH_SECONDS:
	    ulong = current_time.tv_sec;
	    do_ulong = 1;
	    break;
	case RFT_TIME_SUBSECONDS:
	    ulong = current_time.tv_usec / 1000;
	    do_ulong = 1;
	    ulong_fmt = "%03lu";
	    break;
	case RFT_USERNAME:
	    if (req->request->auth_user_request)
		str = authenticateUserUsername(req->request->auth_user_request->auth_user);

	    if (!str || !*str)
		str = req->conn->rfc931;

#ifdef USE_SSL
	    if ((!str || !*str) && req->conn != NULL)
		str = sslGetUserEmail(fd_table[req->conn->fd].ssl);
#endif

	    if (!str || !*str)
		str = req->request->extacl_user;

	    break;
	case RFT_USERLOGIN:
	    str = req->request->login;
	    break;
	case RFT_USERIDENT:
	    str = req->conn->rfc931;
	    break;
	case RFT_USERSSL:
#ifdef USE_SSL
	    if (req->conn != NULL)
		str = sslGetUserEmail(fd_table[req->conn->fd].ssl);
#endif
	    break;
	case RFT_EXTERNALACL_USER:
	    str = req->request->extacl_user;
	    break;
	case RFT_METHOD:
	    str = req->request->method->string;
	    break;
	case RFT_PROTOCOL:
	    str = ProtocolStr[req->request->protocol];
	    break;
	case RFT_URL:
	    str = req->uri;
	    break;
	case RFT_URLPATH:
	    str = req->request->urlpath.buf;
	    break;
	case RFT_URLHOST:
	    str = req->request->host;
	    break;
	case RFT_HDRHOST:
	    str = httpHeaderGetStr(&req->request->header, HDR_HOST);
	    break;
	case RFT_EXTERNALACL_LOGSTR:
	    str = req->request->extacl_log.buf;
	    break;
	default:
	    assert(0 && "Invalid rewrite token type");
	    break;
	}

	if (do_ulong) {
	    char tmpstr[12];
	    int nbytes = snprintf(tmpstr, 12, ulong_fmt, ulong);
	    assert(nbytes > 0);
	    dev = xreacat(dev, &len, tmpstr, nbytes);
	} else {
	    if ((str == NULL) || (*str == '\0'))
		str = "-";

	    if (str_len == 0)
		str_len = strlen(str);

	    if (head->urlEncode) {
		str = rfc1738_escape_part(str);
		str_len = strlen(str);
	    }
	    dev = xreacat(dev, &len, str, str_len);
	}
    }
    debug(85, 5) ("internalRedirectProcessURL: done: %s\n", dev);
    return dev;
}
Esempio n. 6
0
static void
authenticateAuthUserRequestSetIp(auth_user_request_t * auth_user_request, struct in_addr ipaddr)
{
    auth_user_ip_t *ipdata, *tempnode;
    auth_user_t *auth_user;
    char *ip1;
    int found = 0;
    CBDATA_INIT_TYPE(auth_user_ip_t);
    if (!auth_user_request->auth_user)
	return;
    auth_user = auth_user_request->auth_user;
    ipdata = (auth_user_ip_t *) auth_user->ip_list.head;
    /*
     * we walk the entire list to prevent the first item in the list
     * preventing old entries being flushed and locking a user out after
     * a timeout+reconfigure
     */
    while (ipdata) {
	tempnode = (auth_user_ip_t *) ipdata->node.next;
	/* walk the ip list */
	if (ipdata->ipaddr.s_addr == ipaddr.s_addr) {
	    /* This ip has already been seen. */
	    found = 1;
	    /* update IP ttl */
	    ipdata->ip_expiretime = squid_curtime;
	} else if (ipdata->ip_expiretime + Config.authenticateIpTTL < squid_curtime) {
	    /* This IP has expired - remove from the seen list */
	    dlinkDelete(&ipdata->node, &auth_user->ip_list);
	    cbdataFree(ipdata);
	    /* catch incipient underflow */
	    assert(auth_user->ipcount);
	    auth_user->ipcount--;
	}
	ipdata = tempnode;
    }

    if (found)
	return;

    /* This ip is not in the seen list */
    ipdata = cbdataAlloc(auth_user_ip_t);
    ipdata->ip_expiretime = squid_curtime;
    ipdata->ipaddr = ipaddr;
    dlinkAddTail(ipdata, &ipdata->node, &auth_user->ip_list);
    auth_user->ipcount++;

    ip1 = xstrdup(inet_ntoa(ipaddr));
    debug(29, 2) ("authenticateAuthUserRequestSetIp: user '%s' has been seen at a new IP address (%s)\n ", authenticateUserUsername(auth_user), ip1);
    safe_free(ip1);
}
Esempio n. 7
0
static void
authenticateDigestDecodeAuth(auth_user_request_t * auth_user_request, const char *proxy_auth)
{
    String temp;
    const char *item;
    const char *p;
    const char *pos = NULL;
    char *username = NULL;
    digest_nonce_h *nonce;
    int ilen;
    digest_request_h *digest_request;
    digest_user_h *digest_user;
    auth_user_t *auth_user;
    dlink_node *node;

    debug(29, 9) ("authenticateDigestDecodeAuth: beginning\n");
    assert(auth_user_request != NULL);

    digest_request = authDigestRequestNew();

    /* trim DIGEST from string */
    while (xisgraph(*proxy_auth))
	proxy_auth++;

    /* Trim leading whitespace before decoding */
    while (xisspace(*proxy_auth))
	proxy_auth++;

    stringInit(&temp, proxy_auth);
    while (strListGetItem(&temp, ',', &item, &ilen, &pos)) {
	if ((p = strchr(item, '=')) && (p - item < ilen))
	    ilen = p++ - item;
	if (!strncmp(item, "username", ilen)) {
	    /* white space */
	    while (xisspace(*p))
		p++;
	    /* quote mark */
	    p++;
	    username = xstrndup(p, strchr(p, '"') + 1 - p);
	    debug(29, 9) ("authDigestDecodeAuth: Found Username '%s'\n", username);
	} else if (!strncmp(item, "realm", ilen)) {
	    /* white space */
	    while (xisspace(*p))
		p++;
	    /* quote mark */
	    p++;
	    digest_request->realm = xstrndup(p, strchr(p, '"') + 1 - p);
	    debug(29, 9) ("authDigestDecodeAuth: Found realm '%s'\n", digest_request->realm);
	} else if (!strncmp(item, "qop", ilen)) {
	    /* white space */
	    while (xisspace(*p))
		p++;
	    if (*p == '\"')
		/* quote mark */
		p++;
	    digest_request->qop = xstrndup(p, strcspn(p, "\" \t\r\n()<>@,;:\\/[]?={}") + 1);
	    debug(29, 9) ("authDigestDecodeAuth: Found qop '%s'\n", digest_request->qop);
	} else if (!strncmp(item, "algorithm", ilen)) {
	    /* white space */
	    while (xisspace(*p))
		p++;
	    if (*p == '\"')
		/* quote mark */
		p++;
	    digest_request->algorithm = xstrndup(p, strcspn(p, "\" \t\r\n()<>@,;:\\/[]?={}") + 1);
	    debug(29, 9) ("authDigestDecodeAuth: Found algorithm '%s'\n", digest_request->algorithm);
	} else if (!strncmp(item, "uri", ilen)) {
	    /* white space */
	    while (xisspace(*p))
		p++;
	    /* quote mark */
	    p++;
	    digest_request->uri = xstrndup(p, strchr(p, '"') + 1 - p);
	    debug(29, 9) ("authDigestDecodeAuth: Found uri '%s'\n", digest_request->uri);
	} else if (!strncmp(item, "nonce", ilen)) {
	    /* white space */
	    while (xisspace(*p))
		p++;
	    /* quote mark */
	    p++;
	    digest_request->nonceb64 = xstrndup(p, strchr(p, '"') + 1 - p);
	    debug(29, 9) ("authDigestDecodeAuth: Found nonce '%s'\n", digest_request->nonceb64);
	} else if (!strncmp(item, "nc", ilen)) {
	    /* white space */
	    while (xisspace(*p))
		p++;
	    xstrncpy(digest_request->nc, p, 9);
	    debug(29, 9) ("authDigestDecodeAuth: Found noncecount '%s'\n", digest_request->nc);
	} else if (!strncmp(item, "cnonce", ilen)) {
	    /* white space */
	    while (xisspace(*p))
		p++;
	    /* quote mark */
	    p++;
	    digest_request->cnonce = xstrndup(p, strchr(p, '"') + 1 - p);
	    debug(29, 9) ("authDigestDecodeAuth: Found cnonce '%s'\n", digest_request->cnonce);
	} else if (!strncmp(item, "response", ilen)) {
	    /* white space */
	    while (xisspace(*p))
		p++;
	    /* quote mark */
	    p++;
	    digest_request->response = xstrndup(p, strchr(p, '"') + 1 - p);
	    debug(29, 9) ("authDigestDecodeAuth: Found response '%s'\n", digest_request->response);
	}
    }
    stringClean(&temp);


    /* now we validate the data given to us */

    /*
     * TODO: on invalid parameters we should return 400, not 407.
     * Find some clean way of doing this. perhaps return a valid
     * struct, and set the direction to clientwards combined with
     * a change to the clientwards handling code (ie let the
     * clientwards call set the error type (but limited to known
     * correct values - 400/401/407
     */

    /* first the NONCE count */
    if (digest_request->cnonce && strlen(digest_request->nc) != 8) {
	debug(29, 4) ("authenticateDigestDecode: nonce count length invalid\n");
	authDigestLogUsername(auth_user_request, username);

	/* we don't need the scheme specific data anymore */
	authDigestRequestDelete(digest_request);
	auth_user_request->scheme_data = NULL;
	return;
    }
    /* now the nonce */
    nonce = authenticateDigestNonceFindNonce(digest_request->nonceb64);
    if (!nonce) {
	/* we couldn't find a matching nonce! */
	debug(29, 4) ("authenticateDigestDecode: Unexpected or invalid nonce recieved\n");
	authDigestLogUsername(auth_user_request, username);

	/* we don't need the scheme specific data anymore */
	authDigestRequestDelete(digest_request);
	auth_user_request->scheme_data = NULL;
	return;
    }
    digest_request->nonce = nonce;
    authDigestNonceLink(nonce);

    /* check the qop is what we expected. Note that for compatability with 
     * RFC 2069 we should support a missing qop. Tough. */
    if (!digest_request->qop || strcmp(digest_request->qop, QOP_AUTH)) {
	/* we recieved a qop option we didn't send */
	debug(29, 4) ("authenticateDigestDecode: Invalid qop option recieved\n");
	authDigestLogUsername(auth_user_request, username);

	/* we don't need the scheme specific data anymore */
	authDigestRequestDelete(digest_request);
	auth_user_request->scheme_data = NULL;
	return;
    }
    /* we can't check the URI just yet. We'll check it in the
     * authenticate phase */

    /* is the response the correct length? */

    if (!digest_request->response || strlen(digest_request->response) != 32) {
	debug(29, 4) ("authenticateDigestDecode: Response length invalid\n");
	authDigestLogUsername(auth_user_request, username);

	/* we don't need the scheme specific data anymore */
	authDigestRequestDelete(digest_request);
	auth_user_request->scheme_data = NULL;
	return;
    }
    /* do we have a username ? */
    if (!username || username[0] == '\0') {
	debug(29, 4) ("authenticateDigestDecode: Empty or not present username\n");
	authDigestLogUsername(auth_user_request, username);

	/* we don't need the scheme specific data anymore */
	authDigestRequestDelete(digest_request);
	auth_user_request->scheme_data = NULL;
	return;
    }
    /* check that we're not being hacked / the username hasn't changed */
    if (nonce->auth_user && strcmp(username, authenticateUserUsername(nonce->auth_user))) {
	debug(29, 4) ("authenticateDigestDecode: Username for the nonce does not equal the username for the request\n");
	authDigestLogUsername(auth_user_request, username);

	/* we don't need the scheme specific data anymore */
	authDigestRequestDelete(digest_request);
	auth_user_request->scheme_data = NULL;
	return;
    }
    /* if we got a qop, did we get a cnonce or did we get a cnonce wihtout a qop? */
    if ((digest_request->qop && !digest_request->cnonce)
	|| (!digest_request->qop && digest_request->cnonce)) {
	debug(29, 4) ("authenticateDigestDecode: qop without cnonce, or vice versa!\n");
	authDigestLogUsername(auth_user_request, username);

	/* we don't need the scheme specific data anymore */
	authDigestRequestDelete(digest_request);
	auth_user_request->scheme_data = NULL;
	return;
    }
    /* check the algorithm is present and supported */
    if (!digest_request->algorithm)
	digest_request->algorithm = xstrndup("MD5", 4);
    else if (strcmp(digest_request->algorithm, "MD5")
	&& strcmp(digest_request->algorithm, "MD5-sess")) {
	debug(29, 4) ("authenticateDigestDecode: invalid algorithm specified!\n");
	authDigestLogUsername(auth_user_request, username);

	/* we don't need the scheme specific data anymore */
	authDigestRequestDelete(digest_request);
	auth_user_request->scheme_data = NULL;
	return;
    }
    /* the method we'll check at the authenticate step as well */


    /* we don't send or parse opaques. Ok so we're flexable ... */

    /* find the user */

    if ((auth_user = authDigestUserFindUsername(username)) == NULL) {
	/* the user doesn't exist in the username cache yet */
	debug(29, 9) ("authDigestDecodeAuth: Creating new digest user '%s'\n", username);
	/* new auth_user */
	auth_user = authenticateAuthUserNew("digest");
	/* new scheme user data */
	digest_user = authDigestUserNew();
	/* save the username */
	digest_user->username = username;
	/* link the primary struct in */
	auth_user->scheme_data = digest_user;
	/* set the user type */
	auth_user->auth_type = AUTH_DIGEST;
	/* this auth_user struct is the one to get added to the
	 * username cache */
	/* store user in hash's */
	authenticateUserNameCacheAdd(auth_user);
	/* 
	 * Add the digest to the user so we can tell if a hacking
	 * or spoofing attack is taking place. We do this by assuming
	 * the user agent won't change user name without warning.
	 */
	authDigestUserLinkNonce(auth_user, nonce);
    } else {
	debug(29, 9) ("authDigestDecodeAuth: Found user '%s' in the user cache as '%p'\n", username, auth_user);
	digest_user = auth_user->scheme_data;
	xfree(username);
    }
    /*link the request and the user */
    auth_user_request->auth_user = auth_user;
    auth_user_request->scheme_data = digest_request;
    /* lock for the request link */
    authenticateAuthUserLock(auth_user);
    node = dlinkNodeNew();
    dlinkAdd(auth_user_request, node, &auth_user->requests);

    debug(29, 9) ("username = '******'\nrealm = '%s'\nqop = '%s'\nalgorithm = '%s'\nuri = '%s'\nnonce = '%s'\nnc = '%s'\ncnonce = '%s'\nresponse = '%s'\ndigestnonce = '%p'\n",
	digest_user->username, digest_request->realm,
	digest_request->qop, digest_request->algorithm,
	digest_request->uri, digest_request->nonceb64,
	digest_request->nc, digest_request->cnonce, digest_request->response, nonce);

    return;
}