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