chk_ar.cpp 16.6 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
/* chk_ar.cpp */

/* Synchronet ARS checking routine */

/* $Id$ */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
rswindell's avatar
rswindell committed
11
 * Copyright 2011 Rob Swindell - http://www.synchro.net/copyright.html		*
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
 *																			*
 * This program is free software; you can redistribute it and/or			*
 * modify it under the terms of the GNU General Public License				*
 * as published by the Free Software Foundation; either version 2			*
 * of the License, or (at your option) any later version.					*
 * See the GNU General Public License for more details: gpl.txt or			*
 * http://www.fsf.org/copyleft/gpl.html										*
 *																			*
 * Anonymous FTP access to the most recent released source is available at	*
 * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
 *																			*
 * Anonymous CVS access to the development source and modification history	*
 * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
 *     (just hit return, no password is necessary)							*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * You are encouraged to submit any modifications (preferably in Unix diff	*
 * format) via e-mail to mods@synchro.net									*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/

#include "sbbs.h"

rswindell's avatar
rswindell committed
40
bool sbbs_t::ar_exp(const uchar **ptrptr, user_t* user, client_t* client)
41
{
42
	bool	result,_not,_or,equal;
43
44
	uint	i,n,artype,age;
	ulong	l;
45
	struct tm tm;
rswindell's avatar
rswindell committed
46
	const char*	p;
47
48
49
50
51
52
53
54

	result = true;

	for(;(**ptrptr);(*ptrptr)++) {

		if((**ptrptr)==AR_ENDNEST)
			break;

55
		_not=_or=equal = false;
56
57

		if((**ptrptr)==AR_OR) {
58
			_or=true;
59
60
			(*ptrptr)++; 
		}
61
62
		
		if((**ptrptr)==AR_NOT) {
63
			_not=true;
64
65
			(*ptrptr)++; 
		}
66
67
68

		if((**ptrptr)==AR_EQUAL) {
			equal=true;
69
70
			(*ptrptr)++; 
		}
71

72
		if((result && _or) || (!result && !_or))
73
74
75
76
			break;

		if((**ptrptr)==AR_BEGNEST) {
			(*ptrptr)++;
rswindell's avatar
rswindell committed
77
			if(ar_exp(ptrptr,user,client))
78
				result=!_not;
79
			else
80
				result=_not;
81
82
83
84
			while((**ptrptr)!=AR_ENDNEST && (**ptrptr)) /* in case of early exit */
				(*ptrptr)++;
			if(!(**ptrptr))
				break;
85
86
			continue; 
		}
87
88
89
90
91
92
93
94
95

		artype=(**ptrptr);
		switch(artype) {
			case AR_ANSI:				/* No arguments */
			case AR_RIP:
			case AR_WIP:
			case AR_LOCAL:
			case AR_EXPERT:
			case AR_SYSOP:
96
97
			case AR_GUEST:
			case AR_QNODE:
98
99
100
			case AR_QUIET:
			case AR_OS2:
			case AR_DOS:
101
102
103
			case AR_WIN32:
			case AR_UNIX:
			case AR_LINUX:
104
105
106
				break;
			default:
				(*ptrptr)++;
107
108
				break; 
		}
109
110
111
112
113
114

		n=(**ptrptr);
		i=(*(short *)*ptrptr);
		switch(artype) {
			case AR_LEVEL:
				if((equal && user->level!=n) || (!equal && user->level<n))
115
					result=_not;
116
				else
117
					result=!_not;
118
119
				if(!result) {
					noaccess_str=text[NoAccessLevel];
120
121
					noaccess_val=n; 
				}
122
123
124
125
				break;
			case AR_AGE:
				age=getage(&cfg,user->birth);
				if((equal && age!=n) || (!equal && age<n))
126
					result=_not;
127
				else
128
					result=!_not;
129
130
				if(!result) {
					noaccess_str=text[NoAccessAge];
131
132
					noaccess_val=n; 
				}
133
134
135
				break;
			case AR_BPS:
				if((equal && cur_rate!=i) || (!equal && cur_rate<i))
136
					result=_not;
137
				else
138
					result=!_not;
139
140
141
				(*ptrptr)++;
				if(!result) {
					noaccess_str=text[NoAccessBPS];
142
143
					noaccess_val=i; 
				}
144
145
146
				break;
			case AR_ANSI:
				if(!(user->misc&ANSI))
147
148
					result=_not;
				else result=!_not;
149
150
151
				break;
			case AR_RIP:
				if(!(user->misc&RIP))
152
153
					result=_not;
				else result=!_not;
154
155
156
				break;
			case AR_WIP:
				if(!(user->misc&WIP))
157
158
					result=_not;
				else result=!_not;
159
160
161
				break;
			case AR_OS2:
				#ifndef __OS2__
162
					result=_not;
163
				#else
164
					result=!_not;
165
166
167
				#endif
				break;
			case AR_DOS:
deuce's avatar
deuce committed
168
				result=_not;
169
170
171
				break;
			case AR_WIN32:
				#ifndef _WIN32
172
					result=_not;
173
				#else
174
					result=!_not;
175
176
177
178
				#endif
				break;
			case AR_UNIX:
				#ifndef __unix__
179
					result=_not;
180
				#else
181
					result=!_not;
182
183
184
185
				#endif
				break;
			case AR_LINUX:
				#ifndef __linux__
186
					result=_not;
187
				#else
188
					result=!_not;
189
190
				#endif
				break;
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
			case AR_ACTIVE:
				if(user->misc&(DELETED|INACTIVE))
					result=_not;
				else result=!_not;
				break;
			case AR_INACTIVE:
				if(!(user->misc&INACTIVE))
					result=_not;
				else result=!_not;
				break;
			case AR_DELETED:
				if(!(user->misc&DELETED))
					result=_not;
				else result=!_not;
				break;
206
207
			case AR_EXPERT:
				if(!(user->misc&EXPERT))
208
209
					result=_not;
				else result=!_not;
210
211
212
				break;
			case AR_SYSOP:
				if(!SYSOP)
213
214
					result=_not;
				else result=!_not;
215
				break;
216
217
218
219
220
221
222
223
224
225
			case AR_GUEST:
				if(!(user->rest&FLAG('G')))
					result=_not;
				else result=!_not;
				break;
			case AR_QNODE:
				if(!(user->rest&FLAG('Q')))
					result=_not;
				else result=!_not;
				break;
226
227
			case AR_QUIET:
				if(thisnode.status!=NODE_QUIET)
228
229
					result=_not;
				else result=!_not;
230
231
232
				break;
			case AR_LOCAL:
				if(online!=ON_LOCAL)
233
234
					result=_not;
				else result=!_not;
235
236
237
				break;
			case AR_DAY:
				now=time(NULL);
238
239
240
				localtime_r(&now,&tm);
				if((equal && tm.tm_wday!=(int)n) 
					|| (!equal && tm.tm_wday<(int)n))
241
					result=_not;
242
				else
243
					result=!_not;
244
245
				if(!result) {
					noaccess_str=text[NoAccessDay];
246
247
					noaccess_val=n; 
				}
248
249
250
251
252
				break;
			case AR_CREDIT:
				l=(ulong)i*1024UL;
				if((equal && user->cdt+user->freecdt!=l)
					|| (!equal && user->cdt+user->freecdt<l))
253
					result=_not;
254
				else
255
					result=!_not;
256
257
258
				(*ptrptr)++;
				if(!result) {
					noaccess_str=text[NoAccessCredit];
259
260
					noaccess_val=l; 
				}
261
262
263
				break;
			case AR_NODE:
				if((equal && cfg.node_num!=n) || (!equal && cfg.node_num<n))
264
					result=_not;
265
				else
266
					result=!_not;
267
268
				if(!result) {
					noaccess_str=text[NoAccessNode];
269
270
					noaccess_val=n; 
				}
271
272
273
				break;
			case AR_USER:
				if((equal && user->number!=i) || (!equal && user->number<i))
274
					result=_not;
275
				else
276
					result=!_not;
277
278
279
				(*ptrptr)++;
				if(!result) {
					noaccess_str=text[NoAccessUser];
280
281
					noaccess_val=i; 
				}
282
283
284
285
286
287
288
				break;
			case AR_GROUP:
				if((equal
					&& (cursubnum>=cfg.total_subs
						|| cfg.sub[cursubnum]->grp!=i))
					|| (!equal && cursubnum<cfg.total_subs
						&& cfg.sub[cursubnum]->grp<i))
289
					result=_not;
290
				else
291
					result=!_not;
292
293
294
				(*ptrptr)++;
				if(!result) {
					noaccess_str=text[NoAccessGroup];
295
296
					noaccess_val=i+1; 
				}
297
298
299
				break;
			case AR_SUB:
				if((equal && cursubnum!=i) || (!equal && cursubnum<i))
300
					result=_not;
301
				else
302
					result=!_not;
303
304
305
				(*ptrptr)++;
				if(!result) {
					noaccess_str=text[NoAccessSub];
306
307
					noaccess_val=i+1; 
				}
308
309
310
				break;
			case AR_SUBCODE:
				if(cursubnum>=cfg.total_subs
rswindell's avatar
rswindell committed
311
					|| !findstr_in_string(cfg.sub[cursubnum]->code,(char*)*ptrptr))
312
					result=_not;
313
				else
314
					result=!_not;
315
316
317
318
319
320
321
322
323
324
325
				while(*(*ptrptr))
					(*ptrptr)++;
				if(!result)
					noaccess_str=text[NoAccessSub];
				break;
			case AR_LIB:
				if((equal
					&& (curdirnum>=cfg.total_dirs
						|| cfg.dir[curdirnum]->lib!=i))
					|| (!equal && curdirnum<cfg.total_dirs
						&& cfg.dir[curdirnum]->lib<i))
326
					result=_not;
327
				else
328
					result=!_not;
329
330
331
				(*ptrptr)++;
				if(!result) {
					noaccess_str=text[NoAccessLib];
332
333
					noaccess_val=i+1; 
				}
334
335
336
				break;
			case AR_DIR:
				if((equal && curdirnum!=i) || (!equal && curdirnum<i))
337
					result=_not;
338
				else
339
					result=!_not;
340
341
342
				(*ptrptr)++;
				if(!result) {
					noaccess_str=text[NoAccessDir];
343
344
					noaccess_val=i+1; 
				}
345
346
347
				break;
			case AR_DIRCODE:
				if(curdirnum>=cfg.total_dirs
rswindell's avatar
rswindell committed
348
					|| !findstr_in_string(cfg.dir[curdirnum]->code,(char *)*ptrptr))
349
					result=_not;
350
				else
351
					result=!_not;
352
353
354
355
356
357
358
359
				while(*(*ptrptr))
					(*ptrptr)++;
				if(!result)
					noaccess_str=text[NoAccessSub];
				break;
			case AR_EXPIRE:
				now=time(NULL);
				if(!user->expire || now+((long)i*24L*60L*60L)>user->expire)
360
					result=_not;
361
				else
362
					result=!_not;
363
364
365
				(*ptrptr)++;
				if(!result) {
					noaccess_str=text[NoAccessExpire];
366
367
					noaccess_val=i; 
				}
368
369
				break;
			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
376
377
378
379
				(*ptrptr)++;
				break;
			case AR_LASTON:
				now=time(NULL);
				if((now-user->laston)/(24L*60L*60L)<(long)i)
380
					result=_not;
381
				else
382
					result=!_not;
383
384
385
386
				(*ptrptr)++;
				break;
			case AR_LOGONS:
				if((equal && user->logons!=i) || (!equal && user->logons<i))
387
					result=_not;
388
				else
389
					result=!_not;
390
391
392
393
				(*ptrptr)++;
				break;
			case AR_MAIN_CMDS:
				if((equal && main_cmds!=i) || (!equal && main_cmds<i))
394
					result=_not;
395
				else
396
					result=!_not;
397
398
399
400
				(*ptrptr)++;
				break;
			case AR_FILE_CMDS:
				if((equal && xfer_cmds!=i) || (!equal && xfer_cmds<i))
401
					result=_not;
402
				else
403
					result=!_not;
404
405
406
407
				(*ptrptr)++;
				break;
			case AR_TLEFT:
				if(timeleft/60<(ulong)n)
408
					result=_not;
409
				else
410
					result=!_not;
411
412
				if(!result) {
					noaccess_str=text[NoAccessTimeLeft];
413
414
					noaccess_val=n; 
				}
415
416
417
				break;
			case AR_TUSED:
				if((time(NULL)-logontime)/60<(long)n)
418
					result=_not;
419
				else
420
					result=!_not;
421
422
				if(!result) {
					noaccess_str=text[NoAccessTimeUsed];
423
424
					noaccess_val=n; 
				}
425
426
427
				break;
			case AR_TIME:
				now=time(NULL);
428
429
				localtime_r(&now,&tm);
				if((tm.tm_hour*60)+tm.tm_min<(int)i)
430
					result=_not;
431
				else
432
					result=!_not;
433
434
435
				(*ptrptr)++;
				if(!result) {
					noaccess_str=text[NoAccessTime];
436
437
					noaccess_val=i; 
				}
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
446
				if(!result) {
					noaccess_str=text[NoAccessPCR];
447
448
					noaccess_val=n; 
				}
449
				break;
450
			case AR_UDR:	/* up/download byte ratio (by percentage) */
451
452
453
				l=user->dlb;
				if(!l) l=1;
				if(user->dlb>user->ulb
454
					&& (!user->ulb || (100/((float)l/user->ulb))<n))
455
					result=_not;
456
				else
457
					result=!_not;
458
459
				if(!result) {
					noaccess_str=text[NoAccessUDR];
460
461
					noaccess_val=n; 
				}
462
				break;
463
			case AR_UDFR:	/* up/download file ratio (in percentage) */
464
465
466
				i=user->dls;
				if(!i) i=1;
				if(user->dls>user->uls
467
					&& (!user->uls || (100/((float)i/user->uls))<n))
468
					result=_not;
469
				else
470
					result=!_not;
471
472
				if(!result) {
					noaccess_str=text[NoAccessUDFR];
473
474
					noaccess_val=n; 
				}
475
				break;
rswindell's avatar
rswindell committed
476
477
478
479
480
481
482
			case AR_ULS:
				if((equal && user->uls!=i) || (!equal && user->uls<i))
					result=_not;
				else
					result=!_not;
				(*ptrptr)++;
				break;
483
484
485
486
487
488
489
490
491
			case AR_ULK:
				if((equal && (user->ulb/1024)!=i) || (!equal && (user->ulb/1024)<i))
					result=_not;
				else
					result=!_not;
				(*ptrptr)++;
				break;
			case AR_ULM:
				if((equal && (user->ulb/(1024*1024))!=i) || (!equal && (user->ulb/(1024*1024))<i))
rswindell's avatar
rswindell committed
492
493
494
495
496
497
498
499
500
501
502
503
					result=_not;
				else
					result=!_not;
				(*ptrptr)++;
				break;
			case AR_DLS:
				if((equal && user->dls!=i) || (!equal && user->dls<i))
					result=_not;
				else
					result=!_not;
				(*ptrptr)++;
				break;
504
505
506
507
508
509
510
511
512
			case AR_DLK:
				if((equal && user->dlb/1024!=i) || (!equal && user->dlb/1024<i))
					result=_not;
				else
					result=!_not;
				(*ptrptr)++;
				break;
			case AR_DLM:
				if((equal && user->dlb/(1024*1024)!=i) || (!equal && user->dlb/(1024*1024)<i))
rswindell's avatar
rswindell committed
513
514
515
516
517
					result=_not;
				else
					result=!_not;
				(*ptrptr)++;
				break;
518
519
520
			case AR_FLAG1:
				if((!equal && !(user->flags1&FLAG(n)))
					|| (equal && user->flags1!=FLAG(n)))
521
					result=_not;
522
				else
523
					result=!_not;
524
525
				if(!result) {
					noaccess_str=text[NoAccessFlag1];
526
527
					noaccess_val=n; 
				}
528
529
530
531
				break;
			case AR_FLAG2:
				if((!equal && !(user->flags2&FLAG(n)))
					|| (equal && user->flags2!=FLAG(n)))
532
					result=_not;
533
				else
534
					result=!_not;
535
536
				if(!result) {
					noaccess_str=text[NoAccessFlag2];
537
538
					noaccess_val=n; 
				}
539
540
541
542
				break;
			case AR_FLAG3:
				if((!equal && !(user->flags3&FLAG(n)))
					|| (equal && user->flags3!=FLAG(n)))
543
					result=_not;
544
				else
545
					result=!_not;
546
547
				if(!result) {
					noaccess_str=text[NoAccessFlag3];
548
549
					noaccess_val=n; 
				}
550
551
552
553
				break;
			case AR_FLAG4:
				if((!equal && !(user->flags4&FLAG(n)))
					|| (equal && user->flags4!=FLAG(n)))
554
					result=_not;
555
				else
556
					result=!_not;
557
558
				if(!result) {
					noaccess_str=text[NoAccessFlag4];
559
560
					noaccess_val=n; 
				}
561
562
563
564
				break;
			case AR_REST:
				if((!equal && !(user->rest&FLAG(n)))
					|| (equal && user->rest!=FLAG(n)))
565
					result=_not;
566
				else
567
					result=!_not;
568
569
				if(!result) {
					noaccess_str=text[NoAccessRest];
570
571
					noaccess_val=n; 
				}
572
573
574
575
				break;
			case AR_EXEMPT:
				if((!equal && !(user->exempt&FLAG(n)))
					|| (equal && user->exempt!=FLAG(n)))
576
					result=_not;
577
				else
578
					result=!_not;
579
580
				if(!result) {
					noaccess_str=text[NoAccessExempt];
581
582
					noaccess_val=n; 
				}
583
584
585
				break;
			case AR_SEX:
				if(user->sex!=n)
586
					result=_not;
587
				else
588
					result=!_not;
589
590
				if(!result) {
					noaccess_str=text[NoAccessSex];
591
592
					noaccess_val=n; 
				}
593
594
595
				break; 
			case AR_SHELL:
				if(user->shell>=cfg.total_shells
rswindell's avatar
rswindell committed
596
					|| !findstr_in_string(cfg.shell[user->shell]->code,(char*)*ptrptr))
597
598
599
600
601
602
					result=_not;
				else
					result=!_not;
				while(*(*ptrptr))
					(*ptrptr)++;
				break;
603
			case AR_PROT:
rswindell's avatar
rswindell committed
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
				if(client!=NULL)
					p=client->protocol;
				else
					p=user->modem;
				if(!findstr_in_string(p,(char*)*ptrptr))
					result=_not;
				else
					result=!_not;
				while(*(*ptrptr))
					(*ptrptr)++;
				break;
			case AR_HOST:
				if(client!=NULL)
					p=client->host;
				else
					p=user->comp;
				if(!findstr_in_string(p,(char*)*ptrptr))
					result=_not;
				else
					result=!_not;
				while(*(*ptrptr))
					(*ptrptr)++;
				break;
			case AR_IP:
				if(client!=NULL)
					p=client->addr;
				else
					p=user->note;
				if(!findstr_in_string(p,(char*)*ptrptr))
633
634
635
636
637
638
					result=_not;
				else
					result=!_not;
				while(*(*ptrptr))
					(*ptrptr)++;
				break;
639
640
		}
	}
641
642
643
	return(result);
}

