/* setup the necessary info to log the username */ static void authDigestLogUsername(auth_user_request_t * auth_user_request, char *username) { auth_user_t *auth_user; digest_user_h *digest_user; dlink_node *node; /* log the username */ debug(29, 9) ("authDigestLogUsername: Creating new user for logging '%s'\n", username); /* new auth_user */ auth_user = authenticateAuthUserNew("digest"); /* new scheme data */ digest_user = authDigestUserNew(); /* save the credentials */ digest_user->username = username; /* link the scheme data in */ auth_user->scheme_data = digest_user; /* set the auth_user type */ auth_user->auth_type = AUTH_BROKEN; /* link the request to the user */ auth_user_request->auth_user = auth_user; /* lock for the auth_user_request link */ authenticateAuthUserLock(auth_user); node = dlinkNodeNew(); dlinkAdd(auth_user_request, node, &auth_user->requests); }
static void authenticateDecodeNegotiateAuth(auth_user_request_t * auth_user_request, const char *proxy_auth) { dlink_node *node; assert(auth_user_request->auth_user == NULL); auth_user_request->auth_user = authenticateAuthUserNew("negotiate"); auth_user_request->auth_user->auth_type = AUTH_NEGOTIATE; auth_user_request->auth_user->scheme_data = memPoolAlloc(negotiate_user_pool); auth_user_request->scheme_data = memPoolAlloc(negotiate_request_pool); memset(auth_user_request->scheme_data, '\0', sizeof(negotiate_request_t)); /* lock for the auth_user_request link */ authenticateAuthUserLock(auth_user_request->auth_user); node = dlinkNodeNew(); dlinkAdd(auth_user_request, node, &auth_user_request->auth_user->requests); /* the helper does the rest, with data collected in * authenticateNegotiateAuthenticateUser */ debug(29, 9) ("authenticateDecodeNegotiateAuth: Negotiate authentication\n"); return; }
static void authenticateBasicDecodeAuth(auth_user_request_t * auth_user_request, const char *proxy_auth) { char *sent_auth; char *cleartext; basic_data *basic_auth, local_basic; auth_user_t *auth_user; dlink_node *node; /* decode the username */ /* trim BASIC from string */ while (xisgraph(*proxy_auth)) proxy_auth++; local_basic.passwd = NULL; /* Trim leading whitespace before decoding */ while (xisspace(*proxy_auth)) proxy_auth++; /* username and password */ sent_auth = xstrdup(proxy_auth); /* Trim trailing \n before decoding */ strtok(sent_auth, "\n"); cleartext = uudecode(sent_auth); xfree(sent_auth); /* * Don't allow NL or CR in the credentials. * Oezguer Kesim <*****@*****.**> */ debug(29, 9) ("authenticateBasicDecodeAuth: cleartext = '%s'\n", cleartext); if (strcspn(cleartext, "\r\n") != strlen(cleartext)) { debug(29, 1) ("authenticateBasicDecodeAuth: bad characters in authorization header '%s'\n", proxy_auth); xfree(cleartext); return; } local_basic.username = cleartext; if ((cleartext = strchr(local_basic.username, ':')) != NULL) *(cleartext)++ = '\0'; local_basic.passwd = cleartext; if (cleartext == NULL) { debug(29, 4) ("authenticateBasicDecodeAuth: no password in proxy authorization header '%s'\n", proxy_auth); local_basic.passwd = NULL; auth_user_request->message = xstrdup("no password was present in the HTTP [proxy-]authorization header. This is most likely a browser bug"); } else if (*cleartext == '\0' && !basicConfig->blankpassword) { debug(29, 4) ("authenticateBasicDecodeAuth: Disallowing empty password," "user is '%s'\n", local_basic.username); local_basic.passwd = NULL; auth_user_request->message = xstrdup("Request denied because you provided an empty password. Users MUST have a password."); } /* special case: we have to free the strings for user and password * if we are not returning a filled out structure */ if (local_basic.passwd == NULL) { if (local_basic.username) { /* log the username */ debug(29, 9) ("authBasicDecodeAuth: Creating new user for logging '%s'\n", local_basic.username); /* new auth_user */ auth_user = authenticateAuthUserNew("basic"); /* new scheme data */ basic_auth = authBasicDataNew(); /* save the credentials */ basic_auth->username = local_basic.username; /* link the scheme data in */ auth_user->scheme_data = basic_auth; /* set the auth_user type */ auth_user->auth_type = AUTH_BROKEN; /* link the request to the user */ auth_user_request->auth_user = auth_user; /* lock for the auth_user_request link */ authenticateAuthUserLock(auth_user); node = dlinkNodeNew(); dlinkAdd(auth_user_request, node, &auth_user->requests); } return; } else { local_basic.passwd = xstrndup(cleartext, USER_IDENT_SZ); } if (!basicConfig->casesensitive) Tolower(local_basic.username); /* now lookup and see if we have a matching auth_user structure in memory. */ if ((auth_user = authBasicAuthUserFindUsername(local_basic.username)) == NULL) { /* the user doesn't exist in the username cache yet */ debug(29, 9) ("authBasicDecodeAuth: Creating new user '%s'\n", local_basic.username); /* new auth_user */ auth_user = authenticateAuthUserNew("basic"); /* new scheme data */ basic_auth = authBasicDataNew(); /* save the credentials */ basic_auth->username = local_basic.username; basic_auth->passwd = local_basic.passwd; /* link the scheme data in */ auth_user->scheme_data = basic_auth; /* set the auth_user type */ auth_user->auth_type = AUTH_BASIC; /* current time for timeouts */ auth_user->expiretime = current_time.tv_sec; /* this auth_user struct is the 'lucky one' to get added to the username cache */ /* the requests after this link to the auth_user */ /* store user in hash */ authenticateUserNameCacheAdd(auth_user); } else { debug(29, 9) ("authBasicDecodeAuth: Found user '%s' in the user cache as '%p'\n", local_basic.username, auth_user); xfree(local_basic.username); basic_auth = auth_user->scheme_data; if (strcmp(local_basic.passwd, basic_auth->passwd)) { debug(29, 4) ("authBasicDecodeAuth: new password found. Updating in user master record and resetting auth state to unchecked\n"); basic_auth->flags.credentials_ok = 0; xfree(basic_auth->passwd); basic_auth->passwd = local_basic.passwd; } else xfree(local_basic.passwd); if (basic_auth->flags.credentials_ok == 3) { debug(29, 4) ("authBasicDecodeAuth: last attempt to authenticate this user failed, resetting auth state to unchecked\n"); basic_auth->flags.credentials_ok = 0; } } /* link the request to the user */ auth_user_request->auth_user = auth_user; /* lock for the auth_user_request link */ authenticateAuthUserLock(auth_user); node = dlinkNodeNew(); dlinkAdd(auth_user_request, node, &auth_user->requests); return; }
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; }