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