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