造冰箱的大熊猫@cnblogs 2019/1/21
1、环境
操作系统/Ubuntu 16.04.5 LTS,内核/4.15.0-43-generic,convert/ImageMagick 6.8.9-9
2、问题
使用convert命令将一个jpeg格式的图片文件转换为pdf文档时,提示“convert: not authorized `1.pdf` @ error/constitute.c/WriteImage/1028”错误。
$ convert 1.jpg 1.pdf convert: not authorized `1.pdf` @ error/constitute.c/WriteImage/1028. $
3、分析
不关心问题原因的,可以跳过这部分直接跳到下面的“4、排除故障”。
从sourceforge下载ImageMagick的源代码压缩包(版本6.8.9-10,没找到6.8.9-9的源代码)[1]。解压缩获得源代码。
根据错误信息,在源代码“magick”目录下打开“constitute.c”文件,并跳转到该文件的1028行(下面代码中第6行)。从代码中可以看到,错误是由于IsRightsAuthorized()函数返回错误导致的。
domain=CoderPolicyDomain; rights=WritePolicyRights; if (IsRightsAuthorized(domain,rights,write_info->magick) == MagickFalse) { sans_exception=DestroyExceptionInfo(sans_exception); write_info=DestroyImageInfo(write_info); errno=EPERM; ThrowBinaryException(PolicyError,"NotAuthorized",filename); }
打开“policy.c” 文件,找到IsRightsAuthorized()函数的代码(如下所示),判断函数返回失败(MagickFalse)是由于给定的PolicyDomian和PoicyRights与policy_cache中的值不匹配导致的。
MagickExport MagickBooleanType IsRightsAuthorized(const PolicyDomain domain, const PolicyRights rights,const char *pattern) { const PolicyInfo *policy_info; ExceptionInfo *exception; MagickBooleanType authorized; register PolicyInfo *p; (void) LogMagickEvent(PolicyEvent,GetMagickModule(), "Domain: %s; rights=%s; pattern=\"%s\" ...", CommandOptionToMnemonic(MagickPolicyDomainOptions,domain), CommandOptionToMnemonic(MagickPolicyRightsOptions,rights),pattern); exception=AcquireExceptionInfo(); policy_info=GetPolicyInfo("*",exception); exception=DestroyExceptionInfo(exception); if (policy_info == (PolicyInfo *) NULL) return(MagickTrue); authorized=MagickTrue; LockSemaphoreInfo(policy_semaphore); ResetLinkedListIterator(policy_cache); p=(PolicyInfo *) GetNextValueInLinkedList(policy_cache); while ((p != (PolicyInfo *) NULL) && (authorized != MagickFalse)) { if ((p->domain == domain) && (GlobExpression(pattern,p->pattern,MagickFalse) != MagickFalse)) { if (((rights & ReadPolicyRights) != 0) && ((p->rights & ReadPolicyRights) == 0)) authorized=MagickFalse; if (((rights & WritePolicyRights) != 0) && ((p->rights & WritePolicyRights) == 0)) authorized=MagickFalse; if (((rights & ExecutePolicyRights) != 0) && ((p->rights & ExecutePolicyRights) == 0)) authorized=MagickFalse; } p=(PolicyInfo *) GetNextValueInLinkedList(policy_cache); } UnlockSemaphoreInfo(policy_semaphore); return(authorized); }
在该文件中继续搜索,发现policy_cache由IsPolicyCacheInstantiated()函数从PolicyFilename指向的文件中读取。而PolicyFilename为“policy.xml”(#define PolicyFilename "policy.xml")。
static MagickBooleanType IsPolicyCacheInstantiated(ExceptionInfo *exception) { if (policy_cache == (LinkedListInfo *) NULL) { if (policy_semaphore == (SemaphoreInfo *) NULL) ActivateSemaphoreInfo(&policy_semaphore); LockSemaphoreInfo(policy_semaphore); if (policy_cache == (LinkedListInfo *) NULL) policy_cache=AcquirePolicyCache(PolicyFilename,exception); UnlockSemaphoreInfo(policy_semaphore); } return(policy_cache != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse); }
在“/etc/ImageMagick-6”下搜索到“policy.xml”文件。根据该文件中给出的注释信息,pdf文件的权限被设置为“none”,要想获得写权限,需增加“write”权限。具体操作步骤参考“4、排除故障”。
在policy.xml禁止pdf写权限是在Ubuntu的某次安全性升级时实施的[2],具体与imagemagickluanchpad的安全策略相关[ 3]。没仔细研究到底是什么情况,有兴趣的研究明白的请告知。
4、排除故障
使用文件编辑器打开“/etc/ImageMagick-6/policy.xml”,找到类似“<policy domain="coder" rights="none" pattern="PDF" />”的一行,将其中的“none”改为“write”,保存文件。重新执行convert命令即可。
参考