|
|
1.1 root 1: /* chk_ar.cpp */
2:
3: /* Synchronet ARS checking routine */
4:
1.1.1.2 ! root 5: /* $Id: chk_ar.cpp,v 1.21 2009/03/20 09:36:20 rswindell Exp $ */
1.1 root 6:
7: /****************************************************************************
8: * @format.tab-size 4 (Plain Text/Source Code File Header) *
9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
10: * *
1.1.1.2 ! root 11: * Copyright 2009 Rob Swindell - http://www.synchro.net/copyright.html *
1.1 root 12: * *
13: * This program is free software; you can redistribute it and/or *
14: * modify it under the terms of the GNU General Public License *
15: * as published by the Free Software Foundation; either version 2 *
16: * of the License, or (at your option) any later version. *
17: * See the GNU General Public License for more details: gpl.txt or *
18: * http://www.fsf.org/copyleft/gpl.html *
19: * *
20: * Anonymous FTP access to the most recent released source is available at *
21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
22: * *
23: * Anonymous CVS access to the development source and modification history *
24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: *
25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login *
26: * (just hit return, no password is necessary) *
27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src *
28: * *
29: * For Synchronet coding style and modification guidelines, see *
30: * http://www.synchro.net/source.html *
31: * *
32: * You are encouraged to submit any modifications (preferably in Unix diff *
33: * format) via e-mail to [email protected] *
34: * *
35: * Note: If this box doesn't appear square, then you need to fix your tabs. *
36: ****************************************************************************/
37:
38: #include "sbbs.h"
39:
1.1.1.2 ! root 40: bool sbbs_t::ar_exp(const uchar **ptrptr, user_t* user, client_t* client)
1.1 root 41: {
42: bool result,_not,_or,equal;
43: uint i,n,artype,age;
44: ulong l;
45: struct tm tm;
1.1.1.2 ! root 46: const char* p;
1.1 root 47:
48: result = true;
49:
50: for(;(**ptrptr);(*ptrptr)++) {
51:
52: if((**ptrptr)==AR_ENDNEST)
53: break;
54:
55: _not=_or=equal = false;
56:
57: if((**ptrptr)==AR_OR) {
58: _or=true;
1.1.1.2 ! root 59: (*ptrptr)++;
! 60: }
1.1 root 61:
62: if((**ptrptr)==AR_NOT) {
63: _not=true;
1.1.1.2 ! root 64: (*ptrptr)++;
! 65: }
1.1 root 66:
67: if((**ptrptr)==AR_EQUAL) {
68: equal=true;
1.1.1.2 ! root 69: (*ptrptr)++;
! 70: }
1.1 root 71:
72: if((result && _or) || (!result && !_or))
73: break;
74:
75: if((**ptrptr)==AR_BEGNEST) {
76: (*ptrptr)++;
1.1.1.2 ! root 77: if(ar_exp(ptrptr,user,client))
1.1 root 78: result=!_not;
79: else
80: result=_not;
81: while((**ptrptr)!=AR_ENDNEST && (**ptrptr)) /* in case of early exit */
82: (*ptrptr)++;
83: if(!(**ptrptr))
84: break;
1.1.1.2 ! root 85: continue;
! 86: }
1.1 root 87:
88: artype=(**ptrptr);
89: switch(artype) {
90: case AR_ANSI: /* No arguments */
91: case AR_RIP:
92: case AR_WIP:
93: case AR_LOCAL:
94: case AR_EXPERT:
95: case AR_SYSOP:
96: case AR_GUEST:
97: case AR_QNODE:
98: case AR_QUIET:
99: case AR_OS2:
100: case AR_DOS:
101: case AR_WIN32:
102: case AR_UNIX:
103: case AR_LINUX:
104: break;
105: default:
106: (*ptrptr)++;
1.1.1.2 ! root 107: break;
! 108: }
1.1 root 109:
110: n=(**ptrptr);
111: i=(*(short *)*ptrptr);
112: switch(artype) {
113: case AR_LEVEL:
114: if((equal && user->level!=n) || (!equal && user->level<n))
115: result=_not;
116: else
117: result=!_not;
118: if(!result) {
119: noaccess_str=text[NoAccessLevel];
1.1.1.2 ! root 120: noaccess_val=n;
! 121: }
1.1 root 122: break;
123: case AR_AGE:
124: age=getage(&cfg,user->birth);
125: if((equal && age!=n) || (!equal && age<n))
126: result=_not;
127: else
128: result=!_not;
129: if(!result) {
130: noaccess_str=text[NoAccessAge];
1.1.1.2 ! root 131: noaccess_val=n;
! 132: }
1.1 root 133: break;
134: case AR_BPS:
135: if((equal && cur_rate!=i) || (!equal && cur_rate<i))
136: result=_not;
137: else
138: result=!_not;
139: (*ptrptr)++;
140: if(!result) {
141: noaccess_str=text[NoAccessBPS];
1.1.1.2 ! root 142: noaccess_val=i;
! 143: }
1.1 root 144: break;
145: case AR_ANSI:
146: if(!(user->misc&ANSI))
147: result=_not;
148: else result=!_not;
149: break;
150: case AR_RIP:
151: if(!(user->misc&RIP))
152: result=_not;
153: else result=!_not;
154: break;
155: case AR_WIP:
156: if(!(user->misc&WIP))
157: result=_not;
158: else result=!_not;
159: break;
160: case AR_OS2:
161: #ifndef __OS2__
162: result=_not;
163: #else
164: result=!_not;
165: #endif
166: break;
167: case AR_DOS:
168: result=_not;
169: break;
170: case AR_WIN32:
171: #ifndef _WIN32
172: result=_not;
173: #else
174: result=!_not;
175: #endif
176: break;
177: case AR_UNIX:
178: #ifndef __unix__
179: result=_not;
180: #else
181: result=!_not;
182: #endif
183: break;
184: case AR_LINUX:
185: #ifndef __linux__
186: result=_not;
187: #else
188: result=!_not;
189: #endif
190: break;
191: case AR_ACTIVE:
192: if(user->misc&(DELETED|INACTIVE))
193: result=_not;
194: else result=!_not;
195: break;
196: case AR_INACTIVE:
197: if(!(user->misc&INACTIVE))
198: result=_not;
199: else result=!_not;
200: break;
201: case AR_DELETED:
202: if(!(user->misc&DELETED))
203: result=_not;
204: else result=!_not;
205: break;
206: case AR_EXPERT:
207: if(!(user->misc&EXPERT))
208: result=_not;
209: else result=!_not;
210: break;
211: case AR_SYSOP:
212: if(!SYSOP)
213: result=_not;
214: else result=!_not;
215: break;
216: case AR_GUEST:
217: if(!(user->rest&FLAG('G')))
218: result=_not;
219: else result=!_not;
220: break;
221: case AR_QNODE:
222: if(!(user->rest&FLAG('Q')))
223: result=_not;
224: else result=!_not;
225: break;
226: case AR_QUIET:
227: if(thisnode.status!=NODE_QUIET)
228: result=_not;
229: else result=!_not;
230: break;
231: case AR_LOCAL:
232: if(online!=ON_LOCAL)
233: result=_not;
234: else result=!_not;
235: break;
236: case AR_DAY:
237: now=time(NULL);
238: localtime_r(&now,&tm);
239: if((equal && tm.tm_wday!=(int)n)
240: || (!equal && tm.tm_wday<(int)n))
241: result=_not;
242: else
243: result=!_not;
244: if(!result) {
245: noaccess_str=text[NoAccessDay];
1.1.1.2 ! root 246: noaccess_val=n;
! 247: }
1.1 root 248: break;
249: case AR_CREDIT:
250: l=(ulong)i*1024UL;
251: if((equal && user->cdt+user->freecdt!=l)
252: || (!equal && user->cdt+user->freecdt<l))
253: result=_not;
254: else
255: result=!_not;
256: (*ptrptr)++;
257: if(!result) {
258: noaccess_str=text[NoAccessCredit];
1.1.1.2 ! root 259: noaccess_val=l;
! 260: }
1.1 root 261: break;
262: case AR_NODE:
263: if((equal && cfg.node_num!=n) || (!equal && cfg.node_num<n))
264: result=_not;
265: else
266: result=!_not;
267: if(!result) {
268: noaccess_str=text[NoAccessNode];
1.1.1.2 ! root 269: noaccess_val=n;
! 270: }
1.1 root 271: break;
272: case AR_USER:
273: if((equal && user->number!=i) || (!equal && user->number<i))
274: result=_not;
275: else
276: result=!_not;
277: (*ptrptr)++;
278: if(!result) {
279: noaccess_str=text[NoAccessUser];
1.1.1.2 ! root 280: noaccess_val=i;
! 281: }
1.1 root 282: break;
283: case AR_GROUP:
284: if((equal
285: && (cursubnum>=cfg.total_subs
286: || cfg.sub[cursubnum]->grp!=i))
287: || (!equal && cursubnum<cfg.total_subs
288: && cfg.sub[cursubnum]->grp<i))
289: result=_not;
290: else
291: result=!_not;
292: (*ptrptr)++;
293: if(!result) {
294: noaccess_str=text[NoAccessGroup];
1.1.1.2 ! root 295: noaccess_val=i+1;
! 296: }
1.1 root 297: break;
298: case AR_SUB:
299: if((equal && cursubnum!=i) || (!equal && cursubnum<i))
300: result=_not;
301: else
302: result=!_not;
303: (*ptrptr)++;
304: if(!result) {
305: noaccess_str=text[NoAccessSub];
1.1.1.2 ! root 306: noaccess_val=i+1;
! 307: }
1.1 root 308: break;
309: case AR_SUBCODE:
310: if(cursubnum>=cfg.total_subs
1.1.1.2 ! root 311: || !findstr_in_string(cfg.sub[cursubnum]->code,(char*)*ptrptr))
1.1 root 312: result=_not;
313: else
314: result=!_not;
315: while(*(*ptrptr))
316: (*ptrptr)++;
317: if(!result)
318: noaccess_str=text[NoAccessSub];
319: break;
320: case AR_LIB:
321: if((equal
322: && (curdirnum>=cfg.total_dirs
323: || cfg.dir[curdirnum]->lib!=i))
324: || (!equal && curdirnum<cfg.total_dirs
325: && cfg.dir[curdirnum]->lib<i))
326: result=_not;
327: else
328: result=!_not;
329: (*ptrptr)++;
330: if(!result) {
331: noaccess_str=text[NoAccessLib];
1.1.1.2 ! root 332: noaccess_val=i+1;
! 333: }
1.1 root 334: break;
335: case AR_DIR:
336: if((equal && curdirnum!=i) || (!equal && curdirnum<i))
337: result=_not;
338: else
339: result=!_not;
340: (*ptrptr)++;
341: if(!result) {
342: noaccess_str=text[NoAccessDir];
1.1.1.2 ! root 343: noaccess_val=i+1;
! 344: }
1.1 root 345: break;
346: case AR_DIRCODE:
347: if(curdirnum>=cfg.total_dirs
1.1.1.2 ! root 348: || !findstr_in_string(cfg.dir[curdirnum]->code,(char *)*ptrptr))
1.1 root 349: result=_not;
350: else
351: result=!_not;
352: while(*(*ptrptr))
353: (*ptrptr)++;
354: if(!result)
355: noaccess_str=text[NoAccessSub];
356: break;
357: case AR_EXPIRE:
358: now=time(NULL);
359: if(!user->expire || now+((long)i*24L*60L*60L)>user->expire)
360: result=_not;
361: else
362: result=!_not;
363: (*ptrptr)++;
364: if(!result) {
365: noaccess_str=text[NoAccessExpire];
1.1.1.2 ! root 366: noaccess_val=i;
! 367: }
1.1 root 368: break;
369: case AR_RANDOM:
370: n=sbbs_random(i+1);
371: if((equal && n!=i) || (!equal && n<i))
372: result=_not;
373: else
374: result=!_not;
375: (*ptrptr)++;
376: break;
377: case AR_LASTON:
378: now=time(NULL);
379: if((now-user->laston)/(24L*60L*60L)<(long)i)
380: result=_not;
381: else
382: result=!_not;
383: (*ptrptr)++;
384: break;
385: case AR_LOGONS:
386: if((equal && user->logons!=i) || (!equal && user->logons<i))
387: result=_not;
388: else
389: result=!_not;
390: (*ptrptr)++;
391: break;
392: case AR_MAIN_CMDS:
393: if((equal && main_cmds!=i) || (!equal && main_cmds<i))
394: result=_not;
395: else
396: result=!_not;
397: (*ptrptr)++;
398: break;
399: case AR_FILE_CMDS:
400: if((equal && xfer_cmds!=i) || (!equal && xfer_cmds<i))
401: result=_not;
402: else
403: result=!_not;
404: (*ptrptr)++;
405: break;
406: case AR_TLEFT:
407: if(timeleft/60<(ulong)n)
408: result=_not;
409: else
410: result=!_not;
411: if(!result) {
412: noaccess_str=text[NoAccessTimeLeft];
1.1.1.2 ! root 413: noaccess_val=n;
! 414: }
1.1 root 415: break;
416: case AR_TUSED:
417: if((time(NULL)-logontime)/60<(long)n)
418: result=_not;
419: else
420: result=!_not;
421: if(!result) {
422: noaccess_str=text[NoAccessTimeUsed];
1.1.1.2 ! root 423: noaccess_val=n;
! 424: }
1.1 root 425: break;
426: case AR_TIME:
427: now=time(NULL);
428: localtime_r(&now,&tm);
429: if((tm.tm_hour*60)+tm.tm_min<(int)i)
430: result=_not;
431: else
432: result=!_not;
433: (*ptrptr)++;
434: if(!result) {
435: noaccess_str=text[NoAccessTime];
1.1.1.2 ! root 436: noaccess_val=i;
! 437: }
1.1 root 438: break;
439: case AR_PCR: /* post/call ratio (by percentage) */
440: if(user->logons>user->posts
441: && (!user->posts || (100/((float)user->logons/user->posts))<(long)n))
442: result=_not;
443: else
444: result=!_not;
445: if(!result) {
446: noaccess_str=text[NoAccessPCR];
1.1.1.2 ! root 447: noaccess_val=n;
! 448: }
1.1 root 449: break;
450: case AR_UDR: /* up/download byte ratio (by percentage) */
451: l=user->dlb;
452: if(!l) l=1;
453: if(user->dlb>user->ulb
454: && (!user->ulb || (100/((float)l/user->ulb))<n))
455: result=_not;
456: else
457: result=!_not;
458: if(!result) {
459: noaccess_str=text[NoAccessUDR];
1.1.1.2 ! root 460: noaccess_val=n;
! 461: }
1.1 root 462: break;
463: case AR_UDFR: /* up/download file ratio (in percentage) */
464: i=user->dls;
465: if(!i) i=1;
466: if(user->dls>user->uls
467: && (!user->uls || (100/((float)i/user->uls))<n))
468: result=_not;
469: else
470: result=!_not;
471: if(!result) {
472: noaccess_str=text[NoAccessUDFR];
1.1.1.2 ! root 473: noaccess_val=n;
! 474: }
! 475: break;
! 476: case AR_ULS:
! 477: if((equal && user->uls!=i) || (!equal && user->uls<i))
! 478: result=_not;
! 479: else
! 480: result=!_not;
! 481: (*ptrptr)++;
! 482: break;
! 483: case AR_ULK:
! 484: if((equal && (user->ulb/1024)!=i) || (!equal && (user->ulb/1024)<i))
! 485: result=_not;
! 486: else
! 487: result=!_not;
! 488: (*ptrptr)++;
! 489: break;
! 490: case AR_ULM:
! 491: if((equal && (user->ulb/(1024*1024))!=i) || (!equal && (user->ulb/(1024*1024))<i))
! 492: result=_not;
! 493: else
! 494: result=!_not;
! 495: (*ptrptr)++;
! 496: break;
! 497: case AR_DLS:
! 498: if((equal && user->dls!=i) || (!equal && user->dls<i))
! 499: result=_not;
! 500: else
! 501: result=!_not;
! 502: (*ptrptr)++;
! 503: break;
! 504: case AR_DLK:
! 505: if((equal && user->dlb/1024!=i) || (!equal && user->dlb/1024<i))
! 506: result=_not;
! 507: else
! 508: result=!_not;
! 509: (*ptrptr)++;
! 510: break;
! 511: case AR_DLM:
! 512: if((equal && user->dlb/(1024*1024)!=i) || (!equal && user->dlb/(1024*1024)<i))
! 513: result=_not;
! 514: else
! 515: result=!_not;
! 516: (*ptrptr)++;
1.1 root 517: break;
518: case AR_FLAG1:
519: if((!equal && !(user->flags1&FLAG(n)))
520: || (equal && user->flags1!=FLAG(n)))
521: result=_not;
522: else
523: result=!_not;
524: if(!result) {
525: noaccess_str=text[NoAccessFlag1];
1.1.1.2 ! root 526: noaccess_val=n;
! 527: }
1.1 root 528: break;
529: case AR_FLAG2:
530: if((!equal && !(user->flags2&FLAG(n)))
531: || (equal && user->flags2!=FLAG(n)))
532: result=_not;
533: else
534: result=!_not;
535: if(!result) {
536: noaccess_str=text[NoAccessFlag2];
1.1.1.2 ! root 537: noaccess_val=n;
! 538: }
1.1 root 539: break;
540: case AR_FLAG3:
541: if((!equal && !(user->flags3&FLAG(n)))
542: || (equal && user->flags3!=FLAG(n)))
543: result=_not;
544: else
545: result=!_not;
546: if(!result) {
547: noaccess_str=text[NoAccessFlag3];
1.1.1.2 ! root 548: noaccess_val=n;
! 549: }
1.1 root 550: break;
551: case AR_FLAG4:
552: if((!equal && !(user->flags4&FLAG(n)))
553: || (equal && user->flags4!=FLAG(n)))
554: result=_not;
555: else
556: result=!_not;
557: if(!result) {
558: noaccess_str=text[NoAccessFlag4];
1.1.1.2 ! root 559: noaccess_val=n;
! 560: }
1.1 root 561: break;
562: case AR_REST:
563: if((!equal && !(user->rest&FLAG(n)))
564: || (equal && user->rest!=FLAG(n)))
565: result=_not;
566: else
567: result=!_not;
568: if(!result) {
569: noaccess_str=text[NoAccessRest];
1.1.1.2 ! root 570: noaccess_val=n;
! 571: }
1.1 root 572: break;
573: case AR_EXEMPT:
574: if((!equal && !(user->exempt&FLAG(n)))
575: || (equal && user->exempt!=FLAG(n)))
576: result=_not;
577: else
578: result=!_not;
579: if(!result) {
580: noaccess_str=text[NoAccessExempt];
1.1.1.2 ! root 581: noaccess_val=n;
! 582: }
1.1 root 583: break;
584: case AR_SEX:
585: if(user->sex!=n)
586: result=_not;
587: else
588: result=!_not;
589: if(!result) {
590: noaccess_str=text[NoAccessSex];
1.1.1.2 ! root 591: noaccess_val=n;
! 592: }
1.1 root 593: break;
594: case AR_SHELL:
595: if(user->shell>=cfg.total_shells
1.1.1.2 ! root 596: || !findstr_in_string(cfg.shell[user->shell]->code,(char*)*ptrptr))
1.1 root 597: result=_not;
598: else
599: result=!_not;
600: while(*(*ptrptr))
601: (*ptrptr)++;
602: break;
603: case AR_PROT:
1.1.1.2 ! root 604: if(client!=NULL)
! 605: p=client->protocol;
! 606: else
! 607: p=user->modem;
! 608: if(!findstr_in_string(p,(char*)*ptrptr))
! 609: result=_not;
! 610: else
! 611: result=!_not;
! 612: while(*(*ptrptr))
! 613: (*ptrptr)++;
! 614: break;
! 615: case AR_HOST:
! 616: if(client!=NULL)
! 617: p=client->host;
! 618: else
! 619: p=user->comp;
! 620: if(!findstr_in_string(p,(char*)*ptrptr))
! 621: result=_not;
! 622: else
! 623: result=!_not;
! 624: while(*(*ptrptr))
! 625: (*ptrptr)++;
! 626: break;
! 627: case AR_IP:
! 628: if(client!=NULL)
! 629: p=client->addr;
! 630: else
! 631: p=user->note;
! 632: if(!findstr_in_string(p,(char*)*ptrptr))
1.1 root 633: result=_not;
634: else
635: result=!_not;
636: while(*(*ptrptr))
637: (*ptrptr)++;
638: break;
639: }
640: }
641: return(result);
642: }
643:
1.1.1.2 ! root 644: bool sbbs_t::chk_ar(const uchar *ar, user_t* user, client_t* client)
1.1 root 645: {
1.1.1.2 ! root 646: const uchar *p;
1.1 root 647:
648: if(ar==NULL)
649: return(true);
650: p=ar;
1.1.1.2 ! root 651: return(ar_exp(&p,user,client));
1.1 root 652: }
653:
654:
655: /****************************************************************************/
656: /* This function fills the usrsub, usrsubs, usrgrps, curgrp, and cursub */
657: /* variables based on the security clearance of the current user (useron) */
658: /****************************************************************************/
659: void sbbs_t::getusrsubs()
660: {
661: uint i,j,k,l;
662:
663: for(j=0,i=0;i<cfg.total_grps;i++) {
1.1.1.2 ! root 664: if(!chk_ar(cfg.grp[i]->ar,&useron,&client))
1.1 root 665: continue;
666: for(k=0,l=0;l<cfg.total_subs;l++) {
667: if(cfg.sub[l]->grp!=i) continue;
1.1.1.2 ! root 668: if(!chk_ar(cfg.sub[l]->ar,&useron,&client))
1.1 root 669: continue;
670: usrsub[j][k++]=l;
671: }
672: usrsubs[j]=k;
673: if(!k) /* No subs accessible in group */
674: continue;
675: usrgrp[j++]=i;
676: }
677: usrgrps=j;
678: if(usrgrps==0)
679: return;
680: while((curgrp>=usrgrps || !usrsubs[curgrp]) && curgrp) curgrp--;
681: while(cursub[curgrp]>=usrsubs[curgrp] && cursub[curgrp]) cursub[curgrp]--;
682: }
683:
684: /****************************************************************************/
685: /* This function fills the usrdir, usrdirs, usrlibs, curlib, and curdir */
686: /* variables based on the security clearance of the current user (useron) */
687: /****************************************************************************/
688: void sbbs_t::getusrdirs()
689: {
690: uint i,j,k,l;
691:
692: if(useron.rest&FLAG('T')) {
693: usrlibs=0;
694: return;
695: }
696: for(j=0,i=0;i<cfg.total_libs;i++) {
1.1.1.2 ! root 697: if(!chk_ar(cfg.lib[i]->ar,&useron,&client))
1.1 root 698: continue;
699: for(k=0,l=0;l<cfg.total_dirs;l++) {
700: if(cfg.dir[l]->lib!=i) continue;
1.1.1.2 ! root 701: if(!chk_ar(cfg.dir[l]->ar,&useron,&client))
1.1 root 702: continue;
1.1.1.2 ! root 703: usrdir[j][k++]=l;
! 704: }
1.1 root 705: usrdirs[j]=k;
706: if(!k) /* No dirs accessible in lib */
707: continue;
708: usrlib[j++]=i;
709: }
710: usrlibs=j;
711: if(usrlibs==0)
712: return;
713: while((curlib>=usrlibs || !usrdirs[curlib]) && curlib) curlib--;
714: while(curdir[curlib]>=usrdirs[curlib] && curdir[curlib]) curdir[curlib]--;
715: }
716:
717: uint sbbs_t::getusrgrp(uint subnum)
718: {
719: uint ugrp;
720:
721: if(subnum==INVALID_SUB)
722: return(0);
723:
724: if(usrgrps<=0)
725: return(0);
726:
727: for(ugrp=0;ugrp<usrgrps;ugrp++)
728: if(usrgrp[ugrp]==cfg.sub[subnum]->grp)
729: break;
730:
731: return(ugrp+1);
732: }
733:
734: uint sbbs_t::getusrsub(uint subnum)
735: {
736: uint usub;
737: uint ugrp;
738:
739: ugrp = getusrgrp(subnum);
740: if(ugrp<=0)
741: return(0);
742:
743: for(usub=0;usub<usrsubs[ugrp];usub++)
744: if(usrsub[ugrp][usub]==subnum)
745: break;
746:
747: return(usub+1);
748: }
749:
750: int sbbs_t::dir_op(uint dirnum)
751: {
1.1.1.2 ! root 752: return(SYSOP || (cfg.dir[dirnum]->op_ar[0] && chk_ar(cfg.dir[dirnum]->op_ar,&useron,&client)));
1.1 root 753: }
754:
755:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.