1 /* vi:ai:et:ts=8 sw=2
2  */
3 /*
4  * wzdftpd - a modular and cool ftp server
5  * Copyright (C) 2002-2004  Pierre Chifflier
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20  *
21  * As a special exemption, Pierre Chifflier
22  * and other respective copyright holders give permission to link this program
23  * with OpenSSL, and distribute the resulting executable, without including
24  * the source code for OpenSSL in the source distribution.
25  */
26 
27 #include "wzd_all.h"
28 
29 #ifndef WZD_USE_PCH
30 
31 #if defined(WIN32)
32 #include <winsock2.h>
33 #else
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <netinet/in.h>
37 #include <arpa/inet.h>
38 #endif
39 
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <time.h>
44 #include <fcntl.h> /* O_RDONLY */
45 
46 #include "wzd_structs.h"
47 #include "wzd_messages.h"
48 #include "wzd_misc.h"
49 #include "wzd_log.h"
50 
51 #include "wzd_cache.h"
52 #include "wzd_section.h"
53 #include "wzd_string.h"
54 #include "wzd_utf8.h"
55 #include "wzd_vfs.h"
56 
57 #include "wzd_debug.h"
58 
59 #endif /* WZD_USE_PCH */
60 
61 #define DEFAULT_MSG	"No message for this code"
62 
63 #define BUFFER_LEN	4096
64 
65 char *msg_tab[HARD_MSG_LIMIT];
66 
init_default_messages(void)67 void init_default_messages(void)
68 {
69   memset(msg_tab,0,HARD_MSG_LIMIT*sizeof(char *));
70 
71   msg_tab[150] = strdup("Status OK, about to open data connection.");
72 
73   msg_tab[200] = strdup("%s"); /* Command okay */
74   msg_tab[211] = strdup("%s");
75   msg_tab[213] = strdup("%s"); /* mdtm */
76   msg_tab[214] = strdup("The following commands can be used:\n"
77       "SITE TYPE PORT PASV EPRT EPSV ABOR PWD ALLO FEAT NOOP\n"
78       "SYST RNFR RNTO CWD LIST STAT MKD  RMD RETR STOR REST\n"
79       "MDTM SIZE DELE PRET XCRC XMD5 OPTS HELP QUIT\n"
80       "Help OK"); /* TODO sort */
81   msg_tab[215] = strdup("UNIX Type: L8");
82   msg_tab[220] = strdup("wzd server ready.");
83   msg_tab[221] = strdup("Cya !");
84   msg_tab[226] = strdup("Closing data connection.\r\n%msg\r\n- [Section: %sectionname] - [Free: %spacefree] - [Dl: %usertotal_dl2] - [Ul: %usertotal_ul2] -");
85   msg_tab[227] = strdup("Entering Passive Mode (%hhu,%hhu,%hhu,%hhu,%hu,%hu)"); /* DON'T TOUCH ! */
86   msg_tab[230] = strdup("User logged in, proceed.");
87   msg_tab[234] = strdup("AUTH command OK. Initializing %s mode"); /* SSL init */
88   msg_tab[235] = strdup("%s%s");
89   msg_tab[250] = strdup("%s%s");
90 /*  msg_tab[257] = strdup("\"%s\" %s");*/
91   msg_tab[258] = strdup("\"%s\" %s");
92 
93   msg_tab[331] = strdup("User %s okay, need password.");
94   msg_tab[334] = strdup("%s%s");
95   msg_tab[350] = strdup("%s"); /* "Restarting at %ld. Send STORE or RETRIEVE.", or "OK, send RNTO" */
96 
97   msg_tab[421] = strdup("%s"); /* Service not available, closing control connection. */
98   msg_tab[425] = strdup("Can't open data connection.");
99   msg_tab[426] = strdup("Error occured, data connection closed.");
100   msg_tab[431] = strdup("%s"); /* Unable to accept security mechanism. */
101   msg_tab[451] = strdup("Transmission error occured.");
102   msg_tab[491] = strdup("Data connection already active.");
103 
104   msg_tab[501] = strdup("%s");
105   msg_tab[502] = strdup("Command not implemented.");
106   msg_tab[503] = strdup("%s");
107   msg_tab[530] = strdup("%s"); /* Not logged in." */
108   msg_tab[535] = strdup("%s"); /* Not logged in." */
109   msg_tab[550] = strdup("%s: %s");
110   msg_tab[553] = strdup("Requested action not taken: %s");
111 }
112 
free_messages(void)113 void free_messages(void)
114 {
115   int i;
116 
117   for (i=0; i<HARD_MSG_LIMIT; i++)
118   {
119     if (msg_tab[i]) {
120       free(msg_tab[i]);
121       msg_tab[i]=0;
122     }
123   }
124 }
125 
getMessage(int code,int * must_free)126 const char * getMessage(int code, int *must_free)
127 {
128   const char * ptr;
129   char * file_buffer;
130   unsigned long filesize, size;
131   u64_t sz64;
132 
133   if (code < 0 || code > HARD_MSG_LIMIT)
134     return DEFAULT_MSG;
135   *must_free = 0;
136   ptr = msg_tab[code];
137   if (!ptr || strlen(ptr)==0) return DEFAULT_MSG;
138   if (ptr[0]=='+') { /* returns file content */
139     wzd_cache_t * fp;
140     fp = wzd_cache_open(ptr+1,O_RDONLY,0644);
141     if (!fp) return DEFAULT_MSG;
142     sz64 = wzd_cache_getsize(fp);
143     if (sz64 > INT_MAX) {
144       out_log(LEVEL_HIGH,"%s:%d couldn't allocate " PRIu64 " bytes for message %d\n",__FILE__,__LINE__,code);
145       wzd_cache_close(fp);
146       *must_free = 0;
147       return NULL;
148     }
149     filesize = (unsigned int) sz64;
150     file_buffer = wzd_malloc(filesize+1);
151     if ( (size=wzd_cache_read(fp,file_buffer,filesize))!=filesize ) {
152       wzd_free(file_buffer);
153       wzd_cache_close(fp);
154       return DEFAULT_MSG;
155     }
156     file_buffer[filesize]='\0';
157     wzd_cache_close(fp);
158     *must_free = 1;
159     return file_buffer;
160   }
161   return ptr;
162 }
163 
setMessage(const char * newMessage,int code)164 void setMessage(const char *newMessage, int code)
165 {
166   if (code < 0 || code > HARD_MSG_LIMIT) return;
167   if (msg_tab[code]) free(msg_tab[code]);
168   msg_tab[code] = (char*)newMessage;
169 }
170 
171 /*************** send_message ************************/
172 
send_message(int code,wzd_context_t * context)173 int send_message(int code, wzd_context_t * context)
174 {
175   wzd_string_t * str;
176   int ret;
177 
178   str = format_message(context,code);
179 #ifdef DEBUG
180   out_err(LEVEL_FLOOD,"<thread %ld> -> %s",(unsigned long)context->pid_child,str_tochar(str));
181 #endif
182   ret = (context->write_fct)(context->controlfd,str_tochar(str),str_length(str),0,HARD_XFER_TIMEOUT,context);
183 
184   str_deallocate(str);
185 
186   return ret;
187 }
188 
189 /*************** send_message_with_args **************/
190 
send_message_with_args(int code,wzd_context_t * context,...)191 int send_message_with_args(int code, wzd_context_t * context, ...)
192 {
193   va_list argptr;
194   wzd_string_t * str;
195   int ret;
196 
197   va_start(argptr,context); /* note: ansi compatible version of va_start */
198   str = v_format_message(context,code,argptr);
199 #ifdef HAVE_UTF8
200   if (context->connection_flags & CONNECTION_UTF8)
201   {
202     if (!str_is_valid_utf8(str))
203       str_local_to_utf8(str,local_charset());
204   }
205 #endif
206   va_end (argptr);
207 #ifdef DEBUG
208   out_err(LEVEL_FLOOD,"<thread %ld> ->ML %s",(unsigned long)context->pid_child,str_tochar(str));
209 #endif
210   ret = (context->write_fct)(context->controlfd,str_tochar(str),str_length(str),0,HARD_XFER_TIMEOUT,context);
211 
212   str_deallocate(str);
213   return 0;
214 }
215 
216 /*************** send_message_raw ********************/
217 
send_message_raw(const char * msg,wzd_context_t * context)218 int send_message_raw(const char *msg, wzd_context_t * context)
219 {
220   int ret;
221 
222   if (!msg || strlen(msg)==0) return 0;
223 
224 #ifdef DEBUG
225 if (msg[strlen(msg)-1]!='\n')
226   out_err(LEVEL_FLOOD,"<thread %ld> -> %s\n",(unsigned long)context->pid_child,msg);
227 else
228   out_err(LEVEL_FLOOD,"<thread %ld> -> %s",(unsigned long)context->pid_child,msg);
229 #endif
230   ret = (context->write_fct)(context->controlfd,msg,strlen(msg),0,HARD_XFER_TIMEOUT,context);
231 
232   return ret;
233 }
234 
235 
send_message_formatted(int code,wzd_context_t * context,const char * format,...)236 int send_message_formatted(int code, wzd_context_t * context, const char * format, ...)
237 {
238   va_list argptr;
239   wzd_string_t * str;
240   wzd_string_t ** str_list, ** it;
241   int ret;
242 
243   if (!format || code<0) return -1;
244 
245   va_start(argptr, format);
246 
247   str = str_allocate();
248   ret = str_vsprintf(str, format, argptr);
249 
250   if (ret < 0) return -1;
251 
252   /* convert str to unicode if connection is in UTF-8 mode */
253 #ifdef HAVE_UTF8
254   if (context->connection_flags & CONNECTION_UTF8)
255   {
256     if (!str_is_valid_utf8(str))
257       str_local_to_utf8(str,local_charset());
258   }
259 #endif
260 
261   if (ret < 0) return -1;
262 
263   /* split lines and send formatted message to client */
264   str_list = str_split(str, "\r\n", 0);
265   str_deallocate(str);
266 
267   it = str_list;
268 
269   if (*(it+1) == NULL) { /* one line */
270     out_log(LEVEL_FLOOD, "send_message_formatted UL -> [%d %s]\n", code, str_tochar(*it));
271     str_prepend_printf(*it,"%.3d ",code);
272     str_append(*it,"\r\n");
273     ret = (context->write_fct)(context->controlfd,str_tochar(*it),str_length(*it),0,HARD_XFER_TIMEOUT,context);
274   } else { /* multi-line */
275     out_log(LEVEL_FLOOD, "send_message_formatted ML -> [%d-%s]\n", code, str_tochar(*it));
276     it++;
277     for (; *it; it++) {
278       if (*(it+1) == NULL) { /* last line */
279         out_log(LEVEL_FLOOD, "send_message_formatted ML -> [%d %s]\n", code, str_tochar(*it));
280         str_prepend_printf(*it,"%.3d ",code);
281         str_append(*it,"\r\n");
282         ret = (context->write_fct)(context->controlfd,str_tochar(*it),str_length(*it),0,HARD_XFER_TIMEOUT,context);
283       } else {
284         out_log(LEVEL_FLOOD, "send_message_formatted ML -> [ %s]\n", str_tochar(*it));
285         str_prepend_printf(*it,"%.3d-",code);
286         str_append(*it,"\r\n");
287         ret = (context->write_fct)(context->controlfd,str_tochar(*it),str_length(*it),0,HARD_XFER_TIMEOUT,context);
288       }
289     }
290   }
291 
292 
293   va_end(argptr);
294   str_deallocate_array(str_list);
295   return 0;
296 }
297 
298 /** \brief Allocate memory for a struct wzd_reply_t */
reply_alloc(void)299 struct wzd_reply_t * reply_alloc(void)
300 {
301   struct wzd_reply_t * reply;
302 
303   reply = wzd_malloc(sizeof(struct wzd_reply_t));
304   reply->code = 0;
305   reply->_reply = NULL;
306   reply->sent = 0;
307 
308   return reply;
309 }
310 
311 /** \brief Free memory used by struct wzd_reply_t */
reply_free(struct wzd_reply_t * reply)312 void reply_free(struct wzd_reply_t * reply)
313 {
314   WZD_ASSERT_VOID(reply != NULL);
315   if (reply == NULL) return;
316 
317   wzd_free(reply->_reply);
318   wzd_free(reply);
319 }
320 
321 /** \brief Clear the stored reply */
reply_clear(wzd_context_t * context)322 void reply_clear(wzd_context_t * context)
323 {
324   WZD_ASSERT_VOID(context != NULL);
325   WZD_ASSERT_VOID(context->reply != NULL);
326 
327   if (context == NULL) return;
328   if (context->reply == NULL) return;
329 
330   context->reply->code = 0;
331   /* re-use allocated string if any */
332   if (context->reply->_reply != NULL)
333     str_erase(context->reply->_reply,0,-1);
334   else
335     context->reply->_reply = str_allocate();
336   context->reply->sent = 0;
337 }
338 
339 /** \brief Set the current reply code */
reply_set_code(wzd_context_t * context,int code)340 void reply_set_code(wzd_context_t * context, int code)
341 {
342   WZD_ASSERT_VOID(context != NULL);
343   WZD_ASSERT_VOID(context->reply != NULL);
344 
345   context->reply->code = code;
346 }
347 
348 /** \brief Get the current reply code */
reply_get_code(wzd_context_t * context)349 int reply_get_code(wzd_context_t * context)
350 {
351   WZD_ASSERT(context != NULL);
352   WZD_ASSERT(context->reply != NULL);
353 
354   return context->reply->code;
355 }
356 
357 /** \brief Add a message to the stored reply */
reply_push(wzd_context_t * context,const char * s)358 int reply_push(wzd_context_t * context, const char * s)
359 {
360   WZD_ASSERT(context != NULL);
361   WZD_ASSERT(context->reply != NULL);
362   WZD_ASSERT(s != NULL);
363 
364   if (context == NULL ||
365       context->reply == NULL ||
366       s == NULL)
367     return -1;
368 
369   if (context->reply->_reply == NULL) {
370     context->reply->_reply = STR(s);
371   } else {
372     str_append(context->reply->_reply,s);
373   }
374 
375   return 0;
376 }
377 
378 /** \brief Send formatted reply to client.
379  *
380  * \a code must be set
381  */
reply_send(wzd_context_t * context)382 int reply_send(wzd_context_t * context)
383 {
384   int ret;
385 
386   WZD_ASSERT(context != NULL);
387   WZD_ASSERT(context->reply != NULL);
388 
389   if (context == NULL ||
390       context->reply == NULL)
391     return -1;
392 
393   if (context->reply->code <= 0) return -1;
394 
395   if (context->reply->sent != 0) {
396     out_log(LEVEL_NORMAL,"WARNING reply already sent, discarding second (or more) reply\n");
397     return -1;
398   }
399 
400   ret = send_message_formatted(context->reply->code,context,str_tochar(context->reply->_reply));
401 
402   context->reply->sent++;
403 
404   return 0;
405 }
406 
407