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