static int http_da_parse(struct soap *soap) { struct http_da_data *data = (struct http_da_data*)soap_lookup_plugin(soap, http_da_id); if (!data) return SOAP_PLUGIN_ERROR; data->qop = NULL; /* HTTP GET w/o body with qop=auth-int still requires a digest */ md5_handler(soap, &data->context, MD5_INIT, NULL, 0); md5_handler(soap, &data->context, MD5_FINAL, data->digest, 0); if ((soap->error = data->fparse(soap))) return soap->error; if (data->qop && !soap_tag_cmp(data->qop, "auth-int")) { if (soap->fpreparerecv != http_da_preparerecv) { data->fpreparerecv = soap->fpreparerecv; soap->fpreparerecv = http_da_preparerecv; } if (soap->fpreparefinalrecv != http_da_preparefinalrecv) { data->fpreparefinalrecv = soap->fpreparefinalrecv; soap->fpreparefinalrecv = http_da_preparefinalrecv; } md5_handler(soap, &data->context, MD5_INIT, NULL, 0); } return SOAP_OK; }
static int http_da_prepareinit(struct soap *soap) { struct http_da_data *data = (struct http_da_data*)soap_lookup_plugin(soap, http_da_id); if (!data) return SOAP_PLUGIN_ERROR; if ((soap->mode & SOAP_IO) != SOAP_IO_STORE && (soap->mode & (SOAP_ENC_DIME | SOAP_ENC_MIME))) { /* TODO: handle attachments automatically, does not work yet */ soap->mode &= ~SOAP_IO; soap->mode |= SOAP_IO_STORE; } else { if (soap->fpreparerecv == http_da_preparerecv) soap->fpreparerecv = data->fpreparerecv; if (soap->fdisconnect == http_da_disconnect) soap->fdisconnect = data->fdisconnect; if (soap->userid && soap->passwd) { md5_handler(soap, &data->context, MD5_INIT, NULL, 0); if (soap->fpreparesend != http_da_preparesend) { data->fpreparesend = soap->fpreparesend; soap->fpreparesend = http_da_preparesend; } } if (data->fprepareinit) return data->fprepareinit(soap); } return SOAP_OK; }
static void http_da_delete(struct soap *soap, struct soap_plugin *p) { if (((struct http_da_data*)p->data)->context) md5_handler(soap, &((struct http_da_data*)p->data)->context, MD5_DELETE, NULL, 0); if (p->data) SOAP_FREE(soap, p->data); }
static void http_md5_delete(struct soap *soap, struct soap_plugin *p) { struct http_md5_data *data = (struct http_md5_data*)soap_lookup_plugin(soap, http_md5_id); if (data) { md5_handler(soap, &data->context, MD5_DELETE, NULL, 0); SOAP_FREE(soap, data); } }
static int http_md5_preparerecv(struct soap *soap, const char *buf, size_t len) { struct http_md5_data *data = (struct http_md5_data*)soap_lookup_plugin(soap, http_md5_id); if (!data) return SOAP_PLUGIN_ERROR; md5_handler(soap, &data->context, MD5_UPDATE, (char*)buf, len); if (data->fpreparerecv) return data->fpreparerecv(soap, buf, len); return SOAP_OK; }
static int http_da_parse_header(struct soap *soap, const char *key, const char *val) { struct http_da_data *data = (struct http_da_data*)soap_lookup_plugin(soap, http_da_id); if (!data) return SOAP_PLUGIN_ERROR; /* check if server received Authorization Digest HTTP header from client */ if (!soap_tag_cmp(key, "Authorization") && !soap_tag_cmp(val, "Digest *")) { soap->authrealm = soap_strdup(soap, soap_get_header_attribute(soap, val + 7, "realm")); soap->userid = soap_strdup(soap, soap_get_header_attribute(soap, val + 7, "username")); soap->passwd = NULL; data->nonce = soap_strdup(soap, soap_get_header_attribute(soap, val + 7, "nonce")); data->opaque = soap_strdup(soap, soap_get_header_attribute(soap, val + 7, "opaque")); data->qop = soap_strdup(soap, soap_get_header_attribute(soap, val + 7, "qop")); data->alg = NULL; data->ncount = soap_strdup(soap, soap_get_header_attribute(soap, val + 7, "nc")); data->cnonce = soap_strdup(soap, soap_get_header_attribute(soap, val + 7, "cnonce")); data->response = soap_strdup(soap, soap_get_header_attribute(soap, val + 7, "response")); if (data->qop && !soap_tag_cmp(data->qop, "auth-int")) { if (soap->fpreparerecv != http_da_preparerecv) { data->fpreparerecv = soap->fpreparerecv; soap->fpreparerecv = http_da_preparerecv; } if (soap->fdisconnect != http_da_disconnect) { data->fdisconnect = soap->fdisconnect; soap->fdisconnect = http_da_disconnect; } md5_handler(soap, &data->context, MD5_INIT, NULL, 0); } return SOAP_OK; } /* check if client received WWW-Authenticate Digest HTTP header from server */ if (!soap_tag_cmp(key, "WWW-Authenticate") && !soap_tag_cmp(val, "Digest *")) { soap->authrealm = soap_strdup(soap, soap_get_header_attribute(soap, val + 7, "realm")); data->nonce = soap_strdup(soap, soap_get_header_attribute(soap, val + 7, "nonce")); data->opaque = soap_strdup(soap, soap_get_header_attribute(soap, val + 7, "opaque")); data->qop = soap_strdup(soap, soap_get_header_attribute(soap, val + 7, "qop")); data->alg = soap_strdup(soap, soap_get_header_attribute(soap, val + 7, "algorithm")); data->nc = 1; data->ncount = NULL; data->cnonce = NULL; data->response = NULL; return SOAP_OK; } return data->fparsehdr(soap, key, val); }
static int http_md5_post_header(struct soap *soap, const char *key, const char *val) { struct http_md5_data *data = (struct http_md5_data*)soap_lookup_plugin(soap, http_md5_id); char buf64[25]; /* 24 base64 chars + '\0' */ int err; if (!data) return SOAP_PLUGIN_ERROR; if (!key) /* last line */ { if ((err = md5_handler(soap, &data->context, MD5_FINAL, data->digest, 0))) return err; data->fposthdr(soap, "Content-MD5", soap_s2base64(soap, (unsigned char*)data->digest, buf64, 16)); } return data->fposthdr(soap, key, val); }
static int http_md5_disconnect(struct soap *soap) { struct http_md5_data *data = (struct http_md5_data*)soap_lookup_plugin(soap, http_md5_id); char digest[16]; if (!data) return SOAP_PLUGIN_ERROR; md5_handler(soap, &data->context, MD5_FINAL, digest, 0); soap->fpreparerecv = data->fpreparerecv; soap->fdisconnect = data->fdisconnect; if (memcmp(digest, data->digest, 16)) return soap_sender_fault(soap, "MD5 digest mismatch: message corrupted", NULL); if (soap->fdisconnect) return soap->fdisconnect(soap); return SOAP_OK; }
static int http_da_disconnect(struct soap *soap) { struct http_da_data *data = (struct http_da_data*)soap_lookup_plugin(soap, http_da_id); if (!data) return SOAP_PLUGIN_ERROR; md5_handler(soap, &data->context, MD5_FINAL, data->digest, 0); soap->fpreparerecv = data->fpreparerecv; soap->fdisconnect = data->fdisconnect; if (soap->fdisconnect) return soap->fdisconnect(soap); return SOAP_OK; }
static int http_da_prepareinitsend(struct soap *soap) { struct http_da_data *data = (struct http_da_data*)soap_lookup_plugin(soap, http_da_id); if (!data) return SOAP_PLUGIN_ERROR; if ((soap->mode & SOAP_IO) != SOAP_IO_STORE && (soap->mode & (SOAP_ENC_DIME | SOAP_ENC_MIME))) { /* support non-streaming MIME/DIME attachments by buffering the message */ soap->omode &= ~SOAP_IO; soap->omode |= SOAP_IO_STORE; soap->mode &= ~SOAP_IO; soap->mode |= SOAP_IO_STORE; } else { if ((soap->userid && soap->passwd) || (soap->proxy_userid && soap->proxy_passwd)) { md5_handler(soap, &data->context, MD5_INIT, NULL, 0); if (soap->fpreparesend != http_da_preparesend) { data->fpreparesend = soap->fpreparesend; soap->fpreparesend = http_da_preparesend; } if ((soap->mode & SOAP_IO) == SOAP_IO_CHUNK) soap->mode |= SOAP_IO_LENGTH; } } if (data->fprepareinitsend) return data->fprepareinitsend(soap); return SOAP_OK; }
static void http_da_calc_response(struct soap *soap, void **context, char HA1hex[33], char *nonce, char *ncount, char *cnonce, char *qop, char *method, char *uri, char entityHAhex[33], char response[33]) { char HA2[16], HA2hex[33], responseHA[16]; md5_handler(soap, context, MD5_INIT, NULL, 0); md5_handler(soap, context, MD5_UPDATE, method, strlen(method)); md5_handler(soap, context, MD5_UPDATE, ":", 1); md5_handler(soap, context, MD5_UPDATE, uri, strlen(uri)); if (!soap_tag_cmp(qop, "auth-int")) { md5_handler(soap, context, MD5_UPDATE, ":", 1); md5_handler(soap, context, MD5_UPDATE, entityHAhex, 32); } md5_handler(soap, context, MD5_FINAL, HA2, 0); soap_s2hex(soap, (unsigned char*)HA2, HA2hex, 16); md5_handler(soap, context, MD5_INIT, NULL, 0); md5_handler(soap, context, MD5_UPDATE, HA1hex, 32); md5_handler(soap, context, MD5_UPDATE, ":", 1); md5_handler(soap, context, MD5_UPDATE, nonce, strlen(nonce)); md5_handler(soap, context, MD5_UPDATE, ":", 1); if (qop && *qop) { md5_handler(soap, context, MD5_UPDATE, ncount, strlen(ncount)); md5_handler(soap, context, MD5_UPDATE, ":", 1); md5_handler(soap, context, MD5_UPDATE, cnonce, strlen(cnonce)); md5_handler(soap, context, MD5_UPDATE, ":", 1); md5_handler(soap, context, MD5_UPDATE, qop, strlen(qop)); md5_handler(soap, context, MD5_UPDATE, ":", 1); } md5_handler(soap, context, MD5_UPDATE, HA2hex, 32); md5_handler(soap, context, MD5_FINAL, responseHA, 0); soap_s2hex(soap, (unsigned char*)responseHA, response, 16); }
static void http_da_calc_HA1(struct soap *soap, void **context, char *alg, char *userid, char *realm, char *passwd, char *nonce, char *cnonce, char HA1hex[33]) { char HA1[16]; md5_handler(soap, context, MD5_INIT, NULL, 0); md5_handler(soap, context, MD5_UPDATE, userid, strlen(userid)); md5_handler(soap, context, MD5_UPDATE, ":", 1); md5_handler(soap, context, MD5_UPDATE, realm, strlen(realm)); md5_handler(soap, context, MD5_UPDATE, ":", 1); md5_handler(soap, context, MD5_UPDATE, passwd, strlen(passwd)); md5_handler(soap, context, MD5_FINAL, HA1, 0); if (alg && !soap_tag_cmp(alg, "MD5-sess")) { md5_handler(soap, context, MD5_INIT, NULL, 0); md5_handler(soap, context, MD5_UPDATE, HA1, 16); md5_handler(soap, context, MD5_UPDATE, ":", 1); md5_handler(soap, context, MD5_UPDATE, nonce, strlen(nonce)); md5_handler(soap, context, MD5_UPDATE, ":", 1); md5_handler(soap, context, MD5_UPDATE, cnonce, strlen(cnonce)); md5_handler(soap, context, MD5_FINAL, HA1, 0); }; soap_s2hex(soap, (unsigned char*)HA1, HA1hex, 16); };
static int http_da_post_header(struct soap *soap, const char *key, const char *val) { struct http_da_data *data = (struct http_da_data*)soap_lookup_plugin(soap, http_da_id); if (!data) return SOAP_PLUGIN_ERROR; /* client's HTTP Authorization response */ if (key && !strcmp(key, "Authorization")) { char HA1[33], entityHAhex[33], response[33]; char cnonce[HTTP_DA_NONCELEN]; char ncount[9]; char *qop, *method; md5_handler(soap, &data->context, MD5_FINAL, data->digest, 0); http_da_calc_nonce(soap, cnonce); http_da_calc_HA1(soap, &data->context, data->alg, soap->userid, soap->authrealm, soap->passwd, data->nonce, cnonce, HA1); if (data->qop && !soap_tag_cmp(data->qop, "*auth-int*")) { qop = "auth-int"; soap_s2hex(soap, (unsigned char*)data->digest, entityHAhex, 16); } else if (data->qop) qop = "auth"; else qop = NULL; if (soap->status == SOAP_GET) method = "GET"; else method = "POST"; sprintf(ncount, "%8.8lx", data->nc++); http_da_calc_response(soap, &data->context, HA1, data->nonce, ncount, cnonce, qop, method, soap->path, entityHAhex, response); sprintf(soap->tmpbuf, "Digest realm=\"%s\", username=\"%s\", nonce=\"%s\", uri=\"%s\", nc=%s, cnonce=\"%s\", response=\"%s\"", soap->authrealm, soap->userid, data->nonce, soap->path, ncount, cnonce, response); if (data->opaque) sprintf(soap->tmpbuf + strlen(soap->tmpbuf), ", opaque=\"%s\"", data->opaque); if (qop) sprintf(soap->tmpbuf + strlen(soap->tmpbuf), ", qop=\"%s\"", qop); return data->fposthdr(soap, key, soap->tmpbuf); } /* server's HTTP Authorization response */ if (key && !strcmp(key, "WWW-Authenticate")) { char nonce[HTTP_DA_NONCELEN]; char opaque[HTTP_DA_OPAQUELEN]; http_da_calc_nonce(soap, nonce); http_da_calc_opaque(soap, opaque); http_da_session_start(soap->authrealm, nonce, opaque); sprintf(soap->tmpbuf, "Digest realm=\"%s\", qop=\"auth,auth-int\", nonce=\"%s\", opaque=\"%s\"", soap->authrealm, nonce, opaque); return data->fposthdr(soap, key, soap->tmpbuf); } return data->fposthdr(soap, key, val); }
static int http_da_post_header(struct soap *soap, const char *key, const char *val) { struct http_da_data *data = (struct http_da_data*)soap_lookup_plugin(soap, http_da_id); if (!data) return SOAP_PLUGIN_ERROR; /* client's HTTP Authorization request */ if (key && (!strcmp(key, "Authorization") || !strcmp(key, "Proxy-Authorization"))) { char HA1[33], entityHAhex[33], response[33]; char cnonce[HTTP_DA_NONCELEN]; char ncount[9]; const char *qop, *method; const char *userid = (*key == 'A' ? soap->userid : soap->proxy_userid); const char *passwd = (*key == 'A' ? soap->passwd : soap->proxy_passwd); md5_handler(soap, &data->context, MD5_FINAL, data->digest, 0); if (!userid || !passwd || !soap->authrealm || !data->nonce) { #ifdef SOAP_DEBUG fprintf(stderr, "Debug message: authentication header failed, missing authentication data\n"); #endif return SOAP_OK; } http_da_calc_nonce(soap, cnonce); http_da_calc_HA1(soap, &data->context, data->alg, userid, soap->authrealm, passwd, data->nonce, cnonce, HA1); if (data->qop && !soap_tag_cmp(data->qop, "*auth-int*")) { qop = "auth-int"; soap_s2hex(soap, (unsigned char*)data->digest, entityHAhex, 16); } else if (data->qop) qop = "auth"; else qop = NULL; if (soap->status == SOAP_GET) method = "GET"; else if (soap->status == SOAP_CONNECT) method = "CONNECT"; else method = "POST"; #ifdef HAVE_SNPRINTF soap_snprintf(ncount, sizeof(ncount), "%8.8lx", data->nc++); #else sprintf(ncount, "%8.8lx", data->nc++); #endif http_da_calc_response(soap, &data->context, HA1, data->nonce, ncount, cnonce, qop, method, soap->path, entityHAhex, response); #ifdef HAVE_SNPRINTF soap_snprintf(soap->tmpbuf, sizeof(soap->tmpbuf), "Digest realm=\"%s\", username=\"%s\", nonce=\"%s\", uri=\"%s\", nc=%s, cnonce=\"%s\", response=\"%s\"", soap->authrealm, userid, data->nonce, soap->path, ncount, cnonce, response); #else sprintf(soap->tmpbuf, "Digest realm=\"%s\", username=\"%s\", nonce=\"%s\", uri=\"%s\", nc=%s, cnonce=\"%s\", response=\"%s\"", soap->authrealm, userid, data->nonce, soap->path, ncount, cnonce, response); #endif if (data->opaque) #ifdef HAVE_SNPRINTF soap_snprintf(soap->tmpbuf + strlen(soap->tmpbuf), sizeof(soap->tmpbuf) - strlen(soap->tmpbuf), ", opaque=\"%s\"", data->opaque); #else sprintf(soap->tmpbuf + strlen(soap->tmpbuf), ", opaque=\"%s\"", data->opaque); #endif if (qop) #ifdef HAVE_SNPRINTF soap_snprintf(soap->tmpbuf + strlen(soap->tmpbuf), sizeof(soap->tmpbuf) - strlen(soap->tmpbuf), ", qop=\"%s\"", qop); #else sprintf(soap->tmpbuf + strlen(soap->tmpbuf), ", qop=\"%s\"", qop); #endif return data->fposthdr(soap, key, soap->tmpbuf); } /* server's HTTP Authorization challenge/response */ if (key && (!strcmp(key, "WWW-Authenticate") || !strcmp(key, "Proxy-Authenticate"))) { char nonce[HTTP_DA_NONCELEN]; char opaque[HTTP_DA_OPAQUELEN]; http_da_calc_nonce(soap, nonce); http_da_calc_opaque(soap, opaque); http_da_session_start(soap->authrealm, nonce, opaque); #ifdef HAVE_SNPRINTF soap_snprintf(soap->tmpbuf, sizeof(soap->tmpbuf), "Digest realm=\"%s\", qop=\"auth,auth-int\", nonce=\"%s\", opaque=\"%s\"", soap->authrealm, nonce, opaque); #else sprintf(soap->tmpbuf, "Digest realm=\"%s\", qop=\"auth,auth-int\", nonce=\"%s\", opaque=\"%s\"", soap->authrealm, nonce, opaque); #endif return data->fposthdr(soap, key, soap->tmpbuf); } return data->fposthdr(soap, key, val); }