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