/src/imagemagick/MagickCore/policy.c
Line | Count | Source |
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 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/license/ % |
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 | | */ |
36 | | |
37 | | /* |
38 | | Include declarations. |
39 | | */ |
40 | | #include "MagickCore/studio.h" |
41 | | #include "MagickCore/cache-private.h" |
42 | | #include "MagickCore/client.h" |
43 | | #include "MagickCore/configure.h" |
44 | | #include "MagickCore/configure-private.h" |
45 | | #include "MagickCore/exception.h" |
46 | | #include "MagickCore/exception-private.h" |
47 | | #include "MagickCore/linked-list-private.h" |
48 | | #include "MagickCore/magick-private.h" |
49 | | #include "MagickCore/memory_.h" |
50 | | #include "MagickCore/memory-private.h" |
51 | | #include "MagickCore/monitor.h" |
52 | | #include "MagickCore/monitor-private.h" |
53 | | #include "MagickCore/option.h" |
54 | | #include "MagickCore/policy.h" |
55 | | #include "MagickCore/policy-private.h" |
56 | | #include "MagickCore/resource_.h" |
57 | | #include "MagickCore/resource-private.h" |
58 | | #include "MagickCore/semaphore.h" |
59 | | #include "MagickCore/stream-private.h" |
60 | | #include "MagickCore/string_.h" |
61 | | #include "MagickCore/string-private.h" |
62 | | #include "MagickCore/token.h" |
63 | | #include "MagickCore/timer-private.h" |
64 | | #include "MagickCore/utility.h" |
65 | | #include "MagickCore/utility-private.h" |
66 | | #include "MagickCore/xml-tree.h" |
67 | | #include "MagickCore/xml-tree-private.h" |
68 | | #if defined(MAGICKCORE_XML_DELEGATE) |
69 | | # include <libxml/parser.h> |
70 | | # include <libxml/tree.h> |
71 | | #endif |
72 | | |
73 | | /* |
74 | | Define declarations. |
75 | | */ |
76 | 295 | #define PolicyFilename "policy.xml" |
77 | | |
78 | | /* |
79 | | Typedef declarations. |
80 | | */ |
81 | | struct _PolicyInfo |
82 | | { |
83 | | char |
84 | | *path; |
85 | | |
86 | | PolicyDomain |
87 | | domain; |
88 | | |
89 | | PolicyRights |
90 | | rights; |
91 | | |
92 | | char |
93 | | *name, |
94 | | *pattern, |
95 | | *value; |
96 | | |
97 | | MagickBooleanType |
98 | | exempt, |
99 | | stealth, |
100 | | debug; |
101 | | |
102 | | SemaphoreInfo |
103 | | *semaphore; |
104 | | |
105 | | size_t |
106 | | signature; |
107 | | }; |
108 | | |
109 | | typedef struct _PolicyMapInfo |
110 | | { |
111 | | const PolicyDomain |
112 | | domain; |
113 | | |
114 | | const PolicyRights |
115 | | rights; |
116 | | |
117 | | const char |
118 | | *name, |
119 | | *pattern, |
120 | | *value; |
121 | | } PolicyMapInfo; |
122 | | |
123 | | /* |
124 | | Static declarations. |
125 | | */ |
126 | | static const PolicyMapInfo |
127 | | PolicyMap[] = |
128 | | { |
129 | | { UndefinedPolicyDomain, UndefinedPolicyRights, (const char *) NULL, |
130 | | (const char *) NULL, (const char *) NULL } |
131 | | }; |
132 | | |
133 | | static LinkedListInfo |
134 | | *policy_cache = (LinkedListInfo *) NULL; |
135 | | |
136 | | static SemaphoreInfo |
137 | | *policy_semaphore = (SemaphoreInfo *) NULL; |
138 | | |
139 | | /* |
140 | | Forward declarations. |
141 | | */ |
142 | | static MagickBooleanType |
143 | | IsPolicyCacheInstantiated(ExceptionInfo *), |
144 | | LoadPolicyCache(LinkedListInfo *,const char *,const char *,const size_t, |
145 | | ExceptionInfo *); |
146 | | |
147 | | /* |
148 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
149 | | % % |
150 | | % % |
151 | | % % |
152 | | % A c q u i r e P o l i c y C a c h e % |
153 | | % % |
154 | | % % |
155 | | % % |
156 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
157 | | % |
158 | | % AcquirePolicyCache() caches one or more policy configurations which provides |
159 | | % a mapping between policy attributes and a policy name. |
160 | | % |
161 | | % The format of the AcquirePolicyCache method is: |
162 | | % |
163 | | % LinkedListInfo *AcquirePolicyCache(const char *filename, |
164 | | % ExceptionInfo *exception) |
165 | | % |
166 | | % A description of each parameter follows: |
167 | | % |
168 | | % o filename: the policy configuration file name. |
169 | | % |
170 | | % o exception: return any errors or warnings in this structure. |
171 | | % |
172 | | */ |
173 | | static LinkedListInfo *AcquirePolicyCache(const char *filename, |
174 | | ExceptionInfo *exception) |
175 | 295 | { |
176 | 295 | LinkedListInfo |
177 | 295 | *cache; |
178 | | |
179 | 295 | MagickBooleanType |
180 | 295 | status; |
181 | | |
182 | 295 | ssize_t |
183 | 295 | i; |
184 | | |
185 | | /* |
186 | | Load external policy map. |
187 | | */ |
188 | 295 | cache=NewLinkedList(0); |
189 | 295 | status=MagickTrue; |
190 | | #if MAGICKCORE_ZERO_CONFIGURATION_SUPPORT |
191 | | magick_unreferenced(filename); |
192 | | status=LoadPolicyCache(cache,ZeroConfigurationPolicy,"[zero-configuration]",0, |
193 | | exception); |
194 | | if (status == MagickFalse) |
195 | | CatchException(exception); |
196 | | #else |
197 | 295 | { |
198 | 295 | const StringInfo |
199 | 295 | *option; |
200 | | |
201 | 295 | LinkedListInfo |
202 | 295 | *options; |
203 | | |
204 | 295 | options=GetConfigureOptions(filename,exception); |
205 | 295 | option=(const StringInfo *) GetNextValueInLinkedList(options); |
206 | 295 | while (option != (const StringInfo *) NULL) |
207 | 0 | { |
208 | 0 | status=LoadPolicyCache(cache,(const char *) GetStringInfoDatum(option), |
209 | 0 | GetStringInfoPath(option),0,exception); |
210 | 0 | if (status == MagickFalse) |
211 | 0 | CatchException(exception); |
212 | 0 | option=(const StringInfo *) GetNextValueInLinkedList(options); |
213 | 0 | } |
214 | 295 | options=DestroyConfigureOptions(options); |
215 | 295 | } |
216 | 295 | #endif |
217 | | /* |
218 | | Load built-in policy map. |
219 | | */ |
220 | 590 | for (i=0; i < (ssize_t) (sizeof(PolicyMap)/sizeof(*PolicyMap)); i++) |
221 | 295 | { |
222 | 295 | const PolicyMapInfo |
223 | 295 | *p; |
224 | | |
225 | 295 | PolicyInfo |
226 | 295 | *policy_info; |
227 | | |
228 | 295 | p=PolicyMap+i; |
229 | 295 | policy_info=(PolicyInfo *) AcquireMagickMemory(sizeof(*policy_info)); |
230 | 295 | if (policy_info == (PolicyInfo *) NULL) |
231 | 0 | { |
232 | 0 | (void) ThrowMagickException(exception,GetMagickModule(), |
233 | 0 | ResourceLimitError,"MemoryAllocationFailed","`%s'", |
234 | 0 | p->name == (char *) NULL ? "" : p->name); |
235 | 0 | CatchException(exception); |
236 | 0 | continue; |
237 | 0 | } |
238 | 295 | (void) memset(policy_info,0,sizeof(*policy_info)); |
239 | 295 | policy_info->path=(char *) "[built-in]"; |
240 | 295 | policy_info->domain=p->domain; |
241 | 295 | policy_info->rights=p->rights; |
242 | 295 | policy_info->name=(char *) p->name; |
243 | 295 | policy_info->pattern=(char *) p->pattern; |
244 | 295 | policy_info->value=(char *) p->value; |
245 | 295 | policy_info->exempt=MagickTrue; |
246 | 295 | policy_info->signature=MagickCoreSignature; |
247 | 295 | status=AppendValueToLinkedList(cache,policy_info); |
248 | 295 | if (status == MagickFalse) |
249 | 0 | { |
250 | 0 | (void) ThrowMagickException(exception,GetMagickModule(), |
251 | 0 | ResourceLimitError,"MemoryAllocationFailed","`%s'", |
252 | 0 | p->name == (char *) NULL ? "" : p->name); |
253 | 0 | CatchException(exception); |
254 | 0 | } |
255 | 295 | } |
256 | 295 | return(cache); |
257 | 295 | } |
258 | | |
259 | | /* |
260 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
261 | | % % |
262 | | % % |
263 | | % % |
264 | | + G e t P o l i c y I n f o % |
265 | | % % |
266 | | % % |
267 | | % % |
268 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
269 | | % |
270 | | % GetPolicyInfo() searches the policy list for the specified name and if found |
271 | | % returns attributes for that policy. |
272 | | % |
273 | | % The format of the GetPolicyInfo method is: |
274 | | % |
275 | | % PolicyInfo *GetPolicyInfo(const char *name,ExceptionInfo *exception) |
276 | | % |
277 | | % A description of each parameter follows: |
278 | | % |
279 | | % o name: the policy name. |
280 | | % |
281 | | % o exception: return any errors or warnings in this structure. |
282 | | % |
283 | | */ |
284 | | static PolicyInfo *GetPolicyInfo(const char *name,ExceptionInfo *exception) |
285 | 3.44M | { |
286 | 3.44M | char |
287 | 3.44M | policyname[MagickPathExtent], |
288 | 3.44M | *q; |
289 | | |
290 | 3.44M | ElementInfo |
291 | 3.44M | *p; |
292 | | |
293 | 3.44M | PolicyDomain |
294 | 3.44M | domain; |
295 | | |
296 | 3.44M | PolicyInfo |
297 | 3.44M | *policy; |
298 | | |
299 | 3.44M | assert(exception != (ExceptionInfo *) NULL); |
300 | 3.44M | if (IsPolicyCacheInstantiated(exception) == MagickFalse) |
301 | 0 | return((PolicyInfo *) NULL); |
302 | | /* |
303 | | Strip names of whitespace. |
304 | | */ |
305 | 3.44M | *policyname='\0'; |
306 | 3.44M | if (name != (const char *) NULL) |
307 | 3.44M | (void) CopyMagickString(policyname,name,MagickPathExtent); |
308 | 63.4M | for (q=policyname; *q != '\0'; q++) |
309 | 60.0M | { |
310 | 60.0M | if (isspace((int) ((unsigned char) *q)) == 0) |
311 | 60.0M | continue; |
312 | 0 | (void) CopyMagickString(q,q+1,MagickPathExtent); |
313 | 0 | q--; |
314 | 0 | } |
315 | | /* |
316 | | Strip domain from policy name (e.g. resource:map). |
317 | | */ |
318 | 3.44M | domain=UndefinedPolicyDomain; |
319 | 21.6M | for (q=policyname; *q != '\0'; q++) |
320 | 21.6M | { |
321 | 21.6M | if (*q != ':') |
322 | 18.1M | continue; |
323 | 3.44M | *q='\0'; |
324 | 3.44M | domain=(PolicyDomain) ParseCommandOption(MagickPolicyDomainOptions, |
325 | 3.44M | MagickTrue,policyname); |
326 | 3.44M | (void) CopyMagickString(policyname,q+1,MagickPathExtent); |
327 | 3.44M | break; |
328 | 21.6M | } |
329 | | /* |
330 | | Search for policy tag. |
331 | | */ |
332 | 3.44M | policy=(PolicyInfo *) NULL; |
333 | 3.44M | LockSemaphoreInfo(policy_semaphore); |
334 | 3.44M | ResetLinkedListIterator(policy_cache); |
335 | 3.44M | p=GetHeadElementInLinkedList(policy_cache); |
336 | 3.44M | if ((name == (const char *) NULL) || (LocaleCompare(name,"*") == 0)) |
337 | 0 | { |
338 | 0 | UnlockSemaphoreInfo(policy_semaphore); |
339 | 0 | if (p != (ElementInfo *) NULL) |
340 | 0 | policy=(PolicyInfo *) p->value; |
341 | 0 | return(policy); |
342 | 0 | } |
343 | 6.89M | while (p != (ElementInfo *) NULL) |
344 | 3.44M | { |
345 | 3.44M | policy=(PolicyInfo *) p->value; |
346 | 3.44M | if ((domain == UndefinedPolicyDomain) || (policy->domain == domain)) |
347 | 0 | if (LocaleCompare(policyname,policy->name) == 0) |
348 | 0 | break; |
349 | 3.44M | p=p->next; |
350 | 3.44M | } |
351 | 3.44M | if (p == (ElementInfo *) NULL) |
352 | 3.44M | policy=(PolicyInfo *) NULL; |
353 | 0 | else |
354 | 0 | (void) SetHeadElementInLinkedList(policy_cache,p); |
355 | 3.44M | UnlockSemaphoreInfo(policy_semaphore); |
356 | 3.44M | return(policy); |
357 | 3.44M | } |
358 | | |
359 | | /* |
360 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
361 | | % % |
362 | | % % |
363 | | % % |
364 | | % G e t P o l i c y I n f o L i s t % |
365 | | % % |
366 | | % % |
367 | | % % |
368 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
369 | | % |
370 | | % GetPolicyInfoList() returns any policies that match the specified pattern. |
371 | | % |
372 | | % The format of the GetPolicyInfoList function is: |
373 | | % |
374 | | % const PolicyInfo **GetPolicyInfoList(const char *pattern, |
375 | | % size_t *number_policies,ExceptionInfo *exception) |
376 | | % |
377 | | % A description of each parameter follows: |
378 | | % |
379 | | % o pattern: Specifies a pointer to a text string containing a pattern. |
380 | | % |
381 | | % o number_policies: returns the number of policies in the list. |
382 | | % |
383 | | % o exception: return any errors or warnings in this structure. |
384 | | % |
385 | | */ |
386 | | MagickExport const PolicyInfo **GetPolicyInfoList(const char *pattern, |
387 | | size_t *number_policies,ExceptionInfo *exception) |
388 | 0 | { |
389 | 0 | const PolicyInfo |
390 | 0 | **policies; |
391 | |
|
392 | 0 | ElementInfo |
393 | 0 | *p; |
394 | |
|
395 | 0 | ssize_t |
396 | 0 | i; |
397 | |
|
398 | 0 | assert(pattern != (char *) NULL); |
399 | 0 | assert(number_policies != (size_t *) NULL); |
400 | 0 | if (IsEventLogging() != MagickFalse) |
401 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern); |
402 | 0 | *number_policies=0; |
403 | 0 | if (IsPolicyCacheInstantiated(exception) == MagickFalse) |
404 | 0 | return((const PolicyInfo **) NULL); |
405 | 0 | policies=(const PolicyInfo **) AcquireQuantumMemory((size_t) |
406 | 0 | GetNumberOfElementsInLinkedList(policy_cache)+1UL,sizeof(*policies)); |
407 | 0 | if (policies == (const PolicyInfo **) NULL) |
408 | 0 | return((const PolicyInfo **) NULL); |
409 | 0 | LockSemaphoreInfo(policy_semaphore); |
410 | 0 | p=GetHeadElementInLinkedList(policy_cache); |
411 | 0 | for (i=0; p != (ElementInfo *) NULL; ) |
412 | 0 | { |
413 | 0 | const PolicyInfo |
414 | 0 | *policy; |
415 | |
|
416 | 0 | policy=(const PolicyInfo *) p->value; |
417 | 0 | if ((policy->stealth == MagickFalse) && |
418 | 0 | (GlobExpression(policy->name,pattern,MagickFalse) != MagickFalse)) |
419 | 0 | policies[i++]=policy; |
420 | 0 | p=p->next; |
421 | 0 | } |
422 | 0 | UnlockSemaphoreInfo(policy_semaphore); |
423 | 0 | if (i == 0) |
424 | 0 | policies=(const PolicyInfo **) RelinquishMagickMemory((void*) policies); |
425 | 0 | else |
426 | 0 | policies[i]=(PolicyInfo *) NULL; |
427 | 0 | *number_policies=(size_t) i; |
428 | 0 | return(policies); |
429 | 0 | } |
430 | | |
431 | | /* |
432 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
433 | | % % |
434 | | % % |
435 | | % % |
436 | | % G e t P o l i c y L i s t % |
437 | | % % |
438 | | % % |
439 | | % % |
440 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
441 | | % |
442 | | % GetPolicyList() returns any policies that match the specified pattern. |
443 | | % |
444 | | % The format of the GetPolicyList function is: |
445 | | % |
446 | | % char **GetPolicyList(const char *pattern,size_t *number_policies, |
447 | | % ExceptionInfo *exception) |
448 | | % |
449 | | % A description of each parameter follows: |
450 | | % |
451 | | % o pattern: a pointer to a text string containing a pattern. |
452 | | % |
453 | | % o number_policies: returns the number of policies in the list. |
454 | | % |
455 | | % o exception: return any errors or warnings in this structure. |
456 | | % |
457 | | */ |
458 | | |
459 | | static char *AcquirePolicyString(const char *source,const size_t pad) |
460 | 0 | { |
461 | 0 | char |
462 | 0 | *destination; |
463 | |
|
464 | 0 | size_t |
465 | 0 | length; |
466 | |
|
467 | 0 | length=0; |
468 | 0 | if (source != (char *) NULL) |
469 | 0 | length+=strlen(source); |
470 | 0 | destination=(char *) NULL; |
471 | | /* AcquireMagickMemory needs to be used here to avoid an omp deadlock */ |
472 | 0 | if (~length >= pad) |
473 | 0 | destination=(char *) AcquireMagickMemory((length+pad)*sizeof(*destination)); |
474 | 0 | if (destination == (char *) NULL) |
475 | 0 | ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireString"); |
476 | 0 | if (source != (char *) NULL) |
477 | 0 | (void) memcpy(destination,source,length*sizeof(*destination)); |
478 | 0 | destination[length]='\0'; |
479 | 0 | return(destination); |
480 | 0 | } |
481 | | |
482 | | MagickExport char **GetPolicyList(const char *pattern,size_t *number_policies, |
483 | | ExceptionInfo *exception) |
484 | 0 | { |
485 | 0 | char |
486 | 0 | **policies; |
487 | |
|
488 | 0 | const ElementInfo |
489 | 0 | *p; |
490 | |
|
491 | 0 | ssize_t |
492 | 0 | i; |
493 | |
|
494 | 0 | assert(pattern != (char *) NULL); |
495 | 0 | assert(number_policies != (size_t *) NULL); |
496 | 0 | if (IsEventLogging() != MagickFalse) |
497 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern); |
498 | 0 | *number_policies=0; |
499 | 0 | if (IsPolicyCacheInstantiated(exception) == MagickFalse) |
500 | 0 | return((char **) NULL); |
501 | 0 | policies=(char **) AcquireQuantumMemory((size_t) |
502 | 0 | GetNumberOfElementsInLinkedList(policy_cache)+1UL,sizeof(*policies)); |
503 | 0 | if (policies == (char **) NULL) |
504 | 0 | return((char **) NULL); |
505 | 0 | LockSemaphoreInfo(policy_semaphore); |
506 | 0 | p=GetHeadElementInLinkedList(policy_cache); |
507 | 0 | for (i=0; p != (ElementInfo *) NULL; ) |
508 | 0 | { |
509 | 0 | const PolicyInfo |
510 | 0 | *policy; |
511 | |
|
512 | 0 | policy=(const PolicyInfo *) p->value; |
513 | 0 | if ((policy->stealth == MagickFalse) && |
514 | 0 | (GlobExpression(policy->name,pattern,MagickFalse) != MagickFalse)) |
515 | 0 | policies[i++]=AcquirePolicyString(policy->name,1); |
516 | 0 | p=p->next; |
517 | 0 | } |
518 | 0 | UnlockSemaphoreInfo(policy_semaphore); |
519 | 0 | if (i == 0) |
520 | 0 | policies=(char **) RelinquishMagickMemory(policies); |
521 | 0 | else |
522 | 0 | policies[i]=(char *) NULL; |
523 | 0 | *number_policies=(size_t) i; |
524 | 0 | return(policies); |
525 | 0 | } |
526 | | |
527 | | /* |
528 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
529 | | % % |
530 | | % % |
531 | | % % |
532 | | % G e t P o l i c y V a l u e % |
533 | | % % |
534 | | % % |
535 | | % % |
536 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
537 | | % |
538 | | % GetPolicyValue() returns the value associated with the named policy. |
539 | | % |
540 | | % The format of the GetPolicyValue method is: |
541 | | % |
542 | | % char *GetPolicyValue(const char *name) |
543 | | % |
544 | | % A description of each parameter follows: |
545 | | % |
546 | | % o name: The name of the policy. |
547 | | % |
548 | | */ |
549 | | MagickExport char *GetPolicyValue(const char *name) |
550 | 3.44M | { |
551 | 3.44M | const char |
552 | 3.44M | *value; |
553 | | |
554 | 3.44M | const PolicyInfo |
555 | 3.44M | *policy_info; |
556 | | |
557 | 3.44M | ExceptionInfo |
558 | 3.44M | *exception; |
559 | | |
560 | 3.44M | assert(name != (const char *) NULL); |
561 | 3.44M | if (IsEventLogging() != MagickFalse) |
562 | 0 | (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",name); |
563 | 3.44M | exception=AcquireExceptionInfo(); |
564 | 3.44M | policy_info=GetPolicyInfo(name,exception); |
565 | 3.44M | exception=DestroyExceptionInfo(exception); |
566 | 3.44M | if (policy_info == (PolicyInfo *) NULL) |
567 | 3.44M | return((char *) NULL); |
568 | 0 | value=policy_info->value; |
569 | 0 | if ((value == (const char *) NULL) || (*value == '\0')) |
570 | 0 | return((char *) NULL); |
571 | 0 | return(AcquirePolicyString(value,1)); |
572 | 0 | } |
573 | | |
574 | | /* |
575 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
576 | | % % |
577 | | % % |
578 | | % % |
579 | | + I s P a t h A u t h o r i z e d % |
580 | | % % |
581 | | % % |
582 | | % % |
583 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
584 | | % |
585 | | % IsPathAuthorized() determines if the specified path is authorized based on |
586 | | % the current policy settings. |
587 | | % |
588 | | % The format of the IsPathAuthorized method is: |
589 | | % |
590 | | % MagickBooleanType IsPathAuthorized(const PolicyRights rights, |
591 | | % const char *path) |
592 | | % |
593 | | % A description of each parameter follows. |
594 | | % |
595 | | % o rights: The policy rights to check. |
596 | | % |
597 | | % o path: The path to check. |
598 | | % |
599 | | */ |
600 | | static inline MagickBooleanType IsPathContainsSymlink(const char *path) |
601 | 0 | { |
602 | 0 | char |
603 | 0 | partial[MagickPathExtent]; |
604 | |
|
605 | 0 | const char |
606 | 0 | *p; |
607 | |
|
608 | 0 | ssize_t |
609 | 0 | offset = 0; |
610 | |
|
611 | 0 | if (path == (const char *) NULL) |
612 | 0 | return(MagickFalse); |
613 | 0 | *partial='\0'; |
614 | 0 | p=path; |
615 | 0 | if (*p == *DirectorySeparator) |
616 | 0 | { |
617 | | /* |
618 | | Path starts with a directory separator, include it. |
619 | | */ |
620 | 0 | if ((offset+1) >= (ssize_t) sizeof(partial)) |
621 | 0 | return(MagickFalse); |
622 | 0 | partial[offset++]=(*p++); |
623 | 0 | partial[offset]='\0'; |
624 | 0 | } |
625 | 0 | while (*p != '\0') |
626 | 0 | { |
627 | 0 | char |
628 | 0 | component[MagickPathExtent]; |
629 | |
|
630 | 0 | ssize_t |
631 | 0 | i = 0; |
632 | | |
633 | | /* |
634 | | Copy next component into a temporary buffer. |
635 | | */ |
636 | 0 | while ((*p != '\0') && (*p != *DirectorySeparator) && |
637 | 0 | ((i+1) < (ssize_t) sizeof(component))) |
638 | 0 | component[i++]=(*p++); |
639 | 0 | component[i]='\0'; |
640 | 0 | if (i == 0) |
641 | 0 | { |
642 | | /* |
643 | | skip repeated separators. |
644 | | */ |
645 | 0 | if (*p == *DirectorySeparator) |
646 | 0 | p++; |
647 | 0 | continue; |
648 | 0 | } |
649 | 0 | if ((offset > 0) && (partial[offset-1] != *DirectorySeparator)) |
650 | 0 | { |
651 | | /* |
652 | | Append separator if needed. |
653 | | */ |
654 | 0 | if ((offset+1) >= (ssize_t) sizeof(partial)) |
655 | 0 | return MagickFalse; |
656 | 0 | partial[offset++]=(*DirectorySeparator); |
657 | 0 | partial[offset]='\0'; |
658 | 0 | } |
659 | | /* |
660 | | Append component. |
661 | | */ |
662 | 0 | if ((offset+i) >= (ssize_t) sizeof(partial)) |
663 | 0 | return(MagickFalse); |
664 | 0 | (void) memcpy(partial+offset,component,i); |
665 | 0 | offset+=i; |
666 | 0 | partial[offset]='\0'; |
667 | 0 | if (*p != '\0') |
668 | 0 | { |
669 | | /* |
670 | | Check whether this prefix is a symlink. |
671 | | */ |
672 | 0 | if (is_symlink_utf8(partial) != MagickFalse) |
673 | 0 | return(MagickTrue); |
674 | 0 | } |
675 | | /* |
676 | | Skip separator. |
677 | | */ |
678 | 0 | if (*p == *DirectorySeparator) |
679 | 0 | p++; |
680 | 0 | } |
681 | 0 | return(MagickFalse); |
682 | 0 | } |
683 | | |
684 | | MagickExport MagickBooleanType IsPathAuthorized(const PolicyRights rights, |
685 | | const char *path) |
686 | 621k | { |
687 | 621k | MagickBooleanType symlink_follow_allowed = IsRightsAuthorizedByName( |
688 | 621k | SystemPolicyDomain,"symlink",rights,"follow"); |
689 | 621k | MagickBooleanType status = |
690 | 621k | ((IsRightsAuthorized(PathPolicyDomain,rights,path) != MagickFalse) && |
691 | 621k | ((symlink_follow_allowed != MagickFalse) || |
692 | 621k | (is_symlink_utf8(path) == MagickFalse))) ? MagickTrue : MagickFalse; |
693 | 621k | if ((status != MagickFalse) && (symlink_follow_allowed == MagickFalse)) |
694 | 0 | { |
695 | 0 | if ((is_symlink_utf8(path) != MagickFalse) || |
696 | 0 | (IsPathContainsSymlink(path) != MagickFalse)) |
697 | 0 | status=MagickFalse; |
698 | 0 | } |
699 | 621k | if (status != MagickFalse) |
700 | 621k | status=IsFileResourceIdentityValid(path); |
701 | 621k | return(status); |
702 | 621k | } |
703 | | |
704 | | /* |
705 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
706 | | % % |
707 | | % % |
708 | | % % |
709 | | + 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 % |
710 | | % % |
711 | | % % |
712 | | % % |
713 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
714 | | % |
715 | | % IsPolicyCacheInstantiated() determines if the policy list is instantiated. |
716 | | % If not, it instantiates the list and returns it. |
717 | | % |
718 | | % The format of the IsPolicyInstantiated method is: |
719 | | % |
720 | | % MagickBooleanType IsPolicyCacheInstantiated(ExceptionInfo *exception) |
721 | | % |
722 | | % A description of each parameter follows. |
723 | | % |
724 | | % o exception: return any errors or warnings in this structure. |
725 | | % |
726 | | */ |
727 | | static MagickBooleanType IsPolicyCacheInstantiated(ExceptionInfo *exception) |
728 | 6.42M | { |
729 | 6.42M | if (policy_cache == (LinkedListInfo *) NULL) |
730 | 295 | { |
731 | 295 | (void) GetMaxMemoryRequest(); /* avoid OMP deadlock */ |
732 | 295 | if (policy_semaphore == (SemaphoreInfo *) NULL) |
733 | 295 | ActivateSemaphoreInfo(&policy_semaphore); |
734 | 295 | LockSemaphoreInfo(policy_semaphore); |
735 | 295 | if (policy_cache == (LinkedListInfo *) NULL) |
736 | 295 | policy_cache=AcquirePolicyCache(PolicyFilename,exception); |
737 | 295 | UnlockSemaphoreInfo(policy_semaphore); |
738 | 295 | } |
739 | 6.42M | return(policy_cache != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse); |
740 | 6.42M | } |
741 | | |
742 | | /* |
743 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
744 | | % % |
745 | | % % |
746 | | % % |
747 | | % I s R i g h t s A u t h o r i z e d % |
748 | | % % |
749 | | % % |
750 | | % % |
751 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
752 | | % |
753 | | % IsRightsAuthorized() returns MagickTrue if the policy authorizes the |
754 | | % requested rights for the specified domain. |
755 | | % |
756 | | % Policy evaluation uses a “last match wins” model. Be careful when adding |
757 | | % new rules: any later policy can override earlier denies or allows. Place |
758 | | % broad deny rules first, followed by specific exceptions, and review |
759 | | % ordering to avoid accidental authorization. |
760 | | % |
761 | | % The format of the IsRightsAuthorized method is: |
762 | | % |
763 | | % MagickBooleanType IsRightsAuthorized(const PolicyDomain domain, |
764 | | % const PolicyRights rights,const char *pattern) |
765 | | % |
766 | | % A description of each parameter follows: |
767 | | % |
768 | | % o domain: the policy domain. |
769 | | % |
770 | | % o rights: the policy rights. |
771 | | % |
772 | | % o pattern: the pattern. |
773 | | % |
774 | | */ |
775 | | |
776 | | MagickExport MagickBooleanType IsRightsAuthorizedByName( |
777 | | const PolicyDomain domain,const char *name,const PolicyRights rights, |
778 | | const char *pattern) |
779 | 2.98M | { |
780 | 2.98M | char |
781 | 2.98M | *canonical_directory = (char *) NULL, |
782 | 2.98M | *canonical_path = (char *) NULL, |
783 | 2.98M | *canonical_candidate = (char *) NULL, |
784 | 2.98M | directory[MagickPathExtent], |
785 | 2.98M | filename[MagickPathExtent]; |
786 | | |
787 | 2.98M | ElementInfo |
788 | 2.98M | *p; |
789 | | |
790 | 2.98M | ExceptionInfo |
791 | 2.98M | *exception; |
792 | | |
793 | 2.98M | MagickBooleanType |
794 | 2.98M | canonical_matched_any = MagickFalse, |
795 | 2.98M | matched_any = MagickFalse, |
796 | 2.98M | paths_provisioned = MagickFalse, |
797 | 2.98M | status; |
798 | | |
799 | 2.98M | PolicyRights |
800 | 2.98M | canonical_allowed_accumulator = AllPolicyRights, |
801 | 2.98M | effective_rights = AllPolicyRights; |
802 | | |
803 | | /* |
804 | | Load policies. |
805 | | */ |
806 | 2.98M | if ((GetLogEventMask() & PolicyEvent) != 0) |
807 | 0 | (void) LogMagickEvent(PolicyEvent,GetMagickModule(), |
808 | 0 | "Domain: %s; name: %s; rights=%s; pattern=\"%s\"; ...", |
809 | 0 | CommandOptionToMnemonic(MagickPolicyDomainOptions,domain), |
810 | 0 | name == (const char *) NULL ? "undefined" : name, |
811 | 0 | CommandOptionToMnemonic(MagickPolicyRightsOptions,rights), |
812 | 0 | pattern == (const char *) NULL ? "undefined" : pattern); |
813 | 2.98M | exception=AcquireExceptionInfo(); |
814 | 2.98M | status=IsPolicyCacheInstantiated(exception); |
815 | 2.98M | exception=DestroyExceptionInfo(exception); |
816 | 2.98M | if (status == MagickFalse) |
817 | 0 | { |
818 | 0 | if ((GetLogEventMask() & PolicyEvent) != 0) |
819 | 0 | (void) LogMagickEvent(PolicyEvent,GetMagickModule(), |
820 | 0 | " authorized: true (no security policies found)"); |
821 | 0 | return(MagickTrue); |
822 | 0 | } |
823 | | /* |
824 | | Evaluate policies in order; last match wins, however, canonical denies are |
825 | | enforced after evaluation. |
826 | | */ |
827 | 2.98M | LockSemaphoreInfo(policy_semaphore); |
828 | 2.98M | ResetLinkedListIterator(policy_cache); |
829 | 2.98M | p=GetHeadElementInLinkedList(policy_cache); |
830 | 5.96M | for ( ; p != (ElementInfo *) NULL; p=p->next) |
831 | 2.98M | { |
832 | 2.98M | const PolicyInfo |
833 | 2.98M | *policy = (PolicyInfo *) p->value; |
834 | | |
835 | 2.98M | MagickBooleanType |
836 | 2.98M | match = MagickFalse, |
837 | 2.98M | matched_canonical = MagickFalse; |
838 | | |
839 | 2.98M | if (policy->domain != domain) |
840 | 2.98M | continue; |
841 | 0 | if ((name != (char *) NULL) && (LocaleCompare(name,policy->name) != 0)) |
842 | 0 | continue; |
843 | 0 | match=GlobExpression(pattern,policy->pattern,MagickFalse); |
844 | 0 | if (policy->domain == PathPolicyDomain) |
845 | 0 | { |
846 | 0 | if (paths_provisioned == MagickFalse) |
847 | 0 | { |
848 | | /* |
849 | | Generate directory, basename, and canonical path. |
850 | | */ |
851 | 0 | paths_provisioned=MagickTrue; |
852 | 0 | GetPathComponent(pattern,HeadPath,directory); |
853 | 0 | GetPathComponent(pattern,TailPath,filename); |
854 | 0 | canonical_directory=realpath_utf8(directory); |
855 | 0 | if ((canonical_directory != (char *) NULL) && (*filename != '\0')) |
856 | 0 | { |
857 | 0 | size_t |
858 | 0 | length; |
859 | |
|
860 | 0 | length=strlen(canonical_directory)+strlen(filename)+2; |
861 | 0 | canonical_candidate=(char *) AcquireCriticalMemory(length* |
862 | 0 | sizeof(*canonical_candidate)); |
863 | 0 | if (canonical_candidate != (char *) NULL) |
864 | 0 | (void) FormatLocaleString(canonical_candidate,length,"%s%s%s", |
865 | 0 | canonical_directory,DirectorySeparator,filename); |
866 | 0 | } |
867 | 0 | canonical_path=realpath_utf8(pattern); |
868 | 0 | } |
869 | | /* |
870 | | Match against directory, basename, and canonical path. |
871 | | */ |
872 | 0 | if ((canonical_directory != (char *) NULL) && (match == MagickFalse)) |
873 | 0 | match=GlobExpression(canonical_directory,policy->pattern,MagickFalse); |
874 | 0 | if ((canonical_candidate != (char *) NULL) && (match == MagickFalse)) |
875 | 0 | match=GlobExpression(canonical_candidate,policy->pattern,MagickFalse); |
876 | 0 | if ((canonical_path != (char *) NULL) && (match == MagickFalse)) |
877 | 0 | match=GlobExpression(canonical_path,policy->pattern,MagickFalse); |
878 | 0 | if ((canonical_path != (char *) NULL) && |
879 | 0 | (GlobExpression(canonical_path,policy->pattern,MagickFalse) != MagickFalse)) |
880 | 0 | matched_canonical=MagickTrue; |
881 | 0 | else |
882 | 0 | if ((canonical_candidate != (char *) NULL) && |
883 | 0 | (GlobExpression(canonical_candidate,policy->pattern,MagickFalse) != MagickFalse)) |
884 | 0 | matched_canonical=MagickTrue; |
885 | 0 | else |
886 | 0 | if ((canonical_directory != (char *) NULL) && |
887 | 0 | (GlobExpression(canonical_directory,policy->pattern,MagickFalse) != MagickFalse)) |
888 | 0 | matched_canonical=MagickTrue; |
889 | 0 | } |
890 | 0 | if (match == MagickFalse) |
891 | 0 | continue; |
892 | 0 | matched_any=MagickTrue; |
893 | 0 | effective_rights=policy->rights; |
894 | 0 | if (matched_canonical != MagickFalse) |
895 | 0 | { |
896 | | /* |
897 | | If this match was against a canonical form, accumulate allowed rights. |
898 | | */ |
899 | 0 | canonical_matched_any=MagickTrue; |
900 | 0 | canonical_allowed_accumulator=(PolicyRights) ((int) |
901 | 0 | canonical_allowed_accumulator & (int) policy->rights); |
902 | 0 | } |
903 | 0 | } |
904 | 2.98M | UnlockSemaphoreInfo(policy_semaphore); |
905 | 2.98M | if (canonical_directory != (char *) NULL) |
906 | 0 | canonical_directory=DestroyString(canonical_directory); |
907 | 2.98M | if (canonical_candidate != (char *) NULL) |
908 | 0 | canonical_candidate=DestroyString(canonical_candidate); |
909 | 2.98M | if (canonical_path != (char *) NULL) |
910 | 0 | canonical_path=DestroyString(canonical_path); |
911 | | /* |
912 | | Is rights authorized? |
913 | | */ |
914 | 2.98M | status=MagickTrue; |
915 | 2.98M | if (matched_any != MagickFalse) |
916 | 0 | { |
917 | 0 | if (((rights & ReadPolicyRights) != 0) && |
918 | 0 | ((effective_rights & ReadPolicyRights) == 0)) |
919 | 0 | status=MagickFalse; |
920 | 0 | if (((rights & WritePolicyRights) != 0) && |
921 | 0 | ((effective_rights & WritePolicyRights) == 0)) |
922 | 0 | status=MagickFalse; |
923 | 0 | if (((rights & ExecutePolicyRights) != 0) && |
924 | 0 | ((effective_rights & ExecutePolicyRights) == 0)) |
925 | 0 | status=MagickFalse; |
926 | 0 | } |
927 | | /* |
928 | | Enforce sticky canonical denies. |
929 | | */ |
930 | 2.98M | if (canonical_matched_any != MagickFalse) |
931 | 0 | { |
932 | 0 | PolicyRights canonical_denied_mask = (PolicyRights) ((int) |
933 | 0 | AllPolicyRights & (int) ~canonical_allowed_accumulator); |
934 | 0 | if ((canonical_denied_mask & rights) != 0) |
935 | 0 | status=MagickFalse; |
936 | 0 | } |
937 | 2.98M | if ((GetLogEventMask() & PolicyEvent) != 0) |
938 | 0 | (void) LogMagickEvent(PolicyEvent,GetMagickModule(), |
939 | 0 | " authorized: %s",status == MagickFalse ? "false" : "true"); |
940 | 2.98M | return(status); |
941 | 2.98M | } |
942 | | |
943 | | MagickExport MagickBooleanType IsRightsAuthorized(const PolicyDomain domain, |
944 | | const PolicyRights rights,const char *pattern) |
945 | 2.33M | { |
946 | 2.33M | return(IsRightsAuthorizedByName(domain,(const char *) NULL,rights,pattern)); |
947 | 2.33M | } |
948 | | |
949 | | /* |
950 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
951 | | % % |
952 | | % % |
953 | | % % |
954 | | % L i s t P o l i c y I n f o % |
955 | | % % |
956 | | % % |
957 | | % % |
958 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
959 | | % |
960 | | % ListPolicyInfo() lists policies to the specified file. |
961 | | % |
962 | | % The format of the ListPolicyInfo method is: |
963 | | % |
964 | | % MagickBooleanType ListPolicyInfo(FILE *file,ExceptionInfo *exception) |
965 | | % |
966 | | % A description of each parameter follows. |
967 | | % |
968 | | % o file: List policy names to this file handle. |
969 | | % |
970 | | % o exception: return any errors or warnings in this structure. |
971 | | % |
972 | | */ |
973 | | MagickExport MagickBooleanType ListPolicyInfo(FILE *file, |
974 | | ExceptionInfo *exception) |
975 | 0 | { |
976 | 0 | const char |
977 | 0 | *path, |
978 | 0 | *domain; |
979 | |
|
980 | 0 | const PolicyInfo |
981 | 0 | **policy_info; |
982 | |
|
983 | 0 | ssize_t |
984 | 0 | i; |
985 | |
|
986 | 0 | size_t |
987 | 0 | number_policies; |
988 | | |
989 | | /* |
990 | | List name and attributes of each policy in the list. |
991 | | */ |
992 | 0 | if (file == (const FILE *) NULL) |
993 | 0 | file=stdout; |
994 | 0 | policy_info=GetPolicyInfoList("*",&number_policies,exception); |
995 | 0 | if (policy_info == (const PolicyInfo **) NULL) |
996 | 0 | return(MagickFalse); |
997 | 0 | path=(const char *) NULL; |
998 | 0 | for (i=0; i < (ssize_t) number_policies; i++) |
999 | 0 | { |
1000 | 0 | if (policy_info[i]->stealth != MagickFalse) |
1001 | 0 | continue; |
1002 | 0 | if (((path == (const char *) NULL) || |
1003 | 0 | (LocaleCompare(path,policy_info[i]->path) != 0)) && |
1004 | 0 | (policy_info[i]->path != (char *) NULL)) |
1005 | 0 | (void) FormatLocaleFile(file,"\nPath: %s\n",policy_info[i]->path); |
1006 | 0 | path=policy_info[i]->path; |
1007 | 0 | domain=CommandOptionToMnemonic(MagickPolicyDomainOptions, |
1008 | 0 | policy_info[i]->domain); |
1009 | 0 | (void) FormatLocaleFile(file," Policy: %s\n",domain); |
1010 | 0 | if ((policy_info[i]->domain == CachePolicyDomain) || |
1011 | 0 | (policy_info[i]->domain == ResourcePolicyDomain) || |
1012 | 0 | (policy_info[i]->domain == SystemPolicyDomain)) |
1013 | 0 | { |
1014 | 0 | if (policy_info[i]->name != (char *) NULL) |
1015 | 0 | (void) FormatLocaleFile(file," name: %s\n",policy_info[i]->name); |
1016 | 0 | if (policy_info[i]->value != (char *) NULL) |
1017 | 0 | (void) FormatLocaleFile(file," value: %s\n",policy_info[i]->value); |
1018 | 0 | } |
1019 | 0 | else |
1020 | 0 | { |
1021 | 0 | (void) FormatLocaleFile(file," rights: "); |
1022 | 0 | if (policy_info[i]->rights == NoPolicyRights) |
1023 | 0 | (void) FormatLocaleFile(file,"None "); |
1024 | 0 | if ((policy_info[i]->rights & ReadPolicyRights) != 0) |
1025 | 0 | (void) FormatLocaleFile(file,"Read "); |
1026 | 0 | if ((policy_info[i]->rights & WritePolicyRights) != 0) |
1027 | 0 | (void) FormatLocaleFile(file,"Write "); |
1028 | 0 | if ((policy_info[i]->rights & ExecutePolicyRights) != 0) |
1029 | 0 | (void) FormatLocaleFile(file,"Execute "); |
1030 | 0 | (void) FormatLocaleFile(file,"\n"); |
1031 | 0 | if (policy_info[i]->pattern != (char *) NULL) |
1032 | 0 | (void) FormatLocaleFile(file," pattern: %s\n", |
1033 | 0 | policy_info[i]->pattern); |
1034 | 0 | } |
1035 | 0 | } |
1036 | 0 | policy_info=(const PolicyInfo **) RelinquishMagickMemory((void *) |
1037 | 0 | policy_info); |
1038 | 0 | (void) fflush(file); |
1039 | 0 | return(MagickTrue); |
1040 | 0 | } |
1041 | | |
1042 | | /* |
1043 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1044 | | % % |
1045 | | % % |
1046 | | % % |
1047 | | + L o a d P o l i c y C a c h e % |
1048 | | % % |
1049 | | % % |
1050 | | % % |
1051 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1052 | | % |
1053 | | % LoadPolicyCache() loads the policy configurations which provides a mapping |
1054 | | % between policy attributes and a policy domain. |
1055 | | % |
1056 | | % The format of the LoadPolicyCache method is: |
1057 | | % |
1058 | | % MagickBooleanType LoadPolicyCache(LinkedListInfo *cache,const char *xml, |
1059 | | % const char *filename,const size_t depth,ExceptionInfo *exception) |
1060 | | % |
1061 | | % A description of each parameter follows: |
1062 | | % |
1063 | | % o xml: The policy list in XML format. |
1064 | | % |
1065 | | % o filename: The policy list filename. |
1066 | | % |
1067 | | % o depth: depth of <include /> statements. |
1068 | | % |
1069 | | % o exception: return any errors or warnings in this structure. |
1070 | | % |
1071 | | */ |
1072 | | static MagickBooleanType LoadPolicyCache(LinkedListInfo *cache, |
1073 | | const char *policy,const char *filename,const size_t depth, |
1074 | | ExceptionInfo *exception) |
1075 | 0 | { |
1076 | 0 | char |
1077 | 0 | keyword[MagickPathExtent], |
1078 | 0 | *token; |
1079 | |
|
1080 | 0 | const char |
1081 | 0 | *q; |
1082 | |
|
1083 | 0 | MagickStatusType |
1084 | 0 | status; |
1085 | |
|
1086 | 0 | PolicyInfo |
1087 | 0 | *policy_info; |
1088 | |
|
1089 | 0 | size_t |
1090 | 0 | extent; |
1091 | | |
1092 | | /* |
1093 | | Load the policy map file. |
1094 | | */ |
1095 | 0 | (void) LogMagickEvent(ConfigureEvent,GetMagickModule(), |
1096 | 0 | "Loading policy file \"%s\" ...",filename); |
1097 | 0 | if (policy == (char *) NULL) |
1098 | 0 | return(MagickFalse); |
1099 | 0 | status=MagickTrue; |
1100 | 0 | policy_info=(PolicyInfo *) NULL; |
1101 | 0 | token=AcquirePolicyString(policy,MagickPathExtent); |
1102 | 0 | extent=strlen(token)+MagickPathExtent; |
1103 | 0 | for (q=policy; *q != '\0'; ) |
1104 | 0 | { |
1105 | | /* |
1106 | | Interpret XML. |
1107 | | */ |
1108 | 0 | (void) GetNextToken(q,&q,extent,token); |
1109 | 0 | if (*token == '\0') |
1110 | 0 | break; |
1111 | 0 | (void) CopyMagickString(keyword,token,MagickPathExtent); |
1112 | 0 | if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0) |
1113 | 0 | { |
1114 | | /* |
1115 | | Docdomain element. |
1116 | | */ |
1117 | 0 | while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0')) |
1118 | 0 | (void) GetNextToken(q,&q,extent,token); |
1119 | 0 | continue; |
1120 | 0 | } |
1121 | 0 | if (LocaleNCompare(keyword,"<!--",4) == 0) |
1122 | 0 | { |
1123 | | /* |
1124 | | Comment element. |
1125 | | */ |
1126 | 0 | while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0')) |
1127 | 0 | (void) GetNextToken(q,&q,extent,token); |
1128 | 0 | continue; |
1129 | 0 | } |
1130 | 0 | if (LocaleCompare(keyword,"<include") == 0) |
1131 | 0 | { |
1132 | | /* |
1133 | | Include element. |
1134 | | */ |
1135 | 0 | while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0')) |
1136 | 0 | { |
1137 | 0 | (void) CopyMagickString(keyword,token,MagickPathExtent); |
1138 | 0 | (void) GetNextToken(q,&q,extent,token); |
1139 | 0 | if (*token != '=') |
1140 | 0 | continue; |
1141 | 0 | (void) GetNextToken(q,&q,extent,token); |
1142 | 0 | if (LocaleCompare(keyword,"file") == 0) |
1143 | 0 | { |
1144 | 0 | if (depth > MagickMaxRecursionDepth) |
1145 | 0 | (void) ThrowMagickException(exception,GetMagickModule(), |
1146 | 0 | ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token); |
1147 | 0 | else |
1148 | 0 | { |
1149 | 0 | char |
1150 | 0 | path[MagickPathExtent], |
1151 | 0 | *file_xml; |
1152 | |
|
1153 | 0 | GetPathComponent(filename,HeadPath,path); |
1154 | 0 | if (*path != '\0') |
1155 | 0 | (void) ConcatenateMagickString(path,DirectorySeparator, |
1156 | 0 | MagickPathExtent); |
1157 | 0 | if (*token == *DirectorySeparator) |
1158 | 0 | (void) CopyMagickString(path,token,MagickPathExtent); |
1159 | 0 | else |
1160 | 0 | (void) ConcatenateMagickString(path,token,MagickPathExtent); |
1161 | 0 | file_xml=FileToXML(path,~0UL); |
1162 | 0 | if (file_xml != (char *) NULL) |
1163 | 0 | { |
1164 | 0 | status&=(MagickStatusType) LoadPolicyCache(cache,file_xml, |
1165 | 0 | path,depth+1,exception); |
1166 | 0 | file_xml=DestroyString(file_xml); |
1167 | 0 | } |
1168 | 0 | } |
1169 | 0 | } |
1170 | 0 | } |
1171 | 0 | continue; |
1172 | 0 | } |
1173 | 0 | if (LocaleCompare(keyword,"<policy") == 0) |
1174 | 0 | { |
1175 | | /* |
1176 | | Policy element. |
1177 | | */ |
1178 | 0 | policy_info=(PolicyInfo *) AcquireCriticalMemory(sizeof(*policy_info)); |
1179 | 0 | (void) memset(policy_info,0,sizeof(*policy_info)); |
1180 | 0 | policy_info->path=AcquirePolicyString(filename,1); |
1181 | 0 | policy_info->exempt=MagickFalse; |
1182 | 0 | policy_info->signature=MagickCoreSignature; |
1183 | 0 | continue; |
1184 | 0 | } |
1185 | 0 | if (policy_info == (PolicyInfo *) NULL) |
1186 | 0 | continue; |
1187 | 0 | if ((LocaleCompare(keyword,"/>") == 0) || |
1188 | 0 | (LocaleCompare(keyword,"</policy>") == 0)) |
1189 | 0 | { |
1190 | 0 | status=AppendValueToLinkedList(cache,policy_info); |
1191 | 0 | if (status == MagickFalse) |
1192 | 0 | (void) ThrowMagickException(exception,GetMagickModule(), |
1193 | 0 | ResourceLimitError,"MemoryAllocationFailed","`%s'", |
1194 | 0 | policy_info->name); |
1195 | 0 | policy_info=(PolicyInfo *) NULL; |
1196 | 0 | continue; |
1197 | 0 | } |
1198 | 0 | (void) GetNextToken(q,(const char **) NULL,extent,token); |
1199 | 0 | if (*token != '=') |
1200 | 0 | continue; |
1201 | 0 | (void) GetNextToken(q,&q,extent,token); |
1202 | 0 | (void) GetNextToken(q,&q,extent,token); |
1203 | 0 | switch (*keyword) |
1204 | 0 | { |
1205 | 0 | case 'D': |
1206 | 0 | case 'd': |
1207 | 0 | { |
1208 | 0 | if (LocaleCompare((char *) keyword,"domain") == 0) |
1209 | 0 | { |
1210 | 0 | policy_info->domain=(PolicyDomain) ParseCommandOption( |
1211 | 0 | MagickPolicyDomainOptions,MagickTrue,token); |
1212 | 0 | break; |
1213 | 0 | } |
1214 | 0 | break; |
1215 | 0 | } |
1216 | 0 | case 'N': |
1217 | 0 | case 'n': |
1218 | 0 | { |
1219 | 0 | if (LocaleCompare((char *) keyword,"name") == 0) |
1220 | 0 | { |
1221 | 0 | policy_info->name=AcquirePolicyString(token,1); |
1222 | 0 | break; |
1223 | 0 | } |
1224 | 0 | break; |
1225 | 0 | } |
1226 | 0 | case 'P': |
1227 | 0 | case 'p': |
1228 | 0 | { |
1229 | 0 | if (LocaleCompare((char *) keyword,"pattern") == 0) |
1230 | 0 | { |
1231 | 0 | policy_info->pattern=AcquirePolicyString(token,1); |
1232 | 0 | break; |
1233 | 0 | } |
1234 | 0 | break; |
1235 | 0 | } |
1236 | 0 | case 'R': |
1237 | 0 | case 'r': |
1238 | 0 | { |
1239 | 0 | if (LocaleCompare((char *) keyword,"rights") == 0) |
1240 | 0 | { |
1241 | 0 | policy_info->rights=(PolicyRights) ParseCommandOption( |
1242 | 0 | MagickPolicyRightsOptions,MagickTrue,token); |
1243 | 0 | break; |
1244 | 0 | } |
1245 | 0 | break; |
1246 | 0 | } |
1247 | 0 | case 'S': |
1248 | 0 | case 's': |
1249 | 0 | { |
1250 | 0 | if (LocaleCompare((char *) keyword,"stealth") == 0) |
1251 | 0 | { |
1252 | 0 | policy_info->stealth=IsStringTrue(token); |
1253 | 0 | break; |
1254 | 0 | } |
1255 | 0 | break; |
1256 | 0 | } |
1257 | 0 | case 'V': |
1258 | 0 | case 'v': |
1259 | 0 | { |
1260 | 0 | if (LocaleCompare((char *) keyword,"value") == 0) |
1261 | 0 | { |
1262 | 0 | policy_info->value=AcquirePolicyString(token,1); |
1263 | 0 | break; |
1264 | 0 | } |
1265 | 0 | break; |
1266 | 0 | } |
1267 | 0 | default: |
1268 | 0 | break; |
1269 | 0 | } |
1270 | 0 | } |
1271 | 0 | token=(char *) RelinquishMagickMemory(token); |
1272 | 0 | return(status != 0 ? MagickTrue : MagickFalse); |
1273 | 0 | } |
1274 | | |
1275 | | /* |
1276 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1277 | | % % |
1278 | | % % |
1279 | | % % |
1280 | | + P o l i c y C o m p o n e n t G e n e s i s % |
1281 | | % % |
1282 | | % % |
1283 | | % % |
1284 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1285 | | % |
1286 | | % PolicyComponentGenesis() instantiates the policy component. |
1287 | | % |
1288 | | % The format of the PolicyComponentGenesis method is: |
1289 | | % |
1290 | | % MagickBooleanType PolicyComponentGenesis(void) |
1291 | | % |
1292 | | */ |
1293 | | MagickPrivate MagickBooleanType PolicyComponentGenesis(void) |
1294 | 295 | { |
1295 | 295 | if (policy_semaphore == (SemaphoreInfo *) NULL) |
1296 | 0 | policy_semaphore=AcquireSemaphoreInfo(); |
1297 | 295 | return(MagickTrue); |
1298 | 295 | } |
1299 | | |
1300 | | /* |
1301 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1302 | | % % |
1303 | | % % |
1304 | | % % |
1305 | | + P o l i c y C o m p o n e n t T e r m i n u s % |
1306 | | % % |
1307 | | % % |
1308 | | % % |
1309 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1310 | | % |
1311 | | % PolicyComponentTerminus() destroys the policy component. |
1312 | | % |
1313 | | % The format of the PolicyComponentTerminus method is: |
1314 | | % |
1315 | | % PolicyComponentTerminus(void) |
1316 | | % |
1317 | | */ |
1318 | | |
1319 | | static void *DestroyPolicyElement(void *policy_info) |
1320 | 0 | { |
1321 | 0 | PolicyInfo |
1322 | 0 | *p; |
1323 | |
|
1324 | 0 | p=(PolicyInfo *) policy_info; |
1325 | 0 | if (p->exempt == MagickFalse) |
1326 | 0 | { |
1327 | 0 | if (p->value != (char *) NULL) |
1328 | 0 | p->value=DestroyString(p->value); |
1329 | 0 | if (p->pattern != (char *) NULL) |
1330 | 0 | p->pattern=DestroyString(p->pattern); |
1331 | 0 | if (p->name != (char *) NULL) |
1332 | 0 | p->name=DestroyString(p->name); |
1333 | 0 | if (p->path != (char *) NULL) |
1334 | 0 | p->path=DestroyString(p->path); |
1335 | 0 | } |
1336 | 0 | p=(PolicyInfo *) RelinquishMagickMemory(p); |
1337 | 0 | return((void *) NULL); |
1338 | 0 | } |
1339 | | |
1340 | | MagickPrivate void PolicyComponentTerminus(void) |
1341 | 0 | { |
1342 | 0 | if (policy_semaphore == (SemaphoreInfo *) NULL) |
1343 | 0 | ActivateSemaphoreInfo(&policy_semaphore); |
1344 | 0 | LockSemaphoreInfo(policy_semaphore); |
1345 | 0 | if (policy_cache != (LinkedListInfo *) NULL) |
1346 | 0 | policy_cache=DestroyLinkedList(policy_cache,DestroyPolicyElement); |
1347 | 0 | UnlockSemaphoreInfo(policy_semaphore); |
1348 | 0 | RelinquishSemaphoreInfo(&policy_semaphore); |
1349 | 0 | } |
1350 | | |
1351 | | /* |
1352 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1353 | | % % |
1354 | | % % |
1355 | | % % |
1356 | | % S e t M a g i c k S e c u r i t y P o l i c y % |
1357 | | % % |
1358 | | % % |
1359 | | % % |
1360 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1361 | | % |
1362 | | % SetMagickSecurityPolicy() sets or restricts the ImageMagick security policy. |
1363 | | % It returns MagickFalse if the policy the policy does not parse. |
1364 | | % |
1365 | | % The format of the SetMagickSecurityPolicy method is: |
1366 | | % |
1367 | | % MagickBooleanType SetMagickSecurityPolicy(const char *policy, |
1368 | | % ExceptionInfo *exception) |
1369 | | % |
1370 | | % A description of each parameter follows: |
1371 | | % |
1372 | | % o policy: the security policy in the XML format. |
1373 | | % |
1374 | | % o exception: return any errors or warnings in this structure. |
1375 | | % |
1376 | | */ |
1377 | | |
1378 | | static MagickBooleanType ValidateSecurityPolicy(const char *policy, |
1379 | | const char *url,ExceptionInfo *exception) |
1380 | 0 | { |
1381 | | #if defined(MAGICKCORE_XML_DELEGATE) |
1382 | | xmlDocPtr |
1383 | | document; |
1384 | | |
1385 | | /* |
1386 | | Parse security policy. |
1387 | | */ |
1388 | | document=xmlReadMemory(policy,(int) strlen(policy),url,NULL, |
1389 | | XML_PARSE_NOERROR | XML_PARSE_NOWARNING); |
1390 | | if (document == (xmlDocPtr) NULL) |
1391 | | { |
1392 | | (void) ThrowMagickException(exception,GetMagickModule(),ConfigureError, |
1393 | | "PolicyValidationException","'%s'",url); |
1394 | | return(MagickFalse); |
1395 | | } |
1396 | | xmlFreeDoc(document); |
1397 | | #else |
1398 | 0 | (void) policy; |
1399 | 0 | (void) url; |
1400 | 0 | (void) exception; |
1401 | 0 | #endif |
1402 | 0 | return(MagickTrue); |
1403 | 0 | } |
1404 | | |
1405 | | MagickExport MagickBooleanType SetMagickSecurityPolicy(const char *policy, |
1406 | | ExceptionInfo *exception) |
1407 | 0 | { |
1408 | 0 | MagickBooleanType |
1409 | 0 | status; |
1410 | |
|
1411 | 0 | LinkedListInfo |
1412 | 0 | *user_policies; |
1413 | |
|
1414 | 0 | PolicyInfo |
1415 | 0 | *p; |
1416 | | |
1417 | | /* |
1418 | | Load user policies. |
1419 | | */ |
1420 | 0 | assert(exception != (ExceptionInfo *) NULL); |
1421 | 0 | if (policy == (const char *) NULL) |
1422 | 0 | return(MagickFalse); |
1423 | 0 | if (ValidateSecurityPolicy(policy,PolicyFilename,exception) == MagickFalse) |
1424 | 0 | return(MagickFalse); |
1425 | 0 | status=LoadPolicyCache(policy_cache,policy,"[user-policy]",0,exception); |
1426 | 0 | if (status == MagickFalse) |
1427 | 0 | return(status); |
1428 | | /* |
1429 | | Synchronize user policies. |
1430 | | */ |
1431 | 0 | user_policies=NewLinkedList(0); |
1432 | 0 | status=LoadPolicyCache(user_policies,policy,"[user-policy]",0,exception); |
1433 | 0 | if (status == MagickFalse) |
1434 | 0 | { |
1435 | 0 | user_policies=DestroyLinkedList(user_policies,DestroyPolicyElement); |
1436 | 0 | return(MagickFalse); |
1437 | 0 | } |
1438 | 0 | ResetLinkedListIterator(user_policies); |
1439 | 0 | p=(PolicyInfo *) GetNextValueInLinkedList(user_policies); |
1440 | 0 | while (p != (PolicyInfo *) NULL) |
1441 | 0 | { |
1442 | 0 | if ((p->name != (char *) NULL) && (p->value != (char *) NULL)) |
1443 | 0 | (void) SetMagickSecurityPolicyValue(p->domain,p->name,p->value,exception); |
1444 | 0 | p=(PolicyInfo *) GetNextValueInLinkedList(user_policies); |
1445 | 0 | } |
1446 | 0 | user_policies=DestroyLinkedList(user_policies,DestroyPolicyElement); |
1447 | 0 | return(status); |
1448 | 0 | } |
1449 | | |
1450 | | /* |
1451 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1452 | | % % |
1453 | | % % |
1454 | | % % |
1455 | | % S e t M a g i c k S e c u r i t y P o l i c y V a l u e % |
1456 | | % % |
1457 | | % % |
1458 | | % % |
1459 | | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
1460 | | % |
1461 | | % SetMagickSecurityPolicyValue() sets a value associated with an ImageMagick |
1462 | | % security policy. For most policies, the value must be less than any value |
1463 | | % set by the security policy configuration file (i.e. policy.xml). It returns |
1464 | | % MagickFalse if the policy cannot be modified or if the policy does not parse. |
1465 | | % |
1466 | | % The format of the SetMagickSecurityPolicyValue method is: |
1467 | | % |
1468 | | % MagickBooleanType SetMagickSecurityPolicyValue( |
1469 | | % const PolicyDomain domain,const char *name,const char *value, |
1470 | | % ExceptionInfo *exception) |
1471 | | % |
1472 | | % A description of each parameter follows: |
1473 | | % |
1474 | | % o domain: the domain of the policy (e.g. system, resource). |
1475 | | % |
1476 | | % o name: the name of the policy. |
1477 | | % |
1478 | | % o value: the value to set the policy to. |
1479 | | % |
1480 | | % o exception: return any errors or warnings in this structure. |
1481 | | % |
1482 | | */ |
1483 | | MagickExport MagickBooleanType SetMagickSecurityPolicyValue( |
1484 | | const PolicyDomain domain,const char *name,const char *value, |
1485 | | ExceptionInfo *exception) |
1486 | 1.18k | { |
1487 | 1.18k | magick_unreferenced(exception); |
1488 | 1.18k | assert(exception != (ExceptionInfo *) NULL); |
1489 | 1.18k | if ((name == (const char *) NULL) || (value == (const char *) NULL)) |
1490 | 0 | return(MagickFalse); |
1491 | 1.18k | switch (domain) |
1492 | 1.18k | { |
1493 | 295 | case CachePolicyDomain: |
1494 | 295 | { |
1495 | 295 | if (LocaleCompare(name,"memory-map") == 0) |
1496 | 295 | { |
1497 | 295 | if (LocaleCompare(value,"anonymous") != 0) |
1498 | 0 | return(MagickFalse); |
1499 | 295 | ResetCacheAnonymousMemory(); |
1500 | 295 | ResetStreamAnonymousMemory(); |
1501 | 295 | return(MagickTrue); |
1502 | 295 | } |
1503 | 0 | break; |
1504 | 295 | } |
1505 | 0 | case ResourcePolicyDomain: |
1506 | 0 | { |
1507 | 0 | ssize_t |
1508 | 0 | type; |
1509 | |
|
1510 | 0 | type=ParseCommandOption(MagickResourceOptions,MagickFalse,name); |
1511 | 0 | if (type >= 0) |
1512 | 0 | { |
1513 | 0 | MagickSizeType |
1514 | 0 | limit; |
1515 | |
|
1516 | 0 | limit=MagickResourceInfinity; |
1517 | 0 | if (LocaleCompare("unlimited",value) != 0) |
1518 | 0 | limit=StringToMagickSizeType(value,100.0); |
1519 | 0 | if ((ResourceType) type == TimeResource) |
1520 | 0 | limit=(MagickSizeType) ParseMagickTimeToLive(value); |
1521 | 0 | return(SetMagickResourceLimit((ResourceType) type,limit)); |
1522 | 0 | } |
1523 | 0 | break; |
1524 | 0 | } |
1525 | 885 | case SystemPolicyDomain: |
1526 | 885 | { |
1527 | 885 | if (LocaleCompare(name,"max-memory-request") == 0) |
1528 | 295 | { |
1529 | 295 | MagickSizeType |
1530 | 295 | limit; |
1531 | | |
1532 | 295 | limit=MagickResourceInfinity; |
1533 | 295 | if (LocaleCompare("unlimited",value) != 0) |
1534 | 295 | limit=StringToMagickSizeType(value,100.0); |
1535 | 295 | SetMaxMemoryRequest(limit); |
1536 | 295 | return(MagickTrue); |
1537 | 295 | } |
1538 | 590 | if (LocaleCompare(name,"max-profile-size") == 0) |
1539 | 295 | { |
1540 | 295 | MagickSizeType |
1541 | 295 | limit; |
1542 | | |
1543 | 295 | limit=MagickResourceInfinity; |
1544 | 295 | if (LocaleCompare("unlimited",value) != 0) |
1545 | 295 | limit=StringToMagickSizeType(value,100.0); |
1546 | 295 | SetMaxProfileSize(limit); |
1547 | 295 | return(MagickTrue); |
1548 | 295 | } |
1549 | 295 | if (LocaleCompare(name,"memory-map") == 0) |
1550 | 295 | { |
1551 | 295 | if (LocaleCompare(value,"anonymous") != 0) |
1552 | 0 | return(MagickFalse); |
1553 | 295 | ResetVirtualAnonymousMemory(); |
1554 | 295 | return(MagickTrue); |
1555 | 295 | } |
1556 | 0 | if (LocaleCompare(name,"precision") == 0) |
1557 | 0 | { |
1558 | 0 | int |
1559 | 0 | limit; |
1560 | |
|
1561 | 0 | limit=StringToInteger(value); |
1562 | 0 | SetMagickPrecision(limit); |
1563 | 0 | return(MagickTrue); |
1564 | 0 | } |
1565 | 0 | break; |
1566 | 0 | } |
1567 | 0 | case CoderPolicyDomain: |
1568 | 0 | case DelegatePolicyDomain: |
1569 | 0 | case FilterPolicyDomain: |
1570 | 0 | case ModulePolicyDomain: |
1571 | 0 | case PathPolicyDomain: |
1572 | 0 | default: |
1573 | 0 | break; |
1574 | 1.18k | } |
1575 | 0 | return(MagickFalse); |
1576 | 1.18k | } |