DocumentationGenerated on Thu Aug 31 00:02:27 2006 |
||
babyftpd.cppGo to the documentation of this file.00001 00002 // $Id: babyftpd.cpp,v 1.138 2005/08/23 19:34:02 klas Exp $ 00003 // 00004 // Usage: main function, commandline parsing and function that 00005 // on the main socket. 00006 // 00007 // A part of babyftpd, licensed under the GNU GPL, see the file 00008 // LICENSE for complete information. 00010 00011 #define BABYFTPD_CPP 00012 #define NETINCLS 00013 #define BABY_IO 00014 #define BABY_CORE 00015 #include "babyftpd.h" 00016 00017 int main(int argc, char **argv) 00018 { 00019 pid_t pid; 00020 00021 logging = new class Log; 00022 config = new class Configuration; 00023 config->parse_command_line(argc, argv); 00024 // we send the start message for logging here so that starts our log. 00025 logging->log_this(3, TYPE_INFO, config->general.welcome_msg + " started."); 00026 // the config file variable exists in the Configuration class :p 00027 if(config->parse_config_file() == false) 00028 cout << "Failed to open the config file (" << config->conf_file << 00029 "), check if it exists + permissions." << endl; 00030 // if the conffile changes variables from commandline we reset them. 00031 config->parse_command_line(argc, argv); 00032 00033 if(config->general.no_daemon == false) 00034 pid = fork(); 00035 else 00036 pid = 0; 00037 00038 switch(pid) 00039 { 00040 case -1: 00041 // error 00042 exit(1); 00043 break; 00044 00045 case 0: 00046 // child 00047 int new_pid; 00048 setsid(); 00049 if(config->general.no_daemon == false) 00050 new_pid = fork(); 00051 else 00052 new_pid = 0; 00053 00054 switch(new_pid) 00055 { 00056 case -1: 00057 exit(0); 00058 break; 00059 00060 case 0: 00061 break; 00062 00063 default: 00064 _exit(0); 00065 } 00066 00067 chdir("/"); 00068 umask(0); 00069 00070 close(STDIN_FILENO); 00071 close(STDOUT_FILENO); 00072 close(STDERR_FILENO); 00073 00074 if(!config->general.pid_file.empty()) 00075 { 00076 ofstream pidstream; 00077 pidstream.open(config->general.pid_file.c_str(), ofstream::out); 00078 if(!pidstream) 00079 logging->log_this(2, TYPE_INFO, "Failed to open pid_file " + 00080 config->general.pid_file + " for writing. continuing."); 00081 else 00082 { 00083 pidstream << getpid(); 00084 pidstream.close(); 00085 } 00086 } 00087 00088 // we can't spawn the logging thread until after we are daemonized 00089 pthread_create(&logging_thread, NULL, log_wrapper, NULL); 00090 00091 pthread_key_create(&my_user, kill_user); 00092 pthread_key_create(&my_data, kill_data); 00093 00094 pthread_rwlock_init(&user_list_lock, NULL); 00095 sem_init(&cleanup_list_lock, 0, 1); 00096 sem_init(&comm.pam_lock, 0, 1); 00097 00098 signal(SIGTERM, sig_handler); 00099 signal(SIGINT, sig_handler); 00100 signal(SIGHUP, sig_handler); 00101 signal(SIGPIPE, sig_handler); 00102 00103 main_thread = pthread_self(); 00104 00105 #ifdef USE_TLS 00106 #ifndef OLD_GCRYPT 00107 gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); 00108 #endif // OLD_GCRYPT 00109 int ret; 00110 pthread_rwlock_init(&cache_lock, NULL); 00111 gnutls_global_init(); 00112 00113 gnutls_certificate_allocate_credentials(&x509_cred); 00114 ret = gnutls_certificate_set_x509_trust_file(x509_cred, 00115 config->general.tls_ca.c_str(), GNUTLS_X509_FMT_PEM); 00116 if(ret < 0) 00117 logging->log_this(2, TYPE_INFO, gnutls_strerror(ret)); 00118 00119 ret = gnutls_certificate_set_x509_crl_file(x509_cred, 00120 config->general.tls_crl.c_str(), GNUTLS_X509_FMT_PEM); 00121 if(ret < 0) 00122 logging->log_this(2, TYPE_INFO, gnutls_strerror(ret)); 00123 00124 ret = gnutls_certificate_set_x509_key_file(x509_cred, 00125 config->general.tls_cert.c_str(), config->general.tls_key.c_str(), 00126 GNUTLS_X509_FMT_PEM); 00127 if(ret < 0) 00128 logging->log_this(2, TYPE_INFO, gnutls_strerror(ret)); 00129 00130 gnutls_dh_params_init(&dh_params); 00131 00132 gnutls_dh_params_generate2(dh_params, 1024); 00133 00134 gnutls_certificate_set_dh_params(x509_cred, dh_params); 00135 dh_time = time(NULL); 00136 00137 #endif // USE_TLS 00138 handler = new Handler; 00139 listener(); 00140 break; 00141 00142 default: 00143 // parent 00144 _exit(0); 00145 break; 00146 } 00147 } 00148 00149 bool listener(void) 00150 { 00151 struct sockaddr_in address; 00152 struct timeval tv = {config->general.lifebeat_tick,0}; 00153 00154 int first_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 00155 address.sin_family = AF_INET; 00156 address.sin_addr.s_addr = INADDR_ANY; 00157 address.sin_port = htons(config->general.port); 00158 if(bind(first_socket, reinterpret_cast<struct sockaddr*>(&address), 00159 sizeof(address)) < 0) 00160 { 00161 logging->log_this(2, TYPE_INFO, "Port " + 00162 util.itos(config->general.port) + " already in use."); 00163 exit_baby(1, EXIT_FULL); 00164 } 00165 seteuid(config->general.user); 00166 setgid(config->general.group); 00167 listen(first_socket, LISTEN_LIMIT); 00168 while(true) 00169 { 00170 pthread_t thread_tmp; 00171 socklen_t socketlen = sizeof(struct sockaddr_in); 00172 fd_set sock_set; 00173 time_t before = time(NULL) - (config->general.lifebeat_tick - tv.tv_sec); 00174 00175 FD_ZERO(&sock_set); 00176 FD_SET(first_socket, &sock_set); 00177 if(!select(first_socket + 1, &sock_set, NULL, NULL, &tv)) 00178 { 00179 lifebeat(); 00180 tv.tv_sec = config->general.lifebeat_tick; // important to reset lifebeat 00181 continue; 00182 } 00183 00184 int *final_socket = new int; 00185 *final_socket = accept(first_socket, 00186 reinterpret_cast<struct sockaddr*>(&address), &socketlen); 00187 if(*final_socket != -1) 00188 pthread_create(&thread_tmp, NULL, user_wrapper, (final_socket)); 00189 else 00190 { 00191 logging->log_this(3, TYPE_INFO, "Failed to accept new caller."); 00192 // if the socket is accepted and the thread created the pointer will 00193 // get deleted there after it is stored. 00194 delete final_socket; 00195 } 00196 00197 tv.tv_sec = config->general.lifebeat_tick - (time(NULL) - before); 00198 if(tv.tv_sec < 0 || tv.tv_sec > config->general.lifebeat_tick) 00199 tv.tv_sec = 0; 00200 } 00201 close(first_socket); 00202 00203 return(true); 00204 } 00205 00206 void lifebeat(void) 00207 { 00208 logging->log_this(4, TYPE_DEBUG, "lifebeat reached."); 00209 00210 sem_wait(&cleanup_list_lock); 00211 while(!cleanup_list.empty()) 00212 { 00213 logging->log_this(4, TYPE_DEBUG, "joining thread #" + 00214 util.itos(cleanup_list.back())); 00215 pthread_join(cleanup_list.back(), NULL); 00216 cleanup_list.pop_back(); 00217 } 00218 sem_post(&cleanup_list_lock); 00219 00220 #ifdef USE_TLS 00221 if((time(NULL) - dh_time) > config->general.dh_regenerate) 00222 { 00223 gnutls_dh_params temp_dh_params; 00224 gnutls_dh_params_init(&temp_dh_params); 00225 gnutls_dh_params_generate2(temp_dh_params, 1024); 00226 gnutls_dh_params_cpy(dh_params, temp_dh_params); 00227 gnutls_dh_params_deinit(temp_dh_params); 00228 gnutls_certificate_set_dh_params(x509_cred, dh_params); 00229 dh_time = time(NULL); 00230 } 00231 #endif // USE_TLS 00232 } 00233 00234 static void *user_wrapper(void *socket_id) 00235 { 00236 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); 00237 00238 class User *user = handler->initializer((*(static_cast<int*>(socket_id)))); 00239 delete (static_cast<int*>(socket_id)); 00240 pthread_setspecific(my_user, static_cast<void*>(user)); 00241 00242 handler->init(user); 00243 00244 logging->log_this(3, TYPE_DEBUG, "closed connection from: " + 00245 user->host_name()); 00246 pthread_exit(NULL); // the thread exits..., and takes the user with it.. 00247 } 00248 00249 static void *log_wrapper(void *not_used) 00250 { 00251 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); 00252 logging->log_main(); 00253 00254 pthread_exit(NULL); 00255 } 00256 00257 00258 void sig_handler(int signal) 00259 { 00260 switch(signal) 00261 { 00262 case SIGTERM: 00263 case SIGINT: 00264 logging->log_this(3, TYPE_INFO, "SIGTERM received."); 00265 00266 logging->log_this(4, TYPE_DEBUG, "main thread. users: " + 00267 util.itos(user_list.size())); 00268 00269 for(vector<User*>::iterator user_it = user_list.begin(); 00270 user_it != user_list.end(); user_it++) 00271 pthread_cancel((*user_it)->thread_id()); 00272 00273 struct timeval times; 00274 times.tv_sec = 1; 00275 times.tv_usec = 0; 00276 select(0, NULL, NULL, NULL, ×); 00277 00278 logging->log_this(3, TYPE_INFO, "main thread exiting."); 00279 exit_baby(1, EXIT_FULL); 00280 break; 00281 00282 case SIGHUP: 00283 logging->log_this(3, TYPE_INFO, 00284 "SIGHUP received, reloading configuration"); 00285 config->parse_config_file(); 00286 break; 00287 00288 case SIGPIPE: 00289 logging->log_this(3, TYPE_INFO, 00290 "SIGPIPE received in thread: " + util.itos(pthread_self())); 00291 if(!pthread_equal(pthread_self(), main_thread) || 00292 pthread_equal(pthread_self(), logging_thread)) 00293 pthread_exit(NULL); // if this is a user or data thread, bail. 00294 break; 00295 } 00296 } 00297 00298 void exit_baby(int num, enum exits how) 00299 { 00300 if(how == EXIT_FULL) 00301 { 00302 if(!config->general.pid_file.empty()) 00303 unlink(config->general.pid_file.c_str()); 00304 00305 while(!cleanup_list.empty()) 00306 { 00307 logging->log_this(4, TYPE_DEBUG, "joining thread #" + 00308 util.itos(cleanup_list.back())); 00309 pthread_join(cleanup_list.back(), NULL); 00310 cleanup_list.pop_back(); 00311 } 00312 00313 delete handler; 00314 pthread_key_delete(my_user); 00315 pthread_key_delete(my_data); 00316 00317 #ifdef USE_TLS 00318 // emptying and freeing session cache. 00319 for(vector<cache*>::iterator cache_it = cache_db.begin(); 00320 cache_it != cache_db.end(); cache_it++) 00321 { 00322 gnutls_free((*cache_it)->key.data); 00323 gnutls_free((*cache_it)->data.data); 00324 delete(*cache_it); 00325 cache_db.erase(cache_it); 00326 } 00327 00328 gnutls_dh_params_deinit(dh_params); 00329 gnutls_certificate_free_credentials(x509_cred); 00330 gnutls_global_deinit(); 00331 pthread_rwlock_destroy(&cache_lock); 00332 #endif // USE_TLS 00333 sem_destroy(&comm.pam_lock); 00334 sem_destroy(&cleanup_list_lock); 00335 pthread_rwlock_destroy(&user_list_lock); 00336 pthread_cancel(logging_thread); 00337 pthread_join(logging_thread, NULL); 00338 } 00339 delete logging; 00340 00341 delete config; 00342 exit(num); 00343 } 00344 00345 #ifdef USE_TLS // code for session resuming 00346 00347 int tls_db_store(void *dbf, gnutls_datum key, gnutls_datum data) 00348 { 00349 struct cache *temp_cache = new cache; 00350 00351 temp_cache->key.data = static_cast<unsigned char*>(gnutls_malloc(key.size)); 00352 temp_cache->key.size = key.size; 00353 memcpy(temp_cache->key.data, key.data, key.size); 00354 00355 temp_cache->data.data = 00356 static_cast<unsigned char*>(gnutls_malloc(data.size)); 00357 temp_cache->data.size = data.size; 00358 memcpy(temp_cache->data.data, data.data, data.size); 00359 00360 pthread_rwlock_wrlock(&cache_lock); 00361 cache_db.push_back(temp_cache); 00362 pthread_rwlock_unlock(&cache_lock); 00363 return(0); 00364 } 00365 00366 gnutls_datum tls_db_fetch(void *dbf, gnutls_datum key) 00367 { 00368 gnutls_datum data = { NULL, 0 }; 00369 00370 pthread_rwlock_rdlock(&cache_lock); 00371 for(vector<cache*>::iterator cache_it = cache_db.begin(); 00372 cache_it != cache_db.end(); cache_it++) 00373 if(memcmp(key.data, (*cache_it)->key.data, (*cache_it)->key.size) == 0) 00374 { 00375 data.size = (*cache_it)->data.size; 00376 data.data = static_cast<unsigned char*>(gnutls_malloc(data.size)); 00377 memcpy(data.data, (*cache_it)->data.data, data.size); 00378 break; 00379 } 00380 pthread_rwlock_unlock(&cache_lock); 00381 00382 return(data); 00383 } 00384 00385 int tls_db_delete(void *dbf, gnutls_datum key) 00386 { 00387 int ret = -1; 00388 pthread_rwlock_rdlock(&cache_lock); 00389 for(vector<cache*>::iterator cache_it = cache_db.begin(); 00390 cache_it != cache_db.end(); cache_it++) 00391 if(memcmp(key.data, (*cache_it)->key.data, (*cache_it)->key.size) == 0) 00392 { 00393 pthread_rwlock_unlock(&cache_lock); 00394 pthread_rwlock_wrlock(&cache_lock); 00395 gnutls_free((*cache_it)->key.data); 00396 gnutls_free((*cache_it)->data.data); 00397 delete(*cache_it); 00398 cache_db.erase(cache_it); 00399 ret = 0; 00400 break; 00401 } 00402 pthread_rwlock_unlock(&cache_lock); 00403 00404 return(ret); 00405 } 00406 00407 #endif // USE_TLS |
- Copyright © 2005, BabyFTPd
- Powered by: