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-2021 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 %    https://imagemagick.org/script/license.php                               %
26 %                                                                             %
27 %  Unless required by applicable law or agreed to in writing, software        %
28 %  distributed under the License is distributed on an "AS IS" BASIS,          %
29 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
30 %  See the License for the specific language governing permissions and        %
31 %  limitations under the License.                                             %
32 %                                                                             %
33 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
34 %
35 %  We use linked-lists because splay-trees do not currently support duplicate
36 %  key / value pairs (.e.g X11 green compliance and SVG green compliance).
37 %
38 */
39 
40 /*
41   Include declarations.
42 */
43 #include "MagickCore/studio.h"
44 #include "MagickCore/cache-private.h"
45 #include "MagickCore/client.h"
46 #include "MagickCore/configure.h"
47 #include "MagickCore/configure-private.h"
48 #include "MagickCore/exception.h"
49 #include "MagickCore/exception-private.h"
50 #include "MagickCore/magick-private.h"
51 #include "MagickCore/memory_.h"
52 #include "MagickCore/memory-private.h"
53 #include "MagickCore/monitor.h"
54 #include "MagickCore/monitor-private.h"
55 #include "MagickCore/option.h"
56 #include "MagickCore/policy.h"
57 #include "MagickCore/policy-private.h"
58 #include "MagickCore/resource_.h"
59 #include "MagickCore/resource-private.h"
60 #include "MagickCore/semaphore.h"
61 #include "MagickCore/stream-private.h"
62 #include "MagickCore/string_.h"
63 #include "MagickCore/string-private.h"
64 #include "MagickCore/token.h"
65 #include "MagickCore/utility.h"
66 #include "MagickCore/utility-private.h"
67 #include "MagickCore/xml-tree.h"
68 #include "MagickCore/xml-tree-private.h"
69 
70 /*
71   Define declarations.
72 */
73 #define PolicyFilename  "policy.xml"
74 
75 /*
76   Typedef declarations.
77 */
78 struct _PolicyInfo
79 {
80   char
81     *path;
82 
83   PolicyDomain
84     domain;
85 
86   PolicyRights
87     rights;
88 
89   char
90     *name,
91     *pattern,
92     *value;
93 
94   MagickBooleanType
95     exempt,
96     stealth,
97     debug;
98 
99   SemaphoreInfo
100     *semaphore;
101 
102   size_t
103     signature;
104 };
105 
106 typedef struct _PolicyMapInfo
107 {
108   const PolicyDomain
109     domain;
110 
111   const PolicyRights
112     rights;
113 
114   const char
115     *name,
116     *pattern,
117     *value;
118 } PolicyMapInfo;
119 
120 /*
121   Static declarations.
122 */
123 static const PolicyMapInfo
124   PolicyMap[] =
125   {
126     { UndefinedPolicyDomain, UndefinedPolicyRights, (const char *) NULL,
127       (const char *) NULL, (const char *) NULL }
128   };
129 
130 static LinkedListInfo
131   *policy_cache = (LinkedListInfo *) NULL;
132 
133 static SemaphoreInfo
134   *policy_semaphore = (SemaphoreInfo *) NULL;
135 
136 /*
137   Forward declarations.
138 */
139 static MagickBooleanType
140   IsPolicyCacheInstantiated(ExceptionInfo *),
141   LoadPolicyCache(LinkedListInfo *,const char *,const char *,const size_t,
142     ExceptionInfo *);
143 
144 /*
145 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
146 %                                                                             %
147 %                                                                             %
148 %                                                                             %
149 %  A c q u i r e P o l i c y C a c h e                                        %
150 %                                                                             %
151 %                                                                             %
152 %                                                                             %
153 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
154 %
155 %  AcquirePolicyCache() caches one or more policy configurations which provides
156 %  a mapping between policy attributes and a policy name.
157 %
158 %  The format of the AcquirePolicyCache method is:
159 %
160 %      LinkedListInfo *AcquirePolicyCache(const char *filename,
161 %        ExceptionInfo *exception)
162 %
163 %  A description of each parameter follows:
164 %
165 %    o filename: the policy configuration file name.
166 %
167 %    o exception: return any errors or warnings in this structure.
168 %
169 */
AcquirePolicyCache(const char * filename,ExceptionInfo * exception)170 static LinkedListInfo *AcquirePolicyCache(const char *filename,
171   ExceptionInfo *exception)
172 {
173   LinkedListInfo
174     *cache;
175 
176   MagickStatusType
177     status;
178 
179   ssize_t
180     i;
181 
182   /*
183     Load external policy map.
184   */
185   cache=NewLinkedList(0);
186   status=MagickTrue;
187 #if MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
188   (void) filename;
189   status=LoadPolicyCache(cache,ZeroConfigurationPolicy,"[zero-configuration]",0,
190     exception);
191 #else
192   {
193     const StringInfo
194       *option;
195 
196     LinkedListInfo
197       *options;
198 
199     options=GetConfigureOptions(filename,exception);
200     option=(const StringInfo *) GetNextValueInLinkedList(options);
201     while (option != (const StringInfo *) NULL)
202     {
203       status&=LoadPolicyCache(cache,(const char *) GetStringInfoDatum(option),
204         GetStringInfoPath(option),0,exception);
205       option=(const StringInfo *) GetNextValueInLinkedList(options);
206     }
207     options=DestroyConfigureOptions(options);
208   }
209 #endif
210   /*
211     Load built-in policy map.
212   */
213   for (i=0; i < (ssize_t) (sizeof(PolicyMap)/sizeof(*PolicyMap)); i++)
214   {
215     PolicyInfo
216       *policy_info;
217 
218     const PolicyMapInfo
219       *p;
220 
221     p=PolicyMap+i;
222     policy_info=(PolicyInfo *) AcquireMagickMemory(sizeof(*policy_info));
223     if (policy_info == (PolicyInfo *) NULL)
224       {
225         (void) ThrowMagickException(exception,GetMagickModule(),
226           ResourceLimitError,"MemoryAllocationFailed","`%s'",
227           p->name == (char *) NULL ? "" : p->name);
228         continue;
229       }
230     (void) memset(policy_info,0,sizeof(*policy_info));
231     policy_info->path=(char *) "[built-in]";
232     policy_info->domain=p->domain;
233     policy_info->rights=p->rights;
234     policy_info->name=(char *) p->name;
235     policy_info->pattern=(char *) p->pattern;
236     policy_info->value=(char *) p->value;
237     policy_info->exempt=MagickTrue;
238     policy_info->signature=MagickCoreSignature;
239     status&=AppendValueToLinkedList(cache,policy_info);
240     if (status == MagickFalse)
241       (void) ThrowMagickException(exception,GetMagickModule(),
242         ResourceLimitError,"MemoryAllocationFailed","`%s'",policy_info->name);
243   }
244   return(cache);
245 }
246 
247 /*
248 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
249 %                                                                             %
250 %                                                                             %
251 %                                                                             %
252 +   G e t P o l i c y I n f o                                                 %
253 %                                                                             %
254 %                                                                             %
255 %                                                                             %
256 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
257 %
258 %  GetPolicyInfo() searches the policy list for the specified name and if found
259 %  returns attributes for that policy.
260 %
261 %  The format of the GetPolicyInfo method is:
262 %
263 %      PolicyInfo *GetPolicyInfo(const char *name,ExceptionInfo *exception)
264 %
265 %  A description of each parameter follows:
266 %
267 %    o name: the policy name.
268 %
269 %    o exception: return any errors or warnings in this structure.
270 %
271 */
GetPolicyInfo(const char * name,ExceptionInfo * exception)272 static PolicyInfo *GetPolicyInfo(const char *name,ExceptionInfo *exception)
273 {
274   char
275     policyname[MagickPathExtent];
276 
277   PolicyDomain
278     domain;
279 
280   PolicyInfo
281     *p;
282 
283   char
284     *q;
285 
286   assert(exception != (ExceptionInfo *) NULL);
287   if (IsPolicyCacheInstantiated(exception) == MagickFalse)
288     return((PolicyInfo *) NULL);
289   /*
290     Strip names of whitespace.
291   */
292   *policyname='\0';
293   if (name != (const char *) NULL)
294     (void) CopyMagickString(policyname,name,MagickPathExtent);
295   for (q=policyname; *q != '\0'; q++)
296   {
297     if (isspace((int) ((unsigned char) *q)) == 0)
298       continue;
299     (void) CopyMagickString(q,q+1,MagickPathExtent);
300     q--;
301   }
302   /*
303     Strip domain from policy name (e.g. resource:map).
304   */
305   domain=UndefinedPolicyDomain;
306   for (q=policyname; *q != '\0'; q++)
307   {
308     if (*q != ':')
309       continue;
310     *q='\0';
311     domain=(PolicyDomain) ParseCommandOption(MagickPolicyDomainOptions,
312       MagickTrue,policyname);
313     (void) CopyMagickString(policyname,q+1,MagickPathExtent);
314     break;
315   }
316   /*
317     Search for policy tag.
318   */
319   LockSemaphoreInfo(policy_semaphore);
320   ResetLinkedListIterator(policy_cache);
321   p=(PolicyInfo *) GetNextValueInLinkedList(policy_cache);
322   if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
323     {
324       UnlockSemaphoreInfo(policy_semaphore);
325       return(p);
326     }
327   while (p != (PolicyInfo *) NULL)
328   {
329     if ((domain == UndefinedPolicyDomain) || (p->domain == domain))
330       if (LocaleCompare(policyname,p->name) == 0)
331         break;
332     p=(PolicyInfo *) GetNextValueInLinkedList(policy_cache);
333   }
334   if (p != (PolicyInfo *) NULL)
335     (void) InsertValueInLinkedList(policy_cache,0,
336       RemoveElementByValueFromLinkedList(policy_cache,p));
337   UnlockSemaphoreInfo(policy_semaphore);
338   return(p);
339 }
340 
341 /*
342 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
343 %                                                                             %
344 %                                                                             %
345 %                                                                             %
346 %   G e t P o l i c y I n f o L i s t                                         %
347 %                                                                             %
348 %                                                                             %
349 %                                                                             %
350 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
351 %
352 %  GetPolicyInfoList() returns any policies that match the specified pattern.
353 %
354 %  The format of the GetPolicyInfoList function is:
355 %
356 %      const PolicyInfo **GetPolicyInfoList(const char *pattern,
357 %        size_t *number_policies,ExceptionInfo *exception)
358 %
359 %  A description of each parameter follows:
360 %
361 %    o pattern: Specifies a pointer to a text string containing a pattern.
362 %
363 %    o number_policies:  returns the number of policies in the list.
364 %
365 %    o exception: return any errors or warnings in this structure.
366 %
367 */
GetPolicyInfoList(const char * pattern,size_t * number_policies,ExceptionInfo * exception)368 MagickExport const PolicyInfo **GetPolicyInfoList(const char *pattern,
369   size_t *number_policies,ExceptionInfo *exception)
370 {
371   const PolicyInfo
372     **policies;
373 
374   const PolicyInfo
375     *p;
376 
377   ssize_t
378     i;
379 
380   /*
381     Allocate policy list.
382   */
383   assert(pattern != (char *) NULL);
384   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
385   assert(number_policies != (size_t *) NULL);
386   *number_policies=0;
387   p=GetPolicyInfo("*",exception);
388   if (p == (const PolicyInfo *) NULL)
389     return((const PolicyInfo **) NULL);
390   policies=(const PolicyInfo **) AcquireQuantumMemory((size_t)
391     GetNumberOfElementsInLinkedList(policy_cache)+1UL,sizeof(*policies));
392   if (policies == (const PolicyInfo **) NULL)
393     return((const PolicyInfo **) NULL);
394   /*
395     Generate policy list.
396   */
397   LockSemaphoreInfo(policy_semaphore);
398   ResetLinkedListIterator(policy_cache);
399   p=(const PolicyInfo *) GetNextValueInLinkedList(policy_cache);
400   for (i=0; p != (const PolicyInfo *) NULL; )
401   {
402     if ((p->stealth == MagickFalse) &&
403         (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
404       policies[i++]=p;
405     p=(const PolicyInfo *) GetNextValueInLinkedList(policy_cache);
406   }
407   UnlockSemaphoreInfo(policy_semaphore);
408   policies[i]=(PolicyInfo *) NULL;
409   *number_policies=(size_t) i;
410   return(policies);
411 }
412 
413 /*
414 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
415 %                                                                             %
416 %                                                                             %
417 %                                                                             %
418 %   G e t P o l i c y L i s t                                                 %
419 %                                                                             %
420 %                                                                             %
421 %                                                                             %
422 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
423 %
424 %  GetPolicyList() returns any policies that match the specified pattern.
425 %
426 %  The format of the GetPolicyList function is:
427 %
428 %      char **GetPolicyList(const char *pattern,size_t *number_policies,
429 %        ExceptionInfo *exception)
430 %
431 %  A description of each parameter follows:
432 %
433 %    o pattern: a pointer to a text string containing a pattern.
434 %
435 %    o number_policies:  returns the number of policies in the list.
436 %
437 %    o exception: return any errors or warnings in this structure.
438 %
439 */
440 
AcquirePolicyString(const char * source,const size_t pad)441 static char *AcquirePolicyString(const char *source,const size_t pad)
442 {
443   char
444     *destination;
445 
446   size_t
447     length;
448 
449   length=0;
450   if (source != (char *) NULL)
451     length+=strlen(source);
452   destination=(char *) NULL;
453   /* AcquireMagickMemory needs to be used here to avoid an omp deadlock */
454   if (~length >= pad)
455     destination=(char *) AcquireMagickMemory((length+pad)*sizeof(*destination));
456   if (destination == (char *) NULL)
457     ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireString");
458   if (source != (char *) NULL)
459     (void) memcpy(destination,source,length*sizeof(*destination));
460   destination[length]='\0';
461   return(destination);
462 }
463 
GetPolicyList(const char * pattern,size_t * number_policies,ExceptionInfo * exception)464 MagickExport char **GetPolicyList(const char *pattern,size_t *number_policies,
465   ExceptionInfo *exception)
466 {
467   char
468     **policies;
469 
470   const PolicyInfo
471     *p;
472 
473   ssize_t
474     i;
475 
476   /*
477     Allocate policy list.
478   */
479   assert(pattern != (char *) NULL);
480   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
481   assert(number_policies != (size_t *) NULL);
482   *number_policies=0;
483   p=GetPolicyInfo("*",exception);
484   if (p == (const PolicyInfo *) NULL)
485     return((char **) NULL);
486   policies=(char **) AcquireQuantumMemory((size_t)
487     GetNumberOfElementsInLinkedList(policy_cache)+1UL,sizeof(*policies));
488   if (policies == (char **) NULL)
489     return((char **) NULL);
490   /*
491     Generate policy list.
492   */
493   LockSemaphoreInfo(policy_semaphore);
494   ResetLinkedListIterator(policy_cache);
495   p=(const PolicyInfo *) GetNextValueInLinkedList(policy_cache);
496   for (i=0; p != (const PolicyInfo *) NULL; )
497   {
498     if ((p->stealth == MagickFalse) &&
499         (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
500       policies[i++]=AcquirePolicyString(p->name,1);
501     p=(const PolicyInfo *) GetNextValueInLinkedList(policy_cache);
502   }
503   UnlockSemaphoreInfo(policy_semaphore);
504   policies[i]=(char *) NULL;
505   *number_policies=(size_t) i;
506   return(policies);
507 }
508 
509 /*
510 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
511 %                                                                             %
512 %                                                                             %
513 %                                                                             %
514 %   G e t P o l i c y V a l u e                                               %
515 %                                                                             %
516 %                                                                             %
517 %                                                                             %
518 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
519 %
520 %  GetPolicyValue() returns the value associated with the named policy.
521 %
522 %  The format of the GetPolicyValue method is:
523 %
524 %      char *GetPolicyValue(const char *name)
525 %
526 %  A description of each parameter follows:
527 %
528 %    o name:  The name of the policy.
529 %
530 */
GetPolicyValue(const char * name)531 MagickExport char *GetPolicyValue(const char *name)
532 {
533   const char
534     *value;
535 
536   const PolicyInfo
537     *policy_info;
538 
539   ExceptionInfo
540     *exception;
541 
542   assert(name != (const char *) NULL);
543   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",name);
544   exception=AcquireExceptionInfo();
545   policy_info=GetPolicyInfo(name,exception);
546   exception=DestroyExceptionInfo(exception);
547   if (policy_info == (PolicyInfo *) NULL)
548     return((char *) NULL);
549   value=policy_info->value;
550   if ((value == (const char *) NULL) || (*value == '\0'))
551     return((char *) NULL);
552   return(AcquirePolicyString(value,1));
553 }
554 
555 /*
556 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
557 %                                                                             %
558 %                                                                             %
559 %                                                                             %
560 +   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                         %
561 %                                                                             %
562 %                                                                             %
563 %                                                                             %
564 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
565 %
566 %  IsPolicyCacheInstantiated() determines if the policy list is instantiated.
567 %  If not, it instantiates the list and returns it.
568 %
569 %  The format of the IsPolicyInstantiated method is:
570 %
571 %      MagickBooleanType IsPolicyCacheInstantiated(ExceptionInfo *exception)
572 %
573 %  A description of each parameter follows.
574 %
575 %    o exception: return any errors or warnings in this structure.
576 %
577 */
IsPolicyCacheInstantiated(ExceptionInfo * exception)578 static MagickBooleanType IsPolicyCacheInstantiated(ExceptionInfo *exception)
579 {
580   if (policy_cache == (LinkedListInfo *) NULL)
581     {
582       if (policy_semaphore == (SemaphoreInfo *) NULL)
583         ActivateSemaphoreInfo(&policy_semaphore);
584       LockSemaphoreInfo(policy_semaphore);
585       if (policy_cache == (LinkedListInfo *) NULL)
586         policy_cache=AcquirePolicyCache(PolicyFilename,exception);
587       UnlockSemaphoreInfo(policy_semaphore);
588     }
589   return(policy_cache != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
590 }
591 
592 /*
593 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
594 %                                                                             %
595 %                                                                             %
596 %                                                                             %
597 %   I s R i g h t s A u t h o r i z e d                                       %
598 %                                                                             %
599 %                                                                             %
600 %                                                                             %
601 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
602 %
603 %  IsRightsAuthorized() returns MagickTrue if the policy authorizes the
604 %  requested rights for the specified domain.
605 %
606 %  The format of the IsRightsAuthorized method is:
607 %
608 %      MagickBooleanType IsRightsAuthorized(const PolicyDomain domain,
609 %        const PolicyRights rights,const char *pattern)
610 %
611 %  A description of each parameter follows:
612 %
613 %    o domain: the policy domain.
614 %
615 %    o rights: the policy rights.
616 %
617 %    o pattern: the coder, delegate, filter, or path pattern.
618 %
619 */
IsRightsAuthorized(const PolicyDomain domain,const PolicyRights rights,const char * pattern)620 MagickExport MagickBooleanType IsRightsAuthorized(const PolicyDomain domain,
621   const PolicyRights rights,const char *pattern)
622 {
623   const PolicyInfo
624     *policy_info;
625 
626   ExceptionInfo
627     *exception;
628 
629   MagickBooleanType
630     authorized;
631 
632   PolicyInfo
633     *p;
634 
635   if (IsEventLogging() != MagickFalse)
636     (void) LogMagickEvent(PolicyEvent,GetMagickModule(),
637       "Domain: %s; rights=%s; pattern=\"%s\" ...",
638       CommandOptionToMnemonic(MagickPolicyDomainOptions,domain),
639       CommandOptionToMnemonic(MagickPolicyRightsOptions,rights),pattern);
640   exception=AcquireExceptionInfo();
641   policy_info=GetPolicyInfo("*",exception);
642   exception=DestroyExceptionInfo(exception);
643   if (policy_info == (PolicyInfo *) NULL)
644     return(MagickTrue);
645   authorized=MagickTrue;
646   LockSemaphoreInfo(policy_semaphore);
647   ResetLinkedListIterator(policy_cache);
648   p=(PolicyInfo *) GetNextValueInLinkedList(policy_cache);
649   while (p != (PolicyInfo *) NULL)
650   {
651     if ((p->domain == domain) &&
652         (GlobExpression(pattern,p->pattern,MagickFalse) != MagickFalse))
653       {
654         if ((rights & ReadPolicyRights) != 0)
655           authorized=(p->rights & ReadPolicyRights) != 0 ? MagickTrue :
656             MagickFalse;
657         if ((rights & WritePolicyRights) != 0)
658           authorized=(p->rights & WritePolicyRights) != 0 ? MagickTrue :
659             MagickFalse;
660         if ((rights & ExecutePolicyRights) != 0)
661           authorized=(p->rights & ExecutePolicyRights) != 0 ? MagickTrue :
662             MagickFalse;
663       }
664     p=(PolicyInfo *) GetNextValueInLinkedList(policy_cache);
665   }
666   UnlockSemaphoreInfo(policy_semaphore);
667   return(authorized);
668 }
669 
670 /*
671 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
672 %                                                                             %
673 %                                                                             %
674 %                                                                             %
675 %  L i s t P o l i c y I n f o                                                %
676 %                                                                             %
677 %                                                                             %
678 %                                                                             %
679 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
680 %
681 %  ListPolicyInfo() lists policies to the specified file.
682 %
683 %  The format of the ListPolicyInfo method is:
684 %
685 %      MagickBooleanType ListPolicyInfo(FILE *file,ExceptionInfo *exception)
686 %
687 %  A description of each parameter follows.
688 %
689 %    o file:  List policy names to this file handle.
690 %
691 %    o exception: return any errors or warnings in this structure.
692 %
693 */
ListPolicyInfo(FILE * file,ExceptionInfo * exception)694 MagickExport MagickBooleanType ListPolicyInfo(FILE *file,
695   ExceptionInfo *exception)
696 {
697   const char
698     *path,
699     *domain;
700 
701   const PolicyInfo
702     **policy_info;
703 
704   ssize_t
705     i;
706 
707   size_t
708     number_policies;
709 
710   /*
711     List name and attributes of each policy in the list.
712   */
713   if (file == (const FILE *) NULL)
714     file=stdout;
715   policy_info=GetPolicyInfoList("*",&number_policies,exception);
716   if (policy_info == (const PolicyInfo **) NULL)
717     return(MagickFalse);
718   path=(const char *) NULL;
719   for (i=0; i < (ssize_t) number_policies; i++)
720   {
721     if (policy_info[i]->stealth != MagickFalse)
722       continue;
723     if (((path == (const char *) NULL) ||
724          (LocaleCompare(path,policy_info[i]->path) != 0)) &&
725          (policy_info[i]->path != (char *) NULL))
726       (void) FormatLocaleFile(file,"\nPath: %s\n",policy_info[i]->path);
727     path=policy_info[i]->path;
728     domain=CommandOptionToMnemonic(MagickPolicyDomainOptions,
729       policy_info[i]->domain);
730     (void) FormatLocaleFile(file,"  Policy: %s\n",domain);
731     if ((policy_info[i]->domain == CachePolicyDomain) ||
732         (policy_info[i]->domain == ResourcePolicyDomain) ||
733         (policy_info[i]->domain == SystemPolicyDomain))
734       {
735         if (policy_info[i]->name != (char *) NULL)
736           (void) FormatLocaleFile(file,"    name: %s\n",policy_info[i]->name);
737         if (policy_info[i]->value != (char *) NULL)
738           (void) FormatLocaleFile(file,"    value: %s\n",policy_info[i]->value);
739       }
740     else
741       {
742         (void) FormatLocaleFile(file,"    rights: ");
743         if (policy_info[i]->rights == NoPolicyRights)
744           (void) FormatLocaleFile(file,"None ");
745         if ((policy_info[i]->rights & ReadPolicyRights) != 0)
746           (void) FormatLocaleFile(file,"Read ");
747         if ((policy_info[i]->rights & WritePolicyRights) != 0)
748           (void) FormatLocaleFile(file,"Write ");
749         if ((policy_info[i]->rights & ExecutePolicyRights) != 0)
750           (void) FormatLocaleFile(file,"Execute ");
751         (void) FormatLocaleFile(file,"\n");
752         if (policy_info[i]->pattern != (char *) NULL)
753           (void) FormatLocaleFile(file,"    pattern: %s\n",
754             policy_info[i]->pattern);
755       }
756   }
757   policy_info=(const PolicyInfo **) RelinquishMagickMemory((void *)
758     policy_info);
759   (void) fflush(file);
760   return(MagickTrue);
761 }
762 
763 /*
764 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
765 %                                                                             %
766 %                                                                             %
767 %                                                                             %
768 +   L o a d P o l i c y C a c h e                                             %
769 %                                                                             %
770 %                                                                             %
771 %                                                                             %
772 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
773 %
774 %  LoadPolicyCache() loads the policy configurations which provides a mapping
775 %  between policy attributes and a policy domain.
776 %
777 %  The format of the LoadPolicyCache method is:
778 %
779 %      MagickBooleanType LoadPolicyCache(LinkedListInfo *cache,const char *xml,
780 %        const char *filename,const size_t depth,ExceptionInfo *exception)
781 %
782 %  A description of each parameter follows:
783 %
784 %    o xml:  The policy list in XML format.
785 %
786 %    o filename:  The policy list filename.
787 %
788 %    o depth: depth of <include /> statements.
789 %
790 %    o exception: return any errors or warnings in this structure.
791 %
792 */
LoadPolicyCache(LinkedListInfo * cache,const char * xml,const char * filename,const size_t depth,ExceptionInfo * exception)793 static MagickBooleanType LoadPolicyCache(LinkedListInfo *cache,const char *xml,
794   const char *filename,const size_t depth,ExceptionInfo *exception)
795 {
796   char
797     keyword[MagickPathExtent],
798     *token;
799 
800   const char
801     *q;
802 
803   MagickStatusType
804     status;
805 
806   PolicyInfo
807     *policy_info;
808 
809   size_t
810     extent;
811 
812   /*
813     Load the policy map file.
814   */
815   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
816     "Loading policy file \"%s\" ...",filename);
817   if (xml == (char *) NULL)
818     return(MagickFalse);
819   status=MagickTrue;
820   policy_info=(PolicyInfo *) NULL;
821   token=AcquirePolicyString(xml,MagickPathExtent);
822   extent=strlen(token)+MagickPathExtent;
823   for (q=(const char *) xml; *q != '\0'; )
824   {
825     /*
826       Interpret XML.
827     */
828     (void) GetNextToken(q,&q,extent,token);
829     if (*token == '\0')
830       break;
831     (void) CopyMagickString(keyword,token,MagickPathExtent);
832     if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
833       {
834         /*
835           Docdomain element.
836         */
837         while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
838           (void) GetNextToken(q,&q,extent,token);
839         continue;
840       }
841     if (LocaleNCompare(keyword,"<!--",4) == 0)
842       {
843         /*
844           Comment element.
845         */
846         while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
847           (void) GetNextToken(q,&q,extent,token);
848         continue;
849       }
850     if (LocaleCompare(keyword,"<include") == 0)
851       {
852         /*
853           Include element.
854         */
855         while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
856         {
857           (void) CopyMagickString(keyword,token,MagickPathExtent);
858           (void) GetNextToken(q,&q,extent,token);
859           if (*token != '=')
860             continue;
861           (void) GetNextToken(q,&q,extent,token);
862           if (LocaleCompare(keyword,"file") == 0)
863             {
864               if (depth > MagickMaxRecursionDepth)
865                 (void) ThrowMagickException(exception,GetMagickModule(),
866                   ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
867               else
868                 {
869                   char
870                     path[MagickPathExtent],
871                     *file_xml;
872 
873                   GetPathComponent(filename,HeadPath,path);
874                   if (*path != '\0')
875                     (void) ConcatenateMagickString(path,DirectorySeparator,
876                       MagickPathExtent);
877                   if (*token == *DirectorySeparator)
878                     (void) CopyMagickString(path,token,MagickPathExtent);
879                   else
880                     (void) ConcatenateMagickString(path,token,MagickPathExtent);
881                   file_xml=FileToXML(path,~0UL);
882                   if (file_xml != (char *) NULL)
883                     {
884                       status&=LoadPolicyCache(cache,file_xml,path,
885                         depth+1,exception);
886                       file_xml=DestroyString(file_xml);
887                     }
888                 }
889             }
890         }
891         continue;
892       }
893     if (LocaleCompare(keyword,"<policy") == 0)
894       {
895         /*
896           Policy element.
897         */
898         policy_info=(PolicyInfo *) AcquireCriticalMemory(sizeof(*policy_info));
899         (void) memset(policy_info,0,sizeof(*policy_info));
900         policy_info->path=AcquirePolicyString(filename,1);
901         policy_info->exempt=MagickFalse;
902         policy_info->signature=MagickCoreSignature;
903         continue;
904       }
905     if (policy_info == (PolicyInfo *) NULL)
906       continue;
907     if ((LocaleCompare(keyword,"/>") == 0) ||
908         (LocaleCompare(keyword,"</policy>") == 0))
909       {
910         status=AppendValueToLinkedList(cache,policy_info);
911         if (status == MagickFalse)
912           (void) ThrowMagickException(exception,GetMagickModule(),
913             ResourceLimitError,"MemoryAllocationFailed","`%s'",
914             policy_info->name);
915         policy_info=(PolicyInfo *) NULL;
916         continue;
917       }
918     (void) GetNextToken(q,(const char **) NULL,extent,token);
919     if (*token != '=')
920       continue;
921     (void) GetNextToken(q,&q,extent,token);
922     (void) GetNextToken(q,&q,extent,token);
923     switch (*keyword)
924     {
925       case 'D':
926       case 'd':
927       {
928         if (LocaleCompare((char *) keyword,"domain") == 0)
929           {
930             policy_info->domain=(PolicyDomain) ParseCommandOption(
931               MagickPolicyDomainOptions,MagickTrue,token);
932             break;
933           }
934         break;
935       }
936       case 'N':
937       case 'n':
938       {
939         if (LocaleCompare((char *) keyword,"name") == 0)
940           {
941             policy_info->name=AcquirePolicyString(token,1);
942             break;
943           }
944         break;
945       }
946       case 'P':
947       case 'p':
948       {
949         if (LocaleCompare((char *) keyword,"pattern") == 0)
950           {
951             policy_info->pattern=AcquirePolicyString(token,1);
952             break;
953           }
954         break;
955       }
956       case 'R':
957       case 'r':
958       {
959         if (LocaleCompare((char *) keyword,"rights") == 0)
960           {
961             policy_info->rights=(PolicyRights) ParseCommandOption(
962               MagickPolicyRightsOptions,MagickTrue,token);
963             break;
964           }
965         break;
966       }
967       case 'S':
968       case 's':
969       {
970         if (LocaleCompare((char *) keyword,"stealth") == 0)
971           {
972             policy_info->stealth=IsStringTrue(token);
973             break;
974           }
975         break;
976       }
977       case 'V':
978       case 'v':
979       {
980         if (LocaleCompare((char *) keyword,"value") == 0)
981           {
982             policy_info->value=AcquirePolicyString(token,1);
983             break;
984           }
985         break;
986       }
987       default:
988         break;
989     }
990   }
991   token=(char *) RelinquishMagickMemory(token);
992   return(status != 0 ? MagickTrue : MagickFalse);
993 }
994 
995 /*
996 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
997 %                                                                             %
998 %                                                                             %
999 %                                                                             %
1000 +   P o l i c y C o m p o n e n t G e n e s i s                               %
1001 %                                                                             %
1002 %                                                                             %
1003 %                                                                             %
1004 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1005 %
1006 %  PolicyComponentGenesis() instantiates the policy component.
1007 %
1008 %  The format of the PolicyComponentGenesis method is:
1009 %
1010 %      MagickBooleanType PolicyComponentGenesis(void)
1011 %
1012 */
PolicyComponentGenesis(void)1013 MagickPrivate MagickBooleanType PolicyComponentGenesis(void)
1014 {
1015   if (policy_semaphore == (SemaphoreInfo *) NULL)
1016     policy_semaphore=AcquireSemaphoreInfo();
1017   return(MagickTrue);
1018 }
1019 
1020 /*
1021 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1022 %                                                                             %
1023 %                                                                             %
1024 %                                                                             %
1025 +   P o l i c y C o m p o n e n t T e r m i n u s                             %
1026 %                                                                             %
1027 %                                                                             %
1028 %                                                                             %
1029 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1030 %
1031 %  PolicyComponentTerminus() destroys the policy component.
1032 %
1033 %  The format of the PolicyComponentTerminus method is:
1034 %
1035 %      PolicyComponentTerminus(void)
1036 %
1037 */
1038 
DestroyPolicyElement(void * policy_info)1039 static void *DestroyPolicyElement(void *policy_info)
1040 {
1041   PolicyInfo
1042     *p;
1043 
1044   p=(PolicyInfo *) policy_info;
1045   if (p->exempt == MagickFalse)
1046     {
1047       if (p->value != (char *) NULL)
1048         p->value=DestroyString(p->value);
1049       if (p->pattern != (char *) NULL)
1050         p->pattern=DestroyString(p->pattern);
1051       if (p->name != (char *) NULL)
1052         p->name=DestroyString(p->name);
1053       if (p->path != (char *) NULL)
1054         p->path=DestroyString(p->path);
1055     }
1056   p=(PolicyInfo *) RelinquishMagickMemory(p);
1057   return((void *) NULL);
1058 }
1059 
PolicyComponentTerminus(void)1060 MagickPrivate void PolicyComponentTerminus(void)
1061 {
1062   if (policy_semaphore == (SemaphoreInfo *) NULL)
1063     ActivateSemaphoreInfo(&policy_semaphore);
1064   LockSemaphoreInfo(policy_semaphore);
1065   if (policy_cache != (LinkedListInfo *) NULL)
1066     policy_cache=DestroyLinkedList(policy_cache,DestroyPolicyElement);
1067   UnlockSemaphoreInfo(policy_semaphore);
1068   RelinquishSemaphoreInfo(&policy_semaphore);
1069 }
1070 
1071 /*
1072 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1073 %                                                                             %
1074 %                                                                             %
1075 %                                                                             %
1076 %  S e t M a g i c k S e c u r i t y P o l i c y                              %
1077 %                                                                             %
1078 %                                                                             %
1079 %                                                                             %
1080 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1081 %
1082 %  SetMagickSecurityPolicy() sets the ImageMagick security policy.  It returns
1083 %  MagickFalse if the policy is already set or if the policy does not parse.
1084 %
1085 %  The format of the SetMagickSecurityPolicy method is:
1086 %
1087 %      MagickBooleanType SetMagickSecurityPolicy(const char *policy,
1088 %        ExceptionInfo *exception)
1089 %
1090 %  A description of each parameter follows:
1091 %
1092 %    o policy: the security policy in the XML format.
1093 %
1094 %    o exception: return any errors or warnings in this structure.
1095 %
1096 */
SetMagickSecurityPolicy(const char * policy,ExceptionInfo * exception)1097 MagickExport MagickBooleanType SetMagickSecurityPolicy(const char *policy,
1098   ExceptionInfo *exception)
1099 {
1100   PolicyInfo
1101     *p;
1102 
1103   MagickBooleanType
1104     status;
1105 
1106   assert(exception != (ExceptionInfo *) NULL);
1107   if (policy == (const char *) NULL)
1108     return(MagickFalse);
1109   if (IsPolicyCacheInstantiated(exception) == MagickFalse)
1110     return(MagickFalse);
1111   LockSemaphoreInfo(policy_semaphore);
1112   ResetLinkedListIterator(policy_cache);
1113   p=(PolicyInfo *) GetNextValueInLinkedList(policy_cache);
1114   if ((p != (PolicyInfo *) NULL) && (p->domain != UndefinedPolicyDomain))
1115     {
1116       UnlockSemaphoreInfo(policy_semaphore);
1117       return(MagickFalse);
1118     }
1119   UnlockSemaphoreInfo(policy_semaphore);
1120   status=LoadPolicyCache(policy_cache,policy,"[user-policy]",0,exception);
1121   if (status == MagickFalse)
1122     return(MagickFalse);
1123   return(ResourceComponentGenesis());
1124 }
1125 
1126 /*
1127 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1128 %                                                                             %
1129 %                                                                             %
1130 %                                                                             %
1131 %  S e t M a g i c k S e c u r i t y P o l i c y V a l u e                    %
1132 %                                                                             %
1133 %                                                                             %
1134 %                                                                             %
1135 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1136 %
1137 %  SetMagickSecurityPolicyValue() sets a value associated with an ImageMagick
1138 %  security policy.  For most policies, the value must be less than any value
1139 %  set by the security policy configuration file (i.e. policy.xml).  It returns
1140 %  MagickFalse if the policy cannot be modified or if the policy does not parse.
1141 %
1142 %  The format of the SetMagickSecurityPolicyValue method is:
1143 %
1144 %      MagickBooleanType SetMagickSecurityPolicyValue(
1145 %        const PolicyDomain domain,const char *name,const char *value,
1146 %        ExceptionInfo *exception)
1147 %
1148 %  A description of each parameter follows:
1149 %
1150 %    o domain: the domain of the policy (e.g. system, resource).
1151 %
1152 %    o name: the name of the policy.
1153 %
1154 %    o value: the value to set the policy to.
1155 %
1156 %    o exception: return any errors or warnings in this structure.
1157 %
1158 */
1159 
SetPolicyValue(const PolicyDomain domain,const char * name,const char * value)1160 static MagickBooleanType SetPolicyValue(const PolicyDomain domain,
1161   const char *name,const char *value)
1162 {
1163   MagickBooleanType
1164     status;
1165 
1166   PolicyInfo
1167     *p;
1168 
1169   status=MagickTrue;
1170   LockSemaphoreInfo(policy_semaphore);
1171   ResetLinkedListIterator(policy_cache);
1172   p=(PolicyInfo *) GetNextValueInLinkedList(policy_cache);
1173   while (p != (PolicyInfo *) NULL)
1174   {
1175     if ((p->domain == domain) && (LocaleCompare(name,p->name) == 0))
1176       break;
1177     p=(PolicyInfo *) GetNextValueInLinkedList(policy_cache);
1178   }
1179   if (p != (PolicyInfo *) NULL)
1180     {
1181       if (p->value != (char *) NULL)
1182         p->value=DestroyString(p->value);
1183     }
1184   else
1185     {
1186       p=(PolicyInfo *) AcquireCriticalMemory(sizeof(*p));
1187       (void) memset(p,0,sizeof(*p));
1188       p->exempt=MagickFalse;
1189       p->signature=MagickCoreSignature;
1190       p->domain=domain;
1191       p->name=AcquirePolicyString(name,1);
1192       status=AppendValueToLinkedList(policy_cache,p);
1193     }
1194   p->value=AcquirePolicyString(value,1);
1195   UnlockSemaphoreInfo(policy_semaphore);
1196   if (status == MagickFalse)
1197     p=(PolicyInfo *) RelinquishMagickMemory(p);
1198   return(status);
1199 }
1200 
SetMagickSecurityPolicyValue(const PolicyDomain domain,const char * name,const char * value,ExceptionInfo * exception)1201 MagickExport MagickBooleanType SetMagickSecurityPolicyValue(
1202   const PolicyDomain domain,const char *name,const char *value,
1203   ExceptionInfo *exception)
1204 {
1205   char
1206     *current_value;
1207 
1208   magick_unreferenced(exception);
1209   assert(exception != (ExceptionInfo *) NULL);
1210   if ((name == (const char *) NULL) || (value == (const char *) NULL))
1211     return(MagickFalse);
1212   switch(domain)
1213   {
1214     case CachePolicyDomain:
1215     {
1216       if (LocaleCompare(name,"memory-map") == 0)
1217         {
1218           if (LocaleCompare(value,"anonymous") != 0)
1219             return(MagickFalse);
1220           ResetCacheAnonymousMemory();
1221           ResetStreamAnonymousMemory();
1222           return(SetPolicyValue(domain,name,value));
1223         }
1224       if (LocaleCompare(name,"synchronize") == 0)
1225         return(SetPolicyValue(domain,name,value));
1226       break;
1227     }
1228     case ResourcePolicyDomain:
1229     {
1230       ssize_t
1231         type;
1232 
1233       if (LocaleCompare(name,"temporary-path") == 0)
1234         return(SetPolicyValue(domain,name,value));
1235       type=ParseCommandOption(MagickResourceOptions,MagickFalse,name);
1236       if (type >= 0)
1237         {
1238           MagickSizeType
1239             limit;
1240 
1241           limit=MagickResourceInfinity;
1242           if (LocaleCompare("unlimited",value) != 0)
1243             limit=StringToMagickSizeType(value,100.0);
1244           return(SetMagickResourceLimit((ResourceType) type,limit));
1245         }
1246       break;
1247     }
1248     case SystemPolicyDomain:
1249     {
1250       if (LocaleCompare(name,"font") == 0)
1251         return(SetPolicyValue(domain,name,value));
1252       if (LocaleCompare(name,"max-memory-request") == 0)
1253         {
1254           current_value=GetPolicyValue("system:max-memory-request");
1255           if ((current_value == (char *) NULL) ||
1256               (StringToSizeType(value,100.0) < StringToSizeType(current_value,100.0)))
1257             {
1258               if (current_value != (char *) NULL)
1259                 current_value=DestroyString(current_value);
1260               ResetMaxMemoryRequest();
1261               return(SetPolicyValue(domain,name,value));
1262             }
1263           if (current_value != (char *) NULL)
1264             current_value=DestroyString(current_value);
1265         }
1266       if (LocaleCompare(name,"memory-map") == 0)
1267         {
1268           if (LocaleCompare(value,"anonymous") != 0)
1269             return(MagickFalse);
1270           ResetVirtualAnonymousMemory();
1271           return(SetPolicyValue(domain,name,value));
1272         }
1273       if (LocaleCompare(name,"precision") == 0)
1274         {
1275           ResetMagickPrecision();
1276           return(SetPolicyValue(domain,name,value));
1277         }
1278       if (LocaleCompare(name,"shred") == 0)
1279         {
1280           current_value=GetPolicyValue("system:shred");
1281           if ((current_value == (char *) NULL) ||
1282               (StringToInteger(value) > StringToInteger(current_value)))
1283             {
1284               if (current_value != (char *) NULL)
1285                 current_value=DestroyString(current_value);
1286               return(SetPolicyValue(domain,name,value));
1287             }
1288           if (current_value != (char *) NULL)
1289             current_value=DestroyString(current_value);
1290         }
1291       break;
1292     }
1293     case CoderPolicyDomain:
1294     case DelegatePolicyDomain:
1295     case FilterPolicyDomain:
1296     case ModulePolicyDomain:
1297     case PathPolicyDomain:
1298     default:
1299       break;
1300   }
1301   return(MagickFalse);
1302 }
1303