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