?? httpauth.c
字號:
sess->stored_rdig = rdig; } /* And finally, H(A2) */ md5_process_bytes( a2_md5_ascii, 32, &rdig ); md5_finish_ctx( &rdig, rdig_md5 ); md5_hexify( rdig_md5, rdig_md5_ascii ); /* Buffer size calculation. */ retlen = 6 /* Digest */ + 1 + 8 + 1 + 2 + strlen(sess->username) /* username="..." */ + 2 + 5 + 1 + 2 + strlen(sess->unq_realm) /* , realm="..." */ + 2 + 5 + 1 + 2 + strlen(sess->unq_nonce) /* , nonce="..." */ + 2 + 3 + 1 + 2 + strlen(sess->uri) /* , uri="..." */ + 2 + 8 + 1 + 2 + 32 /* , response="..." */ + 2 + 9 + 1 + strlen(http_auth_alg_names[sess->alg]) /* , algorithm= */ ; if( sess->opaque != NULL ) retlen += 2 + 6 + 1 + strlen(sess->opaque); /* , opaque=... */ if( sess->qop != http_auth_qop_none ) retlen += 2 + 6 + 2 + 1 + strlen(sess->unq_cnonce) + /* , cnonce="..." */ 2 + 2 + 1 + 8 + /* , nc=... */ 2 + 3 + 1 + strlen(http_auth_qop_values[sess->qop]) /* , qop=... */ ; retlen += 2; /* \r\n */ DEBUG( DEBUG_HTTPAUTH, "Calculated length of buffer: %d\n", retlen ); ret = malloc( retlen + 1 ); sprintf( ret, "Digest username=\"%s\", realm=\"%s\"" ", nonce=\"%s\", uri=\"%s\", response=\"%s\"" ", algorithm=%s", sess->username, sess->unq_realm, sess->unq_nonce, sess->uri, rdig_md5_ascii, http_auth_alg_names[sess->alg]); if( sess->opaque != NULL ) { /* We never unquote it, so it's still quoted here */ strcat( ret, ", opaque=" ); strcat( ret, sess->opaque ); } if( sess->qop != http_auth_qop_none ) { /* Add in cnonce and nc-value fields */ strcat( ret, ", cnonce=\"" ); strcat( ret, sess->unq_cnonce ); strcat( ret, "\", nc=" ); strcat( ret, nc_value ); strcat( ret, ", qop=" ); strcat( ret, http_auth_qop_values[sess->qop] ); } DEBUG( DEBUG_HTTPAUTH, "Digest header field value:\n%s\n", ret ); strcat( ret, "\r\n" ); DEBUG( DEBUG_HTTPAUTH, "Calculated length: %d, actual length: %d\n", retlen, strlen( ret ) ); return ret;}inline void http_auth_response_body( http_auth_session_t *sess, const char *buffer, size_t buffer_len ) { if( sess->scheme != http_auth_scheme_digest ) return; DEBUG( DEBUG_HTTPAUTH, "Digesting %d bytes of response body.\n" ); md5_process_bytes( buffer, buffer_len, &sess->response_body );}/* Pass this the value of the 'Authentication-Info:' header field, if * one is received. Returns false if gives incorrect authentication * information for the server. */bool http_auth_verify_response( http_auth_session_t *sess, const char *value ) { char **pairs; http_auth_qop_t qop = http_auth_qop_none; char *nextnonce = NULL, /* for the nextnonce= value */ *rspauth = NULL, /* for the rspauth= value */ *cnonce = NULL, /* for the cnonce= value */ *nc = NULL, /* for the nc= value */ *unquoted, *qop_value = NULL; int n, nonce_count; bool okay; if( sess->scheme != http_auth_scheme_digest ) { DEBUG( DEBUG_HTTPAUTH, "Found Auth-Info header not in response to Digest credentials - dodgy.\n" ); return false; } pairs = strpairs( value, ',', '=', http_quotes, http_whitespace ); for( n = 0; pairs[n]!=NULL; n+=2 ) { unquoted = strstrip( pairs[n+1], '"' ); if( strcasecmp( pairs[n], "qop" ) == 0 ) { qop_value = strdup( pairs[n+1] ); if( strcasecmp( pairs[n+1], "auth-int" ) == 0 ) { qop = http_auth_qop_auth_int; } else if( strcasecmp( pairs[n+1], "auth" ) == 0 ) { qop = http_auth_qop_auth; } else { qop = http_auth_qop_none; } } else if( strcasecmp( pairs[n], "nextnonce" ) == 0 ) { nextnonce = strdup( unquoted ); } else if( strcasecmp( pairs[n], "rspauth" ) == 0 ) { rspauth = strdup( unquoted ); } else if( strcasecmp( pairs[n], "cnonce" ) == 0 ) { cnonce = strdup( unquoted ); } else if( strcasecmp( pairs[n], "nc" ) == 0 ) { nc = strdup( pairs[n] ); if( sscanf( pairs[n+1], "%x", &nonce_count ) != 1 ) { DEBUG( DEBUG_HTTPAUTH, "Couldn't scan [%s] for nonce count.\n", pairs[n+1] ); } else { DEBUG( DEBUG_HTTPAUTH, "Got nonce_count: %d\n", nonce_count ); } } free( unquoted ); } strpairs_free( pairs ); /* Presume the worst */ okay = false; if( (qop != http_auth_qop_none) && (qop_value != NULL) ) { if( (rspauth == NULL) || (cnonce == NULL) || (nc == NULL) ) { DEBUG( DEBUG_HTTPAUTH, "Missing rspauth, cnonce or nc with qop.\n" ); } else { /* Have got rspauth, cnonce and nc */ if( strcmp( cnonce, sess->unq_cnonce ) != 0 ) { DEBUG( DEBUG_HTTPAUTH, "Response cnonce doesn't match.\n" ); } else if( nonce_count != sess->nonce_count ) { DEBUG( DEBUG_HTTPAUTH, "Response nonce count doesn't match.\n" ); } else { /* Calculate and check the response-digest value. */ /* TODO: Should we use our sent qop-value here, or * the one the server gave us? Currently, we use the server * qop-value... that's what mod_digest does. */ struct md5_ctx a2; unsigned char a2_md5[16], rdig_md5[16]; char a2_md5_ascii[33], rdig_md5_ascii[33]; DEBUG( DEBUG_HTTPAUTH, "Calculating response-digest.\n" ); /* First off, H(A2) again. */ md5_init_ctx( &a2 ); md5_process_bytes( ":", 1, &a2 ); md5_process_bytes( sess->uri, strlen(sess->uri), &a2 ); if( qop == http_auth_qop_auth_int ) { unsigned char heb_md5[16]; char heb_md5_ascii[33]; /* Add on ":" H(entity-body) */ md5_finish_ctx( &sess->response_body, heb_md5 ); md5_hexify( heb_md5, heb_md5_ascii ); md5_process_bytes( ":", 1, &a2 ); md5_process_bytes( heb_md5_ascii, 32, &a2 ); DEBUG( DEBUG_HTTPAUTH, "Digested [:%s]\n", heb_md5_ascii ); } md5_finish_ctx( &a2, a2_md5 ); md5_hexify( a2_md5, a2_md5_ascii ); /* We have the stored digest-so-far of * H(A1) ":" unq(nonce-value) * [ ":" nc-value ":" unq(cnonce-value) ] for qop * in sess->stored_rdig, to safe digesting them again. * */ if( qop != http_auth_qop_none ) { /* Add in qop-value */ DEBUG( DEBUG_HTTPAUTH, "Digesting qop-value [%s:].\n", qop_value ); md5_process_bytes( qop_value, strlen(qop_value), &sess->stored_rdig ); md5_process_bytes( ":", 1, &sess->stored_rdig ); } /* Digest ":" H(A2) */ md5_process_bytes( a2_md5_ascii, 32, &sess->stored_rdig ); /* All done */ md5_finish_ctx( &sess->stored_rdig, rdig_md5 ); md5_hexify( rdig_md5, rdig_md5_ascii ); DEBUG( DEBUG_HTTPAUTH, "Calculated response-digest of: [%s]\n", rdig_md5_ascii ); DEBUG( DEBUG_HTTPAUTH, "Given response-digest of: [%s]\n", rspauth ); /* And... do they match? */ okay = (strcmp( rdig_md5_ascii, rspauth ) == 0); DEBUG( DEBUG_HTTPAUTH, "Matched: %s\n", okay?"OH YES!":"nope." ); } free( rspauth ); free( cnonce ); free( nc ); } free( qop_value ); } else { DEBUG( DEBUG_HTTPAUTH, "No qop directive, auth okay.\n" ); okay = true; } /* Check for a nextnonce */ if( nextnonce != NULL ) { DEBUG( DEBUG_HTTPAUTH, "Found nextnonce of [%s].\n", nextnonce ); if( sess->unq_nonce != NULL ) free( sess->unq_nonce ); sess->unq_nonce = nextnonce; } return okay;}bool http_auth_challenge( http_auth_session_t *sess, const char *value ) { char **pairs, *pnt, *unquoted, *key; http_auth_chall_t **challenges = NULL, *this_chall = NULL; int numchalls = 0, n; bool success; DEBUG( DEBUG_HTTPAUTH, "Got new auth challenge: %s\n", value ); /* Clean up old session information. */ http_auth_clean( sess ); /* The header value may be made up of one or more challenges. * We split it down into attribute-value pairs, then search for * schemes in the pair keys. */ pairs = strpairs( value, ',', '=', http_quotes, http_whitespace ); for( n = 0; pairs[n]!=NULL; n+=2 ) { /* Look for an auth-scheme in the key */ pnt = strchr( pairs[n], ' ' ); if( pnt != NULL ) { /* We have a new challenge */ DEBUG( DEBUG_HTTPAUTH, "New challenge.\n" ); numchalls++; challenges = realloc( challenges, numchalls * sizeof(http_auth_chall_t *) ); challenges[numchalls-1] = malloc( sizeof(http_auth_chall_t) ); this_chall = challenges[numchalls-1]; /* Initialize the challenge parameters */ memset( this_chall, 0, sizeof(http_auth_chall_t) ); /* Which auth-scheme is it (case-insensitive matching) */ if( strncasecmp( pairs[n], "basic ", 6 ) == 0 ) { DEBUG( DEBUG_HTTPAUTH, "Basic scheme.\n" ); this_chall->scheme = http_auth_scheme_basic; } else if( strncasecmp( pairs[n], "digest ", 7 ) == 0 ) { DEBUG( DEBUG_HTTPAUTH, "Digest scheme.\n" ); this_chall->scheme = http_auth_scheme_digest; } else { DEBUG( DEBUG_HTTPAUTH, "Unknown scheme.\n" ); this_chall->scheme = http_auth_scheme_none; } /* Now, the real key for this pair starts after the * auth-scheme... skipping whitespace */ while( strchr( http_whitespace, *(++pnt) ) != NULL ) /* nullop */; key = pnt; } else if( this_chall == NULL ) { /* If we haven't got an auth-scheme, and we're * haven't yet found a challenge, skip this pair. */ continue; } else { key = pairs[n]; } DEBUG( DEBUG_HTTPAUTH, "Got pair: [%s] = [%s]\n", key, pairs[n+1] ); /* Most values are quoted, so unquote them here */ unquoted = strstrip( pairs[n+1], '"' ); /* Now parse the attribute */ DEBUG( DEBUG_HTTPAUTH, "Unquoted pair is: [%s]\n", unquoted ); if( strcasecmp( key, "realm" ) == 0 ) { this_chall->realm = pairs[n+1]; } else if( strcasecmp( key, "nonce" ) == 0 ) { this_chall->nonce = pairs[n+1]; } /* else if( strcasecmp( key, "domain" ) == 0 ) { this_chall->domain = pairs[n+1]; } */ else if( strcasecmp( key, "opaque" ) == 0 ) { this_chall->opaque = pairs[n+1]; } else if( strcasecmp( key, "stale" ) == 0 ) { /* Truth value */ this_chall->stale = ( strcasecmp( unquoted, "true" ) == 0 ); } else if( strcasecmp( key, "algorithm" ) == 0 ) { if( strcasecmp( unquoted, "md5" ) == 0 ) { this_chall->alg = http_auth_alg_md5; } else if( strcasecmp( unquoted, "md5-sess" ) == 0 ) { this_chall->alg = http_auth_alg_md5_sess; } else { this_chall->alg = http_auth_alg_unknown; } } else if( strcasecmp( key, "qop" ) == 0 ) { char **qops; int qop; qops = strsplit( unquoted, ',', NULL, http_whitespace ); this_chall->got_qop = true; for( qop = 0; qops[qop] != NULL; qop++ ) { if( strcasecmp( qops[qop], "auth" ) == 0 ) { this_chall->qop_auth = true; } else if( strcasecmp( qops[qop], "auth-int" ) == 0 ) { this_chall->qop_auth_int = true; } } strsplit_free( qops ); } free( unquoted ); } /* Did we find any challenges */ if( numchalls == 0 ) return false; DEBUG( DEBUG_HTTPAUTH, "Finished parsing parameters.\n" ); success = false; DEBUG( DEBUG_HTTPAUTH, "Looking for Digest challenges.\n" ); /* Try a digest challenge */ for( n = 0; n < numchalls; n++ ) { if( challenges[n]->scheme == http_auth_scheme_digest ) { if( http_auth_challenge_digest( sess, challenges[n] ) ) { success = true; break; } } } if( !success ) { DEBUG( DEBUG_HTTPAUTH, "No good Digest challenges, looking for Basic.\n" ); for( n = 0; n < numchalls; n++ ) { if( challenges[n]->scheme == http_auth_scheme_basic ) { if( http_auth_challenge_basic( sess, challenges[n] ) ) { success = true; break; } } } if( !success ) { /* No good challenges - record this in the session state */ DEBUG( DEBUG_HTTPAUTH, "Did not understand any challenges.\n" ); sess->scheme = http_auth_scheme_none; } } /* Free up the parsed header values */ strpairs_free( pairs ); return success; }
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -