1 /* 2 * part of owftpd By Paul H Alfille 3 * The whole is GPLv2 licenced though the ftp code was more liberally licenced when first used. 4 */ 5 6 #ifndef OWFTPD_H 7 #define OWFTPD_H 8 9 #include <config.h> 10 #include "owfs_config.h" 11 #include "ow.h" 12 #include "ow_connection.h" 13 14 #ifdef HAVE_LIMITS_H 15 #include <limits.h> 16 #endif 17 #include <arpa/inet.h> 18 #include <netinet/tcp.h> 19 #include <assert.h> 20 21 /* _x_ must be a pointer to a sockaddr structure */ 22 23 #define SAFAM(_x_) (((struct sockaddr *)(_x_))->sa_family) 24 #define cSAFAM(_x_) (((const struct sockaddr *)(_x_))->sa_family) 25 26 #define SIN4ADDR(_x_) (((struct sockaddr_in *)(_x_))->sin_addr) 27 #define SIN4PORT(_x_) (((struct sockaddr_in *)(_x_))->sin_port) 28 #define SIN6ADDR(_x_) (((struct sockaddr_in6 *)(_x_))->sin6_addr) 29 #define SIN6PORT(_x_) (((struct sockaddr_in6 *)(_x_))->sin6_port) 30 #define cSIN4ADDR(_x_) (((const struct sockaddr_in *)(_x_))->sin_addr) 31 #define cSIN4PORT(_x_) (((const struct sockaddr_in *)(_x_))->sin_port) 32 #define cSIN6ADDR(_x_) (((const struct sockaddr_in6 *)(_x_))->sin6_addr) 33 #define cSIN6PORT(_x_) (((const struct sockaddr_in6 *)(_x_))->sin6_port) 34 35 #ifdef INET6 36 #define SINADDR(_x_) ((SAFAM(_x_)==AF_INET6) ? SIN6ADDR(_x_) : SIN4ADDR(_x_)) 37 #define SINPORT(_x_) ((SAFAM(_x_)==AF_INET6) ? SIN6PORT(_x_) : SIN4PORT(_x_)) 38 #define cSINADDR(_x_) ((cSAFAM(_x_)==AF_INET6) ? cSIN6ADDR(_x_) : cSIN4ADDR(_x_)) 39 #define cSINPORT(_x_) ((cSAFAM(_x_)==AF_INET6) ? cSIN6PORT(_x_) : cSIN4PORT(_x_)) 40 #else 41 #define SINADDR(_x_) SIN4ADDR(_x_) 42 #define SINPORT(_x_) SIN4PORT(_x_) 43 #define cSINADDR(_x_) cSIN4ADDR(_x_) 44 #define cSINPORT(_x_) cSIN4PORT(_x_) 45 #endif 46 47 #ifndef INET_ADDRSTRLEN 48 #define INET_ADDRSTRLEN 16 49 #endif 50 51 #ifndef INET6_ADDRSTRLEN 52 #define INET6_ADDRSTRLEN 46 53 #endif 54 55 #ifdef INET6 56 #define IP6_ADDRSTRLEN INET6_ADDRSTRLEN 57 #define IP4_ADDRSTRLEN INET_ADDRSTRLEN 58 #define IP_ADDRSTRLEN INET6_ADDRSTRLEN 59 #else 60 #define IP_ADDRSTRLEN INET_ADDRSTRLEN 61 #endif 62 63 #if defined(INET6) && defined(HAVE_STRUCT_SOCKADDR_STORAGE) 64 typedef struct sockaddr_storage sockaddr_storage_t; 65 #define SSFAM(_x_) (((sockaddr_storage_t *)(_x_))->ss_family) 66 #define cSSFAM(_x_) (((const sockaddr_storage_t *)(_x_))->ss_family) 67 #else 68 typedef struct sockaddr_in sockaddr_storage_t; 69 #define SSFAM(_x_) (((sockaddr_storage_t *)(_x_))->sin_family) 70 #define cSSFAM(_x_) (((const sockaddr_storage_t *)(_x_))->sin_family) 71 #endif 72 73 #ifdef HAVE_BROKEN_SS_FAMILY 74 #undef SSFAM 75 #undef cSSFAM 76 #define SSFAM(_x_) (((sockaddr_storage_t *)(_x_))->__ss_family) 77 #define cSSFAM(_x_) (((const sockaddr_storage_t *)(_x_))->__ss_family) 78 #endif 79 80 81 /* address to listen on (use NULL to listen on all addresses) */ 82 #define FTP_ADDRESS NULL 83 84 /* default port FTP server listens on (use 0 to listen on default port) */ 85 #define FTP_PORT 0 86 87 /* ranges possible for command-line specified port numbers */ 88 #define MIN_PORT 0 89 #define MAX_PORT 65535 90 91 /* default port FTP server listens on (use 0 to listen on default port) */ 92 #define DEFAULT_PORTNAME "0.0.0.0:21" 93 94 /* bounds on command-line specified number of clients */ 95 #define MIN_NUM_CLIENTS 1 96 #define MAX_NUM_CLIENTS 300 97 98 enum parse_status_e { 99 parse_status_init, // need to test for initial / 100 parse_status_init2, // need to test for virginity (no wildness) 101 parse_status_back, // .. still allowed 102 parse_status_next, // figure out this level 103 parse_status_last, // last level 104 parse_status_tame, // no wildcard at all 105 }; 106 107 enum file_list_e { 108 file_list_list, 109 file_list_nlst, 110 }; 111 112 struct file_parse_s { 113 ASCII buffer[PATH_MAX + 1]; 114 ASCII *rest; 115 enum parse_status_e pse; // state machine 116 enum file_list_e fle; // long or short listing flag 117 FILE_DESCRIPTOR_OR_ERROR out; // file descriptor to send result 118 int ret; // return status 119 int start; 120 }; 121 122 struct cd_parse_s { 123 ASCII buffer[PATH_MAX + 1]; // working copy of current directory 124 ASCII *rest; 125 enum parse_status_e pse; // state machine 126 int ret; // return status 127 int solutions; // is the solution unique? 128 ASCII *dir; 129 }; 130 131 void FileLexParse(struct file_parse_s *fps); 132 void FileLexCD(struct cd_parse_s *cps); 133 134 /* each watched thread gets one of these structures */ 135 struct watched_s { 136 /* thread to monitor */ 137 pthread_t watched_thread; 138 139 /* flag whether in a watchdog list */ 140 int in_list; 141 142 /* time when to cancel thread if no activity */ 143 time_t alarm_time; 144 145 /* for location in doubly-linked list */ 146 struct watched_s *older; 147 struct watched_s *newer; 148 149 /* watchdog that this watched_s is in */ 150 void *watchdog; 151 }; 152 153 /* the watchdog keeps track of all information */ 154 struct watchdog_s { 155 pthread_mutex_t mutex; 156 int inactivity_timeout; 157 158 /* the head and tail of our list */ 159 struct watched_s *oldest; 160 struct watched_s *newest; 161 }; 162 163 int watchdog_init(struct watchdog_s *w, int inactivity_timeout); 164 void watchdog_add_watched(struct watchdog_s *w, struct watched_s *watched); 165 void watchdog_defer_watched(struct watched_s *watched); 166 void watchdog_remove_watched(struct watched_s *watched); 167 168 169 /* size of buffer */ 170 #define BUF_LEN 2048 171 172 /* information on a telnet session */ 173 struct telnet_session_s { 174 FILE_DESCRIPTOR_OR_ERROR in_fd; 175 int in_errno; 176 int in_eof; 177 int in_take; 178 int in_add; 179 char in_buf[BUF_LEN]; 180 int in_buflen; 181 182 int in_status; 183 184 FILE_DESCRIPTOR_OR_ERROR out_fd; 185 int out_errno; 186 int out_eof; 187 int out_take; 188 int out_add; 189 char out_buf[BUF_LEN]; 190 int out_buflen; 191 }; 192 193 #ifdef NDEBUG 194 195 #define daemon_assert(expr) 196 197 #else /* NDEBUG */ 198 199 void daemon_assert_fail(const char *assertion, const char *file, int line, const char *function); 200 201 #ifndef __STRING 202 #define __STRING(x) #x 203 #endif 204 205 #define daemon_assert(expr) \ 206 ((expr) ? 0 : \ 207 (daemon_assert_fail(__STRING(expr), __FILE__, __LINE__, __func__)));\ 208 assert(expr) 209 210 // last assert is to silence static analyzers 211 212 #endif /* NDEBUG */ 213 214 /* data representation types supported */ 215 #define TYPE_ASCII 0 216 #define TYPE_IMAGE 1 217 218 /* file structure types supported */ 219 #define STRU_FILE 0 220 #define STRU_RECORD 1 221 222 /* data path chosen */ 223 #define DATA_PORT 0 224 #define DATA_PASSIVE 1 225 226 /* space required for text representation of address and port, 227 e.g. "192.168.0.1 port 1024" or 228 "2001:3333:DEAD:BEEF:0666:0013:0069:0042 port 65535" */ 229 #define ADDRPORT_STRLEN 58 230 231 /* structure encapsulating an FTP session's information */ 232 struct ftp_session_s { 233 /* flag whether session is active */ 234 int session_active; 235 236 /* incremented for each command */ 237 unsigned long command_number; 238 239 /* options about transfer set by user */ 240 int data_type; 241 int file_structure; 242 243 /* offset to begin sending file from */ 244 off_t file_offset; 245 unsigned long file_offset_command_number; 246 247 /* flag set if client requests ESPV ALL - this prevents subsequent 248 use of PORT, PASV, LPRT, LPSV, or EPRT */ 249 int epsv_all_set; 250 251 /* address of client */ 252 sockaddr_storage_t client_addr; 253 char client_addr_str[ADDRPORT_STRLEN]; 254 255 /* address of server (including IPv4 version) */ 256 sockaddr_storage_t server_addr; 257 struct sockaddr_in server_ipv4_addr; 258 259 /* telnet session to encapsulate control channel logic */ 260 struct telnet_session_s *telnet_session; 261 262 /* current working directory of this connection */ 263 char dir[PATH_MAX + 1]; 264 265 /* data channel information, including type, 266 and client address or server port depending on type */ 267 int data_channel; 268 sockaddr_storage_t data_port; 269 FILE_DESCRIPTOR_OR_ERROR server_fd; 270 271 /* watchdog to handle timeout */ 272 struct watched_s *watched; 273 }; 274 275 int ftp_session_init(struct ftp_session_s *f, 276 const sockaddr_storage_t * client_addr, const sockaddr_storage_t * server_addr, struct telnet_session_s *t, const char *dir); 277 void ftp_session_drop(struct ftp_session_s *f, const char *reason); 278 void ftp_session_run(struct ftp_session_s *f, struct watched_s *watched); 279 void ftp_session_destroy(struct ftp_session_s *f); 280 281 struct ftp_listener_s { 282 283 /* file descriptor incoming connections arrive on */ 284 FILE_DESCRIPTOR_OR_ERROR file_descriptor; 285 286 /* maximum number of connections */ 287 int max_connections; 288 289 /* current number of connections */ 290 int num_connections; 291 292 /* timeout (in seconds) for connections */ 293 int inactivity_timeout; 294 295 /* watchdog monitoring this listener's connections */ 296 struct watchdog_s watchdog; 297 298 /* mutext to lock changes to this structure */ 299 pthread_mutex_t mutex; 300 301 /* starting directory */ 302 char dir[3]; // only root directory for OWFS 303 304 /* boolean defining whether listener is running or not */ 305 int listener_running; 306 307 /* thread identifier for listener */ 308 pthread_t listener_thread; 309 310 /* end of pipe to wake up listening thread with */ 311 /* end of pipe listening thread waits on */ 312 FILE_DESCRIPTOR_OR_ERROR shutdown_request_fd[2]; 313 314 /* condition to signal thread requesting shutdown */ 315 pthread_cond_t shutdown_cond; 316 317 }; 318 319 int ftp_listener_init(struct ftp_listener_s *f); 320 int ftp_listener_start(struct ftp_listener_s *f); 321 void ftp_listener_stop(struct ftp_listener_s *f); 322 323 /* special macro for handling EPSV ALL requests */ 324 #define EPSV_ALL (-1) 325 326 /* maximum possible number of arguments */ 327 #define MAX_ARG 2 328 329 /* maximum string length */ 330 #define MAX_STRING_LEN PATH_MAX 331 332 struct ftp_command_s { 333 char command[5]; 334 int num_arg; 335 union { 336 char string[MAX_STRING_LEN + 1]; 337 sockaddr_storage_t host_port; 338 int num; 339 off_t offset; 340 } arg[MAX_ARG]; 341 }; 342 343 /* methods */ 344 int ftp_command_parse(const char *input, struct ftp_command_s *cmd); 345 346 /* functions */ 347 void telnet_session_init(struct telnet_session_s *t, FILE_DESCRIPTOR_OR_ERROR in, FILE_DESCRIPTOR_OR_ERROR out); 348 int telnet_session_print(struct telnet_session_s *t, const char *s); 349 int telnet_session_println(struct telnet_session_s *t, const char *s); 350 int telnet_session_readln(struct telnet_session_s *t, char *buf, int buflen); 351 void telnet_session_destroy(struct telnet_session_s *t); 352 353 #endif /* OWFTPD_H */ 354