40#include "magick/studio.h"
41#include "magick/cache-private.h"
42#include "magick/client.h"
43#include "magick/configure.h"
44#include "magick/exception.h"
45#include "magick/exception-private.h"
46#include "magick/hashmap-private.h"
47#include "magick/locale_.h"
48#include "magick/magick-private.h"
49#include "magick/memory_.h"
50#include "magick/memory-private.h"
51#include "magick/monitor.h"
52#include "magick/monitor-private.h"
53#include "magick/option.h"
54#include "magick/policy.h"
55#include "magick/policy-private.h"
56#include "magick/resource_.h"
57#include "magick/semaphore.h"
58#include "magick/stream-private.h"
59#include "magick/string_.h"
60#include "magick/string-private.h"
61#include "magick/timer-private.h"
62#include "magick/token.h"
63#include "magick/utility.h"
64#include "magick/xml-tree.h"
65#include "magick/xml-tree-private.h"
66#if defined(MAGICKCORE_XML_DELEGATE)
67# include <libxml/parser.h>
68# include <libxml/tree.h>
74#define PolicyFilename "policy.xml"
127 { UndefinedPolicyDomain, UndefinedPolicyRights, (
const char *) NULL,
128 (
const char *) NULL, (
const char *) NULL }
140static MagickBooleanType
142 LoadPolicyCache(
LinkedListInfo *,
const char *,
const char *,
const size_t,
144 SetMagickSecurityPolicyValue(
const PolicyDomain,
const char *,
const char *,
188 cache=NewLinkedList(0);
190 ThrowFatalException(ResourceLimitFatalError,
"MemoryAllocationFailed");
192#if MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
193 magick_unreferenced(filename);
194 status=LoadPolicyCache(cache,ZeroConfigurationPolicy,
"[zero-configuration]",0,
196 if (status == MagickFalse)
197 CatchException(exception);
206 options=GetConfigureOptions(filename,exception);
207 option=(
const StringInfo *) GetNextValueInLinkedList(options);
210 status&=LoadPolicyCache(cache,(
const char *) GetStringInfoDatum(option),
211 GetStringInfoPath(option),0,exception);
212 if (status == MagickFalse)
213 CatchException(exception);
214 option=(
const StringInfo *) GetNextValueInLinkedList(options);
216 options=DestroyConfigureOptions(options);
222 for (i=0; i < (ssize_t) (
sizeof(PolicyMap)/
sizeof(*PolicyMap)); i++)
231 policy_info=(
PolicyInfo *) AcquireMagickMemory(
sizeof(*policy_info));
234 (void) ThrowMagickException(exception,GetMagickModule(),
235 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",
236 p->name == (
char *) NULL ?
"" : p->name);
237 CatchException(exception);
241 (void) memset(policy_info,0,
sizeof(*policy_info));
242 policy_info->path=(
char *)
"[built-in]";
243 policy_info->domain=p->domain;
244 policy_info->rights=p->rights;
245 policy_info->name=(
char *) p->name;
246 policy_info->pattern=(
char *) p->pattern;
247 policy_info->value=(
char *) p->value;
248 policy_info->exempt=MagickTrue;
249 policy_info->signature=MagickCoreSignature;
250 status&=AppendValueToLinkedList(cache,policy_info);
251 if (status == MagickFalse)
253 (void) ThrowMagickException(exception,GetMagickModule(),
254 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",
255 p->name == (
char *) NULL ?
"" : p->name);
256 CatchException(exception);
259 if (status == MagickFalse)
260 CatchException(exception);
292 policyname[MagickPathExtent],
305 if (IsPolicyCacheInstantiated(exception) == MagickFalse)
311 if (name != (
const char *) NULL)
312 (void) CopyMagickString(policyname,name,MagickPathExtent);
313 for (q=policyname; *q !=
'\0'; q++)
315 if (isspace((
int) ((
unsigned char) *q)) == 0)
317 (void) CopyMagickString(q,q+1,MagickPathExtent);
323 domain=UndefinedPolicyDomain;
324 for (q=policyname; *q !=
'\0'; q++)
329 domain=(PolicyDomain) ParseCommandOption(MagickPolicyDomainOptions,
330 MagickTrue,policyname);
331 (void) CopyMagickString(policyname,q+1,MagickPathExtent);
338 LockSemaphoreInfo(policy_semaphore);
339 ResetLinkedListIterator(policy_cache);
340 p=GetHeadElementInLinkedList(policy_cache);
341 if ((name == (
const char *) NULL) || (LocaleCompare(name,
"*") == 0))
343 UnlockSemaphoreInfo(policy_semaphore);
351 if ((domain == UndefinedPolicyDomain) || (policy->domain == domain))
352 if (LocaleCompare(policyname,policy->name) == 0)
359 (
void) SetHeadElementInLinkedList(policy_cache,p);
360 UnlockSemaphoreInfo(policy_semaphore);
391MagickExport
const PolicyInfo **GetPolicyInfoList(
const char *pattern,
406 assert(pattern != (
char *) NULL);
407 assert(number_policies != (
size_t *) NULL);
408 if (IsEventLogging() != MagickFalse)
409 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",pattern);
411 p=GetPolicyInfo(
"*",exception);
414 policies=(
const PolicyInfo **) AcquireQuantumMemory((
size_t)
415 GetNumberOfElementsInLinkedList(policy_cache)+1UL,
sizeof(*policies));
421 LockSemaphoreInfo(policy_semaphore);
422 ResetLinkedListIterator(policy_cache);
423 p=(
const PolicyInfo *) GetNextValueInLinkedList(policy_cache);
426 if ((p->stealth == MagickFalse) &&
427 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
429 p=(
const PolicyInfo *) GetNextValueInLinkedList(policy_cache);
431 UnlockSemaphoreInfo(policy_semaphore);
433 *number_policies=(size_t) i;
465static char *AcquirePolicyString(
const char *source,
const size_t pad)
474 if (source != (
char *) NULL)
475 length+=strlen(source);
476 destination=(
char *) NULL;
478 destination=(
char *) AcquireMagickMemory((length+pad)*
sizeof(*destination));
479 if (destination == (
char *) NULL)
480 ThrowFatalException(ResourceLimitFatalError,
"UnableToAcquireString");
481 if (source != (
char *) NULL)
482 (void) memcpy(destination,source,length*
sizeof(*destination));
483 destination[length]=
'\0';
487MagickExport
char **GetPolicyList(
const char *pattern,
size_t *number_policies,
502 assert(pattern != (
char *) NULL);
503 assert(number_policies != (
size_t *) NULL);
504 if (IsEventLogging() != MagickFalse)
505 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",pattern);
507 p=GetPolicyInfo(
"*",exception);
509 return((
char **) NULL);
510 policies=(
char **) AcquireQuantumMemory((
size_t)
511 GetNumberOfElementsInLinkedList(policy_cache)+1UL,
sizeof(*policies));
512 if (policies == (
char **) NULL)
513 return((
char **) NULL);
517 LockSemaphoreInfo(policy_semaphore);
518 ResetLinkedListIterator(policy_cache);
519 p=(
const PolicyInfo *) GetNextValueInLinkedList(policy_cache);
522 if ((p->stealth == MagickFalse) &&
523 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
524 policies[i++]=AcquirePolicyString(p->name,1);
525 p=(
const PolicyInfo *) GetNextValueInLinkedList(policy_cache);
527 UnlockSemaphoreInfo(policy_semaphore);
528 policies[i]=(
char *) NULL;
529 *number_policies=(size_t) i;
555MagickExport
char *GetPolicyValue(
const char *name)
566 assert(name != (
const char *) NULL);
567 if (IsEventLogging() != MagickFalse)
568 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",name);
569 exception=AcquireExceptionInfo();
570 policy_info=GetPolicyInfo(name,exception);
571 exception=DestroyExceptionInfo(exception);
573 return((
char *) NULL);
574 value=policy_info->value;
575 if ((value == (
const char *) NULL) || (*value ==
'\0'))
576 return((
char *) NULL);
577 return(AcquirePolicyString(value,1));
603static MagickBooleanType IsPolicyCacheInstantiated(
ExceptionInfo *exception)
607 GetMaxMemoryRequest();
609 ActivateSemaphoreInfo(&policy_semaphore);
610 LockSemaphoreInfo(policy_semaphore);
612 policy_cache=AcquirePolicyCache(PolicyFilename,exception);
613 UnlockSemaphoreInfo(policy_semaphore);
615 return(policy_cache != (
LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
646MagickExport MagickBooleanType IsRightsAuthorized(
const PolicyDomain domain,
647 const PolicyRights rights,
const char *pattern)
661 if ((GetLogEventMask() & PolicyEvent) != 0)
662 (void) LogMagickEvent(PolicyEvent,GetMagickModule(),
663 "Domain: %s; rights=%s; pattern=\"%s\" ...",
664 CommandOptionToMnemonic(MagickPolicyDomainOptions,domain),
665 CommandOptionToMnemonic(MagickPolicyRightsOptions,rights),pattern);
666 exception=AcquireExceptionInfo();
667 policy_info=GetPolicyInfo(
"*",exception);
668 exception=DestroyExceptionInfo(exception);
671 authorized=MagickTrue;
672 LockSemaphoreInfo(policy_semaphore);
673 ResetLinkedListIterator(policy_cache);
674 p=(
PolicyInfo *) GetNextValueInLinkedList(policy_cache);
677 if ((p->domain == domain) &&
678 (GlobExpression(pattern,p->pattern,MagickFalse) != MagickFalse))
680 if ((rights & ReadPolicyRights) != 0)
681 authorized=(p->rights & ReadPolicyRights) != 0 ? MagickTrue :
683 if ((rights & WritePolicyRights) != 0)
684 authorized=(p->rights & WritePolicyRights) != 0 ? MagickTrue :
686 if ((rights & ExecutePolicyRights) != 0)
687 authorized=(p->rights & ExecutePolicyRights) != 0 ? MagickTrue :
690 p=(
PolicyInfo *) GetNextValueInLinkedList(policy_cache);
692 UnlockSemaphoreInfo(policy_semaphore);
720MagickExport MagickBooleanType ListPolicyInfo(FILE *file,
739 if (file == (
const FILE *) NULL)
741 policy_info=GetPolicyInfoList(
"*",&number_policies,exception);
742 if (policy_info == (
const PolicyInfo **) NULL)
744 path=(
const char *) NULL;
745 for (i=0; i < (ssize_t) number_policies; i++)
747 if (policy_info[i]->stealth != MagickFalse)
749 if (((path == (
const char *) NULL) ||
750 (LocaleCompare(path,policy_info[i]->path) != 0)) &&
751 (policy_info[i]->path != (
char *) NULL))
752 (void) FormatLocaleFile(file,
"\nPath: %s\n",policy_info[i]->path);
753 path=policy_info[i]->path;
754 domain=CommandOptionToMnemonic(MagickPolicyDomainOptions,
755 policy_info[i]->domain);
756 (void) FormatLocaleFile(file,
" Policy: %s\n",domain);
757 if ((policy_info[i]->domain == CachePolicyDomain) ||
758 (policy_info[i]->domain == ResourcePolicyDomain) ||
759 (policy_info[i]->domain == SystemPolicyDomain))
761 if (policy_info[i]->name != (
char *) NULL)
762 (void) FormatLocaleFile(file,
" name: %s\n",policy_info[i]->name);
763 if (policy_info[i]->value != (
char *) NULL)
764 (void) FormatLocaleFile(file,
" value: %s\n",policy_info[i]->value);
768 (void) FormatLocaleFile(file,
" rights: ");
769 if (policy_info[i]->rights == NoPolicyRights)
770 (void) FormatLocaleFile(file,
"None ");
771 if ((policy_info[i]->rights & ReadPolicyRights) != 0)
772 (void) FormatLocaleFile(file,
"Read ");
773 if ((policy_info[i]->rights & WritePolicyRights) != 0)
774 (void) FormatLocaleFile(file,
"Write ");
775 if ((policy_info[i]->rights & ExecutePolicyRights) != 0)
776 (void) FormatLocaleFile(file,
"Execute ");
777 (void) FormatLocaleFile(file,
"\n");
778 if (policy_info[i]->pattern != (
char *) NULL)
779 (void) FormatLocaleFile(file,
" pattern: %s\n",
780 policy_info[i]->pattern);
783 policy_info=(
const PolicyInfo **) RelinquishMagickMemory((
void *)
819static MagickBooleanType LoadPolicyCache(
LinkedListInfo *cache,
const char *xml,
820 const char *filename,
const size_t depth,
ExceptionInfo *exception)
823 keyword[MagickPathExtent],
841 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
842 "Loading policy file \"%s\" ...",filename);
843 if (xml == (
char *) NULL)
847 token=AcquirePolicyString(xml,MagickPathExtent);
848 extent=strlen(token)+MagickPathExtent;
849 for (q=(
const char *) xml; *q !=
'\0'; )
854 (void) GetNextToken(q,&q,extent,token);
857 (void) CopyMagickString(keyword,token,MagickPathExtent);
858 if (LocaleNCompare(keyword,
"<!DOCTYPE",9) == 0)
863 while ((LocaleNCompare(q,
"]>",2) != 0) && (*q !=
'\0'))
864 (void) GetNextToken(q,&q,extent,token);
867 if (LocaleNCompare(keyword,
"<!--",4) == 0)
872 while ((LocaleNCompare(q,
"->",2) != 0) && (*q !=
'\0'))
873 (void) GetNextToken(q,&q,extent,token);
876 if (LocaleCompare(keyword,
"<include") == 0)
881 while (((*token !=
'/') && (*(token+1) !=
'>')) && (*q !=
'\0'))
883 (void) CopyMagickString(keyword,token,MagickPathExtent);
884 (void) GetNextToken(q,&q,extent,token);
887 (void) GetNextToken(q,&q,extent,token);
888 if (LocaleCompare(keyword,
"file") == 0)
890 if (depth > MagickMaxRecursionDepth)
891 (void) ThrowMagickException(exception,GetMagickModule(),
892 ConfigureError,
"IncludeElementNestedTooDeeply",
"`%s'",token);
896 path[MagickPathExtent],
899 GetPathComponent(filename,HeadPath,path);
901 (void) ConcatenateMagickString(path,DirectorySeparator,
903 if (*token == *DirectorySeparator)
904 (void) CopyMagickString(path,token,MagickPathExtent);
906 (
void) ConcatenateMagickString(path,token,MagickPathExtent);
907 xml=FileToXML(path,~0UL);
908 if (xml != (
char *) NULL)
910 status&=LoadPolicyCache(cache,xml,path,depth+1,
912 xml=(
char *) RelinquishMagickMemory(xml);
919 if (LocaleCompare(keyword,
"<policy") == 0)
924 policy_info=(
PolicyInfo *) AcquireMagickMemory(
sizeof(*policy_info));
926 ThrowFatalException(ResourceLimitFatalError,
"MemoryAllocationFailed");
927 (void) memset(policy_info,0,
sizeof(*policy_info));
928 policy_info->path=AcquirePolicyString(filename,1);
929 policy_info->exempt=MagickFalse;
930 policy_info->signature=MagickCoreSignature;
935 if ((LocaleCompare(keyword,
"/>") == 0) ||
936 (LocaleCompare(keyword,
"</policy>") == 0))
938 status=AppendValueToLinkedList(cache,policy_info);
939 if (status == MagickFalse)
940 (void) ThrowMagickException(exception,GetMagickModule(),
941 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",
946 (void) GetNextToken(q,(
const char **) NULL,extent,token);
949 (void) GetNextToken(q,&q,extent,token);
950 (void) GetNextToken(q,&q,extent,token);
956 if (LocaleCompare((
char *) keyword,
"domain") == 0)
958 policy_info->domain=(PolicyDomain) ParseCommandOption(
959 MagickPolicyDomainOptions,MagickTrue,token);
967 if (LocaleCompare((
char *) keyword,
"name") == 0)
969 policy_info->name=AcquirePolicyString(token,1);
977 if (LocaleCompare((
char *) keyword,
"pattern") == 0)
979 policy_info->pattern=AcquirePolicyString(token,1);
987 if (LocaleCompare((
char *) keyword,
"rights") == 0)
989 policy_info->rights=(PolicyRights) ParseCommandOption(
990 MagickPolicyRightsOptions,MagickTrue,token);
998 if (LocaleCompare((
char *) keyword,
"stealth") == 0)
1000 policy_info->stealth=IsMagickTrue(token);
1008 if (LocaleCompare((
char *) keyword,
"value") == 0)
1010 policy_info->value=AcquirePolicyString(token,1);
1019 token=(
char *) RelinquishMagickMemory(token);
1020 if (status == MagickFalse)
1021 CatchException(exception);
1022 return(status != 0 ? MagickTrue : MagickFalse);
1043MagickExport MagickBooleanType PolicyComponentGenesis(
void)
1046 policy_semaphore=AllocateSemaphoreInfo();
1069static void *DestroyPolicyElement(
void *policy_info)
1075 if (p->exempt == MagickFalse)
1077 if (p->value != (
char *) NULL)
1078 p->value=DestroyString(p->value);
1079 if (p->pattern != (
char *) NULL)
1080 p->pattern=DestroyString(p->pattern);
1081 if (p->name != (
char *) NULL)
1082 p->name=DestroyString(p->name);
1083 if (p->path != (
char *) NULL)
1084 p->path=DestroyString(p->path);
1087 return((
void *) NULL);
1090MagickExport
void PolicyComponentTerminus(
void)
1093 ActivateSemaphoreInfo(&policy_semaphore);
1094 LockSemaphoreInfo(policy_semaphore);
1096 policy_cache=DestroyLinkedList(policy_cache,DestroyPolicyElement);
1097 UnlockSemaphoreInfo(policy_semaphore);
1098 DestroySemaphoreInfo(&policy_semaphore);
1128static MagickBooleanType ValidateSecurityPolicy(
const char *policy,
1131#if defined(MAGICKCORE_XML_DELEGATE)
1138 document=xmlReadMemory(policy,(
int) strlen(policy),url,NULL,
1139 XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
1140 if (document == (xmlDocPtr) NULL)
1142 (void) ThrowMagickException(exception,GetMagickModule(),ConfigureError,
1143 "PolicyValidationException",
"'%s'",url);
1144 return(MagickFalse);
1146 xmlFreeDoc(document);
1155MagickExport MagickBooleanType SetMagickSecurityPolicy(
const char *policy,
1171 if (policy == (
const char *) NULL)
1172 return(MagickFalse);
1173 if (ValidateSecurityPolicy(policy,PolicyFilename,exception) == MagickFalse)
1174 return(MagickFalse);
1175 status=LoadPolicyCache(policy_cache,policy,
"[user-policy]",0,exception);
1176 if (status == MagickFalse)
1181 user_policies=NewLinkedList(0);
1182 status=LoadPolicyCache(user_policies,policy,
"[user-policy]",0,exception);
1183 if (status == MagickFalse)
1185 user_policies=DestroyLinkedList(user_policies,DestroyPolicyElement);
1186 return(MagickFalse);
1188 ResetLinkedListIterator(user_policies);
1189 p=(
PolicyInfo *) GetNextValueInLinkedList(user_policies);
1192 if ((p->name != (
char *) NULL) && (p->value != (
char *) NULL))
1193 (void) SetMagickSecurityPolicyValue(p->domain,p->name,p->value,exception);
1194 p=(
PolicyInfo *) GetNextValueInLinkedList(user_policies);
1196 user_policies=DestroyLinkedList(user_policies,DestroyPolicyElement);
1233static MagickBooleanType SetMagickSecurityPolicyValue(
const PolicyDomain domain,
1234 const char *name,
const char *value,
ExceptionInfo *exception)
1236 magick_unreferenced(exception);
1238 if ((name == (
const char *) NULL) || (value == (
const char *) NULL))
1239 return(MagickFalse);
1242 case CachePolicyDomain:
1244 if (LocaleCompare(name,
"memory-map") == 0)
1246 if (LocaleCompare(value,
"anonymous") != 0)
1247 return(MagickFalse);
1248 ResetCacheAnonymousMemory();
1249 ResetStreamAnonymousMemory();
1254 case ResourcePolicyDomain:
1259 type=ParseCommandOption(MagickResourceOptions,MagickFalse,name);
1265 limit=MagickResourceInfinity;
1266 if (LocaleCompare(
"unlimited",value) != 0)
1267 limit=StringToMagickSizeType(value,100.0);
1268 if ((ResourceType) type == TimeResource)
1269 limit=(MagickSizeType) ParseMagickTimeToLive(value);
1270 return(SetMagickResourceLimit((ResourceType) type,limit));
1274 case SystemPolicyDomain:
1276 if (LocaleCompare(name,
"max-memory-request") == 0)
1281 limit=MagickResourceInfinity;
1282 if (LocaleCompare(
"unlimited",value) != 0)
1283 limit=StringToMagickSizeType(value,100.0);
1284 SetMaxMemoryRequest(limit);
1287 if (LocaleCompare(name,
"memory-map") == 0)
1289 if (LocaleCompare(value,
"anonymous") != 0)
1290 return(MagickFalse);
1291 ResetVirtualAnonymousMemory();
1294 if (LocaleCompare(name,
"precision") == 0)
1299 limit=StringToInteger(value);
1300 SetMagickPrecision(limit);
1305 case CoderPolicyDomain:
1306 case DelegatePolicyDomain:
1307 case FilterPolicyDomain:
1308 case ModulePolicyDomain:
1309 case PathPolicyDomain:
1313 return(MagickFalse);