]> granicus.if.org Git - imagemagick/blob - MagickCore/policy.c
Add check to ensure security policy is instantiated
[imagemagick] / MagickCore / policy.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                  PPPP    OOO   L      IIIII   CCCC  Y   Y                   %
6 %                  P   P  O   O  L        I    C       Y Y                    %
7 %                  PPPP   O   O  L        I    C        Y                     %
8 %                  P      O   O  L        I    C        Y                     %
9 %                  P       OOO   LLLLL  IIIII   CCCC    Y                     %
10 %                                                                             %
11 %                                                                             %
12 %                         MagickCore Policy Methods                           %
13 %                                                                             %
14 %                              Software Design                                %
15 %                                   Cristy                                    %
16 %                                 July 1992                                   %
17 %                                                                             %
18 %                                                                             %
19 %  Copyright 1999-2017 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://www.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 \f
40 /*
41   Include declarations.
42 */
43 #include "MagickCore/studio.h"
44 #include "MagickCore/client.h"
45 #include "MagickCore/configure.h"
46 #include "MagickCore/configure-private.h"
47 #include "MagickCore/exception.h"
48 #include "MagickCore/exception-private.h"
49 #include "MagickCore/memory_.h"
50 #include "MagickCore/monitor.h"
51 #include "MagickCore/monitor-private.h"
52 #include "MagickCore/option.h"
53 #include "MagickCore/policy.h"
54 #include "MagickCore/policy-private.h"
55 #include "MagickCore/resource-private.h"
56 #include "MagickCore/semaphore.h"
57 #include "MagickCore/string_.h"
58 #include "MagickCore/token.h"
59 #include "MagickCore/utility.h"
60 #include "MagickCore/utility-private.h"
61 #include "MagickCore/xml-tree.h"
62 #include "MagickCore/xml-tree-private.h"
63 \f
64 /*
65   Define declarations.
66 */
67 #define PolicyFilename  "policy.xml"
68 \f
69 /*
70   Typedef declarations.
71 */
72 struct _PolicyInfo
73 {
74   char
75     *path;
76
77   PolicyDomain
78     domain;
79
80   PolicyRights
81     rights;
82
83   char
84     *name,
85     *pattern,
86     *value;
87
88   MagickBooleanType
89     exempt,
90     stealth,
91     debug;
92
93   SemaphoreInfo
94     *semaphore;
95
96   size_t
97     signature;
98 };
99
100 typedef struct _PolicyMapInfo
101 {
102   const PolicyDomain
103     domain;
104
105   const PolicyRights
106     rights;
107
108   const char
109     *name,
110     *pattern,
111     *value;
112 } PolicyMapInfo;
113 \f
114 /*
115   Static declarations.
116 */
117 static const PolicyMapInfo
118   PolicyMap[] =
119   {
120     { UndefinedPolicyDomain, UndefinedPolicyRights, (const char *) NULL,
121       (const char *) NULL, (const char *) NULL }
122   };
123
124 static LinkedListInfo
125   *policy_cache = (LinkedListInfo *) NULL;
126
127 static SemaphoreInfo
128   *policy_semaphore = (SemaphoreInfo *) NULL;
129 \f
130 /*
131   Forward declarations.
132 */
133 static MagickBooleanType
134   IsPolicyCacheInstantiated(ExceptionInfo *),
135   LoadPolicyCache(LinkedListInfo *,const char *,const char *,const size_t,
136     ExceptionInfo *);
137 \f
138 /*
139 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
140 %                                                                             %
141 %                                                                             %
142 %                                                                             %
143 %  A c q u i r e P o l i c y C a c h e                                        %
144 %                                                                             %
145 %                                                                             %
146 %                                                                             %
147 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
148 %
149 %  AcquirePolicyCache() caches one or more policy configurations which provides
150 %  a mapping between policy attributes and a policy name.
151 %
152 %  The format of the AcquirePolicyCache method is:
153 %
154 %      LinkedListInfo *AcquirePolicyCache(const char *filename,
155 %        ExceptionInfo *exception)
156 %
157 %  A description of each parameter follows:
158 %
159 %    o filename: the policy configuration file name.
160 %
161 %    o exception: return any errors or warnings in this structure.
162 %
163 */
164 static LinkedListInfo *AcquirePolicyCache(const char *filename,
165   ExceptionInfo *exception)
166 {
167   LinkedListInfo
168     *cache;
169
170   MagickStatusType
171     status;
172
173   register ssize_t
174     i;
175
176   /*
177     Load external policy map.
178   */
179   cache=NewLinkedList(0);
180   if (cache == (LinkedListInfo *) NULL)
181     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
182   status=MagickTrue;
183 #if defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT)
184   status=LoadPolicyCache(cache,ZeroConfigurationPolicy,"[zero-configuration]",0,
185     exception);
186 #else
187   {
188     const StringInfo
189       *option;
190
191     LinkedListInfo
192       *options;
193
194     options=GetConfigureOptions(filename,exception);
195     option=(const StringInfo *) GetNextValueInLinkedList(options);
196     while (option != (const StringInfo *) NULL)
197     {
198       status&=LoadPolicyCache(cache,(const char *) GetStringInfoDatum(option),
199         GetStringInfoPath(option),0,exception);
200       option=(const StringInfo *) GetNextValueInLinkedList(options);
201     }
202     options=DestroyConfigureOptions(options);
203   }
204 #endif
205   /*
206     Load built-in policy map.
207   */
208   for (i=0; i < (ssize_t) (sizeof(PolicyMap)/sizeof(*PolicyMap)); i++)
209   {
210     PolicyInfo
211       *policy_info;
212
213     register const PolicyMapInfo
214       *p;
215
216     p=PolicyMap+i;
217     policy_info=(PolicyInfo *) AcquireMagickMemory(sizeof(*policy_info));
218     if (policy_info == (PolicyInfo *) NULL)
219       {
220         (void) ThrowMagickException(exception,GetMagickModule(),
221           ResourceLimitError,"MemoryAllocationFailed","`%s'",p->name);
222         continue;
223       }
224     (void) ResetMagickMemory(policy_info,0,sizeof(*policy_info));
225     policy_info->path=(char *) "[built-in]";
226     policy_info->domain=p->domain;
227     policy_info->rights=p->rights;
228     policy_info->name=(char *) p->name;
229     policy_info->pattern=(char *) p->pattern;
230     policy_info->value=(char *) p->value;
231     policy_info->exempt=MagickTrue;
232     policy_info->signature=MagickCoreSignature;
233     status&=AppendValueToLinkedList(cache,policy_info);
234     if (status == MagickFalse)
235       (void) ThrowMagickException(exception,GetMagickModule(),
236         ResourceLimitError,"MemoryAllocationFailed","`%s'",policy_info->name);
237   }
238   return(cache);
239 }
240 \f
241 /*
242 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
243 %                                                                             %
244 %                                                                             %
245 %                                                                             %
246 +   G e t P o l i c y I n f o                                                 %
247 %                                                                             %
248 %                                                                             %
249 %                                                                             %
250 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
251 %
252 %  GetPolicyInfo() searches the policy list for the specified name and if found
253 %  returns attributes for that policy.
254 %
255 %  The format of the GetPolicyInfo method is:
256 %
257 %      PolicyInfo *GetPolicyInfo(const char *name,ExceptionInfo *exception)
258 %
259 %  A description of each parameter follows:
260 %
261 %    o name: the policy name.
262 %
263 %    o exception: return any errors or warnings in this structure.
264 %
265 */
266 static PolicyInfo *GetPolicyInfo(const char *name,ExceptionInfo *exception)
267 {
268   char
269     policyname[MagickPathExtent];
270
271   PolicyDomain
272     domain;
273
274   register PolicyInfo
275     *p;
276
277   register char
278     *q;
279
280   assert(exception != (ExceptionInfo *) NULL);
281   if (IsPolicyCacheInstantiated(exception) == MagickFalse)
282     return((PolicyInfo *) NULL);
283   /*
284     Strip names of whitespace.
285   */
286   *policyname='\0';
287   if (name != (const char *) NULL)
288     (void) CopyMagickString(policyname,name,MagickPathExtent);
289   for (q=policyname; *q != '\0'; q++)
290   {
291     if (isspace((int) ((unsigned char) *q)) == 0)
292       continue;
293     (void) CopyMagickString(q,q+1,MagickPathExtent);
294     q--;
295   }
296   /*
297     Strip domain from policy name (e.g. resource:map).
298   */
299   domain=UndefinedPolicyDomain;
300   for (q=policyname; *q != '\0'; q++)
301   {
302     if (*q != ':')
303       continue;
304     *q='\0';
305     domain=(PolicyDomain) ParseCommandOption(MagickPolicyDomainOptions,
306       MagickTrue,policyname);
307     (void) CopyMagickString(policyname,q+1,MagickPathExtent);
308     break;
309   }
310   /*
311     Search for policy tag.
312   */
313   LockSemaphoreInfo(policy_semaphore);
314   ResetLinkedListIterator(policy_cache);
315   p=(PolicyInfo *) GetNextValueInLinkedList(policy_cache);
316   if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0))
317     {
318       UnlockSemaphoreInfo(policy_semaphore);
319       return(p);
320     }
321   while (p != (PolicyInfo *) NULL)
322   {
323     if ((domain == UndefinedPolicyDomain) || (p->domain == domain))
324       if (LocaleCompare(policyname,p->name) == 0)
325         break;
326     p=(PolicyInfo *) GetNextValueInLinkedList(policy_cache);
327   }
328   if (p != (PolicyInfo *) NULL)
329     (void) InsertValueInLinkedList(policy_cache,0,
330       RemoveElementByValueFromLinkedList(policy_cache,p));
331   UnlockSemaphoreInfo(policy_semaphore);
332   return(p);
333 }
334 \f
335 /*
336 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
337 %                                                                             %
338 %                                                                             %
339 %                                                                             %
340 %   G e t P o l i c y I n f o L i s t                                         %
341 %                                                                             %
342 %                                                                             %
343 %                                                                             %
344 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
345 %
346 %  GetPolicyInfoList() returns any policies that match the specified pattern.
347 %
348 %  The format of the GetPolicyInfoList function is:
349 %
350 %      const PolicyInfo **GetPolicyInfoList(const char *pattern,
351 %        size_t *number_policies,ExceptionInfo *exception)
352 %
353 %  A description of each parameter follows:
354 %
355 %    o pattern: Specifies a pointer to a text string containing a pattern.
356 %
357 %    o number_policies:  returns the number of policies in the list.
358 %
359 %    o exception: return any errors or warnings in this structure.
360 %
361 */
362 MagickExport const PolicyInfo **GetPolicyInfoList(const char *pattern,
363   size_t *number_policies,ExceptionInfo *exception)
364 {
365   const PolicyInfo
366     **policies;
367
368   register const PolicyInfo
369     *p;
370
371   register ssize_t
372     i;
373
374   /*
375     Allocate policy list.
376   */
377   assert(pattern != (char *) NULL);
378   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
379   assert(number_policies != (size_t *) NULL);
380   *number_policies=0;
381   p=GetPolicyInfo("*",exception);
382   if (p == (const PolicyInfo *) NULL)
383     return((const PolicyInfo **) NULL);
384   policies=(const PolicyInfo **) AcquireQuantumMemory((size_t)
385     GetNumberOfElementsInLinkedList(policy_cache)+1UL,sizeof(*policies));
386   if (policies == (const PolicyInfo **) NULL)
387     return((const PolicyInfo **) NULL);
388   /*
389     Generate policy list.
390   */
391   LockSemaphoreInfo(policy_semaphore);
392   ResetLinkedListIterator(policy_cache);
393   p=(const PolicyInfo *) GetNextValueInLinkedList(policy_cache);
394   for (i=0; p != (const PolicyInfo *) NULL; )
395   {
396     if ((p->stealth == MagickFalse) &&
397         (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
398       policies[i++]=p;
399     p=(const PolicyInfo *) GetNextValueInLinkedList(policy_cache);
400   }
401   UnlockSemaphoreInfo(policy_semaphore);
402   policies[i]=(PolicyInfo *) NULL;
403   *number_policies=(size_t) i;
404   return(policies);
405 }
406 \f
407 /*
408 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
409 %                                                                             %
410 %                                                                             %
411 %                                                                             %
412 %   G e t P o l i c y L i s t                                                 %
413 %                                                                             %
414 %                                                                             %
415 %                                                                             %
416 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
417 %
418 %  GetPolicyList() returns any policies that match the specified pattern.
419 %
420 %  The format of the GetPolicyList function is:
421 %
422 %      char **GetPolicyList(const char *pattern,size_t *number_policies,
423 %        ExceptionInfo *exception)
424 %
425 %  A description of each parameter follows:
426 %
427 %    o pattern: a pointer to a text string containing a pattern.
428 %
429 %    o number_policies:  returns the number of policies in the list.
430 %
431 %    o exception: return any errors or warnings in this structure.
432 %
433 */
434 MagickExport char **GetPolicyList(const char *pattern,
435   size_t *number_policies,ExceptionInfo *exception)
436 {
437   char
438     **policies;
439
440   register const PolicyInfo
441     *p;
442
443   register ssize_t
444     i;
445
446   /*
447     Allocate policy list.
448   */
449   assert(pattern != (char *) NULL);
450   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern);
451   assert(number_policies != (size_t *) NULL);
452   *number_policies=0;
453   p=GetPolicyInfo("*",exception);
454   if (p == (const PolicyInfo *) NULL)
455     return((char **) NULL);
456   policies=(char **) AcquireQuantumMemory((size_t)
457     GetNumberOfElementsInLinkedList(policy_cache)+1UL,sizeof(*policies));
458   if (policies == (char **) NULL)
459     return((char **) NULL);
460   /*
461     Generate policy list.
462   */
463   LockSemaphoreInfo(policy_semaphore);
464   ResetLinkedListIterator(policy_cache);
465   p=(const PolicyInfo *) GetNextValueInLinkedList(policy_cache);
466   for (i=0; p != (const PolicyInfo *) NULL; )
467   {
468     if ((p->stealth == MagickFalse) &&
469         (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
470       policies[i++]=ConstantString(p->name);
471     p=(const PolicyInfo *) GetNextValueInLinkedList(policy_cache);
472   }
473   UnlockSemaphoreInfo(policy_semaphore);
474   policies[i]=(char *) NULL;
475   *number_policies=(size_t) i;
476   return(policies);
477 }
478 \f
479 /*
480 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
481 %                                                                             %
482 %                                                                             %
483 %                                                                             %
484 %   G e t P o l i c y V a l u e                                               %
485 %                                                                             %
486 %                                                                             %
487 %                                                                             %
488 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
489 %
490 %  GetPolicyValue() returns the value associated with the named policy.
491 %
492 %  The format of the GetPolicyValue method is:
493 %
494 %      char *GetPolicyValue(const char *name)
495 %
496 %  A description of each parameter follows:
497 %
498 %    o policy_info:  The policy info.
499 %
500 */
501 MagickExport char *GetPolicyValue(const char *name)
502 {
503   const char
504     *value;
505
506   const PolicyInfo
507     *policy_info;
508
509   ExceptionInfo
510     *exception;
511
512   assert(name != (const char *) NULL);
513   (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",name);
514   exception=AcquireExceptionInfo();
515   policy_info=GetPolicyInfo(name,exception);
516   exception=DestroyExceptionInfo(exception);
517   if (policy_info == (PolicyInfo *) NULL)
518     return((char *) NULL);
519   value=policy_info->value;
520   if ((value == (const char *) NULL) || (*value == '\0'))
521     return((char *) NULL);
522   return(ConstantString(value));
523 }
524 \f
525 /*
526 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
527 %                                                                             %
528 %                                                                             %
529 %                                                                             %
530 +   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                         %
531 %                                                                             %
532 %                                                                             %
533 %                                                                             %
534 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
535 %
536 %  IsPolicyCacheInstantiated() determines if the policy list is instantiated.
537 %  If not, it instantiates the list and returns it.
538 %
539 %  The format of the IsPolicyInstantiated method is:
540 %
541 %      MagickBooleanType IsPolicyCacheInstantiated(ExceptionInfo *exception)
542 %
543 %  A description of each parameter follows.
544 %
545 %    o exception: return any errors or warnings in this structure.
546 %
547 */
548 static MagickBooleanType IsPolicyCacheInstantiated(ExceptionInfo *exception)
549 {
550   if (policy_cache == (LinkedListInfo *) NULL)
551     {
552       if (policy_semaphore == (SemaphoreInfo *) NULL)
553         ActivateSemaphoreInfo(&policy_semaphore);
554       LockSemaphoreInfo(policy_semaphore);
555       if (policy_cache == (LinkedListInfo *) NULL)
556         policy_cache=AcquirePolicyCache(PolicyFilename,exception);
557       UnlockSemaphoreInfo(policy_semaphore);
558     }
559   return(policy_cache != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
560 }
561 \f
562 /*
563 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
564 %                                                                             %
565 %                                                                             %
566 %                                                                             %
567 %   I s R i g h t s A u t h o r i z e d                                       %
568 %                                                                             %
569 %                                                                             %
570 %                                                                             %
571 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
572 %
573 %  IsRightsAuthorized() returns MagickTrue if the policy authorizes the
574 %  requested rights for the specified domain.
575 %
576 %  The format of the IsRightsAuthorized method is:
577 %
578 %      MagickBooleanType IsRightsAuthorized(const PolicyDomain domain,
579 %        const PolicyRights rights,const char *pattern)
580 %
581 %  A description of each parameter follows:
582 %
583 %    o domain: the policy domain.
584 %
585 %    o rights: the policy rights.
586 %
587 %    o pattern: the coder, delegate, filter, or path pattern.
588 %
589 */
590 MagickExport MagickBooleanType IsRightsAuthorized(const PolicyDomain domain,
591   const PolicyRights rights,const char *pattern)
592 {
593   const PolicyInfo
594     *policy_info;
595
596   ExceptionInfo
597     *exception;
598
599   MagickBooleanType
600     authorized;
601
602   register PolicyInfo
603     *p;
604
605   (void) LogMagickEvent(PolicyEvent,GetMagickModule(),
606     "Domain: %s; rights=%s; pattern=\"%s\" ...",
607     CommandOptionToMnemonic(MagickPolicyDomainOptions,domain),
608     CommandOptionToMnemonic(MagickPolicyRightsOptions,rights),pattern);
609   exception=AcquireExceptionInfo();
610   policy_info=GetPolicyInfo("*",exception);
611   exception=DestroyExceptionInfo(exception);
612   if (policy_info == (PolicyInfo *) NULL)
613     return(MagickTrue);
614   authorized=MagickTrue;
615   LockSemaphoreInfo(policy_semaphore);
616   ResetLinkedListIterator(policy_cache);
617   p=(PolicyInfo *) GetNextValueInLinkedList(policy_cache);
618   while (p != (PolicyInfo *) NULL)
619   {
620     if ((p->domain == domain) &&
621         (GlobExpression(pattern,p->pattern,MagickFalse) != MagickFalse))
622       {
623         if ((rights & ReadPolicyRights) != 0)
624           authorized=(p->rights & ReadPolicyRights) != 0 ? MagickTrue :
625             MagickFalse;
626         if ((rights & WritePolicyRights) != 0)
627           authorized=(p->rights & WritePolicyRights) != 0 ? MagickTrue :
628             MagickFalse;
629         if ((rights & ExecutePolicyRights) != 0)
630           authorized=(p->rights & ExecutePolicyRights) != 0 ? MagickTrue :
631             MagickFalse;
632       }
633     p=(PolicyInfo *) GetNextValueInLinkedList(policy_cache);
634   }
635   UnlockSemaphoreInfo(policy_semaphore);
636   return(authorized);
637 }
638 \f
639 /*
640 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
641 %                                                                             %
642 %                                                                             %
643 %                                                                             %
644 %  L i s t P o l i c y I n f o                                                %
645 %                                                                             %
646 %                                                                             %
647 %                                                                             %
648 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
649 %
650 %  ListPolicyInfo() lists policies to the specified file.
651 %
652 %  The format of the ListPolicyInfo method is:
653 %
654 %      MagickBooleanType ListPolicyInfo(FILE *file,ExceptionInfo *exception)
655 %
656 %  A description of each parameter follows.
657 %
658 %    o file:  List policy names to this file handle.
659 %
660 %    o exception: return any errors or warnings in this structure.
661 %
662 */
663 MagickExport MagickBooleanType ListPolicyInfo(FILE *file,
664   ExceptionInfo *exception)
665 {
666   const char
667     *path,
668     *domain;
669
670   const PolicyInfo
671     **policy_info;
672
673   register ssize_t
674     i;
675
676   size_t
677     number_policies;
678
679   /*
680     List name and attributes of each policy in the list.
681   */
682   if (file == (const FILE *) NULL)
683     file=stdout;
684   policy_info=GetPolicyInfoList("*",&number_policies,exception);
685   if (policy_info == (const PolicyInfo **) NULL)
686     return(MagickFalse);
687   path=(const char *) NULL;
688   for (i=0; i < (ssize_t) number_policies; i++)
689   {
690     if (policy_info[i]->stealth != MagickFalse)
691       continue;
692     if (((path == (const char *) NULL) ||
693          (LocaleCompare(path,policy_info[i]->path) != 0)) &&
694          (policy_info[i]->path != (char *) NULL))
695       (void) FormatLocaleFile(file,"\nPath: %s\n",policy_info[i]->path);
696     path=policy_info[i]->path;
697     domain=CommandOptionToMnemonic(MagickPolicyDomainOptions,
698       policy_info[i]->domain);
699     (void) FormatLocaleFile(file,"  Policy: %s\n",domain);
700     if ((policy_info[i]->domain == CachePolicyDomain) ||
701         (policy_info[i]->domain == ResourcePolicyDomain) ||
702         (policy_info[i]->domain == SystemPolicyDomain))
703       {
704         if (policy_info[i]->name != (char *) NULL)
705           (void) FormatLocaleFile(file,"    name: %s\n",policy_info[i]->name);
706         if (policy_info[i]->value != (char *) NULL)
707           (void) FormatLocaleFile(file,"    value: %s\n",policy_info[i]->value);
708       }
709     else
710       {
711         (void) FormatLocaleFile(file,"    rights: ");
712         if (policy_info[i]->rights == NoPolicyRights)
713           (void) FormatLocaleFile(file,"None ");
714         if ((policy_info[i]->rights & ReadPolicyRights) != 0)
715           (void) FormatLocaleFile(file,"Read ");
716         if ((policy_info[i]->rights & WritePolicyRights) != 0)
717           (void) FormatLocaleFile(file,"Write ");
718         if ((policy_info[i]->rights & ExecutePolicyRights) != 0)
719           (void) FormatLocaleFile(file,"Execute ");
720         (void) FormatLocaleFile(file,"\n");
721         if (policy_info[i]->pattern != (char *) NULL)
722           (void) FormatLocaleFile(file,"    pattern: %s\n",
723             policy_info[i]->pattern);
724       }
725   }
726   policy_info=(const PolicyInfo **) RelinquishMagickMemory((void *)
727     policy_info);
728   (void) fflush(file);
729   return(MagickTrue);
730 }
731 \f
732 /*
733 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
734 %                                                                             %
735 %                                                                             %
736 %                                                                             %
737 +   L o a d P o l i c y C a c h e                                             %
738 %                                                                             %
739 %                                                                             %
740 %                                                                             %
741 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
742 %
743 %  LoadPolicyCache() loads the policy configurations which provides a mapping
744 %  between policy attributes and a policy domain.
745 %
746 %  The format of the LoadPolicyCache method is:
747 %
748 %      MagickBooleanType LoadPolicyCache(LinkedListInfo *cache,const char *xml,
749 %        const char *filename,const size_t depth,ExceptionInfo *exception)
750 %
751 %  A description of each parameter follows:
752 %
753 %    o xml:  The policy list in XML format.
754 %
755 %    o filename:  The policy list filename.
756 %
757 %    o depth: depth of <include /> statements.
758 %
759 %    o exception: return any errors or warnings in this structure.
760 %
761 */
762 static MagickBooleanType LoadPolicyCache(LinkedListInfo *cache,const char *xml,
763   const char *filename,const size_t depth,ExceptionInfo *exception)
764 {
765   char
766     keyword[MagickPathExtent],
767     *token;
768
769   const char
770     *q;
771
772   MagickStatusType
773     status;
774
775   PolicyInfo
776     *policy_info;
777
778   size_t
779     extent;
780
781   /*
782     Load the policy map file.
783   */
784   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
785     "Loading policy file \"%s\" ...",filename);
786   if (xml == (char *) NULL)
787     return(MagickFalse);
788   status=MagickTrue;
789   policy_info=(PolicyInfo *) NULL;
790   token=AcquireString(xml);
791   extent=strlen(token)+MagickPathExtent;
792   for (q=(const char *) xml; *q != '\0'; )
793   {
794     /*
795       Interpret XML.
796     */
797     GetNextToken(q,&q,extent,token);
798     if (*token == '\0')
799       break;
800     (void) CopyMagickString(keyword,token,MagickPathExtent);
801     if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0)
802       {
803         /*
804           Docdomain element.
805         */
806         while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0'))
807           GetNextToken(q,&q,extent,token);
808         continue;
809       }
810     if (LocaleNCompare(keyword,"<!--",4) == 0)
811       {
812         /*
813           Comment element.
814         */
815         while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0'))
816           GetNextToken(q,&q,extent,token);
817         continue;
818       }
819     if (LocaleCompare(keyword,"<include") == 0)
820       {
821         /*
822           Include element.
823         */
824         while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0'))
825         {
826           (void) CopyMagickString(keyword,token,MagickPathExtent);
827           GetNextToken(q,&q,extent,token);
828           if (*token != '=')
829             continue;
830           GetNextToken(q,&q,extent,token);
831           if (LocaleCompare(keyword,"file") == 0)
832             {
833               if (depth > 200)
834                 (void) ThrowMagickException(exception,GetMagickModule(),
835                   ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token);
836               else
837                 {
838                   char
839                     path[MagickPathExtent],
840                     *file_xml;
841
842                   GetPathComponent(filename,HeadPath,path);
843                   if (*path != '\0')
844                     (void) ConcatenateMagickString(path,DirectorySeparator,
845                       MagickPathExtent);
846                   if (*token == *DirectorySeparator)
847                     (void) CopyMagickString(path,token,MagickPathExtent);
848                   else
849                     (void) ConcatenateMagickString(path,token,MagickPathExtent);
850                   file_xml=FileToXML(path,~0UL);
851                   if (file_xml != (char *) NULL)
852                     {
853                       status&=LoadPolicyCache(cache,file_xml,path,
854                         depth+1,exception);
855                       file_xml=DestroyString(file_xml);
856                     }
857                 }
858             }
859         }
860         continue;
861       }
862     if (LocaleCompare(keyword,"<policy") == 0)
863       {
864         /*
865           Policy element.
866         */
867         policy_info=(PolicyInfo *) AcquireMagickMemory(sizeof(*policy_info));
868         if (policy_info == (PolicyInfo *) NULL)
869           ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
870         (void) ResetMagickMemory(policy_info,0,sizeof(*policy_info));
871         policy_info->path=ConstantString(filename);
872         policy_info->exempt=MagickFalse;
873         policy_info->signature=MagickCoreSignature;
874         continue;
875       }
876     if (policy_info == (PolicyInfo *) NULL)
877       continue;
878     if ((LocaleCompare(keyword,"/>") == 0) ||
879         (LocaleCompare(keyword,"</policy>") == 0))
880       {
881         status=AppendValueToLinkedList(cache,policy_info);
882         if (status == MagickFalse)
883           (void) ThrowMagickException(exception,GetMagickModule(),
884             ResourceLimitError,"MemoryAllocationFailed","`%s'",
885             policy_info->name);
886         policy_info=(PolicyInfo *) NULL;
887         continue;
888       }
889     GetNextToken(q,(const char **) NULL,extent,token);
890     if (*token != '=')
891       continue;
892     GetNextToken(q,&q,extent,token);
893     GetNextToken(q,&q,extent,token);
894     switch (*keyword)
895     {
896       case 'D':
897       case 'd':
898       {
899         if (LocaleCompare((char *) keyword,"domain") == 0)
900           {
901             policy_info->domain=(PolicyDomain) ParseCommandOption(
902               MagickPolicyDomainOptions,MagickTrue,token);
903             break;
904           }
905         break;
906       }
907       case 'N':
908       case 'n':
909       {
910         if (LocaleCompare((char *) keyword,"name") == 0)
911           {
912             policy_info->name=ConstantString(token);
913             break;
914           }
915         break;
916       }
917       case 'P':
918       case 'p':
919       {
920         if (LocaleCompare((char *) keyword,"pattern") == 0)
921           {
922             policy_info->pattern=ConstantString(token);
923             break;
924           }
925         break;
926       }
927       case 'R':
928       case 'r':
929       {
930         if (LocaleCompare((char *) keyword,"rights") == 0)
931           {
932             policy_info->rights=(PolicyRights) ParseCommandOption(
933               MagickPolicyRightsOptions,MagickTrue,token);
934             break;
935           }
936         break;
937       }
938       case 'S':
939       case 's':
940       {
941         if (LocaleCompare((char *) keyword,"stealth") == 0)
942           {
943             policy_info->stealth=IsStringTrue(token);
944             break;
945           }
946         break;
947       }
948       case 'V':
949       case 'v':
950       {
951         if (LocaleCompare((char *) keyword,"value") == 0)
952           {
953             policy_info->value=ConstantString(token);
954             break;
955           }
956         break;
957       }
958       default:
959         break;
960     }
961   }
962   token=(char *) RelinquishMagickMemory(token);
963   return(status != 0 ? MagickTrue : MagickFalse);
964 }
965 \f
966 /*
967 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
968 %                                                                             %
969 %                                                                             %
970 %                                                                             %
971 +   P o l i c y C o m p o n e n t G e n e s i s                               %
972 %                                                                             %
973 %                                                                             %
974 %                                                                             %
975 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
976 %
977 %  PolicyComponentGenesis() instantiates the policy component.
978 %
979 %  The format of the PolicyComponentGenesis method is:
980 %
981 %      MagickBooleanType PolicyComponentGenesis(void)
982 %
983 */
984 MagickPrivate MagickBooleanType PolicyComponentGenesis(void)
985 {
986   if (policy_semaphore == (SemaphoreInfo *) NULL)
987     policy_semaphore=AcquireSemaphoreInfo();
988   return(MagickTrue);
989 }
990 \f
991 /*
992 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
993 %                                                                             %
994 %                                                                             %
995 %                                                                             %
996 +   P o l i c y C o m p o n e n t T e r m i n u s                             %
997 %                                                                             %
998 %                                                                             %
999 %                                                                             %
1000 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1001 %
1002 %  PolicyComponentTerminus() destroys the policy component.
1003 %
1004 %  The format of the PolicyComponentTerminus method is:
1005 %
1006 %      PolicyComponentTerminus(void)
1007 %
1008 */
1009
1010 static void *DestroyPolicyElement(void *policy_info)
1011 {
1012   register PolicyInfo
1013     *p;
1014
1015   p=(PolicyInfo *) policy_info;
1016   if (p->exempt == MagickFalse)
1017     {
1018       if (p->value != (char *) NULL)
1019         p->value=DestroyString(p->value);
1020       if (p->pattern != (char *) NULL)
1021         p->pattern=DestroyString(p->pattern);
1022       if (p->name != (char *) NULL)
1023         p->name=DestroyString(p->name);
1024       if (p->path != (char *) NULL)
1025         p->path=DestroyString(p->path);
1026     }
1027   p=(PolicyInfo *) RelinquishMagickMemory(p);
1028   return((void *) NULL);
1029 }
1030
1031 MagickPrivate void PolicyComponentTerminus(void)
1032 {
1033   if (policy_semaphore == (SemaphoreInfo *) NULL)
1034     ActivateSemaphoreInfo(&policy_semaphore);
1035   LockSemaphoreInfo(policy_semaphore);
1036   if (policy_cache != (LinkedListInfo *) NULL)
1037     policy_cache=DestroyLinkedList(policy_cache,DestroyPolicyElement);
1038   UnlockSemaphoreInfo(policy_semaphore);
1039   RelinquishSemaphoreInfo(&policy_semaphore);
1040 }
1041 \f
1042 /*
1043 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1044 %                                                                             %
1045 %                                                                             %
1046 %                                                                             %
1047 %  S e t M a g i c k S e c u r i t y P o l i c y                              %
1048 %                                                                             %
1049 %                                                                             %
1050 %                                                                             %
1051 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1052 %
1053 %  SetMagickSecurityPolicy() sets the ImageMagick security policy.  It returns
1054 %  MagickFalse if the policy is already set or if the policy does not parse.
1055 %
1056 %  The format of the SetMagickSecurityPolicy method is:
1057 %
1058 %      MagickBooleanType SetMagickSecurityPolicy(const char *policy,
1059 %        ExceptionInfo *exception)
1060 %
1061 %  A description of each parameter follows:
1062 %
1063 %    o policy: the security policy in the XML format.
1064 %
1065 %    o exception: return any errors or warnings in this structure.
1066 %
1067 */
1068 MagickExport MagickBooleanType SetMagickSecurityPolicy(const char *policy,
1069   ExceptionInfo *exception)
1070 {
1071   PolicyInfo
1072     *p;
1073   
1074   MagickBooleanType
1075     status;
1076   
1077   if (IsPolicyCacheInstantiated(exception) == MagickFalse)
1078     return((PolicyInfo *) NULL);
1079   LockSemaphoreInfo(policy_semaphore);
1080   ResetLinkedListIterator(policy_cache);
1081   p=(PolicyInfo *) GetNextValueInLinkedList(policy_cache);
1082   if ((p != (PolicyInfo *) NULL) && (p->domain != UndefinedPolicyDomain))
1083     {
1084       UnlockSemaphoreInfo(policy_semaphore);
1085       return(MagickFalse);
1086     }
1087   UnlockSemaphoreInfo(policy_semaphore);
1088   status=LoadPolicyCache(policy_cache,policy,"[user-policy]",0,exception);
1089   if (status == MagickFalse)
1090     return(MagickFalse);
1091   return(ResourceComponentGenesis());
1092 }