// -*-c++-*- /* $Id: auth2str.C,v 1.2 2001/11/19 06:02:03 dm 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 * */ /* * The routines in this file transform an authentry from * authdb_types.x into a string and vice versa. The strings have the * following formats. For users: * * name:version:audit-info:U:owner:pubkey:privs:pwauth:privkey * * Here privs is a semicolon-delimited list of the following: * * admin - meaning administrative privileges on the database * login=LOGNAME - privileges correspond to local user LOGNAME * ids=UID,GID[,GID,...] - privileges correspond to user and group ids * * For groups: * * name:version:audit-info:G:owners:gid:members */ #include "authdb.h" #include "rxx.h" #include "serial.h" #include "parseopt.h" #define AUTHNAME "[A-Za-z/]\\w{0,31}" #define NOBAD "[^\\x00-\\x1f\\x7f-\\xff:]*" static rxx namerx (AUTHNAME); 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 (NOBAD); static bool printlist (strbuf &res, const authnamelist &list) { for (u_int i = 0; i < list.size (); i++) { if (!namerx.match (list[i])) return false; if (i) res << ","; res << list[i]; } return true; } static bool printuser (strbuf &res, const authdb_user &u) { res << ":U::0x" << u.pubkey.getstr (16) << ":"; bool cred = false; for (u_int i = 0; i < u.privs.size (); i++) { if (i) res << ";"; switch (u.privs[i].type) { case PRIV_ADMIN: res << "admin"; break; case PRIV_LOGIN: if (cred) return false; cred = true; if (!namerx.match (*u.privs[i].login)) return false; res << "login=" << *u.privs[i].login; break; case PRIV_IDS: if (cred) return false; cred = true; res << "ids=" << u.privs[i].ids->uid << "," << u.privs[i].ids->gid; for (u_int j = 0; j < u.privs[i].ids->groups.size (); j++) res << "," << u.privs[i].ids->groups[j]; break; default: return false; } } res << ":"; switch (u.pwauth.type) { case PWAUTH_NONE: break; case PWAUTH_SRP: { str s (u.pwauth.srp->base (), u.pwauth.srp->size ()); if (!srprx.match (s)) return false; res << s; break; } default: return false; } res << ":" << armor64 (u.privkey.base (), u.privkey.size ()); return true; } str authent2str (const authentry *ae) { strbuf res; if (!namerx.match (ae->name)) return NULL; res << ae->name << ":" << ae->vers << ":"; str audit (ae->audit.base (), ae->audit.size ()); if (nobadrx.match (audit)) res << audit; switch (ae->info.type) { case AUTHDB_USER: if (!printuser (res, *ae->info.user)) return NULL; break; case AUTHDB_GROUP: res << ":G:"; if (!printlist (res, ae->info.group->owners)) return NULL; res << ":" << ae->info.group->id << ":"; if (!printlist (res, ae->info.group->members)) return NULL; break; default: return NULL; } return res; } static bool parselist (authnamelist *lp, str txt) { vec list; split (&list, commaplus, txt); lp->setsize (list.size ()); for (u_int i = 0; i < list.size (); i++) { if (!namerx.match (list[i])) return false; (*lp)[i] = list[i]; } return true; } static bool parseids (authids *ids, str txt, bool strict) { vec list; split (&list, commaplus, txt); if (list.size () < 2) return false; if (list.size () - 2 > ids->groups.maxsize) { if (strict) return false; ids->groups.setsize (ids->groups.maxsize); } else ids->groups.setsize (list.size () - 2); if (!convertint (list.pop_front (), &ids->uid) || !convertint (list.pop_front (), &ids->gid)) return false; for (u_int i = 0; i < list.size (); i++) if (!convertint (list[i], &ids->groups[i])) return false; return true; } static bool parsepriv (privlist *privs, str txt, bool strict) { static rxx semiplus (";+"); static rxx loginrx ("login=("AUTHNAME")"); static rxx idsrx ("ids=([\\d,]+)"); vec txtv; split (&txtv, semiplus, txt); vec pv; bool cred = false; for (str *tp = txtv.base (); tp < txtv.lim (); tp++) { if (*tp == "admin") pv.push_back (privilege (PRIV_ADMIN)); else if (loginrx.match (*tp)) { if (cred) return false; cred = true; pv.push_back (privilege (PRIV_LOGIN)); *pv.back ().login = loginrx[1]; } else if (idsrx.match (*tp)) { if (cred) return false; cred = true; pv.push_back (privilege (PRIV_IDS)); if (!parseids (pv.back ().ids, idsrx[1], strict)) return false; } else if (strict) return false; } return true; } static bool parseuser (authentry *ae, str txt, bool strict) { static rxx userrx ("([^:]+)?:(0x[0-9a-f]+):([^:]*):([^:]+)?" ":([0-9a-zA-Z+/=]*)"); if (!userrx.match (txt)) return false; if (str owner = userrx[1]) *ae->info.user->owner.alloc () = owner; else ae->info.user->owner.clear (); ae->info.user->pubkey = userrx[2]; if (!parsepriv (&ae->info.user->privs, userrx[3], strict)) return false; ae->info.user->pwauth.set_type (PWAUTH_NONE); if (str pwa = userrx[4]) { if (srprx.match (pwa)) { ae->info.user->pwauth.set_type (PWAUTH_SRP); *ae->info.user->pwauth.srp = pwa; } else if (strict) return false; } if (str privkey = dearmor64 (userrx[5])) ae->info.user->privkey = privkey; else return false; return true; } bool str2authent (authentry *ae, str txt, bool strict) { static rxx authline ("("AUTHNAME"):(\\d+)?:("NOBAD"):([A-Z]):(.*)\n?"); static rxx grouprx ("([^:]*):(\\d+):([^:]*)"); if (!authline.match (txt)) return false; ae->name = authline[1]; ae->vers = 0; if (str v = authline[2]) convertint (v, &ae->vers); ae->audit = authline[3]; switch (authline[4][0]) { case 'U': if (!parseuser (ae, authline[5], strict)) return false; break; case 'G': ae->info.set_type (AUTHDB_GROUP); if (!grouprx.match (authline[5]) || !convertint (grouprx[2], &ae->info.group->id) || !parselist (&ae->info.group->owners, grouprx[1]) || !parselist (&ae->info.group->members, grouprx[3])) return false; break; default: return false; } return true; }