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) || (defined __CYGWIN__ && defined WINSOCK_SUPPORT)
32 #include <winsock2.h>
33 #else
34 #include <unistd.h>
35 #include <sys/socket.h>
36 #include <netinet/in.h>
37 #include <arpa/inet.h>
38 #include <netdb.h>
39 #endif
40 
41 #include <stdio.h>
42 #include <stdlib.h>
43 #define __USE_GNU  /* avoid warning for strndup */
44 #include <string.h>
45 #include <fcntl.h>
46 #include <sys/stat.h>
47 
48 #include "wzd_structs.h"
49 #include "wzd_log.h"
50 #include "wzd_misc.h"
51 
52 #endif /* WZD_USE_PCH */
53 
54 #ifdef HAVE_EXECINFO_H
55 # include <execinfo.h>
56 #endif
57 
58 /* uncomment to trace ALL fd registration operations */
59 /*#define WZD_DBG_FD*/
60 
61 
62 #define FD_SIG 0xbf07a4fbUL
63 #define WZD_MAX_FD 1024
64 
65 #ifdef DEBUG
66 struct wzd_fd {
67   unsigned long sig;
68   int fd;
69   char file[256];
70   unsigned int line;
71   char function[256];
72   char desc[256];
73 };
74 
75 static struct wzd_fd _wzd_fd_table[WZD_MAX_FD];
76 
77 static void fd_init(void);
78 
79 #endif
80 
81 int fd_register(int fd, const char *desc, const char *file, unsigned int line, const char *function);
82 int fd_unregister(int fd, const char *desc, const char *file, unsigned int line, const char *function);
83 void fd_dump(void);
84 
85 size_t wzd_strnlen (const char *s, size_t n);
86 
87 /** init all debug functions */
wzd_debug_init(void)88 void wzd_debug_init(void)
89 {
90 #ifdef DEBUG
91   fd_init();
92 #endif
93 }
94 
95 /** end all debug functions */
wzd_debug_fini(void)96 void wzd_debug_fini(void)
97 {
98 #ifdef DEBUG
99   fd_dump();
100 #endif
101 }
102 
103 /** Check if fd is a valid file descriptor */
fd_is_valid(int fd)104 int fd_is_valid(int fd)
105 {
106   /* cygwin does NOT accept testing winsock fd's */
107 #if defined(_MSC_VER) || (defined(__CYGWIN__) && defined(WINSOCK_SUPPORT))
108   return 1;
109 #else
110   static struct statbuf s;
111 
112   if (fs_fstat(fd,&s)<0) return 0;
113   return 1;
114 #endif
115 }
116 
117 /* Memory allocation */
wzd_malloc(size_t size)118 /*@null@*/ void * wzd_malloc(size_t size)
119 {
120   return (void*)malloc(size);
121 }
122 
123 /* Memory reallocation */
wzd_realloc(void * ptr,size_t size)124 void * wzd_realloc(void * ptr, size_t size)
125 {
126   return (void*)realloc(ptr, size);
127 }
128 
129 /** \brief Copy memory area. The memory areas may overlap. */
wzd_memmove(void * dst,const void * src,size_t size)130 void * wzd_memmove(void * dst, const void * src, size_t size)
131 {
132   return memmove(dst,src,size);
133 }
134 
135 /** \brief Free memory allocated by wzd_malloc */
wzd_free(void * ptr)136 void wzd_free(void *ptr)
137 {
138   free(ptr);
139 }
140 
141 /** \brief Copy with allocation */
wzd_strdup(const char * s)142 char * wzd_strdup(const char *s)
143 {
144   return strdup(s);
145 }
146 
147 /** \brief Copy with allocation, at most \a n bytes */
wzd_strndup(const char * s,size_t n)148 char * wzd_strndup(const char *s, size_t n)
149 {
150 #ifdef HAVE_STRNDUP
151   return strndup(s,n);
152 #else
153   size_t len = wzd_strnlen(s, n);
154   char * new = wzd_malloc (len + 1);
155 
156   new[len] = '\0';
157 
158   return memcpy(new, s, len);
159 #endif
160 }
161 
162 /** same as strncpy, but write only one zero at end of string */
wzd_strncpy(char * dst,const char * src,size_t n)163 char * wzd_strncpy(char *dst, const char *src, size_t n)
164 {
165   if (n != 0)
166   {
167     register char *d = dst;
168     register const char *s = src;
169 
170     do {
171       if ( (*d++ = *s++) == 0 ) break;
172     } while (--n != 0);
173   }
174   return dst;
175 }
176 
177 /** Find the length of \a s , but scan at most \a n characters. */
wzd_strnlen(const char * s,size_t n)178 size_t wzd_strnlen (const char *s, size_t n)
179 {
180   const char *end = memchr (s, '\0', n);
181   return end ? (size_t)(end - s) : n;
182 }
183 
184 #ifdef DEBUG
185 /** Initializes fd debug table */
fd_init(void)186 static void fd_init(void)
187 {
188   unsigned int i;
189   for (i=0; i<WZD_MAX_FD; i++) {
190     _wzd_fd_table[i].sig = FD_SIG;
191     _wzd_fd_table[i].fd = -1;
192   }
193 }
194 #endif /* DEBUG */
195 
fd_register(int fd,const char * desc,const char * file,unsigned int line,const char * function)196 int fd_register(int fd, const char *desc, const char *file, unsigned int line, const char *function)
197 {
198 #ifdef DEBUG
199   if (fd < 0) return 1;
200   if (fd >= WZD_MAX_FD) return 2;
201 
202   /* fd already registered ? */
203   if (_wzd_fd_table[fd].fd != -1) {
204     out_err(LEVEL_HIGH,"A file descriptor is already present at index %d\n",fd);
205     out_err(LEVEL_HIGH,"current fd: %d [%s]\n\t%s:%d (%s)\n",
206         _wzd_fd_table[fd].fd,
207         _wzd_fd_table[fd].desc,
208         _wzd_fd_table[fd].file,
209         _wzd_fd_table[fd].line,
210         _wzd_fd_table[fd].function);
211     out_err(LEVEL_HIGH,"offending fd: %d [%s]\n\t%s:%d (%s)\n",
212         fd,
213         desc,
214         file,
215         line,
216         function);
217     return 3;
218   }
219 
220   _wzd_fd_table[fd].fd = fd;
221   strncpy(_wzd_fd_table[fd].desc,desc,sizeof(_wzd_fd_table[fd].desc));
222   strncpy(_wzd_fd_table[fd].file,file,sizeof(_wzd_fd_table[fd].file));
223   _wzd_fd_table[fd].line = line;
224   strncpy(_wzd_fd_table[fd].function,function,sizeof(_wzd_fd_table[fd].function));
225 #ifdef WZD_DBG_FD
226   out_err(LEVEL_HIGH,"added fd: %d [%s]\n\t%s:%d (%s)\n",
227       fd,
228       desc,
229       file,
230       line,
231       function);
232 #endif
233 
234 #endif
235   return 0;
236 }
237 
fd_unregister(int fd,const char * desc,const char * file,unsigned int line,const char * function)238 int fd_unregister(int fd, const char *desc, const char *file, unsigned int line, const char *function)
239 {
240 #ifdef DEBUG
241   if (fd < 0) return 1;
242   if (fd >= WZD_MAX_FD) return 2;
243 
244   /* fd already registered ? */
245   if (_wzd_fd_table[fd].fd == -1) {
246     out_err(LEVEL_HIGH,"No file descriptor at index %d\n",fd);
247     out_err(LEVEL_HIGH,"offending fd: %d [%s]\n\t%s:%d (%s)\n",
248         fd,
249         desc,
250         file,
251         line,
252         function);
253     return 3;
254   }
255 
256   _wzd_fd_table[fd].fd = -1;
257   memset(_wzd_fd_table[fd].desc,0,sizeof(_wzd_fd_table[fd].desc));
258   memset(_wzd_fd_table[fd].file,0,sizeof(_wzd_fd_table[fd].file));
259   _wzd_fd_table[fd].line = 0;
260   memset(_wzd_fd_table[fd].function,0,sizeof(_wzd_fd_table[fd].function));
261 #ifdef WZD_DBG_FD
262   out_err(LEVEL_HIGH,"removed fd: %d [%s]\n\t%s:%d (%s)\n",
263       fd,
264       desc,
265       file,
266       line,
267       function);
268 #endif
269 
270 #endif
271   return 0;
272 }
273 
fd_dump(void)274 void fd_dump(void)
275 {
276 #ifdef DEBUG
277   unsigned int i;
278   out_err(LEVEL_HIGH,"starting fd list dump:\n");
279   for (i=0; i<WZD_MAX_FD; i++) {
280     if (_wzd_fd_table[i].fd == -1) continue;
281 
282     out_err(LEVEL_HIGH,"fd: %d [%s]\n\t%s:%d (%s)\n",
283         _wzd_fd_table[i].fd,
284         _wzd_fd_table[i].desc,
285         _wzd_fd_table[i].file,
286         _wzd_fd_table[i].line,
287         _wzd_fd_table[i].function);
288   }
289   out_err(LEVEL_HIGH,"end of fd list dump:\n");
290 #endif
291 }
292 
dump_backtrace(void)293 void dump_backtrace(void)
294 {
295 #ifdef HAVE_BACKTRACE
296   void *bt[25];
297   char **ptr;
298   int i, size;
299 
300   if ((size=backtrace(bt,25))>0) {
301     if ((ptr=backtrace_symbols(bt,25))) {
302       for (i=0; i<size; i++) {
303         if (ptr[i])
304           out_err(LEVEL_HIGH,"frame %d: %s\n",i,ptr[i]);
305       }
306     }
307   }
308 #endif
309 }
310 
311 /** \brief Check current context for corruptions */
check_context(wzd_context_t * context)312 int check_context(wzd_context_t * context)
313 {
314   if (GetMyContext() != context)
315   {
316     out_err(LEVEL_CRITICAL,"CRITICAL GetMyContext does not match context !\n");
317     out_err(LEVEL_CRITICAL,"CRITICAL GetMyContext %p\n",GetMyContext());
318     out_err(LEVEL_CRITICAL,"CRITICAL context      %p\n",context);
319     return 1;
320   }
321   if (!context->magic == CONTEXT_MAGIC)
322   {
323     out_err(LEVEL_CRITICAL,"CRITICAL context->magic is invalid, context may be corrupted\n");
324     return 1;
325   }
326   if (context->controlfd == (fd_t)-1 || !fd_is_valid(context->controlfd)) {
327     out_err(LEVEL_CRITICAL,"Trying to set invalid sockfd (%d) %s:%d\n",
328         context->controlfd,__FILE__,__LINE__);
329     return 1;
330   }
331 
332   return 0;
333 }
334 
335