Changeset View
Changeset View
Standalone View
Standalone View
libexec/tftpd/tftp-options.c
Show All 31 Lines | |||||
#include <sys/socket.h> | #include <sys/socket.h> | ||||
#include <sys/stat.h> | #include <sys/stat.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <netinet/in.h> | #include <netinet/in.h> | ||||
#include <arpa/tftp.h> | #include <arpa/tftp.h> | ||||
#include <ctype.h> | #include <ctype.h> | ||||
#include <stdarg.h> | |||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <syslog.h> | #include <syslog.h> | ||||
#include "tftp-utils.h" | #include "tftp-utils.h" | ||||
#include "tftp-io.h" | #include "tftp-io.h" | ||||
#include "tftp-options.h" | #include "tftp-options.h" | ||||
Show All 11 Lines | struct options options[] = { | ||||
{ "windowsize", NULL, NULL, option_windowsize, 1 }, | { "windowsize", NULL, NULL, option_windowsize, 1 }, | ||||
{ NULL, NULL, NULL, NULL, 0 } | { NULL, NULL, NULL, NULL, 0 } | ||||
}; | }; | ||||
/* By default allow them */ | /* By default allow them */ | ||||
int options_rfc_enabled = 1; | int options_rfc_enabled = 1; | ||||
int options_extra_enabled = 1; | int options_extra_enabled = 1; | ||||
int | |||||
options_set_request(enum opt_enum opt, const char *fmt, ...) | |||||
{ | |||||
va_list ap; | |||||
char *str; | |||||
int ret; | |||||
if (fmt == NULL) { | |||||
str = NULL; | |||||
} else { | |||||
va_start(ap, fmt); | |||||
ret = vasprintf(&str, fmt, ap); | |||||
va_end(ap); | |||||
if (ret < 0) | |||||
return (ret); | |||||
} | |||||
if (options[opt].o_request != NULL && | |||||
options[opt].o_request != options[opt].o_reply) | |||||
free(options[opt].o_request); | |||||
options[opt].o_request = str; | |||||
return (0); | |||||
} | |||||
int | |||||
options_set_reply(enum opt_enum opt, const char *fmt, ...) | |||||
{ | |||||
va_list ap; | |||||
char *str; | |||||
int ret; | |||||
if (fmt == NULL) { | |||||
str = NULL; | |||||
} else { | |||||
va_start(ap, fmt); | |||||
ret = vasprintf(&str, fmt, ap); | |||||
va_end(ap); | |||||
if (ret < 0) | |||||
return (ret); | |||||
} | |||||
if (options[opt].o_reply != NULL && | |||||
options[opt].o_reply != options[opt].o_request) | |||||
free(options[opt].o_reply); | |||||
options[opt].o_reply = str; | |||||
return (0); | |||||
} | |||||
static void | |||||
options_set_reply_equal_request(enum opt_enum opt) | |||||
{ | |||||
if (options[opt].o_reply != NULL && | |||||
options[opt].o_reply != options[opt].o_request) | |||||
free(options[opt].o_reply); | |||||
options[opt].o_reply = options[opt].o_request; | |||||
} | |||||
/* | /* | ||||
* Rules for the option handlers: | * Rules for the option handlers: | ||||
* - If there is no o_request, there will be no processing. | * - If there is no o_request, there will be no processing. | ||||
* | * | ||||
* For servers | * For servers | ||||
* - Logging is done as warnings. | * - Logging is done as warnings. | ||||
* - The handler exit()s if there is a serious problem with the | * - The handler exit()s if there is a serious problem with the | ||||
* values submitted in the option. | * values submitted in the option. | ||||
Show All 10 Lines | |||||
option_tsize(int peer __unused, struct tftphdr *tp __unused, int mode, | option_tsize(int peer __unused, struct tftphdr *tp __unused, int mode, | ||||
struct stat *stbuf) | struct stat *stbuf) | ||||
{ | { | ||||
if (options[OPT_TSIZE].o_request == NULL) | if (options[OPT_TSIZE].o_request == NULL) | ||||
return (0); | return (0); | ||||
if (mode == RRQ) | if (mode == RRQ) | ||||
asprintf(&options[OPT_TSIZE].o_reply, | options_set_reply(OPT_TSIZE, "%ju", stbuf->st_size); | ||||
"%ju", (uintmax_t)stbuf->st_size); | |||||
else | else | ||||
/* XXX Allows writes of all sizes. */ | /* XXX Allows writes of all sizes. */ | ||||
options[OPT_TSIZE].o_reply = | options_set_reply_equal_request(OPT_TSIZE); | ||||
strdup(options[OPT_TSIZE].o_request); | |||||
return (0); | return (0); | ||||
} | } | ||||
int | int | ||||
option_timeout(int peer) | option_timeout(int peer) | ||||
{ | { | ||||
int to; | int to; | ||||
if (options[OPT_TIMEOUT].o_request == NULL) | if (options[OPT_TIMEOUT].o_request == NULL) | ||||
return (0); | return (0); | ||||
to = atoi(options[OPT_TIMEOUT].o_request); | to = atoi(options[OPT_TIMEOUT].o_request); | ||||
if (to < TIMEOUT_MIN || to > TIMEOUT_MAX) { | if (to < TIMEOUT_MIN || to > TIMEOUT_MAX) { | ||||
tftp_log(acting_as_client ? LOG_ERR : LOG_WARNING, | tftp_log(acting_as_client ? LOG_ERR : LOG_WARNING, | ||||
"Received bad value for timeout. " | "Received bad value for timeout. " | ||||
"Should be between %d and %d, received %d", | "Should be between %d and %d, received %d", | ||||
TIMEOUT_MIN, TIMEOUT_MAX, to); | TIMEOUT_MIN, TIMEOUT_MAX, to); | ||||
send_error(peer, EBADOP); | send_error(peer, EBADOP); | ||||
if (acting_as_client) | if (acting_as_client) | ||||
return (1); | return (1); | ||||
exit(1); | exit(1); | ||||
} else { | } else { | ||||
timeoutpacket = to; | timeoutpacket = to; | ||||
options[OPT_TIMEOUT].o_reply = | options_set_reply_equal_request(OPT_TIMEOUT); | ||||
strdup(options[OPT_TIMEOUT].o_request); | |||||
} | } | ||||
settimeouts(timeoutpacket, timeoutnetwork, maxtimeouts); | settimeouts(timeoutpacket, timeoutnetwork, maxtimeouts); | ||||
if (debug & DEBUG_OPTIONS) | if (debug & DEBUG_OPTIONS) | ||||
tftp_log(LOG_DEBUG, "Setting timeout to '%s'", | tftp_log(LOG_DEBUG, "Setting timeout to '%s'", | ||||
options[OPT_TIMEOUT].o_reply); | options[OPT_TIMEOUT].o_reply); | ||||
return (0); | return (0); | ||||
Show All 14 Lines | tftp_log(acting_as_client ? LOG_ERR : LOG_WARNING, | ||||
"ignoring request", | "ignoring request", | ||||
options[OPT_ROLLOVER].o_request); | options[OPT_ROLLOVER].o_request); | ||||
if (acting_as_client) { | if (acting_as_client) { | ||||
send_error(peer, EBADOP); | send_error(peer, EBADOP); | ||||
return (1); | return (1); | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
options[OPT_ROLLOVER].o_reply = | options_set_reply_equal_request(OPT_ROLLOVER); | ||||
strdup(options[OPT_ROLLOVER].o_request); | |||||
if (debug & DEBUG_OPTIONS) | if (debug & DEBUG_OPTIONS) | ||||
tftp_log(LOG_DEBUG, "Setting rollover to '%s'", | tftp_log(LOG_DEBUG, "Setting rollover to '%s'", | ||||
options[OPT_ROLLOVER].o_reply); | options[OPT_ROLLOVER].o_reply); | ||||
return (0); | return (0); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | if (acting_as_client) { | ||||
"Invalid blocksize (%d bytes), " | "Invalid blocksize (%d bytes), " | ||||
"net.inet.udp.maxdgram sysctl limits it to " | "net.inet.udp.maxdgram sysctl limits it to " | ||||
"%ld bytes.\n", size, maxdgram); | "%ld bytes.\n", size, maxdgram); | ||||
size = maxdgram; | size = maxdgram; | ||||
/* No reason to return */ | /* No reason to return */ | ||||
} | } | ||||
} | } | ||||
asprintf(&options[OPT_BLKSIZE].o_reply, "%d", size); | options_set_reply(OPT_BLKSIZE, "%d", size); | ||||
segsize = size; | segsize = size; | ||||
pktsize = size + 4; | pktsize = size + 4; | ||||
if (debug & DEBUG_OPTIONS) | if (debug & DEBUG_OPTIONS) | ||||
tftp_log(LOG_DEBUG, "Setting blksize to '%s'", | tftp_log(LOG_DEBUG, "Setting blksize to '%s'", | ||||
options[OPT_BLKSIZE].o_reply); | options[OPT_BLKSIZE].o_reply); | ||||
return (0); | return (0); | ||||
} | } | ||||
Show All 37 Lines | if (size > (int)maxdgram) { | ||||
} | } | ||||
tftp_log(LOG_INFO, | tftp_log(LOG_INFO, | ||||
"Invalid blocksize2 (%d bytes), net.inet.udp.maxdgram " | "Invalid blocksize2 (%d bytes), net.inet.udp.maxdgram " | ||||
"sysctl limits it to %ld bytes.\n", size, maxdgram); | "sysctl limits it to %ld bytes.\n", size, maxdgram); | ||||
size = sizes[i]; | size = sizes[i]; | ||||
/* No need to return */ | /* No need to return */ | ||||
} | } | ||||
asprintf(&options[OPT_BLKSIZE2].o_reply, "%d", size); | options_set_reply(OPT_BLKSIZE2, "%d", size); | ||||
segsize = size; | segsize = size; | ||||
pktsize = size + 4; | pktsize = size + 4; | ||||
if (debug & DEBUG_OPTIONS) | if (debug & DEBUG_OPTIONS) | ||||
tftp_log(LOG_DEBUG, "Setting blksize2 to '%s'", | tftp_log(LOG_DEBUG, "Setting blksize2 to '%s'", | ||||
options[OPT_BLKSIZE2].o_reply); | options[OPT_BLKSIZE2].o_reply); | ||||
return (0); | return (0); | ||||
} | } | ||||
Show All 18 Lines | if (acting_as_client) { | ||||
tftp_log(LOG_WARNING, | tftp_log(LOG_WARNING, | ||||
"Invalid windowsize (%d blocks), ignoring request", | "Invalid windowsize (%d blocks), ignoring request", | ||||
size); | size); | ||||
return (0); | return (0); | ||||
} | } | ||||
} | } | ||||
/* XXX: Should force a windowsize of 1 for non-seekable files. */ | /* XXX: Should force a windowsize of 1 for non-seekable files. */ | ||||
asprintf(&options[OPT_WINDOWSIZE].o_reply, "%d", size); | options_set_reply(OPT_WINDOWSIZE, "%d", size); | ||||
windowsize = size; | windowsize = size; | ||||
if (debug & DEBUG_OPTIONS) | if (debug & DEBUG_OPTIONS) | ||||
tftp_log(LOG_DEBUG, "Setting windowsize to '%s'", | tftp_log(LOG_DEBUG, "Setting windowsize to '%s'", | ||||
options[OPT_WINDOWSIZE].o_reply); | options[OPT_WINDOWSIZE].o_reply); | ||||
return (0); | return (0); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 73 Lines • ▼ Show 20 Lines | if (debug & DEBUG_OPTIONS) | ||||
"option: '%s' value: '%s'", option, value); | "option: '%s' value: '%s'", option, value); | ||||
for (c = option; *c; c++) | for (c = option; *c; c++) | ||||
if (isupper(*c)) | if (isupper(*c)) | ||||
*c = tolower(*c); | *c = tolower(*c); | ||||
for (i = 0; options[i].o_type != NULL; i++) { | for (i = 0; options[i].o_type != NULL; i++) { | ||||
if (strcmp(option, options[i].o_type) == 0) { | if (strcmp(option, options[i].o_type) == 0) { | ||||
if (!acting_as_client) | if (!acting_as_client) | ||||
options[i].o_request = value; | options_set_request(i, "%s", value); | ||||
if (!options_extra_enabled && !options[i].rfc) { | if (!options_extra_enabled && !options[i].rfc) { | ||||
tftp_log(LOG_INFO, | tftp_log(LOG_INFO, | ||||
"Option '%s' with value '%s' found " | "Option '%s' with value '%s' found " | ||||
"but it is not an RFC option", | "but it is not an RFC option", | ||||
option, value); | option, value); | ||||
continue; | continue; | ||||
} | } | ||||
if (options[i].o_handler) | if (options[i].o_handler) | ||||
Show All 14 Lines | |||||
/* | /* | ||||
* Set some default values in the options | * Set some default values in the options | ||||
*/ | */ | ||||
void | void | ||||
init_options(void) | init_options(void) | ||||
{ | { | ||||
options[OPT_ROLLOVER].o_request = strdup("0"); | options_set_request(OPT_ROLLOVER, "0"); | ||||
} | } |