enum kcgi_err kworker_auth_parent(int fd, struct khttpauth *auth) { enum kcgi_err ke; if (fullread(fd, &auth->type, sizeof(enum kauth), 0, &ke) < 0) return(ke); switch (auth->type) { case (KAUTH_DIGEST): if (fullread(fd, &auth->authorised, sizeof(int), 0, &ke) < 0) return(ke); if ( ! auth->authorised) break; if (fullread(fd, &auth->d.digest.alg, sizeof(enum khttpalg), 0, &ke) < 0) return(ke); if (fullread(fd, &auth->d.digest.qop, sizeof(enum khttpqop), 0, &ke) < 0) return(ke); if (KCGI_OK != (ke = fullreadword(fd, &auth->d.digest.user))) return(ke); if (KCGI_OK != (ke = fullreadword(fd, &auth->d.digest.uri))) return(ke); if (KCGI_OK != (ke = fullreadword(fd, &auth->d.digest.realm))) return(ke); if (KCGI_OK != (ke = fullreadword(fd, &auth->d.digest.nonce))) return(ke); if (KCGI_OK != (ke = fullreadword(fd, &auth->d.digest.cnonce))) return(ke); if (KCGI_OK != (ke = fullreadword(fd, &auth->d.digest.response))) return(ke); if (fullread(fd, &auth->d.digest.count, sizeof(size_t), 0, &ke) < 0) return(ke); if (KCGI_OK != (ke = fullreadword(fd, &auth->d.digest.opaque))) return(ke); break; case (KAUTH_BASIC): if (fullread(fd, &auth->authorised, sizeof(int), 0, &ke) < 0) return(ke); if ( ! auth->authorised) break; if (KCGI_OK != (ke = fullreadword(fd, &auth->d.basic.response))) return(ke); break; default: break; } return(KCGI_OK); }
/* * This is the parent kcgi process. * It spins on input from the child until all fields have been received. * These fields are sent from the child's output() function. * Each input field consists of the data and its validation state. * We build up the kpair arrays here with this data, then assign the * kpairs into named buckets. */ enum kcgi_err kworker_parent(int fd, struct kreq *r, int eofok) { struct kpair kp; struct kpair *kpp; enum krequ requ; enum input type; int rc; enum kcgi_err ke; size_t i, dgsz; /* Pointers freed at "out" label. */ memset(&kp, 0, sizeof(struct kpair)); /* * First read all of our parsed parameters. * Each parsed parameter is handled a little differently. * This list will end with META__MAX. */ if (fullread(fd, &r->reqsz, sizeof(size_t), 0, &ke) < 0) { XWARNX("failed to read request header size"); goto out; } r->reqs = XCALLOC(r->reqsz, sizeof(struct khead)); if (NULL == r->reqs) { ke = KCGI_ENOMEM; goto out; } for (i = 0; i < r->reqsz; i++) { if (fullread(fd, &requ, sizeof(enum krequ), 0, &ke) < 0) { XWARNX("failed to read request identifier"); goto out; } if (KCGI_OK != (ke = fullreadword(fd, &r->reqs[i].key))) { XWARNX("failed to read request key"); goto out; } if (KCGI_OK != (ke = fullreadword(fd, &r->reqs[i].val))) { XWARNX("failed to read request value"); goto out; } if (requ != KREQU__MAX) r->reqmap[requ] = &r->reqs[i]; } if (fullread(fd, &r->method, sizeof(enum kmethod), 0, &ke) < 0) { XWARNX("failed to read request method"); goto out; } else if (fullread(fd, &r->auth, sizeof(enum kauth), 0, &ke) < 0) { XWARNX("failed to read authorisation type"); goto out; } else if (KCGI_OK != (ke = kworker_auth_parent(fd, &r->rawauth))) { XWARNX("failed to read raw authorisation"); goto out; } else if (fullread(fd, &r->scheme, sizeof(enum kscheme), 0, &ke) < 0) { XWARNX("failed to read scheme"); goto out; } else if (KCGI_OK != (ke = fullreadword(fd, &r->remote))) { XWARNX("failed to read remote"); goto out; } else if (KCGI_OK != (ke = fullreadword(fd, &r->fullpath))) { XWARNX("failed to read fullpath"); goto out; } else if (KCGI_OK != (ke = fullreadword(fd, &r->suffix))) { XWARNX("failed to read suffix"); goto out; } else if (KCGI_OK != (ke = fullreadword(fd, &r->pagename))) { XWARNX("failed to read page part"); goto out; } else if (KCGI_OK != (ke = fullreadword(fd, &r->path))) { XWARNX("failed to read path part"); goto out; } else if (KCGI_OK != (ke = fullreadword(fd, &r->pname))) { XWARNX("failed to read script name"); goto out; } else if (KCGI_OK != (ke = fullreadword(fd, &r->host))) { XWARNX("failed to read host name"); goto out; } else if (fullread(fd, &r->port, sizeof(uint16_t), 0, &ke) < 0) { XWARNX("failed to read port"); goto out; } else if (fullread(fd, &dgsz, sizeof(size_t), 0, &ke) < 0) { XWARNX("failed to read digest length"); goto out; } else if (MD5_DIGEST_LENGTH == dgsz) { /* This is a binary value. */ if (NULL == (r->rawauth.digest = XMALLOC(dgsz))) goto out; if (fullread(fd, r->rawauth.digest, dgsz, 0, &ke) < 0) { XWARNX("failed to read digest"); goto out; } } while ((rc = input(&type, &kp, fd, &ke, eofok)) > 0) { assert(type < IN__MAX); /* * We have a parsed field from the child process. * Begin by expanding the number of parsed fields * depending on whether we have a cookie or form input. * Then copy the new data. */ kpp = IN_COOKIE == type ? kpair_expand(&r->cookies, &r->cookiesz) : kpair_expand(&r->fields, &r->fieldsz); if (NULL == kpp) { rc = -1; ke = KCGI_ENOMEM; break; } *kpp = kp; } if (rc < 0) goto out; /* * Now that the field and cookie arrays are fixed and not going * to be reallocated any more, we run through both arrays and * assign the named fields into buckets. */ for (i = 0; i < r->fieldsz; i++) { kpp = &r->fields[i]; if (kpp->keypos == r->keysz) continue; if (KPAIR_INVALID != kpp->state) { kpp->next = r->fieldmap[kpp->keypos]; r->fieldmap[kpp->keypos] = kpp; } else { kpp->next = r->fieldnmap[kpp->keypos]; r->fieldnmap[kpp->keypos] = kpp; } } for (i = 0; i < r->cookiesz; i++) { kpp = &r->cookies[i]; if (kpp->keypos == r->keysz) continue; if (KPAIR_INVALID != kpp->state) { kpp->next = r->cookiemap[kpp->keypos]; r->cookiemap[kpp->keypos] = kpp; } else { kpp->next = r->cookienmap[kpp->keypos]; r->cookienmap[kpp->keypos] = kpp; } } ke = KCGI_OK; /* * Usually, "kp" would be zeroed after its memory is copied into * one of the form-input arrays. * However, in the case of error, these may still have * allocations, so free them now. */ out: free(kp.key); free(kp.val); free(kp.file); free(kp.ctype); free(kp.xcode); return(ke); }