1/*++
2/* NAME
3/*	tls_mgr 3
4/* SUMMARY
5/*	tlsmgr client interface
6/* SYNOPSIS
7/*	#include <tls_mgr.h>
8/*
9/*	int	tls_mgr_seed(buf, len)
10/*	VSTRING	*buf;
11/*	int	len;
12/*
13/*	int	tls_mgr_policy(cache_type, cachable, timeout)
14/*	const char *cache_type;
15/*	int	*cachable;
16/*	int	*timeout;
17/*
18/*	int	tls_mgr_update(cache_type, cache_id, buf, len)
19/*	const char *cache_type;
20/*	const char *cache_id;
21/*	const char *buf;
22/*	ssize_t	len;
23/*
24/*	int	tls_mgr_lookup(cache_type, cache_id, buf)
25/*	const char *cache_type;
26/*	const char *cache_id;
27/*	VSTRING	*buf;
28/*
29/*	int	tls_mgr_delete(cache_type, cache_id)
30/*	const char *cache_type;
31/*	const char *cache_id;
32/*
33/*	TLS_TICKET_KEY *tls_mgr_key(keyname, timeout)
34/*	unsigned char *keyname;
35/*	int	timeout;
36/* DESCRIPTION
37/*	These routines communicate with the tlsmgr(8) server for
38/*	entropy and session cache management. Since these are
39/*	non-critical services, requests are allowed to fail without
40/*	disrupting Postfix.
41/*
42/*	tls_mgr_seed() requests entropy from the tlsmgr(8)
43/*	Pseudo Random Number Generator (PRNG) pool.
44/*
45/*	tls_mgr_policy() requests the session caching policy.
46/*
47/*	tls_mgr_lookup() loads the specified session from
48/*	the specified session cache.
49/*
50/*	tls_mgr_update() saves the specified session to
51/*	the specified session cache.
52/*
53/*	tls_mgr_delete() removes specified session from
54/*	the specified session cache.
55/*
56/*	tls_mgr_key() is used to retrieve the current TLS session ticket
57/*	encryption or decryption keys.
58/*
59/*	Arguments:
60/* .IP cache_type
61/*	One of TLS_MGR_SCACHE_SMTPD, TLS_MGR_SCACHE_SMTP or
62/*	TLS_MGR_SCACHE_LMTP.
63/* .IP cachable
64/*	Pointer to int, set non-zero if the requested cache_type
65/*	is enabled.
66/* .IP timeout
67/*	Pointer to int, returns the cache entry timeout.
68/* .IP cache_id
69/*	The session cache lookup key.
70/* .IP buf
71/*	The result or input buffer.
72/* .IP len
73/*	The length of the input buffer, or the amount of data requested.
74/* .IP keyname
75/*	Is null when requesting the current encryption keys.  Otherwise,
76/*	keyname is a pointer to an array of TLS_TICKET_NAMELEN unsigned
77/*	chars (not NUL terminated) that is an identifier for a key
78/*	previously used to encrypt a session ticket.  When encrypting
79/*	a null result indicates that session tickets are not supported, when
80/*	decrypting it indicates that no matching keys were found.
81/* .IP timeout
82/*	The encryption key timeout.  Once a key has been active for this many
83/*	seconds it is retired and used only for decrypting previously issued
84/*	session tickets for another timeout seconds, and is then destroyed.
85/*	The timeout must not be longer than half the SSL session lifetime.
86/* DIAGNOSTICS
87/*	All client functions return one of the following status codes:
88/* .IP TLS_MGR_STAT_OK
89/*      The request completed, and the requested operation was
90/*	successful (for example, the requested session was found,
91/*	or the specified session was saved or removed).
92/* .IP TLS_MGR_STAT_ERR
93/*      The request completed, but the requested operation failed
94/*	(for example, the requested object was not found or the
95/*	specified session was not saved or removed).
96/* .IP TLS_MGR_STAT_FAIL
97/*      The request could not complete (the client could not
98/*	communicate with the tlsmgr(8) server).
99/* SEE ALSO
100/*	tlsmgr(8) TLS session and PRNG management
101/* LICENSE
102/* .ad
103/* .fi
104/*	The Secure Mailer license must be distributed with this software.
105/* AUTHOR(S)
106/*	Wietse Venema
107/*	IBM T.J. Watson Research
108/*	P.O. Box 704
109/*	Yorktown Heights, NY 10598, USA
110/*--*/
111
112/* System library. */
113
114#include <sys_defs.h>
115
116#ifdef USE_TLS
117
118#ifdef STRCASECMP_IN_STRINGS_H
119#include <strings.h>
120#endif
121
122/* Utility library. */
123
124#include <msg.h>
125#include <vstream.h>
126#include <vstring.h>
127#include <attr.h>
128#include <attr_clnt.h>
129#include <mymalloc.h>
130#include <stringops.h>
131
132/* Global library. */
133
134#include <mail_params.h>
135#include <mail_proto.h>
136
137/* TLS library. */
138#include <tls_mgr.h>
139
140/* Application-specific. */
141
142#define STR(x) vstring_str(x)
143#define LEN(x) VSTRING_LEN(x)
144
145static ATTR_CLNT *tls_mgr;
146
147/* tls_mgr_open - create client handle */
148
149static void tls_mgr_open(void)
150{
151    char   *service;
152
153    /*
154     * Sanity check.
155     */
156    if (tls_mgr != 0)
157	msg_panic("tls_mgr_open: multiple initialization");
158
159    /*
160     * Use whatever IPC is preferred for internal use: UNIX-domain sockets or
161     * Solaris streams.
162     */
163    service = concatenate("local:" TLS_MGR_CLASS "/", var_tls_mgr_service,
164			  (char *) 0);
165    tls_mgr = attr_clnt_create(service, var_ipc_timeout,
166			       var_ipc_idle_limit, var_ipc_ttl_limit);
167    myfree(service);
168
169    attr_clnt_control(tls_mgr,
170		      ATTR_CLNT_CTL_PROTO, attr_vprint, attr_vscan,
171		      ATTR_CLNT_CTL_END);
172}
173
174/* tls_mgr_seed - request PRNG seed */
175
176int     tls_mgr_seed(VSTRING *buf, int len)
177{
178    int     status;
179
180    /*
181     * Create the tlsmgr client handle.
182     */
183    if (tls_mgr == 0)
184	tls_mgr_open();
185
186    /*
187     * Request seed.
188     */
189    if (attr_clnt_request(tls_mgr,
190			  ATTR_FLAG_NONE,	/* Request attributes */
191			  ATTR_TYPE_STR, TLS_MGR_ATTR_REQ, TLS_MGR_REQ_SEED,
192			  ATTR_TYPE_INT, TLS_MGR_ATTR_SIZE, len,
193			  ATTR_TYPE_END,
194			  ATTR_FLAG_MISSING,	/* Reply attributes */
195			  ATTR_TYPE_INT, TLS_MGR_ATTR_STATUS, &status,
196			  ATTR_TYPE_DATA, TLS_MGR_ATTR_SEED, buf,
197			  ATTR_TYPE_END) != 2)
198	status = TLS_MGR_STAT_FAIL;
199    return (status);
200}
201
202/* tls_mgr_policy - request caching policy */
203
204int     tls_mgr_policy(const char *cache_type, int *cachable, int *timeout)
205{
206    int     status;
207
208    /*
209     * Create the tlsmgr client handle.
210     */
211    if (tls_mgr == 0)
212	tls_mgr_open();
213
214    /*
215     * Request policy.
216     */
217    if (attr_clnt_request(tls_mgr,
218			  ATTR_FLAG_NONE,	/* Request attributes */
219			ATTR_TYPE_STR, TLS_MGR_ATTR_REQ, TLS_MGR_REQ_POLICY,
220			  ATTR_TYPE_STR, TLS_MGR_ATTR_CACHE_TYPE, cache_type,
221			  ATTR_TYPE_END,
222			  ATTR_FLAG_MISSING,	/* Reply attributes */
223			  ATTR_TYPE_INT, TLS_MGR_ATTR_STATUS, &status,
224			  ATTR_TYPE_INT, TLS_MGR_ATTR_CACHABLE, cachable,
225			  ATTR_TYPE_INT, TLS_MGR_ATTR_SESSTOUT, timeout,
226			  ATTR_TYPE_END) != 3)
227	status = TLS_MGR_STAT_FAIL;
228    return (status);
229}
230
231/* tls_mgr_lookup - request cached session */
232
233int     tls_mgr_lookup(const char *cache_type, const char *cache_id,
234		               VSTRING *buf)
235{
236    int     status;
237
238    /*
239     * Create the tlsmgr client handle.
240     */
241    if (tls_mgr == 0)
242	tls_mgr_open();
243
244    /*
245     * Send the request and receive the reply.
246     */
247    if (attr_clnt_request(tls_mgr,
248			  ATTR_FLAG_NONE,	/* Request */
249			ATTR_TYPE_STR, TLS_MGR_ATTR_REQ, TLS_MGR_REQ_LOOKUP,
250			  ATTR_TYPE_STR, TLS_MGR_ATTR_CACHE_TYPE, cache_type,
251			  ATTR_TYPE_STR, TLS_MGR_ATTR_CACHE_ID, cache_id,
252			  ATTR_TYPE_END,
253			  ATTR_FLAG_MISSING,	/* Reply */
254			  ATTR_TYPE_INT, TLS_MGR_ATTR_STATUS, &status,
255			  ATTR_TYPE_DATA, TLS_MGR_ATTR_SESSION, buf,
256			  ATTR_TYPE_END) != 2)
257	status = TLS_MGR_STAT_FAIL;
258    return (status);
259}
260
261/* tls_mgr_update - save session to cache */
262
263int     tls_mgr_update(const char *cache_type, const char *cache_id,
264		               const char *buf, ssize_t len)
265{
266    int     status;
267
268    /*
269     * Create the tlsmgr client handle.
270     */
271    if (tls_mgr == 0)
272	tls_mgr_open();
273
274    /*
275     * Send the request and receive the reply.
276     */
277    if (attr_clnt_request(tls_mgr,
278			  ATTR_FLAG_NONE,	/* Request */
279			ATTR_TYPE_STR, TLS_MGR_ATTR_REQ, TLS_MGR_REQ_UPDATE,
280			  ATTR_TYPE_STR, TLS_MGR_ATTR_CACHE_TYPE, cache_type,
281			  ATTR_TYPE_STR, TLS_MGR_ATTR_CACHE_ID, cache_id,
282			  ATTR_TYPE_DATA, TLS_MGR_ATTR_SESSION, len, buf,
283			  ATTR_TYPE_END,
284			  ATTR_FLAG_MISSING,	/* Reply */
285			  ATTR_TYPE_INT, TLS_MGR_ATTR_STATUS, &status,
286			  ATTR_TYPE_END) != 1)
287	status = TLS_MGR_STAT_FAIL;
288    return (status);
289}
290
291/* tls_mgr_delete - remove cached session */
292
293int     tls_mgr_delete(const char *cache_type, const char *cache_id)
294{
295    int     status;
296
297    /*
298     * Create the tlsmgr client handle.
299     */
300    if (tls_mgr == 0)
301	tls_mgr_open();
302
303    /*
304     * Send the request and receive the reply.
305     */
306    if (attr_clnt_request(tls_mgr,
307			  ATTR_FLAG_NONE,	/* Request */
308			ATTR_TYPE_STR, TLS_MGR_ATTR_REQ, TLS_MGR_REQ_DELETE,
309			  ATTR_TYPE_STR, TLS_MGR_ATTR_CACHE_TYPE, cache_type,
310			  ATTR_TYPE_STR, TLS_MGR_ATTR_CACHE_ID, cache_id,
311			  ATTR_TYPE_END,
312			  ATTR_FLAG_MISSING,	/* Reply */
313			  ATTR_TYPE_INT, TLS_MGR_ATTR_STATUS, &status,
314			  ATTR_TYPE_END) != 1)
315	status = TLS_MGR_STAT_FAIL;
316    return (status);
317}
318
319/* request_scache_key - ask tlsmgr(8) for matching key */
320
321static TLS_TICKET_KEY *request_scache_key(unsigned char *keyname)
322{
323    TLS_TICKET_KEY tmp;
324    static VSTRING *keybuf;
325    char   *name;
326    size_t  len;
327    int     status;
328
329    /*
330     * Create the tlsmgr client handle.
331     */
332    if (tls_mgr == 0)
333	tls_mgr_open();
334
335    if (keybuf == 0)
336	keybuf = vstring_alloc(sizeof(tmp));
337
338    /* In tlsmgr requests we encode null key names as empty strings. */
339    name = keyname ? (char *) keyname : "";
340    len = keyname ? TLS_TICKET_NAMELEN : 0;
341
342    /*
343     * Send the request and receive the reply.
344     */
345    if (attr_clnt_request(tls_mgr,
346			  ATTR_FLAG_NONE,	/* Request */
347			ATTR_TYPE_STR, TLS_MGR_ATTR_REQ, TLS_MGR_REQ_TKTKEY,
348			  ATTR_TYPE_DATA, TLS_MGR_ATTR_KEYNAME, len, name,
349			  ATTR_TYPE_END,
350			  ATTR_FLAG_MISSING,	/* Reply */
351			  ATTR_TYPE_INT, TLS_MGR_ATTR_STATUS, &status,
352			  ATTR_TYPE_DATA, TLS_MGR_ATTR_KEYBUF, keybuf,
353			  ATTR_TYPE_END) != 2
354	|| status != TLS_MGR_STAT_OK
355	|| LEN(keybuf) != sizeof(tmp))
356	return (0);
357
358    memcpy((char *) &tmp, STR(keybuf), sizeof(tmp));
359    return (tls_scache_key_rotate(&tmp));
360}
361
362/* tls_mgr_key - session ticket key lookup, local cache, then tlsmgr(8) */
363
364TLS_TICKET_KEY *tls_mgr_key(unsigned char *keyname, int timeout)
365{
366    TLS_TICKET_KEY *key = 0;
367    time_t  now = time((time_t *) 0);
368
369    /* A zero timeout disables session tickets. */
370    if (timeout <= 0)
371	return (0);
372
373    if ((key = tls_scache_key(keyname, now, timeout)) == 0)
374	key = request_scache_key(keyname);
375    return (key);
376}
377
378#ifdef TEST
379
380/* System library. */
381
382#include <stdlib.h>
383
384/* Utility library. */
385
386#include <argv.h>
387#include <msg_vstream.h>
388#include <vstring_vstream.h>
389#include <hex_code.h>
390
391/* Global library. */
392
393#include <config.h>
394
395/* Application-specific. */
396
397int     main(int unused_ac, char **av)
398{
399    VSTRING *inbuf = vstring_alloc(10);
400    int     status;
401    ARGV   *argv = 0;
402
403    msg_vstream_init(av[0], VSTREAM_ERR);
404
405    msg_verbose = 3;
406
407    mail_conf_read();
408    msg_info("using config files in %s", var_config_dir);
409
410    if (chdir(var_queue_dir) < 0)
411	msg_fatal("chdir %s: %m", var_queue_dir);
412
413    while (vstring_fgets_nonl(inbuf, VSTREAM_IN)) {
414	argv = argv_split(STR(inbuf), " \t\r\n");
415	if (argv->argc == 0) {
416	    argv_free(argv);
417	    continue;
418	}
419#define COMMAND(argv, str, len) \
420    (strcasecmp(argv->argv[0], str) == 0 && argv->argc == len)
421
422	if (COMMAND(argv, "policy", 2)) {
423	    int     cachable;
424	    int     timeout;
425
426	    status = tls_mgr_policy(argv->argv[1], &cachable, &timeout);
427	    vstream_printf("status=%d cachable=%d timeout=%d\n",
428			   status, cachable, timeout);
429	} else if (COMMAND(argv, "seed", 2)) {
430	    VSTRING *buf = vstring_alloc(10);
431	    VSTRING *hex = vstring_alloc(10);
432	    int     len = atoi(argv->argv[1]);
433
434	    status = tls_mgr_seed(buf, len);
435	    hex_encode(hex, STR(buf), LEN(buf));
436	    vstream_printf("status=%d seed=%s\n", status, STR(hex));
437	    vstring_free(hex);
438	    vstring_free(buf);
439	} else if (COMMAND(argv, "lookup", 3)) {
440	    VSTRING *buf = vstring_alloc(10);
441
442	    status = tls_mgr_lookup(argv->argv[1], argv->argv[2], buf);
443	    vstream_printf("status=%d session=%.*s\n",
444			   status, LEN(buf), STR(buf));
445	    vstring_free(buf);
446	} else if (COMMAND(argv, "update", 4)) {
447	    status = tls_mgr_update(argv->argv[1], argv->argv[2],
448				    argv->argv[3], strlen(argv->argv[3]));
449	    vstream_printf("status=%d\n", status);
450	} else if (COMMAND(argv, "delete", 3)) {
451	    status = tls_mgr_delete(argv->argv[1], argv->argv[2]);
452	    vstream_printf("status=%d\n", status);
453	} else {
454	    vstream_printf("usage:\n"
455			   "seed byte_count\n"
456			   "policy smtpd|smtp|lmtp\n"
457			   "lookup smtpd|smtp|lmtp cache_id\n"
458			   "update smtpd|smtp|lmtp cache_id session\n"
459			   "delete smtpd|smtp|lmtp cache_id\n");
460	}
461	vstream_fflush(VSTREAM_OUT);
462	argv_free(argv);
463    }
464
465    vstring_free(inbuf);
466    return (0);
467}
468
469#endif					/* TEST */
470
471#endif					/* USE_TLS */
472