use std::format in logger, re-organize main.cpp, add SIGINT handling.
This commit is contained in:
@@ -56,7 +56,7 @@ public:
|
||||
return 0;
|
||||
}
|
||||
// Fatal error
|
||||
logger->print(LOGLEVEL_ERROR, "C(%i) SSL handshake failed with error: %d", control_sock, err);
|
||||
logger->print(LOGLEVEL_ERROR, "client {} SSL handshake failed with error: {}", control_sock, err);
|
||||
ERR_print_errors_fp(stderr);
|
||||
SSL_free(control_ssl);
|
||||
control_ssl = nullptr;
|
||||
@@ -66,7 +66,7 @@ public:
|
||||
}
|
||||
// Handshake completed successfully
|
||||
ssl_handshake_complete = true;
|
||||
logger->print(LOGLEVEL_DEBUG, "C(%i) SSL handshake completed", control_sock);
|
||||
logger->print(LOGLEVEL_DEBUG, "client {} SSL handshake completed", control_sock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -226,7 +226,7 @@ public:
|
||||
if (getsockname(data_fd, (struct sockaddr *)&data_address, &datalen) == 0) {
|
||||
dataport = ntohs(data_address.sin_port);
|
||||
memcpy(&netport[0], &dataport, 2);
|
||||
logger->print(LOGLEVEL_DEBUG, "D(%i) PASV initialized: %u.%u.%u.%u:%u", data_fd, server_address[0], server_address[1], server_address[2], server_address[3], dataport);
|
||||
logger->print(LOGLEVEL_DEBUG, "client {} initialized PASV on dataline {}: {}.{}.{}.{}:{}", control_sock, data_fd, server_address[0], server_address[1], server_address[2], server_address[3], dataport);
|
||||
} else {
|
||||
perror("pasv getpeername() failed");
|
||||
close(data_fd);
|
||||
@@ -248,7 +248,7 @@ public:
|
||||
submit(227, std::string(pasvok));
|
||||
free(pasvok);
|
||||
if ((data_sock = accept(data_fd, NULL, NULL)) >= 0) {
|
||||
logger->print(LOGLEVEL_INFO, "D(%i) PASV accepted: %i", data_fd, data_sock);
|
||||
logger->print(LOGLEVEL_INFO, "dataline {} PASV accepted on socket {}", data_fd, data_sock);
|
||||
|
||||
if (is_secure && protect_data) {
|
||||
if (!setupDataSSL()) {
|
||||
@@ -260,7 +260,7 @@ public:
|
||||
|
||||
state = FTP_STATE_ONDATA;
|
||||
} else {
|
||||
logger->print(LOGLEVEL_ERROR, "D(%i) PASV accept failed: %s", data_fd, strerror(errno));
|
||||
logger->print(LOGLEVEL_ERROR, "dataline {} PASV accept failed: {}", data_fd, strerror(errno));
|
||||
submit(425, "Can't open data connection");
|
||||
data_close();
|
||||
}
|
||||
@@ -408,7 +408,7 @@ public:
|
||||
// The socket is not ready, main loop will handle it
|
||||
return 0;
|
||||
}
|
||||
logger->print(LOGLEVEL_ERROR, "C(%i) SSL_write failed with error: %d", control_sock, err);
|
||||
logger->print(LOGLEVEL_ERROR, "client {} SSL_write failed with error: {}", control_sock, err);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
@@ -416,10 +416,10 @@ public:
|
||||
}
|
||||
|
||||
if (result >= 0) {
|
||||
logger->print(LOGLEVEL_DEBUG, "C(%i) << %s", control_sock, msg.c_str());
|
||||
logger->print(LOGLEVEL_DEBUG, "sent client {}: {}", control_sock, msg);
|
||||
return 0;
|
||||
}
|
||||
logger->print(LOGLEVEL_ERROR, "C(%i) !< %s", control_sock, msg.c_str());
|
||||
logger->print(LOGLEVEL_ERROR, "send to client {} failed: {}", control_sock, msg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -430,7 +430,7 @@ public:
|
||||
// Send through SSL if secure connection is established
|
||||
int written = SSL_write(control_ssl, response.c_str(), response.length());
|
||||
if (written <= 0) {
|
||||
logger->print(LOGLEVEL_ERROR, "C(%i) SSL_write failed", control_sock);
|
||||
logger->print(LOGLEVEL_ERROR, "client {} SSL_write failed", control_sock);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
@@ -438,7 +438,7 @@ public:
|
||||
send(control_sock, response.c_str(), response.length(), 0);
|
||||
}
|
||||
|
||||
logger->print(LOGLEVEL_DEBUG, "C(%i) << %d %s", control_sock, code, msg.c_str());
|
||||
logger->print(LOGLEVEL_DEBUG, "sent client {}: {} {}", control_sock, code, msg);
|
||||
}
|
||||
|
||||
void submit(int code, const std::vector<std::string>& msgs) {
|
||||
@@ -461,14 +461,14 @@ public:
|
||||
if (ssl_err == SSL_ERROR_WANT_WRITE || ssl_err == SSL_ERROR_WANT_READ) {
|
||||
continue; // Need to retry
|
||||
}
|
||||
logger->print(LOGLEVEL_DEBUG, "D(%i) SSL write error: %d", data_sock, ssl_err);
|
||||
logger->print(LOGLEVEL_DEBUG, "dataline {} SSL write error: {}", data_sock, ssl_err);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
bytes = send(data_sock, out + total_sent, size - total_sent, 0);
|
||||
if (bytes < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
logger->print(LOGLEVEL_DEBUG, "D(%i) !< Error: %s", data_sock, strerror(errno));
|
||||
logger->print(LOGLEVEL_DEBUG, "send to dataline {} error: {}", data_sock, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -479,7 +479,7 @@ public:
|
||||
|
||||
int data_close() {
|
||||
if (data_sock <= 0) return 0;
|
||||
logger->print(LOGLEVEL_DEBUG, "D(%i) Closing...", data_sock);
|
||||
logger->print(LOGLEVEL_DEBUG, "dataline {} closing...", data_sock);
|
||||
|
||||
if (data_ssl) {
|
||||
SSL_shutdown(data_ssl);
|
||||
@@ -546,19 +546,19 @@ private:
|
||||
bool setupControlSSL() {
|
||||
control_ssl = SSL_new(SSLManager::getInstance().getContext());
|
||||
if (!control_ssl) {
|
||||
logger->print(LOGLEVEL_ERROR, "C(%i) SSL_new failed", control_sock);
|
||||
logger->print(LOGLEVEL_ERROR, "client {} SSL_new failed", control_sock);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SSL_set_fd(control_ssl, control_sock)) {
|
||||
logger->print(LOGLEVEL_ERROR, "C(%i) SSL_set_fd failed", control_sock);
|
||||
logger->print(LOGLEVEL_ERROR, "client {} SSL_set_fd failed", control_sock);
|
||||
SSL_free(control_ssl);
|
||||
control_ssl = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
ssl_handshake_complete = false;
|
||||
logger->print(LOGLEVEL_DEBUG, "C(%i) SSL setup complete, handshake pending", control_sock);
|
||||
logger->print(LOGLEVEL_DEBUG, "waiting for client{} SSL handshake", control_sock);
|
||||
|
||||
// Cache the session after successful handshake
|
||||
if (cached_session) {
|
||||
@@ -575,7 +575,7 @@ private:
|
||||
|
||||
data_ssl = SSL_new(SSLManager::getInstance().getContext());
|
||||
if (!data_ssl) {
|
||||
logger->print(LOGLEVEL_ERROR, "C(%i) Data SSL_new failed", control_sock);
|
||||
logger->print(LOGLEVEL_ERROR, "dataline {} SSL_new failed", data_sock);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -586,7 +586,7 @@ private:
|
||||
|
||||
SSL_set_accept_state(data_ssl);
|
||||
if (!SSL_set_fd(data_ssl, data_sock)) {
|
||||
logger->print(LOGLEVEL_ERROR, "C(%i) Data SSL_set_fd failed", control_sock);
|
||||
logger->print(LOGLEVEL_ERROR, "dataline {} SSL_set_fd failed", data_sock);
|
||||
SSL_free(data_ssl);
|
||||
data_ssl = nullptr;
|
||||
return false;
|
||||
@@ -606,7 +606,7 @@ private:
|
||||
pfd.events = (ssl_err == SSL_ERROR_WANT_READ) ? POLLIN : POLLOUT;
|
||||
|
||||
if (poll(&pfd, 1, 1000) <= 0) {
|
||||
logger->print(LOGLEVEL_ERROR, "C(%i) Data SSL handshake timeout", control_sock);
|
||||
logger->print(LOGLEVEL_ERROR, "dataline {} SSL handshake timeout", data_sock);
|
||||
SSL_free(data_ssl);
|
||||
data_ssl = nullptr;
|
||||
return false;
|
||||
@@ -614,7 +614,7 @@ private:
|
||||
continue;
|
||||
}
|
||||
|
||||
logger->print(LOGLEVEL_ERROR, "C(%i) Data SSL handshake failed: %s",
|
||||
logger->print(LOGLEVEL_ERROR, "dataline {} SSL handshake failed: {}",
|
||||
control_sock, ERR_error_string(ERR_get_error(), nullptr));
|
||||
SSL_free(data_ssl);
|
||||
data_ssl = nullptr;
|
||||
@@ -626,32 +626,30 @@ private:
|
||||
|
||||
// Log whether session was reused
|
||||
if (SSL_session_reused(data_ssl)) {
|
||||
logger->print(LOGLEVEL_DEBUG, "C(%i) Data SSL session resumed", control_sock);
|
||||
logger->print(LOGLEVEL_DEBUG, "dataline {} SSL session resumed", data_sock);
|
||||
} else {
|
||||
logger->print(LOGLEVEL_DEBUG, "C(%i) Data SSL new session", control_sock);
|
||||
logger->print(LOGLEVEL_DEBUG, "dataline {} SSL new session", data_sock);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void authedInit() {
|
||||
logger->print(LOGLEVEL_INFO, "C(%i) logging in as '%s'", control_sock, auth_data->username);
|
||||
struct file_data fd;
|
||||
std::string root;
|
||||
std::string home = "/";
|
||||
std::vector<std::string> auth_response;
|
||||
if (auth->isChroot()) {
|
||||
root = std::string(this->auth_data->home_dir);
|
||||
logger->print(LOGLEVEL_INFO, "C(%i) Set chrooted root of '%s' to '%s'", control_sock, auth_data->username, root.c_str());
|
||||
} else {
|
||||
root = "/";
|
||||
home = std::string(this->auth_data->home_dir);
|
||||
logger->print(LOGLEVEL_INFO, "C(%i) Set home of '%s' to '%s'", control_sock, auth_data->username, home.c_str());
|
||||
}
|
||||
if (
|
||||
((struct file_data)filer->setRoot(root)).error.code == 0 &&
|
||||
((struct file_data)filer->setCWD(home)).error.code == 0
|
||||
) {
|
||||
logger->print(LOGLEVEL_DEBUG, "authenticated {} on client {} with root '{}' and home '{}'", auth_data->username, control_sock, root, home);
|
||||
state = FTP_STATE_AUTHED;
|
||||
auth_response.push_back("Login OK");
|
||||
std::string user_motd = getMotD();
|
||||
@@ -662,6 +660,7 @@ private:
|
||||
auth_response.push_back(line);
|
||||
}
|
||||
}
|
||||
logger->print(LOGLEVEL_INFO, "user '{}' logged in on client {}", auth_data->username, control_sock);
|
||||
submit(230, auth_response);
|
||||
return;
|
||||
}
|
||||
@@ -685,7 +684,7 @@ private:
|
||||
|
||||
FILE* pipe = popen(cmd.c_str(), "r");
|
||||
if (!pipe) {
|
||||
logger->print(LOGLEVEL_ERROR, "Failed to execute MOTD command: %s", cmd.c_str());
|
||||
logger->print(LOGLEVEL_ERROR, "motd command failed: {}", cmd);
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -702,7 +701,7 @@ private:
|
||||
|
||||
std::ifstream file(path);
|
||||
if (!file) {
|
||||
logger->print(LOGLEVEL_ERROR, "Failed to open MOTD file: %s", path.c_str());
|
||||
logger->print(LOGLEVEL_ERROR, "failed to open motd file: {}", path);
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
34
src/logger.h
34
src/logger.h
@@ -8,7 +8,7 @@
|
||||
#include <mutex>
|
||||
#include <map>
|
||||
|
||||
#define LOGLEVEL_CONSOLE 5
|
||||
#define LOGLEVEL_MIN 10
|
||||
#define LOGLEVEL_CRITICAL 4
|
||||
#define LOGLEVEL_ERROR 3
|
||||
#define LOGLEVEL_WARNING 2
|
||||
@@ -28,16 +28,31 @@ public:
|
||||
logfiles[level] = std::ofstream(path, std::ios::binary|std::ios::app);
|
||||
}
|
||||
|
||||
template<class... Args>
|
||||
void print(int level, const char* message, Args... args) {
|
||||
void setConsoleLevel(int level) {
|
||||
this->console_level = level;
|
||||
}
|
||||
|
||||
void print(int level, std::string message) {
|
||||
std::lock_guard<std::mutex> lock(log_mutex);
|
||||
char* prepared;
|
||||
asprintf(&prepared, "[%s] (%c) %s\n", getTime(), logTypeChar(level), message);
|
||||
char* formatted;
|
||||
asprintf(&formatted, prepared, args...);
|
||||
fprintf(stdout, formatted);
|
||||
|
||||
std::string output = std::format("[{}] ({}) {}\n", getTime(), logTypeChar(level), message);
|
||||
|
||||
if (level >= console_level) std::cout << output;
|
||||
if (logMutex.try_lock() && logfiles[level].is_open()) {
|
||||
logfiles[level].write(formatted, strlen(formatted));
|
||||
logfiles[level].write(output.c_str(), output.length());
|
||||
logfiles[level].flush();
|
||||
logMutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
template<class... Args>
|
||||
void print(int level, std::format_string<Args...> message, Args... args) {
|
||||
std::lock_guard<std::mutex> lock(log_mutex);
|
||||
std::string formatted = std::vformat(message.get(), std::make_format_args(args...));
|
||||
std::string output = std::format("[{}] ({}) {}\n", getTime(), logTypeChar(level), formatted);
|
||||
if (level >= console_level) std::cout << output;
|
||||
if (logMutex.try_lock() && logfiles[level].is_open()) {
|
||||
logfiles[level].write(output.c_str(), output.length());
|
||||
logfiles[level].flush();
|
||||
logMutex.unlock();
|
||||
}
|
||||
@@ -50,6 +65,7 @@ public:
|
||||
}
|
||||
private:
|
||||
std::map<int, std::ofstream> logfiles;
|
||||
int console_level = LOGLEVEL_MIN;
|
||||
|
||||
static const char* getTime() {
|
||||
time_t rawtime;
|
||||
|
||||
477
src/main.cpp
477
src/main.cpp
@@ -8,6 +8,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <csignal>
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
#include <system_error>
|
||||
@@ -33,198 +34,23 @@ struct ftpconn {
|
||||
bool close = false;
|
||||
} fdc[MAX_CLIENTS];
|
||||
|
||||
void runClient(struct ftpconn* cfd) {
|
||||
if (!cfd) {
|
||||
logger->print(LOGLEVEL_ERROR, "Invalid connection handle");
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> lock(client_mutex);
|
||||
if (!cfd->client) {
|
||||
logger->print(LOGLEVEL_ERROR, "Invalid client handle");
|
||||
return;
|
||||
}
|
||||
|
||||
int client_sock = cfd->client->control_sock;
|
||||
Client* client = cfd->client;
|
||||
lock.unlock();
|
||||
|
||||
char inbuf[BUFFERSIZE];
|
||||
logger->print(LOGLEVEL_DEBUG, "C(%i) Client initialized", client_sock);
|
||||
|
||||
while (true) {
|
||||
memset(inbuf, 0, BUFFERSIZE);
|
||||
|
||||
if (fcntl(client_sock, F_GETFD) < 0) {
|
||||
logger->print(LOGLEVEL_DEBUG, "C(%i) Socket closed", client_sock);
|
||||
break;
|
||||
}
|
||||
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 60;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
fd_set readfds, writefds;
|
||||
FD_ZERO(&readfds);
|
||||
FD_ZERO(&writefds);
|
||||
FD_SET(client_sock, &readfds);
|
||||
|
||||
// Add socket to writefds if SSL wants to write
|
||||
if (client->isSecure() && client->getSSL()) {
|
||||
FD_SET(client_sock, &writefds);
|
||||
}
|
||||
|
||||
int select_result = select(client_sock + 1, &readfds, &writefds, NULL, &tv);
|
||||
if (select_result < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
logger->print(LOGLEVEL_ERROR, "C(%i) Select failed: %s", client_sock, strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
||||
if (select_result == 0) {
|
||||
logger->print(LOGLEVEL_DEBUG, "C(%i) Connection timeout", client_sock);
|
||||
break;
|
||||
}
|
||||
|
||||
int rc;
|
||||
if (client->isSecure() && client->getSSL()) {
|
||||
if (!client->isHandshakeComplete()) {
|
||||
// Continue SSL handshake
|
||||
ERR_clear_error(); // Clear any previous errors
|
||||
int ret = SSL_accept(client->getSSL());
|
||||
if (ret <= 0) {
|
||||
int ssl_err = SSL_get_error(client->getSSL(), ret);
|
||||
if (ssl_err == SSL_ERROR_WANT_READ || ssl_err == SSL_ERROR_WANT_WRITE) {
|
||||
continue; // Need more data for handshake
|
||||
}
|
||||
unsigned long err = ERR_get_error();
|
||||
char err_buf[256];
|
||||
ERR_error_string_n(err, err_buf, sizeof(err_buf));
|
||||
logger->print(LOGLEVEL_ERROR, "C(%i) SSL handshake failed with error: %d (%s)",
|
||||
client_sock, ssl_err, err_buf);
|
||||
break;
|
||||
}
|
||||
client->setHandshakeComplete(true);
|
||||
logger->print(LOGLEVEL_DEBUG, "C(%i) SSL handshake completed", client_sock);
|
||||
continue;
|
||||
} else {
|
||||
// Normal SSL read after handshake
|
||||
ERR_clear_error(); // Clear any previous errors
|
||||
rc = SSL_read(client->getSSL(), inbuf, sizeof(inbuf) - 1);
|
||||
if (rc <= 0) {
|
||||
int ssl_err = SSL_get_error(client->getSSL(), rc);
|
||||
if (ssl_err == SSL_ERROR_WANT_READ || ssl_err == SSL_ERROR_WANT_WRITE) {
|
||||
continue;
|
||||
}
|
||||
if (ssl_err == SSL_ERROR_SYSCALL) {
|
||||
unsigned long err = ERR_get_error();
|
||||
if (err == 0 && rc == 0) {
|
||||
logger->print(LOGLEVEL_DEBUG, "C(%i) SSL connection closed", client_sock);
|
||||
} else {
|
||||
char err_buf[256];
|
||||
ERR_error_string_n(err, err_buf, sizeof(err_buf));
|
||||
logger->print(LOGLEVEL_ERROR, "C(%i) SSL_read syscall error: %s",
|
||||
client_sock, err_buf);
|
||||
}
|
||||
} else {
|
||||
unsigned long err = ERR_get_error();
|
||||
char err_buf[256];
|
||||
ERR_error_string_n(err, err_buf, sizeof(err_buf));
|
||||
logger->print(LOGLEVEL_ERROR, "C(%i) SSL_read failed with error: %d (%s)",
|
||||
client_sock, ssl_err, err_buf);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rc = recv(client_sock, inbuf, sizeof(inbuf) - 1, 0);
|
||||
if (rc <= 0) {
|
||||
if (rc == 0) {
|
||||
logger->print(LOGLEVEL_DEBUG, "C(%i) Client disconnected", client_sock);
|
||||
} else {
|
||||
logger->print(LOGLEVEL_ERROR, "C(%i) Recv failed: %s", client_sock, strerror(errno));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inbuf[rc] = '\0';
|
||||
if (rc >= 2 && inbuf[rc-2] == '\r' && inbuf[rc-1] == '\n') {
|
||||
rc -= 2;
|
||||
inbuf[rc] = '\0';
|
||||
}
|
||||
|
||||
std::string input(inbuf, rc);
|
||||
logger->print(LOGLEVEL_DEBUG, "C(%i) >> %s", client_sock, input.c_str());
|
||||
|
||||
std::string::size_type space_pos = input.find(" ");
|
||||
std::string cmd = space_pos != std::string::npos ?
|
||||
toUpper(input.substr(0, space_pos)) : toUpper(input);
|
||||
std::string args = space_pos != std::string::npos ?
|
||||
input.substr(space_pos + 1) : "";
|
||||
|
||||
lock.lock();
|
||||
if (!cfd->client) {
|
||||
lock.unlock();
|
||||
break;
|
||||
}
|
||||
|
||||
int revc = client->receive(cmd, args);
|
||||
lock.unlock();
|
||||
|
||||
if (revc != 0) break;
|
||||
}
|
||||
|
||||
// Mark for cleanup
|
||||
logger->print(LOGLEVEL_DEBUG, "C(%i) Client thread ending", client_sock);
|
||||
cfd->close = true;
|
||||
}
|
||||
|
||||
void initializePlugins() {
|
||||
std::string plugin_dir = config->getValue("core", "plugin_path", PLUGIN_DIR);
|
||||
|
||||
auto& auth_manager = PluginManager<Auth>::getInstance();
|
||||
auto& filer_manager = PluginManager<Filer>::getInstance();
|
||||
|
||||
auth_manager.setLogger(logger);
|
||||
filer_manager.setLogger(logger);
|
||||
|
||||
// Try loading all plugins into both managers
|
||||
for (const auto& entry : std::filesystem::directory_iterator(plugin_dir)) {
|
||||
if (entry.path().extension() == ".so") {
|
||||
logger->print(LOGLEVEL_DEBUG, "Loading plugin: %s", entry.path().c_str());
|
||||
auth_manager.loadPlugin(entry.path().string());
|
||||
filer_manager.loadPlugin(entry.path().string());
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize auth
|
||||
std::string auth_type = config->getValue("engines", "auth", "pam");
|
||||
auth = auth_manager.createPlugin(auth_type, config->get(auth_type)->get());
|
||||
|
||||
if (!auth) {
|
||||
logger->print(LOGLEVEL_CRITICAL, "Failed to create auth engine: %s", auth_type.c_str());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Initialize filer
|
||||
std::string filer_type = config->getValue("engines", "filer", "local");
|
||||
default_filer_name = filer_type;
|
||||
default_filer_factory = filer_manager.getFactory(filer_type);
|
||||
|
||||
if (!default_filer_factory) {
|
||||
logger->print(LOGLEVEL_CRITICAL, "Failed to get filer factory for type: %s", filer_type.c_str());
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
void runClient(struct ftpconn* cfd);
|
||||
void initializePlugins();
|
||||
void shutdown(int signum);
|
||||
|
||||
int main(int argc , char *argv[]) {
|
||||
printf("%s %s Copyright (C) 2024 Worlio LLC\n", APPNAME, VERSION);
|
||||
printf("This program comes with ABSOLUTELY NO WARRANTY.\n");
|
||||
printf("This is free software, and you are welcome to redistribute it under certain conditions.\n\n");
|
||||
std::cout <<
|
||||
std::format(
|
||||
"{} {} Maintained by Worlio LLC 2024-2025\n"
|
||||
"This program comes with ABSOLUTELY NO WARRANTY.\n"
|
||||
"This is free software, and you are welcome to redistribute it under certain conditions.\n\n",
|
||||
APPNAME,
|
||||
VERSION
|
||||
);
|
||||
|
||||
// SIGNALS
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
std::signal(SIGINT, shutdown);
|
||||
|
||||
config = new ConfigFile(concatPath(std::string(CONFIG_DIR), "ftp.conf"));
|
||||
server_name = config->getValue("core", "server_name", "%a %v");
|
||||
@@ -249,17 +75,37 @@ int main(int argc , char *argv[]) {
|
||||
logger->openFileOnLevel(LOGLEVEL_ERROR, config->getValue("logging", "error", mainLogFile).c_str());
|
||||
logger->openFileOnLevel(LOGLEVEL_CRITICAL, config->getValue("logging", "critical", mainLogFile).c_str());
|
||||
|
||||
std::string console_loglevel_string = config->getValue("logging", "console", "all");
|
||||
if (console_loglevel_string == "all")
|
||||
logger->setConsoleLevel(LOGLEVEL_MAX);
|
||||
else if (console_loglevel_string == "debug")
|
||||
logger->setConsoleLevel(LOGLEVEL_DEBUG);
|
||||
else if (console_loglevel_string == "info")
|
||||
logger->setConsoleLevel(LOGLEVEL_INFO);
|
||||
else if (console_loglevel_string == "warning")
|
||||
logger->setConsoleLevel(LOGLEVEL_WARNING);
|
||||
else if (console_loglevel_string == "error")
|
||||
logger->setConsoleLevel(LOGLEVEL_ERROR);
|
||||
else if (console_loglevel_string == "critical")
|
||||
logger->setConsoleLevel(LOGLEVEL_CRITICAL);
|
||||
else if (console_loglevel_string == "none")
|
||||
logger->setConsoleLevel(LOGLEVEL_MIN);
|
||||
else {
|
||||
logger->setConsoleLevel(LOGLEVEL_MIN);
|
||||
logger->print(LOGLEVEL_ERROR, "Could not determine console log type.");
|
||||
}
|
||||
|
||||
bool ssl_enable = config->getBool("net", "ssl", true);
|
||||
bool ssl_flags = SSL_OP_NO_TICKET;
|
||||
if (ssl_enable) {
|
||||
std::string cert_file = config->getValue("ssl", "certificate", "cert.pem");
|
||||
if (cert_file[0] != '/')
|
||||
cert_file = concatPath(std::string(CONFIG_DIR), cert_file);
|
||||
logger->print(LOGLEVEL_INFO, "Using certificate file: %s", cert_file.c_str());
|
||||
logger->print(LOGLEVEL_INFO, "Using certificate file: {}", cert_file);
|
||||
std::string key_file = config->getValue("ssl", "private_key", "key.pem");
|
||||
if (key_file[0] != '/')
|
||||
key_file = concatPath(std::string(CONFIG_DIR), key_file);
|
||||
logger->print(LOGLEVEL_INFO, "Using private key file: %s", key_file.c_str());
|
||||
logger->print(LOGLEVEL_INFO, "Using private key file: {}", key_file);
|
||||
if (!SSLManager::getInstance().initialize(cert_file, key_file)) {
|
||||
logger->print(LOGLEVEL_CRITICAL, "Failed to initialize SSL");
|
||||
return 1;
|
||||
@@ -338,11 +184,11 @@ int main(int argc , char *argv[]) {
|
||||
if ((src = bind(master_socket, (struct sockaddr *)&ctrl_address, sizeof(ctrl_address))) < 0) {
|
||||
logger->print(
|
||||
LOGLEVEL_CRITICAL,
|
||||
"Bind to %i.%i.%i.%i:%i failed",
|
||||
&server_address[0],
|
||||
&server_address[1],
|
||||
&server_address[2],
|
||||
&server_address[3],
|
||||
"Bind to {}.{}.{}.{}:{} failed",
|
||||
static_cast<unsigned int>(server_address[0]),
|
||||
static_cast<unsigned int>(server_address[1]),
|
||||
static_cast<unsigned int>(server_address[2]),
|
||||
static_cast<unsigned int>(server_address[3]),
|
||||
server_port
|
||||
);
|
||||
close(master_socket);
|
||||
@@ -381,7 +227,7 @@ int main(int argc , char *argv[]) {
|
||||
// Handle poll errors properly without skipping cleanup
|
||||
if (fds[i].revents != POLLIN) {
|
||||
if (fds[i].fd != master_socket) {
|
||||
logger->print(LOGLEVEL_ERROR, "Poll error on fd %d", fds[i].fd);
|
||||
logger->print(LOGLEVEL_ERROR, "net: poll error on fd {}", fds[i].fd);
|
||||
fdc[i].close = true;
|
||||
}
|
||||
}
|
||||
@@ -392,7 +238,7 @@ int main(int argc , char *argv[]) {
|
||||
newsock = accept(master_socket, NULL, NULL);
|
||||
if (newsock < 0) {
|
||||
if (errno != EWOULDBLOCK) {
|
||||
logger->print(LOGLEVEL_ERROR, "accept() failed: %s", strerror(errno));
|
||||
logger->print(LOGLEVEL_ERROR, "net: accept() failed: {}", strerror(errno));
|
||||
runServer = false;
|
||||
}
|
||||
break;
|
||||
@@ -417,7 +263,7 @@ int main(int argc , char *argv[]) {
|
||||
int flags = fcntl(newsock, F_GETFL, 0);
|
||||
fcntl(newsock, F_SETFL, flags | O_NONBLOCK);
|
||||
|
||||
logger->print(LOGLEVEL_DEBUG, "C(%i) Accepted client in slot %d", newsock, slot);
|
||||
logger->print(LOGLEVEL_DEBUG, "client {} accepted in slot {}", newsock, slot);
|
||||
|
||||
fds[slot].fd = newsock;
|
||||
fds[slot].events = POLLIN;
|
||||
@@ -439,7 +285,7 @@ int main(int argc , char *argv[]) {
|
||||
// Handle cleanup for any connections marked for closing
|
||||
if (fds[i].fd != master_socket && (fdc[i].close || fds[i].revents != POLLIN)) {
|
||||
int fd = fds[i].fd;
|
||||
logger->print(LOGLEVEL_DEBUG, "C(%i) Cleaning up client in slot %d", fd, i);
|
||||
logger->print(LOGLEVEL_DEBUG, "cleaning up client {} from slot {}", fd, i);
|
||||
|
||||
// Close socket
|
||||
if (fd > 0) {
|
||||
@@ -464,8 +310,6 @@ int main(int argc , char *argv[]) {
|
||||
fds[i].revents = 0;
|
||||
memset(&fdc[i], 0, sizeof(struct ftpconn));
|
||||
|
||||
logger->print(LOGLEVEL_DEBUG, "C(%i) Cleanup completed", fd);
|
||||
|
||||
// Recalculate nfds if needed
|
||||
if (i == nfds - 1) {
|
||||
for (int j = nfds - 1; j >= 0; j--) {
|
||||
@@ -478,21 +322,234 @@ int main(int argc , char *argv[]) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger->print(LOGLEVEL_INFO, "Server closing...");
|
||||
close(master_socket);
|
||||
for (int i = 0; i < current_size; i++) {
|
||||
if (fds[i].fd != master_socket) {
|
||||
int fd = fds[i].fd;
|
||||
|
||||
logger->print(LOGLEVEL_DEBUG, "disconnecting client {} from slot {}", fd, i);
|
||||
|
||||
// Cleanup
|
||||
for (int i = 0; i < nfds; i++) {
|
||||
if (fds[i].fd >= 0) {
|
||||
close(fds[i].fd);
|
||||
if (fdc[i].thread && fdc[i].thread->joinable()) {
|
||||
fdc[i].thread->join();
|
||||
if (fd > 0) {
|
||||
shutdown(fd, SHUT_RDWR);
|
||||
close(fd);
|
||||
}
|
||||
delete fdc[i].thread;
|
||||
|
||||
if (fdc[i].thread) {
|
||||
if (fdc[i].thread->joinable()) {
|
||||
fdc[i].thread->join();
|
||||
}
|
||||
delete fdc[i].thread;
|
||||
}
|
||||
// Clean up client
|
||||
delete fdc[i].client;
|
||||
|
||||
// Reset slot
|
||||
fds[i].fd = -1;
|
||||
fds[i].events = 0;
|
||||
fds[i].revents = 0;
|
||||
memset(&fdc[i], 0, sizeof(struct ftpconn));
|
||||
|
||||
if (i == nfds - 1) {
|
||||
for (int j = nfds - 1; j >= 0; j--) {
|
||||
if (fds[j].fd != -1) {
|
||||
nfds = j + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
close(master_socket);
|
||||
logger->print(LOGLEVEL_INFO, "Server closing...");
|
||||
logger->close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void initializePlugins() {
|
||||
std::string plugin_dir = config->getValue("core", "plugin_path", PLUGIN_DIR);
|
||||
|
||||
auto& auth_manager = PluginManager<Auth>::getInstance();
|
||||
auto& filer_manager = PluginManager<Filer>::getInstance();
|
||||
|
||||
auth_manager.setLogger(logger);
|
||||
filer_manager.setLogger(logger);
|
||||
|
||||
// Try loading all plugins into both managers
|
||||
for (const auto& entry : std::filesystem::directory_iterator(plugin_dir)) {
|
||||
if (entry.path().extension() == ".so") {
|
||||
logger->print(LOGLEVEL_DEBUG, "Loading plugin: {}", entry.path().string());
|
||||
auth_manager.loadPlugin(entry.path().string());
|
||||
filer_manager.loadPlugin(entry.path().string());
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize auth
|
||||
std::string auth_type = config->getValue("engines", "auth", "pam");
|
||||
auth = auth_manager.createPlugin(auth_type, config->get(auth_type)->get());
|
||||
|
||||
if (!auth) {
|
||||
logger->print(LOGLEVEL_CRITICAL, "Failed to create auth engine: {}", auth_type);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Initialize filer
|
||||
std::string filer_type = config->getValue("engines", "filer", "local");
|
||||
default_filer_name = filer_type;
|
||||
default_filer_factory = filer_manager.getFactory(filer_type);
|
||||
|
||||
if (!default_filer_factory) {
|
||||
logger->print(LOGLEVEL_CRITICAL, "Failed to get filer factory for type {}", filer_type);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void runClient(struct ftpconn* cfd) {
|
||||
if (!cfd) {
|
||||
logger->print(LOGLEVEL_ERROR, "Invalid connection handle");
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> lock(client_mutex);
|
||||
if (!cfd->client) {
|
||||
logger->print(LOGLEVEL_ERROR, "Invalid client handle");
|
||||
return;
|
||||
}
|
||||
|
||||
int client_sock = cfd->client->control_sock;
|
||||
Client* client = cfd->client;
|
||||
lock.unlock();
|
||||
|
||||
char inbuf[BUFFERSIZE];
|
||||
logger->print(LOGLEVEL_DEBUG, "client {} initialized", client_sock);
|
||||
|
||||
while (!cfd->close) {
|
||||
memset(inbuf, 0, BUFFERSIZE);
|
||||
|
||||
if (fcntl(client_sock, F_GETFD) < 0) {
|
||||
logger->print(LOGLEVEL_DEBUG, "closed client {} socket", client_sock);
|
||||
break;
|
||||
}
|
||||
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 60;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
fd_set readfds, writefds;
|
||||
FD_ZERO(&readfds);
|
||||
FD_ZERO(&writefds);
|
||||
FD_SET(client_sock, &readfds);
|
||||
|
||||
// Add socket to writefds if SSL wants to write
|
||||
if (client->isSecure() && client->getSSL()) {
|
||||
FD_SET(client_sock, &writefds);
|
||||
}
|
||||
|
||||
int select_result = select(client_sock + 1, &readfds, &writefds, NULL, &tv);
|
||||
if (select_result < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
logger->print(LOGLEVEL_ERROR, "client {} experienced select fail: %s", client_sock, strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
||||
if (select_result == 0) {
|
||||
logger->print(LOGLEVEL_INFO, "client {} timeout", client_sock);
|
||||
break;
|
||||
}
|
||||
|
||||
int rc;
|
||||
if (client->isSecure() && client->getSSL()) {
|
||||
if (!client->isHandshakeComplete()) {
|
||||
// Continue SSL handshake
|
||||
ERR_clear_error(); // Clear any previous errors
|
||||
int ret = SSL_accept(client->getSSL());
|
||||
if (ret <= 0) {
|
||||
int ssl_err = SSL_get_error(client->getSSL(), ret);
|
||||
if (ssl_err == SSL_ERROR_WANT_READ || ssl_err == SSL_ERROR_WANT_WRITE) {
|
||||
continue; // Need more data for handshake
|
||||
}
|
||||
unsigned long err = ERR_get_error();
|
||||
char err_buf[256];
|
||||
ERR_error_string_n(err, err_buf, sizeof(err_buf));
|
||||
logger->print(LOGLEVEL_ERROR, "client {} SSL handshake failed with error: {} ({})",
|
||||
client_sock, ssl_err, err_buf);
|
||||
break;
|
||||
}
|
||||
client->setHandshakeComplete(true);
|
||||
logger->print(LOGLEVEL_DEBUG, "client {} SSL handshake completed", client_sock);
|
||||
continue;
|
||||
} else {
|
||||
// Normal SSL read after handshake
|
||||
ERR_clear_error(); // Clear any previous errors
|
||||
rc = SSL_read(client->getSSL(), inbuf, sizeof(inbuf) - 1);
|
||||
if (rc <= 0) {
|
||||
int ssl_err = SSL_get_error(client->getSSL(), rc);
|
||||
if (ssl_err == SSL_ERROR_WANT_READ || ssl_err == SSL_ERROR_WANT_WRITE) {
|
||||
continue;
|
||||
}
|
||||
if (ssl_err == SSL_ERROR_SYSCALL) {
|
||||
unsigned long err = ERR_get_error();
|
||||
if (err == 0 && rc == 0) {
|
||||
logger->print(LOGLEVEL_DEBUG, "client {} SSL connection closed", client_sock);
|
||||
} else {
|
||||
char err_buf[256];
|
||||
ERR_error_string_n(err, err_buf, sizeof(err_buf));
|
||||
logger->print(LOGLEVEL_ERROR, "client {} experienced SSL_read syscall error: {}",
|
||||
client_sock, err_buf);
|
||||
}
|
||||
} else {
|
||||
unsigned long err = ERR_get_error();
|
||||
char err_buf[256];
|
||||
ERR_error_string_n(err, err_buf, sizeof(err_buf));
|
||||
logger->print(LOGLEVEL_ERROR, "client {} experienced SSL_read error: {} ({})",
|
||||
client_sock, ssl_err, err_buf);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rc = recv(client_sock, inbuf, sizeof(inbuf) - 1, 0);
|
||||
if (rc <= 0) {
|
||||
if (rc == 0) {
|
||||
logger->print(LOGLEVEL_DEBUG, "client {} disconnected", client_sock);
|
||||
} else {
|
||||
logger->print(LOGLEVEL_ERROR, "recieve from client {} failed: {}", client_sock, strerror(errno));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
inbuf[rc] = '\0';
|
||||
if (rc >= 2 && inbuf[rc-2] == '\r' && inbuf[rc-1] == '\n') {
|
||||
rc -= 2;
|
||||
inbuf[rc] = '\0';
|
||||
}
|
||||
|
||||
std::string input(inbuf, rc);
|
||||
logger->print(LOGLEVEL_DEBUG, "recieved from client {}: {}", client_sock, input);
|
||||
|
||||
std::string::size_type space_pos = input.find(" ");
|
||||
std::string cmd = space_pos != std::string::npos ?
|
||||
toUpper(input.substr(0, space_pos)) : toUpper(input);
|
||||
std::string args = space_pos != std::string::npos ?
|
||||
input.substr(space_pos + 1) : "";
|
||||
|
||||
lock.lock();
|
||||
if (!cfd->client) {
|
||||
lock.unlock();
|
||||
break;
|
||||
}
|
||||
|
||||
int revc = client->receive(cmd, args);
|
||||
lock.unlock();
|
||||
|
||||
if (revc != 0) break;
|
||||
}
|
||||
|
||||
// Mark for cleanup
|
||||
logger->print(LOGLEVEL_DEBUG, "client {} thread ending", client_sock);
|
||||
cfd->close = true;
|
||||
}
|
||||
|
||||
void shutdown(int signum) {
|
||||
runServer = false;
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
#define PLUGIN_H
|
||||
|
||||
#include <string>
|
||||
#include <format>
|
||||
#include "logger.h"
|
||||
|
||||
typedef int (*GetAPIVersionFunc)();
|
||||
@@ -11,7 +12,7 @@ typedef const char* (*GetPluginTypeFunc)();
|
||||
class IPlugin {
|
||||
public:
|
||||
virtual ~IPlugin() = default;
|
||||
static void setLogger(Logger* log) { logger = log; }
|
||||
static void setLogger(Logger* _logger) { logger = _logger; }
|
||||
protected:
|
||||
static Logger* logger;
|
||||
};
|
||||
@@ -44,7 +45,7 @@ struct PluginTraits {
|
||||
const char* getPluginDescription() { return description; } \
|
||||
const char* getPluginVersion() { return version; } \
|
||||
int getAPIVersion() { return PluginTraits<BaseClass>::API_VERSION; } \
|
||||
void setLogger(Logger* log) { IPlugin::setLogger(log); } \
|
||||
void setLogger(Logger* _logger) { IPlugin::setLogger(_logger); } \
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -32,15 +32,15 @@ public:
|
||||
if (plugin) plugin->initialize(config);
|
||||
return plugin;
|
||||
}
|
||||
if (logger) logger->print(LOGLEVEL_ERROR, "Plugin type '%s' not found", type.c_str());
|
||||
if (logger) logger->print(LOGLEVEL_ERROR, "plugin type '{}' not found", type);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool loadPlugin(const std::string& path) {
|
||||
void* handle = dlopen(path.c_str(), RTLD_LAZY);
|
||||
if (!handle) {
|
||||
if (logger) logger->print(LOGLEVEL_ERROR, "Failed to load plugin %s: %s",
|
||||
path.c_str(), dlerror());
|
||||
if (logger) logger->print(LOGLEVEL_ERROR, "failed to load {}: {}",
|
||||
path, dlerror());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ public:
|
||||
|
||||
// Check if already loaded
|
||||
if (plugins.find(plugin_name) != plugins.end()) {
|
||||
if (logger) logger->print(LOGLEVEL_DEBUG, "Plugin %s is already loaded", plugin_name.c_str());
|
||||
if (logger) logger->print(LOGLEVEL_DEBUG, "Plugin {} is already loaded", plugin_name);
|
||||
dlclose(handle);
|
||||
return true;
|
||||
}
|
||||
@@ -87,9 +87,8 @@ public:
|
||||
get_api_version, setLogger, handle);
|
||||
|
||||
plugins[plugin_name] = plugin_info;
|
||||
if (logger) logger->print(LOGLEVEL_INFO, "Loaded plugin: %s v%s (%s interface)",
|
||||
plugin_name.c_str(), plugin_info.version.c_str(),
|
||||
PluginTraits<T>::interfaceName());
|
||||
if (logger) logger->print(LOGLEVEL_INFO, "Loaded {} plugin: {} v{}",
|
||||
PluginTraits<T>::interfaceName(), plugin_name, plugin_info.version);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -98,14 +97,13 @@ public:
|
||||
if (it != plugins.end()) {
|
||||
return it->second.create;
|
||||
}
|
||||
if (logger) logger->print(LOGLEVEL_ERROR, "Plugin type '%s' not found", type.c_str());
|
||||
if (logger) logger->print(LOGLEVEL_ERROR, "plugin type '{}' not found", type);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void unloadPlugins() {
|
||||
if (logger) logger->print(LOGLEVEL_DEBUG, "Unloading all plugins");
|
||||
for (auto& pair : plugins) {
|
||||
if (logger) logger->print(LOGLEVEL_DEBUG, "Unloading plugin: %s", pair.first.c_str());
|
||||
if (logger) logger->print(LOGLEVEL_DEBUG, "unloading plugin: {}", pair.first);
|
||||
dlclose(pair.second.handle);
|
||||
}
|
||||
plugins.clear();
|
||||
@@ -139,7 +137,7 @@ private:
|
||||
!get_name ? "getPluginName" :
|
||||
!get_desc ? "getPluginDescription" :
|
||||
"getPluginVersion";
|
||||
logger->print(LOGLEVEL_ERROR, "Missing required function: %s", missing);
|
||||
logger->print(LOGLEVEL_ERROR, "missing required function: {}", missing);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -150,8 +148,8 @@ private:
|
||||
if (version != PluginTraits<T>::API_VERSION) {
|
||||
if (logger) {
|
||||
logger->print(LOGLEVEL_ERROR,
|
||||
"Incompatible plugin API version in %s (got %d, expected %d)",
|
||||
path.c_str(), version, PluginTraits<T>::API_VERSION);
|
||||
"incompatible plugin API version in {} (got {}, expected {})",
|
||||
path, version, PluginTraits<T>::API_VERSION);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ public:
|
||||
|
||||
virtual bool authenticate(ClientAuthDetails* auth_data) override {
|
||||
if (!auth_data || !auth_data->username[0] || !auth_data->password[0]) {
|
||||
logger->print(LOGLEVEL_ERROR, "auth_pam: Cannot use empty auth data");
|
||||
logger->print(LOGLEVEL_ERROR, "cannot use empty auth data");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ public:
|
||||
// Start PAM session
|
||||
int retval = pam_start(service_name.c_str(), auth_data->username, &conv, &pamh);
|
||||
if (retval != PAM_SUCCESS) {
|
||||
logger->print(LOGLEVEL_ERROR, "auth_pam: Failed to start PAM: %s",
|
||||
logger->print(LOGLEVEL_ERROR, "failed to start PAM: {}",
|
||||
pamh ? pam_strerror(pamh, retval) : "Unknown error");
|
||||
if (pamh) pam_end(pamh, retval);
|
||||
return false;
|
||||
@@ -85,7 +85,7 @@ public:
|
||||
// Authenticate user
|
||||
retval = pam_authenticate(pamh, 0);
|
||||
if (retval != PAM_SUCCESS) {
|
||||
logger->print(LOGLEVEL_ERROR, "auth_pam: Authentication failed: %s",
|
||||
logger->print(LOGLEVEL_ERROR, "authentication failed: {}",
|
||||
pam_strerror(pamh, retval));
|
||||
pam_end(pamh, retval);
|
||||
return false;
|
||||
@@ -94,7 +94,7 @@ public:
|
||||
// Check account validity
|
||||
retval = pam_acct_mgmt(pamh, 0);
|
||||
if (retval != PAM_SUCCESS) {
|
||||
logger->print(LOGLEVEL_ERROR, "auth_pam: Account validation failed: %s",
|
||||
logger->print(LOGLEVEL_ERROR, "account validation failed: {}",
|
||||
pam_strerror(pamh, retval));
|
||||
pam_end(pamh, retval);
|
||||
return false;
|
||||
@@ -106,7 +106,7 @@ public:
|
||||
// Get user info
|
||||
struct passwd* pw = getpwnam(auth_data->username);
|
||||
if (!pw) {
|
||||
logger->print(LOGLEVEL_ERROR, "auth_pam: Failed to get user info for %s",
|
||||
logger->print(LOGLEVEL_ERROR, "failed to get user info for {}",
|
||||
auth_data->username);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -43,10 +43,9 @@ public:
|
||||
cwd = "/";
|
||||
|
||||
} catch (const fs::filesystem_error& ex) {
|
||||
logger->print(LOGLEVEL_ERROR, "setRoot error: %s", ex.what());
|
||||
logger->print(LOGLEVEL_ERROR, "setRoot error: {}", ex.what());
|
||||
fd.error = {FilerStatusCodes::Exception, ex.what()};
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
@@ -68,7 +67,7 @@ public:
|
||||
|
||||
cwd = new_cwd;
|
||||
} catch (const fs::filesystem_error& ex) {
|
||||
logger->print(LOGLEVEL_ERROR, "setCWD error: %s", ex.what());
|
||||
logger->print(LOGLEVEL_ERROR, "setCWD error: {}", ex.what());
|
||||
fd.error = {FilerStatusCodes::Exception, ex.what()};
|
||||
}
|
||||
|
||||
@@ -105,16 +104,16 @@ public:
|
||||
*target = fs::path(*target).lexically_normal();
|
||||
if (fs::is_symlink(*target) && resolve_symlink) {
|
||||
fs::path resolved_sym = fs::weakly_canonical(*target);
|
||||
logger->print(LOGLEVEL_DEBUG, "Resolved symlink path: %s", resolved_sym.c_str());
|
||||
logger->print(LOGLEVEL_DEBUG, "resolved symlink path: {}", resolved_sym.string());
|
||||
return resolve_ext_symlinks ? true : resolved_sym.string().starts_with(root.string());
|
||||
} else if (!(*target).string().starts_with(root.string()))
|
||||
return false;
|
||||
|
||||
logger->print(LOGLEVEL_DEBUG, "Resolved path: %s", target->c_str());
|
||||
logger->print(LOGLEVEL_DEBUG, "resolved path: {}", target->string());
|
||||
|
||||
return true;
|
||||
} catch (const std::exception& e) {
|
||||
logger->print(LOGLEVEL_ERROR, "Path resolution error: %s", e.what());
|
||||
logger->print(LOGLEVEL_ERROR, "path resolution error: {}", e.what());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -151,7 +150,7 @@ public:
|
||||
fd.path = strdup(requested_path.c_str());
|
||||
fd.relpath = strdup(fs::relative(requested_path, root).c_str());
|
||||
} catch (const fs::filesystem_error& ex) {
|
||||
logger->print(LOGLEVEL_ERROR, "Path fallback: %s", ex.what());
|
||||
logger->print(LOGLEVEL_ERROR, "traversal error: {}", ex.what());
|
||||
fd.error = file_error{FilerStatusCodes::Exception, ex.what()};
|
||||
}
|
||||
return fd;
|
||||
|
||||
Reference in New Issue
Block a user