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