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