static int getstreamsocket(int family, char *errbuf, size_t errbufsize) { int fd, optval, r; fd = netSocket(family, SOCK_STREAM, IPPROTO_TCP); if(fd < 0) { snprintf(errbuf, errbufsize, "Unable to create socket: %s", strerror(net_errno)); return -1; } /** * Switch to nonblocking */ optval = 1; r = netSetSockOpt(fd, SOL_SOCKET, SO_NBIO, &optval, sizeof(optval)); if(r < 0) { snprintf(errbuf, errbufsize, "Unable to go nonblocking: %s", strerror(net_errno)); netClose(fd); return -1; } return fd; }
void tcp_close(tcpcon_t *tc) { #if ENABLE_POLARSSL if(tc->ssl != NULL) { ssl_close_notify(tc->ssl); ssl_free(tc->ssl); free(tc->ssl); free(tc->ssn); free(tc->hs); } #endif htsbuf_queue_flush(&tc->spill); netClose(tc->fd); free(tc); }
tcpcon_t * tcp_connect(const char *hostname, int port, char *errbuf, size_t errbufsize, int timeout, int ssl) { struct net_hostent *hp; char *tmphstbuf; int fd, r, err, herr, optval; const char *errtxt; struct sockaddr_in in; socklen_t errlen = sizeof(int); if(!strcmp(hostname, "localhost")) { if((fd = getstreamsocket(AF_INET, errbuf, errbufsize)) == -1) return NULL; memset(&in, 0, sizeof(in)); in.sin_family = AF_INET; in.sin_port = htons(port); in.sin_addr.s_addr = htonl(INADDR_LOOPBACK); r = netConnect(fd, (struct sockaddr *)&in, sizeof(struct sockaddr_in)); } else { herr = 0; tmphstbuf = NULL; /* free NULL is a nop */ hp = netGetHostByName(hostname); if(hp == NULL) herr = h_errno; if(herr != 0) { switch(herr) { case HOST_NOT_FOUND: errtxt = "Unknown host"; break; case NO_ADDRESS: errtxt = "The requested name is valid but does not have an IP address"; break; case NO_RECOVERY: errtxt = "A non-recoverable name server error occurred"; break; case TRY_AGAIN: errtxt = "A temporary error occurred on an authoritative name server"; break; default: errtxt = "Unknown error"; break; } snprintf(errbuf, errbufsize, "%s", errtxt); free(tmphstbuf); return NULL; } else if(hp == NULL) { snprintf(errbuf, errbufsize, "Resolver internal error"); free(tmphstbuf); return NULL; } if((fd = getstreamsocket(hp->h_addrtype, errbuf, errbufsize)) == -1) { free(tmphstbuf); return NULL; } switch(hp->h_addrtype) { case AF_INET: memset(&in, 0, sizeof(in)); in.sin_family = AF_INET; in.sin_port = htons(port); lv2_void* netaddrlist = (lv2_void*)(u64)hp->h_addr_list; memcpy(&in.sin_addr, (char*)(u64)netaddrlist[0], sizeof(struct in_addr)); r = netConnect(fd, (struct sockaddr *)&in, sizeof(struct sockaddr_in)); break; default: snprintf(errbuf, errbufsize, "Invalid protocol family"); free(tmphstbuf); return NULL; } free(tmphstbuf); } if(r < 0) { if(net_errno == NET_EINPROGRESS) { struct pollfd pfd; pfd.fd = fd; pfd.events = POLLOUT; pfd.revents = 0; r = netPoll(&pfd, 1, timeout); if(r == 0) { /* Timeout */ snprintf(errbuf, errbufsize, "Connection attempt timed out"); netClose(fd); return NULL; } if(r == -1) { snprintf(errbuf, errbufsize, "poll() error: %s", strerror(net_errno)); netClose(fd); return NULL; } netGetSockOpt(fd, SOL_SOCKET, SO_ERROR, (void *)&err, &errlen); } else { err = net_errno; } } else { err = 0; } if(err != 0) { snprintf(errbuf, errbufsize, "%s", strerror(err)); netClose(fd); return NULL; } optval = 0; r = netSetSockOpt(fd, SOL_SOCKET, SO_NBIO, &optval, sizeof(optval)); if(r < 0) { snprintf(errbuf, errbufsize, "Unable to go blocking: %s", strerror(net_errno)); netClose(fd); return NULL; } tcpcon_t *tc = calloc(1, sizeof(tcpcon_t)); tc->fd = fd; htsbuf_queue_init(&tc->spill, 0); if(ssl) { #if ENABLE_POLARSSL if(1) { tc->ssl = malloc(sizeof(ssl_context)); if(ssl_init(tc->ssl)) { snprintf(errbuf, errlen, "SSL failed to initialize"); close(fd); free(tc->ssl); free(tc); return NULL; } tc->ssn = malloc(sizeof(ssl_session)); tc->hs = malloc(sizeof(havege_state)); havege_init(tc->hs); memset(tc->ssn, 0, sizeof(ssl_session)); ssl_set_endpoint(tc->ssl, SSL_IS_CLIENT ); ssl_set_authmode(tc->ssl, SSL_VERIFY_NONE ); ssl_set_rng(tc->ssl, havege_rand, tc->hs ); ssl_set_bio(tc->ssl, net_recv, &tc->fd, net_send, &tc->fd); ssl_set_ciphers(tc->ssl, ssl_default_ciphers ); ssl_set_session(tc->ssl, 1, 600, tc->ssn ); tc->read = polarssl_read; tc->write = polarssl_write; } else #endif { snprintf(errbuf, errlen, "SSL not supported"); tcp_close(tc); return NULL; } } else { tc->read = tcp_read; tc->write = tcp_write; } return tc; }
static void handleclient(u64 conn_s_p) { // todo: clean up int conn_s = (int)conn_s_p; int list_s_data = -1; int conn_s_data = -1; int datareq = 0; char cwd[256]; char rnfr[256]; char filename[256]; char user[32]; u32 rest = 0; int authd = 0; int active = 1; Lv2FsFile tempfd; char buf[BUFFER_SIZE]; char buffer[1024]; char client_cmd[8][128]; ssize_t bytes; #if LOGIN_CHECK == 1 // load password file char passwordcheck[33]; // check if password file exists - if not, use default password if(exists(PASSWORD_FPATH) == 0) { Lv2FsFile fd; u64 read; lv2FsOpen(PASSWORD_FPATH, LV2_O_RDONLY, &fd, 0, NULL, 0); lv2FsRead(fd, passwordcheck, 32, &read); lv2FsClose(fd); if(strlen(passwordcheck) != 32) { strcpy(passwordcheck, LOGIN_PASSWORD); } } else { strcpy(passwordcheck, LOGIN_PASSWORD); } #endif // start directory strcpy(cwd, "/"); // welcome message swritel(conn_s, "220-OpenPS3FTP by @jjolano\r\n"); sprintf(buffer, "220 Version %s\r\n", VERSION); swritel(conn_s, buffer); while(exitapp == 0 && active && (bytes = sreadl(conn_s, buffer, 1024)) > 0) { // get rid of the newline at the end of the string buffer[strcspn(buffer, "\n")] = '\0'; buffer[strcspn(buffer, "\r")] = '\0'; // parse received string into array int parameter_count = 0; char *result = strtok(buffer, " "); strcpy(client_cmd[0], result); while(parameter_count < 7 && (result = strtok(NULL, " ")) != NULL) { parameter_count++; strcpy(client_cmd[parameter_count], result); } // identify the command int cmd_id; for(cmd_id = 0; cmd_id < client_cmds_count; cmd_id++) { if(strcasecmp(client_cmd[0], client_cmds[cmd_id]) == 0) { break; } } // execute command if(authd == 0) { // not logged in switch(cmd_id) { case 0: // USER #if LOGIN_CHECK == 1 if(parameter_count >= 1) { int i; for(i = 2; i <= parameter_count; i++) { strcat(client_cmd[1], " "); strcat(client_cmd[1], client_cmd[i]); } strcpy(user, client_cmd[1]); sprintf(buffer, "331 User %s OK. Password required\r\n", user); swritel(conn_s, buffer); } else { swritel(conn_s, "501 Please provide a username\r\n"); } #else sprintf(buffer, "331 User %s OK. Password (not really) required\r\n", user); swritel(conn_s, buffer); #endif break; case 1: // PASS #if LOGIN_CHECK == 1 if(parameter_count >= 1) { int i; for(i = 2; i <= parameter_count; i++) { strcat(client_cmd[1], " "); strcat(client_cmd[1], client_cmd[i]); } // hash the password given char output[33]; md5(output, client_cmd[1]); if(strcmp(user, LOGIN_USERNAME) == 0 && strcmp(output, passwordcheck) == 0) { swritel(conn_s, "230 Successful authentication\r\n"); authd = 1; } else { swritel(conn_s, "430 Invalid username or password - \r\n"); } } else { swritel(conn_s, "501 Invalid username or password\r\n"); } #else swritel(conn_s, "230 Successful authentication\r\n"); authd = 1; #endif break; case 2: // QUIT swritel(conn_s, "221 See you later\r\n"); active = 0; break; default: swritel(conn_s, "530 You are not logged in\r\n"); } } else { // logged in switch(cmd_id) { case 0: // USER case 1: // PASS swritel(conn_s, "530 You are already logged in\r\n"); break; case 2: // QUIT swritel(conn_s, "221 See you later\r\n"); active = 0; break; case 3: // PASV rest = 0; netSocketInfo snf; int ret = netGetSockInfo(conn_s, &snf, 1); if(ret >= 0 && snf.local_adr.s_addr != 0) { // assign a random port for passive mode srand(conn_s); int rand1 = (rand() % 251) + 4; int rand2 = rand() % 256; sprintf(buffer, "227 Entering Passive Mode (%u,%u,%u,%u,%i,%i)\r\n", (snf.local_adr.s_addr & 0xFF000000) >> 24, (snf.local_adr.s_addr & 0xFF0000) >> 16, (snf.local_adr.s_addr & 0xFF00) >> 8, (snf.local_adr.s_addr & 0xFF), rand1, rand2); short int pasvport = (rand1 * 256) + rand2; struct sockaddr_in servaddr; memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(pasvport); list_s_data = netSocket(AF_INET, SOCK_STREAM, 0); netBind(list_s_data, (struct sockaddr *) &servaddr, sizeof(servaddr)); netListen(list_s_data, 1); swritel(conn_s, buffer); if((conn_s_data = netAccept(list_s_data, NULL, NULL)) == -1) { swritel(conn_s, "550 PASV command failed\r\n"); } else { datareq = 1; } break; } swritel(conn_s, "550 PASV command failed\r\n"); break; case 4: // PORT if(parameter_count == 1) { rest = 0; char connectinfo[32]; strcpy(connectinfo, client_cmd[1]); char data[7][4]; int i = 0; char *result = strtok(connectinfo, ","); strcpy(data[0], result); while(i < 6 && (result = strtok(NULL, ",")) != NULL) { i++; strcpy(data[i], result); } char conn_ipaddr[16]; sprintf(conn_ipaddr, "%s.%s.%s.%s", data[0], data[1], data[2], data[3]); struct sockaddr_in servaddr; memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons((atoi(data[4]) * 256) + atoi(data[5])); inet_pton(AF_INET, conn_ipaddr, &servaddr.sin_addr); conn_s_data = netSocket(AF_INET, SOCK_STREAM, 0); if(connect(conn_s_data, (struct sockaddr *)&servaddr, sizeof(servaddr)) == 0) { swritel(conn_s, "200 PORT command successful\r\n"); datareq = 1; } else { swritel(conn_s, "550 PORT command failed\r\n"); } } else { swritel(conn_s, "501 Syntax error\r\n"); } break; case 5: // SITE if(strcasecmp(client_cmd[1], "CHMOD") == 0) { int i; for(i = 4; i <= parameter_count; i++) { strcat(client_cmd[3], " "); strcat(client_cmd[3], client_cmd[i]); } absPath(filename, client_cmd[3], cwd); char perms[4]; sprintf(perms, "0%s", client_cmd[2]); if(lv2FsChmod(filename, S_IFMT | strtol(perms, NULL, 8)) == 0) { swritel(conn_s, "250 File permissions successfully set\r\n"); } else { swritel(conn_s, "550 Failed to set file permissions\r\n"); } } else { swritel(conn_s, "500 Unrecognized SITE command\r\n"); } break; case 6: // FEAT swritel(conn_s, "211- Extensions supported:\r\n"); int i; for(i = 0; i < feat_cmds_count; i++) { sprintf(buffer, " %s\r\n", feat_cmds[i]); swritel(conn_s, buffer); } swritel(conn_s, "211 End.\r\n"); break; case 7: // TYPE swritel(conn_s, "200 TYPE command successful\r\n"); break; case 8: // REST if(parameter_count == 1) { rest = atoi(client_cmd[1]); swritel(conn_s, "350 REST command successful\r\n"); } else { swritel(conn_s, "501 Syntax error\r\n"); } break; case 9: // RETR if(parameter_count >= 1) { if(conn_s_data == -1) { swritel(conn_s, "425 No data connection\r\n"); break; } swritel(conn_s, "150 Opening data connection\r\n"); int i; for(i = 2; i <= parameter_count; i++) { strcat(client_cmd[1], " "); strcat(client_cmd[1], client_cmd[i]); } absPath(filename, client_cmd[1], cwd); u64 pos; u64 read = -1; Lv2FsFile fd; lv2FsOpen(filename, LV2_O_RDONLY, &fd, 0, NULL, 0); lv2FsLSeek64(fd, (s64)rest, SEEK_SET, &pos); if(fd >= 0) { while(lv2FsRead(fd, buf, BUFFER_SIZE - 1, &read) == 0 && read > 0) { netSend(conn_s_data, buf, read, 0); } if(read == 0) { swritel(conn_s, "226 Transfer complete\r\n"); } else { swritel(conn_s, "426 Transfer failed\r\n"); } } else { swritel(conn_s, "452 File access error\r\n"); } lv2FsClose(fd); } else { swritel(conn_s, "501 Syntax error\r\n"); } break; case 10: // PWD sprintf(buffer, "257 \"%s\" is the current directory\r\n", cwd); swritel(conn_s, buffer); break; case 11: // CWD if(parameter_count >= 1) { int i; for(i = 2; i <= parameter_count; i++) { strcat(client_cmd[1], " "); strcat(client_cmd[1], client_cmd[i]); } strcpy(filename, client_cmd[1]); if(strcmp(filename, "../") == 0) { for(int i = strlen(cwd) - 2; i > 0; i--) { if(cwd[i] != '/') { cwd[i] = '\0'; } else { break; } } sprintf(buffer, "250 Directory change successful: %s\r\n", cwd); swritel(conn_s, buffer); break; } if(filename[0] == '/') { strcpy(cwd, (strlen(filename) == 1) ? "/" : filename); } else { strcat(cwd, filename); } if(cwd[strlen(cwd) - 1] != '/') { strcat(cwd, "/"); } if(isDir(cwd)) { sprintf(buffer, "250 Directory change successful: %s\r\n", cwd); } else { sprintf(buffer, "550 Could not change directory: %s\r\n", cwd); } swritel(conn_s, buffer); } else { sprintf(buffer, "257 \"%s\" is the current directory\r\n", cwd); swritel(conn_s, buffer); } break; case 12: // CDUP for(int i = strlen(cwd) - 2; i > 0; i--) { if(cwd[i] != '/') { cwd[i] = '\0'; } else { break; } } sprintf(buffer, "250 Directory change successful: %s\r\n", cwd); swritel(conn_s, buffer); break; case 13: // NLST if(conn_s_data == -1) { swritel(conn_s, "425 No data connection\r\n"); break; } swritel(conn_s, "150 Opening data connection\r\n"); if(parameter_count >= 1) { int i; for(i = 2; i <= parameter_count; i++) { strcat(client_cmd[1], " "); strcat(client_cmd[1], client_cmd[i]); } absPath(filename, client_cmd[1], cwd); } else { strcpy(filename, cwd); } if(lv2FsOpenDir(filename, &tempfd) == 0) { u64 read; Lv2FsDirent ent; while(lv2FsReadDir(tempfd, &ent, &read) == 0 && read != 0) { sprintf(buffer, "%s\r\n", ent.d_name); swritel(conn_s_data, buffer); } swritel(conn_s, "226 Transfer complete\r\n"); } else { swritel(conn_s, "451 Cannot access directory\r\n"); } lv2FsCloseDir(tempfd); break; case 14: // LIST if(conn_s_data == -1) { swritel(conn_s, "425 No data connection\r\n"); break; } swritel(conn_s, "150 Opening data connection\r\n"); if(parameter_count >= 1) { int i; for(i = 2; i <= parameter_count; i++) { strcat(client_cmd[1], " "); strcat(client_cmd[1], client_cmd[i]); } absPath(filename, client_cmd[1], cwd); } else { strcpy(filename, cwd); } if(lv2FsOpenDir(filename, &tempfd) == 0) { u64 read; Lv2FsDirent ent; while(lv2FsReadDir(tempfd, &ent, &read) == 0 && read != 0) { sprintf(filename, "%s%s", cwd, ent.d_name); Lv2FsStat entry; lv2FsStat(filename, &entry); struct tm *tm; char timebuf[32]; tm = localtime(&entry.st_mtime); strftime(timebuf, 31, "%b %d %Y", tm); sprintf(buffer, "%s%s%s%s%s%s%s%s%s%s 1 root root %lu %s %s\r\n", ((entry.st_mode & S_IFDIR) != 0)?"d":"-", ((entry.st_mode & S_IRUSR) != 0)?"r":"-", ((entry.st_mode & S_IWUSR) != 0)?"w":"-", ((entry.st_mode & S_IXUSR) != 0)?"x":"-", ((entry.st_mode & S_IRGRP) != 0)?"r":"-", ((entry.st_mode & S_IWGRP) != 0)?"w":"-", ((entry.st_mode & S_IXGRP) != 0)?"x":"-", ((entry.st_mode & S_IROTH) != 0)?"r":"-", ((entry.st_mode & S_IWOTH) != 0)?"w":"-", ((entry.st_mode & S_IXOTH) != 0)?"x":"-", (long unsigned int)entry.st_size, timebuf, ent.d_name); swritel(conn_s_data, buffer); } swritel(conn_s, "226 Transfer complete\r\n"); } else { swritel(conn_s, "451 Cannot access directory\r\n"); } lv2FsCloseDir(tempfd); break; case 15: // STOR if(parameter_count >= 1) { if(conn_s_data == -1) { swritel(conn_s, "425 No data connection\r\n"); break; } swritel(conn_s, "150 Opening data connection\r\n"); int i; for(i = 2; i <= parameter_count; i++) { strcat(client_cmd[1], " "); strcat(client_cmd[1], client_cmd[i]); } absPath(filename, client_cmd[1], cwd); u64 pos; u64 read = -1; u64 write = -1; Lv2FsFile fd; lv2FsOpen(filename, LV2_O_WRONLY | LV2_O_CREAT, &fd, 0, NULL, 0); lv2FsChmod(filename, S_IFMT | 0666); lv2FsLSeek64(fd, (s32)rest, SEEK_SET, &pos); if(fd >= 0) { while((read = (u64)netRecv(conn_s_data, buf, BUFFER_SIZE - 1, MSG_WAITALL)) > 0) { lv2FsWrite(fd, buf, read, &write); if(write != read) { break; } } if(read == 0) { swritel(conn_s, "226 Transfer complete\r\n"); } else { swritel(conn_s, "426 Transfer failed\r\n"); } } else { swritel(conn_s, "452 File access error\r\n"); } lv2FsClose(fd); } else { swritel(conn_s, "501 Syntax error\r\n"); } break; case 16: // NOOP swritel(conn_s, "200 Zzzz...\r\n"); break; case 17: // DELE if(parameter_count >= 1) { int i; for(i = 2; i <= parameter_count; i++) { strcat(client_cmd[1], " "); strcat(client_cmd[1], client_cmd[i]); } absPath(filename, client_cmd[1], cwd); if(lv2FsUnlink(filename) == 0) { swritel(conn_s, "250 File successfully deleted\r\n"); } else { swritel(conn_s, "550 Failed to delete file\r\n"); } } else { swritel(conn_s, "501 Syntax error\r\n"); } break; case 18: // MKD if(parameter_count >= 1) { int i; for(i = 2; i <= parameter_count; i++) { strcat(client_cmd[1], " "); strcat(client_cmd[1], client_cmd[i]); } absPath(filename, client_cmd[1], cwd); if(lv2FsMkdir(filename, 0775) == 0) { swritel(conn_s, "250 Directory successfully created\r\n"); } else { swritel(conn_s, "550 Failed to create directory\r\n"); } } else { swritel(conn_s, "501 Syntax error\r\n"); } break; case 19: // RMD if(parameter_count >= 1) { int i; for(i = 2; i <= parameter_count; i++) { strcat(client_cmd[1], " "); strcat(client_cmd[1], client_cmd[i]); } absPath(filename, client_cmd[1], cwd); if(lv2FsRmdir(filename) == 0) { swritel(conn_s, "250 Directory successfully deleted\r\n"); } else { swritel(conn_s, "550 Failed to remove directory\r\n"); } } else { swritel(conn_s, "501 Syntax error\r\n"); } break; case 20: // RNFR if(parameter_count >= 1) { int i; for(i = 2; i <= parameter_count; i++) { strcat(client_cmd[1], " "); strcat(client_cmd[1], client_cmd[i]); } absPath(rnfr, client_cmd[1], cwd); if(exists(rnfr) == 0) { swritel(conn_s, "350 RNFR successful - ready for destination\r\n"); } else { swritel(conn_s, "550 RNFR failed - file does not exist\r\n"); } } else { swritel(conn_s, "501 Syntax error\r\n"); } break; case 21: // RNTO if(parameter_count >= 1) { int i; for(i = 2; i <= parameter_count; i++) { strcat(client_cmd[1], " "); strcat(client_cmd[1], client_cmd[i]); } absPath(filename, client_cmd[1], cwd); if(lv2FsRename(rnfr, filename) == 0) { swritel(conn_s, "250 File successfully renamed\r\n"); } else { swritel(conn_s, "550 Failed to rename file\r\n"); } } else { swritel(conn_s, "501 Syntax error\r\n"); } break; case 22: // SIZE if(parameter_count >= 1) { int i; for(i = 2; i <= parameter_count; i++) { strcat(client_cmd[1], " "); strcat(client_cmd[1], client_cmd[i]); } absPath(filename, client_cmd[1], cwd); Lv2FsStat entry; if(lv2FsStat(filename, &entry) == 0) { sprintf(buffer, "213 %lu\r\n", (long unsigned int)entry.st_size); } else { sprintf(buffer, "550 Requested file doesn't exist\r\n"); } swritel(conn_s, buffer); } else { swritel(conn_s, "501 Syntax error\r\n"); } break; case 23: // SYST swritel(conn_s, "215 UNIX Type: L8\r\n"); break; case 24: // HELP swritel(conn_s, "214 No help for you.\r\n"); break; case 25: // PASSWD if(parameter_count >= 1) { int i; for(i = 2; i <= parameter_count; i++) { strcat(client_cmd[1], " "); strcat(client_cmd[1], client_cmd[i]); } // hash the password given char output[33]; md5(output, client_cmd[1]); Lv2FsFile fd; u64 written; lv2FsOpen(PASSWORD_FPATH, LV2_O_WRONLY | LV2_O_CREAT, &fd, 0, NULL, 0); lv2FsWrite(fd, output, 32, &written); lv2FsClose(fd); swritel(conn_s, "200 Password successfully changed\r\n"); } else { swritel(conn_s, "501 Invalid password\r\n"); } break; case 26: // MLSD if(conn_s_data == -1) { swritel(conn_s, "425 No data connection\r\n"); break; } swritel(conn_s, "150 Opening data connection\r\n"); if(parameter_count >= 1) { int i; for(i = 2; i <= parameter_count; i++) { strcat(client_cmd[1], " "); strcat(client_cmd[1], client_cmd[i]); } absPath(filename, client_cmd[1], cwd); } else { strcpy(filename, cwd); } if(lv2FsOpenDir(filename, &tempfd) == 0) { u64 read; Lv2FsDirent ent; while(lv2FsReadDir(tempfd, &ent, &read) == 0 && read != 0) { sprintf(filename, "%s%s", cwd, ent.d_name); Lv2FsStat entry; lv2FsStat(filename, &entry); struct tm *tm; char timebuf[32]; tm = localtime(&entry.st_mtime); strftime(timebuf, 31, "%Y%m%d%H%M%S", tm); int permint = 0; permint += (((entry.st_mode & S_IRUSR) != 0)?400:0) + (((entry.st_mode & S_IWUSR) != 0)?200:0) + (((entry.st_mode & S_IXUSR) != 0)?100:0); permint += (((entry.st_mode & S_IRGRP) != 0)?40:0) + (((entry.st_mode & S_IWGRP) != 0)?20:0) + (((entry.st_mode & S_IXGRP) != 0)?10:0); permint += (((entry.st_mode & S_IROTH) != 0)?4:0) + (((entry.st_mode & S_IWOTH) != 0)?2:0) + (((entry.st_mode & S_IXOTH) != 0)?1:0); sprintf(buffer, "type=%s;size=%lu;modify=%s;UNIX.mode=0%i;UNIX.uid=root;UNIX.gid=root; %s\r\n", ((entry.st_mode & S_IFDIR) != 0)?"dir":"file", (long unsigned int)entry.st_size, timebuf, permint, ent.d_name); swritel(conn_s_data, buffer); } swritel(conn_s, "226 Transfer complete\r\n"); } else { swritel(conn_s, "501 Directory access error\r\n"); } lv2FsCloseDir(tempfd); break; case 27: // MLST swritel(conn_s, "250- Listing directory"); if(parameter_count >= 1) { int i; for(i = 2; i <= parameter_count; i++) { strcat(client_cmd[1], " "); strcat(client_cmd[1], client_cmd[i]); } absPath(filename, client_cmd[1], cwd); } else { strcpy(filename, cwd); } if(lv2FsOpenDir(filename, &tempfd) == 0) { u64 read; Lv2FsDirent ent; while(lv2FsReadDir(tempfd, &ent, &read) == 0 && read != 0) { sprintf(filename, "%s%s", cwd, ent.d_name); Lv2FsStat entry; lv2FsStat(filename, &entry); struct tm *tm; char timebuf[32]; tm = localtime(&entry.st_mtime); strftime(timebuf, 31, "%Y%m%d%H%M%S", tm); int permint = 0; permint += (((entry.st_mode & S_IRUSR) != 0)?400:0) + (((entry.st_mode & S_IWUSR) != 0)?200:0) + (((entry.st_mode & S_IXUSR) != 0)?100:0); permint += (((entry.st_mode & S_IRGRP) != 0)?40:0) + (((entry.st_mode & S_IWGRP) != 0)?20:0) + (((entry.st_mode & S_IXGRP) != 0)?10:0); permint += (((entry.st_mode & S_IROTH) != 0)?4:0) + (((entry.st_mode & S_IWOTH) != 0)?2:0) + (((entry.st_mode & S_IXOTH) != 0)?1:0); sprintf(buffer, " type=%s;size=%lu;modify=%s;UNIX.mode=0%i;UNIX.uid=root;UNIX.gid=root; %s\r\n", ((entry.st_mode & S_IFDIR) != 0)?"dir":"file", (long unsigned int)entry.st_size, timebuf, permint, ent.d_name); swritel(conn_s, buffer); } } swritel(conn_s, "250 End\r\n"); lv2FsCloseDir(tempfd); break; case 28: // EXITAPP swritel(conn_s, "221 Exiting OpenPS3FTP, bye\r\n"); exitapp = 1; break; case 29: // TEST swritel(conn_s, "211-Listing parameters\r\n"); sprintf(buffer, "211-Count: %i\r\n", parameter_count); swritel(conn_s, buffer); int tx; for(tx = 0; tx <= parameter_count; tx++) { sprintf(buffer, " %i:%s\r\n", tx, client_cmd[tx]); swritel(conn_s, buffer); } swritel(conn_s, "211 End\r\n"); break; default: swritel(conn_s, "500 Unrecognized command\r\n"); } if(datareq == 1) { datareq = 0; } else { // close any active data connections if(conn_s_data > -1) { netShutdown(conn_s_data, 2); netClose(conn_s_data); conn_s_data = -1; } if(list_s_data > -1) { netShutdown(list_s_data, 2); netClose(list_s_data); list_s_data = -1; } } } }
static void handleclient(u64 conn_s_p) { int conn_s = (int)conn_s_p; int list_s_data = -1; int conn_s_data = -1; char cwd[2048]; char login_user[32]; char login_pass[64]; char rename_from[2048]; u32 rest = 0; int authd = 0; char message[4096]; char buffer[2048]; sprintf(cwd, "/"); sprintf(message, "220-OpenPS3FTP by @jjolano\r\n"); Writeline(conn_s, message, strlen(message)); sprintf(message, "220 Version %s\r\n", VERSION); Writeline(conn_s, message, strlen(message)); while(program_running == 1) { sys_ppu_thread_yield(); if(Readline(conn_s, buffer, 2047) == 0 || strncmp(buffer, "QUIT", 4) == 0 || strncmp(buffer, "BYE", 3) == 0) { break; } buffer[strcspn(buffer, "\n")] = '\0'; buffer[strcspn(buffer, "\r")] = '\0'; if(strncmp(buffer, "USER", 4) == 0) { if(strlen(buffer) > 7) { strcpy(login_user, buffer+5); sprintf(message, "331 Username %s OK. Password required\r\n", login_user); Writeline(conn_s, message, strlen(message)); } else { sprintf(message, "430 No username specified\r\n"); Writeline(conn_s, message, strlen(message)); } } else if(strncmp(buffer, "PASS", 4) == 0) { if(strlen(buffer) > 7) { strcpy(login_pass, buffer+5); if(strcmp(LOGIN_USERNAME, login_user) == 0 && strcmp(LOGIN_PASSWORD, login_pass) == 0) { authd = 1; sprintf(message, "230 Successful authentication\r\n"); } else { sprintf(message, "430 Invalid username or password\r\n"); Writeline(conn_s, message, strlen(message)); } } else { sprintf(message, "430 Invalid username or password\r\n"); } Writeline(conn_s, message, strlen(message)); } else if(authd == 0) { sprintf(message, "530 Not logged in\r\n"); Writeline(conn_s, message, strlen(message)); } else if(strncmp(buffer, "FEAT", 4) == 0) { sprintf(message, "211-Extensions supported:\r\n"); Writeline(conn_s, message, strlen(message)); sprintf(message, " SIZE\r\n"); Writeline(conn_s, message, strlen(message)); sprintf(message, " PASV\r\n"); Writeline(conn_s, message, strlen(message)); sprintf(message, "211 End\r\n"); Writeline(conn_s, message, strlen(message)); } else if(strncmp(buffer, "TYPE", 4) == 0) { sprintf(message, "200 TYPE is now %s\r\n", buffer+5); Writeline(conn_s, message, strlen(message)); } else if(strncmp(buffer, "PORT", 4) == 0) { rest = 0; char connectinfo[24]; strcpy(connectinfo, buffer+5); char data[7][4]; int len = strlen(connectinfo); int i, x = 0, y = 0; for(i = 0;i < len;i++) { if(connectinfo[i] == ',') { data[x][y] = '\0'; x++; y = 0; } else { data[x][y] = connectinfo[i]; y++; } } char conn_ipaddr[16]; sprintf(conn_ipaddr, "%s.%s.%s.%s", data[0], data[1], data[2], data[3]); int p1 = atoi(data[4]); int p2 = atoi(data[5]); short int conn_port = (p1 * 256) + p2; netClose(conn_s_data); netClose(list_s_data); list_s_data = -1; conn_s_data = netSocket(AF_INET, SOCK_STREAM, 0); struct sockaddr_in servaddr; memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(conn_port); inet_pton(AF_INET, conn_ipaddr, &servaddr.sin_addr); if(connect(conn_s_data, (struct sockaddr *)&servaddr, sizeof(servaddr)) == 0) { sprintf(message, "200 PORT command successful\r\n"); Writeline(conn_s, message, strlen(message)); continue; } sprintf(message, "425 Internal Error\r\n"); Writeline(conn_s, message, strlen(message)); } else if(strncmp(buffer, "PASV", 4) == 0) { rest = 0; netSocketInfo snf; int ret = netGetSockInfo(conn_s, &snf, 1); if(ret >= 0 && snf.local_adr.s_addr != 0) { netClose(conn_s_data); netClose(list_s_data); conn_s_data = -1; list_s_data = -1; // create the socket list_s_data = netSocket(AF_INET, SOCK_STREAM, 0); // calculate the passive mode port //srand((unsigned)time(NULL)); //srand((unsigned)time(NULL) + rand()); int rand1 = 4 + rand() % 255; int rand2 = rand() % 256; short int port = (rand1 * 256) + rand2; struct sockaddr_in servaddr; memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(port); // bind address to listener, listen, and accept netBind(list_s_data, (struct sockaddr *) &servaddr, sizeof(servaddr)); netListen(list_s_data, LISTENQ); sprintf(message, "227 Entering Passive Mode (%u,%u,%u,%u,%i,%i)\r\n", (snf.local_adr.s_addr & 0xFF000000) >> 24, (snf.local_adr.s_addr & 0xFF0000) >> 16, (snf.local_adr.s_addr & 0xFF00) >> 8, (snf.local_adr.s_addr & 0xFF), rand1, rand2); Writeline(conn_s, message, strlen(message)); if((conn_s_data = netAccept(list_s_data, NULL, NULL)) < 0) { printf("warning: failed to accept a connection\n"); netClose(conn_s_data); netClose(list_s_data); conn_s_data = -1; list_s_data = -1; } else { // PASV success continue; } } sprintf(message, "425 Internal Error\r\n"); Writeline(conn_s, message, strlen(message)); }