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