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