WvStreams
unisecuregen.cc
00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 2002 Net Integration Technologies, Inc.
00004  * 
00005  * UniSecureGen is a UniConfGen for checking permissions before allowing
00006  * access to a UniConf tree.  See unisecuregen.h and unipermgen.h.
00007  */
00008 #include "unisecuregen.h"
00009 #include "wvmoniker.h"
00010 #include "wvstringlist.h"
00011 #include "wvtclstring.h"
00012 #include "wvlog.h"
00013 #include "wvbuf.h"
00014 #include "wvlinkerhack.h"
00015 
00016 WV_LINK(UniSecureGen);
00017 
00018 
00019 static IUniConfGen *creator(WvStringParm s, IObject *)
00020 {
00021     return new UniSecureGen(s);
00022 }
00023 
00024 static WvMoniker<IUniConfGen> reg("perm", creator);
00025 
00026 
00027 UniSecureGen::UniSecureGen(WvStringParm moniker, UniPermGen *_perms)
00028     : UniFilterGen(NULL)
00029 {
00030     WvString mainmon(moniker), permmon;
00031 
00032     if (!_perms)
00033     {
00034         WvConstInPlaceBuf buf(moniker, moniker.len());
00035         permmon = wvtcl_getword(buf);
00036         mainmon = wvtcl_getword(buf);
00037     
00038         IUniConfGen *_perms = wvcreate<IUniConfGen>(permmon);
00039         assert(_perms);
00040         perms = new UniPermGen(_perms);
00041         perms->refresh();
00042     }
00043     
00044     IUniConfGen *main = wvcreate<IUniConfGen>(mainmon);
00045     setinner(main);
00046 }
00047 
00048 
00049 UniSecureGen::UniSecureGen(IUniConfGen *_gen, UniPermGen *_perms)
00050     : UniFilterGen(_gen)
00051 {
00052     assert(_perms);
00053     perms = _perms;
00054     perms->refresh();
00055 }
00056 
00057 
00058 void UniSecureGen::setcredentials(const UniPermGen::Credentials &_cred)
00059 {
00060     cred.user = _cred.user;
00061     cred.groups.zap();
00062     WvStringTable::Iter i(_cred.groups);
00063     for (i.rewind(); i.next(); )
00064         cred.groups.add(new WvString(*i), true);
00065 }
00066 
00067 
00068 void UniSecureGen::setcredentials(WvStringParm user, const WvStringList &groups)
00069 {
00070     cred.user = user;
00071     cred.groups.zap();
00072     WvStringList::Iter i(groups);
00073     for (i.rewind(); i.next(); )
00074         cred.groups.add(new WvString(*i), true);
00075 }
00076 
00077 
00078 bool UniSecureGen::refresh()
00079 {
00080     perms->refresh();
00081     return UniFilterGen::refresh();
00082 }
00083 
00084 
00085 void UniSecureGen::commit()
00086 {
00087     perms->commit();
00088     UniFilterGen::commit();
00089 }
00090 
00091 
00092 WvString UniSecureGen::get(const UniConfKey &key)
00093 {
00094     if (findperm(key, UniPermGen::READ))
00095     {
00096         WvString val = UniFilterGen::get(key);
00097         return val;
00098     }
00099 
00100     return WvString::null;
00101 }
00102 
00103 
00104 bool UniSecureGen::exists(const UniConfKey &key)
00105 {
00106     if (findperm(key.removelast(), UniPermGen::EXEC))
00107         return UniFilterGen::exists(key);
00108     return false;
00109 }
00110 
00111 
00112 void UniSecureGen::set(const UniConfKey &key, WvStringParm value)
00113 {
00114     if (findperm(key, UniPermGen::WRITE))
00115         UniFilterGen::set(key, value);
00116 }
00117 
00118 
00119 bool UniSecureGen::haschildren(const UniConfKey &key)
00120 {
00121     if (findperm(key, UniPermGen::EXEC))
00122         return UniFilterGen::haschildren(key);
00123     return false;
00124 }
00125 
00126 
00127 class _UniSecureIter : public UniConfGen::Iter
00128 {
00129     UniFilterGen::Iter *it;
00130     UniSecureGen *gen;
00131     UniConfKey subpath;
00132 
00133 public:
00134     _UniSecureIter(UniFilterGen::Iter *_it, UniSecureGen *_gen, UniConfKey _subpath) :
00135         it(_it),
00136         gen(_gen),
00137         subpath(_subpath)
00138         { }
00139     virtual ~_UniSecureIter()
00140         { delete it; }
00141 
00142     virtual void rewind() 
00143         { it->rewind(); }
00144 
00145     virtual bool next()
00146         { return it->next(); }
00147 
00148     virtual UniConfKey key() const 
00149         { return it->key(); } // if we've come this far, this is ok
00150 
00151     virtual WvString value() const
00152         {
00153             UniConfKey realkey = it->key();
00154             realkey.prepend(subpath);
00155             return gen->get(realkey);
00156         }               
00157 };
00158 
00159 
00160 UniConfGen::Iter *UniSecureGen::iterator(const UniConfKey &key)
00161 {
00162     // we don't check the permissions on keys returned by the iterator, but
00163     // that's okay: since this iterator is non-recursive, and we've checked
00164     // permissions on the parent key, we know we're allowed to at least read
00165     // the *names* of all child keys (even if the value itself is unreadable)
00166     if (findperm(key, UniPermGen::EXEC))
00167         return new _UniSecureIter(UniFilterGen::iterator(key), this, key); 
00168 
00169     return NULL;
00170 }
00171 
00172 
00173 UniConfGen::Iter *UniSecureGen::recursiveiterator(const UniConfKey &key)
00174 {
00175     // FIXME: this needs to check permissions on *every* key, not just the
00176     // top one, so we'll cheat: use the default UniConfGen recursiveiterator
00177     // instead, which just calls the non-recursive iterator recursively.
00178     // This can be bad for performance, but not in any of the situations
00179     // we currently need. (ie. security is usually done on the server side,
00180     // but it's the client-to-server connection that needs a fast recursive
00181     // iterator, so it'll be fine.)
00182     if (findperm(key, UniPermGen::EXEC))
00183         return UniConfGen::recursiveiterator(key);
00184 
00185     return NULL;
00186 }
00187 
00188 
00189 void UniSecureGen::gencallback(const UniConfKey &key, WvStringParm value)
00190 {
00191     if (findperm(key, UniPermGen::READ))
00192         delta(key, value);
00193 }
00194 
00195 
00196 bool UniSecureGen::findperm(const UniConfKey &key, UniPermGen::Type type)
00197 {
00198     if (!drilldown(key))
00199         return false;
00200     else
00201         return perms->getperm(key, cred, type);
00202 }
00203 
00204 
00205 bool UniSecureGen::drilldown(const UniConfKey &key)
00206 {
00207     UniConfKey check;
00208     UniConfKey left = key;
00209 
00210     while (!left.isempty())
00211     {
00212         // check the exec perm
00213         if (!perms->getperm(check, cred, UniPermGen::EXEC))
00214             return false;
00215 
00216         // move the first segment of left to check
00217         // note that when left is empty, we exit the loop before checking the
00218         // last segment.  That's on purpose: the last segment is the 'file'
00219         // and we only need to check the 'directories'
00220         check.append(left.first());
00221         left = left.removefirst();
00222     }
00223     return true;
00224 }