// -*-c++-*- /* $Id: dbrec2str.C,v 1.11 2002/10/22 20:33:43 max Exp $ */ /* * * Copyright (C) 2001 David Mazieres (dm@uun.org) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA * */ /* * Converts users to/from the following text representation: * USER:name:uid:version:gid:owner:pubkey:privs:srpinfo:privkey:audit * * Converts groups to/from the following: * GROUP:name:gid:version:owners:members:audit */ #include "authdb.h" #include "wmstr.h" #include "serial.h" #include "rxx.h" #include "parseopt.h" #include "sfsschnorr.h" #define AUTHNAME "[A-Za-z][\\w/]{0,31}" #define BADCHAR "\\x00-\\x1f\\x7f-\\xff:" static rxx namerx (AUTHNAME); static rxx colon (":"); static rxx comma (","); static rxx commaplus (",+"); static rxx srprx ("SRP,N=(0x[\\da-f]+),g=(0x[\\da-f]+)," "s=(\\d+\\$[A-Za-z0-9+/]+={0,2}\\$[\\w\\.\\-]*)," "v=(0x[\\da-f]+)"); static rxx nobadrx ("[^"BADCHAR"]*"); static rxx badcharrx ("(["BADCHAR"])"); static rxx hexrx ("0x[\\da-fA-F]+"); static rxx decrx ("\\d+"); void err_report (int i, str d, str v); static bool printname (strbuf &sb, sfs_idname name) { if (!namerx.match (name)) return false; sb << name; return true; } static bool parsename (sfs_idname *name, str s) { if (!namerx.match (s)) return false; *name = s; return true; } #if 0 static bool printnum (strbuf &sb, u_int32_t num) { sb.fmt ("%u", num); return true; } static bool parsenum (u_int32_t *nump, str s) { return convertint (s, nump); } #endif template static bool printlist (strbuf &sb, const rpc_vec &v, bool (*printfn) (strbuf &, T)) { bool first = true; for (const T *tp = v.base (); tp < v.lim (); tp++) { if (first) first = false; else sb << ","; if (!printfn (sb, *tp)) return false; } return true; } template static bool parselist (rpc_vec *vp, str s, bool (*parsefn) (T *, str)) { vec sv; split (&sv, commaplus, s); if (!sv.empty () && !sv.front ().len ()) sv.pop_front (); if (!sv.empty () && !sv.back ().len ()) sv.pop_back (); vp->setsize (sv.size ()); for (size_t i = 0; i < vp->size (); i++) if (!parsefn (&(*vp)[i], sv[i])) return false; return true; } str single_char_sub (const str &in, const char find, const str &repl) { const char *cp = in.cstr (); int len = in.len (); int segstart = 0; int seglen = 0; strbuf sb; for (int i = 0; i < len ; i++) { if (cp[i] == find) { if (seglen) sb << substr (cp, segstart, seglen); sb << repl; seglen = 0; segstart = i + 1; } else { seglen ++; } } if (seglen) sb << substr (cp, segstart, seglen); return sb; } 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 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 << ":" << audit; return true; } bool groupinfo2str (strbuf &sb, const sfsauth_groupinfo *gi) { if (!namerx.match (gi->name) || badcharrx.search (gi->audit)) return false; sb << gi->name; sb.fmt (":%u:%u:", gi->id, gi->vers); if (!printlist (sb, gi->owners, printname)) return false; sb << ":"; if (!printlist (sb, gi->members, printname)) return false; sb << ":" << gi->audit; return true; } str authdbrec2str (const sfsauth_dbrec *dbr) { strbuf sb; switch (dbr->type) { case SFSAUTH_USER: sb << "USER:"; if (userinfo2str (sb, dbr->userinfo)) { str s (sb); return str2wstr (s); } return NULL; case SFSAUTH_GROUP: sb << "GROUP:"; if (groupinfo2str (sb, dbr->groupinfo)) return sb; return NULL; default: return NULL; } } void err_report (const str &name, int fieldno, const str &desc, str val) { warn << "Name " << name << ", " << warn << "Field " << fieldno << ": '" << desc << "': Bad value: " << val << "\n"; } bool str2userinfo (sfsauth_userinfo *ui, str s) { str name; vec uv; if (split (&uv, colon, s, 12, true) != 11) return false; str2wstr (uv[7]); str2wstr (uv[8]); str fields[11] = { "name", "uid", "version", "gid", "owner", "pubkey", "privs", "srp", "privkey", "srvprivkey", "audit" }; if (!namerx.match (uv[0])) { err_report ("", 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; } } 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)) return false; if (uv[4].len ()) *ui->owner.alloc () = uv[4]; else ui->owner.clear (); ptr 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[10]; return true; } bool str2groupinfo (sfsauth_groupinfo *gi, str s) { vec gv; if (split (&gv, colon, s, 7, true) != 6) 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], parsename) || !parselist (&gi->members, gv[4], parsename)) return false; gi->audit = gv[5]; return true; } bool str2authdbrec (sfsauth_dbrec *dbr, str s) { static rxx _userrx ("^USER:(.*)$"); rxx userrx (_userrx); static rxx grouprx ("^GROUP:(.*)$"); 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 return false; }