DocumentationGenerated on Thu Aug 31 00:02:27 2006 |
||
Commands.cppGo to the documentation of this file.00001 00002 // $Id: Commands.cpp,v 1.251 2005/08/24 21:07:45 klas Exp $ 00003 // 00004 // Usage: Ftp commands and data transfer functions 00005 // 00006 // A part of babyftpd, licensed under the GNU GPL, see the file 00007 // LICENSE for complete information. 00009 00010 #define COMMANDS_CPP 00011 #define NETINCLS 00012 #define BABY_CORE 00013 #include "Commands.h" 00014 00015 class Commands comm; 00016 00017 void *data_wrapper(void *void_data) 00018 { 00019 class Data *data = static_cast<class Data*>(void_data); 00020 string message; 00021 time_t start_time = time(NULL); 00022 size_t trans_size = 0; // will hold the total number of sent bytes 00023 00024 data->thread_id(pthread_self()); 00025 00026 pthread_setspecific(my_data, void_data); 00027 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); 00028 00029 data->host_name(inet_ntoa(data->addr().sin_addr)); 00030 00031 // I don't like it, but we need to drop permissions again... 00032 // not true for new threads, need to look deeper into this. 00033 struct passwd pwd, *pwd_ptr; 00034 char pwdata[PWBUF_SIZE]; 00035 getpwnam_r(data->user->user_name().c_str(), &pwd, pwdata, sizeof(pwdata), 00036 &pwd_ptr); 00037 uid_t uid = pwd.pw_uid; 00038 gid_t gid = pwd.pw_gid; 00039 setuid(uid); 00040 setgid(gid); 00041 00042 #ifdef USE_TLS // handshakes etc 00043 if(data->settings(TLS_PROT_D)) 00044 if(!data->engage_tls()) // failed handshake 00045 message = 00046 "451 Failed to negotiate TLS as was asked. Closing data connection."; 00047 #endif // USE_TLS 00048 while(message.empty()) 00049 { 00050 char *read_buf = new char[data->packet_size()]; 00051 size_t size = 0, size2 = 0; 00052 if(data->settings(RETR_TRANS)) 00053 { 00054 size2 = read(data->file_id(), read_buf, data->packet_size()); 00055 if(size2 > 0) 00056 size = data->send(read_buf, size2); 00057 } 00058 else // STOR_STRANS 00059 size = data->receive(read_buf, data->packet_size() - 1); 00060 00061 trans_size += size; 00062 if(!data->settings(RETR_TRANS)) 00063 { 00064 if(size != 0 && (write(data->file_id(), read_buf, size) == -1)) 00065 { 00066 logging->log_this(3, TYPE_DEBUG, "Write failed to file: " + 00067 data->file_name() + " from host: " + data->host_name() + 00068 " with error %m"); 00069 message = "451 File transfer failed."; 00070 } 00071 else if(size == 0) 00072 { 00073 if(close(data->file_id()) != 0) 00074 message = "550 Failed saving file."; 00075 else 00076 message = "226 Transfer complete."; 00077 } 00078 } 00079 else // RETR_TRANS 00080 { 00081 if(size != size2) 00082 message = "550 Transfer failed."; 00083 else if(size2 != data->packet_size()) 00084 message = "226 Transfer complete."; 00085 } 00086 delete[] read_buf; 00087 } 00088 00089 *data->user << message << "\r\n"; 00090 if(config->logger.xferlog) 00091 { 00092 string time_string; 00093 util.time_string(time_string, "%a %b %d %H:%M:%S %Y "); 00094 00095 // as ' ' separates fields in the xferlog we convert them to '_' here 00096 string temp_name = data->file_name(); 00097 for(string::iterator name_it = temp_name.begin(); 00098 name_it != temp_name.end(); name_it++) 00099 if(isspace(*name_it)) 00100 *name_it = '_'; 00101 00102 // let us build a string! 00103 string xferlog = time_string; 00104 xferlog += util.itos(time(NULL) - start_time); 00105 xferlog += " " + data->host_name(); 00106 xferlog += " " + util.itos(trans_size); 00107 xferlog += " " + temp_name + " "; 00108 xferlog += (data->settings(BINARY)?"b":"a"); 00109 xferlog += " _ "; // we don't support any special-action to flag here. 00110 xferlog += (data->settings(RETR_TRANS)?"o":"i"); 00111 xferlog += (data->user->settings(ANONYMOUS)? // a for anonymous, r for real 00112 " a " + data->user->anonymous_id(): // if the user is anonymous we log 00113 " r " + data->user->user_name()); // the id string, else the user name. 00114 xferlog += " FTP"; // maybe ftps for encrypted? no. IANA. 00115 xferlog += " 0"; // there should be more auth methods available here? 00116 xferlog += " *"; // or should this be uid? 00117 00118 logging->log_this(1, TYPE_XFER, xferlog); 00119 } 00120 00121 pthread_exit(NULL); 00122 } 00123 00124 // parsing strings so we get something good to work with, 00125 // beware of this function, it is one of the most expensive 00126 // functions in the game... 00127 string Commands::parsedir(User *user, string orig_string) 00128 { 00129 string new_string; 00130 00131 if(orig_string[0] != '/') 00132 orig_string = user->current_dir() + '/' + orig_string; 00133 00134 class StringTokenizer *token = new StringTokenizer(orig_string, "/", false); 00135 vector<string> dir_array; 00136 dir_array.reserve(token->countTokens()); 00137 00138 while(token->hasMoreTokens()) 00139 { 00140 dir_array.push_back(token->nextToken()); 00141 00142 if(dir_array.back().size() < 3) 00143 { // to save us from expensive string comparisons 00144 if(dir_array.back() == "..") 00145 { 00146 dir_array.pop_back(); 00147 if(!dir_array.empty()) 00148 dir_array.pop_back(); 00149 } 00150 else if(dir_array.back() == ".") 00151 dir_array.pop_back(); 00152 } 00153 } 00154 delete token; 00155 00156 if(dir_array.empty()) 00157 new_string = '/'; 00158 else 00159 for(vector<string>::iterator dir_it = dir_array.begin(); 00160 dir_it != dir_array.end(); dir_it++) 00161 new_string += '/' + *dir_it; 00162 00163 if(user->root_dir().size() > 1) 00164 if(new_string.find(user->root_dir()) != 0) 00165 new_string = user->root_dir() + new_string; 00166 00167 00168 return(new_string); 00169 } 00170 00171 int pam_conversate(int num_msg, const struct pam_message **msg, 00172 struct pam_response **resp, void *appdata_ptr) 00173 { 00174 struct pam_response *reply = NULL; 00175 int count = 0; 00176 struct pam_data *auth_data = (static_cast<struct pam_data*>(appdata_ptr)); 00177 00178 for(int i = 0; i < num_msg; i++) 00179 { 00180 struct pam_response *reply_tmp; 00181 switch(msg[i]->msg_style) 00182 { 00183 case PAM_PROMPT_ECHO_ON: 00184 case PAM_PROMPT_ECHO_OFF: 00185 reply_tmp = (static_cast<struct pam_response*> 00186 (malloc(sizeof(struct pam_response) * (count + 1)))); 00187 memcpy(reply_tmp, reply, count); 00188 if(reply) 00189 free(reply); 00190 reply = reply_tmp; 00191 00192 // is this really how it should be done? 00193 if(msg[i]->msg_style == PAM_PROMPT_ECHO_ON) 00194 reply[i].resp = strndup(auth_data->user_name.c_str(), 00195 auth_data->user_name.size()); 00196 else 00197 reply[i].resp = strndup(auth_data->password.c_str(), 00198 auth_data->password.size()); 00199 00200 reply[count++].resp_retcode = PAM_SUCCESS; 00201 break; 00202 00203 case PAM_TEXT_INFO: 00204 break; 00205 00206 case PAM_ERROR_MSG: 00207 default: 00208 if(reply) 00209 free(reply); 00210 return PAM_CONV_ERR; 00211 } 00212 } 00213 *resp = reply; 00214 return PAM_SUCCESS; 00215 } |
- Copyright © 2005, BabyFTPd
- Powered by: