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