about summary refs log tree commit diff stats
path: root/src/handlers.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/handlers.c')
-rw-r--r--src/handlers.c535
1 files changed, 0 insertions, 535 deletions
diff --git a/src/handlers.c b/src/handlers.c
deleted file mode 100644
index d42382e..0000000
--- a/src/handlers.c
+++ /dev/null
@@ -1,535 +0,0 @@
-#ifdef __linux__
-#define _POSIX_C_SOURCE 200809L
-#define _DEFAULT_SOURCE
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#include <string.h>
-#include <syslog.h>
-#include <limits.h>
-#include <errno.h>
-#include <unistd.h>
-#ifdef __FreeBSD__
-#include <sys/param.h>
-#endif
-
-#include "handlers.h"
-#include "packet.h"
-#include "netascii.h"
-
-inline nbd_opmode get_mode(char *mode) {
-	nbd_opmode opmode;
-	if (strncmp(mode, (char *)&"netascii", NBD_NBTPD_ARGS_MODE_MAX) == 0) {
-		opmode = NETASCII;
-	} else if (strncmp(mode, (char *)&"octet", NBD_NBTPD_ARGS_MODE_MAX) == 0) {
-		opmode = OCTET;
-	} else if (strncmp(mode, (char *)&"mail", NBD_NBTPD_ARGS_MODE_MAX) == 0) {
-		opmode = MAIL;
-	} else {
-		opmode = NOT_FOUND;
-	}
-	return opmode;
-}
-
-int makesock(nbd_nbtpd_args *argptr) {
-	int s = socket(AF_INET, SOCK_DGRAM, 0);
-	if (s <= 0) {
-		syslog(LOG_ERR, "unable to define socket: %s", strerror(errno));
-		return -1;
-	}
-	struct timeval timeout = { 30, 0 };
-	if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) {
-		syslog(LOG_ERR, "unable to set socket timeout: %s", strerror(errno));
-		close(s);
-		return -1;
-	}
-	if (connect(s, (struct sockaddr *)&(argptr->client), sizeof(struct sockaddr)) < 0) {
-		syslog(
-			LOG_ERR,
-			"unable to connect to client %s: %s",
-			inet_ntoa(argptr->client.sin_addr),
-			strerror(errno)
-		);
-		close(s);
-		return -1;
-	}
-	return s;
-}
-
-char *checkpath(nbd_nbtpd_args *argptr, uint8_t read) {
-	char *fname = NULL, *wd = NULL, *path = NULL, *ptr = NULL;
-	char **parts = NULL;
-	if (!is_netascii_str((char *)&argptr->path)) {
-		argptr->err = 1;
-		goto cleanup;
-	}
-	if (read) {
-		fname = realpath((char *)&argptr->path, NULL);
-	} else {
-		//TODO: figure out how to canonicalize non-existent path
-		char *tok = NULL;
-		parts = malloc(sizeof(parts) * NBD_NBTPD_ARGS_PATH_MAX);
-		if (parts == NULL) {
-			goto cleanup;
-		}
-		memset(parts, '\0', sizeof(parts) * NBD_NBTPD_ARGS_PATH_MAX);
-		ptr = (char *)&argptr->path;
-		for (int i = 0; ((tok = strsep(&ptr, "/")) != NULL); i++ ) {
-			parts[i] = tok;
-		}
-		path = malloc(NBD_NBTPD_ARGS_PATH_MAX);
-		if (path == NULL) {
-			goto cleanup;
-		}
-		memset(path, '\0', NBD_NBTPD_ARGS_PATH_MAX);
-		int z = 0;
-		for (int i = 0; parts[i] != NULL; i++) {
-			if (strncmp(parts[i], "..", 2) == 0) {
-				continue;
-			}
-			if (strncmp(parts[i], ".", NBD_NBTPD_ARGS_PATH_MAX) == 0) {
-				continue;
-			}
-			for (int x = 0; parts[i][x] != '\0'; x++) {
-				if (z < NBD_NBTPD_ARGS_PATH_MAX) {
-					path[z++] = parts[i][x];
-				} else {
-					goto cleanup;
-				}
-			}
-			if (z < NBD_NBTPD_ARGS_PATH_MAX) {
-				path[z++] = '/';
-			} else {
-				goto cleanup;
-			}
-		}
-		// erase trailing slash
-		path[z - 1] = '\0';
-		fname = strdup(path);
-	}
-	if (fname == NULL) {
-		syslog(LOG_ERR, "unable to get real path: %s", strerror(errno));
-		argptr->err = 1;
-		goto cleanup;
-	}
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- * POSIX does not define what happens when getcwd() is given NULL.     *
- * This means that illumos libc and GNU libc both return a newly       *
- * malloc()'d string, while FreeBSD libc does not.  Also, FreeBSD uses *
- * constant MAXPATHLEN defined in <sys/param.h> rather than PATH_MAX.  *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-#ifdef __FreeBSD__
-	wd = malloc(MAXPATHLEN);
-	if (wd == NULL) {
-		syslog(LOG_ERR, "unable to allocate PATH_MAX memory: %s", strerror(errno));
-		argptr->err = 0;
-		goto cleanup;
-	}
-	if (getcwd(wd, MAXPATHLEN) == NULL) {
-		argptr->err = 0;
-		goto cleanup;
-	}
-#else
-	if ((wd = getcwd(NULL, PATH_MAX)) == NULL) {
-		argptr->err = 0;
-		goto cleanup;
-	}
-#endif
-	syslog(LOG_DEBUG, "cwd: %s :: realpath: %s", wd, fname);
-	if (read) {
-		if (strncmp(wd, fname, strlen(wd))) {
-			syslog(
-				LOG_ERR,
-				"%s:%d requested invalid file %s",
-				inet_ntoa(argptr->client.sin_addr),
-				ntohs(argptr->client.sin_port),
-				fname
-			);
-			argptr->err = 2;
-			goto cleanup;
-		}
-	} else {
-		strcat(wd, "/");
-		strcat(wd, fname);
-		char *intermediate = wd;
-		wd = fname;
-		fname = intermediate;
-	}
-cleanup:
-	free(wd);
-	free(path);
-	free(parts);
-	return fname;
-}
-
-ssize_t senderror(int s, nbd_nbtpd_args *argptr) {
-	size_t buflen = 4 + strlen(nbd_tftp_error_to_message((nbd_tftp_ecode)argptr->err));
-	char *buf = nbd_tftp_ser_error_from_code((nbd_tftp_ecode)argptr->err);
-	ssize_t sb = send(s, buf, buflen, 0);
-	free(buf);
-	return sb;
-}
-
-void *read_req_resp(void *args) {
-	char *fname = NULL, *buf = NULL, *rxb = NULL;
-	FILE *fp = NULL;
-	nbd_nbtpd_args *argptr = (nbd_nbtpd_args *)args;
-	syslog(
-		LOG_DEBUG,
-		"%s:%d is requesting file %s",
-		inet_ntoa(argptr->client.sin_addr),
-		ntohs(argptr->client.sin_port),
-		argptr->path
-	);
-	fname = checkpath(argptr, 1);
-	if (fname == NULL) {
-		goto pre_socket;
-	}
-	if (!is_netascii_str((char *)&(argptr->mode))) {
-		syslog(
-			LOG_ERR,
-			"%s:%d mode is invalid %s",
-			inet_ntoa(argptr->client.sin_addr),
-			ntohs(argptr->client.sin_port),
-			argptr->mode
-		);
-		argptr->err = 4;
-		goto pre_socket;
-	}
-	nbd_opmode opmode = get_mode((char *)&(argptr->mode));
-	if ((opmode != NETASCII) && (opmode != OCTET)) {
-		argptr->err = 4;
-		goto pre_socket;
-	}
-	fp = fopen(fname, "r");
-	if (fp == NULL) {
-		syslog(
-			LOG_ERR,
-			"failed to open file for reading: %s",
-			strerror(errno)
-		);
-		argptr->err = 2;
-		goto pre_socket;
-	}
-	buf = malloc(512);
-	rxb = malloc(256);
-	if ((buf == NULL) || (rxb == NULL)) {
-		syslog(
-			LOG_CRIT,
-			"failed to allocate memory: %s",
-			strerror(errno)
-		);
-		argptr->err = 0;
-		goto pre_socket;
-	}
-	int s = makesock(argptr);
-	if (s <= 0) {
-		goto cleanup;
-	}
-	uint8_t rxon = 0, lon = 1;
-	uint16_t bnum = 0;
-	while (lon) {
-		memset(buf, '\0', 512);
-		uint8_t verif = 0;
-		uint8_t vcount = 0;
-		size_t num_read = fread(buf, 1, 512, fp);
-		if (((num_read < 512) && (!feof(fp))) || (vcount > 5)) {
-			argptr->err = 0;
-			senderror(s, argptr);
-			goto cleanup;
-		}
-		if ((opmode == NETASCII) && (!is_netascii_buf(buf, num_read))) {
-			syslog(
-				LOG_ERR,
-				"%s:%d: requested file is not netascii compliant.",
-				inet_ntoa(argptr->client.sin_addr),
-				ntohs(argptr->client.sin_port)
-			);
-			argptr->err = 5;
-			senderror(s, argptr);
-			goto cleanup;
-		}
-		char *packet = nbd_tftp_ser_data_from_parts(++bnum, buf, num_read);
-		while (!verif) {
-			syslog(LOG_DEBUG, "sending block number %d to %s:%d",
-				bnum,
-				inet_ntoa(argptr->client.sin_addr),
-				htons(argptr->client.sin_port)
-			);
-			if (send(s, packet, num_read + 4, 0) < 0) {
-				syslog(
-					LOG_ERR,
-					"unable to send data to %s: %s",
-					inet_ntoa(argptr->client.sin_addr),
-					strerror(errno)
-				);
-				continue;
-			}
-			rxon = 1;
-			uint8_t rxcount = 0;
-			while (rxon) {
-				syslog(LOG_DEBUG, "waiting for ack %d from %s:%d",
-					bnum,
-					inet_ntoa(argptr->client.sin_addr),
-					htons(argptr->client.sin_port)
-				);
-				memset(rxb, '\0', 256);
-				ssize_t rcv = recv(s, rxb, 256, 0);
-				syslog(LOG_DEBUG, "recv'd %ld bytes from %s:%d",
-					rcv,
-					inet_ntoa(argptr->client.sin_addr),
-					htons(argptr->client.sin_port)
-				);
-				if (rcv == 4) {
-					nbd_tftp_packet_ack ack = nbd_tftp_de_ack(rxb, rcv);
-					if (ack.opcode == 5) {
-						goto socket_clean;
-					}
-					syslog(LOG_DEBUG, "%s:%d ack'd with block number: %d (expect %d)",
-						inet_ntoa(argptr->client.sin_addr),
-						htons(argptr->client.sin_port),
-						ack.block_num,
-						bnum
-					);
-					if (ack.block_num == bnum) {
-						rxon = 0;
-						verif = 1;
-						break;
-					}
-					if (ack.block_num == (bnum - 1)) {
-						rxon = 0;
-						vcount++;
-						break;
-					}
-				}
-				if (++rxcount > 30) {
-					argptr->err = 0;
-					senderror(s, argptr);
-					goto cleanup;
-				}
-				if (rcv > 4) {
-					if ((((uint16_t)buf[0] << 8) + buf[1]) == 5) {
-						goto socket_clean;
-					}
-				}
-			}
-		}
-		free(packet);
-		if (num_read < 512) {
-			lon = 0;
-		}
-	}
-socket_clean:
-	close(s);
-cleanup:
-	fclose(fp);
-	free(buf);
-	free(rxb);
-	free(fname);
-	free(args);
-	return (void *)NULL;
-pre_socket:
-	if (fp != NULL) {
-		fclose(fp);
-	}
-	free(buf);
-	free(rxb);
-	free(fname);
-	return nbd_nbtpd_resp_error(args);
-}
-
-void *write_req_resp(void *args) {
-	char *fname = NULL, *rxb = NULL;
-	FILE *fp = NULL;
-	nbd_nbtpd_args *argptr = (nbd_nbtpd_args *)args;
-	syslog(
-		LOG_DEBUG,
-		"%s:%d is trying to write file %s",
-		inet_ntoa(argptr->client.sin_addr),
-		ntohs(argptr->client.sin_port),
-		argptr->path
-	);
-	fname = checkpath(argptr, 0);
-	if (fname == NULL) {
-		syslog(LOG_ERR, "fname is NULL");
-		goto pre_socket;
-	}
-	if (!is_netascii_str((char *)&(argptr->mode))) {
-		syslog(
-			LOG_ERR,
-			"%s:%d mode is invalid %s",
-			inet_ntoa(argptr->client.sin_addr),
-			ntohs(argptr->client.sin_port),
-			argptr->mode
-		);
-		argptr->err = 4;
-		goto pre_socket;
-	}
-	nbd_opmode opmode = get_mode((char *)&(argptr->mode));
-	if ((opmode != NETASCII) && (opmode != OCTET)) {
-		syslog(LOG_ERR, "%s:%d mode is not supported.", inet_ntoa(argptr->client.sin_addr), ntohs(argptr->client.sin_port));
-		argptr->err = 4;
-		goto pre_socket;
-	}
-	fp = fopen(fname, "w");
-	if (fp == NULL) {
-		syslog(
-			LOG_ERR,
-			"failed to open file for writing: %s",
-			strerror(errno)
-		);
-		argptr->err = 2;
-		goto pre_socket;
-	}
-	rxb = malloc(768); // 768 is 1.5x expected block size
-	if (rxb == NULL) {
-		syslog(
-			LOG_CRIT,
-			"failed to allocate memory: %s",
-			strerror(errno)
-		);
-		argptr->err = 0;
-		goto pre_socket;
-	}
-	int s = makesock(argptr);
-	if (s <= 0) {
-		goto cleanup;
-	}
-	uint8_t rxon = 0, lon = 1;
-	uint16_t bnum = 0;
-	ssize_t rcv = 516;
-	while (lon) {
-		uint8_t verif = 0;
-		uint8_t vcount = 0;
-		char *packet = nbd_tftp_ser_ack_from_block_num(bnum++);
-		while (!verif) {
-			syslog(LOG_DEBUG, "sending ack number %d to %s:%d",
-				bnum,
-				inet_ntoa(argptr->client.sin_addr),
-				htons(argptr->client.sin_port)
-			);
-			if (send(s, packet, 4, 0) < 0) {
-				syslog(
-					LOG_ERR,
-					"unable to send ack to %s:%d: %s",
-					inet_ntoa(argptr->client.sin_addr),
-					htons(argptr->client.sin_port),
-					strerror(errno)
-				);
-				continue;
-			}
-			if ((rcv < 516) || (vcount > 5)) {
-				lon = 0;
-				break;
-			}
-			rxon = 1;
-			uint8_t rxcount = 0;
-			while (rxon) {
-				syslog(LOG_DEBUG, "waiting for data from %s:%d",
-					inet_ntoa(argptr->client.sin_addr),
-					htons(argptr->client.sin_port)
-				);
-				memset(rxb, '\0', 768);
-				rcv = recv(s, rxb, 768, 0);
-				syslog(LOG_DEBUG, "recv'd %ld bytes from %s:%d",
-					rcv,
-					inet_ntoa(argptr->client.sin_addr),
-					htons(argptr->client.sin_port)
-				);
-				if (rcv >= 4) {
-					nbd_tftp_packet_data data = nbd_tftp_de_data(rxb, rcv);
-					if (data.opcode == 5) {
-						free(data.data);
-						goto cleanup;
-					}
-					syslog(
-						LOG_DEBUG,
-						"%s:%d sent block number: %d (expect %d)",
-						inet_ntoa(argptr->client.sin_addr),
-						htons(argptr->client.sin_port),
-						data.block_num,
-						bnum
-					);
-					if (data.block_num == bnum) {
-						rxon = 0;
-						verif = 1;
-						if (data.datalen > 0) {
-							if ((opmode == NETASCII) && (!is_netascii_buf(data.data, data.datalen))) {
-								syslog(
-									LOG_ERR,
-									"%s:%d: requested file is not netascii compliant.",
-									inet_ntoa(argptr->client.sin_addr),
-									ntohs(argptr->client.sin_port)
-								);
-								argptr->err = 5;
-								senderror(s, argptr);
-								free(data.data);
-								goto cleanup;
-							}
-							if (fwrite(data.data, 1, data.datalen, fp) < data.datalen) {
-								syslog(LOG_ERR, "filewrite failed for %s: %s", fname, strerror(errno));
-								argptr->err = 0;
-								senderror(s, argptr);
-								free(data.data);
-								goto clean_socket;
-							}
-						}
-						free(data.data);
-						break;
-					}
-					if (data.block_num == (bnum - 1)) {
-						rxon = 0;
-						vcount++;
-						free(data.data);
-						break;
-					}
-					free(data.data);
-				}
-				if (++rxcount > 30) {
-					syslog(LOG_ERR, "retry count exceeded");
-					argptr->err = 0;
-					senderror(s, argptr);
-					goto clean_socket;
-				}
-			}
-		}
-		free(packet);
-	}
-clean_socket:
-	close(s);
-cleanup:
-	fclose(fp);
-	free(rxb);
-	free(fname);
-	free(args);
-	return (void *)NULL;
-pre_socket:
-	if (fp != NULL) {
-		fclose(fp);
-	}
-	free(rxb);
-	free(fname);
-	return nbd_nbtpd_resp_error(args);
-}
-
-void *nbd_nbtpd_resp_error(void *args) {
-	nbd_nbtpd_args *argptr = (nbd_nbtpd_args *)args;
-	int s = makesock(argptr);
-	if (s <= 0) {
-		syslog(
-			LOG_ERR,
-			"cannot send error to %s:%d",
-			inet_ntoa(argptr->client.sin_addr),
-			ntohs(argptr->client.sin_port)
-		);
-		goto cleanup;
-	}
-	senderror(s, argptr);
-cleanup:
-	free(args);
-	return (void *)NULL;
-}
-