1 /*****************************************************************************/
2 /*                                                                           */
3 /*                 (C) Copyright 1995       Alberto Pasquale                 */
4 /*                 Portions (C) Copyright 1999 Per Lundberg                  */
5 /*                                                                           */
6 /*                   A L L   R I G H T S   R E S E R V E D                   */
7 /*                                                                           */
8 /*****************************************************************************/
9 /*                                                                           */
10 /* This source code is NOT in the public domain and it CANNOT be used or     */
11 /* distributed without written permission from the author.                   */
12 /*                                                                           */
13 /*****************************************************************************/
14 /*                                                                           */
15 /*   How to contact the author:  Alberto Pasquale of 2:332/504@fidonet       */
16 /*                               Viale Verdi 106                             */
17 /*                               41100 Modena                                */
18 /*                               Italy                                       */
19 /*                                                                           */
20 /*****************************************************************************/
21 
22 // MaxAcs.Cpp
23 
24 #include "bbsgenlb.hpp"
25 #include "uclass.h"
26 #include <apgenlib.hpp>
27 #include <string.h>
28 #include <ctype.h>
29 
30 #define _LEVELSIZE 80       // max length of access level name
31 #define _TOKACSSIZE 160     // max length of "<=Normal/a!b"
32 #define _PRODACSSIZE 512    // max length of TOKACS separated by '&'
33 
34 // returns 0 on success.  keys0 are the keys preceded by '!'
35 
GetKeys(char * ks,dword * keys1,dword * keys0=NULL)36 static int GetKeys (char *ks, dword *keys1, dword *keys0 = NULL)
37 {
38 	char *c;
39 	int u, nbit;
40     long bit;
41 
42     BOOL flag0 = FALSE;
43     *keys1 = 0L;
44     if (keys0)
45         *keys0 = 0L;
46 
47     for (c = ks; (u = toupper(*c)) != 0; c++)
48 	{
49         if ((keys0) && (u == '!')) {
50             flag0 = TRUE;
51             continue;
52         }
53 
54         if ((u < '1') || (u > 'X') || (u > '8') && (u < 'A'))
55             return -1;
56 
57         if (isdigit (u))
58             nbit = u - '1';
59         else
60             nbit = u - 'A' + 8;
61 
62 		bit = 1L << nbit;
63 
64         if (flag0) {
65             *keys0 |= bit;
66             flag0 = FALSE;
67         } else
68             *keys1 |= bit;
69 	}
70     return 0;
71 }
72 
73 
MAXACS()74 MAXACS::MAXACS ()
75 {
76     buffer = NULL;
77 }
78 
79 
~MAXACS()80 MAXACS::~MAXACS ()
81 {
82     if (buffer)
83         delete[] buffer;
84 }
85 
86 
Read(char * acsname)87 int MAXACS::Read (char *acsname)
88 {
89     char fullname[PATH_MAX];
90     strcpy (fullname, acsname);
91     addext (fullname, ".DAT");
92 
93     FILE *f = fopen (fullname, "rb");
94     if (!f)
95         return -1;
96     long fsize = filelength (fileno (f));
97     if ((fsize == -1) || (fsize < (long)sizeof (CLSHDR))) {
98         fclose (f);
99         return -1;
100     }
101 
102     buffer = new byte[fsize];
103 
104     if (fread (buffer, (size_t)fsize, 1, f) != 1) {
105         fclose (f);
106         return -1;
107     }
108 
109     fclose (f);
110 
111     CLSHDR *chp = (CLSHDR *) buffer;
112     if (chp->ulclhid != CLS_ID)
113         return -1;
114 
115     usn = chp->usn;
116     ussize = chp->ussize;
117 
118     int heapofs = chp->usclfirst + usn * ussize;
119 
120     if (fsize < (heapofs + chp->usstr))
121         return -1;
122 
123     heap = (char *) (buffer + heapofs);
124     uscl1 = buffer + chp->usclfirst;
125 
126     return 0;
127 }
128 
129 
GetLevel(char * slevel,word * level)130 int MAXACS::GetLevel (char *slevel, word *level)
131 {
132     byte *b;
133     int i;
134     for (i = 0, b = uscl1; i < usn; i ++, b += ussize) {
135         CLSREC *crp = (CLSREC *) b;
136         if ((stricmp (slevel, heap + crp->zAbbrev) == 0) ||
137             (stricmp (slevel, heap + crp->zAlias)  == 0)) {
138             *level = crp->usLevel;
139             return 0;
140         }
141     }
142     return -1;
143 }
144 
145 
GetGenAcs(char * lks,word * level,dword * keys1,dword * keys0)146 int MAXACS::GetGenAcs (char *lks, word *level, dword *keys1, dword *keys0)
147 {
148     char slevel[_LEVELSIZE];
149 
150     char *p = strchr (lks, '/');
151     if (p) {                        // there are keys
152         strzcpy (slevel, lks, __min (p - lks + 1, _LEVELSIZE));
153         if (keys1)
154             if (GetKeys (p+1, keys1, keys0))
155                 return -1;
156     } else {
157         strzcpy (slevel, lks, _LEVELSIZE);
158         if (keys1) {
159             *keys1 = 0L;
160             if (keys0)
161                 *keys0 = 0L;
162         }
163     }
164 
165     if (isdigit (slevel[0])) {      // numeric access level
166         char *endptr;
167         ulong res = strtoul (slevel, &endptr, 10);
168         if ((res > 65535) || (*endptr != '\0'))
169             return -1;
170         *level = (word) res;
171     } else {                // string access level: look up access.dat
172         if (GetLevel (slevel, level))
173             return -1;
174     }
175 
176     return 0;
177 }
178 
179 
GetAcs(char * ACS,word * level,dword * keys)180 int MAXACS::GetAcs (char *ACS, word *level, dword *keys)
181 {
182     return GetGenAcs (ACS, level, keys);
183 }
184 
185 
TokAcs(char * TokAcs,word level,dword keys)186 BOOL MAXACS::TokAcs (char *TokAcs, word level, dword keys)
187 {
188     char *p = TokAcs;
189 
190     if (stricmp (p, "NoAccess") == 0)
191         return FALSE;
192     if (strncasecmp (p, "name=", 5) == 0)
193         return FALSE;
194     if (strncasecmp (p, "alias=", 6) == 0)
195         return FALSE;
196 
197     _privcmp op;
198 
199     switch (strspn (p, "=><!")) {       // evaluate comparison operator
200         case 0:
201             op = privGE;
202             break;
203         case 1:
204             if (*p == '=')
205                 op = privEQ;
206             else if (*p == '>')
207                 op = privGT;
208             else if (*p == '<')
209                 op = privLT;
210             else
211                 return FALSE;
212             p ++;
213             break;
214         case 2:
215             if ((*p == '>') && (*(p+1) == '='))
216                 op = privGE;
217             else if ((*p == '<') && (*(p+1) == '='))
218                 op = privLE;
219             else if ((*p == '<') && (*(p+1) == '>'))
220                 op = privNE;
221             else if ((*p == '!') && (*(p+1) == '='))
222                 op = privNE;
223             else
224                 return FALSE;
225             p += 2;
226             break;
227         default:
228             return FALSE;
229     }
230 
231         // now evaluate the level/keys
232 
233     word reqlevel;
234     dword reqkeys1, reqkeys0;
235 
236     if (GetGenAcs (p, &reqlevel, &reqkeys1, &reqkeys0))
237         return FALSE;
238 
239     switch (op) {           // compare level
240         case privGE:
241             if (!(level >= reqlevel))
242                 return FALSE;
243             break;
244         case privLE:
245             if (!(level <= reqlevel))
246                 return FALSE;
247             break;
248         case privGT:
249             if (!(level > reqlevel))
250                 return FALSE;
251             break;
252         case privLT:
253             if (!(level < reqlevel))
254                 return FALSE;
255             break;
256         case privEQ:
257             if (!(level == reqlevel))
258                 return FALSE;
259             break;
260         case privNE:
261             if (!(level != reqlevel))
262                 return FALSE;
263             break;
264         default:
265             return FALSE;
266     }
267 
268                     // and now let's check keys
269 
270     if ((reqkeys1 & keys) != reqkeys1)  // missing some required key
271         return FALSE;
272 
273     if ((reqkeys0 & keys) != 0)     // has some key that must be absent
274         return FALSE;
275 
276     return TRUE;
277 }
278 
279 
ProdAccess(char * pac,word level,dword keys)280 BOOL MAXACS::ProdAccess (char *pac, word level, dword keys)
281 {
282     char tokacs[_TOKACSSIZE];
283 
284     char *p = pac;
285     while (*p) {
286         int toklen = strcspn (p, "&");
287         if (toklen == 0)
288             return FALSE;
289         strzcpy (tokacs, p, __min (toklen + 1, _TOKACSSIZE));
290         if (!TokAcs (tokacs, level, keys))
291             return FALSE;
292         p += toklen;
293         if (*p == '&')
294             p ++;
295     }
296     return TRUE;
297 }
298 
299 
HaveAccess(char * ACS,word level,dword keys)300 BOOL MAXACS::HaveAccess (char *ACS, word level, dword keys)
301 {
302     char prodacs[_PRODACSSIZE];
303 
304     char *p = ACS;
305     while (*p) {
306         int toklen = strcspn (p, "|");
307         if (toklen == 0)
308             return FALSE;
309         strzcpy (prodacs, p, __min (toklen + 1, _PRODACSSIZE));
310         if (ProdAccess (prodacs, level, keys))
311             return TRUE;
312         p += toklen;
313         if (*p == '|')
314             p ++;
315     }
316     return FALSE;
317 }
318 
319 
LevName(word level)320 char *MAXACS::LevName (word level)
321 {
322     byte *b;
323     int i;
324     for (i = 0, b = uscl1; i < usn; i ++, b += ussize) {
325         CLSREC *crp = (CLSREC *) b;
326         if (level == crp->usLevel)
327             return heap + crp->zAbbrev;
328     }
329     return NULL;
330 }
331 
332 
LevStr(word level)333 char *MAXACS::LevStr (word level)
334 {
335     char *p = LevName (level);
336     if (p)
337         return p;
338 
339     static char buf[6];
340     sprintf (buf, "%hu", level);
341     return buf;
342 }
343 
344 
345