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