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