1 /*
2 * Copyright (c) 2011 QUALCOMM Incorporated. All rights reserved.
3 * The file License.txt specifies the terms for use, modification,
4 * and redistribution.
5 *
6 *
7 * File: pop_extend.c
8 *
9 * Revisions:
10 * 04/24/08 [RCG]
11 * - Fix compilation error with some compilers.
12 *
13 * 02/22/06 [RCG]
14 * - Handle case where macro redefined
15 * - Don't increment last_index until sure within bounds
16 * - Increase max MDEF length from 100 to 500 (since max
17 * length includes name and value)
18 * - Correct error message when MDEF too long
19 *
20 * 08/13/03 [RCG]
21 * - Patch from Uli Zappe to fix SCRAM compilation bugs.
22 *
23 * 03/12/03 [RCG]
24 * - Free allocated memory in more MDEF error cases.
25 * - Impose maximum size on MDEF.
26 * - Don't use free'd memory in pop_msg call (reported
27 * by Florian Heinz).
28 *
29 * 09/17/02 [RCG]
30 * - pop_stls now return POP_SUCCESS (even though it
31 * generates a POP_FAILURE message) except for a
32 * timeout, so that the state machine stays in auth1
33 * and doesn't go into halt (thus these errors are
34 * not fatal).
35 *
36 * 01/15/01 [RCG]
37 * - login_delay and expire now in p.
38 * - bShy now in p.
39 *
40 * 12/21/00 [RCG]
41 * - Handle tls_support instead of stls / alternate_port.
42 *
43 * 11/20/00 [RCG]
44 * - Inactivity timeout for STLS aborts.
45 *
46 * 10/12/00 [RCG}
47 * - Fitted LGL's TLS changes.
48 *
49 * 06/05/00 [RCG]
50 * - CAPA IMPLEMENTATION tag omitted if SHY and not
51 * authenticated.
52 *
53 * 02/09/00 [RCG]
54 * - Added AUTH-RESP-CODE.
55 *
56 * 03/18/98 [PY]
57 * - File added.
58 *
59 */
60
61
62 #include "config.h"
63
64 #include <sys/types.h>
65 #include <stdio.h>
66 #include <stdlib.h>
67 #include <pwd.h>
68 #include <string.h>
69
70 #include "popper.h"
71
72 #ifndef HAVE_BCOPY
73 # define bcopy(src,dest,len) (void) (memcpy(dest,src,len))
74 # define bzero(dest,len) (void) (memset(dest, (char)NULL, len))
75 # define bcmp(b1,b2,n) memcmp(b1,b2,n)
76 #endif /* not HAVE_BCOPY */
77
78 #ifndef HAVE_INDEX
79 # define index(s,c) strchr(s,c)
80 # define rindex(s,c) strrchr(s,c)
81 #endif /* not HAVE_INDEX */
82
83
84 extern volatile BOOL poptimeout;
85
86
87 int
pop_capa(POP * p)88 pop_capa ( POP *p )
89 {
90 POP_WRITE_LIT ( p, "+OK Capability list follows\r\n" );
91 POP_WRITE_LIT ( p, "TOP\r\n" );
92
93 /*
94 POP_WRITE_LIT ( p, "PIPELINING\r\n", );
95 */
96
97 # if defined(SCRAM)
98 POP_WRITE_LIT ( p, "SASL SCRAM-MD5\r\n" );
99 # elif defined(CYRUS_SASL)
100 pop_sasl_mechs ( p );
101 # endif
102
103 # if !defined(APOP_ONLY) && !defined(SCRAM_ONLY)
104 if ( p->AllowClearText != ClearTextNever )
105 POP_WRITE_LIT ( p, "USER\r\n" );
106 #endif
107
108 if ( p->login_delay != -1 )
109 pop_write_fmt ( p, "LOGIN-DELAY %d\r\n", p->login_delay );
110 if ( p->expire == -1 )
111 POP_WRITE_LIT ( p, "EXPIRE NEVER\r\n" );
112 else
113 pop_write_fmt ( p, "EXPIRE %d\r\n", p->expire );
114
115 POP_WRITE_LIT ( p, "UIDL\r\n" );
116 POP_WRITE_LIT ( p, "RESP-CODES\r\n" );
117 POP_WRITE_LIT ( p, "AUTH-RESP-CODE\r\n" );
118
119 POP_WRITE_LIT ( p, "X-MANGLE\r\n" );
120 POP_WRITE_LIT ( p, "X-MACRO\r\n" );
121
122 POP_WRITE_LIT ( p, "X-LOCALTIME " );
123 pop_write_line ( p, get_time() );
124
125 if ( p->tls_support == QPOP_TLS_STLS )
126 POP_WRITE_LIT ( p, "STLS\r\n" );
127
128 if ( p->bShy == FALSE || p->CurrentState == trans ) {
129 pop_write_fmt ( p,
130 "IMPLEMENTATION %s%.*s%s-version-%s\r\n",
131 QPOP_NAME,
132 (strlen(IMPLEMENTSFX)>0 ? 1 : 0), "-",
133 IMPLEMENTSFX, VERSION );
134 }
135
136 pop_write_line ( p, "." );
137
138 pop_write_flush ( p );
139 return ( POP_SUCCESS );
140 }
141
142
143 MDEFRecordType mdrArr [ MAX_MDEF_INDEX ];
144 int last_index = -1;
145
146
147 int
pop_mdef(POP * p)148 pop_mdef ( POP *p )
149 {
150 int len = 0;
151 int current_index = 0;
152 char *char_ptr = NULL;
153 char *pt = NULL;
154 MDEFRecordType local_element;
155
156
157 pop_lower ( p->pop_parm[1] );
158 len = p->pop_parmlen[1];
159 if ( len > MAX_MDEF_LENGTH )
160 return pop_msg ( p, POP_FAILURE, HERE, "MDEF too long" );
161
162 char_ptr = strdup ( p->pop_parm[1] );
163 if ( char_ptr == NULL )
164 return pop_msg ( p, POP_FAILURE, HERE,
165 "[SYS/TEMP] internal error" );
166
167 pt = strchr ( char_ptr,'(' );
168 if ( !pt )
169 {
170 free ( char_ptr );
171 return pop_msg ( p, POP_FAILURE, HERE,
172 "Syntax error: \"(\" expected" );
173 }
174
175 *pt = '\0';
176 local_element.mdef_macro = char_ptr;
177 char_ptr = pt + 1;
178 pt = strrchr ( char_ptr,')' );
179 if ( !pt )
180 {
181 free ( local_element.mdef_macro );
182 return pop_msg ( p, POP_FAILURE, HERE,
183 "Syntax error: \")\" expected" );
184 }
185
186 *pt = '\0';
187 local_element.mdef_value = char_ptr;
188
189 for ( current_index = 0;
190 current_index <= last_index;
191 current_index++ )
192 if ( strcmp ( mdrArr[current_index].mdef_macro,
193 local_element.mdef_macro ) == 0 )
194 {
195 if ( strcmp ( mdrArr[current_index].mdef_value,
196 local_element.mdef_value ) == 0 )
197 {
198 DEBUG_LOG1 ( p, "macro \"%s\" identical to prior version",
199 local_element.mdef_macro );
200 free ( local_element.mdef_macro ); /* From strdup */
201 }
202 else
203 {
204 DEBUG_LOG3 ( p, "macro \"%s\" redefined from \"%s\" "
205 "to \"%s\"",
206 local_element.mdef_macro,
207 mdrArr[current_index].mdef_value,
208 local_element.mdef_value );
209 free ( mdrArr [ current_index ].mdef_macro );
210 mdrArr [ current_index ].mdef_macro = local_element.mdef_macro;
211 mdrArr [ current_index ].mdef_value = local_element.mdef_value;
212 }
213 return pop_msg ( p, POP_SUCCESS, HERE,
214 "Macro \"%s\" accepted",
215 mdrArr[current_index].mdef_macro );
216 break;
217 } /* found macro with same name */
218
219 if ( current_index >= MAX_MDEF_INDEX )
220 {
221 free ( local_element.mdef_macro ); /* From strdup */
222 return pop_msg ( p, POP_FAILURE, HERE,
223 "Server only takes a maximum of %d MDEFs",
224 MAX_MDEF_INDEX);
225 }
226
227 if ( current_index > last_index )
228 last_index = current_index;
229
230 mdrArr [ current_index ].mdef_macro = local_element.mdef_macro;
231 /* Redundant */
232 mdrArr [ current_index ].mdef_value = local_element.mdef_value;
233 DEBUG_LOG2 ( p, "macro \"%s\" defined as \"%s\"",
234 local_element.mdef_macro,
235 local_element.mdef_value );
236 return ( pop_msg ( p,POP_SUCCESS, HERE, "Macro \"%s\" accepted",
237 local_element.mdef_macro ) );
238 }
239
240
241
242
243 /*
244 * Initiate a TLS handshake
245 */
246
247 int
pop_stls(POP * p)248 pop_stls ( POP *p )
249 {
250 if ( p->tls_support != QPOP_TLS_STLS )
251 {
252 pop_msg ( p, POP_FAILURE, HERE, "Command not enabled" );
253 return POP_SUCCESS; /* "success" so the error isn't fatal */
254 }
255 else if ( p->tls_started )
256 {
257 pop_msg ( p, POP_FAILURE, HERE, "TLS in progress" );
258 return POP_SUCCESS; /* "success" so the error isn't fatal */
259 }
260 else
261 pop_msg ( p, POP_SUCCESS, HERE, "STLS" );
262
263 if ( pop_tls_handshake ( p->tls_context ) == 0 )
264 p->tls_started = TRUE;
265
266 /*
267 * If TLS fails we just go on. RFC 2595 seems a bit ambiguous
268 * about this. Also we don't redisplay the banner with the APOP
269 * cookie. This doesn't take advantage of a little extra security
270 * we could get for APOP by having the cookie integrity checked.
271 *
272 * Note that if the handshake timed out we abort, just as for any
273 * other inactivity timeout.
274 */
275
276 DEBUG_LOG1 ( p, "pop_stls returning %d",
277 poptimeout ? POP_FAILURE : POP_SUCCESS );
278 return ( poptimeout ? POP_FAILURE : POP_SUCCESS );
279 }
280