xref: /freebsd/contrib/sendmail/src/macro.c (revision d39bd2c1388b520fcba9abed1932acacead60fba)
1 /*
2  * Copyright (c) 1998-2001, 2003, 2006, 2007 Proofpoint, Inc. and its suppliers.
3  *	All rights reserved.
4  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
5  * Copyright (c) 1988, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * By using this file, you agree to the terms and conditions set
9  * forth in the LICENSE file which can be found at the top level of
10  * the sendmail distribution.
11  *
12  */
13 
14 #include <sendmail.h>
15 
16 SM_RCSID("@(#)$Id: macro.c,v 8.108 2013-11-22 20:51:55 ca Exp $")
17 
18 #include <sm/sendmail.h>
19 #if MAXMACROID != (BITMAPBITS - 1)
20 	ERROR Read the comment in conf.h
21 #endif
22 
23 static char	*MacroName[MAXMACROID + 1];	/* macro id to name table */
24 
25 /*
26 **  Codes for long named macros.
27 **  See also macname():
28 	* if not ASCII printable, look up the name *
29 	if (n <= 0x20 || n > 0x7f)
30 **  First use 1 to NEXTMACROID_L, then use NEXTMACROID_H to MAXMACROID.
31 */
32 
33 #define NEXTMACROID_L 037
34 #define NEXTMACROID_H 0240
35 
36 #if _FFR_MORE_MACROS
37 /* table for next id in non-printable ASCII range: disallow some value */
38 static int NextMIdTable[] =
39 {
40 	/*  0  nul */	 1,
41 	/*  1  soh */	 2,
42 	/*  2  stx */	 3,
43 	/*  3  etx */	 4,
44 	/*  4  eot */	 5,
45 	/*  5  enq */	 6,
46 	/*  6  ack */	 7,
47 	/*  7  bel */	 8,
48 	/*  8  bs  */	14,
49 	/*  9  ht  */	-1,
50 	/* 10  nl  */	-1,
51 	/* 11  vt  */	-1,
52 	/* 12  np  */	-1,
53 	/* 13  cr  */	-1,
54 	/* 14  so  */	15,
55 	/* 15  si  */	16,
56 	/* 16  dle */	17,
57 	/* 17  dc1 */	18,
58 	/* 18  dc2 */	19,
59 	/* 19  dc3 */	20,
60 	/* 20  dc4 */	21,
61 	/* 21  nak */	22,
62 	/* 22  syn */	23,
63 	/* 23  etb */	24,
64 	/* 24  can */	25,
65 	/* 25  em  */	26,
66 	/* 26  sub */	27,
67 	/* 27  esc */	28,
68 	/* 28  fs  */	29,
69 	/* 29  gs  */	30,
70 	/* 30  rs  */	31,
71 	/* 31  us  */	32,
72 	/* 32  sp  */	-1,
73 };
74 
75 #define NEXTMACROID(mid)	(		\
76 	(mid < NEXTMACROID_L) ? (NextMIdTable[mid]) :	\
77 	((mid < NEXTMACROID_H) ? NEXTMACROID_H : (mid + 1)))
78 
79 int		NextMacroId = 1;	/* codes for long named macros */
80 /* see sendmail.h: Special characters in rewriting rules. */
81 #else /* _FFR_MORE_MACROS */
82 int		NextMacroId = 0240;	/* codes for long named macros */
83 #define NEXTMACROID(mid)	((mid) + 1)
84 #endif /* _FFR_MORE_MACROS */
85 
86 /*
87 **  INITMACROS -- initialize the macro system
88 **
89 **	This just involves defining some macros that are actually
90 **	used internally as metasymbols to be themselves.
91 **
92 **	Parameters:
93 **		none.
94 **
95 **	Returns:
96 **		none.
97 **
98 **	Side Effects:
99 **		initializes several macros to be themselves.
100 */
101 
102 struct metamac	MetaMacros[] =
103 {
104 	/* LHS pattern matching characters */
105 	{ '*', MATCHZANY },	{ '+', MATCHANY },	{ '-', MATCHONE },
106 	{ '=', MATCHCLASS },	{ '~', MATCHNCLASS },
107 
108 	/* these are RHS metasymbols */
109 	{ '#', CANONNET },	{ '@', CANONHOST },	{ ':', CANONUSER },
110 	{ '>', CALLSUBR },
111 
112 	/* the conditional operations */
113 	{ '?', CONDIF },	{ '|', CONDELSE },	{ '.', CONDFI },
114 
115 	/* the hostname lookup characters */
116 	{ '[', HOSTBEGIN },	{ ']', HOSTEND },
117 	{ '(', LOOKUPBEGIN },	{ ')', LOOKUPEND },
118 
119 	/* miscellaneous control characters */
120 	{ '&', MACRODEXPAND },
121 
122 	{ '\0', '\0' }
123 };
124 
125 #define MACBINDING(name, mid) \
126 		stab(name, ST_MACRO, ST_ENTER)->s_macro = mid; \
127 		MacroName[mid] = name;
128 
129 void
initmacros(e)130 initmacros(e)
131 	ENVELOPE *e;
132 {
133 	struct metamac *m;
134 	int c;
135 	char buf[5];
136 
137 	for (m = MetaMacros; m->metaname != '\0'; m++)
138 	{
139 		buf[0] = m->metaval;
140 		buf[1] = '\0';
141 		macdefine(&e->e_macro, A_TEMP, m->metaname, buf);
142 	}
143 	buf[0] = MATCHREPL;
144 	buf[2] = '\0';
145 	for (c = '0'; c <= '9'; c++)
146 	{
147 		buf[1] = c;
148 		macdefine(&e->e_macro, A_TEMP, c, buf);
149 	}
150 
151 	/* set defaults for some macros sendmail will use later */
152 	macdefine(&e->e_macro, A_PERM, 'n', "MAILER-DAEMON");
153 
154 	/* set up external names for some internal macros */
155 	MACBINDING("opMode", MID_OPMODE);
156 	/*XXX should probably add equivalents for all short macros here XXX*/
157 }
158 
159 /*
160 **  EXPAND/DOEXPAND -- macro expand a string using $x escapes.
161 **	(including conditionals, e.g., $?x Y $| N $.)
162 **
163 **	Parameters:
164 **		s -- the string to expand. [i]
165 **		buf -- the place to put the expansion. [i]
166 **		bufsize -- the size of the buffer.
167 **		explevel -- the depth of expansion (doexpand only)
168 **		e -- envelope in which to work.
169 **
170 **	Returns:
171 **		none.
172 */
173 
174 static void doexpand __P(( char *, char *, size_t, int, ENVELOPE *));
175 
176 static void
doexpand(s,buf,bufsize,explevel,e)177 doexpand(s, buf, bufsize, explevel, e)
178 	char *s;
179 	char *buf;
180 	size_t bufsize;
181 	int explevel;
182 	ENVELOPE *e;
183 {
184 	char *xp;
185 	char *q;
186 	bool skipping;		/* set if conditionally skipping output */
187 	bool recurse;		/* set if recursion required */
188 	size_t i;
189 	int skiplev;		/* skipping nesting level */
190 	int iflev;		/* if nesting level */
191 	bool quotenext;		/* quote the following character */
192 	char xbuf[MACBUFSIZE];
193 
194 	if (tTd(35, 24))
195 	{
196 		sm_dprintf("expand(");
197 		xputs(sm_debug_file(), s);
198 		sm_dprintf(")\n");
199 	}
200 
201 	recurse = false;
202 	skipping = false;
203 	skiplev = 0;
204 	iflev = 0;
205 	quotenext = false;
206 	if (s == NULL)
207 		s = "";
208 	for (xp = xbuf; *s != '\0'; s++)
209 	{
210 		int c;
211 
212 		/*
213 		**  Check for non-ordinary (special?) character.
214 		**	'q' will be the interpolated quantity.
215 		*/
216 
217 		q = NULL;
218 		c = *s & 0377;
219 
220 		if (quotenext)
221 		{
222 			quotenext = false;
223 			goto simpleinterpolate;
224 		}
225 
226 		switch (c)
227 		{
228 		  case CONDIF:		/* see if var set */
229 			iflev++;
230 			c = *++s & 0377;
231 			if (skipping)
232 				skiplev++;
233 			else
234 			{
235 				char *mv;
236 
237 				mv = macvalue(c, e);
238 				skipping = (mv == NULL || *mv == '\0');
239 			}
240 			continue;
241 
242 		  case CONDELSE:	/* change state of skipping */
243 			if (iflev == 0)
244 				break;	/* XXX: error */
245 			if (skiplev == 0)
246 				skipping = !skipping;
247 			continue;
248 
249 		  case CONDFI:		/* stop skipping */
250 			if (iflev == 0)
251 				break;	/* XXX: error */
252 			iflev--;
253 			if (skiplev == 0)
254 				skipping = false;
255 			if (skipping)
256 				skiplev--;
257 			continue;
258 
259 		  case MACROEXPAND:	/* macro interpolation */
260 			c = bitidx(*++s);
261 			if (c != '\0')
262 				q = macvalue(c, e);
263 			else
264 			{
265 				s--;
266 				q = NULL;
267 			}
268 			if (q == NULL)
269 				continue;
270 			break;
271 
272 		  case METAQUOTE:
273 			/* next octet completely quoted */
274 			quotenext = true;
275 			break;
276 		}
277 
278 		/*
279 		**  Interpolate q or output one character
280 		*/
281 
282   simpleinterpolate:
283 		if (skipping || xp >= &xbuf[sizeof(xbuf) - 1])
284 			continue;
285 		if (q == NULL)
286 			*xp++ = c;
287 		else
288 		{
289 			/* copy to end of q or max space remaining in buf */
290 			bool hiderecurse = false;
291 
292 			while ((c = *q++) != '\0' &&
293 				xp < &xbuf[sizeof(xbuf) - 1])
294 			{
295 				/* check for any sendmail metacharacters */
296 				if (!hiderecurse && (c & 0340) == 0200)
297 					recurse = true;
298 				*xp++ = c;
299 
300 				/* give quoted characters a free ride */
301 				hiderecurse = (c & 0377) == METAQUOTE;
302 			}
303 		}
304 	}
305 	*xp = '\0';
306 
307 	if (tTd(35, 28))
308 	{
309 		sm_dprintf("expand(%d) ==> ", explevel);
310 		xputs(sm_debug_file(), xbuf);
311 		sm_dprintf("\n");
312 	}
313 
314 	/* recurse as appropriate */
315 	if (recurse)
316 	{
317 		if (explevel < MaxMacroRecursion)
318 		{
319 			doexpand(xbuf, buf, bufsize, explevel + 1, e);
320 			return;
321 		}
322 		syserr("expand: recursion too deep (%d max)",
323 			MaxMacroRecursion);
324 	}
325 
326 	/* copy results out */
327 	if (explevel == 0)
328 		(void) sm_strlcpy(buf, xbuf, bufsize);
329 	else
330 	{
331 		/* leave in internal form */
332 		i = xp - xbuf;
333 		if (i >= bufsize)
334 			i = bufsize - 1;
335 		memmove(buf, xbuf, i);
336 		buf[i] = '\0';
337 	}
338 
339 	if (tTd(35, 24))
340 	{
341 		sm_dprintf("expand ==> ");
342 		xputs(sm_debug_file(), buf);
343 		sm_dprintf("\n");
344 	}
345 }
346 
347 void
expand(s,buf,bufsize,e)348 expand(s, buf, bufsize, e)
349 	char *s;
350 	char *buf;
351 	size_t bufsize;
352 	ENVELOPE *e;
353 {
354 	doexpand(s, buf, bufsize, 0, e);
355 }
356 
357 /*
358 **  MACTABCLEAR -- clear entire macro table
359 **
360 **	Parameters:
361 **		mac -- Macro table.
362 **
363 **	Returns:
364 **		none.
365 **
366 **	Side Effects:
367 **		clears entire mac structure including rpool pointer!
368 */
369 
370 void
mactabclear(mac)371 mactabclear(mac)
372 	MACROS_T *mac;
373 {
374 	int i;
375 
376 	if (mac->mac_rpool == NULL)
377 	{
378 		for (i = 0; i < MAXMACROID; i++)
379 			SM_FREE(mac->mac_table[i]);
380 	}
381 	memset((char *) mac, '\0', sizeof(*mac));
382 }
383 
384 /*
385 **  MACDEFINE -- bind a macro name to a value
386 **
387 **	Set a macro to a value, with fancy storage management.
388 **	macdefine will make a copy of the value, if required,
389 **	and will ensure that the storage for the previous value
390 **	is not leaked.
391 **
392 **	Parameters:
393 **		mac -- Macro table.
394 **		vclass -- storage class of 'value', ignored if value==NULL.
395 **			A_HEAP	means that the value was allocated by
396 **				malloc, and that macdefine owns the storage.
397 **			A_TEMP	means that value points to temporary storage,
398 **				and thus macdefine needs to make a copy.
399 **			A_PERM	means that value points to storage that
400 **				will remain allocated and unchanged for
401 **				at least the lifetime of mac.  Use A_PERM if:
402 **				-- value == NULL,
403 **				-- value points to a string literal,
404 **				-- value was allocated from mac->mac_rpool
405 **				   or (in the case of an envelope macro)
406 **				   from e->e_rpool,
407 **				-- in the case of an envelope macro,
408 **				   value is a string member of the envelope
409 **				   such as e->e_sender.
410 **		id -- Macro id.  This is a single character macro name
411 **			such as 'g', or a value returned by macid().
412 **		value -- Macro value: either NULL, or a string.
413 **
414 **	Returns:
415 **		none.
416 */
417 
418 void
419 #if SM_HEAP_CHECK
macdefine_tagged(mac,vclass,id,value,file,line,grp)420 macdefine_tagged(mac, vclass, id, value, file, line, grp)
421 #else
422 macdefine(mac, vclass, id, value)
423 #endif
424 	MACROS_T *mac;
425 	ARGCLASS_T vclass;
426 	int id;
427 	char *value;
428 #if SM_HEAP_CHECK
429 	char *file;
430 	int line;
431 	int grp;
432 #endif
433 {
434 	char *newvalue;
435 
436 	if (id < 0 || id > MAXMACROID)
437 		return;
438 
439 	if (tTd(35, 9))
440 	{
441 		sm_dprintf("%sdefine(%s as ",
442 			mac->mac_table[id] == NULL ? "" : "re", macname(id));
443 		xputs(sm_debug_file(), value);
444 		sm_dprintf(")\n");
445 	}
446 #if USE_EAI && 0
447 //	if (('j' == id || 'm' == id) && !addr_is_ascii(value))
448 //		return an error/warning to caller and let them handle it.
449 #endif
450 
451 	if (mac->mac_rpool == NULL)
452 	{
453 		char *freeit = NULL;
454 
455 		if (mac->mac_table[id] != NULL &&
456 		    bitnset(id, mac->mac_allocated))
457 			freeit = mac->mac_table[id];
458 
459 		if (value == NULL || vclass == A_HEAP)
460 		{
461 			sm_heap_checkptr_tagged(value, file, line);
462 			newvalue = value;
463 			clrbitn(id, mac->mac_allocated);
464 		}
465 		else
466 		{
467 #if SM_HEAP_CHECK
468 			newvalue = sm_strdup_tagged_x(value, file, line, 0);
469 #else
470 			newvalue = sm_strdup_x(value);
471 #endif
472 			setbitn(id, mac->mac_allocated);
473 		}
474 		mac->mac_table[id] = newvalue;
475 		if (freeit != NULL)
476 			sm_free(freeit);
477 	}
478 	else
479 	{
480 		if (value == NULL || vclass == A_PERM)
481 			newvalue = value;
482 		else
483 			newvalue = sm_rpool_strdup_x(mac->mac_rpool, value);
484 		mac->mac_table[id] = newvalue;
485 		if (vclass == A_HEAP)
486 			sm_free(value);
487 	}
488 
489 #if _FFR_RESET_MACRO_GLOBALS
490 	switch (id)
491 	{
492 	  case 'j':
493 		PSTRSET(MyHostName, value);
494 		break;
495 	}
496 #endif /* _FFR_RESET_MACRO_GLOBALS */
497 }
498 
499 /*
500 **  MACSET -- set a named macro to a value (low level)
501 **
502 **	No fancy storage management; the caller takes full responsibility.
503 **	Often used with macget; see also macdefine.
504 **
505 **	Parameters:
506 **		mac -- Macro table.
507 **		i -- Macro name, specified as an integer offset.
508 **		value -- Macro value: either NULL, or a string.
509 **
510 **	Returns:
511 **		none.
512 */
513 
514 void
macset(mac,i,value)515 macset(mac, i, value)
516 	MACROS_T *mac;
517 	int i;
518 	char *value;
519 {
520 	if (i < 0 || i > MAXMACROID)
521 		return;
522 
523 	if (tTd(35, 9))
524 	{
525 		sm_dprintf("macset(%s as ", macname(i));
526 		xputs(sm_debug_file(), value);
527 		sm_dprintf(")\n");
528 	}
529 	mac->mac_table[i] = value;
530 }
531 
532 /*
533 **  MACVALUE -- return uninterpreted value of a macro.
534 **
535 **	Does fancy path searching.
536 **	The low level counterpart is macget.
537 **
538 **	Parameters:
539 **		n -- the name of the macro.
540 **		e -- envelope in which to start looking for the macro.
541 **
542 **	Returns:
543 **		The value of n.
544 **
545 **	Side Effects:
546 **		none.
547 */
548 
549 char *
macvalue(n,e)550 macvalue(n, e)
551 	int n;
552 	ENVELOPE *e;
553 {
554 	n = bitidx(n);
555 	if (e != NULL && e->e_mci != NULL)
556 	{
557 		char *p = e->e_mci->mci_macro.mac_table[n];
558 
559 		if (p != NULL)
560 			return p;
561 	}
562 	while (e != NULL)
563 	{
564 		char *p = e->e_macro.mac_table[n];
565 
566 		if (p != NULL)
567 			return p;
568 		if (e == e->e_parent)
569 			break;
570 		e = e->e_parent;
571 	}
572 #if _FFR_BLANKENV_MACV
573 	if (LOOKUP_MACRO_IN_BLANKENV && e != &BlankEnvelope)
574 	{
575 		char *p = BlankEnvelope.e_macro.mac_table[n];
576 
577 		if (p != NULL)
578 			return p;
579 	}
580 #endif
581 	return GlobalMacros.mac_table[n];
582 }
583 
584 /*
585 **  MACNAME -- return the name of a macro given its internal id
586 **
587 **	Parameter:
588 **		n -- the id of the macro
589 **
590 **	Returns:
591 **		The name of n.
592 **
593 **	Side Effects:
594 **		none.
595 **
596 **	WARNING:
597 **		Not thread-safe.
598 */
599 
600 char *
macname(n)601 macname(n)
602 	int n;
603 {
604 	static char mbuf[2];
605 
606 	n = (int)(unsigned char)n;
607 	if (n > MAXMACROID)
608 		return "***OUT OF RANGE MACRO***";
609 
610 	/* if not ASCII printable, look up the name */
611 	if (n <= 0x20 || n > 0x7f)
612 	{
613 		char *p = MacroName[n];
614 
615 		if (p != NULL)
616 			return p;
617 		return "***UNDEFINED MACRO***";
618 	}
619 
620 	/* if in the ASCII graphic range, just return the id directly */
621 	mbuf[0] = n;
622 	mbuf[1] = '\0';
623 	return mbuf;
624 }
625 
626 /*
627 **  MACID_PARSE -- return id of macro identified by its name
628 **
629 **	Parameters:
630 **		p -- pointer to name string -- either a single
631 **			character or {name}.
632 **		ep -- filled in with the pointer to the byte
633 **			after the name.
634 **
635 **	Returns:
636 **		0 -- An error was detected.
637 **		1..MAXMACROID -- The internal id code for this macro.
638 **
639 **	Side Effects:
640 **		If this is a new macro name, a new id is allocated.
641 **		On error, syserr is called.
642 */
643 
644 int
macid_parse(p,ep)645 macid_parse(p, ep)
646 	char *p;
647 	char **ep;
648 {
649 	int mid;
650 	char *bp;
651 	char mbuf[MAXMACNAMELEN + 1];
652 
653 	if (tTd(35, 14))
654 	{
655 		sm_dprintf("macid(");
656 		xputs(sm_debug_file(), p);
657 		sm_dprintf(") => ");
658 	}
659 
660 	if (*p == '\0' || (p[0] == '{' && p[1] == '}'))
661 	{
662 		syserr("Name required for macro/class");
663 		if (ep != NULL)
664 			*ep = p;
665 		if (tTd(35, 14))
666 			sm_dprintf("NULL\n");
667 		return 0;
668 	}
669 	if (*p != '{')
670 	{
671 		/* the macro is its own code */
672 		if (ep != NULL)
673 			*ep = p + 1;
674 		if (tTd(35, 14))
675 		{
676 			char buf[2];
677 
678 			buf[0] = *p;
679 			buf[1] = '\0';
680 			xputs(sm_debug_file(), buf);
681 			sm_dprintf("\n");
682 		}
683 		return bitidx(*p);
684 	}
685 	bp = mbuf;
686 	while (*++p != '\0' && *p != '}' && bp < &mbuf[sizeof(mbuf) - 1])
687 	{
688 		if (isascii(*p) && (isalnum(*p) || *p == '_'))
689 			*bp++ = *p;
690 		else
691 			syserr("Invalid macro/class character %c", *p);
692 	}
693 	*bp = '\0';
694 	mid = -1;
695 	if (*p == '\0')
696 	{
697 		syserr("Unbalanced { on %s", mbuf);	/* missing } */
698 	}
699 	else if (*p != '}')
700 	{
701 		syserr("Macro/class name ({%s}) too long (%d chars max)",
702 			mbuf, (int) (sizeof(mbuf) - 1));
703 	}
704 	else if (mbuf[1] == '\0' && mbuf[0] >= 0x20)
705 	{
706 		/* ${x} == $x */
707 		mid = bitidx(mbuf[0]);
708 		p++;
709 	}
710 	else
711 	{
712 		STAB *s;
713 
714 		s = stab(mbuf, ST_MACRO, ST_ENTER);
715 		if (s->s_macro != 0)
716 			mid = s->s_macro;
717 		else
718 		{
719 			if (NextMacroId > MAXMACROID)
720 			{
721 				syserr("Macro/class {%s}: too many long names",
722 					mbuf);
723 				s->s_macro = -1;
724 			}
725 			else
726 			{
727 				MacroName[NextMacroId] = s->s_name;
728 				s->s_macro = mid = NextMacroId;
729 				NextMacroId = NEXTMACROID(NextMacroId);
730 			}
731 		}
732 		p++;
733 	}
734 	if (ep != NULL)
735 		*ep = p;
736 	if (mid < 0 || mid > MAXMACROID)
737 	{
738 		syserr("Unable to assign macro/class ID (mid = 0x%x)", mid);
739 		if (tTd(35, 14))
740 			sm_dprintf("NULL\n");
741 		return 0;
742 	}
743 	if (tTd(35, 14))
744 		sm_dprintf("0x%x\n", mid);
745 	return mid;
746 }
747 
748 /*
749 **  WORDINCLASS -- tell if a word is in a specific class
750 **
751 **	Parameters:
752 **		str -- the name of the word to look up.
753 **		cl -- the class name.
754 **
755 **	Returns:
756 **		true if str can be found in cl.
757 **		false otherwise.
758 */
759 
760 bool
wordinclass(str,cl)761 wordinclass(str, cl)
762 	char *str;
763 	int cl;
764 {
765 	STAB *s;
766 #if _FFR_DYN_CLASS
767 	MAP *map;
768 	int status;
769 	char *p;
770 	char key[MAXLINE];
771 
772 	p = macname(cl);
773 	s = stab(p, ST_DYNMAP, ST_FIND);
774 	if (NULL == s)
775 	{
776 #endif
777 		s = stab(str, ST_CLASS, ST_FIND);
778 		return s != NULL && bitnset(bitidx(cl), s->s_class);
779 #if _FFR_DYN_CLASS
780 	}
781 	map = &s->s_dynclass;
782 	SM_REQUIRE(NULL != map);
783 	SM_REQUIRE(!SM_IS_EMPTY(str));
784 	if (bitset(MF_OPENBOGUS, map->map_mflags))
785 	{
786 		/* need to set some error! */
787 		return false;
788 	}
789 
790 	key[0] = '\0';
791 	if (!SM_IS_EMPTY(map->map_tag))
792 	{
793 		sm_strlcpy(key, map->map_tag, sizeof(key));
794 		sm_strlcat(key, ":", sizeof(key));
795 	}
796 	sm_strlcat(key, str, sizeof(key));
797 	status = EX_OK;
798 	p = (map->map_class->map_lookup)(map, key, NULL, &status);
799 	if (NULL != p)
800 		return true;
801 	if ((EX_OK == status && NULL == p) || EX_NOTFOUND == status)
802 		return false;
803 
804 	sm_syslog(LOG_WARNING, CurEnv->e_id,
805 		"dynamic class: A{%s}: map lookup failed: key=%s, status=%d",
806 		map->map_mname, key, status);
807 
808 	/* Note: this error is shown to the client, so do not "leak" info */
809 	usrerr("451 4.3.1 temporary error");
810 
811 	return false;
812 #endif
813 }
814