rswindell's avatar
rswindell committed
644
bool sbbs_t::chk_ar(const uchar *ar, user_t* user, client_t* client)
645
{
646
	const uchar *p;
647
648
649
650

	if(ar==NULL)
		return(true);
	p=ar;
rswindell's avatar
rswindell committed
651
	return(ar_exp(&p,user,client));
652
653
654
655
656
657
658
659
660
661
662
663
}


/****************************************************************************/
/* This function fills the usrsub, usrsubs, usrgrps, curgrp, and cursub     */
/* variables based on the security clearance of the current user (useron)   */
/****************************************************************************/
void sbbs_t::getusrsubs()
{
    uint i,j,k,l;

	for(j=0,i=0;i<cfg.total_grps;i++) {
rswindell's avatar
rswindell committed
664
		if(!chk_ar(cfg.grp[i]->ar,&useron,&client))
665
666
667
			continue;
		for(k=0,l=0;l<cfg.total_subs;l++) {
			if(cfg.sub[l]->grp!=i) continue;
rswindell's avatar
rswindell committed
668
			if(!chk_ar(cfg.sub[l]->ar,&useron,&client))
669
				continue;
670
671
			usrsub[j][k++]=l; 
		}
672
673
674
		usrsubs[j]=k;
		if(!k)          /* No subs accessible in group */
			continue;
675
676
		usrgrp[j++]=i; 
	}
677
	usrgrps=j;
678
679
	if(usrgrps==0)
		return;
680
681
682
683
684
685
686
687
688
689
690
691
692
693
	while((curgrp>=usrgrps || !usrsubs[curgrp]) && curgrp) curgrp--;
	while(cursub[curgrp]>=usrsubs[curgrp] && cursub[curgrp]) cursub[curgrp]--;
}

