u_int acl::get_permissions (sfsauth_cred *cred, str *key, vec<sfs_idname> *groups) { vec<str> credstrings; u_int p = 0; // 3 kinds of access: anonymous, public key, unix credentials // anonymous means that the user wasn't running an agent or // for some reason the authd couldn't even return a public key if (key) credstrings.push_back (strbuf () << TYPEPK << ACLDIV << *key); if (cred) credstrings.push_back (strbuf () << TYPELOCALUSER << ACLDIV << cred->unixcred->username); if (groups) { for (unsigned int i = 0; i < groups->size (); i++) credstrings.push_back (strbuf () << TYPELOCALGROUP << ACLDIV << (*groups)[i]); } if (!cred && !key) credstrings.push_back (strbuf () << TYPESYS << ACLDIV << SYS_ANONYMOUS); str flattened_creds (""); for (u_int i = 0; i < credstrings.size (); i++) { warn ("CRED[%d]: %s\n", i, credstrings[i].cstr ()); flattened_creds = strbuf () << flattened_creds << credstrings[i]; } #if PCACHE //make hash out of acl and user; ask cache about hash str ua = strbuf () << armor32 (str (aclhash, sizeof (aclhash))) << flattened_creds; bzero (hashbuf, sizeof (hashbuf)); sha1_hash (hashbuf, ua.cstr (), ua.len ()); if (is_cached (hashbuf, p)) { warn << "Using cached perms (" << get_strpermissions (p) << ") for cache key "<< armor32 (str (hashbuf, sizeof (hashbuf))) << "\n"; return p; } else { warn << "Did not find cached perms (" << ua << ") for cache key " << armor32 (str (hashbuf, sizeof (hashbuf))) << "\n"; } #endif p = parse_acl (credstrings); #if PCACHE insert_cache (hashbuf, p); #endif return p; }
void acl::insert_cache (const char *u, u_int p) { lastpos = (lastpos + 1) % PCACHESIZE; if (pcache[lastpos].set (u, p)) { #if ACL_CACHETEST warn << "Inserting cache permissions for key " << armor32 (str (u, sizeof (hashbuf))) << "\nat cache position " << lastpos << "\n"; #endif } else warn << "Failed to cache permissions for key " << armor32 (str (u, sizeof (hashbuf))) << "\n"; }
inline str arg2user (const sfs_autharg2 &aa) { str user; switch (aa.type) { case SFS_AUTHREQ2: user = aa.sigauth->req.user; break; case SFS_UNIXPWAUTH: user = aa.pwauth->req.user; break; case SFS_SRPAUTH: user = aa.srpauth->req.user; break; default: user = ""; break; } for (const char *p = user; *p; p++) if (*p <= ' ' || *p >= 127) { user = ""; break; } if (user.len ()) return user; switch (aa.type) { case SFS_AUTHREQ: if (ptr<sfspub> pk = sfscrypt.alloc (aa.authreq1->usrkey)) user = strbuf ("keyhash ") << armor32 (pk->get_pubkey_hash ()); break; case SFS_AUTHREQ2: if (ptr<sfspub> pk = sfscrypt.alloc (aa.sigauth->key)) user = strbuf ("keyhash ") << armor32 (pk->get_pubkey_hash ()); break; default: break; } if (!user || !user.len ()) user = "******"; return user; }
bool pcache_entry::set (const char *h, u_int p) { //copy h -> hashbuf bzero (hashbuf, sizeof (hashbuf)); memcpy (hashbuf, h, sizeof (hashbuf)); warn << "Setting cache entry perms (" << get_strpermissions (p) << ") for key " << armor32 (str (h, sizeof (hashbuf))) << "\n"; perms = p; key_set = true; return true; }
static void sclone (ref<asrv> s, ref<axprt_clone> x, sockaddr_in sin, svccb *sbp) { s->setcb (NULL); if (!sbp) { warn ("invalid connect from %s\n", inet_ntoa (sin.sin_addr)); return; } if (sbp->proc () != SFSPROC_CONNECT) { sbp->reject (PROC_UNAVAIL); return; } sfs_connectarg *arg = sbp->Xtmpl getarg<sfs_connectarg> (); u_int32_t rel; sfs_service service; str name; sfs_hash hostid; rpc_vec<sfs_extension, RPC_INFINITY> *extensions; switch (arg->civers) { case 4: rel = 4; service = arg->ci4->service; name = arg->ci4->name; hostid = arg->ci4->hostid; extensions = &arg->ci4->extensions; break; case 5: rel = arg->ci5->release; service = arg->ci5->service; if (!sfs_parsepath (arg->ci5->sname, &name, &hostid)) name = arg->ci5->sname; extensions = &arg->ci5->extensions; break; default: sbp->reject (GARBAGE_ARGS); return; } bhash<str> eh; for (const sfs_extension *ep = extensions->base (); ep < extensions->lim (); ep++) eh.insert (*ep); sfs_pathrevoke cert; str rawcert = file2str (revocationdir << "/" << armor32 (hostid.base (), hostid.size ())); if (rawcert && str2xdr (cert, rawcert)) { sfs_connectres res(SFS_REDIRECT); res.revoke->msg = cert.msg; res.revoke->sig = cert.sig; sbp->reply (&res); return; } const char *source = inet_ntoa (sin.sin_addr); server *srv; for (srv = serverlist.first; srv; srv = serverlist.next (srv)) if (srv->host == name && srv->hostid && *srv->hostid == hostid) if (srv->clone (x, sbp, source, rel, service, eh)) return; else break; for (srv = serverlist.first; srv; srv = serverlist.next (srv)) if (srv->host == name && !srv->hostid) if (srv->clone (x, sbp, source, rel, service, eh)) return; else break; for (srv = serverlist.first; srv; srv = serverlist.next (srv)) if (srv->host == name) if (srv->clone (x, sbp, source, rel, service, eh)) return; for (srv = serverlist.first; srv; srv = serverlist.next (srv)) if (srv->clone (x, sbp, source, rel, service, eh)) return; sbp->replyref (sfs_connectres (SFS_NOSUCHHOST)); }
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); }