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