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