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