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