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/xml-tree.h"
58#include "magick/xml-tree-private.h"
59#if defined(MAGICKCORE_XML_DELEGATE)
60# include <libxml/parser.h>
61# include <libxml/tree.h>
67#define PolicyFilename "policy.xml"
120 { UndefinedPolicyDomain, UndefinedPolicyRights, (
const char *) NULL,
121 (
const char *) NULL, (
const char *) NULL }
133static MagickBooleanType
135 LoadPolicyCache(
LinkedListInfo *,
const char *,
const char *,
const size_t,
179 cache=NewLinkedList(0);
181 ThrowFatalException(ResourceLimitFatalError,
"MemoryAllocationFailed");
183#if MAGICKCORE_ZERO_CONFIGURATION_SUPPORT
184 magick_unreferenced(filename);
185 status=LoadPolicyCache(cache,ZeroConfigurationPolicy,
"[zero-configuration]",0,
187 if (status == MagickFalse)
188 CatchException(exception);
197 options=GetConfigureOptions(filename,exception);
198 option=(
const StringInfo *) GetNextValueInLinkedList(options);
201 status&=LoadPolicyCache(cache,(
const char *) GetStringInfoDatum(option),
202 GetStringInfoPath(option),0,exception);
203 if (status == MagickFalse)
204 CatchException(exception);
205 option=(
const StringInfo *) GetNextValueInLinkedList(options);
207 options=DestroyConfigureOptions(options);
213 for (i=0; i < (ssize_t) (
sizeof(PolicyMap)/
sizeof(*PolicyMap)); i++)
222 policy_info=(
PolicyInfo *) AcquireMagickMemory(
sizeof(*policy_info));
225 (void) ThrowMagickException(exception,GetMagickModule(),
226 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",
227 p->name == (
char *) NULL ?
"" : p->name);
228 CatchException(exception);
232 (void) memset(policy_info,0,
sizeof(*policy_info));
233 policy_info->path=(
char *)
"[built-in]";
234 policy_info->domain=p->domain;
235 policy_info->rights=p->rights;
236 policy_info->name=(
char *) p->name;
237 policy_info->pattern=(
char *) p->pattern;
238 policy_info->value=(
char *) p->value;
239 policy_info->exempt=MagickTrue;
240 policy_info->signature=MagickCoreSignature;
241 status&=AppendValueToLinkedList(cache,policy_info);
242 if (status == MagickFalse)
244 (void) ThrowMagickException(exception,GetMagickModule(),
245 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",
246 p->name == (
char *) NULL ?
"" : p->name);
247 CatchException(exception);
250 if (status == MagickFalse)
251 CatchException(exception);
283 policyname[MagickPathExtent];
295 if (IsPolicyCacheInstantiated(exception) == MagickFalse)
301 if (name != (
const char *) NULL)
302 (void) CopyMagickString(policyname,name,MagickPathExtent);
303 for (q=policyname; *q !=
'\0'; q++)
305 if (isspace((
int) ((
unsigned char) *q)) == 0)
307 (void) CopyMagickString(q,q+1,MagickPathExtent);
313 domain=UndefinedPolicyDomain;
314 for (q=policyname; *q !=
'\0'; q++)
319 domain=(PolicyDomain) ParseCommandOption(MagickPolicyDomainOptions,
320 MagickTrue,policyname);
321 (void) CopyMagickString(policyname,q+1,MagickPathExtent);
327 LockSemaphoreInfo(policy_semaphore);
328 ResetLinkedListIterator(policy_cache);
329 p=(
PolicyInfo *) GetNextValueInLinkedList(policy_cache);
330 if ((name == (
const char *) NULL) || (LocaleCompare(name,
"*") == 0))
332 UnlockSemaphoreInfo(policy_semaphore);
337 if ((domain == UndefinedPolicyDomain) || (p->domain == domain))
338 if (LocaleCompare(policyname,p->name) == 0)
340 p=(
PolicyInfo *) GetNextValueInLinkedList(policy_cache);
343 (
void) InsertValueInLinkedList(policy_cache,0,
344 RemoveElementByValueFromLinkedList(policy_cache,p));
345 UnlockSemaphoreInfo(policy_semaphore);
376MagickExport
const PolicyInfo **GetPolicyInfoList(
const char *pattern,
391 assert(pattern != (
char *) NULL);
392 assert(number_policies != (
size_t *) NULL);
393 if (IsEventLogging() != MagickFalse)
394 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",pattern);
396 p=GetPolicyInfo(
"*",exception);
399 policies=(
const PolicyInfo **) AcquireQuantumMemory((
size_t)
400 GetNumberOfElementsInLinkedList(policy_cache)+1UL,
sizeof(*policies));
406 LockSemaphoreInfo(policy_semaphore);
407 ResetLinkedListIterator(policy_cache);
408 p=(
const PolicyInfo *) GetNextValueInLinkedList(policy_cache);
411 if ((p->stealth == MagickFalse) &&
412 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
414 p=(
const PolicyInfo *) GetNextValueInLinkedList(policy_cache);
416 UnlockSemaphoreInfo(policy_semaphore);
418 *number_policies=(size_t) i;
450static char *AcquirePolicyString(
const char *source,
const size_t pad)
459 if (source != (
char *) NULL)
460 length+=strlen(source);
461 destination=(
char *) NULL;
463 destination=(
char *) AcquireMagickMemory((length+pad)*
sizeof(*destination));
464 if (destination == (
char *) NULL)
465 ThrowFatalException(ResourceLimitFatalError,
"UnableToAcquireString");
466 if (source != (
char *) NULL)
467 (
void) memcpy(destination,source,length*
sizeof(*destination));
468 destination[length]=
'\0';
472MagickExport
char **GetPolicyList(
const char *pattern,
size_t *number_policies,
487 assert(pattern != (
char *) NULL);
488 assert(number_policies != (
size_t *) NULL);
489 if (IsEventLogging() != MagickFalse)
490 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",pattern);
492 p=GetPolicyInfo(
"*",exception);
494 return((
char **) NULL);
495 policies=(
char **) AcquireQuantumMemory((
size_t)
496 GetNumberOfElementsInLinkedList(policy_cache)+1UL,
sizeof(*policies));
497 if (policies == (
char **) NULL)
498 return((
char **) NULL);
502 LockSemaphoreInfo(policy_semaphore);
503 ResetLinkedListIterator(policy_cache);
504 p=(
const PolicyInfo *) GetNextValueInLinkedList(policy_cache);
507 if ((p->stealth == MagickFalse) &&
508 (GlobExpression(p->name,pattern,MagickFalse) != MagickFalse))
509 policies[i++]=AcquirePolicyString(p->name,1);
510 p=(
const PolicyInfo *) GetNextValueInLinkedList(policy_cache);
512 UnlockSemaphoreInfo(policy_semaphore);
513 policies[i]=(
char *) NULL;
514 *number_policies=(size_t) i;
540MagickExport
char *GetPolicyValue(
const char *name)
551 assert(name != (
const char *) NULL);
552 if (IsEventLogging() != MagickFalse)
553 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",name);
554 exception=AcquireExceptionInfo();
555 policy_info=GetPolicyInfo(name,exception);
556 exception=DestroyExceptionInfo(exception);
558 return((
char *) NULL);
559 value=policy_info->value;
560 if ((value == (
const char *) NULL) || (*value ==
'\0'))
561 return((
char *) NULL);
562 return(AcquirePolicyString(value,1));
588static MagickBooleanType IsPolicyCacheInstantiated(
ExceptionInfo *exception)
592 GetMaxMemoryRequest();
594 ActivateSemaphoreInfo(&policy_semaphore);
595 LockSemaphoreInfo(policy_semaphore);
597 policy_cache=AcquirePolicyCache(PolicyFilename,exception);
598 UnlockSemaphoreInfo(policy_semaphore);
600 return(policy_cache != (
LinkedListInfo *) NULL ? MagickTrue : MagickFalse);
631MagickExport MagickBooleanType IsRightsAuthorized(
const PolicyDomain domain,
632 const PolicyRights rights,
const char *pattern)
646 if ((GetLogEventMask() & PolicyEvent) != 0)
647 (void) LogMagickEvent(PolicyEvent,GetMagickModule(),
648 "Domain: %s; rights=%s; pattern=\"%s\" ...",
649 CommandOptionToMnemonic(MagickPolicyDomainOptions,domain),
650 CommandOptionToMnemonic(MagickPolicyRightsOptions,rights),pattern);
651 exception=AcquireExceptionInfo();
652 policy_info=GetPolicyInfo(
"*",exception);
653 exception=DestroyExceptionInfo(exception);
656 authorized=MagickTrue;
657 LockSemaphoreInfo(policy_semaphore);
658 ResetLinkedListIterator(policy_cache);
659 p=(
PolicyInfo *) GetNextValueInLinkedList(policy_cache);
662 if ((p->domain == domain) &&
663 (GlobExpression(pattern,p->pattern,MagickFalse) != MagickFalse))
665 if ((rights & ReadPolicyRights) != 0)
666 authorized=(p->rights & ReadPolicyRights) != 0 ? MagickTrue :
668 if ((rights & WritePolicyRights) != 0)
669 authorized=(p->rights & WritePolicyRights) != 0 ? MagickTrue :
671 if ((rights & ExecutePolicyRights) != 0)
672 authorized=(p->rights & ExecutePolicyRights) != 0 ? MagickTrue :
675 p=(
PolicyInfo *) GetNextValueInLinkedList(policy_cache);
677 UnlockSemaphoreInfo(policy_semaphore);
705MagickExport MagickBooleanType ListPolicyInfo(FILE *file,
724 if (file == (
const FILE *) NULL)
726 policy_info=GetPolicyInfoList(
"*",&number_policies,exception);
727 if (policy_info == (
const PolicyInfo **) NULL)
729 path=(
const char *) NULL;
730 for (i=0; i < (ssize_t) number_policies; i++)
732 if (policy_info[i]->stealth != MagickFalse)
734 if (((path == (
const char *) NULL) ||
735 (LocaleCompare(path,policy_info[i]->path) != 0)) &&
736 (policy_info[i]->path != (
char *) NULL))
737 (
void) FormatLocaleFile(file,
"\nPath: %s\n",policy_info[i]->path);
738 path=policy_info[i]->path;
739 domain=CommandOptionToMnemonic(MagickPolicyDomainOptions,
740 policy_info[i]->domain);
741 (void) FormatLocaleFile(file,
" Policy: %s\n",domain);
742 if ((policy_info[i]->domain == CachePolicyDomain) ||
743 (policy_info[i]->domain == ResourcePolicyDomain) ||
744 (policy_info[i]->domain == SystemPolicyDomain))
746 if (policy_info[i]->name != (
char *) NULL)
747 (
void) FormatLocaleFile(file,
" name: %s\n",policy_info[i]->name);
748 if (policy_info[i]->value != (
char *) NULL)
749 (void) FormatLocaleFile(file,
" value: %s\n",policy_info[i]->value);
753 (void) FormatLocaleFile(file,
" rights: ");
754 if (policy_info[i]->rights == NoPolicyRights)
755 (void) FormatLocaleFile(file,
"None ");
756 if ((policy_info[i]->rights & ReadPolicyRights) != 0)
757 (
void) FormatLocaleFile(file,
"Read ");
758 if ((policy_info[i]->rights & WritePolicyRights) != 0)
759 (void) FormatLocaleFile(file,
"Write ");
760 if ((policy_info[i]->rights & ExecutePolicyRights) != 0)
761 (
void) FormatLocaleFile(file,
"Execute ");
762 (void) FormatLocaleFile(file,
"\n");
763 if (policy_info[i]->pattern != (
char *) NULL)
764 (
void) FormatLocaleFile(file,
" pattern: %s\n",
765 policy_info[i]->pattern);
768 policy_info=(
const PolicyInfo **) RelinquishMagickMemory((
void *)
804static MagickBooleanType LoadPolicyCache(
LinkedListInfo *cache,
const char *xml,
805 const char *filename,
const size_t depth,
ExceptionInfo *exception)
808 keyword[MagickPathExtent],
826 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
827 "Loading policy file \"%s\" ...",filename);
828 if (xml == (
char *) NULL)
832 token=AcquirePolicyString(xml,MagickPathExtent);
833 extent=strlen(token)+MagickPathExtent;
834 for (q=(
const char *) xml; *q !=
'\0'; )
839 (void) GetNextToken(q,&q,extent,token);
842 (void) CopyMagickString(keyword,token,MagickPathExtent);
843 if (LocaleNCompare(keyword,
"<!DOCTYPE",9) == 0)
848 while ((LocaleNCompare(q,
"]>",2) != 0) && (*q !=
'\0'))
849 (
void) GetNextToken(q,&q,extent,token);
852 if (LocaleNCompare(keyword,
"<!--",4) == 0)
857 while ((LocaleNCompare(q,
"->",2) != 0) && (*q !=
'\0'))
858 (void) GetNextToken(q,&q,extent,token);
861 if (LocaleCompare(keyword,
"<include") == 0)
866 while (((*token !=
'/') && (*(token+1) !=
'>')) && (*q !=
'\0'))
868 (void) CopyMagickString(keyword,token,MagickPathExtent);
869 (void) GetNextToken(q,&q,extent,token);
872 (void) GetNextToken(q,&q,extent,token);
873 if (LocaleCompare(keyword,
"file") == 0)
875 if (depth > MagickMaxRecursionDepth)
876 (void) ThrowMagickException(exception,GetMagickModule(),
877 ConfigureError,
"IncludeElementNestedTooDeeply",
"`%s'",token);
881 path[MagickPathExtent],
884 GetPathComponent(filename,HeadPath,path);
886 (void) ConcatenateMagickString(path,DirectorySeparator,
888 if (*token == *DirectorySeparator)
889 (void) CopyMagickString(path,token,MagickPathExtent);
891 (
void) ConcatenateMagickString(path,token,MagickPathExtent);
892 xml=FileToXML(path,~0UL);
893 if (xml != (
char *) NULL)
895 status&=LoadPolicyCache(cache,xml,path,depth+1,
897 xml=(
char *) RelinquishMagickMemory(xml);
904 if (LocaleCompare(keyword,
"<policy") == 0)
909 policy_info=(
PolicyInfo *) AcquireMagickMemory(
sizeof(*policy_info));
911 ThrowFatalException(ResourceLimitFatalError,
"MemoryAllocationFailed");
912 (void) memset(policy_info,0,
sizeof(*policy_info));
913 policy_info->path=AcquirePolicyString(filename,1);
914 policy_info->exempt=MagickFalse;
915 policy_info->signature=MagickCoreSignature;
920 if ((LocaleCompare(keyword,
"/>") == 0) ||
921 (LocaleCompare(keyword,
"</policy>") == 0))
923 status=AppendValueToLinkedList(cache,policy_info);
924 if (status == MagickFalse)
925 (void) ThrowMagickException(exception,GetMagickModule(),
926 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",
931 (void) GetNextToken(q,(
const char **) NULL,extent,token);
934 (void) GetNextToken(q,&q,extent,token);
935 (void) GetNextToken(q,&q,extent,token);
941 if (LocaleCompare((
char *) keyword,
"domain") == 0)
943 policy_info->domain=(PolicyDomain) ParseCommandOption(
944 MagickPolicyDomainOptions,MagickTrue,token);
952 if (LocaleCompare((
char *) keyword,
"name") == 0)
954 policy_info->name=AcquirePolicyString(token,1);
962 if (LocaleCompare((
char *) keyword,
"pattern") == 0)
964 policy_info->pattern=AcquirePolicyString(token,1);
972 if (LocaleCompare((
char *) keyword,
"rights") == 0)
974 policy_info->rights=(PolicyRights) ParseCommandOption(
975 MagickPolicyRightsOptions,MagickTrue,token);
983 if (LocaleCompare((
char *) keyword,
"stealth") == 0)
985 policy_info->stealth=IsMagickTrue(token);
993 if (LocaleCompare((
char *) keyword,
"value") == 0)
995 policy_info->value=AcquirePolicyString(token,1);
1004 token=(
char *) RelinquishMagickMemory(token);
1005 if (status == MagickFalse)
1006 CatchException(exception);
1007 return(status != 0 ? MagickTrue : MagickFalse);
1028MagickExport MagickBooleanType PolicyComponentGenesis(
void)
1031 policy_semaphore=AllocateSemaphoreInfo();
1054static void *DestroyPolicyElement(
void *policy_info)
1060 if (p->exempt == MagickFalse)
1062 if (p->value != (
char *) NULL)
1063 p->value=DestroyString(p->value);
1064 if (p->pattern != (
char *) NULL)
1065 p->pattern=DestroyString(p->pattern);
1066 if (p->name != (
char *) NULL)
1067 p->name=DestroyString(p->name);
1068 if (p->path != (
char *) NULL)
1069 p->path=DestroyString(p->path);
1072 return((
void *) NULL);
1075MagickExport
void PolicyComponentTerminus(
void)
1078 ActivateSemaphoreInfo(&policy_semaphore);
1079 LockSemaphoreInfo(policy_semaphore);
1081 policy_cache=DestroyLinkedList(policy_cache,DestroyPolicyElement);
1082 UnlockSemaphoreInfo(policy_semaphore);
1083 DestroySemaphoreInfo(&policy_semaphore);
1113static MagickBooleanType ValidateSecurityPolicy(
const char *policy,
1116#if defined(MAGICKCORE_XML_DELEGATE)
1123 document=xmlReadMemory(policy,(
int) strlen(policy),url,NULL,
1124 XML_PARSE_NOERROR | XML_PARSE_NOWARNING);
1125 if (document == (xmlDocPtr) NULL)
1127 (void) ThrowMagickException(exception,GetMagickModule(),ConfigureError,
1128 "PolicyValidationException",
"'%s'",url);
1129 return(MagickFalse);
1131 xmlFreeDoc(document);
1140MagickExport MagickBooleanType SetMagickSecurityPolicy(
const char *policy,
1150 if (policy == (
const char *) NULL)
1151 return(MagickFalse);
1152 if (ValidateSecurityPolicy(policy,PolicyFilename,exception) == MagickFalse)
1153 return(MagickFalse);
1154 if (IsPolicyCacheInstantiated(exception) == MagickFalse)
1155 return(MagickFalse);
1156 LockSemaphoreInfo(policy_semaphore);
1157 ResetLinkedListIterator(policy_cache);
1158 p=(
PolicyInfo *) GetNextValueInLinkedList(policy_cache);
1159 if ((p != (
PolicyInfo *) NULL) && (p->domain != UndefinedPolicyDomain))
1161 UnlockSemaphoreInfo(policy_semaphore);
1162 return(MagickFalse);
1164 UnlockSemaphoreInfo(policy_semaphore);
1165 status=LoadPolicyCache(policy_cache,policy,
"[user-policy]",0,exception);
1166 if (status == MagickFalse)
1167 return(MagickFalse);
1168 return(ResourceComponentGenesis());