void mgt_sandbox(void) { #ifdef HAVE_SETPPRIV mgt_sandbox_solaris_init(); #endif if (geteuid() == 0) { XXXAZ(setgid(params->gid)); XXXAZ(setuid(params->uid)); } else { REPORT0(LOG_INFO, "Not running as root, no priv-sep"); } /* On Linux >= 2.4, you need to set the dumpable flag to get core dumps after you have done a setuid. */ #ifdef __linux__ if (prctl(PR_SET_DUMPABLE, 1) != 0) REPORT0(LOG_INFO, "Could not set dumpable bit. Core dumps turned off\n"); #endif #ifdef HAVE_SETPPRIV mgt_sandbox_solaris_fini(); #endif }
mgt_sandbox_unix(enum sandbox_e who) { (void)who; if (geteuid() == 0) { XXXAZ(setgid(mgt_param.gid)); XXXAZ(initgroups(mgt_param.user, mgt_param.gid)); XXXAZ(setuid(mgt_param.uid)); } else { REPORT0(LOG_INFO, "Not running as root, no priv-sep"); } }
void mgt_sandbox_solaris_privsep(void) { if (priv_ineffect(PRIV_PROC_SETID)) { if (getgid() != params->gid) XXXAZ(setgid(params->gid)); if (getuid() != params->uid) XXXAZ(setuid(params->uid)); } else { REPORT(LOG_INFO, "Privilege %s missing, will not change uid/gid", PRIV_PROC_SETID); } }
static void vjs_privsep(enum jail_gen_e jge) { (void)jge; if (priv_ineffect(PRIV_PROC_SETID)) { if (getgid() != mgt_param.gid) XXXAZ(setgid(mgt_param.gid)); if (getuid() != mgt_param.uid) XXXAZ(setuid(mgt_param.uid)); } else { MGT_complain(C_SECURITY, "Privilege %s missing, will not change uid/gid", PRIV_PROC_SETID); } }
static void mgt_sandbox_solaris_privsep(enum sandbox_e who) { (void)who; if (priv_ineffect(PRIV_PROC_SETID)) { if (getgid() != mgt_param.gid) XXXAZ(setgid(mgt_param.gid)); if (getuid() != mgt_param.uid) XXXAZ(setuid(mgt_param.uid)); } else { REPORT(LOG_INFO, "Privilege %s missing, will not change uid/gid", PRIV_PROC_SETID); } }
vfp_esi_end(struct sess *sp) { struct vsb *vsb; struct vef_priv *vef; ssize_t l; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); AN(sp->wrk->vep); vsb = VEP_Finish(sp); if (vsb != NULL) { l = VSB_len(vsb); assert(l > 0); /* XXX: This is a huge waste of storage... */ sp->obj->esidata = STV_alloc(sp, l); XXXAN(sp->obj->esidata); memcpy(sp->obj->esidata->ptr, VSB_data(vsb), l); sp->obj->esidata->len = l; VSB_delete(vsb); } if (sp->wrk->vgz_rx != NULL) VGZ_Destroy(&sp->wrk->vgz_rx); if (sp->wrk->vef_priv != NULL) { vef = sp->wrk->vef_priv; CHECK_OBJ_NOTNULL(vef, VEF_MAGIC); sp->wrk->vef_priv = NULL; VGZ_UpdateObj(vef->vgz, sp->obj); VGZ_Destroy(&vef->vgz); XXXAZ(vef->error); FREE_OBJ(vef); } return (0); }
vfp_testgzip_begin(struct busyobj *bo, size_t estimate) { CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); (void)estimate; bo->vgz_rx = VGZ_NewUngzip(bo->vsl, "u F -"); CHECK_OBJ_NOTNULL(bo->vgz_rx, VGZ_MAGIC); XXXAZ(vgz_getmbuf(bo->vgz_rx)); }
vfp_gzip_begin(struct busyobj *bo, size_t estimate) { (void)estimate; CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); AZ(bo->vgz_rx); bo->vgz_rx = VGZ_NewGzip(bo->vsl, "G F -"); XXXAZ(vgz_getmbuf(bo->vgz_rx)); }
static void dyn_dir_init(VRT_CTX, struct xyzzy_debug_dyn *dyn, VCL_STRING addr, VCL_STRING port, VCL_PROBE probe) { struct addrinfo hints, *res = NULL; struct suckaddr *sa; VCL_BACKEND dir, dir2; struct vrt_backend vrt; CHECK_OBJ_NOTNULL(dyn, VMOD_DEBUG_DYN_MAGIC); XXXAN(addr); XXXAN(port); INIT_OBJ(&vrt, VRT_BACKEND_MAGIC); vrt.port = port; vrt.vcl_name = dyn->vcl_name; vrt.hosthdr = addr; vrt.probe = probe; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; AZ(getaddrinfo(addr, port, &hints, &res)); XXXAZ(res->ai_next); sa = VSA_Malloc(res->ai_addr, res->ai_addrlen); AN(sa); if (VSA_Get_Proto(sa) == AF_INET) { vrt.ipv4_addr = addr; vrt.ipv4_suckaddr = sa; } else if (VSA_Get_Proto(sa) == AF_INET6) { vrt.ipv6_addr = addr; vrt.ipv6_suckaddr = sa; } else WRONG("Wrong proto family"); freeaddrinfo(res); dir = VRT_new_backend(ctx, &vrt); AN(dir); /* * NB: A real dynamic backend should not replace the previous * instance if the new one is identical. We do it here because * the d* tests requires a replacement. */ AZ(pthread_mutex_lock(&dyn->mtx)); dir2 = dyn->dir; dyn->dir = dir; AZ(pthread_mutex_unlock(&dyn->mtx)); if (dir2 != NULL) VRT_delete_backend(ctx, &dir2); free(sa); }
mgt_sandbox_unix(enum sandbox_e who) { #define NGID 2000 int i; gid_t gid_list[NGID]; if (geteuid() != 0) { REPORT0(LOG_INFO, "Not running as root, no priv-sep"); return; } XXXAZ(setgid(mgt_param.gid)); XXXAZ(initgroups(mgt_param.user, mgt_param.gid)); if (who == SANDBOX_CC && strlen(mgt_param.group_cc) > 0) { /* Add the optional extra group for the C-compiler access */ i = getgroups(NGID, gid_list); assert(i >= 0); gid_list[i++] = mgt_param.gid_cc; XXXAZ(setgroups(i, gid_list)); } XXXAZ(setuid(mgt_param.uid)); }
/*-------------------------------------------------------------------- * Append data to a signature */ void smp_append_sign(struct smp_signctx *ctx, const void *ptr, uint32_t len) { struct SHA256Context cx; unsigned char sign[SHA256_LEN]; if (len != 0) { SHA256_Update(&ctx->ctx, ptr, len); ctx->ss->length += len; } cx = ctx->ctx; SHA256_Update(&cx, &ctx->ss->length, sizeof(ctx->ss->length)); SHA256_Final(sign, &cx); memcpy(SIGN_END(ctx), sign, sizeof sign); XXXAZ(smp_chk_sign(ctx)); }
vep_do_include(struct vep_state *vep, enum dowhat what) { char *p, *q, *h; ssize_t l; txt url; Debug("DO_INCLUDE(%d)\n", what); if (what == DO_ATTR) { Debug("ATTR (%s) (%s)\n", vep->match_hit->match, VSB_data(vep->attr_vsb)); if (vep->include_src != NULL) { vep_error(vep, "ESI 1.0 <esi:include> " "has multiple src= attributes"); vep->state = VEP_TAGERROR; VSB_delete(vep->attr_vsb); VSB_delete(vep->include_src); vep->attr_vsb = NULL; vep->include_src = NULL; return; } XXXAZ(vep->include_src); /* multiple src= */ vep->include_src = vep->attr_vsb; return; } assert(what == DO_TAG); if (!vep->emptytag) vep_warn(vep, "ESI 1.0 <esi:include> lacks final '/'"); if (vep->include_src == NULL) { vep_error(vep, "ESI 1.0 <esi:include> lacks src attr"); return; } /* * Strictly speaking, we ought to spit out any piled up skip before * emitting the VEC for the include, but objectively that makes no * difference and robs us of a chance to collapse another skip into * this on so we don't do that. * However, we cannot tolerate any verbatim stuff piling up. * The mark_skip() before calling dostuff should have taken * care of that. Make sure. */ assert(vep->o_wait == 0 || vep->last_mark == SKIP); /* XXX: what if it contains NUL bytes ?? */ p = VSB_data(vep->include_src); l = VSB_len(vep->include_src); h = 0; VSB_printf(vep->vsb, "%c", VEC_INCL); if (l > 7 && !memcmp(p, "http://", 7)) { h = p + 7; p = strchr(h, '/'); AN(p); Debug("HOST <%.*s> PATH <%s>\n", (int)(p-h),h, p); VSB_printf(vep->vsb, "Host: %.*s%c", (int)(p-h), h, 0); } else if (*p == '/') { VSB_printf(vep->vsb, "%c", 0); } else { VSB_printf(vep->vsb, "%c", 0); url = vep->sp->wrk->bereq->hd[HTTP_HDR_URL]; /* Look for the last / before a '?' */ h = NULL; for (q = url.b; q < url.e && *q != '?'; q++) if (*q == '/') h = q; if (h == NULL) h = q + 1; Debug("INCL:: [%.*s]/[%s]\n", (int)(h - url.b), url.b, p); VSB_printf(vep->vsb, "%.*s/", (int)(h - url.b), url.b); } l -= (p - VSB_data(vep->include_src)); for (q = p; *q != '\0'; ) { if (*q == '&') { #define R(w,f,r) \ if (q + w <= p + l && !memcmp(q, f, w)) { \ VSB_printf(vep->vsb, "%c", r); \ q += w; \ continue; \ } R(6, "'", '\''); R(6, """, '"'); R(4, "<", '<'); R(4, ">", '>'); R(5, "&", '&'); } VSB_printf(vep->vsb, "%c", *q++); } #undef R VSB_printf(vep->vsb, "%c", 0); VSB_delete(vep->include_src); vep->include_src = NULL; }
static int cnt_lookup(struct worker *wrk, struct req *req) { struct objcore *oc; struct object *o; struct objhead *oh; struct busyobj *bo; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(req, REQ_MAGIC); AZ(req->objcore); CHECK_OBJ_NOTNULL(req->vcl, VCL_CONF_MAGIC); AZ(req->busyobj); VRY_Prep(req); AZ(req->objcore); oc = HSH_Lookup(req); if (oc == NULL) { /* * We lost the session to a busy object, disembark the * worker thread. We return to STP_LOOKUP when the busy * object has been unbusied, and still have the objhead * around to restart the lookup with. */ return (2); } AZ(req->objcore); CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC); oh = oc->objhead; CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC); /* If we inserted a new object it's a miss */ if (oc->flags & OC_F_BUSY) { AZ(req->busyobj); bo = VBO_GetBusyObj(wrk, req); req->busyobj = bo; /* One ref for req, one for FetchBody */ bo->refcount = 2; VRY_Finish(req, bo); oc->busyobj = bo; wrk->stats.cache_miss++; req->objcore = oc; req->req_step = R_STP_MISS; return (0); } /* We are not prepared to do streaming yet */ XXXAZ(req->busyobj); o = oc_getobj(&wrk->stats, oc); CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC); req->obj = o; VRY_Finish(req, NULL); if (oc->flags & OC_F_PASS) { wrk->stats.cache_hitpass++; VSLb(req->vsl, SLT_HitPass, "%u", req->obj->vxid); (void)HSH_Deref(&wrk->stats, NULL, &req->obj); AZ(req->objcore); req->req_step = R_STP_PASS; return (0); } wrk->stats.cache_hit++; VSLb(req->vsl, SLT_Hit, "%u", req->obj->vxid); req->req_step = R_STP_HIT; return (0); }
static void parse_new(struct vcc *tl) { struct symbol *sy1, *sy2, *sy3; const char *p, *s_obj, *s_init, *s_struct, *s_fini; char buf1[128]; char buf2[128]; vcc_NextToken(tl); ExpectErr(tl, ID); sy1 = VCC_FindSymbol(tl, tl->t, SYM_NONE); XXXAZ(sy1); sy1 = VCC_AddSymbolTok(tl, tl->t, SYM_NONE); // XXX: NONE ? XXXAN(sy1); vcc_NextToken(tl); ExpectErr(tl, '='); vcc_NextToken(tl); ExpectErr(tl, ID); sy2 = VCC_FindSymbol(tl, tl->t, SYM_OBJECT); XXXAN(sy2); /*lint -save -e448 */ /* Split the first three args */ p = sy2->args; s_obj = p; p += strlen(p) + 1; s_init = p; while (p[0] != '\0' || p[1] != '\0') p++; p += 2; s_struct = p; p += strlen(p) + 1; s_fini = p + strlen(p) + 1; while (p[0] != '\0' || p[1] != '\0') p++; p += 2; Fh(tl, 0, "static %s *%s;\n\n", s_struct, sy1->name); vcc_NextToken(tl); bprintf(buf1, ", &%s, \"%s\"", sy1->name, sy1->name); vcc_Eval_Func(tl, s_init, buf1, "ASDF", s_init + strlen(s_init) + 1); Fd(tl, 0, "\t%s(&%s);\n", s_fini, sy1->name); ExpectErr(tl, ';'); bprintf(buf1, ", %s", sy1->name); /* Split the methods from the args */ while (*p != '\0') { p += strlen(s_obj); bprintf(buf2, "%s%s", sy1->name, p); sy3 = VCC_AddSymbolStr(tl, buf2, SYM_FUNC); AN(sy3); sy3->eval = vcc_Eval_SymFunc; p += strlen(p) + 1; sy3->cfunc = p; p += strlen(p) + 1; /* Functions which return VOID are procedures */ if (!memcmp(p, "VOID\0", 5)) sy3->kind = SYM_PROC; sy3->args = p; sy3->extra = TlDup(tl, buf1); while (p[0] != '\0' || p[1] != '\0') p++; p += 2; } /*lint -restore */ }
void HTTP1_Session(struct worker *wrk, struct req *req) { enum htc_status_e hs; struct sess *sp; const char *st; int i; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(req, REQ_MAGIC); sp = req->sp; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); /* * Whenever we come in from the acceptor or waiter, we need to set * blocking mode. It would be simpler to do this in the acceptor * or waiter, but we'd rather do the syscall in the worker thread. * On systems which return errors for ioctl, we close early */ if (http1_getstate(sp) == H1NEWREQ && VTCP_blocking(sp->fd)) { if (errno == ECONNRESET) SES_Close(sp, SC_REM_CLOSE); else SES_Close(sp, SC_TX_ERROR); AN(Req_Cleanup(sp, wrk, req)); return; } while (1) { st = http1_getstate(sp); if (st == H1NEWREQ) { assert(isnan(req->t_prev)); assert(isnan(req->t_req)); AZ(req->vcl); AZ(req->esi_level); hs = HTC_RxStuff(req->htc, HTTP1_Complete, &req->t_first, &req->t_req, sp->t_idle + cache_param->timeout_linger, sp->t_idle + cache_param->timeout_idle, cache_param->http_req_size); XXXAZ(req->htc->ws->r); if (hs < HTC_S_EMPTY) { req->acct.req_hdrbytes += req->htc->rxbuf_e - req->htc->rxbuf_b; CNT_AcctLogCharge(wrk->stats, req); Req_Release(req); switch(hs) { case HTC_S_CLOSE: SES_Delete(sp, SC_REM_CLOSE, NAN); return; case HTC_S_TIMEOUT: SES_Delete(sp, SC_RX_TIMEOUT, NAN); return; case HTC_S_OVERFLOW: SES_Delete(sp, SC_RX_OVERFLOW, NAN); return; case HTC_S_EOF: SES_Delete(sp, SC_REM_CLOSE, NAN); return; default: WRONG("htc_status (bad)"); } } if (hs == HTC_S_IDLE) { wrk->stats->sess_herd++; Req_Release(req); SES_Wait(sp, &HTTP1_transport); return; } if (hs != HTC_S_COMPLETE) WRONG("htc_status (nonbad)"); i = http1_dissect(wrk, req); req->acct.req_hdrbytes += req->htc->rxbuf_e - req->htc->rxbuf_b; if (i) { SES_Close(req->sp, req->doclose); http1_setstate(sp, H1CLEANUP); } else { req->req_step = R_STP_RECV; http1_setstate(sp, H1PROC); } } else if (st == H1BUSY) { /* * Return from waitinglist. * Check to see if the remote has left. */ if (VTCP_check_hup(sp->fd)) { AN(req->hash_objhead); (void)HSH_DerefObjHead(wrk, &req->hash_objhead); AZ(req->hash_objhead); SES_Close(sp, SC_REM_CLOSE); AN(Req_Cleanup(sp, wrk, req)); return; } http1_setstate(sp, H1PROC); } else if (st == H1PROC) { req->transport = &HTTP1_transport; if (CNT_Request(wrk, req) == REQ_FSM_DISEMBARK) { req->task.func = http1_req; req->task.priv = req; http1_setstate(sp, H1BUSY); return; } req->transport = NULL; http1_setstate(sp, H1CLEANUP); } else if (st == H1CLEANUP) { if (Req_Cleanup(sp, wrk, req)) return; HTC_RxInit(req->htc, req->ws); if (req->htc->rxbuf_e != req->htc->rxbuf_b) wrk->stats->sess_readahead++; http1_setstate(sp, H1NEWREQ); } else { WRONG("Wrong H1 session state"); } } }
static void parse_new(struct vcc *tl) { struct symbol *sy1, *sy2, *sy3; struct inifin *ifp; const char *p, *s_obj, *s_init, *s_struct, *s_fini; char buf1[128]; char buf2[128]; vcc_NextToken(tl); ExpectErr(tl, ID); if (!vcc_isCid(tl->t)) { VSB_printf(tl->sb, "Names of VCL objects cannot contain '-'\n"); vcc_ErrWhere(tl, tl->t); return; } sy1 = VCC_FindSymbol(tl, tl->t, SYM_NONE); XXXAZ(sy1); sy1 = VCC_AddSymbolTok(tl, tl->t, SYM_NONE); // XXX: NONE ? XXXAN(sy1); vcc_NextToken(tl); ExpectErr(tl, '='); vcc_NextToken(tl); ExpectErr(tl, ID); sy2 = VCC_FindSymbol(tl, tl->t, SYM_OBJECT); if (sy2 == NULL) { VSB_printf(tl->sb, "Object not found: "); vcc_ErrToken(tl, tl->t); VSB_printf(tl->sb, " at "); vcc_ErrWhere(tl, tl->t); return; } XXXAN(sy2); /*lint -save -e448 */ /* Split the first three args */ p = sy2->args; s_obj = p; p += strlen(p) + 1; s_init = p; while (p[0] != '\0' || p[1] != '\0') p++; p += 2; s_struct = p; p += strlen(p) + 1; s_fini = p + strlen(p) + 1; while (p[0] != '\0' || p[1] != '\0') p++; p += 2; Fh(tl, 0, "static %s *%s;\n\n", s_struct, sy1->name); vcc_NextToken(tl); bprintf(buf1, ", &%s, \"%s\"", sy1->name, sy1->name); vcc_Eval_Func(tl, s_init, buf1, "ASDF", s_init + strlen(s_init) + 1); ifp = New_IniFin(tl); VSB_printf(ifp->fin, "\t%s(&%s);", s_fini, sy1->name); ExpectErr(tl, ';'); bprintf(buf1, ", %s", sy1->name); /* Split the methods from the args */ while (*p != '\0') { p += strlen(s_obj); bprintf(buf2, "%s%s", sy1->name, p); sy3 = VCC_AddSymbolStr(tl, buf2, SYM_FUNC); AN(sy3); sy3->eval = vcc_Eval_SymFunc; p += strlen(p) + 1; sy3->cfunc = p; p += strlen(p) + 1; /* Functions which return VOID are procedures */ if (!memcmp(p, "VOID\0", 5)) sy3->kind = SYM_PROC; sy3->args = p; sy3->extra = TlDup(tl, buf1); while (p[0] != '\0' || p[1] != '\0') { if (!memcmp(p, "ENUM\0", 5)) { /* XXX: Special case for ENUM that has it's own \0\0 end marker. Not exactly elegant, we should consider alternatives here. Maybe runlength encode the entire block? */ p += strlen(p) + 1; while (p[0] != '\0' || p[1] != '\0') p++; } p++; } p += 2; } /*lint -restore */ }
int FetchBody(struct sess *sp) { int cls; struct storage *st; struct worker *w; int mklen; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC); w = sp->wrk; CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC); CHECK_OBJ_NOTNULL(sp->obj->http, HTTP_MAGIC); if (w->vfp == NULL) w->vfp = &vfp_nop; AN(sp->director); AssertObjCorePassOrBusy(sp->obj->objcore); AZ(w->vgz_rx); AZ(VTAILQ_FIRST(&sp->obj->store)); switch (w->body_status) { case BS_NONE: cls = 0; mklen = 0; break; case BS_ZERO: cls = 0; mklen = 1; break; case BS_LENGTH: cls = fetch_straight(sp, w->htc, w->h_content_length); mklen = 1; XXXAZ(w->vfp->end(sp)); break; case BS_CHUNKED: cls = fetch_chunked(sp, w->htc); mklen = 1; XXXAZ(w->vfp->end(sp)); break; case BS_EOF: cls = fetch_eof(sp, w->htc); mklen = 1; XXXAZ(w->vfp->end(sp)); break; case BS_ERROR: cls = 1; mklen = 0; break; default: cls = 0; mklen = 0; INCOMPL(); } AZ(w->vgz_rx); /* * It is OK for ->end to just leave the last storage segment * sitting on w->storage, we will always call vfp_nop_end() * to get it trimmed or thrown out if empty. */ AZ(vfp_nop_end(sp)); WSL(w, SLT_Fetch_Body, sp->vbc->vsl_id, "%u(%s) cls %d mklen %u", w->body_status, body_status(w->body_status), cls, mklen); if (w->body_status == BS_ERROR) { VDI_CloseFd(sp); return (__LINE__); } if (cls < 0) { w->stats.fetch_failed++; /* XXX: Wouldn't this store automatically be released ? */ while (!VTAILQ_EMPTY(&sp->obj->store)) { st = VTAILQ_FIRST(&sp->obj->store); VTAILQ_REMOVE(&sp->obj->store, st, list); STV_free(st); } VDI_CloseFd(sp); sp->obj->len = 0; return (__LINE__); } if (cls == 0 && w->do_close) cls = 1; WSL(w, SLT_Length, sp->vbc->vsl_id, "%u", sp->obj->len); { /* Sanity check fetch methods accounting */ ssize_t uu; uu = 0; VTAILQ_FOREACH(st, &sp->obj->store, list) uu += st->len; if (sp->objcore == NULL || (sp->objcore->flags & OC_F_PASS)) /* Streaming might have started freeing stuff */ assert (uu <= sp->obj->len); else assert(uu == sp->obj->len); } if (mklen > 0) { http_Unset(sp->obj->http, H_Content_Length); http_PrintfHeader(w, sp->vsl_id, sp->obj->http, "Content-Length: %jd", (intmax_t)sp->obj->len); } if (cls) VDI_CloseFd(sp); else VDI_RecycleFd(sp); return (0); }