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
16SM_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
23static 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 */
38static 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
79int		NextMacroId = 1;	/* codes for long named macros */
80/* see sendmail.h: Special characters in rewriting rules. */
81#else /* _FFR_MORE_MACROS */
82int		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
102struct 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
129void
130initmacros(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
174static void doexpand __P(( char *, char *, size_t, int, ENVELOPE *));
175
176static void
177doexpand(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
347void
348expand(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
370void
371mactabclear(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
418void
419#if SM_HEAP_CHECK
420macdefine_tagged(mac, vclass, id, value, file, line, grp)
421#else
422macdefine(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
514void
515macset(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
549char *
550macvalue(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
600char *
601macname(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
644int
645macid_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
760bool
761wordinclass(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