/****************************************************************************/
/* This function fills the usrdir, usrdirs, usrlibs, curlib, and curdir     */
/* variables based on the security clearance of the current user (useron)   */
/****************************************************************************/
void sbbs_t::getusrdirs()
{
    uint i,j,k,l;

	if(useron.rest&FLAG('T')) {
		usrlibs=0;
694
695
		return; 
	}
696
	for(j=0,i=0;i<cfg.total_libs;i++) {
rswindell's avatar
rswindell committed
697
		if(!chk_ar(cfg.lib[i]->ar,&useron,&client))
698
699
700
			continue;
		for(k=0,l=0;l<cfg.total_dirs;l++) {
			if(cfg.dir[l]->lib!=i) continue;
rswindell's avatar
rswindell committed
701
			if(!chk_ar(cfg.dir[l]->ar,&useron,&client))
702
				continue;
703
704
			usrdir[j][k++]=l; 
		}
705
706
707
		usrdirs[j]=k;
		if(!k)          /* No dirs accessible in lib */
			continue;
708
709
		usrlib[j++]=i; 
	}
710
	usrlibs=j;
711
712
	if(usrlibs==0)
		return;
713
714
715
716
	while((curlib>=usrlibs || !usrdirs[curlib]) && curlib) curlib--;
	while(curdir[curlib]>=usrdirs[curlib] && curdir[curlib]) curdir[curlib]--;
}

717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
uint sbbs_t::getusrgrp(uint subnum)
{
	uint	ugrp;

	if(subnum==INVALID_SUB)
		return(0);

	if(usrgrps<=0)
		return(0);

	for(ugrp=0;ugrp<usrgrps;ugrp++)
		if(usrgrp[ugrp]==cfg.sub[subnum]->grp)
			break;

	return(ugrp+1);
}

uint sbbs_t::getusrsub(uint subnum)
{
	uint	usub;
	uint	ugrp;

	ugrp = getusrgrp(subnum);
	if(ugrp<=0)
		return(0);
	
	for(usub=0;usub<usrsubs[ugrp];usub++)
		if(usrsub[ugrp][usub]==subnum)
			break;

	return(usub+1);
}

750
751
int sbbs_t::dir_op(uint dirnum)
{
rswindell's avatar
rswindell committed
752
	return(SYSOP || (cfg.dir[dirnum]->op_ar[0] && chk_ar(cfg.dir[dirnum]->op_ar,&useron,&client)));
753
754
755
}