static bool userinfo2str (strbuf &sb, const sfsauth_userinfo *ui) { str audit = single_char_sub (ui->audit, ':', "."); if (!namerx.match (ui->name) || (ui->owner && !namerx.match (*ui->owner)) || !nobadrx.match (ui->privs) || badcharrx.search (ui->pwauth) || badcharrx.search (audit)) return false; sb << ui->name; sb.fmt (":%u:%u:%u:", ui->id, ui->vers, ui->gid); if (ui->owner) sb << *ui->owner; sb << ":"; ptr<sfspub> pk = sfscrypt.alloc (ui->pubkey); if (!pk) return false; pk->export_pubkey (sb); sb << ":" << ui->privs << ":" << ui->pwauth << ":"; str priv = str2wstr (armor64 (ui->privkey.base (), ui->privkey.size())); sb << priv << ":"; sfs_2schnorr_priv::export_keyhalf (ui->srvprivkey, sb); // sb << ":" << ui->refresh << ":" << ui->timeout; sb << ":" << audit; return true; }
int split (vec<str> *out, rxx pat, str expr, size_t lim, bool emptylast) { const char *p = expr; const char *const e = p + expr.len (); size_t n; if (out) out->clear (); // check p < e to see that we're not dealing with an empty // string (especially since x? matches ""). for (n = 0; p < e && n + 1 < lim; n++) { if (!pat._exec (p, e - p, 0)) { return 0; } if (!pat.success ()) break; if (out) out->push_back (str (p, pat.start (0))); p += max (pat.end (0), 1); } if (lim && (p < e || emptylast)) { n++; if (out) { out->push_back (str (p, e - p)); } } return n; }
static void collect_pound_def (str s) { static rxx x ("#\\s*define\\s*(\\S+)\\s+(.*)"); if (guess_defines && x.match (s)) { collect_constant (x[1], "RPC_CONSTANT_POUND_DEF"); } }
static bool is_builtin(const str &s) { static rxx x ("(((unsigned|long|const)\\s+)*|(u_?)?)" "(bool|char|int|short|quad|long|" "int(8|16|32|64)_t)"); return x.match (s); }
int main (int argc, const char *argv[]) { if (argc < 2) return -1; str parent, filename; parentpath (parent, filename, str (argv[1])); warn << parent << "\n"; warn << filename << "\n"; return 0; vec<str> out; splitpath (out, argv[1]); str foo; while (out.size () > 0 && (foo = out.pop_front ())) warn << foo << "\n"; return 0; str path (argv[1]); // vec<str> out; static rxx r ("^(.*)/([^/]+)$"); // static rxx r ("^/*([^/]+)(/.*)?$"); // static rxx r ("^s%/[^/]*$%%"); // static rxx pathsplit ("^/*([^/]+)(/.*)?$"); warn << "path: " << path << "\n"; // path = path/r; if (r.search (path)) { if (r.len(1) != -1) warn << r[1] << " -> "; if (r.len(2) != -1) warn << r[2] << "\n"; warn << "r[0]: " << r[0] << "\n"; } warn << split (&out, "/", path) << "\n"; for (unsigned int i=0; i< out.size(); i++) warn << out[i] << "\n"; return 0; }
void repl_el_capture_t::output (strbuf &out, const char *s, rxx &x) { int start = x.start (_i); int ln = x.len (_i); if (start >= 0 && ln > 0) { str repl = str (s + start, ln); strbuf_output (out, repl); } }
bool sfsgroupmgr::parsegroup (str group, str *gname, str *ghost) { static rxx grouphostrx ("([A-Za-z][\\-\\w\\.]{0,31})(@[A-Za-z].+)?"); if (!grouphostrx.match (group)) { warn << "Could not parse group[@host]: " << group << "\n"; return false; } *gname = grouphostrx[1]; *ghost = grouphostrx[2] ? grouphostrx[2].cstr () : "-"; return true; }
static void extract_matches (vec<str> *out, const char *base, rxx &x) { bool go = true; for (int i = 0; go; i++) { int ln = x.len (i); int start = x.start (i); if (ln < 0 || start < 0) { go = false; } else if (ln > 0) { out->push_back (str (base + start, ln)); } } }
bool is_safe (const str &d) { if (!d || d[0] == '.' || d[d.len () - 1] == '.' || safe_rxx.search (d)) return false; return true; }
bool parse_hn (const str &in, str *host, int *port) { static rxx host_port_rxx ("([.0-9A-Za-z_-]*)(:[0-9]+)?"); if (!host_port_rxx.match (in)) return false; str h = host_port_rxx[1]; if (h && h.len () > 0 && h != "-") *host = h; str p = host_port_rxx[2]; if (p && p.len () > 1) { const char *pc = p.cstr () + 1; p = pc; if (!convertint (p, port)) return false; } return true; }
bool cgi_mpfd_t::match (const http_inhdr_t &hdr, str *bndry) { if (multipart_rxx.match (hdr["content-type"])) { *bndry = multipart_rxx[1]; return true; } return false; }
str rxx_replace_2 (str input, rxx pat, str repl_str) { repl_t repl; str ret; if (!repl.parse (repl_str)) { warn << "XX cannot parse replacement string: " << repl_str << "\n"; } else { const char *p = input; const char *const e = p + input.len (); strbuf b; bool go = true; bool err = false; // check p < e to see that we're not dealing with an empty // string (especially since x? matches ""). while (go && !err && p < e) { if (!pat._exec (p, e - p, 0)) { warn << "XX regex execution failed\n"; err = true; } else if (!pat.success ()) { go = false; } else { str pre = str (p, pat.start (0)); strbuf_output (b, pre); repl.output (b, p, pat); p += max (pat.end (0), 1); } } if (p < e && !err) { str post = str (p, e - p); strbuf_output (b, post); } if (!err) { ret = b; } } return ret; }
// Call the replace function for each matched pattern. str rxx_replace (str input, rxx pat, rxx_replace_cb_t cb) { const char *p = input; const char *const e = p + input.len (); strbuf b; bool go = true; bool err = false; str ret; // check p < e to see that we're not dealing with an empty // string (especially since x? matches ""). while (go && !err && p < e) { if (!pat._exec (p, e - p, 0)) { warn << "XX regex execution failed\n"; err = true; } else if (!pat.success ()) { go = false; } else { str pre = str (p, pat.start (0)); strbuf_output (b, pre); vec<str> v; extract_matches (&v, p, pat); str repl = (*cb) (&v); if (repl) { strbuf_output (b, repl); } p += max (pat.end (0), 1); } } if (p < e && !err) { str post = str (p, e - p); strbuf_output (b, post); } if (!err) { ret = b; } return ret; }
int agentconn::cagent_fd (bool required) { if (agentfd >= 0) return agentfd; static rxx sockfdre ("^-(\\d+)?$"); if (agentsock && sockfdre.search (agentsock)) { if (sockfdre[1]) agentfd = atoi (sockfdre[1]); else agentfd = 0; if (!isunixsocket (agentfd)) fatal << "fd specified with '-S' not unix domain socket\n"; } else if (agentsock) { agentfd = unixsocket_connect (agentsock); if (agentfd < 0 && required) fatal ("%s: %m\n", agentsock.cstr ()); } else if (ccd (false)) { int32_t res; if (clnt_stat err = ccd ()->scall (AGENT_GETAGENT, NULL, &res)) { if (required) fatal << "sfscd: " << err << "\n"; } else if (res) { if (required) fatal << "connecting to agent via sfscd: " << strerror (res) << "\n"; } else if ((agentfd = sfscdxprt->recvfd ()) < 0) { fatal << "connecting to agent via sfscd: " << "could not get file descriptor\n"; } } else { if (str sock = agent_usersock (true)) agentfd = unixsocket_connect (sock); if (agentfd < 0 && required) fatal << "sfscd not running and no standalone agent socket\n"; } return agentfd; }
bool pri2del (sfsauth_dbrec *dbrp, str aek) { static rxx userrx ("^USER:([^:])$"); static rxx grouprx ("^GROUP:([^:])$"); if (userrx.match (aek)) { dbrp->set_type (SFSAUTH_DELUSER); *dbrp->deleted = userrx[1]; } else if (grouprx.match (aek)) { dbrp->set_type (SFSAUTH_DELGROUP); *dbrp->deleted = grouprx[1]; } else { dbrp->set_type (SFSAUTH_ERROR); *dbrp->errmsg = strbuf () << "illegal deleted DB key " << aek; return false; } return true; }
bool to_hostname_and_port (const str &in, str *out, int *port) { bool ret = true; if (!host_and_port.match (in) || (host_and_port[3] && !convertint (host_and_port[3], port))) { ret = false; } else { *out = host_and_port[1]; } return ret; }
bool groupinfo2str (strbuf &sb, const sfsauth_groupinfo *gi) { str audit = single_char_sub (gi->audit, ':', "."); if (!namerx.match (gi->name) || badcharrx.search (audit) || !nobadrx.match (gi->properties)) return false; sb << gi->name; sb.fmt (":%u:%u:", gi->id, gi->vers); if (!printlist (sb, gi->owners, printmember)) return false; sb << ":"; if (!printlist (sb, gi->members, printmember)) return false; // sb << ":" << gi->refresh << ":" << gi->timeout; sb << ":" << gi->properties; sb << ":" << audit; return true; }
str aekey (const sfsauth_dbrec &ae) { switch (ae.type) { case SFSAUTH_USER: return strbuf () << "USER:"******"GROUP:" << ae.groupinfo->name; case SFSAUTH_CACHEENTRY: return strbuf () << "CACHE:" << ae.cacheentry->key; default: { static rxx knrx ("^[^:]*:[^:]*"); str astr = authdbrec2str (&ae); if (!astr) return NULL; if (!knrx.search (astr)) panic << "missing colon: " << astr << "\n"; return knrx[0]; } } }
sfs_connect_t * sfs_connect_srp (str u, srp_client *srpp, sfs_connect_cb cb, str *userp, str *pwdp, bool *serverokp) { static rxx usrhost ("^([^@]+)?@(.*)$"); if (!usrhost.match (u)) { if (userp) *userp = u; (*cb) (NULL, "not of form [user]@hostname"); return NULL; } str user (usrhost[1]), host (usrhost[2]); if (!user && !(user = myusername ())) { (*cb) (NULL, "could not get local username"); return NULL; } ref<sfssrp_authorizer> a (New refcounted<sfssrp_authorizer>); a->srpc = srpp; sfs_connect_t *cs = New sfs_connect_t (wrap (sfs_connect_srp_2, sfs::bundle_t<ref<sfssrp_authorizer>, str *, str *> (a, userp, pwdp), serverokp, cb)); cs->sname () = host; cs->service () = SFS_AUTHSERV; cs->encrypt = true; cs->check_hostid = false; cs->authorizer = a; cs->aarg.user = user; if (!cs->start ()) return NULL; return cs; }
bool str2authdbrec (sfsauth_dbrec *dbr, str s) { static rxx _userrx ("^USER:(.*)$"); rxx userrx (_userrx); static rxx grouprx ("^GROUP:(.*)$"); static rxx cacherx ("^CACHE:(.*)$"); static rxx logrx ("^LOG:(.*)$"); static rxx revinfo ("^REVINFO:([0-9a-fA-F]+):(\\d+)$"); if (revinfo.match (s)) { str id = hex2bytes (revinfo[1]); u_int64_t rev; if (!id || id.len () != sizeof (dbr->revinfo->dbid) || !convertint (revinfo[2], &rev)) return false; dbr->set_type (SFSAUTH_REVINFO); dbr->revinfo->dbrev = rev; memcpy (dbr->revinfo->dbid.base (), id, id.len ()); return true; } else if (userrx.match (s)) { dbr->set_type (SFSAUTH_USER); return str2userinfo (dbr->userinfo, str2wstr (userrx[1])); } else if (grouprx.match (s)) { dbr->set_type (SFSAUTH_GROUP); return str2groupinfo (dbr->groupinfo, grouprx[1]); } else if (cacherx.match (s)) { dbr->set_type (SFSAUTH_CACHEENTRY); return str2cacheentry (dbr->cacheentry, cacherx[1]); } else if (logrx.match (s)) { dbr->set_type (SFSAUTH_LOGENTRY); return str2logentry (dbr->logentry, logrx[1]); } else return false; }
bool str2groupinfo (sfsauth_groupinfo *gi, str s) { vec<str> gv; if (split (&gv, colon, s, 8, true) != 7) return false; if (!namerx.match (gv[0]) || badcharrx.search (gv[5])) return false; gi->name = gv[0]; if (!convertint (gv[1], &gi->id) || !convertint (gv[2], &gi->vers) || !parselist (&gi->owners, gv[3], parsemember) || !parselist (&gi->members, gv[4], parsemember) // || !convertint (gv[5], &gi->refresh) // || !convertint (gv[6], &gi->timeout) ) return false; gi->properties = gv[5]; gi->audit = gv[6]; // gi->audit = gv[7]; return true; }
static void parseconfig () { str cf = configfile; parseargs pa (cf); bool errors = false; str hostname; rpc_ptr<sfs_hash> hostid; server *s = NULL; release *r = NULL; extension *e = NULL; char *c; int line; vec<str> av; while (pa.getline (&av, &line)) { if (!strcasecmp (av[0], "BindAddr")) { in_addr addr; u_int16_t port = 0; if (av.size () < 2 || av.size () > 3 || !inet_aton (av[1], &addr) || (av.size () == 3 && !convertint (av[2], &port))) { warn << cf << ":" << line << ": usage: BindAddr addr [port]\n"; errors = true; continue; } if (!port) port = sfs_defport ? sfs_defport : SFS_PORT; sockaddr_in *sinp = static_cast<sockaddr_in *> (xmalloc (sizeof (*sinp))); bzero (sinp, sizeof (*sinp)); sinp->sin_family = AF_INET; sinp->sin_port = htons (port); sinp->sin_addr = addr; #ifdef HAVE_SA_LEN sinp->sin_len = sizeof (*sinp); #endif /* HAVE_SA_LEN */ listenaddrs.push_back (reinterpret_cast<sockaddr *> (sinp)); } else if (!strcasecmp (av[0], "Server")) { if (av.size () != 2) { warn << cf << ":" << line << ": usage: Server {hostname|*}[:hostid]\n"; errors = true; continue; } if (strchr (av[1], ':') || ((c = strchr (av[1], '@')) && strchr (c, ','))) { hostid.alloc (); if (!sfs_parsepath (av[1], &hostname, hostid)) { warn << cf << ":" << line << ": bad hostname/hostid\n"; errors = true; continue; } } else { hostid.clear (); if (av[1] == "*") hostname = sfshostname (); else hostname = av[1]; } for (s = serverlist.first; s; s = serverlist.next (s)) if (hostname == s->host && ((hostid && s->hostid && *hostid == *s->hostid) || (!hostid && !s->hostid))) break; if (!s) s = New server (hostname, hostid); r = NULL; e = NULL; } else if (!strcasecmp (av[0], "Release")) { static rxx relrx ("^(\\d+)\\.(\\d\\d?)$"); if (av.size () != 2 || (!relrx.search (av[1]) && av[1] != "*")) { warn << cf << ":" << line << ": usage Release { N.NN | * }\n"; errors = true; r = NULL; continue; } if (!s) { warn << cf << ":" << line << ": Release must follow Server\n"; errors = true; r = NULL; continue; } u_int32_t rel; if (av[1] == "*") rel = 0xffffffff; else rel = strtoi64 (relrx[1]) * 100 + strtoi64 (relrx[2]); r = s->reltab[rel]; if (!r) s->reltab.insert ((r = New release (rel))); for (e = r->extlist.first; r->extlist.next (e); e = r->extlist.next (e)) ; } else if (!strcasecmp (av[0], "Extensions")) { av.pop_front (); e = r->getext (av); } else if (!strcasecmp (av[0], "Service")) { if (!parse_service (av, e, cf << ":" << line)) errors = true; } else if (!strcasecmp (av[0], "HashCost")) { if (av.size () != 2 || !convertint (av[1], &sfs_hashcost)) { warn << cf << ":" << line << ": usage: HashCost <nbits>\n"; errors = true; } else { if (sfs_hashcost > sfs_maxhashcost) sfs_hashcost = sfs_maxhashcost; str s (strbuf ("SFS_HASHCOST=%d", sfs_hashcost)); xputenv (const_cast<char*>(s.cstr())); } } else if (!strcasecmp (av[0], "RevocationDir")) { if (av.size () != 2) { warn << cf << ":" << line << ": usage: RevocationDir <directory>\n"; errors = true; } else { revocationdir = av[1]; } } else { errors = true; warn << cf << ":" << line << ": unknown directive '" << av[0] << "'\n"; } } if (errors) fatal ("parse errors in configuration file\n"); }
void identcb (str u, int e) { if (u && identrx.search (u)) user = identrx[2]; a = NULL; cbdone (); }
void authclnt::sfsauth_update (svccb *sbp) { update_info i; i.cp = NULL; i.ur = NULL; if (sbp->getaui () >= credtab.size () || !(i.cp = &credtab[sbp->getaui ()]) || i.cp->type != SFS_UNIXCRED || !(i.ur = utab[sbp->getaui ()]) || i.ur->authtype == SFS_NOAUTH) { sbp->reject (AUTH_REJECTEDCRED); return; } i.res.set_ok (false); i.kname.set_type (SFSAUTH_DBKEY_NAME); *i.kname.name = i.cp->unixcred->username; dbfile *cdbp; if (!get_user_cursor (&cdbp, NULL, &i.cdbr, i.kname) || i.cp->unixcred->username != i.cdbr.userinfo->name) { *i.res.errmsg = "could not load credential db record"; sbp->replyref (i.res); return; } if (i.cp->unixcred->uid != i.cdbr.userinfo->id) { *i.res.errmsg = "invalid uid"; warn << i.cp->unixcred->username << " authenticated with uid " << i.cp->unixcred->uid << " while DB record has uid " << i.cdbr.userinfo->id << "\n"; warn << "could user " << i.cp->unixcred->username << " have" << " wrong UID in sfs_users file?\n"; sbp->replyref (i.res); return; } i.argp = sbp->Xtmpl getarg<sfsauth2_update_arg> (); if (i.argp->req.type != SFS_UPDATEREQ || (i.argp->req.rec.type != SFSAUTH_USER && i.argp->req.rec.type != SFSAUTH_GROUP)) { *i.res.errmsg = "invalid request"; sbp->replyref (i.res); return; } i.opts = i.argp->req.opts; if (i.argp->req.authid != authid) { *i.res.errmsg = "invalid authid"; sbp->replyref (i.res); return ; } static rxx adminrx ("(\\A|,)admin(\\Z|,)"); i.admin = cdbp->allow_admin && adminrx.search (i.cdbr.userinfo->privs); if (!update_checksig (sbp, i, cdbp)) return; if (i.argp->req.rec.type == SFSAUTH_USER) update_user (sbp, i); else update_group (sbp, i); sbp->replyref (i.res); }
void authclnt::update_group (svccb *sbp, update_info &i) { dbfile *udbp; ptr<authcursor> uac; sfsauth_dbrec udbr; *i.kname.name = i.argp->req.rec.groupinfo->name; bool create = i.argp->req.rec.groupinfo->id == 0 && i.argp->req.rec.groupinfo->vers == 1; bool exists = get_group_cursor (&udbp, &uac, &udbr, i.kname, true, create); if (exists && create && udbr.groupinfo->id > udbp->grprange->id_max) { *i.res.errmsg = strbuf () << "all group IDs in the allowed range (" << udbp->grprange->id_min << "-" << udbp->grprange->id_max << ") are in use"; return; } if (!exists) { if (!create) { *i.res.errmsg = "perhaps record is read-only " "or database doesn't accept group updates"; return; } else { *i.res.errmsg = "no writable databases that accept group updates"; return; } } if (create && udbr.groupinfo->vers != 0) { *i.res.errmsg = strbuf () << "group `" << udbr.groupinfo->name << "'already exists"; return; } if (!i.admin) { if (create) { str gname; if (!(gname = group_prefix (udbr.groupinfo->name, i.cdbr.userinfo->name)) || gname.len () < 1) { *i.res.errmsg = strbuf () << "group name must be of the form `" << i.cdbr.userinfo->name << ".groupname'"; return; } static rxx groupquotarx ("(\\A|,)groupquota=([0-9]+)(\\Z|,)"); if (groupquotarx.search (i.cdbr.userinfo->privs) || udbp->default_groupquota >= 0) { u_int32_t max_groups; u_int32_t cur_groups; if (groupquotarx.success ()) convertint (groupquotarx[2], &max_groups); else max_groups = udbp->default_groupquota; // XXX - open could fail ptr<authcursor> gac = udbp->db->open (udbp->dbflags); cur_groups = gac->count_group_prefix (strbuf () << i.cdbr.userinfo->name << "."); if (cur_groups + 1 > max_groups) { *i.res.errmsg = strbuf () << "group quota exceeded (current=" << cur_groups << "/quota=" << max_groups << ")"; return; } } } else { ptr<sfspub> pk = sfscrypt.alloc (i.cdbr.userinfo->pubkey); str h = armor32 (pk->get_pubkey_hash ()); sfs_groupmembers list; unsigned int n = udbr.groupinfo->owners.size (); for (unsigned int j = 0; j < n; j++) list.push_back (udbr.groupinfo->owners[j]); if (!group_prefix (udbr.groupinfo->name, i.cdbr.userinfo->name) && !is_a_member (i.cdbr.userinfo->name, h, list)) { *i.res.errmsg = "access denied"; return; } } } if (i.argp->req.rec.groupinfo->vers < 1) { *i.res.errmsg = "version number of record must be greater than 0"; return; } if (i.argp->req.rec.groupinfo->vers != udbr.groupinfo->vers + 1) { *i.res.errmsg = "version mismatch"; return; } uac->ae.groupinfo->vers = i.argp->req.rec.groupinfo->vers; strbuf sb; sb << "Last modified " << timestr () << " by " ; if (uid && !*uid) sb << "*superuser*"; else sb << i.cp->unixcred->username; sb << "@" << client_name; uac->ae.groupinfo->audit = sb; // XXX: checking to make sure that the owners/groups are well-formed happens in update process_group_updates (udbr.groupinfo->owners, i.argp->req.rec.groupinfo->owners); process_group_updates (udbr.groupinfo->members, i.argp->req.rec.groupinfo->members); uac->ae.groupinfo->owners = udbr.groupinfo->owners; uac->ae.groupinfo->members = udbr.groupinfo->members; bool chlogok = write_group_changelog (i.argp->req.rec.groupinfo->name, i.argp->req.rec.groupinfo->vers, i.argp->req.rec.groupinfo->members, sb); if (!chlogok) { *i.res.errmsg = "could not write changelog; database unmodified"; return; } if (!uac->update ()) { // XXX: remove changelog entry *i.res.errmsg = "database refused update; see SFS documentation for correct syntax"; return; } i.res.set_ok (true); udbp->mkpub (); uac->find_group_name (udbr.groupinfo->name); if (global_dbcache) update_dbcache (uac); }
void hclient_t::do_read () { int rc = uio.input (fd); if (rc == 0 && !output_stuff) { stats.empties ++; warn ("no content before EOF\n"); cexit (-1); return;; } else if (rc == 0) { // legitimate EOF cexit (0); return; } else if (rc == -1) { if (errno != EAGAIN) { stats.read_errors ++ ; warn ("read error: %m\n"); cexit (-1); } return; } assert (rc > 0); // for sane Web servers, this is easy... if (mode != SEDA) { while (uio.resid ()) { output_stuff = true; uio.output (1); } return; } // // for SEDA, we've had to parse the header and cut off the // connection, since it doesn't support closed connections // as we've asked. // rc = uio.copyout (bp); uio.rembytes (rc); bp += rc; // // reqsz < 0 if we haven't found a field yet in the header // if (reqsz < 0) { if (sz_rxx.search (buf)) { if (!convertint (sz_rxx[1], &reqsz)) { warn ("invalid length: %s\n", sz_rxx[1].cstr ()); cexit (-1); } } } if (!body) body = strstr (buf, "\r\n\r\n"); // // if we've seen the required number of bytes (as given by // the header) then we're ready to close (or rock!) // if (body && (bp - body >= reqsz)) { rc_ignore (write (1, buf, bp - buf)); if (noisy) warn ("ok, closing up!\n"); cexit (0); } }
void cgi_mpfd_t::parse_guts () { abuf_stat_t r = ABUF_OK; str dummy; bool inc; while (r == ABUF_OK) { OKDBG4(SVC_MPFD, CHATTER, "cgi_mpfd_t::parse_guts loop " "r=%d, state=%d", int (r), int (state)); inc = true; switch (state) { case MPFD_START: r = match_boundary (); break; case MPFD_EOL0: r = require_crlf (); break; case MPFD_KEY: r = gobble_crlf (); if (r == ABUF_OK) { if (to_start) { state = MPFD_START; to_start = false; } else state = MPFD_SEARCH; inc = false; } else if (r == ABUF_NOMATCH) { r = delimit_key (&mpfd_key); if (r == ABUF_OK) kt = mpfd_ktmap.lookup (mpfd_key); } // else a WAIT or an EOF in gobble_crlf break; case MPFD_SPC: r = abuf->skip_hws (1); cdp.reset (); break; case MPFD_VALUE: if (kt == MPFD_DISPOSITION) { OKDBG3(SVC_MPFD, CHATTER, "cgi_mpfd_t::parse_guts branch to nested " "content disposition parser"); cdp.parse (wrap (this, &cgi_mpfd_t::ext_parse_cb)); OKDBG3(SVC_MPFD, CHATTER, "cgi_mpfd_t::parse_guts return due to " "content disposition parser"); return; } else if (kt == MPFD_TYPE) { r = delimit_val (&content_typ); if (r == ABUF_OK) { if (multipart_rxx.match (content_typ)) { add_boundary (multipart_rxx[1]); to_start = true; } } } else { r = delimit_val (&dummy); } break; case MPFD_EOL1A: r = require_crlf (); break; case MPFD_EOL1B: if (kt == MPFD_DISPOSITION) { if (cdp.typ == CONTDISP_FORMDAT) { cgi_key = cdp.name; filename = cdp.filename; attach = filename; } else if (cdp.typ == CONTDISP_ATTACH) { filename = cdp.filename; attach = true; } else { r = ABUF_PARSE_ERR; } } state = MPFD_KEY; inc = false; break; case MPFD_SEARCH: r = match_boundary (&dat); if (r == ABUF_OK) { if (cgi_key) { if (attach) finsert (cgi_key, cgi_file_t (filename, content_typ, dat)); else insert (cgi_key, dat); cgi_key = NULL; } // in this case, no more boundaries } else if (r == ABUF_PARSE_ERR) { r = ABUF_OK; state = MPFD_EOF; inc = false; } break; case MPFD_SEARCH2: r = parse_2dash (); if (r == ABUF_OK) { remove_boundary (); nxt_state = MPFD_SEARCH; } else if (r == ABUF_NOMATCH) { r = ABUF_OK; nxt_state = MPFD_KEY; } break; case MPFD_SEARCH3: r = require_crlf (); if (r == ABUF_OK) { state = nxt_state; inc = false; } break; case MPFD_EOF: r = abuf->skip_ws (); break; default: break; } if (r == ABUF_OK && inc) MPFD_INC_STATE; } OKDBG4(SVC_MPFD, CHATTER, "cgi_mpfd_t::parse_guts exit loop " "r=%d, state=%d", int (r), int (state)); switch (r) { case ABUF_EOF: int rc; if (state == MPFD_EOF) { rc = HTTP_OK; } else { rc = HTTP_UNEXPECTED_EOF; warn ("mpfd EOF in state %d after %d bytes read\n", int (state), abuf ? abuf->get_ccnt () : -1); } finish_parse (rc); break; case ABUF_PARSE_ERR: finish_parse (HTTP_BAD_REQUEST); break; default: break; } }
bool nameok (const str &name) { static rxx namerx ("[a-zA-Z0-9\\-]+(\\.[a-zA-Z0-9\\-]+)*"); return name.len () < NFS_MAXNAMLEN && namerx.match (name); }
bool str2userinfo (sfsauth_userinfo *ui, str s) { str name; vec<str> uv; if (split (&uv, colon, s, 12, true) != 11) return false; str2wstr (uv[7]); str2wstr (uv[8]); str fields[13] = { "name", "uid", "version", "gid", "owner", "pubkey", "privs", "srp", "privkey", "srvprivkey", // "refresh", "timeout", "audit" }; if (!namerx.match (uv[0])) { err_report ("<null>", 1, fields[0], uv[0]); return false; } name = uv[0]; for (int i = 1; i < 4; i++) { if (!decrx.match (uv[i])) { err_report (name, i+1, fields[i], uv[i]); return false; } } if (uv[4].len () && !namerx.match (uv[4])) { err_report (name, 5, fields[4], uv[4]); return false; } for (int i = 6; i < 10; i++) { if (badcharrx.search (uv[i])) { err_report (name, i+1, fields[i], uv[i]); return false; } } #if 0 for (int i = 10; i < 12; i++) { if (!decrx.match (uv[i])) { err_report (name, i+1, fields[i], uv[i]); return false; } } #endif str privkey = dearmor64 (uv[8]); if (!privkey) { err_report (name, 9, fields[8], "could not dearmor64"); return false; } str2wstr (privkey); ui->privkey.setsize (privkey.len ()); memcpy (ui->privkey.base (), privkey, ui->privkey.size ()); ui->name = uv[0]; if (!convertint (uv[1], &ui->id) || !convertint (uv[2], &ui->vers) || !convertint (uv[3], &ui->gid) // || !convertint (uv[10], &ui->refresh) // || !convertint (uv[11], &ui->timeout) ) return false; if (uv[4].len ()) *ui->owner.alloc () = uv[4]; else ui->owner.clear (); ptr<sfspub> pk = sfscrypt.alloc (uv[5]); if (!pk) return false; if (!pk->export_pubkey (&ui->pubkey)) { warn << "Cannot load keypair for " << uv[0] << "\n"; return false; } ui->privs = uv[6]; ui->pwauth = uv[7]; if (uv[9] && uv[9].len ()) { if (!sfs_2schnorr_priv::parse_keyhalf (&ui->srvprivkey, uv[9])) { warn << "Cannot load server keyhalf for " << uv[0] << "\n"; return false; } } else { ui->srvprivkey.set_type (SFSAUTH_KEYHALF_NONE); } // ui->audit = uv[12]; ui->audit = uv[10]; return true; }
int main (int argc, char *argv[]) { timeout = 120; noisy = false; zippity = false; srandom(time(0)); setprogname (argv[0]); int ch; int n = 1000; nconcur = 500; bool delay = false; timespec startat; startat.tv_nsec = 0; startat.tv_sec = 0; exited = false; hclient_id = 1; use_latencies = false; num_services = 1; tpt_sample_period_secs = 1; tpt_sample_period_nsecs = 0; int lat_stddv = 25; int lat_mean = 75; lose_patience_after = 0; id_cycler_t *svc_cycler = NULL; id_cycler_t *req_cycler = NULL; mode = NONE; bool no_pub = false; int tmp = 0; static rxx lose_patience_rxx ("(\\d+),(\\d+)"); while ((ch = getopt (argc, argv, "c:dlm:n:pr:t:v:zM:P:S:R:T:V:")) != -1) { switch (ch) { case 'c': if (!convertint (optarg, &nconcur)) usage (); if (noisy) warn << "Concurrency factor: " << nconcur << "\n"; break; case 'd': noisy = true; break; case 'l': use_latencies = true; if (noisy) warn << "Using Latencies\n"; break; case 'm': { switch (optarg[0]) { case 's': case 'S': mode = SEDA; if (noisy) warn << "In SEDA mode\n"; break; case 'o': case 'O': mode = OKWS; if (noisy) warn << "In OKWS mode\n"; break; case 'P': case 'p': mode = PHP; if (noisy) warn << "In PHP mode\n"; break; case 'f': case 'F': mode = FLASH; if (noisy) warn << "In FLASH mode\n"; break; default: usage (); break; } break; } case 'n': if (!convertint (optarg, &n)) usage (); if (noisy) warn << "Number of requests: " << n << "\n"; break; case 'p': no_pub = true; break; case 'r': if (!convertint (optarg, &tmp)) usage (); req_cycler = New id_cycler_t (true, tmp, 1); if (noisy) warn << "Ranging ids from 1 to " << tmp << " (randomly)\n"; break; case 't': { if (!convertint (optarg, &startat.tv_sec)) usage (); delay = true; if (noisy) warn << "Delaying start until time=" << startat.tv_sec << "\n"; time_t mytm = time (NULL); tmp = startat.tv_sec - mytm; if (tmp < 0) { warn << "time stamp alreached (it's " << mytm << " right now)!\n"; usage (); } if (noisy) { warn << "Starting in T minus " << tmp << " seconds\n"; } break; } case 'v': if (!convertint (optarg, &tmp)) usage (); svc_cycler = New id_cycler_t (true, tmp, 1); if (noisy) warn << "Randing services from 1 to " << tmp << " (randomly)\n"; break; case 'z': zippity = true; break; case 'M': if (!convertint (optarg, &lat_mean)) usage (); if (noisy) warn << "Mean of latencies: " << lat_mean << "\n"; break; case 'P': if (!convertint (optarg, &tmp)) usage (); tpt_sample_period_secs = tmp / THOUSAND; tpt_sample_period_nsecs = (tmp % THOUSAND) * MILLION; if (noisy) warn ("Sample throughput period=%d.%03d secs\n", tpt_sample_period_secs, tpt_sample_period_nsecs / MILLION); break; case 'R': req_cycler = New id_cycler_t (); if (!req_cycler->init (optarg)) usage (); break; case 'S': if (!convertint (optarg, &lat_stddv)) usage (); if (noisy) warn << "Standard dev. of latency: " << lat_stddv << "\n"; break; case 'T': if (!lose_patience_rxx.match (optarg) || !convertint (lose_patience_rxx[1], &n_still_patient) || !convertint (lose_patience_rxx[2], &lose_patience_after)) usage (); break; case 'V': svc_cycler = New id_cycler_t (); if (!svc_cycler->init (optarg)) usage (); break; default: usage (); } } argc -= optind; argv += optind; if (argc == 0) usage (); str dest = argv[0]; argc --; argv ++; // make the appropriate cyclers... if (argc > 0) { // in this case, the user supplied extra arguments after the hostname // and port; therefore, they're going to be making their own URL // by alternating static parts and cyclers. if (req_cycler) { warn << "Don't provide -r if you're going to make your own URI\n"; usage (); } if (svc_cycler) { warn << "Don't provide -v if you're going to make your own URI\n"; usage (); } for (int i = 0; i < argc; i++) { if (i % 2 == 0) { uri_parts.push_back (argv[i]); } else { id_cycler_t *tmp = New id_cycler_t (); if (!tmp->init (argv[i])) { warn << "Cannot parse ID cycler: " << argv[i] << "\n"; usage (); } id_cyclers.push_back (tmp); } } } else if (mode != NONE) { // no manual URL building required; just specify some defaults // though if none were specified if (!req_cycler) // roughly a million, but this way all reqs will have the same // number of digits req_cycler = New id_cycler_t (true, 900000, 100000); if (!svc_cycler) // don't cycle --- just always return 1 svc_cycler = New id_cycler_t (false, 1, 1); id_cyclers.push_back (svc_cycler); id_cyclers.push_back (req_cycler); switch (mode) { case SEDA: uri_parts.push_back ("mt"); uri_parts.push_back ("?id="); break; case OKWS: { uri_parts.push_back ("mt"); strbuf b ("?"); if (no_pub) b << "nopub=1&"; b << "id="; uri_parts.push_back (b); break; } case PHP: uri_parts.push_back ("mt"); uri_parts.push_back (".php?id="); break; case FLASH: uri_parts.push_back ("cgi-bin/mt"); uri_parts.push_back ("?"); break; default: break; } } // normdist (mean, std-dev, "precision") if (use_latencies) dist = New normdist_t (200,25); if (!hostport.match (dest)) usage (); host = hostport[1]; str port_s = hostport[3]; if (port_s) { if (!convertint (port_s, &port)) usage (); } else { port = 80; } struct timespec tsnow = sfs_get_tsnow (); // unless we don this, shit won't be initialized, and i'll // starting ripping my hair out as to why all of the timestamps // are negative clock_gettime (CLOCK_REALTIME, &tsnow); nrunning = 0; sdflag = true; nreq = n; nreq_fixed = n; tpt_last_nreq = nreq; if (delay) { timecb (startat, wrap (main2, n)); } else { main2 (n); } amain (); }