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