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