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