40#include "magick/studio.h"
41#include "magick/client.h"
42#include "magick/configure.h"
43#include "magick/exception.h"
44#include "magick/exception-private.h"
45#include "magick/locale_.h"
46#include "magick/memory_.h"
47#include "magick/monitor.h"
48#include "magick/monitor-private.h"
49#include "magick/option.h"
50#include "magick/policy.h"
51#include "magick/policy-private.h"
52#include "magick/resource_.h"
53#include "magick/semaphore.h"
54#include "magick/string_.h"
55#include "magick/token.h"
56#include "magick/utility.h"
57#include "magick/utility-private.h"
58#include "magick/xml-tree.h"
59#include "magick/xml-tree-private.h"
60#if defined(MAGICKCORE_XML_DELEGATE)
61# include <libxml/parser.h>
62# include <libxml/tree.h>
68#define PolicyFilename "policy.xml"
121 { UndefinedPolicyDomain, UndefinedPolicyRights, (
const char *) NULL,
122 (
const char *) NULL, (
const char *) NULL }
134static MagickBooleanType
136 LoadPolicyCache(
LinkedListInfo *,
const char *,
const char *,
const size_t,
180 cache=NewLinkedList(0);
182 ThrowFatalException(ResourceLimitFatalError,
"MemoryAllocationFailed");
184#if MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
185 magick_unreferenced(filename);
186 status=LoadPolicyCache(cache,ZeroConfigurationPolicy,
"[zero-configuration]",0,
188 if (status == MagickFalse)
189 CatchException(exception);
198 options=GetConfigureOptions(filename,exception);
199 option=(
const StringInfo *) GetNextValueInLinkedList(options);
202 status&=LoadPolicyCache(cache,(
const char *) GetStringInfoDatum(option),
203 GetStringInfoPath(option),0,exception);
204 if (status == MagickFalse)
205 CatchException(exception);
206 option=(
const StringInfo *) GetNextValueInLinkedList(options);
208 options=DestroyConfigureOptions(options);
214 for (i=0; i < (ssize_t) (
sizeof(PolicyMap)/
sizeof(*PolicyMap)); i++)
223 policy_info=(
PolicyInfo *) AcquireMagickMemory(
sizeof(*policy_info));
226 (void) ThrowMagickException(exception,GetMagickModule(),
227 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",
228 p->name == (
char *) NULL ?
"" : p->name);
229 CatchException(exception);
233 (void) memset(policy_info,0,
sizeof(*policy_info));
234 policy_info->path=(
char *)
"[built-in]";
235 policy_info->domain=p->domain;
236 policy_info->rights=p->rights;
237 policy_info->name=(
char *) p->name;
238 policy_info->pattern=(
char *) p->pattern;
239 policy_info->value=(
char *) p->value;
240 policy_info->exempt=MagickTrue;
241 policy_info->signature=MagickCoreSignature;
242 status&=AppendValueToLinkedList(cache,policy_info);
243 if (status == MagickFalse)
245 (void) ThrowMagickException(exception,GetMagickModule(),
246 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",
247 p->name == (
char *) NULL ?
"" : p->name);
248 CatchException(exception);
251 if (status == MagickFalse)
252 CatchException(exception);
284 policyname[MagickPathExtent];
296 if (IsPolicyCacheInstantiated(exception) == MagickFalse)
302 if (name != (
const char *) NULL)
303 (void) CopyMagickString(policyname,name,MagickPathExtent);
304 for (q=policyname; *q !=
'\0'; q++)
306 if (isspace((
int) ((
unsigned char) *q)) == 0)
308 (void) CopyMagickString(q,q+1,MagickPathExtent);
314 domain=UndefinedPolicyDomain;
315 for (q=policyname; *q !=
'\0'; q++)
320 domain=(PolicyDomain) ParseCommandOption(MagickPolicyDomainOptions,
321 MagickTrue,policyname);
322 (void) CopyMagickString(policyname,q+1,MagickPathExtent);
328 LockSemaphoreInfo(policy_semaphore);
329 ResetLinkedListIterator(policy_cache);
330 p=(
PolicyInfo *) GetNextValueInLinkedList(policy_cache);
331 if ((name == (
const char *) NULL) || (LocaleCompare(name,
"*") == 0))
333 UnlockSemaphoreInfo(policy_semaphore);
338 if ((domain == UndefinedPolicyDomain) || (p->domain == domain))
339 if (LocaleCompare(policyname,p->name) == 0)
341 p=(
PolicyInfo *) GetNextValueInLinkedList(policy_cache);
344 (
void) InsertValueInLinkedList(policy_cache,0,
345 RemoveElementByValueFromLinkedList(policy_cache,p));
346 UnlockSemaphoreInfo(policy_semaphore);
377MagickExport
const PolicyInfo **GetPolicyInfoList(
const char *pattern,
392 assert(pattern != (
char *) NULL);
393 assert(number_policies != (
size_t *) NULL);
394 if (IsEventLogging() != MagickFalse)
395 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",pattern);
397 p=GetPolicyInfo(
"*",exception);
400 policies=(
const PolicyInfo **) AcquireQuantumMemory((
size_t)
401 GetNumberOfElementsInLinkedList(policy_cache)+1UL,
sizeof(*policies));
407 LockSemaphoreInfo(policy_semaphore);
408 ResetLinkedListIterator(policy_cache);
409 p=(
const PolicyInfo *) GetNextValueInLinkedList(policy_cache);
412 if ((p->stealth == MagickFalse) &&
413 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
415 p=(
const PolicyInfo *) GetNextValueInLinkedList(policy_cache);
417 UnlockSemaphoreInfo(policy_semaphore);
419 *number_policies=(size_t) i;
451static char *AcquirePolicyString(
const char *source,
const size_t pad)
460 if (source != (
char *) NULL)
461 length+=strlen(source);
462 destination=(
char *) NULL;
464 destination=(
char *) AcquireMagickMemory((length+pad)*
sizeof(*destination));
465 if (destination == (
char *) NULL)
466 ThrowFatalException(ResourceLimitFatalError,
"UnableToAcquireString");
467 if (source != (
char *) NULL)
468 (
void) memcpy(destination,source,length*
sizeof(*destination));
469 destination[length]=
'\0';
473MagickExport
char **GetPolicyList(
const char *pattern,
size_t *number_policies,
488 assert(pattern != (
char *) NULL);
489 assert(number_policies != (
size_t *) NULL);
490 if (IsEventLogging() != MagickFalse)
491 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",pattern);
493 p=GetPolicyInfo(
"*",exception);
495 return((
char **) NULL);
496 policies=(
char **) AcquireQuantumMemory((
size_t)
497 GetNumberOfElementsInLinkedList(policy_cache)+1UL,
sizeof(*policies));
498 if (policies == (
char **) NULL)
499 return((
char **) NULL);
503 LockSemaphoreInfo(policy_semaphore);
504 ResetLinkedListIterator(policy_cache);
505 p=(
const PolicyInfo *) GetNextValueInLinkedList(policy_cache);
508 if ((p->stealth == MagickFalse) &&
509 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
510 policies[i++]=AcquirePolicyString(p->name,1);
511 p=(
const PolicyInfo *) GetNextValueInLinkedList(policy_cache);
513 UnlockSemaphoreInfo(policy_semaphore);
514 policies[i]=(
char *) NULL;
515 *number_policies=(size_t) i;
541MagickExport
char *GetPolicyValue(
const char *name)
552 assert(name != (
const char *) NULL);
553 if (IsEventLogging() != MagickFalse)
554 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",name);
555 exception=AcquireExceptionInfo();
556 policy_info=GetPolicyInfo(name,exception);
557 exception=DestroyExceptionInfo(exception);
559 return((
char *) NULL);
560 value=policy_info->value;
561 if ((value == (
const char *) NULL) || (*value ==
'\0'))
562 return((
char *) NULL);
563 return(AcquirePolicyString(value,1));
589static MagickBooleanType IsPolicyCacheInstantiated(
ExceptionInfo *exception)
593 GetMaxMemoryRequest();
595 ActivateSemaphoreInfo(&policy_semaphore);
596 LockSemaphoreInfo(policy_semaphore);
598 policy_cache=AcquirePolicyCache(PolicyFilename,exception);
599 UnlockSemaphoreInfo(policy_semaphore);
601 return(policy_cache != (
LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
632MagickExport MagickBooleanType IsRightsAuthorized(
const PolicyDomain domain,
633 const PolicyRights rights,
const char *pattern)
647 if ((GetLogEventMask() & PolicyEvent) != 0)
648 (void) LogMagickEvent(PolicyEvent,GetMagickModule(),
649 "Domain: %s; rights=%s; pattern=\"%s\" ...",
650 CommandOptionToMnemonic(MagickPolicyDomainOptions,domain),
651 CommandOptionToMnemonic(MagickPolicyRightsOptions,rights),pattern);
652 exception=AcquireExceptionInfo();
653 policy_info=GetPolicyInfo(
"*",exception);
654 exception=DestroyExceptionInfo(exception);
657 authorized=MagickTrue;
658 LockSemaphoreInfo(policy_semaphore);
659 ResetLinkedListIterator(policy_cache);
660 p=(
PolicyInfo *) GetNextValueInLinkedList(policy_cache);
664 *real_pattern = (
char *) pattern;
666 if (p->domain == domain)
668 if (p->domain == PathPolicyDomain)
670 real_pattern=realpath_utf8(pattern);
671 if (real_pattern == (
char *) NULL)
672 real_pattern=AcquireString(pattern);
674 if (GlobExpression(real_pattern,p->pattern,MagickFalse) != MagickFalse)
676 if ((rights & ReadPolicyRights) != 0)
677 authorized=(p->rights & ReadPolicyRights) != 0 ? MagickTrue :
679 if ((rights & WritePolicyRights) != 0)
680 authorized=(p->rights & WritePolicyRights) != 0 ? MagickTrue :
682 if ((rights & ExecutePolicyRights) != 0)
683 authorized=(p->rights & ExecutePolicyRights) != 0 ? MagickTrue :
686 if (p->domain == PathPolicyDomain)
687 real_pattern=DestroyString(real_pattern);
689 p=(
PolicyInfo *) GetNextValueInLinkedList(policy_cache);
691 UnlockSemaphoreInfo(policy_semaphore);
719MagickExport MagickBooleanType ListPolicyInfo(FILE *file,
738 if (file == (
const FILE *) NULL)
740 policy_info=GetPolicyInfoList(
"*",&number_policies,exception);
741 if (policy_info == (
const PolicyInfo **) NULL)
743 path=(
const char *) NULL;
744 for (i=0; i < (ssize_t) number_policies; i++)
746 if (policy_info[i]->stealth != MagickFalse)
748 if (((path == (
const char *) NULL) ||
749 (LocaleCompare(path,policy_info[i]->path) != 0)) &&
750 (policy_info[i]->path != (
char *) NULL))
751 (
void) FormatLocaleFile(file,
"\nPath: %s\n",policy_info[i]->path);
752 path=policy_info[i]->path;
753 domain=CommandOptionToMnemonic(MagickPolicyDomainOptions,
754 policy_info[i]->domain);
755 (void) FormatLocaleFile(file,
" Policy: %s\n",domain);
756 if ((policy_info[i]->domain == CachePolicyDomain) ||
757 (policy_info[i]->domain == ResourcePolicyDomain) ||
758 (policy_info[i]->domain == SystemPolicyDomain))
760 if (policy_info[i]->name != (
char *) NULL)
761 (
void) FormatLocaleFile(file,
" name: %s\n",policy_info[i]->name);
762 if (policy_info[i]->value != (
char *) NULL)
763 (void) FormatLocaleFile(file,
" value: %s\n",policy_info[i]->value);
767 (void) FormatLocaleFile(file,
" rights: ");
768 if (policy_info[i]->rights == NoPolicyRights)
769 (void) FormatLocaleFile(file,
"None ");
770 if ((policy_info[i]->rights & ReadPolicyRights) != 0)
771 (
void) FormatLocaleFile(file,
"Read ");
772 if ((policy_info[i]->rights & WritePolicyRights) != 0)
773 (void) FormatLocaleFile(file,
"Write ");
774 if ((policy_info[i]->rights & ExecutePolicyRights) != 0)
775 (
void) FormatLocaleFile(file,
"Execute ");
776 (void) FormatLocaleFile(file,
"\n");
777 if (policy_info[i]->pattern != (
char *) NULL)
778 (
void) FormatLocaleFile(file,
" pattern: %s\n",
779 policy_info[i]->pattern);
782 policy_info=(
const PolicyInfo **) RelinquishMagickMemory((
void *)
818static MagickBooleanType LoadPolicyCache(
LinkedListInfo *cache,
const char *xml,
819 const char *filename,
const size_t depth,
ExceptionInfo *exception)
822 keyword[MagickPathExtent],
840 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
841 "Loading policy file \"%s\" ...",filename);
842 if (xml == (
char *) NULL)
846 token=AcquirePolicyString(xml,MagickPathExtent);
847 extent=strlen(token)+MagickPathExtent;
848 for (q=(
const char *) xml; *q !=
'\0'; )
853 (void) GetNextToken(q,&q,extent,token);
856 (void) CopyMagickString(keyword,token,MagickPathExtent);
857 if (LocaleNCompare(keyword,
"<!DOCTYPE",9) == 0)
862 while ((LocaleNCompare(q,
"]>",2) != 0) && (*q !=
'\0'))
863 (
void) GetNextToken(q,&q,extent,token);
866 if (LocaleNCompare(keyword,
"<!--",4) == 0)
871 while ((LocaleNCompare(q,
"->",2) != 0) && (*q !=
'\0'))
872 (void) GetNextToken(q,&q,extent,token);
875 if (LocaleCompare(keyword,
"<include") == 0)
880 while (((*token !=
'/') && (*(token+1) !=
'>')) && (*q !=
'\0'))
882 (void) CopyMagickString(keyword,token,MagickPathExtent);
883 (void) GetNextToken(q,&q,extent,token);
886 (void) GetNextToken(q,&q,extent,token);
887 if (LocaleCompare(keyword,
"file") == 0)
889 if (depth > MagickMaxRecursionDepth)
890 (void) ThrowMagickException(exception,GetMagickModule(),
891 ConfigureError,
"IncludeElementNestedTooDeeply",
"`%s'",token);
895 path[MagickPathExtent],
898 GetPathComponent(filename,HeadPath,path);
900 (void) ConcatenateMagickString(path,DirectorySeparator,
902 if (*token == *DirectorySeparator)
903 (void) CopyMagickString(path,token,MagickPathExtent);
905 (
void) ConcatenateMagickString(path,token,MagickPathExtent);
906 xml=FileToXML(path,~0UL);
907 if (xml != (
char *) NULL)
909 status&=LoadPolicyCache(cache,xml,path,depth+1,
911 xml=(
char *) RelinquishMagickMemory(xml);
918 if (LocaleCompare(keyword,
"<policy") == 0)
923 policy_info=(
PolicyInfo *) AcquireMagickMemory(
sizeof(*policy_info));
925 ThrowFatalException(ResourceLimitFatalError,
"MemoryAllocationFailed");
926 (void) memset(policy_info,0,
sizeof(*policy_info));
927 policy_info->path=AcquirePolicyString(filename,1);
928 policy_info->exempt=MagickFalse;
929 policy_info->signature=MagickCoreSignature;
934 if ((LocaleCompare(keyword,
"/>") == 0) ||
935 (LocaleCompare(keyword,
"</policy>") == 0))
937 status=AppendValueToLinkedList(cache,policy_info);
938 if (status == MagickFalse)
939 (void) ThrowMagickException(exception,GetMagickModule(),
940 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",
945 (void) GetNextToken(q,(
const char **) NULL,extent,token);
948 (void) GetNextToken(q,&q,extent,token);
949 (void) GetNextToken(q,&q,extent,token);
955 if (LocaleCompare((
char *) keyword,
"domain") == 0)
957 policy_info->domain=(PolicyDomain) ParseCommandOption(
958 MagickPolicyDomainOptions,MagickTrue,token);
966 if (LocaleCompare((
char *) keyword,
"name") == 0)
968 policy_info->name=AcquirePolicyString(token,1);
976 if (LocaleCompare((
char *) keyword,
"pattern") == 0)
978 policy_info->pattern=AcquirePolicyString(token,1);
986 if (LocaleCompare((
char *) keyword,
"rights") == 0)
988 policy_info->rights=(PolicyRights) ParseCommandOption(
989 MagickPolicyRightsOptions,MagickTrue,token);
997 if (LocaleCompare((
char *) keyword,
"stealth") == 0)
999 policy_info->stealth=IsMagickTrue(token);
1007 if (LocaleCompare((
char *) keyword,
"value") == 0)
1009 policy_info->value=AcquirePolicyString(token,1);
1018 token=(
char *) RelinquishMagickMemory(token);
1019 if (status == MagickFalse)
1020 CatchException(exception);
1021 return(status != 0 ? MagickTrue : MagickFalse);
1042MagickExport MagickBooleanType PolicyComponentGenesis(
void)
1045 policy_semaphore=AllocateSemaphoreInfo();
1068static void *DestroyPolicyElement(
void *policy_info)
1074 if (p->exempt == MagickFalse)
1076 if (p->value != (
char *) NULL)
1077 p->value=DestroyString(p->value);
1078 if (p->pattern != (
char *) NULL)
1079 p->pattern=DestroyString(p->pattern);
1080 if (p->name != (
char *) NULL)
1081 p->name=DestroyString(p->name);
1082 if (p->path != (
char *) NULL)
1083 p->path=DestroyString(p->path);
1086 return((
void *) NULL);
1089MagickExport
void PolicyComponentTerminus(
void)
1092 ActivateSemaphoreInfo(&policy_semaphore);
1093 LockSemaphoreInfo(policy_semaphore);
1095 policy_cache=DestroyLinkedList(policy_cache,DestroyPolicyElement);
1096 UnlockSemaphoreInfo(policy_semaphore);
1097 DestroySemaphoreInfo(&policy_semaphore);
1127static MagickBooleanType ValidateSecurityPolicy(
const char *policy,
1130#if defined(MAGICKCORE_XML_DELEGATE)
1137 document=xmlReadMemory(policy,(
int) strlen(policy),url,NULL,
1138 XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
1139 if (document == (xmlDocPtr) NULL)
1141 (void) ThrowMagickException(exception,GetMagickModule(),ConfigureError,
1142 "PolicyValidationException",
"'%s'",url);
1143 return(MagickFalse);
1145 xmlFreeDoc(document);
1154MagickExport MagickBooleanType SetMagickSecurityPolicy(
const char *policy,
1164 if (policy == (
const char *) NULL)
1165 return(MagickFalse);
1166 if (ValidateSecurityPolicy(policy,PolicyFilename,exception) == MagickFalse)
1167 return(MagickFalse);
1168 if (IsPolicyCacheInstantiated(exception) == MagickFalse)
1169 return(MagickFalse);
1170 LockSemaphoreInfo(policy_semaphore);
1171 ResetLinkedListIterator(policy_cache);
1172 p=(
PolicyInfo *) GetNextValueInLinkedList(policy_cache);
1173 if ((p != (
PolicyInfo *) NULL) && (p->domain != UndefinedPolicyDomain))
1175 UnlockSemaphoreInfo(policy_semaphore);
1176 return(MagickFalse);
1178 UnlockSemaphoreInfo(policy_semaphore);
1179 status=LoadPolicyCache(policy_cache,policy,
"[user-policy]",0,exception);
1180 if (status == MagickFalse)
1181 return(MagickFalse);
1182 return(ResourceComponentGenesis());