MagickCore  6.9.12-55
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  if (policy_semaphore == (SemaphoreInfo *) NULL)
579  ActivateSemaphoreInfo(&policy_semaphore);
580  LockSemaphoreInfo(policy_semaphore);
581  if (policy_cache == (LinkedListInfo *) NULL)
582  policy_cache=AcquirePolicyCache(PolicyFilename,exception);
583  UnlockSemaphoreInfo(policy_semaphore);
584  }
585  return(policy_cache != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
586 }
587 
588 /*
589 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
590 % %
591 % %
592 % %
593 % I s R i g h t s A u t h o r i z e d %
594 % %
595 % %
596 % %
597 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
598 %
599 % IsRightsAuthorized() returns MagickTrue if the policy authorizes the
600 % requested rights for the specified domain.
601 %
602 % The format of the IsRightsAuthorized method is:
603 %
604 % MagickBooleanType IsRightsAuthorized(const PolicyDomain domain,
605 % const PolicyRights rights,const char *pattern)
606 %
607 % A description of each parameter follows:
608 %
609 % o domain: the policy domain.
610 %
611 % o rights: the policy rights.
612 %
613 % o pattern: the coder, delegate, filter, or path pattern.
614 %
615 */
616 MagickExport MagickBooleanType IsRightsAuthorized(const PolicyDomain domain,
617  const PolicyRights rights,const char *pattern)
618 {
619  const PolicyInfo
620  *policy_info;
621 
623  *exception;
624 
625  MagickBooleanType
626  authorized;
627 
628  PolicyInfo
629  *p;
630 
631  if ((GetLogEventMask() & PolicyEvent) != 0)
632  (void) LogMagickEvent(PolicyEvent,GetMagickModule(),
633  "Domain: %s; rights=%s; pattern=\"%s\" ...",
634  CommandOptionToMnemonic(MagickPolicyDomainOptions,domain),
635  CommandOptionToMnemonic(MagickPolicyRightsOptions,rights),pattern);
636  exception=AcquireExceptionInfo();
637  policy_info=GetPolicyInfo("*",exception);
638  exception=DestroyExceptionInfo(exception);
639  if (policy_info == (PolicyInfo *) NULL)
640  return(MagickTrue);
641  authorized=MagickTrue;
642  LockSemaphoreInfo(policy_semaphore);
643  ResetLinkedListIterator(policy_cache);
644  p=(PolicyInfo *) GetNextValueInLinkedList(policy_cache);
645  while (p != (PolicyInfo *) NULL)
646  {
647  if ((p->domain == domain) &&
648  (GlobExpression(pattern,p->pattern,MagickFalse) != MagickFalse))
649  {
650  if ((rights & ReadPolicyRights) != 0)
651  authorized=(p->rights & ReadPolicyRights) != 0 ? MagickTrue :
652  MagickFalse;
653  if ((rights & WritePolicyRights) != 0)
654  authorized=(p->rights & WritePolicyRights) != 0 ? MagickTrue :
655  MagickFalse;
656  if ((rights & ExecutePolicyRights) != 0)
657  authorized=(p->rights & ExecutePolicyRights) != 0 ? MagickTrue :
658  MagickFalse;
659  }
660  p=(PolicyInfo *) GetNextValueInLinkedList(policy_cache);
661  }
662  UnlockSemaphoreInfo(policy_semaphore);
663  return(authorized);
664 }
665 
666 /*
667 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
668 % %
669 % %
670 % %
671 % L i s t P o l i c y I n f o %
672 % %
673 % %
674 % %
675 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
676 %
677 % ListPolicyInfo() lists policies to the specified file.
678 %
679 % The format of the ListPolicyInfo method is:
680 %
681 % MagickBooleanType ListPolicyInfo(FILE *file,ExceptionInfo *exception)
682 %
683 % A description of each parameter follows.
684 %
685 % o file: List policy names to this file handle.
686 %
687 % o exception: return any errors or warnings in this structure.
688 %
689 */
690 MagickExport MagickBooleanType ListPolicyInfo(FILE *file,
691  ExceptionInfo *exception)
692 {
693  const char
694  *path,
695  *domain;
696 
697  const PolicyInfo
698  **policy_info;
699 
700  ssize_t
701  i;
702 
703  size_t
704  number_policies;
705 
706  /*
707  List name and attributes of each policy in the list.
708  */
709  if (file == (const FILE *) NULL)
710  file=stdout;
711  policy_info=GetPolicyInfoList("*",&number_policies,exception);
712  if (policy_info == (const PolicyInfo **) NULL)
713  return(MagickFalse);
714  path=(const char *) NULL;
715  for (i=0; i < (ssize_t) number_policies; i++)
716  {
717  if (policy_info[i]->stealth != MagickFalse)
718  continue;
719  if (((path == (const char *) NULL) ||
720  (LocaleCompare(path,policy_info[i]->path) != 0)) &&
721  (policy_info[i]->path != (char *) NULL))
722  (void) FormatLocaleFile(file,"\nPath: %s\n",policy_info[i]->path);
723  path=policy_info[i]->path;
724  domain=CommandOptionToMnemonic(MagickPolicyDomainOptions,
725  policy_info[i]->domain);
726  (void) FormatLocaleFile(file," Policy: %s\n",domain);
727  if ((policy_info[i]->domain == CachePolicyDomain) ||
728  (policy_info[i]->domain == ResourcePolicyDomain) ||
729  (policy_info[i]->domain == SystemPolicyDomain))
730  {
731  if (policy_info[i]->name != (char *) NULL)
732  (void) FormatLocaleFile(file," name: %s\n",policy_info[i]->name);
733  if (policy_info[i]->value != (char *) NULL)
734  (void) FormatLocaleFile(file," value: %s\n",policy_info[i]->value);
735  }
736  else
737  {
738  (void) FormatLocaleFile(file," rights: ");
739  if (policy_info[i]->rights == NoPolicyRights)
740  (void) FormatLocaleFile(file,"None ");
741  if ((policy_info[i]->rights & ReadPolicyRights) != 0)
742  (void) FormatLocaleFile(file,"Read ");
743  if ((policy_info[i]->rights & WritePolicyRights) != 0)
744  (void) FormatLocaleFile(file,"Write ");
745  if ((policy_info[i]->rights & ExecutePolicyRights) != 0)
746  (void) FormatLocaleFile(file,"Execute ");
747  (void) FormatLocaleFile(file,"\n");
748  if (policy_info[i]->pattern != (char *) NULL)
749  (void) FormatLocaleFile(file," pattern: %s\n",
750  policy_info[i]->pattern);
751  }
752  }
753  policy_info=(const PolicyInfo **) RelinquishMagickMemory((void *)
754  policy_info);
755  (void) fflush(file);
756  return(MagickTrue);
757 }
758 
759 /*
760 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
761 % %
762 % %
763 % %
764 + L o a d P o l i c y C a c h e %
765 % %
766 % %
767 % %
768 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
769 %
770 % LoadPolicyCache() loads the policy configurations which provides a mapping
771 % between policy attributes and a policy domain.
772 %
773 % The format of the LoadPolicyCache method is:
774 %
775 % MagickBooleanType LoadPolicyCache(LinkedListInfo *cache,const char *xml,
776 % const char *filename,const size_t depth,ExceptionInfo *exception)
777 %
778 % A description of each parameter follows:
779 %
780 % o xml: The policy list in XML format.
781 %
782 % o filename: The policy list filename.
783 %
784 % o depth: depth of <include /> statements.
785 %
786 % o exception: return any errors or warnings in this structure.
787 %
788 */
789 static MagickBooleanType LoadPolicyCache(LinkedListInfo *cache,const char *xml,
790  const char *filename,const size_t depth,ExceptionInfo *exception)
791 {
792  char
793  keyword[MagickPathExtent],
794  *token;
795 
796  const char
797  *q;
798 
799  MagickStatusType
800  status;
801 
802  PolicyInfo
803  *policy_info;
804 
805  size_t
806  extent;
807 
808  /*
809  Load the policy map file.
810  */
811  (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
812  "Loading policy file \"%s\" ...",filename);
813  if (xml == (char *) NULL)
814  return(MagickFalse);
815  status=MagickTrue;
816  policy_info=(PolicyInfo *) NULL;
817  token=AcquirePolicyString(xml,MagickPathExtent);
818  extent=strlen(token)+MagickPathExtent;
819  for (q=(const char *) xml; *q != '\0'; )
820  {
821  /*
822  Interpret XML.
823  */
824  (void) GetNextToken(q,&q,extent,token);
825  if (*token == '\0')
826  break;
827  (void) CopyMagickString(keyword,token,MagickPathExtent);
828  if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
829  {
830  /*
831  Docdomain element.
832  */
833  while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
834  (void) GetNextToken(q,&q,extent,token);
835  continue;
836  }
837  if (LocaleNCompare(keyword,"<!--",4) == 0)
838  {
839  /*
840  Comment element.
841  */
842  while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
843  (void) GetNextToken(q,&q,extent,token);
844  continue;
845  }
846  if (LocaleCompare(keyword,"<include") == 0)
847  {
848  /*
849  Include element.
850  */
851  while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
852  {
853  (void) CopyMagickString(keyword,token,MagickPathExtent);
854  (void) GetNextToken(q,&q,extent,token);
855  if (*token != '=')
856  continue;
857  (void) GetNextToken(q,&q,extent,token);
858  if (LocaleCompare(keyword,"file") == 0)
859  {
860  if (depth > MagickMaxRecursionDepth)
861  (void) ThrowMagickException(exception,GetMagickModule(),
862  ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
863  else
864  {
865  char
866  path[MagickPathExtent],
867  *xml;
868 
869  GetPathComponent(filename,HeadPath,path);
870  if (*path != '\0')
871  (void) ConcatenateMagickString(path,DirectorySeparator,
872  MagickPathExtent);
873  if (*token == *DirectorySeparator)
874  (void) CopyMagickString(path,token,MagickPathExtent);
875  else
876  (void) ConcatenateMagickString(path,token,MagickPathExtent);
877  xml=FileToXML(path,~0UL);
878  if (xml != (char *) NULL)
879  {
880  status&=LoadPolicyCache(cache,xml,path,depth+1,
881  exception);
882  xml=(char *) RelinquishMagickMemory(xml);
883  }
884  }
885  }
886  }
887  continue;
888  }
889  if (LocaleCompare(keyword,"<policy") == 0)
890  {
891  /*
892  Policy element.
893  */
894  policy_info=(PolicyInfo *) AcquireMagickMemory(sizeof(*policy_info));
895  if (policy_info == (PolicyInfo *) NULL)
896  ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
897  (void) memset(policy_info,0,sizeof(*policy_info));
898  policy_info->path=AcquirePolicyString(filename,1);
899  policy_info->exempt=MagickFalse;
900  policy_info->signature=MagickCoreSignature;
901  continue;
902  }
903  if (policy_info == (PolicyInfo *) NULL)
904  continue;
905  if ((LocaleCompare(keyword,"/>") == 0) ||
906  (LocaleCompare(keyword,"</policy>") == 0))
907  {
908  status=AppendValueToLinkedList(cache,policy_info);
909  if (status == MagickFalse)
910  (void) ThrowMagickException(exception,GetMagickModule(),
911  ResourceLimitError,"MemoryAllocationFailed","`%s'",
912  policy_info->name);
913  policy_info=(PolicyInfo *) NULL;
914  continue;
915  }
916  (void) GetNextToken(q,(const char **) NULL,extent,token);
917  if (*token != '=')
918  continue;
919  (void) GetNextToken(q,&q,extent,token);
920  (void) GetNextToken(q,&q,extent,token);
921  switch (*keyword)
922  {
923  case 'D':
924  case 'd':
925  {
926  if (LocaleCompare((char *) keyword,"domain") == 0)
927  {
928  policy_info->domain=(PolicyDomain) ParseCommandOption(
929  MagickPolicyDomainOptions,MagickTrue,token);
930  break;
931  }
932  break;
933  }
934  case 'N':
935  case 'n':
936  {
937  if (LocaleCompare((char *) keyword,"name") == 0)
938  {
939  policy_info->name=AcquirePolicyString(token,1);
940  break;
941  }
942  break;
943  }
944  case 'P':
945  case 'p':
946  {
947  if (LocaleCompare((char *) keyword,"pattern") == 0)
948  {
949  policy_info->pattern=AcquirePolicyString(token,1);
950  break;
951  }
952  break;
953  }
954  case 'R':
955  case 'r':
956  {
957  if (LocaleCompare((char *) keyword,"rights") == 0)
958  {
959  policy_info->rights=(PolicyRights) ParseCommandOption(
960  MagickPolicyRightsOptions,MagickTrue,token);
961  break;
962  }
963  break;
964  }
965  case 'S':
966  case 's':
967  {
968  if (LocaleCompare((char *) keyword,"stealth") == 0)
969  {
970  policy_info->stealth=IsMagickTrue(token);
971  break;
972  }
973  break;
974  }
975  case 'V':
976  case 'v':
977  {
978  if (LocaleCompare((char *) keyword,"value") == 0)
979  {
980  policy_info->value=AcquirePolicyString(token,1);
981  break;
982  }
983  break;
984  }
985  default:
986  break;
987  }
988  }
989  token=(char *) RelinquishMagickMemory(token);
990  return(status != 0 ? MagickTrue : MagickFalse);
991 }
992 
993 /*
994 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
995 % %
996 % %
997 % %
998 + P o l i c y C o m p o n e n t G e n e s i s %
999 % %
1000 % %
1001 % %
1002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1003 %
1004 % PolicyComponentGenesis() instantiates the policy component.
1005 %
1006 % The format of the PolicyComponentGenesis method is:
1007 %
1008 % MagickBooleanType PolicyComponentGenesis(void)
1009 %
1010 */
1011 MagickExport MagickBooleanType PolicyComponentGenesis(void)
1012 {
1013  if (policy_semaphore == (SemaphoreInfo *) NULL)
1014  policy_semaphore=AllocateSemaphoreInfo();
1015  return(MagickTrue);
1016 }
1017 
1018 /*
1019 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1020 % %
1021 % %
1022 % %
1023 + P o l i c y C o m p o n e n t T e r m i n u s %
1024 % %
1025 % %
1026 % %
1027 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1028 %
1029 % PolicyComponentTerminus() destroys the policy component.
1030 %
1031 % The format of the PolicyComponentTerminus method is:
1032 %
1033 % PolicyComponentTerminus(void)
1034 %
1035 */
1036 
1037 static void *DestroyPolicyElement(void *policy_info)
1038 {
1039  PolicyInfo
1040  *p;
1041 
1042  p=(PolicyInfo *) policy_info;
1043  if (p->exempt == MagickFalse)
1044  {
1045  if (p->value != (char *) NULL)
1046  p->value=DestroyString(p->value);
1047  if (p->pattern != (char *) NULL)
1048  p->pattern=DestroyString(p->pattern);
1049  if (p->name != (char *) NULL)
1050  p->name=DestroyString(p->name);
1051  if (p->path != (char *) NULL)
1052  p->path=DestroyString(p->path);
1053  }
1054  p=(PolicyInfo *) RelinquishMagickMemory(p);
1055  return((void *) NULL);
1056 }
1057 
1058 MagickExport void PolicyComponentTerminus(void)
1059 {
1060  if (policy_semaphore == (SemaphoreInfo *) NULL)
1061  ActivateSemaphoreInfo(&policy_semaphore);
1062  LockSemaphoreInfo(policy_semaphore);
1063  if (policy_cache != (LinkedListInfo *) NULL)
1064  policy_cache=DestroyLinkedList(policy_cache,DestroyPolicyElement);
1065  UnlockSemaphoreInfo(policy_semaphore);
1066  DestroySemaphoreInfo(&policy_semaphore);
1067 }
1068 
1069 /*
1070 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1071 % %
1072 % %
1073 % %
1074 % S e t M a g i c k S e c u r i t y P o l i c y %
1075 % %
1076 % %
1077 % %
1078 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1079 %
1080 % SetMagickSecurityPolicy() sets the ImageMagick security policy. It returns
1081 % MagickFalse if the policy is already set or if the policy does not parse.
1082 %
1083 % The format of the SetMagickSecurityPolicy method is:
1084 %
1085 % MagickBooleanType SetMagickSecurityPolicy(const char *policy,
1086 % ExceptionInfo *exception)
1087 %
1088 % A description of each parameter follows:
1089 %
1090 % o policy: the security policy in the XML format.
1091 %
1092 % o exception: return any errors or warnings in this structure.
1093 %
1094 */
1095 MagickExport MagickBooleanType SetMagickSecurityPolicy(const char *policy,
1096  ExceptionInfo *exception)
1097 {
1098  PolicyInfo
1099  *p;
1100 
1101  MagickBooleanType
1102  status;
1103 
1104  assert(exception != (ExceptionInfo *) NULL);
1105  if (policy == (const char *) NULL)
1106  return(MagickFalse);
1107  if (IsPolicyCacheInstantiated(exception) == MagickFalse)
1108  return(MagickFalse);
1109  LockSemaphoreInfo(policy_semaphore);
1110  ResetLinkedListIterator(policy_cache);
1111  p=(PolicyInfo *) GetNextValueInLinkedList(policy_cache);
1112  if ((p != (PolicyInfo *) NULL) && (p->domain != UndefinedPolicyDomain))
1113  {
1114  UnlockSemaphoreInfo(policy_semaphore);
1115  return(MagickFalse);
1116  }
1117  UnlockSemaphoreInfo(policy_semaphore);
1118  status=LoadPolicyCache(policy_cache,policy,"[user-policy]",0,exception);
1119  if (status == MagickFalse)
1120  return(MagickFalse);
1121  return(ResourceComponentGenesis());
1122 }