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