WvStreams
|
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 }