blob: 1c318c8b1d5b67dce458a60c69285e1e0e0ed383 [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001static mapping projects=([]);
2static string *insecure,*deputy_files;
3
4int ReloadInsecureFile()
5{
6 insecure = efun::explode( read_file("/secure/INSECURE") || "", "\n" );
7 insecure -= ({""});
8 insecure = map( insecure, #'lower_case/*'*/ );
9 return(1);
10}
11
12void LoadDeputyFileList()
13{
14 // Leseberechtigungen fuer /log/ARCH/* setzen
15 deputy_files = efun::explode( read_file("/log/ARCH/DEPUTY_FILELIST") || "",
16 "\n" ) - ({""});
17 return;
18}
19
Zesstra3e9a6c92018-11-06 22:38:42 +010020// Normalisiert den Pfad und liefert ein Array mit Pfadelementen.
21// expand bestimmt, ob im Pfad +, ~ oder P_CURRENTDIR expandiert werden oder
22// nicht.
Zesstraccc58df2018-11-07 23:25:20 +010023string *path_array(string path) {
MG Mud User88f12472016-06-24 23:31:02 +020024
Zesstra3e9a6c92018-11-06 22:38:42 +010025 if (!sizeof(path))
MG Mud User88f12472016-06-24 23:31:02 +020026 return ({"",""}); // additional "" to yield "/" later.
27
Zesstra3e9a6c92018-11-06 22:38:42 +010028 // remove multiple '/'erstn gv
29 path = regreplace(path, "/+", "/", 1);
30
31 // /../ irgendwo im Pfad behandeln, das und vorheriges Element
32 // rausschneiden.
Zesstraf7905352018-11-05 22:46:16 +010033 // Einschraenkungen der RegExp:
MG Mud User88f12472016-06-24 23:31:02 +020034 // /a/b/../../d wuerde nur durch Wiederholung aufgeloest.
35 // /../d wird nicht richtig aufgeloest.
36 //regreplace("/d/inseln/toeter/room/hoehle/../wald/bla.c","(.*)\/[^/]+/\.\.
37 // /(.*)", "\\1\/\\2", RE_GLOBAL)
Zesstraf7905352018-11-05 22:46:16 +010038
Zesstra3e9a6c92018-11-06 22:38:42 +010039 string *p_arr = explode(path, "/") - ({"."});
40
41 // /../ irgendwo im Pfad behandeln, das und vorheriges Element
42 // rausschneiden.
MG Mud User88f12472016-06-24 23:31:02 +020043 // dies sieht schlimmer aus als es ist (member ist O(n)), solange das Array
44 // nicht gross wird.
45 int p;
Zesstra3e9a6c92018-11-06 22:38:42 +010046 while((p=member(p_arr, "..")) != -1)
47 p_arr = p_arr[0..p-2]+p_arr[p+1..];
MG Mud User88f12472016-06-24 23:31:02 +020048
Zesstra3e9a6c92018-11-06 22:38:42 +010049 // Pfade absolutieren
50 // leeres Pfadarray fuehrt zur Rueckgabe von einem Array, was hinterher "/"
51 // ergibt, Arrays mit nur einem Element bekommen in jedem Fall ein Element
52 // "" an den Anfang, laengere Arrays kriegen falls noetig ein "".
53 switch(sizeof(p_arr))
54 {
55 case 0:
56 return ({"",""});
57 case 1:
MG Mud User88f12472016-06-24 23:31:02 +020058 p_arr = ({""}) + p_arr;
Zesstra3e9a6c92018-11-06 22:38:42 +010059 break;
60 default:
61 if (p_arr[0] != "")
62 p_arr = ({""}) + p_arr;
63 }
MG Mud User88f12472016-06-24 23:31:02 +020064
Zesstra3e9a6c92018-11-06 22:38:42 +010065 return p_arr;
66}
67
Zesstrab49624a2018-11-07 21:40:16 +010068// Pfadnormalisierung OHNE Ersetzungen von +, ~ und P_CURRENTDIR (war mal mit)
69// Eigentlich hier ziemlich unnuetz, aber nen Haufen Objekte im Mud ruft das.
Zesstra3e9a6c92018-11-06 22:38:42 +010070string _get_path(string path, string user) {
Zesstraccc58df2018-11-07 23:25:20 +010071 return implode(path_array(path),"/");
Zesstrab45f3b42018-11-07 21:54:07 +010072}
73
Zesstrab49624a2018-11-07 21:40:16 +010074// Diese Funktion wird vom Driver nur fuer den Editor ed gerufen, aber der
Zesstraccc58df2018-11-07 23:25:20 +010075// Rest vom MG ruft es teilweise auch.
Zesstrab45f3b42018-11-07 21:54:07 +010076string make_path_absolute(string path) {
Zesstraccc58df2018-11-07 23:25:20 +010077 return implode(path_array(path),"/");
MG Mud User88f12472016-06-24 23:31:02 +020078}
79
80static int project_access(string user, string project)
81{
MG Mud User88f12472016-06-24 23:31:02 +020082 if (!member(projects,project))
83 {
Zesstra32202602019-11-28 22:03:31 +010084 string s=read_file(PROJECTDIR+"/"+project+"/ACCESS_RIGHTS");
MG Mud User88f12472016-06-24 23:31:02 +020085 if(!s||s=="")
86 return 0;
Zesstra32202602019-11-28 22:03:31 +010087 mapping tmp=([]);
88 foreach(string line: explode(s,"\n")-({""}))
MG Mud User88f12472016-06-24 23:31:02 +020089 {
Zesstra32202602019-11-28 22:03:31 +010090 if (line[0]=='*')
91 tmp[line[1..]]=2;
MG Mud User88f12472016-06-24 23:31:02 +020092 else
Zesstra32202602019-11-28 22:03:31 +010093 tmp[line]=1;
MG Mud User88f12472016-06-24 23:31:02 +020094 }
95 projects[project]=({tmp,time()});
96 return tmp[user];
97 }
98 projects[project][1]=time();
99 return projects[project][0][user];
100}
101
102void OutdateProjectCache(string project)
103{
104 m_delete(projects,project);
105}
106
107static void _cleanup_projects() {
108 int i;
109 mixed *users;
110
111 for (users=m_indices(projects),i=sizeof(users)-1;i>=0;i--)
112 if((time()-projects[users[i]][1])>1800)
113 m_delete(projects,users[i]);
114}
115
116int access_rights(string *p_arr, string euid)
117{
Zesstrad872d182019-11-28 20:13:02 +0100118 int i = sizeof(p_arr) - 2;
MG Mud User88f12472016-06-24 23:31:02 +0200119
120 while ( i >= 0 &&
121 file_size( implode(p_arr[0..i], "/") + "/access_rights.c" ) < 0 )
122 i--;
123
124 if ( i < 0 )
125 return 0;
126
Zesstrad872d182019-11-28 20:13:02 +0100127 if ( !catch(i = ({int})call_other(
MG Mud User88f12472016-06-24 23:31:02 +0200128 implode(p_arr[0..i], "/") + "/access_rights",
129 "access_rights", euid,
130 implode(p_arr[i+1..], "/") ); publish) )
131 return i;
132
133 return 0;
134}
135
Zesstra078991b2013-01-26 11:56:45 +0100136// Hngl. Inkludieren aus /sys ist hier doof.
137#ifndef FSIZE_DIR
138#define FSIZE_DIR -2
139#endif
MG Mud User88f12472016-06-24 23:31:02 +0200140mixed valid_write(string path, string euid, string fun, object obj)
141{
142 int s,lvl;
143 string *strs;
144 int *date;
145
146 if (member(path,' ')!=-1) return 0;
147
148 // Unter LIBDATADIR (/data) sollen komplett identische Schreibrechte
Zesstra078991b2013-01-26 11:56:45 +0100149 // vergeben werden. Ausnahme ist jedoch fun=="mkdir": hier soll die
150 // Erstellung eines Verezeichnisses jedem erlaubt sein, wenn es das
151 // entsprechende Verzeichnis ausserhalb /data/ schon gibt.
MG Mud User88f12472016-06-24 23:31:02 +0200152 if (sizeof(path) > 6
Zesstraeb0ceb82018-02-28 21:31:07 +0100153 && path[0..5] == "/"LIBDATADIR"/")
154 {
Zesstra078991b2013-01-26 11:56:45 +0100155 if (fun=="mkdir")
Zesstraeb0ceb82018-02-28 21:31:07 +0100156 {
157 // wenn schon ausserhalb /data/ existent: erlauben
158 if (file_size(path[5..]) == FSIZE_DIR)
159 return 1;
160 // sonst fall-through und normale gucken, ob der Aufrufer ausserhalb
161 // /data/ denn duerfte.
162 }
MG Mud User88f12472016-06-24 23:31:02 +0200163 return valid_write(path[5..], euid, fun, obj) != 0;
Zesstra078991b2013-01-26 11:56:45 +0100164 }
MG Mud User88f12472016-06-24 23:31:02 +0200165
166 switch(fun) {
167 case "log_file":
Zesstraccc58df2018-11-07 23:25:20 +0100168 strs=path_array("/"+path);
MG Mud User88f12472016-06-24 23:31:02 +0200169 path = implode(strs, "/");
170 strs -= ({""}); // remove trailing and leading "/".
171 if (sizeof(strs)>1 && strs[0]=="log") return path;
172 return 0;
173 case "save_object":
Zesstraa43be352018-11-06 22:40:32 +0100174 if (!sizeof(path)) return 0;
Zesstraccc58df2018-11-07 23:25:20 +0100175 strs=path_array("/"+path);
MG Mud User88f12472016-06-24 23:31:02 +0200176 break;
177 case "ed_start":
Zesstraa43be352018-11-06 22:40:32 +0100178 if (sizeof(path))
Zesstraccc58df2018-11-07 23:25:20 +0100179 strs=path_array(path);
Zesstraa43be352018-11-06 22:40:32 +0100180 else
181 strs=({"players",euid,".err"});
MG Mud User88f12472016-06-24 23:31:02 +0200182 break;
183 default:
Zesstraccc58df2018-11-07 23:25:20 +0100184 strs=path_array(path);
MG Mud User88f12472016-06-24 23:31:02 +0200185 }
186
187 if (!euid || euid=="NOBODY" || euid=="ftp" || euid=="anonymous") return 0;
188
189 // Pfad soll ab jetzt auf jeden Fall absolut sein.
190 if (strs[0] != "")
191 path = "/" + implode(strs, "/");
192 else
193 path=implode(strs, "/");
194
195 // fuer die Rechtebestimmung "/" an Anfang und Ende entfernen
196 strs -= ({""});
197
198 //Root-Objekte und Master duerfen immer.
199 if (euid == ROOTID || obj==TO) return path;
200
201 lvl=query_wiz_level(euid);
202
203 //Toplevel: nur EM+
204 if ((s=sizeof(strs))<=1) return lvl>=ARCH_LVL;
205
206 switch(strs[0]) {
207 case TMPDIR:
208 return 1;
209
210 case STDDIR:
211 case SYSDIR:
212 case LIBOBJDIR:
213 case ETCDIR:
214 case LIBROOMDIR:
215 return lvl>=ARCH_LVL;
216
217 case LIBITEMDIR:
218 return lvl>=ELDER_LVL;
219
220 case SPELLBOOKDIR:
221 // wenn unterhalb eines unterverzeichnisses des Stils "gilde", dann ists
222 // einfach
223 if (sizeof(strs) > 2
224 && guild_master(euid, strs[1]))
225 return 1;
226
227 // sonst nur EMs bzw. access_rights.c fragen.
228 return ((lvl>=ARCH_LVL) || access_rights(strs,euid));
229
230 case GUILDDIR:
231 // wenn unterhalb eines unterverzeichnisses des Stils "filde.gilde",
232 // dann ists einfach
233 if (sizeof(strs) > 2) {
234 string *tmp = explode(strs[1],"files.");
235 if (sizeof(tmp) == 2) {
236 if (guild_master(euid, tmp[1]))
237 return 1;
238 // Objekte dort sollen auch schreiben duerfen.
239 if (euid == ("GUILD."+tmp[1]))
240 return 1;
241 }
242 }
243 // sonst nur EMs bzw. access_rights.c fragen.
244 return ((lvl>=ARCH_LVL) || access_rights(strs,euid));
245
246 case DOCDIR:
247 if ( s > 1 && (strs[1] == "balance") )
248 return ((lvl>=ARCH_LVL) || access_rights(strs,euid));
249 else
250 return ((lvl>=SPECIAL_LVL) || access_rights(strs,euid));
251
252 case FTPDIR:
253 if ( s > 1 && (strs[1] == "incoming" || strs[1] == "tmp" ||
254 s == 3 && strs[1] == "News" && strs[2] == euid+".news") )
255 return 1;
256
257 if (lvl>=ELDER_LVL)
258 return 1;
259
260 return 0;
261
262 case MAILDIR:
263 if (euid==MAILID || strs[1]=="spool") break;
264 return 0;
265
Zesstra8a3f8682017-01-30 23:04:20 +0100266 case "save":
MG Mud User88f12472016-06-24 23:31:02 +0200267 if (lvl>=ARCH_LVL) return 1;
268 if (s==3 && strs[1] == euid[0..0] &&
269 (strs[2]==euid+".o" || strs[2]==euid)) break;
270 return 0;
271
272 case LIBLOGDIR:
273 /* auf /log/ARCH/ haben wirklich nur EMs Zugriff */
274 if (strs[1]=="ARCH" && lvl<ARCH_LVL) return 0;
275
276 /* alles andere duerfen auch Weise... */
277 if (lvl>=ELDER_LVL) return 1;
278
279 /* Allgemeine logfiles in /log duerfen wirklich nur geschrieben werden */
280 if (s==2 && strs[1][0]>='A' && strs[1][0]<='Z' && fun != "write_file")
281 return 0;
282
283 /* Unterhalb von /log/syslog darf nur geschrieben werden */
284 if (s>1 && strs[1]=="syslog" && fun != "write_file")
285 return 0;
286
287 /* loggen ins eigene repfile immer erlauben */
288 if (s==3 && strs[1]=="report" &&
289 strs[2]==explode(euid, ".")[<1]+".rep") break;
290
291 /* in fremden Verzeichnissen hat niemand was zu loggen */
292 if (get_wiz_level(strs[1]) >= WIZARD_LVL &&
293 strs[1] != efun::explode(euid, ".")[<1])
294 return 0;
295 break;
296
297 case WIZARDDIR:
298 /* kein Zugriff auf Objekte mit hoeheren Rechten */
299 if (query_wiz_level(strs[1]) > lvl) return 0;
300
301 /* Magier selbst oder Weise duerfen hier schreiben */
302 if ((IS_WIZARD(euid) && euid==strs[1])||(lvl>=ELDER_LVL)) break;
303
304 /* Es steht jedoch frei, auch anderen Schreibrechte zu geben... */
305 return access_rights(strs,euid);
306
307 case DOMAINDIR:
308 /* neue Regionen duerfen nur Erzmagier anlegen */
309 if (s<2 && lvl<ARCH_LVL) return 0;
310
311 /* kein Zugriff auf Objekte mit hoeheren Rechten */
312 if (s>2 && query_wiz_level(creator_file(path)) > lvl)
313 return 0;
314
315 /* Auf Regionfiles von erzmagier haben nur EMs Zugriff */
316 if (creator_file(path)=="erzmagier" && lvl<ARCH_LVL) return 0;
317
318 /* innerhalb der Region haben RMs und Weise volle Schreibrechte */
319 if (lvl>=ELDER_LVL || domain_master(euid,strs[1])) break;
320
321 /* neue Verzeichnisse in der Region kann nur RM+ anlegen */
322 if (s<=3 && (fun=="mkdir" || fun=="rmdir")) return 0;
323
324 /* Magier auf ihre eigenen Files... */
325 if (s>2 && strs[2]==euid) break;
326
327 /* Files der Magier in der Region in ihre eigenen Verzeichnisse... */
328 if (s>2 && euid==sprintf("d.%s.%s", strs[1], strs[2])) break;
329
330 /* Files mit Regionsuid */
331 if (euid==strs[1]) break;
332
333 /* Es ist moeglich anderen Magiern Rechte bei sich einzuraeumen. */
334 if (access_rights(strs,euid)>0) break;
335
336 /* Auf das Verzeichniss 'alle' haben alle Regionsmitglieder Zugriff.
337 Ausser, wenn sie ueber access_rights.c explizit ausgeschlossen
338 werden (Returncode < 0). */
339 if (s>2 && strs[2]=="alle" && domain_member(euid, strs[1]) &&
340 access_rights(strs,euid)>=0) break;
341 return 0;
342
343 case PROJECTDIR:
344 /* Nur Erzmagier duerfen neue Projektverzeichnisse anlegen... */
345 if (s<3 && lvl<ARCH_LVL) return 0;
346
347 /* alles weitere duerfen auch Weise tun */
348 if (lvl>=ELDER_LVL) break;
349
350 /* in den Serviceverzeichnissen muss lediglich der Name stimmen */
351 if (s>3 && strs[1]=="service" && euid==strs[2]) break;
352
353 /* Objekte eines Projektes haben Schreibzugriffe auf ihr Projekt */
354 if (s>3 && (implode(strs[0..1], ".") == euid
355 || implode(strs[0..2], ".") == euid) ) return 1;
356
357 /* Schreibrechte koennen natuerlich auch vergeben werden... */
358 if (project_access(euid,strs[1])) break;
359 // Alternativ besteht neben dem ACCESS_RIGHTS auch noch die
360 // Moeglichkeit, per access_rights.c Rechte einzuraeumen.
361 if (access_rights(strs,euid)>0) break;
362
363 return 0;
364
365 default: return 0;
366 }
367 return path;
368}
369
370mixed valid_read(string path, string euid, string fun, object obj)
371{
372 int s, lev;
373 string *strs, suf;
374
375 if (member(path,' ')!=-1) return 0;
376
377 // Unter LIBDATADIR (/data) sollen komplett identische Leserechte
378 // vergeben werden.
379 if (sizeof(path) > 6
380 && path[0..5] == "/"LIBDATADIR"/")
381 return valid_read(path[5..], euid, fun, obj) != 0;
382
383 if (!euid) euid="-";
384
Zesstraccc58df2018-11-07 23:25:20 +0100385 strs=path_array(path);
Zesstraa43be352018-11-06 22:40:32 +0100386 // Pfade sind ab jetzt auf jeden Fall absolut.
387 path=implode(strs, "/");
MG Mud User88f12472016-06-24 23:31:02 +0200388
389 // fuer die Rechtebestimmung "/" an Anfang und Ende entfernen
390 strs -= ({""});
391
392 if (!sizeof(strs) || !sizeof(path) || euid == ROOTID || obj==TO) return path;
393
394 if ((s=sizeof(strs)) <= 1) return path;
395
396 lev=query_wiz_level(euid);
397
398 switch(strs[0]) {
399 case "core":
400 case "wahl":
401 return 0;
402
403 case NEWSDIR:
404 if (strs[1] == "archiv.pub") // oeffentliches archiv
405 return path;
406 else if (strs[1] == "archiv.magier" // Magier-Archiv
407 && lev >= WIZARD_LVL)
408 return path;
409
410 return 0; // kein Zugriff auf /news/ oder alles andere.
411
412 case "maps":
413 if (lev<=WIZARD_LVL) return 0;
414
415 case "":
416 case ETCDIR:
417 case STDDIR:
418 case SYSDIR:
419 case DOCDIR:
420 case LIBOBJDIR:
421 case LIBROOMDIR:
422 case LIBITEMDIR:
423 case FTPDIR:
424 return path;
425
426 case MAILDIR:
427 return (euid==MAILID);
428
429 case SECUREDIR:
430 if (strs[1]=="save") return 0;
431 if (path[<2..]==".o" || path[<5..]==".dump") return 0;
432 if (strs[1]!="ARCH" || lev>=ARCH_LVL) return path;
433
434 case LIBLOGDIR:
435 if ( strs[1] == "ARCH" && !IS_DEPUTY(euid) )
436 return 0;
437
438 if ( strs[1] == "ARCH" && lev < ARCH_LVL && s == 3 &&
439 strs[2] != "*" && strs[2][0..2] != "bb." &&
440 member( deputy_files, strs[2] ) < 0 )
441 return 0;
442
443 if ( lev > WIZARD_LVL )
444 return path;
445
446 if ( s == 2 && (strs[1] == "report" || strs[1] == "error") )
447 return path; // fuer 'cd'
448
449 // /log sollte jeder auflisten koennen
450 if ( s == 2 && strs[1]=="*" && fun=="get_dir")
451 return path;
452
453 // unter /log/report/, /log/error und /log/warning/ duerfen alle lesen
454 if ( s==3 &&
455 (strs[1] == "report" || strs[1] == "error"
456 || strs[1] =="warning"))
457 return path;
458
459 // /log/<Magiername> darf von <Magiername> natuerlich auch
460 // gelesen werden
461 if ( s >= 2 && strs[1] == euid )
462 return path;
463
464 return 0;
465
466 case "backup":
Zesstra8a3f8682017-01-30 23:04:20 +0100467 case "save":
MG Mud User88f12472016-06-24 23:31:02 +0200468 if (lev>WIZARD_LVL) return path;
469
470 /* Objekte in /p/* haben bisher leider wizlevel 0 */
471 //if (lev==0) return path;
472
473 if (fun=="file_size") return path;
474
475 // das eigene Savefile darf man natuerlich immer. ;-)
476 if (s==3 && (strs[2]==euid+".o" || strs[2]==euid))
477 return path;
478 return 0;
479
480 case PROJECTDIR:
481 /* Pruefen ob ein File existiert darf jeder... */
482 if (fun=="file_size") return path;
483
484 /* Die Service-Verzeichnisse darf jeder lesen */
485 if (s>3 && strs[1]=="service") return path;
486
487 //Weise duerfen in /p/ schreiben, also auch lesen. (Zesstra, 04.11.06)
488 if (lev>=ELDER_LVL) return path;
489
490 /* wer hier schreiben darf, darf natuerlich auf jeden Fall lesen */
491 //Anmerkung v. Zesstra: das prueft nur, ob jemand in ACCESS_RIGHTS
492 //steht, nicht ob jemand (ggf. aus anderen Gruenden schreiben darf)
493 if (project_access(euid,strs[1])) return path;
494 //Alternativ kann man explizite Schreibrechte auch via access_rights.c
495 //vergeben. (und damit natuerlich auch Leserechte)
496 if (access_rights(strs,euid)>0) return path;
497
498 /* Objekte eines Projektes haben Lesezugriff auf ihr Projekt */
499 if (s>3 && (implode(strs[0..1], ".") == euid
500 || implode(strs[0..2], ".") == euid) ) return path;
501
502 /* Fall-Through */
503
504 case GUILDDIR:
505 /* "secure"-Verzeichnisse darf nur lesen, wer da auch schreiben darf */
506 if ( s > 3 && strs[<2] == "secure" && member( insecure, strs[1] ) < 0
507 && lev < ARCH_LVL && !access_rights(strs, euid) )
508 return 0;
509
510 /* Pruefen ob ein File existiert darf jeder... */
511 if (fun=="file_size") return path;
512
513 /* Fall-Through */
514
515 case SPELLBOOKDIR:
516 // Gildenpbjekte koennen hier lesen
517 if (lev==0 && euid[0..4]=="GUILD") return path;
518
519 // Mit Level <= 20 darf man hier nichts lesen
520 if ( lev<=WIZARD_LVL && sizeof(regexp( ({strs[<1]}), "\\.[och]" )) )
521 return 0;
522
523 return path;
524
525 case WIZARDDIR:
526 if (s==2) return path;
527 /* das eigene Verzeichniss darf man natuerlich immer lesen... */
528 if (strs[1]==euid && lev>=WIZARD_LVL) return path;
529
530 /* Pruefen ob ein File existiert darf jeder... */
531 if (fun=="file_size") return path;
532
533 /* fremde Verzeichnisse mit <= Level 20 noch nicht */
534 if (lev<=WIZARD_LVL) return 0;
535
536 /* wo man schreiben darf, darf man natuerlich auch lesen... */
537 if (lev>=ELDER_LVL) return path;
538
539 // kein Zugriff auf archivierten Code (wo z.B. secure/ drin sein
540 // koennen)
541 if (member(({"bz2","gz","zip"}), explode(strs[<1],".")[<1]) > -1)
542 return 0;
543
544 /* Files ohne Code sind nicht weiter interessant... */
545 if ( !sizeof(regexp( ({strs[<1]}), "\\.[och]" )) )
546 return path;
547
548 /* folgende Funktionen sind natuerlich voellig uninteressant */
549 if (member(({"get_dir", "restore_object"}), fun)!=-1)
550 return path;
551
552 /* Zugriff erlaubt, aber mitloggen */
553 write_file( READ_FILE, sprintf("%O %s %s: %s\n", fun, ctime()[4..],
554 euid, path) );
555 return path;
556
557 case DOMAINDIR:
558 /* Mit Level 15 darf man hier _nichts_ lesen */
559 if ( fun!="file_size" && lev<WIZARD_LVL &&
560 sizeof(regexp( ({strs[<1]}), "\\.[och]" )) ) return 0;
561
562 /* den Verzeichnisbaum von /d/ darf man natuerlich sonst lesen */
563 if (s<=2) return path;
564
565 /* eigenen Code darf man natuerlich auch lesen */
566 if (euid==strs[2] || euid==sprintf("d.%s.%s", strs[1], strs[2]))
567 return path;
568
569 /* Deputies haben ein gemeinsames Verzeichnis unter /d/erzmagier */
570 if (strs[1]=="erzmagier" && strs[2]=="polizei" && IS_DEPUTY(euid))
571 return path;
572
573 /* d/erzmagier darf man nur als Erzmagier lesen */
574 if (strs[1]=="erzmagier" && lev<ARCH_LVL) return 0;
575
576 /* einige Regionen haben std-verzeichnisse, die darf man natuerlich
577 auch mit Level 20 bereits komplett lesen! */
578 if (strs[2]=="std") return path;
579
580 /* "secure"-Verzeichnisse darf nur lesen, wer da auch schreiben darf */
581 if ( s > 4 && strs[<2] == "secure" && member( insecure, strs[2] ) < 0 ){
582 if ( lev < ELDER_LVL && !domain_master(euid, strs[1])
583 && !access_rights(strs, euid) )
584 return 0;
585 else
586 return path;
587 }
588
589 /* Dokus, Infos und .readme darf man immer lesen... */
590 if ( fun=="file_size" || !sizeof(regexp( ({strs[<1]}), "\\.[och]" )) )
591 return path;
592
593 /* Mit Level 20 darf man noch keinen fremden Code lesen! */
594 if (lev<=WIZARD_LVL) return 0;
595
596 /* Weise duerfen natuerlich alles weitere lesen */
597 if (lev>=ELDER_LVL) return path;
598
599 /* Regionsmagier in ihren Regionen natuerlich auch */
600 if (lev>=LORD_LVL && domain_master(euid, strs[1])) return path;
601
602 /* folgende Funktionen sind natuerlich voellig uninteressant */
603 if (member(({"get_dir", "restore_object"}), fun)!=-1)
604 return path;
605
606 /* Zugriff erlaubt, aber mitloggen */
607 write_file( READ_FILE, sprintf("%O %s %s: %s\n", fun, ctime()[4..],
608 euid, path) );
609 return path;
610 }
611 if (lev<ARCH_LVL) return 0;
612 return path;
613}
614