1 /*-
2  ***********************************************************************
3  *
4  * $Id: mask.c,v 1.22 2014/07/18 06:40:44 mavrik Exp $
5  *
6  ***********************************************************************
7  *
8  * Copyright 2005-2014 The FTimes Project, All Rights Reserved.
9  *
10  ***********************************************************************
11  */
12 #include "all-includes.h"
13 
14 /*-
15  ***********************************************************************
16  *
17  * Global variables
18  *
19  ***********************************************************************
20  */
21 /*-
22  ***********************************************************************
23  *
24  * NOTE: The field order in this table must exactly match the order in
25  *       gasDecodeTable (decode.c). Mask calculations rely on this.
26  *
27  ***********************************************************************
28  */
29 static MASK_B2S_TABLE gasCmpMaskTable[] =
30 {
31   { "name",       0 },
32   { "dev",        1 },
33   { "inode",      1 },
34   { "volume",     1 },
35   { "findex",     1 },
36   { "mode",       1 },
37   { "attributes", 1 },
38   { "nlink",      1 },
39   { "uid",        1 },
40   { "gid",        1 },
41   { "rdev",       1 },
42   { "atime",      2 },
43   { "ams",        0 },
44   { "mtime",      2 },
45   { "mms",        0 },
46   { "ctime",      2 },
47   { "cms",        0 },
48   { "chtime",     2 },
49   { "chms",       0 },
50   { "size",       1 },
51   { "altstreams", 1 },
52   { "md5",        1 },
53   { "sha1",       1 },
54   { "sha256",     1 },
55   { "magic",      1 },
56   { "osid",       1 },
57   { "gsid",       1 },
58   { "dacl",       1 },
59 };
60 
61 #ifdef WIN32
62 static MASK_B2S_TABLE gasMapMaskTable[] =
63 {
64   { "volume",     1 },
65   { "findex",     1 },
66   { "attributes", 1 },
67   { "atime",      1 },
68   { "mtime",      1 },
69   { "ctime",      1 },
70   { "chtime",     1 },
71   { "size",       1 },
72   { "altstreams", 1 },
73   { "md5",        1 },
74   { "sha1",       1 },
75   { "sha256",     1 },
76   { "magic",      1 },
77   { "osid",       1 },
78   { "gsid",       1 },
79   { "dacl",       1 },
80 };
81 #else
82 static MASK_B2S_TABLE gasMapMaskTable[] =
83 {
84   { "dev",        1 },
85   { "inode",      1 },
86   { "mode",       1 },
87   { "nlink",      1 },
88   { "uid",        1 },
89   { "gid",        1 },
90   { "rdev",       1 },
91   { "atime",      1 },
92   { "mtime",      1 },
93   { "ctime",      1 },
94   { "size",       1 },
95   { "md5",        1 },
96   { "sha1",       1 },
97   { "sha256",     1 },
98   { "magic",      1 },
99 };
100 #endif
101 
102 /*-
103  ***********************************************************************
104  *
105  * MaskBuildMask
106  *
107  ***********************************************************************
108  */
109 char *
MaskBuildMask(unsigned long ulMask,int iType,char * pcError)110 MaskBuildMask(unsigned long ulMask, int iType, char *pcError)
111 {
112   const char          acRoutine[] = "MaskBuildMask()";
113   char               *pcMask = NULL;
114   int                 i = 0;
115   int                 iCount = 0;
116   int                 iIndex = 0;
117   int                 iMaskSize = 0;
118   int                 iMaskTableLength = MaskGetTableLength(iType);
119   int                 iNLeft = 0;
120   MASK_B2S_TABLE     *pasMaskTable = MaskGetTableReference(iType);
121   unsigned long       ulTestBit = 0;
122 
123   /*-
124    *********************************************************************
125    *
126    * Determine what type of mask we're dealing with.
127    *
128    *********************************************************************
129    */
130   switch (iType)
131   {
132   case MASK_RUNMODE_TYPE_CMP:
133   case MASK_RUNMODE_TYPE_DIG:
134   case MASK_RUNMODE_TYPE_MAP:
135     break;
136   default:
137     snprintf(pcError, MESSAGE_SIZE, "%s: Invalid type [%d]. That shouldn't happen.", acRoutine, iType);
138     return NULL;
139     break;
140   }
141 
142   /*-
143    *********************************************************************
144    *
145    * Allocate enough memory to hold the mask converted into a string.
146    * The caller is expected to free this memory.
147    *
148    *********************************************************************
149    */
150   iMaskSize = iNLeft = strlen("none") + ((strlen("+") + MASK_NAME_SIZE) * iMaskTableLength) + 1;
151   pcMask = calloc(iMaskSize, 1);
152   if (pcMask == NULL)
153   {
154     snprintf(pcError, MESSAGE_SIZE, "%s: calloc(): %s", acRoutine, strerror(errno));
155     return NULL;
156   }
157 
158   /*-
159    *********************************************************************
160    *
161    * Start with the mask's anchor.
162    *
163    *********************************************************************
164    */
165   iCount = snprintf(&pcMask[iIndex], iNLeft, "none");
166   iIndex += iCount;
167   iNLeft -= iCount;
168 
169   /*-
170    *********************************************************************
171    *
172    * Loop through the mask table adding a name only when the number of
173    * bits to set is greater than zero. If the number is zero, it means
174    * the field is (effectively) private.
175    *
176    *********************************************************************
177    */
178   for (i = 0; i < iMaskTableLength; i++)
179   {
180     ulTestBit = 1 << i;
181     if (MASK_BIT_IS_SET(ulMask, ulTestBit) && pasMaskTable[i].iBits2Set > 0)
182     {
183       iCount = snprintf(&pcMask[iIndex], iNLeft, "+%s", pasMaskTable[i].acName);
184       iIndex += iCount;
185       iNLeft -= iCount;
186     }
187   }
188 
189   return pcMask;
190 }
191 
192 /*-
193  ***********************************************************************
194  *
195  * MaskFreeMask
196  *
197  ***********************************************************************
198  */
199 void
MaskFreeMask(MASK_USS_MASK * psMask)200 MaskFreeMask(MASK_USS_MASK *psMask)
201 {
202   if (psMask != NULL)
203   {
204     if (psMask->pcMask != NULL)
205     {
206       free(psMask->pcMask);
207     }
208     free(psMask);
209   }
210 }
211 
212 
213 /*-
214  ***********************************************************************
215  *
216  * MaskGetTableLength
217  *
218  ***********************************************************************
219  */
220 int
MaskGetTableLength(int iType)221 MaskGetTableLength(int iType)
222 {
223   switch (iType)
224   {
225   case MASK_RUNMODE_TYPE_CMP:
226     return (sizeof(gasCmpMaskTable) / sizeof(gasCmpMaskTable[0]));
227     break;
228   case MASK_RUNMODE_TYPE_DIG:
229     return 0;
230     break;
231   case MASK_RUNMODE_TYPE_MAP:
232     return (sizeof(gasMapMaskTable) / sizeof(gasMapMaskTable[0]));
233     break;
234   default:
235     return 0;
236     break;
237   }
238 }
239 
240 
241 /*-
242  ***********************************************************************
243  *
244  * MaskGetTableReference
245  *
246  ***********************************************************************
247  */
248 MASK_B2S_TABLE *
MaskGetTableReference(int iType)249 MaskGetTableReference(int iType)
250 {
251   switch (iType)
252   {
253   case MASK_RUNMODE_TYPE_CMP:
254     return gasCmpMaskTable;
255     break;
256   case MASK_RUNMODE_TYPE_DIG:
257     return NULL;
258     break;
259   case MASK_RUNMODE_TYPE_MAP:
260     return gasMapMaskTable;
261     break;
262   default:
263     return NULL;
264     break;
265   }
266 }
267 
268 
269 /*-
270  ***********************************************************************
271  *
272  * MaskNewMask
273  *
274  ***********************************************************************
275  */
276 MASK_USS_MASK *
MaskNewMask(char * pcError)277 MaskNewMask(char *pcError)
278 {
279   const char          acRoutine[] = "MaskNewMask()";
280   MASK_USS_MASK      *psMask = NULL;
281 
282   /*-
283    *********************************************************************
284    *
285    * The caller is expected to free this memory.
286    *
287    *********************************************************************
288    */
289   psMask = (MASK_USS_MASK *) calloc(sizeof(MASK_USS_MASK), 1);
290   if (psMask == NULL)
291   {
292     snprintf(pcError, MESSAGE_SIZE, "%s: calloc(): %s", acRoutine, strerror(errno));
293     return NULL;
294   }
295 
296   return psMask;
297 }
298 
299 
300 /*-
301  ***********************************************************************
302  *
303  * MaskParseMask
304  *
305  ***********************************************************************
306  */
307 MASK_USS_MASK *
MaskParseMask(char * pcMask,int iType,char * pcError)308 MaskParseMask(char *pcMask, int iType, char *pcError)
309 {
310   const char          acRoutine[] = "MaskParseMask()";
311   char                acLocalError[MESSAGE_SIZE] = "";
312   char                cLastAction = 0;
313   char                cNextAction = 0;
314   char               *pcTemp = NULL;
315   char               *pcTempLine = NULL;
316   char               *pcToken = NULL;
317   int                 i = 0;
318   int                 j = 0;
319   int                 iDone = 0;
320   int                 iError = 0;
321   int                 iLength = strlen(pcMask);
322   int                 iMaskTableLength = MaskGetTableLength(iType);
323   int                 iOffset = 0;
324   MASK_B2S_TABLE     *pasMaskTable = MaskGetTableReference(iType);
325   MASK_USS_MASK      *psMask = NULL;
326   unsigned long       ulAllMask = 0;
327 
328   /*-
329    *********************************************************************
330    *
331    * Sanity check the type and intialize variables.
332    *
333    *********************************************************************
334    */
335   switch (iType)
336   {
337   case MASK_RUNMODE_TYPE_CMP:
338     ulAllMask = CMP_ALL_MASK;
339     break;
340   case MASK_RUNMODE_TYPE_DIG:
341     ulAllMask = DIG_ALL_MASK;
342     break;
343   case MASK_RUNMODE_TYPE_MAP:
344     ulAllMask = MAP_ALL_MASK;
345     break;
346   default:
347     snprintf(pcError, MESSAGE_SIZE, "%s: Invalid type [%d]. That shouldn't happen.", acRoutine, iType);
348     return NULL;
349     break;
350   }
351 
352   /*-
353    *********************************************************************
354    *
355    * Allocate and initialize memory for the mask.
356    *
357    *********************************************************************
358    */
359   psMask = MaskNewMask(acLocalError);
360   if (psMask == NULL)
361   {
362     snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
363     return NULL;
364   }
365 
366   /*-
367    *********************************************************************
368    *
369    * Set the user-supplied string mask.
370    *
371    *********************************************************************
372    */
373   iError = MaskSetMask(psMask, pcMask, acLocalError);
374   if (iError != ER_OK)
375   {
376     snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
377     MaskFreeMask(psMask);
378     return NULL;
379   }
380 
381   /*-
382    *********************************************************************
383    *
384    * Check that the mask begins with a valid anchor.
385    *
386    *********************************************************************
387    */
388   if (strncasecmp(pcMask, "all", 3) == 0)
389   {
390     psMask->ulMask = ~0;
391     iLength = 3;
392   }
393   else if (strncasecmp(pcMask, "none", 4) == 0)
394   {
395     psMask->ulMask = 0;
396     iLength = 4;
397   }
398   else
399   {
400     snprintf(pcError, MESSAGE_SIZE, "%s: Prefix = [%s] != [all|none]: Invalid prefix.", acRoutine, pcMask);
401     MaskFreeMask(psMask);
402     return NULL;
403   }
404 
405   /*-
406    *********************************************************************
407    *
408    * Continue parsing the mask. If there are no more fields, we're done.
409    *
410    *********************************************************************
411    */
412   switch (pcMask[iLength])
413   {
414   case '+':
415   case '-':
416     cLastAction = '?';
417     cNextAction = pcMask[iLength++];
418     break;
419   case 0:
420     psMask->ulMask &= ulAllMask;
421     return psMask;
422     break;
423   default:
424     snprintf(pcError, MESSAGE_SIZE, "%s: Operator = [%c] != [+|-]: Invalid operator.", acRoutine, pcMask[iLength]);
425     MaskFreeMask(psMask);
426     return NULL;
427     break;
428   }
429 
430   /*-
431    *********************************************************************
432    *
433    * Copy the remainder of the input to a scratch pad.
434    *
435    *********************************************************************
436    */
437   pcTemp = &pcMask[iLength];
438   iLength = strlen(pcTemp); /* Calculate new length. */
439   pcTempLine = calloc(iLength + 1, 1);
440   if (pcTempLine == NULL)
441   {
442     snprintf(pcError, MESSAGE_SIZE, "%s: calloc(): %s", acRoutine, strerror(errno));
443     MaskFreeMask(psMask);
444     return NULL;
445   }
446   strncpy(pcTempLine, pcTemp, iLength + 1);
447 
448   /*-
449    *********************************************************************
450    *
451    * Remove EOL characters.
452    *
453    *********************************************************************
454    */
455   SupportChopEOLs(pcTempLine, 0, NULL);
456 
457   /*-
458    *********************************************************************
459    *
460    * Scan through the string looking for tokens delimited by '+', '-',
461    * or 0.
462    *
463    *********************************************************************
464    */
465   for (pcToken = pcTempLine, iOffset = 0, iDone = 0; !iDone;)
466   {
467     if (pcTempLine[iOffset] == '+' || pcTempLine[iOffset] == '-' || pcTempLine[iOffset] == 0)
468     {
469       if (pcTempLine[iOffset] == 0)
470       {
471         iDone = 1;
472       }
473 
474       /*-
475        *****************************************************************
476        *
477        * Update the action values.
478        *
479        *****************************************************************
480        */
481       cLastAction = cNextAction;
482       cNextAction = pcTempLine[iOffset];
483 
484       /*-
485        *****************************************************************
486        *
487        * Terminate the token.
488        *
489        *****************************************************************
490        */
491       pcTempLine[iOffset] = 0;
492 
493       /*-
494        *****************************************************************
495        *
496        * Scan the table looking for this token. Add or subtract the
497        * expanded token value (i.e., the time tokens count for more
498        * than one mask bit each) from the mask depending on whether
499        * '+' or '-' was given.
500        *
501        *****************************************************************
502        */
503       for (i = 0; i < iMaskTableLength; i++)
504       {
505         if (strcasecmp(pcToken, pasMaskTable[i].acName) == 0 && pasMaskTable[i].iBits2Set > 0)
506         {
507           for (j = 0; j < pasMaskTable[i].iBits2Set; j++)
508           {
509             PUTBIT(psMask->ulMask, ((cLastAction == '+') ? 1 : 0), (i + j));
510           }
511           break;
512         }
513       }
514       if (i == iMaskTableLength)
515       {
516         /*-
517          ***************************************************************
518          *
519          * Check to see if this is a group field before aborting.
520          *
521          ***************************************************************
522          */
523         if (strcasecmp(pcToken, "hashes") == 0 && (iType == MASK_RUNMODE_TYPE_CMP || iType == MASK_RUNMODE_TYPE_MAP))
524         {
525           if (cLastAction == '+')
526           {
527             psMask->ulMask |= (iType == MASK_RUNMODE_TYPE_CMP) ? CMP_HASHES_MASK : MAP_HASHES_MASK;
528           }
529           else
530           {
531             psMask->ulMask &= (iType == MASK_RUNMODE_TYPE_CMP) ? ~CMP_HASHES_MASK : ~MAP_HASHES_MASK;
532           }
533         }
534         else if (strcasecmp(pcToken, "times") == 0 && (iType == MASK_RUNMODE_TYPE_CMP || iType == MASK_RUNMODE_TYPE_MAP))
535         {
536           if (cLastAction == '+')
537           {
538             psMask->ulMask |= (iType == MASK_RUNMODE_TYPE_CMP) ? CMP_TIMES_MASK : MAP_TIMES_MASK;
539           }
540           else
541           {
542             psMask->ulMask &= (iType == MASK_RUNMODE_TYPE_CMP) ? ~CMP_TIMES_MASK : ~MAP_TIMES_MASK;
543           }
544         }
545         else
546         {
547           snprintf(pcError, MESSAGE_SIZE, "%s: Token = [%c%s]: Invalid value.", acRoutine, cLastAction, pcToken);
548           MaskFreeMask(psMask);
549           return NULL;
550         }
551       }
552       if (!iDone)
553       {
554         iOffset++;
555         pcToken = &pcTempLine[iOffset];
556       }
557     }
558     else
559     {
560       iOffset++;
561     }
562   }
563 
564   /*-
565    *********************************************************************
566    *
567    * Remove any extra bits, and send it back to the caller.
568    *
569    *********************************************************************
570    */
571   psMask->ulMask &= ulAllMask;
572 
573   return psMask;
574 }
575 
576 
577 /*-
578  ***********************************************************************
579  *
580  * MaskSetDynamicString
581  *
582  ***********************************************************************
583  */
584 int
MaskSetDynamicString(char ** ppcValue,char * pcNewValue,char * pcError)585 MaskSetDynamicString(char **ppcValue, char *pcNewValue, char *pcError)
586 {
587   const char          acRoutine[] = "MaskSetDynamicString()";
588   char               *pcTempValue = NULL;
589   int                 iLength = 0;
590 
591   /*-
592    *********************************************************************
593    *
594    * Allocate additional memory as required. Preserve the user-supplied
595    * pointer in case the operation fails. Then, copy the new value into
596    * place. The caller is expected to free this memory.
597    *
598    *********************************************************************
599    */
600   iLength = strlen(pcNewValue);
601   pcTempValue = realloc(*ppcValue, iLength + 1);
602   if (pcTempValue == NULL)
603   {
604     snprintf(pcError, MESSAGE_SIZE, "%s: realloc(): %s", acRoutine, strerror(errno));
605     return ER;
606   }
607   strncpy(pcTempValue, pcNewValue, iLength + 1);
608   *ppcValue = pcTempValue;
609 
610   return ER_OK;
611 }
612 
613 
614 /*-
615  ***********************************************************************
616  *
617  * MaskSetMask
618  *
619  ***********************************************************************
620  */
621 int
MaskSetMask(MASK_USS_MASK * psMask,char * pcMask,char * pcError)622 MaskSetMask(MASK_USS_MASK *psMask, char *pcMask, char *pcError)
623 {
624   const char          acRoutine[] = "MaskSetMask()";
625   char                acLocalError[MESSAGE_SIZE] = "";
626   int                 iError = 0;
627 
628   if (psMask == NULL)
629   {
630     snprintf(pcError, MESSAGE_SIZE, "%s: Undefined mask.", acRoutine);
631     return ER;
632   }
633 
634   iError = MaskSetDynamicString(&psMask->pcMask, pcMask, acLocalError);
635   if (iError == ER)
636   {
637     snprintf(pcError, MESSAGE_SIZE, "%s: %s", acRoutine, acLocalError);
638     return ER;
639   }
640 
641   return ER_OK;
642 }
643