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