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