-
Notifications
You must be signed in to change notification settings - Fork 3
/
plugin-starttls-ucspi.c
105 lines (85 loc) · 2.17 KB
/
plugin-starttls-ucspi.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include "mailfront.h"
#include <stdlib.h>
#include <unistd.h>
#include <bglibs/iobuf.h>
static RESPONSE(start, 220, "2.0.0 Ready to start TLS");
static RESPONSE(earlytalker, 500, "5.5.1 Unexpected pipelined commands following STARTTLS");
static int tls_available = 0;
static const response* init(void)
{
tls_available = getenv("UCSPITLS") != 0;
return 0;
}
static const response* helo(str* hostname, str* capabilities)
{
if (tls_available)
if (!str_cats(capabilities, "STARTTLS\n")) return &resp_oom;
return 0;
(void)hostname;
}
static int starttls(void)
{
int fd;
char *fdstr;
int extrachars = 0;
char c;
/* STARTTLS must be the last command in a pipeline, otherwise we can
* create a security risk (see CVE-2011-0411). Close input and
* check for any extra pipelined commands, so we can give an error
* message. Note that this will cause an error on the filehandle,
* since we have closed it. */
close(0);
while (!ibuf_eof(&inbuf) && !ibuf_error(&inbuf)) {
if (ibuf_getc(&inbuf, &c))
++extrachars;
}
if (!(fdstr=getenv("SSLCTLFD")))
return 0;
if ((fd = atoi(fdstr)) <= 0)
return 0;
if (write(fd, "y", 1) < 1)
return 0;
if (!(fdstr=getenv("SSLREADFD")))
return 0;
if ((fd = atoi(fdstr)) <= 0)
return 0;
if (dup2(fd, 0) != 0)
return 0;
if (!(fdstr=getenv("SSLWRITEFD")))
return 0;
if ((fd = atoi(fdstr)) <= 0)
return 0;
if (dup2(fd, 1) != 1)
return 0;
/* Re-initialize stdin and clear input buffer */
ibuf_init(&inbuf,0,0,IOBUF_NEEDSCLOSE, 4096);
if (extrachars)
respond(&resp_earlytalker);
return 1;
}
static int enabled(void)
{
return tls_available;
}
static int cmd_STARTTLS(void)
{
if (!respond(&resp_start))
return 0;
if (!starttls())
return 0;
tls_available = 0;
session_setnum("tls_state", 1);
/* Remove UCSPITLS from environment to indicate it no longer available. */
unsetenv("UCSPITLS");
return 1;
}
static const struct command commands[] = {
{ "STARTTLS", .fn_enabled = enabled, .fn_noparam = cmd_STARTTLS },
{ .name = 0 }
};
struct plugin plugin = {
.version = PLUGIN_VERSION,
.commands = commands,
.init = init,
.helo = helo,
};