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