xref: /freebsd/contrib/sendmail/src/stab.c (revision d0cef73d40a409e3116f095b83633b1364e95741)
1 /*
2  * Copyright (c) 1998-2001, 2003 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 #include <sendmail.h>
15 
16 SM_RCSID("@(#)$Id: stab.c,v 8.89 2006/08/15 23:24:58 ca Exp $")
17 
18 /*
19 **  STAB -- manage the symbol table
20 **
21 **	Parameters:
22 **		name -- the name to be looked up or inserted.
23 **		type -- the type of symbol.
24 **		op -- what to do:
25 **			ST_ENTER -- enter the name if not already present.
26 **			ST_FIND -- find it only.
27 **
28 **	Returns:
29 **		pointer to a STAB entry for this name.
30 **		NULL if not found and not entered.
31 **
32 **	Side Effects:
33 **		can update the symbol table.
34 */
35 
36 #define STABSIZE	2003
37 #define SM_LOWER(c)	((isascii(c) && isupper(c)) ? tolower(c) : (c))
38 
39 static STAB	*SymTab[STABSIZE];
40 
41 STAB *
42 stab(name, type, op)
43 	char *name;
44 	int type;
45 	int op;
46 {
47 	register STAB *s;
48 	register STAB **ps;
49 	register int hfunc;
50 	register char *p;
51 	int len;
52 
53 	if (tTd(36, 5))
54 		sm_dprintf("STAB: %s %d ", name, type);
55 
56 	/*
57 	**  Compute the hashing function
58 	*/
59 
60 	hfunc = type;
61 	for (p = name; *p != '\0'; p++)
62 		hfunc = ((hfunc << 1) ^ (SM_LOWER(*p) & 0377)) % STABSIZE;
63 
64 	if (tTd(36, 9))
65 		sm_dprintf("(hfunc=%d) ", hfunc);
66 
67 	ps = &SymTab[hfunc];
68 	if (type == ST_MACRO || type == ST_RULESET)
69 	{
70 		while ((s = *ps) != NULL &&
71 		       (s->s_symtype != type || strcmp(name, s->s_name)))
72 			ps = &s->s_next;
73 	}
74 	else
75 	{
76 		while ((s = *ps) != NULL &&
77 		       (s->s_symtype != type || sm_strcasecmp(name, s->s_name)))
78 			ps = &s->s_next;
79 	}
80 
81 	/*
82 	**  Dispose of the entry.
83 	*/
84 
85 	if (s != NULL || op == ST_FIND)
86 	{
87 		if (tTd(36, 5))
88 		{
89 			if (s == NULL)
90 				sm_dprintf("not found\n");
91 			else
92 			{
93 				long *lp = (long *) s->s_class;
94 
95 				sm_dprintf("type %d val %lx %lx %lx %lx\n",
96 					s->s_symtype, lp[0], lp[1], lp[2], lp[3]);
97 			}
98 		}
99 		return s;
100 	}
101 
102 	/*
103 	**  Make a new entry and link it in.
104 	*/
105 
106 	if (tTd(36, 5))
107 		sm_dprintf("entered\n");
108 
109 	/* determine size of new entry */
110 	switch (type)
111 	{
112 	  case ST_CLASS:
113 		len = sizeof(s->s_class);
114 		break;
115 
116 	  case ST_ADDRESS:
117 		len = sizeof(s->s_address);
118 		break;
119 
120 	  case ST_MAILER:
121 		len = sizeof(s->s_mailer);
122 		break;
123 
124 	  case ST_ALIAS:
125 		len = sizeof(s->s_alias);
126 		break;
127 
128 	  case ST_MAPCLASS:
129 		len = sizeof(s->s_mapclass);
130 		break;
131 
132 	  case ST_MAP:
133 		len = sizeof(s->s_map);
134 		break;
135 
136 	  case ST_HOSTSIG:
137 		len = sizeof(s->s_hostsig);
138 		break;
139 
140 	  case ST_NAMECANON:
141 		len = sizeof(s->s_namecanon);
142 		break;
143 
144 	  case ST_MACRO:
145 		len = sizeof(s->s_macro);
146 		break;
147 
148 	  case ST_RULESET:
149 		len = sizeof(s->s_ruleset);
150 		break;
151 
152 	  case ST_HEADER:
153 		len = sizeof(s->s_header);
154 		break;
155 
156 	  case ST_SERVICE:
157 		len = sizeof(s->s_service);
158 		break;
159 
160 #if LDAPMAP
161 	  case ST_LMAP:
162 		len = sizeof(s->s_lmap);
163 		break;
164 #endif /* LDAPMAP */
165 
166 #if MILTER
167 	  case ST_MILTER:
168 		len = sizeof(s->s_milter);
169 		break;
170 #endif /* MILTER */
171 
172 	  case ST_QUEUE:
173 		len = sizeof(s->s_quegrp);
174 		break;
175 
176 #if SOCKETMAP
177 	  case ST_SOCKETMAP:
178 		len = sizeof(s->s_socketmap);
179 		break;
180 #endif /* SOCKETMAP */
181 
182 	  default:
183 		/*
184 		**  Each mailer has its own MCI stab entry:
185 		**
186 		**  s = stab(host, ST_MCI + m->m_mno, ST_ENTER);
187 		**
188 		**  Therefore, anything ST_MCI or larger is an s_mci.
189 		*/
190 
191 		if (type >= ST_MCI)
192 			len = sizeof(s->s_mci);
193 		else
194 		{
195 			syserr("stab: unknown symbol type %d", type);
196 			len = sizeof(s->s_value);
197 		}
198 		break;
199 	}
200 	len += sizeof(*s) - sizeof(s->s_value);
201 
202 	if (tTd(36, 15))
203 		sm_dprintf("size of stab entry: %d\n", len);
204 
205 	/* make new entry */
206 	s = (STAB *) sm_pmalloc_x(len);
207 	memset((char *) s, '\0', len);
208 	s->s_name = sm_pstrdup_x(name);
209 	s->s_symtype = type;
210 
211 	/* link it in */
212 	*ps = s;
213 
214 	/* set a default value for rulesets */
215 	if (type == ST_RULESET)
216 		s->s_ruleset = -1;
217 
218 	return s;
219 }
220 /*
221 **  STABAPPLY -- apply function to all stab entries
222 **
223 **	Parameters:
224 **		func -- the function to apply.  It will be given two
225 **			parameters (the stab entry and the arg).
226 **		arg -- an arbitrary argument, passed to func.
227 **
228 **	Returns:
229 **		none.
230 */
231 
232 void
233 stabapply(func, arg)
234 	void (*func)__P((STAB *, int));
235 	int arg;
236 {
237 	register STAB **shead;
238 	register STAB *s;
239 
240 	for (shead = SymTab; shead < &SymTab[STABSIZE]; shead++)
241 	{
242 		for (s = *shead; s != NULL; s = s->s_next)
243 		{
244 			if (tTd(36, 90))
245 				sm_dprintf("stabapply: trying %d/%s\n",
246 					s->s_symtype, s->s_name);
247 			func(s, arg);
248 		}
249 	}
250 }
251 /*
252 **  QUEUEUP_MACROS -- queueup the macros in a class
253 **
254 **	Write the macros listed in the specified class into the
255 **	file referenced by qfp.
256 **
257 **	Parameters:
258 **		class -- class ID.
259 **		qfp -- file pointer to the queue file.
260 **		e -- the envelope.
261 **
262 **	Returns:
263 **		none.
264 */
265 
266 void
267 queueup_macros(class, qfp, e)
268 	int class;
269 	SM_FILE_T *qfp;
270 	ENVELOPE *e;
271 {
272 	register STAB **shead;
273 	register STAB *s;
274 
275 	if (e == NULL)
276 		return;
277 
278 	class = bitidx(class);
279 	for (shead = SymTab; shead < &SymTab[STABSIZE]; shead++)
280 	{
281 		for (s = *shead; s != NULL; s = s->s_next)
282 		{
283 			int m;
284 			char *p;
285 
286 			if (s->s_symtype == ST_CLASS &&
287 			    bitnset(bitidx(class), s->s_class) &&
288 			    (m = macid(s->s_name)) != 0 &&
289 			    (p = macvalue(m, e)) != NULL)
290 			{
291 				(void) sm_io_fprintf(qfp, SM_TIME_DEFAULT,
292 						      "$%s%s\n",
293 						      s->s_name,
294 						      denlstring(p, true,
295 								 false));
296 			}
297 		}
298 	}
299 }
300 /*
301 **  COPY_CLASS -- copy class members from one class to another
302 **
303 **	Parameters:
304 **		src -- source class.
305 **		dst -- destination class.
306 **
307 **	Returns:
308 **		none.
309 */
310 
311 void
312 copy_class(src, dst)
313 	int src;
314 	int dst;
315 {
316 	register STAB **shead;
317 	register STAB *s;
318 
319 	src = bitidx(src);
320 	dst = bitidx(dst);
321 	for (shead = SymTab; shead < &SymTab[STABSIZE]; shead++)
322 	{
323 		for (s = *shead; s != NULL; s = s->s_next)
324 		{
325 			if (s->s_symtype == ST_CLASS &&
326 			    bitnset(src, s->s_class))
327 				setbitn(dst, s->s_class);
328 		}
329 	}
330 }
331 
332 /*
333 **  RMEXPSTAB -- remove expired entries from SymTab.
334 **
335 **	These entries need to be removed in long-running processes,
336 **	e.g., persistent queue runners, to avoid consuming memory.
337 **
338 **	XXX It might be useful to restrict the maximum TTL to avoid
339 **		caching data very long.
340 **
341 **	Parameters:
342 **		none.
343 **
344 **	Returns:
345 **		none.
346 **
347 **	Side Effects:
348 **		can remove entries from the symbol table.
349 */
350 
351 #define SM_STAB_FREE(x)	\
352 	do \
353 	{ \
354 		char *o = (x); \
355 		(x) = NULL; \
356 		if (o != NULL) \
357 			sm_free(o); \
358 	} while (0)
359 
360 void
361 rmexpstab()
362 {
363 	int i;
364 	STAB *s, *p, *f;
365 	time_t now;
366 
367 	now = curtime();
368 	for (i = 0; i < STABSIZE; i++)
369 	{
370 		p = NULL;
371 		s = SymTab[i];
372 		while (s != NULL)
373 		{
374 			switch (s->s_symtype)
375 			{
376 			  case ST_HOSTSIG:
377 				if (s->s_hostsig.hs_exp >= now)
378 					goto next;	/* not expired */
379 				SM_STAB_FREE(s->s_hostsig.hs_sig); /* XXX */
380 				break;
381 
382 			  case ST_NAMECANON:
383 				if (s->s_namecanon.nc_exp >= now)
384 					goto next;	/* not expired */
385 				SM_STAB_FREE(s->s_namecanon.nc_cname); /* XXX */
386 				break;
387 
388 			  default:
389 				if (s->s_symtype >= ST_MCI)
390 				{
391 					/* call mci_uncache? */
392 					SM_STAB_FREE(s->s_mci.mci_status);
393 					SM_STAB_FREE(s->s_mci.mci_rstatus);
394 					SM_STAB_FREE(s->s_mci.mci_heloname);
395 #if 0
396 					/* not dynamically allocated */
397 					SM_STAB_FREE(s->s_mci.mci_host);
398 					SM_STAB_FREE(s->s_mci.mci_tolist);
399 #endif /* 0 */
400 #if SASL
401 					/* should always by NULL */
402 					SM_STAB_FREE(s->s_mci.mci_sasl_string);
403 #endif /* SASL */
404 					if (s->s_mci.mci_rpool != NULL)
405 					{
406 						sm_rpool_free(s->s_mci.mci_rpool);
407 						s->s_mci.mci_macro.mac_rpool = NULL;
408 						s->s_mci.mci_rpool = NULL;
409 					}
410 					break;
411 				}
412   next:
413 				p = s;
414 				s = s->s_next;
415 				continue;
416 			}
417 
418 			/* remove entry */
419 			SM_STAB_FREE(s->s_name); /* XXX */
420 			f = s;
421 			s = s->s_next;
422 			sm_free(f);	/* XXX */
423 			if (p == NULL)
424 				SymTab[i] = s;
425 			else
426 				p->s_next = s;
427 		}
428 	}
429 }
430 
431 #if SM_HEAP_CHECK
432 /*
433 **  DUMPSTAB -- dump symbol table.
434 **
435 **	For debugging.
436 */
437 
438 #define MAXSTTYPES	(ST_MCI + 1)
439 
440 void
441 dumpstab()
442 {
443 	int i, t, total, types[MAXSTTYPES];
444 	STAB *s;
445 	static int prevt[MAXSTTYPES], prev = 0;
446 
447 	total = 0;
448 	for (i = 0; i < MAXSTTYPES; i++)
449 		types[i] = 0;
450 	for (i = 0; i < STABSIZE; i++)
451 	{
452 		s = SymTab[i];
453 		while (s != NULL)
454 		{
455 			++total;
456 			t = s->s_symtype;
457 			if (t > MAXSTTYPES - 1)
458 				t = MAXSTTYPES - 1;
459 			types[t]++;
460 			s = s->s_next;
461 		}
462 	}
463 	sm_syslog(LOG_INFO, NOQID, "stab: total=%d (%d)", total, total - prev);
464 	prev = total;
465 	for (i = 0; i < MAXSTTYPES; i++)
466 	{
467 		if (types[i] != 0)
468 		{
469 			sm_syslog(LOG_INFO, NOQID, "stab: type[%2d]=%2d (%d)",
470 				i, types[i], types[i] - prevt[i]);
471 		}
472 		prevt[i] = types[i];
473 	}
474 }
475 #endif /* SM_HEAP_CHECK */
476