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