WvStreams
unisecuregen.cc
1 /*
2  * Worldvisions Weaver Software:
3  * Copyright (C) 2002 Net Integration Technologies, Inc.
4  *
5  * UniSecureGen is a UniConfGen for checking permissions before allowing
6  * access to a UniConf tree. See unisecuregen.h and unipermgen.h.
7  */
8 #include "unisecuregen.h"
9 #include "wvmoniker.h"
10 #include "wvstringlist.h"
11 #include "wvtclstring.h"
12 #include "wvlog.h"
13 #include "wvbuf.h"
14 #include "wvlinkerhack.h"
15 
16 WV_LINK(UniSecureGen);
17 
18 
19 static IUniConfGen *creator(WvStringParm s, IObject *)
20 {
21  return new UniSecureGen(s);
22 }
23 
24 static WvMoniker<IUniConfGen> reg("perm", creator);
25 
26 
27 UniSecureGen::UniSecureGen(WvStringParm moniker, UniPermGen *_perms)
28  : UniFilterGen(NULL)
29 {
30  WvString mainmon(moniker), permmon;
31 
32  if (!_perms)
33  {
34  WvConstInPlaceBuf buf(moniker, moniker.len());
35  permmon = wvtcl_getword(buf);
36  mainmon = wvtcl_getword(buf);
37 
38  IUniConfGen *_perms = wvcreate<IUniConfGen>(permmon);
39  assert(_perms);
40  perms = new UniPermGen(_perms);
41  perms->refresh();
42  }
43 
44  IUniConfGen *main = wvcreate<IUniConfGen>(mainmon);
45  setinner(main);
46 }
47 
48 
49 UniSecureGen::UniSecureGen(IUniConfGen *_gen, UniPermGen *_perms)
50  : UniFilterGen(_gen)
51 {
52  assert(_perms);
53  perms = _perms;
54  perms->refresh();
55 }
56 
57 
58 void UniSecureGen::setcredentials(const UniPermGen::Credentials &_cred)
59 {
60  cred.user = _cred.user;
61  cred.groups.zap();
62  WvStringTable::Iter i(_cred.groups);
63  for (i.rewind(); i.next(); )
64  cred.groups.add(new WvString(*i), true);
65 }
66 
67 
68 void UniSecureGen::setcredentials(WvStringParm user, const WvStringList &groups)
69 {
70  cred.user = user;
71  cred.groups.zap();
72  WvStringList::Iter i(groups);
73  for (i.rewind(); i.next(); )
74  cred.groups.add(new WvString(*i), true);
75 }
76 
77 
79 {
80  perms->refresh();
81  return UniFilterGen::refresh();
82 }
83 
84 
86 {
87  perms->commit();
89 }
90 
91 
93 {
94  if (findperm(key, UniPermGen::READ))
95  {
96  WvString val = UniFilterGen::get(key);
97  return val;
98  }
99 
100  return WvString::null;
101 }
102 
103 
105 {
106  if (findperm(key.removelast(), UniPermGen::EXEC))
107  return UniFilterGen::exists(key);
108  return false;
109 }
110 
111 
113 {
114  if (findperm(key, UniPermGen::WRITE))
115  UniFilterGen::set(key, value);
116 }
117 
118 
120 {
121  if (findperm(key, UniPermGen::EXEC))
122  return UniFilterGen::haschildren(key);
123  return false;
124 }
125 
126 
128 {
129  UniFilterGen::Iter *it;
130  UniSecureGen *gen;
131  UniConfKey subpath;
132 
133 public:
135  it(_it),
136  gen(_gen),
137  subpath(_subpath)
138  { }
139  virtual ~_UniSecureIter()
140  { delete it; }
141 
142  virtual void rewind()
143  { it->rewind(); }
144 
145  virtual bool next()
146  { return it->next(); }
147 
148  virtual UniConfKey key() const
149  { return it->key(); } // if we've come this far, this is ok
150 
151  virtual WvString value() const
152  {
153  UniConfKey realkey = it->key();
154  realkey.prepend(subpath);
155  return gen->get(realkey);
156  }
157 };
158 
159 
161 {
162  // we don't check the permissions on keys returned by the iterator, but
163  // that's okay: since this iterator is non-recursive, and we've checked
164  // permissions on the parent key, we know we're allowed to at least read
165  // the *names* of all child keys (even if the value itself is unreadable)
166  if (findperm(key, UniPermGen::EXEC))
167  return new _UniSecureIter(UniFilterGen::iterator(key), this, key);
168 
169  return NULL;
170 }
171 
172 
174 {
175  // FIXME: this needs to check permissions on *every* key, not just the
176  // top one, so we'll cheat: use the default UniConfGen recursiveiterator
177  // instead, which just calls the non-recursive iterator recursively.
178  // This can be bad for performance, but not in any of the situations
179  // we currently need. (ie. security is usually done on the server side,
180  // but it's the client-to-server connection that needs a fast recursive
181  // iterator, so it'll be fine.)
182  if (findperm(key, UniPermGen::EXEC))
183  return UniConfGen::recursiveiterator(key);
184 
185  return NULL;
186 }
187 
188 
189 void UniSecureGen::gencallback(const UniConfKey &key, WvStringParm value)
190 {
191  if (findperm(key, UniPermGen::READ))
192  delta(key, value);
193 }
194 
195 
196 bool UniSecureGen::findperm(const UniConfKey &key, UniPermGen::Type type)
197 {
198  if (!drilldown(key))
199  return false;
200  else
201  return perms->getperm(key, cred, type);
202 }
203 
204 
205 bool UniSecureGen::drilldown(const UniConfKey &key)
206 {
207  UniConfKey check;
208  UniConfKey left = key;
209 
210  while (!left.isempty())
211  {
212  // check the exec perm
213  if (!perms->getperm(check, cred, UniPermGen::EXEC))
214  return false;
215 
216  // move the first segment of left to check
217  // note that when left is empty, we exit the loop before checking the
218  // last segment. That's on purpose: the last segment is the 'file'
219  // and we only need to check the 'directories'
220  check.append(left.first());
221  left = left.removefirst();
222  }
223  return true;
224 }