00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "vfer_rcp.h"
00023
00024
00025
00026
00027 typedef struct rcpd_info {
00028 char user [MAX_USER];
00029 char home_dir [MAX_PATH];
00030 int frame_size;
00031 int port;
00032 char daemon;
00033 } rcpd_info;
00034
00035 extern char *optarg;
00036 extern int optind;
00037 extern int optopt;
00038 extern int opterr;
00039
00040 void print_help (char* prog, int verbose);
00041 int parse_opts (int argc, char** argv, FILE** testing_out);
00042 int rcpd_connect ();
00043
00044
00045 vfer_fd connect_skt;
00046 vfer_fd listen_skt;
00047 rcpd_info info;
00048 int fd;
00049 int sig_mark = 0;
00050
00051
00052
00053
00054
00055
00056
00057 void print_help(char* prog, int verbose) {
00058 printf("usage: %s [-h] [-v[v]] [-d] [-P port] start|stop\n", prog);
00059 if (verbose == 0) return;
00060 printf("\t-h brings up this help page [optional]\n");
00061 printf("\t-v verbose message printing [optional]\n");
00062 printf("\t-vv more verbose message printing [optional]\n");
00063 printf("\t-d start server as a daemon process [optional]\n");
00064 printf("\t-P specifies port on which to listen [optional]\n");
00065 printf("\tstart starts the server [start|stop required]\n");
00066 printf("\tstop stops all currently running servers [start|stop required]\n");
00067 printf("notes:\n");
00068 printf("\t- port is defaulted to 2046\n");
00069 printf("\t- username matching is the only authentication mechanism\n");
00070 printf("\t- remote->remote copying is not implemented\n");
00071 printf("\t- encryption is not implemented\n");
00072 }
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089 int parse_opts(int argc, char** argv, FILE** testing_out) {
00090 int c;
00091 struct passwd *pwentry;
00092 int uid;
00093 int ret;
00094
00095 opterr=0;
00096 bzero(info.user,MAX_USER);
00097 bzero(info.home_dir,MAX_PATH);
00098 info.frame_size = MAX_FRAME_SIZE;
00099 info.port = DEFAULT_PORT;
00100 info.daemon = 0;
00101 *testing_out = NULL;
00102 while (1)
00103 {
00104 c = getopt (argc, argv, ":hvdP:");
00105 if (c == -1) break;
00106 switch (c) {
00107 case 'h':
00108 return -2;
00109 break;
00110 case 'P':
00111 info.port = atoi(optarg);
00112 break;
00113 case 'd':
00114 info.daemon = 1;
00115 break;
00116 case 'v':
00117 if (*testing_out == NULL) {
00118
00119 *testing_out = stdout;
00120 vfer_debug(stdout, stdout, "a");
00121 } else {
00122 vfer_debug(stdout, stdout, "aCcP");
00123 }
00124 break;
00125 case ':':
00126 T_ERR("parse_opts", "option %c missing value", optopt);
00127 return -1;
00128 case '?':
00129 T_ERR("parse_opts", "unknown option: %c", optopt);
00130 return -1;
00131 default:
00132 T_ERR("parse_opts", "getopt returned character code 0%o", c);
00133 return -1;
00134 }
00135 }
00136 if (argc - optind != 1) {
00137 T_ERR("parse_opts", "exactly one non-option arg required");
00138 return -1;
00139 }
00140
00141
00142 if (strlen(argv[optind]) == 5 && strncmp(argv[optind], "start", 5) == 0) {
00143 ret = 0;
00144 } else if (strlen(argv[optind]) == 4 && strncmp(argv[optind], "stop", 4) == 0) {
00145 ret = 1;
00146 } else {
00147 T_ERR("parse_opts", "non-option arg must be start/stop");
00148 return -1;
00149 }
00150
00151
00152 uid=getuid();
00153 if ((pwentry = getpwuid(uid)) == NULL) {
00154 T_ERR("parse_opts", "failed getting password entry for uid(%d)", uid);
00155 return -1;
00156 }
00157 if (strlen(pwentry->pw_name) > MAX_USER) {
00158 T_ERR("parse_opts", "length of username must be less than %d", MAX_USER);
00159 return -1;
00160 }
00161 if (strlen(pwentry->pw_dir) > MAX_PATH) {
00162 T_ERR("parse_opts", "length of home dir must be less than %d", MAX_PATH);
00163 return -1;
00164 }
00165
00166 strncpy(info.home_dir, pwentry->pw_dir, MAX_PATH);
00167 strncpy(info.user, pwentry->pw_name, MAX_USER);
00168
00169
00170 return ret;
00171 }
00172
00173
00174
00175
00176
00177
00178
00179
00180 int rcpd_connect() {
00181
00182 struct sockaddr_in sa;
00183 int ret;
00184
00185 bzero((char*)(&sa), sizeof(sa));
00186 sa.sin_family = AF_INET;
00187 sa.sin_addr.s_addr = htonl(INADDR_ANY);
00188 sa.sin_port = htons(info.port);
00189
00190 if ((listen_skt = vfer_socket (SOCK_DGRAM)) < 0) {
00191 TEST_PRINT("rcpd_connect", "vfer_socket failed [%s]", vfer_errortext(listen_skt));
00192 close(fd);
00193 return -1;
00194 }
00195
00196 if ((ret = vfer_bind (listen_skt, (struct sockaddr*) &sa, sizeof(sa))) < 0) {
00197 TEST_PRINT("rcpd_connect", "vfer_bind failed [%s]", vfer_errortext(ret));
00198 close(fd);
00199 return -1;
00200 }
00201 if ((ret = vfer_listen (listen_skt, 3)) < 0) {
00202 TEST_PRINT("rcpd_connect", "vfer_listen failed [%s]", vfer_errortext(ret));
00203 close(fd);
00204 return -1;
00205 }
00206 return 0;
00207 }
00208
00209
00210
00211
00212 void sig_handler(int sig) {
00213 exit(1);
00214 }
00215
00216
00217
00218
00219 int main (int argc, char** argv) {
00220 int ret;
00221 client_msg_t client_msg;
00222 server_msg_t server_msg;
00223 struct sockaddr_in sa_accepted;
00224 socklen_t accepted_len;
00225 char buf[INET_ADDRSTRLEN];
00226 struct stat stat_buf;
00227 char path[MAX_PATH * 2];
00228 struct sigaction sa;
00229 int pid;
00230 char fname[16];
00231 FILE* file;
00232 FILE* testing_out;
00233 DIR* dir;
00234 struct dirent* dir_e;
00235 vfer_stats stats;
00236 connect_skt = -1;
00237
00238 ret = parse_opts(argc, argv, &testing_out);
00239 TEST_INIT("VFER_RCPD", "vfer_rcpd.c", testing_out, stdout);
00240
00241 if (ret == -2) {
00242 print_help(argv[0], 1);
00243 return 0;
00244 } else if (ret == -1) {
00245 print_help(argv[0], 0);
00246 return -1;
00247 } else if (ret == 1) {
00248 TEST_PRINT("main", "stopping all running vferd");
00249 dir = opendir("/tmp/");
00250 while ((dir_e = readdir(dir))) {
00251 if (strncmp(dir_e->d_name, "vferd_", 6) == 0) {
00252 pid = atoi(dir_e->d_name + 6);
00253 printf("stopping vferd[%d]\n", pid);
00254 if (kill((pid_t)(pid), SIGKILL) == -1) {
00255 T_ERR("main", "SIGKILL failed on vferd with pid[%d]", pid);
00256 } else {
00257 TEST_PRINT("main", "stopped vferd with pid [%d]", pid);
00258 }
00259 sprintf(fname, "/tmp/%s", dir_e->d_name);
00260 unlink(fname);
00261 }
00262 }
00263 closedir(dir);
00264 return 0;
00265 } else if (ret != 0) {
00266 T_ERR("main", "parse_opts returned bad value, quitting");
00267 return -1;
00268 }
00269
00270
00271
00272 if (info.daemon == 1) {
00273 TEST_PRINT("main", "daemonizing ..");
00274 fflush(stdout);
00275 if (daemon(1,0) == -1) {
00276 TEST_PRINT("main", "couldn't start as daemon, daemon() call failed");
00277 }
00278 }
00279
00280 TEST_PRINT("main", "starting vferd");
00281 pid = (int) getpid();
00282 sprintf(fname, "/tmp/vferd_%d", pid);
00283 file = fopen(fname,"w");
00284 fclose(file);
00285
00286
00287 sa.sa_handler = &(sig_handler);
00288 if (sigaction(SIGINT, &sa, NULL) == -1) {
00289 TEST_PRINT("main", "couldn't install a signal handler for SIGINT");
00290 }
00291
00292
00293 if (rcpd_connect() == -1) {
00294 return -1;
00295 }
00296
00297 TEST_PRINT("main", "started with authenticating username: %s, home_dir: %s", info.user, info.home_dir);
00298
00299 while (1) {
00300 retry_accept:
00301 if ((connect_skt = vfer_accept(listen_skt, (SA*)(&sa_accepted), &accepted_len)) < 0) {
00302 if (connect_skt == VFER_TIMEOUT) {
00303 TEST_PRINT("main", "vfer_accept timedout, retrying");
00304 goto retry_accept;
00305 }
00306 TEST_PRINT("main", "vfer_accept failed [%s]", vfer_errortext(connect_skt));
00307 vfer_close(listen_skt);
00308 return 1;
00309 }
00310
00311 TEST_PRINT("main", "vfer_accept successfull new connection: [%s : %d]",
00312 inet_ntop(AF_INET, &(sa_accepted.sin_addr),buf, INET_ADDRSTRLEN),
00313 ntohs(sa_accepted.sin_port));
00314
00315
00316 if ((ret = vfer_recv(connect_skt, &client_msg, sizeof(client_msg_t))) < 0) {
00317 TEST_PRINT("main", "failed to send server msg to client [%s]", vfer_errortext(ret));
00318 goto CLEAN_UP;
00319 }
00320 client_msg.file_size = ntohl(client_msg.file_size);
00321
00322 TEST_PRINT("main", "received: rpath[%s] local_uname[%s] recvd_uname[%s] from_remote[%d] file_size[%u]",
00323 client_msg.remote_path, client_msg.local_name, client_msg.user, client_msg.from_remote, client_msg.file_size);
00324
00325 server_msg.file_size = 0;
00326 server_msg.file_size = htonl(server_msg.file_size);
00327
00328
00329 if (strncmp(info.user, client_msg.user, MAX_USER) != 0) {
00330 TEST_PRINT("main", "remote connection gave bad username[%s]", client_msg.user);
00331 server_msg.status = RCP_EUSER;
00332 server_msg.status = htonl(server_msg.status);
00333 if ((ret = vfer_send(connect_skt, &server_msg, sizeof(server_msg_t))) < 0) {
00334 TEST_PRINT("main", "failed to send server msg to client [%s]", vfer_errortext(ret));
00335 }
00336 goto CLEAN_UP;
00337 }
00338
00339
00340 if (client_msg.remote_path[0] == '~') {
00341 strncpy(path, info.home_dir, MAX_PATH);
00342 strncpy(path + strlen(path), client_msg.remote_path+1, MAX_PATH);
00343 } else {
00344 strncpy(path, client_msg.remote_path, MAX_PATH);
00345 }
00346
00347 TEST_PRINT("main", "path expanded to: %s", path);
00348 if (client_msg.from_remote == 0) {
00349
00350 if ((fd = open(path, O_RDONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) == -1) {
00351 TEST_PRINT("main", "open for reading failed");
00352 perror("open for reading failed");
00353
00354 server_msg.status = RCP_EOPEN;
00355 server_msg.status = htonl(server_msg.status);
00356 if ((ret = vfer_send(connect_skt, &server_msg, sizeof(server_msg_t))) < 0) {
00357 TEST_PRINT("main", "failed to send server msg to client [%s]", vfer_errortext(ret));
00358 goto CLEAN_UP;
00359 }
00360 } else {
00361
00362 server_msg.status = RCP_READY;
00363 server_msg.file_size = lseek(fd, 0, SEEK_END);
00364 server_msg.file_size = htonl(server_msg.file_size);
00365 server_msg.status = htonl(server_msg.status);
00366 if ((ret = vfer_send(connect_skt, &server_msg, sizeof(server_msg_t))) < 0) {
00367 TEST_PRINT("main", "failed to send server msg to client [%s]", vfer_errortext(ret));
00368 goto CLEAN_UP;
00369 }
00370 server_msg.file_size = ntohl(server_msg.file_size);
00371 if ((ret = vfer_sendfile(connect_skt, fd, 0, server_msg.file_size)) < 0) {
00372 TEST_PRINT("main", "vfer_sendfile failed [%s]", vfer_errortext(ret));
00373 goto CLEAN_UP;
00374 }
00375 }
00376 } else {
00377
00378
00379
00380 if (path[strlen(path) - 1] == '/') {
00381
00382 strncpy(path + strlen(path), client_msg.local_name, 2*MAX_PATH - strlen(path));
00383 } else {
00384
00385 if (stat(path, &stat_buf) == -1) {
00386 server_msg.status = RCP_EOTHER;
00387 switch (errno) {
00388 case ENOENT:
00389
00390 TEST_PRINT("main", "writing to a new file");
00391 break;
00392 case ENOTDIR:
00393 TEST_PRINT("main", "bad path from client");
00394 server_msg.status = RCP_ENOENT;
00395 default:
00396 TEST_PRINT("main", "stat failed");
00397
00398 server_msg.status = htonl(server_msg.status);
00399 if ((ret = vfer_send(connect_skt, &server_msg, sizeof(server_msg_t))) < 0) {
00400 TEST_PRINT("main", "failed to send server msg to client [%s]", vfer_errortext(ret));
00401 goto CLEAN_UP;
00402 }
00403 }
00404 } else {
00405
00406 if (stat_buf.st_mode & S_IFDIR) {
00407
00408 path[strlen(path)] = '/';
00409 path[strlen(path)+1] = 0;
00410 strncpy(path + strlen(path), client_msg.local_name, 256 - strlen(path));
00411 }
00412 }
00413 }
00414
00415 if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) == -1) {
00416 TEST_PRINT("main", "open for writing failed");
00417 perror("open for writing failed");
00418
00419 server_msg.status = RCP_EOPEN;
00420 server_msg.status = htonl(server_msg.status);
00421 if ((ret = vfer_send(connect_skt, &server_msg, sizeof(server_msg_t))) < 0) {
00422 TEST_PRINT("main", "failed to send server msg to client [%s]", vfer_errortext(ret));
00423 goto CLEAN_UP;
00424 }
00425 } else {
00426
00427 server_msg.status = RCP_READY;
00428 server_msg.status = htonl(server_msg.status);
00429 if ((ret = vfer_send(connect_skt, &server_msg, sizeof(server_msg_t))) < 0) {
00430 TEST_PRINT("main", "failed to send server msg to client [%s]", vfer_errortext(ret));
00431 goto CLEAN_UP;
00432 }
00433 if ((ret = vfer_recvfile(connect_skt, fd, 0, client_msg.file_size)) < 0){
00434 TEST_PRINT("main","vfer_recvfile failed [%s]", vfer_errortext(ret));
00435 goto CLEAN_UP;
00436 }
00437 }
00438 }
00439 CLEAN_UP:
00440 TEST_PRINT("main", "Closing the accepted socket");
00441 vfer_close(connect_skt);
00442 stats = vfer_sockstats(connect_skt);
00443 connect_skt = -1;
00444 vfer_rcp_print_stats(&stats);
00445 close(fd);
00446 }
00447
00448 return 0;
00449 }