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