📄 ne_auth.c
字号:
NE_DEBUG(NE_DBG_HTTPAUTH, "Digesting qop-value [%s:].\n", qop_value); ne_md5_process_bytes(qop_value, strlen(qop_value), &sess->stored_rdig); ne_md5_process_bytes(":", 1, &sess->stored_rdig); } /* Digest ":" H(A2) */ ne_md5_process_bytes(a2_md5_ascii, 32, &sess->stored_rdig); /* All done */ ne_md5_finish_ctx(&sess->stored_rdig, rdig_md5); ne_md5_to_ascii(rdig_md5, rdig_md5_ascii); NE_DEBUG(NE_DBG_HTTPAUTH, "Calculated response-digest of: " "[%s]\n", rdig_md5_ascii); NE_DEBUG(NE_DBG_HTTPAUTH, "Given response-digest of: " "[%s]\n", rspauth); /* And... do they match? */ okay = (strcasecmp(rdig_md5_ascii, rspauth) == 0)?0:-1; NE_DEBUG(NE_DBG_HTTPAUTH, "Matched: %s\n", okay?"nope":"YES!"); } } } else { NE_DEBUG(NE_DBG_HTTPAUTH, "No qop directive, auth okay.\n"); okay = 0; } /* Check for a nextnonce */ if (nextnonce != NULL) { NE_DEBUG(NE_DBG_HTTPAUTH, "Found nextnonce of [%s].\n", nextnonce); if (sess->nonce != NULL) ne_free(sess->nonce); sess->nonce = ne_strdup(nextnonce); } ne_free(hdr); return okay;}/* Passed the value of a "(Proxy,WWW)-Authenticate: " header field. * Returns 0 if valid challenge was accepted; non-zero if no valid * challenge was found. */static int auth_challenge(auth_session *sess, const char *value) { char *pnt, *key, *val, *hdr; struct auth_challenge *chall = NULL, *challenges = NULL; int success; pnt = hdr = ne_strdup(value); NE_DEBUG(NE_DBG_HTTPAUTH, "Got new auth challenge: %s\n", value); /* 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. */ while (!tokenize(&pnt, &key, &val, 1)) { if (val == NULL) { /* We have a new challenge */ NE_DEBUG(NE_DBG_HTTPAUTH, "New challenge for scheme [%s]\n", key); chall = ne_calloc(sizeof *chall); chall->next = challenges; challenges = chall; /* Initialize the challenge parameters */ /* Which auth-scheme is it (case-insensitive matching) */ if (strcasecmp(key, "basic") == 0) { NE_DEBUG(NE_DBG_HTTPAUTH, "Basic scheme.\n"); chall->scheme = auth_scheme_basic; } else if (strcasecmp(key, "digest") == 0) { NE_DEBUG(NE_DBG_HTTPAUTH, "Digest scheme.\n"); chall->scheme = auth_scheme_digest;#ifdef HAVE_GSSAPI } else if (strcasecmp(key, "negotiate") == 0) { NE_DEBUG(NE_DBG_HTTPAUTH, "GSSAPI scheme.\n"); chall->scheme = auth_scheme_gssapi;#endif } else { NE_DEBUG(NE_DBG_HTTPAUTH, "Unknown scheme.\n"); ne_free(chall); challenges = NULL; break; } continue; } else if (chall == NULL) { /* If we haven't got an auth-scheme, and we're * haven't yet found a challenge, skip this pair. */ continue; } /* Strip quotes off value. */ val = ne_shave(val, "\"'"); NE_DEBUG(NE_DBG_HTTPAUTH, "Got pair: [%s] = [%s]\n", key, val); if (strcasecmp(key, "realm") == 0) { chall->realm = val; } else if (strcasecmp(key, "nonce") == 0) { chall->nonce = val; } else if (strcasecmp(key, "opaque") == 0) { chall->opaque = val; } else if (strcasecmp(key, "stale") == 0) { /* Truth value */ chall->stale = (strcasecmp(val, "true") == 0); } else if (strcasecmp(key, "algorithm") == 0) { if (strcasecmp(val, "md5") == 0) { chall->alg = auth_alg_md5; } else if (strcasecmp(val, "md5-sess") == 0) { chall->alg = auth_alg_md5_sess; } else { chall->alg = auth_alg_unknown; } } else if (strcasecmp(key, "qop") == 0) { /* iterate over each token in the value */ do { const char *tok = ne_shave(ne_token(&val, ','), " \t"); if (strcasecmp(tok, "auth") == 0) { chall->qop_auth = 1; } else if (strcasecmp(tok, "auth-int") == 0 ) { chall->qop_auth_int = 1; } } while (val); chall->got_qop = chall->qop_auth || chall->qop_auth_int; } } NE_DEBUG(NE_DBG_HTTPAUTH, "Finished parsing parameters.\n"); /* Did we find any challenges */ if (challenges == NULL) { ne_free(hdr); return -1; } success = 0;#ifdef HAVE_GSSAPI if (strcmp(ne_get_scheme(sess->sess), "https") == 0) { NE_DEBUG(NE_DBG_HTTPAUTH, "Looking for GSSAPI.\n"); /* Try a GSSAPI challenge */ for (chall = challenges; chall != NULL; chall = chall->next) { if (chall->scheme == auth_scheme_gssapi) { if (!gssapi_challenge(sess, chall)) { success = 1; break; } } } }#endif /* Try a digest challenge */ if (!success) { NE_DEBUG(NE_DBG_HTTPAUTH, "Looking for Digest challenges.\n"); for (chall = challenges; chall != NULL; chall = chall->next) { if (chall->scheme == auth_scheme_digest) { if (!digest_challenge(sess, chall)) { success = 1; break; } } } } if (!success) { NE_DEBUG(NE_DBG_HTTPAUTH, "No good Digest challenges, looking for Basic.\n"); for (chall = challenges; chall != NULL; chall = chall->next) { if (chall->scheme == auth_scheme_basic) { if (!basic_challenge(sess, chall)) { success = 1; break; } } } if (!success) { /* No good challenges - record this in the session state */ NE_DEBUG(NE_DBG_HTTPAUTH, "Did not understand any challenges.\n"); } } /* Remember whether we can now supply the auth details */ sess->can_handle = success; while (challenges != NULL) { chall = challenges->next; ne_free(challenges); challenges = chall; } ne_free(hdr); return !success;}/* The body reader callback. */static void auth_body_reader(void *cookie, const char *block, size_t length){ struct ne_md5_ctx *ctx = cookie; NE_DEBUG(NE_DBG_HTTPAUTH, "Digesting %" NE_FMT_SIZE_T " bytes of response body.\n", length); ne_md5_process_bytes(block, length, ctx);}static void ah_create(ne_request *req, void *session, const char *method, const char *uri){ auth_session *sess = session; int is_connect = strcmp(method, "CONNECT") == 0; if (sess->context == AUTH_ANY || (is_connect && sess->context == AUTH_CONNECT) || (!is_connect && sess->context == AUTH_NOTCONNECT)) { struct auth_request *areq = ne_calloc(sizeof *areq); NE_DEBUG(NE_DBG_HTTPAUTH, "ah_create, for %s\n", sess->spec->resp_hdr); areq->method = method; areq->uri = uri; areq->request = req; ne_add_response_header_handler(req, sess->spec->resp_hdr, ne_duplicate_header, &areq->auth_hdr); ne_add_response_header_handler(req, sess->spec->resp_info_hdr, ne_duplicate_header, &areq->auth_info_hdr); sess->attempt = 0; ne_set_request_private(req, sess->spec->id, areq); }}static void ah_pre_send(ne_request *r, void *cookie, ne_buffer *request){ auth_session *sess = cookie; struct auth_request *req = ne_get_request_private(r, sess->spec->id); if (!sess->can_handle || !req) { NE_DEBUG(NE_DBG_HTTPAUTH, "Not handling session.\n"); } else { char *value; NE_DEBUG(NE_DBG_HTTPAUTH, "Handling."); req->will_handle = 1; if (sess->qop == auth_qop_auth_int) { /* Digest mode / qop=auth-int: take an MD5 digest of the * response body. */ ne_md5_init_ctx(&req->response_body); ne_add_response_body_reader(req->request, ne_accept_always, auth_body_reader, &req->response_body); } switch(sess->scheme) { case auth_scheme_basic: value = request_basic(sess); break; case auth_scheme_digest: value = request_digest(sess, req); break;#ifdef HAVE_GSSAPI case auth_scheme_gssapi: value = request_gssapi(sess); break;#endif default: value = NULL; break; } if (value != NULL) { ne_buffer_concat(request, sess->spec->req_hdr, ": ", value, NULL); ne_free(value); } }}#define SAFELY(x) ((x) != NULL?(x):"null")static int ah_post_send(ne_request *req, void *cookie, const ne_status *status){ auth_session *sess = cookie; struct auth_request *areq = ne_get_request_private(req, sess->spec->id); int ret = NE_OK; if (!areq) return NE_OK; NE_DEBUG(NE_DBG_HTTPAUTH, "ah_post_send (#%d), code is %d (want %d), %s is %s\n", sess->attempt, status->code, sess->spec->status_code, sess->spec->resp_hdr, SAFELY(areq->auth_hdr)); if (areq->auth_info_hdr != NULL && verify_response(areq, sess, areq->auth_info_hdr)) { NE_DEBUG(NE_DBG_HTTPAUTH, "Response authentication invalid.\n"); ne_set_error(sess->sess, "%s", _(sess->spec->fail_msg)); ret = NE_ERROR; } else if ((status->code == sess->spec->status_code || (status->code == 401 && sess->context == AUTH_CONNECT)) && areq->auth_hdr != NULL) { /* note above: allow a 401 in response to a CONNECT request * from a proxy since some buggy proxies send that. */ NE_DEBUG(NE_DBG_HTTPAUTH, "Got challenge with code %d.\n", status->code); if (!auth_challenge(sess, areq->auth_hdr)) { ret = NE_RETRY; } else { clean_session(sess); ret = sess->spec->fail_code; } } NE_FREE(areq->auth_info_hdr); NE_FREE(areq->auth_hdr); return ret;}static void ah_destroy(ne_request *req, void *session){ auth_session *sess = session; struct auth_request *areq = ne_get_request_private(req, sess->spec->id); if (areq) ne_free(areq);}static void free_auth(void *cookie){ auth_session *sess = cookie; clean_session(sess); ne_free(sess);}static void auth_register(ne_session *sess, int isproxy, const struct auth_class *ahc, const char *id, ne_auth_creds creds, void *userdata) { auth_session *ahs = ne_calloc(sizeof *ahs); ahs->creds = creds; ahs->userdata = userdata; ahs->sess = sess; ahs->spec = ahc; if (strcmp(ne_get_scheme(sess), "https") == 0) ahs->context = isproxy ? AUTH_CONNECT : AUTH_NOTCONNECT; else ahs->context = AUTH_ANY; /* Register hooks */ ne_hook_create_request(sess, ah_create, ahs); ne_hook_pre_send(sess, ah_pre_send, ahs); ne_hook_post_send(sess, ah_post_send, ahs); ne_hook_destroy_request(sess, ah_destroy, ahs); ne_hook_destroy_session(sess, free_auth, ahs); ne_set_session_private(sess, id, ahs);}void ne_set_server_auth(ne_session *sess, ne_auth_creds creds, void *userdata){ auth_register(sess, 0, &ah_server_class, HOOK_SERVER_ID, creds, userdata);}void ne_set_proxy_auth(ne_session *sess, ne_auth_creds creds, void *userdata){ auth_register(sess, 1, &ah_proxy_class, HOOK_PROXY_ID, creds, userdata);}void ne_forget_auth(ne_session *sess){ auth_session *as; if ((as = ne_get_session_private(sess, HOOK_SERVER_ID)) != NULL) clean_session(as); if ((as = ne_get_session_private(sess, HOOK_PROXY_ID)) != NULL) clean_session(as);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -