Home | History | Annotate | Download | only in MagickCore
      1 /*
      2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      3 %                                                                             %
      4 %                                                                             %
      5 %                  PPPP    OOO   L      IIIII   CCCC  Y   Y                   %
      6 %                  P   P  O   O  L        I    C       Y Y                    %
      7 %                  PPPP   O   O  L        I    C        Y                     %
      8 %                  P      O   O  L        I    C        Y                     %
      9 %                  P       OOO   LLLLL  IIIII   CCCC    Y                     %
     10 %                                                                             %
     11 %                                                                             %
     12 %                         MagickCore Policy Methods                           %
     13 %                                                                             %
     14 %                              Software Design                                %
     15 %                                   Cristy                                    %
     16 %                                 July 1992                                   %
     17 %                                                                             %
     18 %                                                                             %
     19 %  Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization      %
     20 %  dedicated to making software imaging solutions freely available.           %
     21 %                                                                             %
     22 %  You may not use this file except in compliance with the License.  You may  %
     23 %  obtain a copy of the License at                                            %
     24 %                                                                             %
     25 %    http://www.imagemagick.org/script/license.php                            %
     26 %                                                                             %
     27 %  Unless required by applicable law or agreed to in writing, software        %
     28 %  distributed under the License is distributed on an "AS IS" BASIS,          %
     29 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
     30 %  See the License for the specific language governing permissions and        %
     31 %  limitations under the License.                                             %
     32 %                                                                             %
     33 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     34 %
     35 %  We use linked-lists because splay-trees do not currently support duplicate
     36 %  key / value pairs (.e.g X11 green compliance and SVG green compliance).
     37 %
     38 */
     39 
     40 /*
     42   Include declarations.
     43 */
     44 #include "MagickCore/studio.h"
     45 #include "MagickCore/client.h"
     46 #include "MagickCore/configure.h"
     47 #include "MagickCore/configure-private.h"
     48 #include "MagickCore/exception.h"
     49 #include "MagickCore/exception-private.h"
     50 #include "MagickCore/memory_.h"
     51 #include "MagickCore/monitor.h"
     52 #include "MagickCore/monitor-private.h"
     53 #include "MagickCore/option.h"
     54 #include "MagickCore/policy.h"
     55 #include "MagickCore/policy-private.h"
     56 #include "MagickCore/semaphore.h"
     57 #include "MagickCore/string_.h"
     58 #include "MagickCore/token.h"
     59 #include "MagickCore/utility.h"
     60 #include "MagickCore/utility-private.h"
     61 #include "MagickCore/xml-tree.h"
     62 #include "MagickCore/xml-tree-private.h"
     63 
     64 /*
     66   Define declarations.
     67 */
     68 #define PolicyFilename  "policy.xml"
     69 
     70 /*
     72   Typedef declarations.
     73 */
     74 struct _PolicyInfo
     75 {
     76   char
     77     *path;
     78 
     79   PolicyDomain
     80     domain;
     81 
     82   PolicyRights
     83     rights;
     84 
     85   char
     86     *name,
     87     *pattern,
     88     *value;
     89 
     90   MagickBooleanType
     91     exempt,
     92     stealth,
     93     debug;
     94 
     95   SemaphoreInfo
     96     *semaphore;
     97 
     98   size_t
     99     signature;
    100 };
    101 
    102 typedef struct _PolicyMapInfo
    103 {
    104   const PolicyDomain
    105     domain;
    106 
    107   const PolicyRights
    108     rights;
    109 
    110   const char
    111     *name,
    112     *pattern,
    113     *value;
    114 } PolicyMapInfo;
    115 
    116 /*
    118   Static declarations.
    119 */
    120 static const PolicyMapInfo
    121   PolicyMap[] =
    122   {
    123     { UndefinedPolicyDomain, UndefinedPolicyRights, (const char *) NULL,
    124       (const char *) NULL, (const char *) NULL }
    125   };
    126 
    127 static LinkedListInfo
    128   *policy_cache = (LinkedListInfo *) NULL;
    129 
    130 static SemaphoreInfo
    131   *policy_semaphore = (SemaphoreInfo *) NULL;
    132 
    133 /*
    135   Forward declarations.
    136 */
    137 static MagickBooleanType
    138   IsPolicyCacheInstantiated(ExceptionInfo *),
    139   LoadPolicyCache(LinkedListInfo *,const char *,const char *,const size_t,
    140     ExceptionInfo *);
    141 
    142 /*
    144 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    145 %                                                                             %
    146 %                                                                             %
    147 %                                                                             %
    148 %  A c q u i r e P o l i c y C a c h e                                        %
    149 %                                                                             %
    150 %                                                                             %
    151 %                                                                             %
    152 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    153 %
    154 %  AcquirePolicyCache() caches one or more policy configurations which provides
    155 %  a mapping between policy attributes and a policy name.
    156 %
    157 %  The format of the AcquirePolicyCache method is:
    158 %
    159 %      LinkedListInfo *AcquirePolicyCache(const char *filename,
    160 %        ExceptionInfo *exception)
    161 %
    162 %  A description of each parameter follows:
    163 %
    164 %    o filename: the font file name.
    165 %
    166 %    o exception: return any errors or warnings in this structure.
    167 %
    168 */
    169 static LinkedListInfo *AcquirePolicyCache(const char *filename,
    170   ExceptionInfo *exception)
    171 {
    172   LinkedListInfo
    173     *cache;
    174 
    175   MagickStatusType
    176     status;
    177 
    178   register ssize_t
    179     i;
    180 
    181   /*
    182     Load external policy map.
    183   */
    184   cache=NewLinkedList(0);
    185   if (cache == (LinkedListInfo *) NULL)
    186     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
    187   status=MagickTrue;
    188 #if !defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT)
    189   {
    190     const StringInfo
    191       *option;
    192 
    193     LinkedListInfo
    194       *options;
    195 
    196     options=GetConfigureOptions(filename,exception);
    197     option=(const StringInfo *) GetNextValueInLinkedList(options);
    198     while (option != (const StringInfo *) NULL)
    199     {
    200       status&=LoadPolicyCache(cache,(const char *)
    201         GetStringInfoDatum(option),GetStringInfoPath(option),0,exception);
    202       option=(const StringInfo *) GetNextValueInLinkedList(options);
    203     }
    204     options=DestroyConfigureOptions(options);
    205   }
    206 #endif
    207   /*
    208     Load built-in policy map.
    209   */
    210   for (i=0; i < (ssize_t) (sizeof(PolicyMap)/sizeof(*PolicyMap)); i++)
    211   {
    212     PolicyInfo
    213       *policy_info;
    214 
    215     register const PolicyMapInfo
    216       *p;
    217 
    218     p=PolicyMap+i;
    219     policy_info=(PolicyInfo *) AcquireMagickMemory(sizeof(*policy_info));
    220     if (policy_info == (PolicyInfo *) NULL)
    221       {
    222         (void) ThrowMagickException(exception,GetMagickModule(),
    223           ResourceLimitError,"MemoryAllocationFailed","`%s'",p->name);
    224         continue;
    225       }
    226     (void) ResetMagickMemory(policy_info,0,sizeof(*policy_info));
    227     policy_info->path=(char *) "[built-in]";
    228     policy_info->domain=p->domain;
    229     policy_info->rights=p->rights;
    230     policy_info->name=(char *) p->name;
    231     policy_info->pattern=(char *) p->pattern;
    232     policy_info->value=(char *) p->value;
    233     policy_info->exempt=MagickTrue;
    234     policy_info->signature=MagickCoreSignature;
    235     status&=AppendValueToLinkedList(cache,policy_info);
    236     if (status == MagickFalse)
    237       (void) ThrowMagickException(exception,GetMagickModule(),
    238         ResourceLimitError,"MemoryAllocationFailed","`%s'",policy_info->name);
    239   }
    240   return(cache);
    241 }
    242 
    243 /*
    245 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    246 %                                                                             %
    247 %                                                                             %
    248 %                                                                             %
    249 +   G e t P o l i c y I n f o                                                 %
    250 %                                                                             %
    251 %                                                                             %
    252 %                                                                             %
    253 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    254 %
    255 %  GetPolicyInfo() searches the policy list for the specified name and if found
    256 %  returns attributes for that policy.
    257 %
    258 %  The format of the GetPolicyInfo method is:
    259 %
    260 %      PolicyInfo *GetPolicyInfo(const char *name,ExceptionInfo *exception)
    261 %
    262 %  A description of each parameter follows:
    263 %
    264 %    o name: the policy name.
    265 %
    266 %    o exception: return any errors or warnings in this structure.
    267 %
    268 */
    269 static PolicyInfo *GetPolicyInfo(const char *name,ExceptionInfo *exception)
    270 {
    271   char
    272     policyname[MagickPathExtent];
    273 
    274   register PolicyInfo
    275     *p;
    276 
    277   register char
    278     *q;
    279 
    280   assert(exception != (ExceptionInfo *) NULL);
    281   if (IsPolicyCacheInstantiated(exception) == MagickFalse)
    282     return((PolicyInfo *) NULL);
    283   /*
    284     Strip names of whitespace.
    285   */
    286   *policyname='\0';
    287   if (name != (const char *) NULL)
    288     (void) CopyMagickString(policyname,name,MagickPathExtent);
    289   for (q=policyname; *q != '\0'; q++)
    290   {
    291     if (isspace((int) ((unsigned char) *q)) == 0)
    292       continue;
    293     (void) CopyMagickString(q,q+1,MagickPathExtent);
    294     q--;
    295   }
    296   /*
    297     Search for policy tag.
    298   */
    299   LockSemaphoreInfo(policy_semaphore);
    300   ResetLinkedListIterator(policy_cache);
    301   p=(PolicyInfo *) GetNextValueInLinkedList(policy_cache);
    302   if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
    303     {
    304       UnlockSemaphoreInfo(policy_semaphore);
    305       return(p);
    306     }
    307   while (p != (PolicyInfo *) NULL)
    308   {
    309     if (LocaleCompare(policyname,p->name) == 0)
    310       break;
    311     p=(PolicyInfo *) GetNextValueInLinkedList(policy_cache);
    312   }
    313   if (p != (PolicyInfo *) NULL)
    314     (void) InsertValueInLinkedList(policy_cache,0,
    315       RemoveElementByValueFromLinkedList(policy_cache,p));
    316   UnlockSemaphoreInfo(policy_semaphore);
    317   return(p);
    318 }
    319 
    320 /*
    322 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    323 %                                                                             %
    324 %                                                                             %
    325 %                                                                             %
    326 %   G e t P o l i c y I n f o L i s t                                         %
    327 %                                                                             %
    328 %                                                                             %
    329 %                                                                             %
    330 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    331 %
    332 %  GetPolicyInfoList() returns any policies that match the specified pattern.
    333 %
    334 %  The format of the GetPolicyInfoList function is:
    335 %
    336 %      const PolicyInfo **GetPolicyInfoList(const char *pattern,
    337 %        size_t *number_policies,ExceptionInfo *exception)
    338 %
    339 %  A description of each parameter follows:
    340 %
    341 %    o pattern: Specifies a pointer to a text string containing a pattern.
    342 %
    343 %    o number_policies:  returns the number of policies in the list.
    344 %
    345 %    o exception: return any errors or warnings in this structure.
    346 %
    347 */
    348 MagickExport const PolicyInfo **GetPolicyInfoList(const char *pattern,
    349   size_t *number_policies,ExceptionInfo *exception)
    350 {
    351   const PolicyInfo
    352     **policies;
    353 
    354   register const PolicyInfo
    355     *p;
    356 
    357   register ssize_t
    358     i;
    359 
    360   /*
    361     Allocate policy list.
    362   */
    363   assert(pattern != (char *) NULL);
    364   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
    365   assert(number_policies != (size_t *) NULL);
    366   *number_policies=0;
    367   p=GetPolicyInfo("*",exception);
    368   if (p == (const PolicyInfo *) NULL)
    369     return((const PolicyInfo **) NULL);
    370   policies=(const PolicyInfo **) AcquireQuantumMemory((size_t)
    371     GetNumberOfElementsInLinkedList(policy_cache)+1UL,sizeof(*policies));
    372   if (policies == (const PolicyInfo **) NULL)
    373     return((const PolicyInfo **) NULL);
    374   /*
    375     Generate policy list.
    376   */
    377   LockSemaphoreInfo(policy_semaphore);
    378   ResetLinkedListIterator(policy_cache);
    379   p=(const PolicyInfo *) GetNextValueInLinkedList(policy_cache);
    380   for (i=0; p != (const PolicyInfo *) NULL; )
    381   {
    382     if ((p->stealth == MagickFalse) &&
    383         (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
    384       policies[i++]=p;
    385     p=(const PolicyInfo *) GetNextValueInLinkedList(policy_cache);
    386   }
    387   UnlockSemaphoreInfo(policy_semaphore);
    388   policies[i]=(PolicyInfo *) NULL;
    389   *number_policies=(size_t) i;
    390   return(policies);
    391 }
    392 
    393 /*
    395 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    396 %                                                                             %
    397 %                                                                             %
    398 %                                                                             %
    399 %   G e t P o l i c y L i s t                                                 %
    400 %                                                                             %
    401 %                                                                             %
    402 %                                                                             %
    403 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    404 %
    405 %  GetPolicyList() returns any policies that match the specified pattern.
    406 %
    407 %  The format of the GetPolicyList function is:
    408 %
    409 %      char **GetPolicyList(const char *pattern,size_t *number_policies,
    410 %        ExceptionInfo *exception)
    411 %
    412 %  A description of each parameter follows:
    413 %
    414 %    o pattern: a pointer to a text string containing a pattern.
    415 %
    416 %    o number_policies:  returns the number of policies in the list.
    417 %
    418 %    o exception: return any errors or warnings in this structure.
    419 %
    420 */
    421 MagickExport char **GetPolicyList(const char *pattern,
    422   size_t *number_policies,ExceptionInfo *exception)
    423 {
    424   char
    425     **policies;
    426 
    427   register const PolicyInfo
    428     *p;
    429 
    430   register ssize_t
    431     i;
    432 
    433   /*
    434     Allocate policy list.
    435   */
    436   assert(pattern != (char *) NULL);
    437   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
    438   assert(number_policies != (size_t *) NULL);
    439   *number_policies=0;
    440   p=GetPolicyInfo("*",exception);
    441   if (p == (const PolicyInfo *) NULL)
    442     return((char **) NULL);
    443   policies=(char **) AcquireQuantumMemory((size_t)
    444     GetNumberOfElementsInLinkedList(policy_cache)+1UL,sizeof(*policies));
    445   if (policies == (char **) NULL)
    446     return((char **) NULL);
    447   /*
    448     Generate policy list.
    449   */
    450   LockSemaphoreInfo(policy_semaphore);
    451   ResetLinkedListIterator(policy_cache);
    452   p=(const PolicyInfo *) GetNextValueInLinkedList(policy_cache);
    453   for (i=0; p != (const PolicyInfo *) NULL; )
    454   {
    455     if ((p->stealth == MagickFalse) &&
    456         (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
    457       policies[i++]=ConstantString(p->name);
    458     p=(const PolicyInfo *) GetNextValueInLinkedList(policy_cache);
    459   }
    460   UnlockSemaphoreInfo(policy_semaphore);
    461   policies[i]=(char *) NULL;
    462   *number_policies=(size_t) i;
    463   return(policies);
    464 }
    465 
    466 /*
    468 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    469 %                                                                             %
    470 %                                                                             %
    471 %                                                                             %
    472 %   G e t P o l i c y V a l u e                                               %
    473 %                                                                             %
    474 %                                                                             %
    475 %                                                                             %
    476 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    477 %
    478 %  GetPolicyValue() returns the value associated with the named policy.
    479 %
    480 %  The format of the GetPolicyValue method is:
    481 %
    482 %      char *GetPolicyValue(const char *name)
    483 %
    484 %  A description of each parameter follows:
    485 %
    486 %    o policy_info:  The policy info.
    487 %
    488 */
    489 MagickExport char *GetPolicyValue(const char *name)
    490 {
    491   const char
    492     *value;
    493 
    494   const PolicyInfo
    495     *policy_info;
    496 
    497   ExceptionInfo
    498     *exception;
    499 
    500   assert(name != (const char *) NULL);
    501   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",name);
    502   exception=AcquireExceptionInfo();
    503   policy_info=GetPolicyInfo(name,exception);
    504   exception=DestroyExceptionInfo(exception);
    505   if (policy_info == (PolicyInfo *) NULL)
    506     return((char *) NULL);
    507   value=policy_info->value;
    508   if ((value == (const char *) NULL) || (*value == '\0'))
    509     return((char *) NULL);
    510   return(ConstantString(value));
    511 }
    512 
    513 /*
    515 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    516 %                                                                             %
    517 %                                                                             %
    518 %                                                                             %
    519 +   I s P o l i c y C a c h e I n s t a n t i a t e d                         %
    520 %                                                                             %
    521 %                                                                             %
    522 %                                                                             %
    523 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    524 %
    525 %  IsPolicyCacheInstantiated() determines if the policy list is instantiated.
    526 %  If not, it instantiates the list and returns it.
    527 %
    528 %  The format of the IsPolicyInstantiated method is:
    529 %
    530 %      MagickBooleanType IsPolicyCacheInstantiated(ExceptionInfo *exception)
    531 %
    532 %  A description of each parameter follows.
    533 %
    534 %    o exception: return any errors or warnings in this structure.
    535 %
    536 */
    537 static MagickBooleanType IsPolicyCacheInstantiated(ExceptionInfo *exception)
    538 {
    539   if (policy_cache == (LinkedListInfo *) NULL)
    540     {
    541       if (policy_semaphore == (SemaphoreInfo *) NULL)
    542         ActivateSemaphoreInfo(&policy_semaphore);
    543       LockSemaphoreInfo(policy_semaphore);
    544       if (policy_cache == (LinkedListInfo *) NULL)
    545         policy_cache=AcquirePolicyCache(PolicyFilename,exception);
    546       UnlockSemaphoreInfo(policy_semaphore);
    547     }
    548   return(policy_cache != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
    549 }
    550 
    551 /*
    553 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    554 %                                                                             %
    555 %                                                                             %
    556 %                                                                             %
    557 %   I s R i g h t s A u t h o r i z e d                                       %
    558 %                                                                             %
    559 %                                                                             %
    560 %                                                                             %
    561 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    562 %
    563 %  IsRightsAuthorized() returns MagickTrue if the policy authorizes the
    564 %  requested rights for the specified domain.
    565 %
    566 %  The format of the IsRightsAuthorized method is:
    567 %
    568 %      MagickBooleanType IsRightsAuthorized(const PolicyDomain domain,
    569 %        const PolicyRights rights,const char *pattern)
    570 %
    571 %  A description of each parameter follows:
    572 %
    573 %    o domain: the policy domain.
    574 %
    575 %    o rights: the policy rights.
    576 %
    577 %    o pattern: the coder, delegate, filter, or path pattern.
    578 %
    579 */
    580 MagickExport MagickBooleanType IsRightsAuthorized(const PolicyDomain domain,
    581   const PolicyRights rights,const char *pattern)
    582 {
    583   const PolicyInfo
    584     *policy_info;
    585 
    586   ExceptionInfo
    587     *exception;
    588 
    589   MagickBooleanType
    590     authorized;
    591 
    592   register PolicyInfo
    593     *p;
    594 
    595   (void) LogMagickEvent(PolicyEvent,GetMagickModule(),
    596     "Domain: %s; rights=%s; pattern=\"%s\" ...",
    597     CommandOptionToMnemonic(MagickPolicyDomainOptions,domain),
    598     CommandOptionToMnemonic(MagickPolicyRightsOptions,rights),pattern);
    599   exception=AcquireExceptionInfo();
    600   policy_info=GetPolicyInfo("*",exception);
    601   exception=DestroyExceptionInfo(exception);
    602   if (policy_info == (PolicyInfo *) NULL)
    603     return(MagickTrue);
    604   authorized=MagickTrue;
    605   LockSemaphoreInfo(policy_semaphore);
    606   ResetLinkedListIterator(policy_cache);
    607   p=(PolicyInfo *) GetNextValueInLinkedList(policy_cache);
    608   while ((p != (PolicyInfo *) NULL) && (authorized != MagickFalse))
    609   {
    610     if ((p->domain == domain) &&
    611         (GlobExpression(pattern,p->pattern,MagickFalse) != MagickFalse))
    612       {
    613         if (((rights & ReadPolicyRights) != 0) &&
    614             ((p->rights & ReadPolicyRights) == 0))
    615           authorized=MagickFalse;
    616         if (((rights & WritePolicyRights) != 0) &&
    617             ((p->rights & WritePolicyRights) == 0))
    618           authorized=MagickFalse;
    619         if (((rights & ExecutePolicyRights) != 0) &&
    620             ((p->rights & ExecutePolicyRights) == 0))
    621           authorized=MagickFalse;
    622       }
    623     p=(PolicyInfo *) GetNextValueInLinkedList(policy_cache);
    624   }
    625   UnlockSemaphoreInfo(policy_semaphore);
    626   return(authorized);
    627 }
    628 
    629 /*
    631 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    632 %                                                                             %
    633 %                                                                             %
    634 %                                                                             %
    635 %  L i s t P o l i c y I n f o                                                %
    636 %                                                                             %
    637 %                                                                             %
    638 %                                                                             %
    639 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    640 %
    641 %  ListPolicyInfo() lists policies to the specified file.
    642 %
    643 %  The format of the ListPolicyInfo method is:
    644 %
    645 %      MagickBooleanType ListPolicyInfo(FILE *file,ExceptionInfo *exception)
    646 %
    647 %  A description of each parameter follows.
    648 %
    649 %    o file:  List policy names to this file handle.
    650 %
    651 %    o exception: return any errors or warnings in this structure.
    652 %
    653 */
    654 MagickExport MagickBooleanType ListPolicyInfo(FILE *file,
    655   ExceptionInfo *exception)
    656 {
    657   const char
    658     *path,
    659     *domain;
    660 
    661   const PolicyInfo
    662     **policy_info;
    663 
    664   register ssize_t
    665     i;
    666 
    667   size_t
    668     number_policies;
    669 
    670   /*
    671     List name and attributes of each policy in the list.
    672   */
    673   if (file == (const FILE *) NULL)
    674     file=stdout;
    675   policy_info=GetPolicyInfoList("*",&number_policies,exception);
    676   if (policy_info == (const PolicyInfo **) NULL)
    677     return(MagickFalse);
    678   path=(const char *) NULL;
    679   for (i=0; i < (ssize_t) number_policies; i++)
    680   {
    681     if (policy_info[i]->stealth != MagickFalse)
    682       continue;
    683     if (((path == (const char *) NULL) ||
    684          (LocaleCompare(path,policy_info[i]->path) != 0)) &&
    685          (policy_info[i]->path != (char *) NULL))
    686       (void) FormatLocaleFile(file,"\nPath: %s\n",policy_info[i]->path);
    687     path=policy_info[i]->path;
    688     domain=CommandOptionToMnemonic(MagickPolicyDomainOptions,
    689       policy_info[i]->domain);
    690     (void) FormatLocaleFile(file,"  Policy: %s\n",domain);
    691     if ((policy_info[i]->domain == CachePolicyDomain) ||
    692         (policy_info[i]->domain == ResourcePolicyDomain) ||
    693         (policy_info[i]->domain == SystemPolicyDomain))
    694       {
    695         if (policy_info[i]->name != (char *) NULL)
    696           (void) FormatLocaleFile(file,"    name: %s\n",policy_info[i]->name);
    697         if (policy_info[i]->value != (char *) NULL)
    698           (void) FormatLocaleFile(file,"    value: %s\n",policy_info[i]->value);
    699       }
    700     else
    701       {
    702         (void) FormatLocaleFile(file,"    rights: ");
    703         if (policy_info[i]->rights == NoPolicyRights)
    704           (void) FormatLocaleFile(file,"None ");
    705         if ((policy_info[i]->rights & ReadPolicyRights) != 0)
    706           (void) FormatLocaleFile(file,"Read ");
    707         if ((policy_info[i]->rights & WritePolicyRights) != 0)
    708           (void) FormatLocaleFile(file,"Write ");
    709         if ((policy_info[i]->rights & ExecutePolicyRights) != 0)
    710           (void) FormatLocaleFile(file,"Execute ");
    711         (void) FormatLocaleFile(file,"\n");
    712         if (policy_info[i]->pattern != (char *) NULL)
    713           (void) FormatLocaleFile(file,"    pattern: %s\n",
    714             policy_info[i]->pattern);
    715       }
    716   }
    717   policy_info=(const PolicyInfo **) RelinquishMagickMemory((void *)
    718     policy_info);
    719   (void) fflush(file);
    720   return(MagickTrue);
    721 }
    722 
    723 /*
    725 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    726 %                                                                             %
    727 %                                                                             %
    728 %                                                                             %
    729 +   L o a d P o l i c y C a c h e                                             %
    730 %                                                                             %
    731 %                                                                             %
    732 %                                                                             %
    733 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    734 %
    735 %  LoadPolicyCache() loads the policy configurations which provides a mapping
    736 %  between policy attributes and a policy domain.
    737 %
    738 %  The format of the LoadPolicyCache method is:
    739 %
    740 %      MagickBooleanType LoadPolicyCache(LinkedListInfo *cache,const char *xml,
    741 %        const char *filename,const size_t depth,ExceptionInfo *exception)
    742 %
    743 %  A description of each parameter follows:
    744 %
    745 %    o xml:  The policy list in XML format.
    746 %
    747 %    o filename:  The policy list filename.
    748 %
    749 %    o depth: depth of <include /> statements.
    750 %
    751 %    o exception: return any errors or warnings in this structure.
    752 %
    753 */
    754 static MagickBooleanType LoadPolicyCache(LinkedListInfo *cache,const char *xml,
    755   const char *filename,const size_t depth,ExceptionInfo *exception)
    756 {
    757   char
    758     keyword[MagickPathExtent],
    759     *token;
    760 
    761   const char
    762     *q;
    763 
    764   MagickStatusType
    765     status;
    766 
    767   PolicyInfo
    768     *policy_info;
    769 
    770   size_t
    771     extent;
    772 
    773   /*
    774     Load the policy map file.
    775   */
    776   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
    777     "Loading policy file \"%s\" ...",filename);
    778   if (xml == (char *) NULL)
    779     return(MagickFalse);
    780   status=MagickTrue;
    781   policy_info=(PolicyInfo *) NULL;
    782   token=AcquireString(xml);
    783   extent=strlen(token)+MagickPathExtent;
    784   for (q=(const char *) xml; *q != '\0'; )
    785   {
    786     /*
    787       Interpret XML.
    788     */
    789     GetNextToken(q,&q,extent,token);
    790     if (*token == '\0')
    791       break;
    792     (void) CopyMagickString(keyword,token,MagickPathExtent);
    793     if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
    794       {
    795         /*
    796           Docdomain element.
    797         */
    798         while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
    799           GetNextToken(q,&q,extent,token);
    800         continue;
    801       }
    802     if (LocaleNCompare(keyword,"<!--",4) == 0)
    803       {
    804         /*
    805           Comment element.
    806         */
    807         while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
    808           GetNextToken(q,&q,extent,token);
    809         continue;
    810       }
    811     if (LocaleCompare(keyword,"<include") == 0)
    812       {
    813         /*
    814           Include element.
    815         */
    816         while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
    817         {
    818           (void) CopyMagickString(keyword,token,MagickPathExtent);
    819           GetNextToken(q,&q,extent,token);
    820           if (*token != '=')
    821             continue;
    822           GetNextToken(q,&q,extent,token);
    823           if (LocaleCompare(keyword,"file") == 0)
    824             {
    825               if (depth > 200)
    826                 (void) ThrowMagickException(exception,GetMagickModule(),
    827                   ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
    828               else
    829                 {
    830                   char
    831                     path[MagickPathExtent],
    832                     *file_xml;
    833 
    834                   GetPathComponent(filename,HeadPath,path);
    835                   if (*path != '\0')
    836                     (void) ConcatenateMagickString(path,DirectorySeparator,
    837                       MagickPathExtent);
    838                   if (*token == *DirectorySeparator)
    839                     (void) CopyMagickString(path,token,MagickPathExtent);
    840                   else
    841                     (void) ConcatenateMagickString(path,token,MagickPathExtent);
    842                   file_xml=FileToXML(path,~0UL);
    843                   if (file_xml != (char *) NULL)
    844                     {
    845                       status&=LoadPolicyCache(cache,file_xml,path,
    846                         depth+1,exception);
    847                       file_xml=DestroyString(file_xml);
    848                     }
    849                 }
    850             }
    851         }
    852         continue;
    853       }
    854     if (LocaleCompare(keyword,"<policy") == 0)
    855       {
    856         /*
    857           Policy element.
    858         */
    859         policy_info=(PolicyInfo *) AcquireMagickMemory(sizeof(*policy_info));
    860         if (policy_info == (PolicyInfo *) NULL)
    861           ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
    862         (void) ResetMagickMemory(policy_info,0,sizeof(*policy_info));
    863         policy_info->path=ConstantString(filename);
    864         policy_info->exempt=MagickFalse;
    865         policy_info->signature=MagickCoreSignature;
    866         continue;
    867       }
    868     if (policy_info == (PolicyInfo *) NULL)
    869       continue;
    870     if (LocaleCompare(keyword,"/>") == 0)
    871       {
    872         status=AppendValueToLinkedList(cache,policy_info);
    873         if (status == MagickFalse)
    874           (void) ThrowMagickException(exception,GetMagickModule(),
    875             ResourceLimitError,"MemoryAllocationFailed","`%s'",
    876             policy_info->name);
    877         policy_info=(PolicyInfo *) NULL;
    878         continue;
    879       }
    880     GetNextToken(q,(const char **) NULL,extent,token);
    881     if (*token != '=')
    882       continue;
    883     GetNextToken(q,&q,extent,token);
    884     GetNextToken(q,&q,extent,token);
    885     switch (*keyword)
    886     {
    887       case 'D':
    888       case 'd':
    889       {
    890         if (LocaleCompare((char *) keyword,"domain") == 0)
    891           {
    892             policy_info->domain=(PolicyDomain) ParseCommandOption(
    893               MagickPolicyDomainOptions,MagickTrue,token);
    894             break;
    895           }
    896         break;
    897       }
    898       case 'N':
    899       case 'n':
    900       {
    901         if (LocaleCompare((char *) keyword,"name") == 0)
    902           {
    903             policy_info->name=ConstantString(token);
    904             break;
    905           }
    906         break;
    907       }
    908       case 'P':
    909       case 'p':
    910       {
    911         if (LocaleCompare((char *) keyword,"pattern") == 0)
    912           {
    913             policy_info->pattern=ConstantString(token);
    914             break;
    915           }
    916         break;
    917       }
    918       case 'R':
    919       case 'r':
    920       {
    921         if (LocaleCompare((char *) keyword,"rights") == 0)
    922           {
    923             policy_info->rights=(PolicyRights) ParseCommandOption(
    924               MagickPolicyRightsOptions,MagickTrue,token);
    925             break;
    926           }
    927         break;
    928       }
    929       case 'S':
    930       case 's':
    931       {
    932         if (LocaleCompare((char *) keyword,"stealth") == 0)
    933           {
    934             policy_info->stealth=IsStringTrue(token);
    935             break;
    936           }
    937         break;
    938       }
    939       case 'V':
    940       case 'v':
    941       {
    942         if (LocaleCompare((char *) keyword,"value") == 0)
    943           {
    944             policy_info->value=ConstantString(token);
    945             break;
    946           }
    947         break;
    948       }
    949       default:
    950         break;
    951     }
    952   }
    953   token=(char *) RelinquishMagickMemory(token);
    954   return(status != 0 ? MagickTrue : MagickFalse);
    955 }
    956 
    957 /*
    959 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    960 %                                                                             %
    961 %                                                                             %
    962 %                                                                             %
    963 +   P o l i c y C o m p o n e n t G e n e s i s                               %
    964 %                                                                             %
    965 %                                                                             %
    966 %                                                                             %
    967 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    968 %
    969 %  PolicyComponentGenesis() instantiates the policy component.
    970 %
    971 %  The format of the PolicyComponentGenesis method is:
    972 %
    973 %      MagickBooleanType PolicyComponentGenesis(void)
    974 %
    975 */
    976 MagickPrivate MagickBooleanType PolicyComponentGenesis(void)
    977 {
    978   if (policy_semaphore == (SemaphoreInfo *) NULL)
    979     policy_semaphore=AcquireSemaphoreInfo();
    980   return(MagickTrue);
    981 }
    982 
    983 /*
    985 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    986 %                                                                             %
    987 %                                                                             %
    988 %                                                                             %
    989 +   P o l i c y C o m p o n e n t T e r m i n u s                             %
    990 %                                                                             %
    991 %                                                                             %
    992 %                                                                             %
    993 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    994 %
    995 %  PolicyComponentTerminus() destroys the policy component.
    996 %
    997 %  The format of the PolicyComponentTerminus method is:
    998 %
    999 %      PolicyComponentTerminus(void)
   1000 %
   1001 */
   1002 
   1003 static void *DestroyPolicyElement(void *policy_info)
   1004 {
   1005   register PolicyInfo
   1006     *p;
   1007 
   1008   p=(PolicyInfo *) policy_info;
   1009   if (p->exempt == MagickFalse)
   1010     {
   1011       if (p->value != (char *) NULL)
   1012         p->value=DestroyString(p->value);
   1013       if (p->pattern != (char *) NULL)
   1014         p->pattern=DestroyString(p->pattern);
   1015       if (p->name != (char *) NULL)
   1016         p->name=DestroyString(p->name);
   1017       if (p->path != (char *) NULL)
   1018         p->path=DestroyString(p->path);
   1019     }
   1020   p=(PolicyInfo *) RelinquishMagickMemory(p);
   1021   return((void *) NULL);
   1022 }
   1023 
   1024 MagickPrivate void PolicyComponentTerminus(void)
   1025 {
   1026   if (policy_semaphore == (SemaphoreInfo *) NULL)
   1027     ActivateSemaphoreInfo(&policy_semaphore);
   1028   LockSemaphoreInfo(policy_semaphore);
   1029   if (policy_cache != (LinkedListInfo *) NULL)
   1030     policy_cache=DestroyLinkedList(policy_cache,DestroyPolicyElement);
   1031   UnlockSemaphoreInfo(policy_semaphore);
   1032   RelinquishSemaphoreInfo(&policy_semaphore);
   1033 }
   1034