📄 ne_auth.c
字号:
{ struct ne_md5_ctx tmp; unsigned char tmp_md5[16]; char password[NE_ABUFSIZ]; /* Verify they've given us the right bits. */ if (parms->alg == auth_alg_unknown || ((parms->alg == auth_alg_md5_sess) && !(parms->qop_auth || parms->qop_auth_int)) || parms->realm==NULL || parms->nonce==NULL) { NE_DEBUG(NE_DBG_HTTPAUTH, "Invalid challenge."); return -1; } if (parms->stale) { /* Just a stale response, don't need to get a new username/password */ NE_DEBUG(NE_DBG_HTTPAUTH, "Stale digest challenge.\n"); } else { /* Forget the old session details */ NE_DEBUG(NE_DBG_HTTPAUTH, "In digest challenge.\n"); clean_session(sess); sess->realm = ne_strdup(parms->realm); /* Not a stale response: really need user authentication */ if (get_credentials(sess, password)) { /* Failed to get credentials */ return -1; } } sess->alg = parms->alg; sess->scheme = auth_scheme_digest; sess->nonce = ne_strdup(parms->nonce); sess->cnonce = get_cnonce(); /* TODO: add domain handling. */ if (parms->opaque != NULL) { sess->opaque = ne_strdup(parms->opaque); /* don't strip the quotes */ } if (parms->got_qop) { /* What type of qop are we to apply to the message? */ NE_DEBUG(NE_DBG_HTTPAUTH, "Got qop directive.\n"); sess->nonce_count = 0; if (parms->qop_auth_int) { sess->qop = auth_qop_auth_int; } else { sess->qop = auth_qop_auth; } } else { /* No qop at all/ */ sess->qop = auth_qop_none; } if (!parms->stale) { /* Calculate H(A1). * tmp = H(unq(username-value) ":" unq(realm-value) ":" passwd) */ NE_DEBUG(NE_DBG_HTTPAUTH, "Calculating H(A1).\n"); ne_md5_init_ctx(&tmp); ne_md5_process_bytes(sess->username, strlen(sess->username), &tmp); ne_md5_process_bytes(":", 1, &tmp); ne_md5_process_bytes(sess->realm, strlen(sess->realm), &tmp); ne_md5_process_bytes(":", 1, &tmp); ne_md5_process_bytes(password, strlen(password), &tmp); memset(password, 0, sizeof password); /* done with that. */ ne_md5_finish_ctx(&tmp, tmp_md5); if (sess->alg == auth_alg_md5_sess) { unsigned char a1_md5[16]; struct ne_md5_ctx a1; char tmp_md5_ascii[33]; /* Now we calculate the SESSION H(A1) * A1 = H(...above...) ":" unq(nonce-value) ":" unq(cnonce-value) */ ne_md5_to_ascii(tmp_md5, tmp_md5_ascii); ne_md5_init_ctx(&a1); ne_md5_process_bytes(tmp_md5_ascii, 32, &a1); ne_md5_process_bytes(":", 1, &a1); ne_md5_process_bytes(sess->nonce, strlen(sess->nonce), &a1); ne_md5_process_bytes(":", 1, &a1); ne_md5_process_bytes(sess->cnonce, strlen(sess->cnonce), &a1); ne_md5_finish_ctx(&a1, a1_md5); ne_md5_to_ascii(a1_md5, sess->h_a1); NE_DEBUG(NE_DBG_HTTPAUTH, "Session H(A1) is [%s]\n", sess->h_a1); } else { ne_md5_to_ascii(tmp_md5, sess->h_a1); NE_DEBUG(NE_DBG_HTTPAUTH, "H(A1) is [%s]\n", sess->h_a1); } } NE_DEBUG(NE_DBG_HTTPAUTH, "I like this Digest challenge.\n"); return 0;}/* callback for ne_pull_request_body. */static int digest_body(void *userdata, const char *buf, size_t count){ struct ne_md5_ctx *ctx = userdata; ne_md5_process_bytes(buf, count, ctx); return 0;}/* Return Digest authentication credentials header value for the given * session. */static char *request_digest(auth_session *sess, struct auth_request *req) { struct ne_md5_ctx a2, rdig; unsigned char a2_md5[16], rdig_md5[16]; char a2_md5_ascii[33], rdig_md5_ascii[33]; char nc_value[9] = {0}; const char *qop_value; /* qop-value */ ne_buffer *ret; /* Increase the nonce-count */ if (sess->qop != auth_qop_none) { sess->nonce_count++; ne_snprintf(nc_value, 9, "%08x", sess->nonce_count); NE_DEBUG(NE_DBG_HTTPAUTH, "Nonce count is %u, nc is [%s]\n", sess->nonce_count, nc_value); } qop_value = sess->qop == auth_qop_auth_int ? "auth-int" : "auth"; /* Calculate H(A2). */ ne_md5_init_ctx(&a2); ne_md5_process_bytes(req->method, strlen(req->method), &a2); ne_md5_process_bytes(":", 1, &a2); ne_md5_process_bytes(req->uri, strlen(req->uri), &a2); if (sess->qop == auth_qop_auth_int) { struct ne_md5_ctx body; char tmp_md5_ascii[33]; unsigned char tmp_md5[16]; ne_md5_init_ctx(&body); /* Calculate H(entity-body): pull in the request body from * where-ever it is coming from, and calculate the digest. */ NE_DEBUG(NE_DBG_HTTPAUTH, "Digesting request body...\n"); ne_pull_request_body(req->request, digest_body, &body); NE_DEBUG(NE_DBG_HTTPAUTH, "Digesting request body done.\n"); ne_md5_finish_ctx(&body, tmp_md5); ne_md5_to_ascii(tmp_md5, tmp_md5_ascii); NE_DEBUG(NE_DBG_HTTPAUTH, "H(entity-body) is [%s]\n", tmp_md5_ascii); /* Append to A2 */ ne_md5_process_bytes(":", 1, &a2); ne_md5_process_bytes(tmp_md5_ascii, 32, &a2); } ne_md5_finish_ctx(&a2, a2_md5); ne_md5_to_ascii(a2_md5, a2_md5_ascii); NE_DEBUG(NE_DBG_HTTPAUTH, "H(A2): %s\n", a2_md5_ascii); NE_DEBUG(NE_DBG_HTTPAUTH, "Calculating Request-Digest.\n"); /* Now, calculation of the Request-Digest. * The first section is the regardless of qop value * H(A1) ":" unq(nonce-value) ":" */ ne_md5_init_ctx(&rdig); /* Use the calculated H(A1) */ ne_md5_process_bytes(sess->h_a1, 32, &rdig); ne_md5_process_bytes(":", 1, &rdig); ne_md5_process_bytes(sess->nonce, strlen(sess->nonce), &rdig); ne_md5_process_bytes(":", 1, &rdig); if (sess->qop != auth_qop_none) { /* Add on: * nc-value ":" unq(cnonce-value) ":" unq(qop-value) ":" */ NE_DEBUG(NE_DBG_HTTPAUTH, "Have qop directive, digesting: [%s:%s:%s]\n", nc_value, sess->cnonce, qop_value); ne_md5_process_bytes(nc_value, 8, &rdig); ne_md5_process_bytes(":", 1, &rdig); ne_md5_process_bytes(sess->cnonce, strlen(sess->cnonce), &rdig); ne_md5_process_bytes(":", 1, &rdig); /* Store a copy of this structure (see note below) */ sess->stored_rdig = rdig; ne_md5_process_bytes(qop_value, strlen(qop_value), &rdig); ne_md5_process_bytes(":", 1, &rdig); } else { /* Store a copy of this structure... we do this because the * calculation of the rspauth= field in the Auth-Info header * is the same as this digest, up to this point. */ sess->stored_rdig = rdig; } /* And finally, H(A2) */ ne_md5_process_bytes(a2_md5_ascii, 32, &rdig); ne_md5_finish_ctx(&rdig, rdig_md5); ne_md5_to_ascii(rdig_md5, rdig_md5_ascii); ret = ne_buffer_create(); ne_buffer_concat(ret, "Digest username=\"", sess->username, "\", " "realm=\"", sess->realm, "\", " "nonce=\"", sess->nonce, "\", " "uri=\"", req->uri, "\", " "response=\"", rdig_md5_ascii, "\", " "algorithm=\"", sess->alg == auth_alg_md5 ? "MD5" : "MD5-sess", "\"", NULL); if (sess->opaque != NULL) { ne_buffer_concat(ret, ", opaque=\"", sess->opaque, "\"", NULL); } if (sess->qop != auth_qop_none) { /* Add in cnonce and nc-value fields */ ne_buffer_concat(ret, ", cnonce=\"", sess->cnonce, "\", " "nc=", nc_value, ", " "qop=\"", qop_value, "\"", NULL); } ne_buffer_zappend(ret, "\r\n"); NE_DEBUG(NE_DBG_HTTPAUTH, "Digest request header is %s\n", ret->data); return ne_buffer_finish(ret);}/* Parse line of comma-separated key-value pairs. If 'ischall' == 1, * then also return a leading space-separated token, as *value == NULL. * Otherwise, if return value is 0, *key and *value will be non-NULL. * If return value is non-zero, parsing has ended. */static int tokenize(char **hdr, char **key, char **value, int ischall){ char *pnt = *hdr; enum { BEFORE_EQ, AFTER_EQ, AFTER_EQ_QUOTED } state = BEFORE_EQ; if (**hdr == '\0') return 1; *key = NULL; do { switch (state) { case BEFORE_EQ: if (*pnt == '=') { if (*key == NULL) return -1; *pnt = '\0'; *value = pnt + 1; state = AFTER_EQ; } else if (*pnt == ' ' && ischall && *key != NULL) { *value = NULL; *pnt = '\0'; *hdr = pnt + 1; return 0; } else if (*key == NULL && strchr(" \r\n\t", *pnt) == NULL) { *key = pnt; } break; case AFTER_EQ: if (*pnt == ',') { *pnt = '\0'; *hdr = pnt + 1; return 0; } else if (*pnt == '\"') { state = AFTER_EQ_QUOTED; } break; case AFTER_EQ_QUOTED: if (*pnt == '\"') { state = AFTER_EQ; } break; } } while (*++pnt != '\0'); if (state == BEFORE_EQ && ischall && *key != NULL) { *value = NULL; } *hdr = pnt; /* End of string: */ return 0;}/* Pass this the value of the 'Authentication-Info:' header field, if * one is received. * Returns: * 0 if it gives a valid authentication for the server * non-zero otherwise (don't believe the response in this case!). */static int verify_response(struct auth_request *req, auth_session *sess, const char *value) { char *hdr, *pnt, *key, *val; auth_qop qop = 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 */ *qop_value = NULL; unsigned int nonce_count; int okay; if (!req->will_handle) { /* Ignore it */ return 0; } if (sess->scheme != auth_scheme_digest) { NE_DEBUG(NE_DBG_HTTPAUTH, "Found Auth-Info header not in response " " to Digest credentials - dodgy.\n"); return -1; } pnt = hdr = ne_strdup(value); NE_DEBUG(NE_DBG_HTTPAUTH, "Auth-Info header: %s\n", value); while (tokenize(&pnt, &key, &val, 0) == 0) { val = ne_shave(val, "\""); NE_DEBUG(NE_DBG_HTTPAUTH, "Pair: [%s] = [%s]\n", key, val); if (strcasecmp(key, "qop") == 0) { qop_value = val; if (strcasecmp(val, "auth-int") == 0) { qop = auth_qop_auth_int; } else if (strcasecmp(val, "auth") == 0) { qop = auth_qop_auth; } else { qop = auth_qop_none; } } else if (strcasecmp(key, "nextnonce") == 0) { nextnonce = val; } else if (strcasecmp(key, "rspauth") == 0) { rspauth = val; } else if (strcasecmp(key, "cnonce") == 0) { cnonce = val; } else if (strcasecmp(key, "nc") == 0) { nc = val; if (sscanf(val, "%x", &nonce_count) != 1) { NE_DEBUG(NE_DBG_HTTPAUTH, "Couldn't find nonce count.\n"); } else { NE_DEBUG(NE_DBG_HTTPAUTH, "Got nonce_count: %u\n", nonce_count); } } } /* Presume the worst */ okay = -1; if ((qop != auth_qop_none) && (qop_value != NULL)) { if ((rspauth == NULL) || (cnonce == NULL) || (nc == NULL)) { NE_DEBUG(NE_DBG_HTTPAUTH, "Missing rspauth, cnonce or nc with qop.\n"); } else { /* Have got rspauth, cnonce and nc */ if (strcmp(cnonce, sess->cnonce) != 0) { NE_DEBUG(NE_DBG_HTTPAUTH, "Response cnonce doesn't match.\n"); } else if (nonce_count != sess->nonce_count) { NE_DEBUG(NE_DBG_HTTPAUTH, "Response nonce count doesn't match.\n"); } else { /* Calculate and check the response-digest value. * joe: IMO the spec is slightly ambiguous as to whether * we use the qop which WE sent, or the qop which THEY * sent... */ struct ne_md5_ctx a2; unsigned char a2_md5[16], rdig_md5[16]; char a2_md5_ascii[33], rdig_md5_ascii[33]; NE_DEBUG(NE_DBG_HTTPAUTH, "Calculating response-digest.\n"); /* First off, H(A2) again. */ ne_md5_init_ctx(&a2); ne_md5_process_bytes(":", 1, &a2); ne_md5_process_bytes(req->uri, strlen(req->uri), &a2); if (qop == auth_qop_auth_int) { unsigned char heb_md5[16]; char heb_md5_ascii[33]; /* Add on ":" H(entity-body) */ ne_md5_finish_ctx(&req->response_body, heb_md5); ne_md5_to_ascii(heb_md5, heb_md5_ascii); ne_md5_process_bytes(":", 1, &a2); ne_md5_process_bytes(heb_md5_ascii, 32, &a2); NE_DEBUG(NE_DBG_HTTPAUTH, "Digested [:%s]\n", heb_md5_ascii); } ne_md5_finish_ctx(&a2, a2_md5); ne_md5_to_ascii(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 save digesting them again. * */ if (qop != auth_qop_none) { /* Add in qop-value */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -