OSDN Git Service

reduce regex's.
[hmh/hhml.git] / ext / ml-tcpserver.cc
1 #include "ml-tcpserver.h"
2 #include "motorconst.h"
3 #include "ml.h"
4 #include "mlenv.h"
5 #include "motorenv.h"
6 #include "ustring.h"
7 #include "expr.h"
8 #include "util_const.h"
9 #include "util_check.h"
10 #include "util_string.h"
11 #include "bdbmacro.h"
12 #include "sigsafe.h"
13 #include <sys/file.h>
14 #include <string.h>
15 #include <time.h>
16 #include <exception>
17
18 /*DOC:
19 ==dbtcpserver module==
20
21 */
22 static uregex  re_iprange ("^[0-9]{1,3}\\.([0-9]{1,3}\\.([0-9]{1,3}\\.([0-9]{1,3})?)?)?$");
23 static uregex  re_domainrange ("^\\.?[a-zA-Z0-9][a-zA-Z0-9\\-]*(\\.[a-zA-Z0-9][a-zA-Z0-9\\-]*)*$");
24
25 void  MLDbTcpserver::setPath (const ustring& name) {
26     dbpath = mlenv->env->path_to_auth (name);
27     dbpath.append (CharConst (kEXT_HASH));
28 }
29
30 void  MLDbTcpserver::opendb () {
31     db.open (dbpath.c_str ());
32     flock (db.db->fd (db.db), LOCK_EX);
33 }
34
35 void  MLDbTcpserver::closedb () {
36     if (db.db) {
37         flock (db.db->fd (db.db), LOCK_UN);
38         db.close ();
39     }
40 }
41
42 void  MLDbTcpserver::addAllow (const ustring& key, time_t span, MNode* rest, MlEnv* mlenv) {
43     ustring  val;
44     ustring  estr;
45
46     if (span < 0)
47         span = 1;               // timeout
48     if (span > 0) {
49         span += time (NULL);
50         val.append (CharConst ("\xff\xff\xff\xff")).append ((const char*)(&span), sizeof (time_t));
51     }
52     if (rest) {
53         while (rest) {
54             estr = eval_str (rest->car (), mlenv);
55             nextNode (rest);
56 //          if (! checkASCII (estr) || estr.length () > 1024)
57             if (! matchASCII (estr.begin (), estr.end ()) || estr.length () > 1024)
58                 throw (estr + uErrorBadValue);
59             val.append (CharConst ("+")).append (estr).append (1, 0);
60         }
61     }
62     db.put (key, val);
63 }
64
65 void  MLDbTcpserver::addDeny (const ustring& key) {
66     ustring  val;
67
68     val.assign (CharConst ("D\x00"));
69     db.put (key, val);
70 }
71
72 void  MLDbTcpserver::del (const ustring& key) {
73     db.del (key);
74 }
75
76 bool  MLDbTcpserver::splitRec (const ustring& rec, bool& allow, time_t& limit, MNodeList& estr) {
77     uiterator  b, e, m;
78
79     b = rec.begin ();
80     e = rec.end ();
81     allow = true;
82     limit = 0;
83     if (b == e) {
84         return true;
85     } else if (matchHead (b, e, CharConst ("D\x00"))) {
86         allow = false;
87         limit = 0;
88         return true;
89     } else if (matchSkip (b, e, CharConst ("\xff\xff\xff\xff"))) {
90         if (e - b >= sizeof (time_t)) {
91             allow = true;
92             memcpy ((void*)&limit, &*b, sizeof (time_t));
93             b += sizeof (time_t);
94         } else {
95             return false;
96         }
97     }
98     while (b <= e) {
99         if (b == e) {
100             return true;
101         } else {
102             if (*b == '+') {
103                 b ++;
104                 if (splitChar (b, e, '\x00', m)) {
105                     estr.append (newMNode_str (new ustring (b, m)));
106                     b = m + 1;
107                 }
108             }
109         }
110     }
111     return false;
112 }
113
114 bool  MLDbTcpserver::splitRec (const ustring& rec, bool& allow, time_t& limit) {
115     uiterator  b, e, m;
116
117     b = rec.begin ();
118     e = rec.end ();
119     allow = true;
120     limit = 0;
121     if (b == e) {
122         return true;
123     } else if (matchHead (b, e, CharConst ("D\x00"))) {
124         allow = false;
125         limit = 0;
126         return true;
127     } else if (matchSkip (b, e, CharConst ("\xff\xff\xff\xff"))) {
128         if (e - b >= sizeof (time_t)) {
129             allow = true;
130             memcpy ((void*)&limit, &*b, sizeof (time_t));
131             b += sizeof (time_t);
132         } else {
133             return false;
134         }
135     }
136     return true;
137 }
138
139 /*DOC:
140 ===$dbtcpserver===
141  ($dbtcpserver NAME [SUBFUNCTION...])
142 DJBのucspi-tcp拡張版のBerkeleyDBアクセス制御データベースのハンドリング。
143
144 */
145 //#MFUNC        $dbtcpserver    ml_dbtcpserver  cMLDbTcpserverID
146 MNode*  ml_dbtcpserver (MNode* cell, MlEnv* mlenv) {
147     MNode*  arg = cell->cdr ();
148     MLDbTcpserver  obj (mlenv);
149     ustring  name;
150     MNodePtr  ans;
151
152     if (! arg)
153         throw (uErrorWrongNumber);
154
155     name = eval_str (arg->car (), mlenv);
156     nextNode (arg);
157
158     if (name.size () == 0)
159         throw (uErrorFilenameEmpty);
160     if (! matchName (name))
161         throw (name + uErrorBadName);
162     if (mlenv->env) {
163         SigSafe  sig;
164         obj.setPath (name);
165
166         mlenv->setMStack (&obj);
167         obj.opendb ();
168         ans = progn (arg, mlenv);
169         mlenv->stopBreak (cell->car ());
170         obj.closedb ();
171     }
172
173     return ans.release ();
174 }
175
176 /*DOC:
177 ===subfunctions of $dbtcpserver===
178
179 */
180 /*DOC:
181 ====add-allow-ip====
182  (add-allow-ip IP SPAN ENV...) -> NIL
183 IPアドレス,アドレスレンジをキーにしたallow行を追加する。
184 ドットで終わる4オクテット未満のアドレスを指定すると,アドレスレンジ指定となる。
185 SPANが0以上の時,登録時からSPAN秒後までの間,レコードが有効になる。
186 環境変数指定を「名前=値」の形式で指定する。環境変数指定は複数指定できる。
187
188 ====add-allow-host====
189  (add-allow-host DOMAIN SPAN ENV...) -> NIL
190 ホスト名,ドメイン名をキーにしたallow行を追加する。
191 ドットで始まるドメイン名を指定すると,ドメイン全体の指定となる。
192 SPANが0以上の時,登録時からSPAN病後までの間,レコードが有効になる。
193 環境変数指定を「名前=値」の形式で指定する。環境変数指定は複数指定できる。
194
195 ====add-deny-ip====
196  (add-deny-ip IP) -> NIL
197 IPアドレス,アドレスレンジをキーにしたdeny行を追加する。
198 ドットで終わる4オクテット未満のアドレスを指定すると,アドレスレンジ指定となる。
199
200 ====add-deny-host====
201  (add-deny-host DOMAIN) -> NIL
202 ホスト名,ドメイン名をキーにしたdeny行を追加する。
203 ドットで始まるドメイン名を指定すると,ドメイン全体の指定となる。
204
205 ====delete-ip====
206  (delete-ip IP) -> NIL
207 IPアドレスをキーとして登録したレコードを削除する。
208
209 ====delete-host====
210  (delete-host DOMAIN)
211 ドメイン名をキーとして登録したレコードを削除する。
212
213 ====read-ip====
214  (read-ip IP) -> (["allow" | "deny"] TIME ENV_LIST)
215 IPアドレスをキーとしてレコードを読み取る。
216 レコードの期限が指定されているものは,期限の時刻のUNIX timeが返される。
217 環境変数指定はリストで返される。
218
219 ====read-host====
220  (read-host DOMAIN) -> (["allow" | "deny"] TIME ENV_LIST)
221 ドメイン名をキーとしてレコードを読み取る。
222 レコードの期限が指定されているものは,期限の時刻のUNIX timeが返される。
223 環境変数指定はリストで返される。
224
225 ====dump-ip====
226  (dump-ip) -> (IP PERM_LIST TIME_LIST ENV_LIST)
227 IPアドレスをキーとした全レコードをリストで返す。
228 空文字列のキーのレコードは,dump-ip関数の戻り値に含まれる。
229
230 ====dump-host====
231  (dump-host) -> (DOMAIN PERM_LIST TIME_LIST ENV_LIST)
232 ドメイン名をキーとしたレコードをリストで返す。
233
234 ====cleanup====
235  (cleanup) -> NIL
236 有効期限指定のあるレコードで,期限を過ぎたレコードを削除する。
237
238 */
239
240 //#SFUNC        add-allow-ip    ml_dbtcpserver_add_allow_ip     $dbtcpserver
241 MNode*  ml_dbtcpserver_add_allow_ip (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
242     MNode*  arg = cell->cdr ();
243     MLDbTcpserver*  obj = MObjRef<MLDbTcpserver> (mobj, cMLDbTcpserverID);
244     std::vector<MNode*>  params;
245     MNode*  rest;
246     ustring  ip;
247     time_t  span;
248
249     setParams (arg, 2, &params, NULL, NULL, &rest);
250     ip = eval_str (params[0], mlenv);
251     span = eval_int (params[1], mlenv);
252     if (ip.length () > 0 && ! checkRe (ip, re_iprange))
253         throw (ip + uErrorBadValue);
254
255     obj->addAllow (ip, span, rest, mlenv);
256
257     return NULL;
258 }
259
260 //#SFUNC        add-allow-host  ml_dbtcpserver_add_allow_host   $dbtcpserver
261 MNode*  ml_dbtcpserver_add_allow_host (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
262     MNode*  arg = cell->cdr ();
263     MLDbTcpserver*  obj = MObjRef<MLDbTcpserver> (mobj, cMLDbTcpserverID);
264     std::vector<MNode*>  params;
265     MNode*  rest;
266     ustring  host;
267     time_t  span;
268
269     setParams (arg, 2, &params, NULL, NULL, &rest);
270     host = eval_str (params[0], mlenv);
271     span = eval_int (params[1], mlenv);
272     if (host.length () > 0 && ! checkRe (host, re_domainrange))
273         throw (host + uErrorBadValue);
274
275     if (host.length () > 0)
276         host = ustring (CharConst ("=")).append (host);
277     obj->addAllow (host, span, rest, mlenv);
278
279     return NULL;
280 }
281
282 //#SFUNC        add-deny-ip     ml_dbtcpserver_add_deny_ip      $dbtcpserver
283 MNode*  ml_dbtcpserver_add_deny_ip (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
284     MNode*  arg = cell->cdr ();
285     MLDbTcpserver*  obj = MObjRef<MLDbTcpserver> (mobj, cMLDbTcpserverID);
286     std::vector<MNode*>  params;
287     ustring  ip;
288
289     setParams (arg, 1, &params, NULL, NULL, NULL);
290     ip = eval_str (params[0], mlenv);
291     if (ip.length () > 0 && ! checkRe (ip, re_iprange))
292         throw (ip + uErrorBadValue);
293
294     obj->addDeny (ip);
295
296     return NULL;
297 }
298
299 //#SFUNC        add-deny-host   ml_dbtcpserver_add_deny_host    $dbtcpserver
300 MNode*  ml_dbtcpserver_add_deny_host (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
301     MNode*  arg = cell->cdr ();
302     MLDbTcpserver*  obj = MObjRef<MLDbTcpserver> (mobj, cMLDbTcpserverID);
303     std::vector<MNode*>  params;
304     ustring  host;
305
306     setParams (arg, 1, &params, NULL, NULL, NULL);
307     host = eval_str (params[0], mlenv);
308     if (host.length () > 0 && ! checkRe (host, re_domainrange))
309         throw (host + uErrorBadValue);
310
311     if (host.length () > 0)
312         host = ustring (CharConst ("=")).append (host);
313     obj->addDeny (host);
314
315     return NULL;
316 }
317
318 //#SFUNC        delete-ip       ml_dbtcpserver_delete_ip        $dbtcpserver
319 MNode*  ml_dbtcpserver_delete_ip (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
320     MNode*  arg = cell->cdr ();
321     MLDbTcpserver*  obj = MObjRef<MLDbTcpserver> (mobj, cMLDbTcpserverID);
322     std::vector<MNode*>  params;
323     ustring  ip;
324
325     setParams (arg, 1, &params, NULL, NULL, NULL);
326     ip = eval_str (params[0], mlenv);
327     if (ip.length () > 0 && ! checkRe (ip, re_iprange))
328         throw (ip + uErrorBadValue);
329
330     obj->del (ip);
331
332     return NULL;
333 }
334
335 //#SFUNC        delete-host     ml_dbtcpserver_delete_host      $dbtcpserver
336 MNode*  ml_dbtcpserver_delete_host (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
337     MNode*  arg = cell->cdr ();
338     MLDbTcpserver*  obj = MObjRef<MLDbTcpserver> (mobj, cMLDbTcpserverID);
339     std::vector<MNode*>  params;
340     ustring  host;
341
342     setParams (arg, 1, &params, NULL, NULL, NULL);
343     host = eval_str (params[0], mlenv);
344     if (host.length () > 0 && ! checkRe (host, re_domainrange))
345         throw (host + uErrorBadValue);
346
347     if (host.length () > 0)
348         host = ustring (CharConst ("=")).append (host);
349     obj->del (host);
350
351     return NULL;
352 }
353
354 static MNode*  accessRec (MLDbTcpserver* obj, const ustring& key) {
355     ustring  val;
356     bool  allow;
357     time_t  limit;
358     MNodeList  estr;
359
360     if (obj->db.get (key, val)) {
361         if (obj->splitRec (val, allow, limit, estr)) {
362             MNodeList  ans;
363             if (allow) {
364                 ans.append (newMNode_str (new ustring (CharConst ("allow"))));
365             } else {
366                 ans.append (newMNode_str (new ustring (CharConst ("deny"))));
367             }
368             ans.append (newMNode_num (limit));
369             ans.append (estr.release ());
370             return ans.release ();
371         }
372     }
373     return NULL;
374 }
375
376 static void  accessRec (MLDbTcpserver* obj, const ustring& key, const ustring& val, MNodeList& lkey, MNodeList& lallow, MNodeList& llimit, MNodeList& lestr) {
377     bool  allow;
378     time_t  limit;
379     MNodeList  estr;
380
381     if (obj->splitRec (val, allow, limit, estr)) {
382         lkey.append (newMNode_str (new ustring (key)));
383         if (allow) {
384             lallow.append (newMNode_str (new ustring (CharConst ("allow"))));
385         } else {
386             lallow.append (newMNode_str (new ustring (CharConst ("deny"))));
387         }
388         llimit.append (newMNode_num (limit));
389         lestr.append (estr.release ());
390     }
391 }
392
393 //#SFUNC        read-ip ml_dbtcpserver_read_ip  $dbtcpserver
394 MNode*  ml_dbtcpserver_read_ip (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
395     MNode*  arg = cell->cdr ();
396     MLDbTcpserver*  obj = MObjRef<MLDbTcpserver> (mobj, cMLDbTcpserverID);
397     std::vector<MNode*>  params;
398     ustring  ip;
399
400     setParams (arg, 1, &params, NULL, NULL, NULL);
401     ip = eval_str (params[0], mlenv);
402     if (ip.length () > 0 && ! checkRe (ip, re_iprange))
403         throw (ip + uErrorBadValue);
404
405     return accessRec (obj, ip);
406 }
407
408 //#SFUNC        read-host       ml_dbtcpserver_read_host        $dbtcpserver
409 MNode*  ml_dbtcpserver_read_host (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
410     MNode*  arg = cell->cdr ();
411     MLDbTcpserver*  obj = MObjRef<MLDbTcpserver> (mobj, cMLDbTcpserverID);
412     std::vector<MNode*>  params;
413     ustring  host;
414
415     setParams (arg, 1, &params, NULL, NULL, NULL);
416     host = eval_str (params[0], mlenv);
417     if (host.length () > 0 && ! checkRe (host, re_domainrange))
418         throw (host + uErrorBadValue);
419
420     if (host.length () > 0)
421         host = ustring (CharConst ("=")).append (host);
422     return accessRec (obj, host);
423 }
424
425 //#SFUNC        dump-ip ml_dbtcpserver_dump_ip  $dbtcpserver
426 MNode*  ml_dbtcpserver_dump_ip (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
427     MNode*  arg = cell->cdr ();
428     MLDbTcpserver*  obj = MObjRef<MLDbTcpserver> (mobj, cMLDbTcpserverID);
429     MNodeList  ans, lkey, lallow, llimit, lestr;
430     ustring  key, val;
431
432     if (arg) 
433         throw (uErrorWrongNumber);
434
435     obj->db.initeach ();
436     while (obj->db.each (key, val)) {
437         if (key.length () > 0 && key[0] == '=') {
438         } else {
439             accessRec (obj, key, val, lkey, lallow, llimit, lestr);
440         }
441     }
442     ans.append (lkey.release ());
443     ans.append (lallow.release ());
444     ans.append (llimit.release ());
445     ans.append (lestr.release ());
446     return ans.release ();
447 }
448
449 //#SFUNC        dump-host       ml_dbtcpserver_dump_host        $dbtcpserver
450 MNode*  ml_dbtcpserver_dump_host (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
451     MNode*  arg = cell->cdr ();
452     MLDbTcpserver*  obj = MObjRef<MLDbTcpserver> (mobj, cMLDbTcpserverID);
453     MNodeList  ans, lkey, lallow, llimit, lestr;
454     ustring  key, val;
455
456     if (arg) 
457         throw (uErrorWrongNumber);
458
459     obj->db.initeach ();
460     while (obj->db.each (key, val)) {
461         if (key.length () > 0 && key[0] == '=') {
462             key.assign (key.begin () + 1, key.end ());
463             accessRec (obj, key, val, lkey, lallow, llimit, lestr);
464         } else {
465         }
466     }
467     ans.append (lkey.release ());
468     ans.append (lallow.release ());
469     ans.append (llimit.release ());
470     ans.append (lestr.release ());
471     return ans.release ();
472 }
473
474 //#SFUNC        cleanup ml_dbtcpserver_cleanup  $dbtcpserver
475 MNode*  ml_dbtcpserver_cleanup (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
476     MNode*  arg = cell->cdr ();
477     MLDbTcpserver*  obj = MObjRef<MLDbTcpserver> (mobj, cMLDbTcpserverID);
478     ustring  key, val;
479     std::vector<ustring>  ary;
480     time_t  now = time (NULL);
481     bool  allow;
482     time_t  limit;
483     std::vector<ustring>::iterator  b, e;
484
485     if (arg) 
486         throw (uErrorWrongNumber);
487
488     obj->db.initeach ();
489     while (obj->db.each (key, val)) {
490         if (obj->splitRec (val, allow, limit)) {
491             if (allow && limit > 0 && limit < now) {
492                 ary.push_back (key);
493             }
494         } else {
495             ary.push_back (key);
496         }
497     }
498     b = ary.begin ();
499     e = ary.end ();
500     for (; b < e; b ++) {
501         obj->db.del (*b);
502     }
503
504     return NULL;
505 }
506