Add patch to fix login to dovecot imapd 2.x (Closes: #715040)
Ondřej Surý
9 years ago
0 | From 98b21c0aa01d4ef1e05158a79dc3e291e53bee81 Mon Sep 17 00:00:00 2001 | |
1 | From: Sebastian Pipping <sebastian@pipping.org> | |
2 | Date: Fri, 5 Jul 2013 18:34:50 +0200 | |
3 | Subject: [PATCH] 2.1.26: Allow "* CAPABILITY" lines in IMAP login reply (v4) | |
4 | ||
5 | --- | |
6 | saslauthd/auth_rimap.c | 125 +++++++++++++++++++++++++++++++++++++++++++------ | |
7 | 1 file changed, 111 insertions(+), 14 deletions(-) | |
8 | ||
9 | --- cyrus-sasl2.orig/saslauthd/auth_rimap.c | |
10 | +++ cyrus-sasl2/saslauthd/auth_rimap.c | |
11 | @@ -3,6 +3,7 @@ | |
12 | ||
13 | /* COPYRIGHT | |
14 | * Copyright (c) 1998 Messaging Direct Ltd. | |
15 | + * Copyright (c) 2013 Sebastian Pipping <sebastian@pipping.org> | |
16 | * All rights reserved. | |
17 | * | |
18 | * Redistribution and use in source and binary forms, with or without | |
19 | @@ -91,6 +92,9 @@ static struct addrinfo *ai = NULL; /* re | |
20 | #define TAG "saslauthd" /* IMAP command tag */ | |
21 | #define LOGIN_CMD (TAG " LOGIN ") /* IMAP login command (with tag) */ | |
22 | #define LOGOUT_CMD (TAG " LOGOUT ") /* IMAP logout command (with tag)*/ | |
23 | +#define LOGIN_REPLY_GOOD (TAG " OK") /* Expected IMAP login reply, good edition (with tag) */ | |
24 | +#define LOGIN_REPLY_BAD (TAG " NO") /* Expected IMAP login reply, bad edition (with tag) */ | |
25 | +#define LOGIN_REPLY_CAP "* CAPABILITY" /* Expected IMAP login reply, capabilities edition */ | |
26 | #define NETWORK_IO_TIMEOUT 30 /* network I/O timeout (seconds) */ | |
27 | #define RESP_LEN 1000 /* size of read response buffer */ | |
28 | ||
29 | @@ -278,6 +282,109 @@ auth_rimap_init ( | |
30 | ||
31 | /* END FUNCTION: auth_rimap_init */ | |
32 | ||
33 | +typedef enum _t_login_status { | |
34 | + LOGIN_STATUS_UNKNOWN, | |
35 | + | |
36 | + LOGIN_STATUS_ACCEPTED, | |
37 | + LOGIN_STATUS_REJECTED, | |
38 | + LOGIN_STATUS_MALFORMED | |
39 | +} t_login_status; | |
40 | + | |
41 | +/* FUNCTION: warn_malformed_imap_login_reply */ | |
42 | +void | |
43 | +warn_malformed_imap_login_reply( | |
44 | + /* PARAMETERS */ | |
45 | + const char * server_reply /* I: plaintext server reply */ | |
46 | + /* END PARAMETERS */ | |
47 | + ) | |
48 | +{ | |
49 | + syslog(LOG_WARNING, "auth_rimap: unexpected response to auth request: %s", server_reply); | |
50 | +} | |
51 | + | |
52 | +/* END FUNCTION: warn_malformed_imap_login_reply */ | |
53 | + | |
54 | +/* FUNCTION: process_login_reply */ | |
55 | + | |
56 | +/* SYNOPSIS | |
57 | + * Classify IMAP server reply into accepted, rejected or malformed. | |
58 | + * END SYNOPSIS */ | |
59 | + | |
60 | +t_login_status | |
61 | +process_login_reply( | |
62 | + /* PARAMETERS */ | |
63 | + char * server_reply, /* I/O: plaintext server reply */ | |
64 | + const char * login /* I : plaintext authenticator */ | |
65 | + /* END PARAMETERS */ | |
66 | + ) | |
67 | +{ | |
68 | + /* VARIABLES */ | |
69 | + t_login_status res = LOGIN_STATUS_UNKNOWN; | |
70 | + char * line_first = server_reply; | |
71 | + char * line_after_last; | |
72 | + /* END VARIABLES */ | |
73 | + | |
74 | + for (;;) { | |
75 | + /* find line boundary */ | |
76 | + line_after_last = strpbrk(line_first, "\x0a\x0d"); | |
77 | + if (line_after_last == NULL) { | |
78 | + warn_malformed_imap_login_reply(line_first); | |
79 | + return LOGIN_STATUS_MALFORMED; | |
80 | + } | |
81 | + | |
82 | + /* handle single line */ | |
83 | + { | |
84 | + /* terminate line (reverted later) */ | |
85 | + const char backup = line_after_last[0]; | |
86 | + line_after_last[0] = '\0'; | |
87 | + | |
88 | + /* classify current line */ | |
89 | + if (strncmp(line_first, LOGIN_REPLY_GOOD, sizeof(LOGIN_REPLY_GOOD) - 1) == 0) { | |
90 | + res = LOGIN_STATUS_ACCEPTED; | |
91 | + } else if (strncmp(line_first, LOGIN_REPLY_BAD, sizeof(LOGIN_REPLY_BAD) - 1) == 0) { | |
92 | + res = LOGIN_STATUS_REJECTED; | |
93 | + } else if (strncmp(line_first, LOGIN_REPLY_CAP, sizeof(LOGIN_REPLY_CAP) - 1) == 0) { | |
94 | + /* keep looking for ".. OK" or ".. NO" */ | |
95 | + } else { | |
96 | + res = LOGIN_STATUS_MALFORMED; | |
97 | + } | |
98 | + | |
99 | + /* report current line */ | |
100 | + if (res == LOGIN_STATUS_MALFORMED) { | |
101 | + warn_malformed_imap_login_reply(line_first); | |
102 | + } else if (flags & VERBOSE) { | |
103 | + syslog(LOG_DEBUG, "auth_rimap: [%s] %s", login, line_first); | |
104 | + } | |
105 | + | |
106 | + /* revert termination */ | |
107 | + line_after_last[0] = backup; | |
108 | + } | |
109 | + | |
110 | + /* are we done? */ | |
111 | + if (res != LOGIN_STATUS_UNKNOWN) { | |
112 | + return res; | |
113 | + } | |
114 | + | |
115 | + /* forward to next line */ | |
116 | + while ((line_after_last[0] == '\x0a') | |
117 | + || (line_after_last[0] == '\x0d')) { | |
118 | + line_after_last++; | |
119 | + } | |
120 | + | |
121 | + /* no more lines? */ | |
122 | + if (line_after_last[0] == '\0') { | |
123 | + warn_malformed_imap_login_reply(""); | |
124 | + return LOGIN_STATUS_MALFORMED; | |
125 | + } | |
126 | + | |
127 | + /* prepare for next round */ | |
128 | + line_first = line_after_last; | |
129 | + } | |
130 | + | |
131 | + assert(! "cannot be reached"); | |
132 | +} | |
133 | + | |
134 | +/* END FUNCTION: process_login_reply */ | |
135 | + | |
136 | /* FUNCTION: auth_rimap */ | |
137 | ||
138 | /* SYNOPSIS | |
139 | @@ -318,6 +425,7 @@ auth_rimap ( | |
140 | char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV]; | |
141 | int saved_errno; | |
142 | int niflags; | |
143 | + t_login_status login_status = LOGIN_STATUS_MALFORMED; | |
144 | /* END VARIABLES */ | |
145 | ||
146 | /* sanity checks */ | |
147 | @@ -533,25 +641,14 @@ auth_rimap ( | |
148 | } | |
149 | ||
150 | rbuf[rc] = '\0'; /* tie off response */ | |
151 | - c = strpbrk(rbuf, "\r\n"); | |
152 | - if (c != NULL) { | |
153 | - *c = '\0'; /* tie off line termination */ | |
154 | - } | |
155 | + login_status = process_login_reply(rbuf, login); | |
156 | ||
157 | - if (!strncmp(rbuf, TAG " OK", sizeof(TAG " OK")-1)) { | |
158 | - if (flags & VERBOSE) { | |
159 | - syslog(LOG_DEBUG, "auth_rimap: [%s] %s", login, rbuf); | |
160 | - } | |
161 | + if (login_status == LOGIN_STATUS_ACCEPTED) { | |
162 | return strdup("OK remote authentication successful"); | |
163 | } | |
164 | - if (!strncmp(rbuf, TAG " NO", sizeof(TAG " NO")-1)) { | |
165 | - if (flags & VERBOSE) { | |
166 | - syslog(LOG_DEBUG, "auth_rimap: [%s] %s", login, rbuf); | |
167 | - } | |
168 | + if (login_status == LOGIN_STATUS_REJECTED) { | |
169 | return strdup("NO remote server rejected your credentials"); | |
170 | } | |
171 | - syslog(LOG_WARNING, "auth_rimap: unexpected response to auth request: %s", | |
172 | - rbuf); | |
173 | return strdup(RESP_UNEXPECTED); | |
174 | ||
175 | } |