1*e7ff5475SWarner Losh /* 2*e7ff5475SWarner Losh * Copyright (C) 2008 Edwin Groothuis. All rights reserved. 3*e7ff5475SWarner Losh * 4*e7ff5475SWarner Losh * Redistribution and use in source and binary forms, with or without 5*e7ff5475SWarner Losh * modification, are permitted provided that the following conditions 6*e7ff5475SWarner Losh * are met: 7*e7ff5475SWarner Losh * 1. Redistributions of source code must retain the above copyright 8*e7ff5475SWarner Losh * notice, this list of conditions and the following disclaimer. 9*e7ff5475SWarner Losh * 2. Redistributions in binary form must reproduce the above copyright 10*e7ff5475SWarner Losh * notice, this list of conditions and the following disclaimer in the 11*e7ff5475SWarner Losh * documentation and/or other materials provided with the distribution. 12*e7ff5475SWarner Losh * 13*e7ff5475SWarner Losh * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14*e7ff5475SWarner Losh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15*e7ff5475SWarner Losh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16*e7ff5475SWarner Losh * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 17*e7ff5475SWarner Losh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18*e7ff5475SWarner Losh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19*e7ff5475SWarner Losh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20*e7ff5475SWarner Losh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21*e7ff5475SWarner Losh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22*e7ff5475SWarner Losh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23*e7ff5475SWarner Losh * SUCH DAMAGE. 24*e7ff5475SWarner Losh */ 25*e7ff5475SWarner Losh 26*e7ff5475SWarner Losh #include <sys/cdefs.h> 27*e7ff5475SWarner Losh __FBSDID("$FreeBSD$"); 28*e7ff5475SWarner Losh 29*e7ff5475SWarner Losh #include <sys/socket.h> 30*e7ff5475SWarner Losh #include <sys/types.h> 31*e7ff5475SWarner Losh #include <sys/sysctl.h> 32*e7ff5475SWarner Losh #include <sys/stat.h> 33*e7ff5475SWarner Losh 34*e7ff5475SWarner Losh #include <netinet/in.h> 35*e7ff5475SWarner Losh #include <arpa/tftp.h> 36*e7ff5475SWarner Losh 37*e7ff5475SWarner Losh #include <ctype.h> 38*e7ff5475SWarner Losh #include <stdio.h> 39*e7ff5475SWarner Losh #include <stdlib.h> 40*e7ff5475SWarner Losh #include <string.h> 41*e7ff5475SWarner Losh #include <syslog.h> 42*e7ff5475SWarner Losh 43*e7ff5475SWarner Losh #include "tftp-utils.h" 44*e7ff5475SWarner Losh #include "tftp-io.h" 45*e7ff5475SWarner Losh #include "tftp-options.h" 46*e7ff5475SWarner Losh 47*e7ff5475SWarner Losh /* 48*e7ff5475SWarner Losh * Option handlers 49*e7ff5475SWarner Losh */ 50*e7ff5475SWarner Losh 51*e7ff5475SWarner Losh struct options options[] = { 52*e7ff5475SWarner Losh { "tsize", NULL, NULL, NULL /* option_tsize */, 1 }, 53*e7ff5475SWarner Losh { "timeout", NULL, NULL, option_timeout, 1 }, 54*e7ff5475SWarner Losh { "blksize", NULL, NULL, option_blksize, 1 }, 55*e7ff5475SWarner Losh { "blksize2", NULL, NULL, option_blksize2, 0 }, 56*e7ff5475SWarner Losh { "rollover", NULL, NULL, option_rollover, 0 }, 57*e7ff5475SWarner Losh { NULL, NULL, NULL, NULL, 0 } 58*e7ff5475SWarner Losh }; 59*e7ff5475SWarner Losh 60*e7ff5475SWarner Losh /* By default allow them */ 61*e7ff5475SWarner Losh int options_rfc_enabled = 1; 62*e7ff5475SWarner Losh int options_extra_enabled = 1; 63*e7ff5475SWarner Losh 64*e7ff5475SWarner Losh /* 65*e7ff5475SWarner Losh * Rules for the option handlers: 66*e7ff5475SWarner Losh * - If there is no o_request, there will be no processing. 67*e7ff5475SWarner Losh * 68*e7ff5475SWarner Losh * For servers 69*e7ff5475SWarner Losh * - Logging is done as warnings. 70*e7ff5475SWarner Losh * - The handler exit()s if there is a serious problem with the 71*e7ff5475SWarner Losh * values submitted in the option. 72*e7ff5475SWarner Losh * 73*e7ff5475SWarner Losh * For clients 74*e7ff5475SWarner Losh * - Logging is done as errors. After all, the server shouldn't 75*e7ff5475SWarner Losh * return rubbish. 76*e7ff5475SWarner Losh * - The handler returns if there is a serious problem with the 77*e7ff5475SWarner Losh * values submitted in the option. 78*e7ff5475SWarner Losh * - Sending the EBADOP packets is done by the handler. 79*e7ff5475SWarner Losh */ 80*e7ff5475SWarner Losh 81*e7ff5475SWarner Losh int 82*e7ff5475SWarner Losh option_tsize(int peer, struct tftphdr *tp, int mode, struct stat *stbuf) 83*e7ff5475SWarner Losh { 84*e7ff5475SWarner Losh 85*e7ff5475SWarner Losh if (options[OPT_TSIZE].o_request == NULL) 86*e7ff5475SWarner Losh return (0); 87*e7ff5475SWarner Losh 88*e7ff5475SWarner Losh if (mode == RRQ) 89*e7ff5475SWarner Losh asprintf(&options[OPT_TSIZE].o_reply, 90*e7ff5475SWarner Losh "%ju", stbuf->st_size); 91*e7ff5475SWarner Losh else 92*e7ff5475SWarner Losh /* XXX Allows writes of all sizes. */ 93*e7ff5475SWarner Losh options[OPT_TSIZE].o_reply = 94*e7ff5475SWarner Losh strdup(options[OPT_TSIZE].o_request); 95*e7ff5475SWarner Losh return (0); 96*e7ff5475SWarner Losh } 97*e7ff5475SWarner Losh 98*e7ff5475SWarner Losh int 99*e7ff5475SWarner Losh option_timeout(int peer) 100*e7ff5475SWarner Losh { 101*e7ff5475SWarner Losh 102*e7ff5475SWarner Losh if (options[OPT_TIMEOUT].o_request == NULL) 103*e7ff5475SWarner Losh return (0); 104*e7ff5475SWarner Losh 105*e7ff5475SWarner Losh int to = atoi(options[OPT_TIMEOUT].o_request); 106*e7ff5475SWarner Losh if (to < TIMEOUT_MIN || to > TIMEOUT_MAX) { 107*e7ff5475SWarner Losh tftp_log(acting_as_client ? LOG_ERR : LOG_WARNING, 108*e7ff5475SWarner Losh "Received bad value for timeout. " 109*e7ff5475SWarner Losh "Should be between %d and %d, received %s", 110*e7ff5475SWarner Losh TIMEOUT_MIN, TIMEOUT_MAX); 111*e7ff5475SWarner Losh send_error(peer, EBADOP); 112*e7ff5475SWarner Losh if (acting_as_client) 113*e7ff5475SWarner Losh return (1); 114*e7ff5475SWarner Losh exit(1); 115*e7ff5475SWarner Losh } else { 116*e7ff5475SWarner Losh timeoutpacket = to; 117*e7ff5475SWarner Losh options[OPT_TIMEOUT].o_reply = 118*e7ff5475SWarner Losh strdup(options[OPT_TIMEOUT].o_request); 119*e7ff5475SWarner Losh } 120*e7ff5475SWarner Losh settimeouts(timeoutpacket, timeoutnetwork, maxtimeouts); 121*e7ff5475SWarner Losh 122*e7ff5475SWarner Losh if (debug&DEBUG_OPTIONS) 123*e7ff5475SWarner Losh tftp_log(LOG_DEBUG, "Setting timeout to '%s'", 124*e7ff5475SWarner Losh options[OPT_TIMEOUT].o_reply); 125*e7ff5475SWarner Losh 126*e7ff5475SWarner Losh return (0); 127*e7ff5475SWarner Losh } 128*e7ff5475SWarner Losh 129*e7ff5475SWarner Losh int 130*e7ff5475SWarner Losh option_rollover(int peer) 131*e7ff5475SWarner Losh { 132*e7ff5475SWarner Losh 133*e7ff5475SWarner Losh if (options[OPT_ROLLOVER].o_request == NULL) 134*e7ff5475SWarner Losh return (0); 135*e7ff5475SWarner Losh 136*e7ff5475SWarner Losh if (strcmp(options[OPT_ROLLOVER].o_request, "0") != 0 137*e7ff5475SWarner Losh && strcmp(options[OPT_ROLLOVER].o_request, "1") != 0) { 138*e7ff5475SWarner Losh tftp_log(acting_as_client ? LOG_ERR : LOG_WARNING, 139*e7ff5475SWarner Losh "Bad value for rollover, " 140*e7ff5475SWarner Losh "should be either 0 or 1, received '%s', " 141*e7ff5475SWarner Losh "ignoring request", 142*e7ff5475SWarner Losh options[OPT_ROLLOVER].o_request); 143*e7ff5475SWarner Losh if (acting_as_client) { 144*e7ff5475SWarner Losh send_error(peer, EBADOP); 145*e7ff5475SWarner Losh return (1); 146*e7ff5475SWarner Losh } 147*e7ff5475SWarner Losh return (0); 148*e7ff5475SWarner Losh } 149*e7ff5475SWarner Losh options[OPT_ROLLOVER].o_reply = 150*e7ff5475SWarner Losh strdup(options[OPT_ROLLOVER].o_request); 151*e7ff5475SWarner Losh 152*e7ff5475SWarner Losh if (debug&DEBUG_OPTIONS) 153*e7ff5475SWarner Losh tftp_log(LOG_DEBUG, "Setting rollover to '%s'", 154*e7ff5475SWarner Losh options[OPT_ROLLOVER].o_reply); 155*e7ff5475SWarner Losh 156*e7ff5475SWarner Losh return (0); 157*e7ff5475SWarner Losh } 158*e7ff5475SWarner Losh 159*e7ff5475SWarner Losh int 160*e7ff5475SWarner Losh option_blksize(int peer) 161*e7ff5475SWarner Losh { 162*e7ff5475SWarner Losh int *maxdgram; 163*e7ff5475SWarner Losh char maxbuffer[100]; 164*e7ff5475SWarner Losh size_t len; 165*e7ff5475SWarner Losh 166*e7ff5475SWarner Losh if (options[OPT_BLKSIZE].o_request == NULL) 167*e7ff5475SWarner Losh return (0); 168*e7ff5475SWarner Losh 169*e7ff5475SWarner Losh /* maximum size of an UDP packet according to the system */ 170*e7ff5475SWarner Losh len = sizeof(maxbuffer); 171*e7ff5475SWarner Losh if (sysctlbyname("net.inet.udp.maxdgram", 172*e7ff5475SWarner Losh maxbuffer, &len, NULL, 0) < 0) { 173*e7ff5475SWarner Losh tftp_log(LOG_ERR, "sysctl: net.inet.udp.maxdgram"); 174*e7ff5475SWarner Losh return (acting_as_client ? 1 : 0); 175*e7ff5475SWarner Losh } 176*e7ff5475SWarner Losh maxdgram = (int *)maxbuffer; 177*e7ff5475SWarner Losh 178*e7ff5475SWarner Losh int size = atoi(options[OPT_BLKSIZE].o_request); 179*e7ff5475SWarner Losh if (size < BLKSIZE_MIN || size > BLKSIZE_MAX) { 180*e7ff5475SWarner Losh if (acting_as_client) { 181*e7ff5475SWarner Losh tftp_log(LOG_ERR, 182*e7ff5475SWarner Losh "Invalid blocksize (%d bytes), aborting", 183*e7ff5475SWarner Losh size); 184*e7ff5475SWarner Losh send_error(peer, EBADOP); 185*e7ff5475SWarner Losh return (1); 186*e7ff5475SWarner Losh } else { 187*e7ff5475SWarner Losh tftp_log(LOG_WARNING, 188*e7ff5475SWarner Losh "Invalid blocksize (%d bytes), ignoring request", 189*e7ff5475SWarner Losh size); 190*e7ff5475SWarner Losh return (0); 191*e7ff5475SWarner Losh } 192*e7ff5475SWarner Losh } 193*e7ff5475SWarner Losh 194*e7ff5475SWarner Losh if (size > *maxdgram) { 195*e7ff5475SWarner Losh if (acting_as_client) { 196*e7ff5475SWarner Losh tftp_log(LOG_ERR, 197*e7ff5475SWarner Losh "Invalid blocksize (%d bytes), " 198*e7ff5475SWarner Losh "net.inet.udp.maxdgram sysctl limits it to " 199*e7ff5475SWarner Losh "%d bytes.\n", size, *maxdgram); 200*e7ff5475SWarner Losh send_error(peer, EBADOP); 201*e7ff5475SWarner Losh return (1); 202*e7ff5475SWarner Losh } else { 203*e7ff5475SWarner Losh tftp_log(LOG_WARNING, 204*e7ff5475SWarner Losh "Invalid blocksize (%d bytes), " 205*e7ff5475SWarner Losh "net.inet.udp.maxdgram sysctl limits it to " 206*e7ff5475SWarner Losh "%d bytes.\n", size, *maxdgram); 207*e7ff5475SWarner Losh size = *maxdgram; 208*e7ff5475SWarner Losh /* No reason to return */ 209*e7ff5475SWarner Losh } 210*e7ff5475SWarner Losh } 211*e7ff5475SWarner Losh 212*e7ff5475SWarner Losh asprintf(&options[OPT_BLKSIZE].o_reply, "%d", size); 213*e7ff5475SWarner Losh segsize = size; 214*e7ff5475SWarner Losh pktsize = size + 4; 215*e7ff5475SWarner Losh if (debug&DEBUG_OPTIONS) 216*e7ff5475SWarner Losh tftp_log(LOG_DEBUG, "Setting blksize to '%s'", 217*e7ff5475SWarner Losh options[OPT_BLKSIZE].o_reply); 218*e7ff5475SWarner Losh 219*e7ff5475SWarner Losh return (0); 220*e7ff5475SWarner Losh } 221*e7ff5475SWarner Losh 222*e7ff5475SWarner Losh int 223*e7ff5475SWarner Losh option_blksize2(int peer) 224*e7ff5475SWarner Losh { 225*e7ff5475SWarner Losh int *maxdgram; 226*e7ff5475SWarner Losh char maxbuffer[100]; 227*e7ff5475SWarner Losh int size, i; 228*e7ff5475SWarner Losh size_t len; 229*e7ff5475SWarner Losh 230*e7ff5475SWarner Losh int sizes[] = { 231*e7ff5475SWarner Losh 8, 16, 32, 64, 128, 256, 512, 1024, 232*e7ff5475SWarner Losh 2048, 4096, 8192, 16384, 32768, 0 233*e7ff5475SWarner Losh }; 234*e7ff5475SWarner Losh 235*e7ff5475SWarner Losh if (options[OPT_BLKSIZE2].o_request == NULL) 236*e7ff5475SWarner Losh return (0); 237*e7ff5475SWarner Losh 238*e7ff5475SWarner Losh /* maximum size of an UDP packet according to the system */ 239*e7ff5475SWarner Losh len = sizeof(maxbuffer); 240*e7ff5475SWarner Losh if (sysctlbyname("net.inet.udp.maxdgram", 241*e7ff5475SWarner Losh maxbuffer, &len, NULL, 0) < 0) { 242*e7ff5475SWarner Losh tftp_log(LOG_ERR, "sysctl: net.inet.udp.maxdgram"); 243*e7ff5475SWarner Losh return (acting_as_client ? 1 : 0); 244*e7ff5475SWarner Losh } 245*e7ff5475SWarner Losh maxdgram = (int *)maxbuffer; 246*e7ff5475SWarner Losh 247*e7ff5475SWarner Losh size = atoi(options[OPT_BLKSIZE2].o_request); 248*e7ff5475SWarner Losh for (i = 0; sizes[i] != 0; i++) { 249*e7ff5475SWarner Losh if (size == sizes[i]) break; 250*e7ff5475SWarner Losh } 251*e7ff5475SWarner Losh if (sizes[i] == 0) { 252*e7ff5475SWarner Losh tftp_log(LOG_INFO, 253*e7ff5475SWarner Losh "Invalid blocksize2 (%d bytes), ignoring request", size); 254*e7ff5475SWarner Losh return (acting_as_client ? 1 : 0); 255*e7ff5475SWarner Losh } 256*e7ff5475SWarner Losh 257*e7ff5475SWarner Losh if (size > *maxdgram) { 258*e7ff5475SWarner Losh for (i = 0; sizes[i+1] != 0; i++) { 259*e7ff5475SWarner Losh if (*maxdgram < sizes[i+1]) break; 260*e7ff5475SWarner Losh } 261*e7ff5475SWarner Losh tftp_log(LOG_INFO, 262*e7ff5475SWarner Losh "Invalid blocksize2 (%d bytes), net.inet.udp.maxdgram " 263*e7ff5475SWarner Losh "sysctl limits it to %d bytes.\n", size, *maxdgram); 264*e7ff5475SWarner Losh size = sizes[i]; 265*e7ff5475SWarner Losh /* No need to return */ 266*e7ff5475SWarner Losh } 267*e7ff5475SWarner Losh 268*e7ff5475SWarner Losh asprintf(&options[OPT_BLKSIZE2].o_reply, "%d", size); 269*e7ff5475SWarner Losh segsize = size; 270*e7ff5475SWarner Losh pktsize = size + 4; 271*e7ff5475SWarner Losh if (debug&DEBUG_OPTIONS) 272*e7ff5475SWarner Losh tftp_log(LOG_DEBUG, "Setting blksize2 to '%s'", 273*e7ff5475SWarner Losh options[OPT_BLKSIZE2].o_reply); 274*e7ff5475SWarner Losh 275*e7ff5475SWarner Losh return (0); 276*e7ff5475SWarner Losh } 277*e7ff5475SWarner Losh 278*e7ff5475SWarner Losh /* 279*e7ff5475SWarner Losh * Append the available options to the header 280*e7ff5475SWarner Losh */ 281*e7ff5475SWarner Losh uint16_t 282*e7ff5475SWarner Losh make_options(int peer, char *buffer, uint16_t size) { 283*e7ff5475SWarner Losh int i; 284*e7ff5475SWarner Losh char *value; 285*e7ff5475SWarner Losh const char *option; 286*e7ff5475SWarner Losh uint16_t length; 287*e7ff5475SWarner Losh uint16_t returnsize = 0; 288*e7ff5475SWarner Losh 289*e7ff5475SWarner Losh if (!options_rfc_enabled) return (0); 290*e7ff5475SWarner Losh 291*e7ff5475SWarner Losh for (i = 0; options[i].o_type != NULL; i++) { 292*e7ff5475SWarner Losh if (options[i].rfc == 0 && !options_extra_enabled) 293*e7ff5475SWarner Losh continue; 294*e7ff5475SWarner Losh 295*e7ff5475SWarner Losh option = options[i].o_type; 296*e7ff5475SWarner Losh if (acting_as_client) 297*e7ff5475SWarner Losh value = options[i].o_request; 298*e7ff5475SWarner Losh else 299*e7ff5475SWarner Losh value = options[i].o_reply; 300*e7ff5475SWarner Losh if (value == NULL) 301*e7ff5475SWarner Losh continue; 302*e7ff5475SWarner Losh 303*e7ff5475SWarner Losh length = strlen(value) + strlen(option) + 2; 304*e7ff5475SWarner Losh if (size <= length) { 305*e7ff5475SWarner Losh tftp_log(LOG_ERR, 306*e7ff5475SWarner Losh "Running out of option space for " 307*e7ff5475SWarner Losh "option '%s' with value '%s': " 308*e7ff5475SWarner Losh "needed %d bytes, got %d bytes", 309*e7ff5475SWarner Losh option, value, size, length); 310*e7ff5475SWarner Losh continue; 311*e7ff5475SWarner Losh } 312*e7ff5475SWarner Losh 313*e7ff5475SWarner Losh sprintf(buffer, "%s%c%s%c", option, '\000', value, '\000'); 314*e7ff5475SWarner Losh size -= length; 315*e7ff5475SWarner Losh buffer += length; 316*e7ff5475SWarner Losh returnsize += length; 317*e7ff5475SWarner Losh } 318*e7ff5475SWarner Losh 319*e7ff5475SWarner Losh return (returnsize); 320*e7ff5475SWarner Losh } 321*e7ff5475SWarner Losh 322*e7ff5475SWarner Losh /* 323*e7ff5475SWarner Losh * Parse the received options in the header 324*e7ff5475SWarner Losh */ 325*e7ff5475SWarner Losh int 326*e7ff5475SWarner Losh parse_options(int peer, char *buffer, uint16_t size) 327*e7ff5475SWarner Losh { 328*e7ff5475SWarner Losh int i, options_failed; 329*e7ff5475SWarner Losh char *c, *cp, *option, *value; 330*e7ff5475SWarner Losh 331*e7ff5475SWarner Losh if (!options_rfc_enabled) return (0); 332*e7ff5475SWarner Losh 333*e7ff5475SWarner Losh /* Parse the options */ 334*e7ff5475SWarner Losh cp = buffer; 335*e7ff5475SWarner Losh options_failed = 0; 336*e7ff5475SWarner Losh while (size > 0) { 337*e7ff5475SWarner Losh option = cp; 338*e7ff5475SWarner Losh i = get_field(peer, cp, size); 339*e7ff5475SWarner Losh cp += i; 340*e7ff5475SWarner Losh 341*e7ff5475SWarner Losh value = cp; 342*e7ff5475SWarner Losh i = get_field(peer, cp, size); 343*e7ff5475SWarner Losh cp += i; 344*e7ff5475SWarner Losh 345*e7ff5475SWarner Losh /* We are at the end */ 346*e7ff5475SWarner Losh if (*option == '\0') break; 347*e7ff5475SWarner Losh 348*e7ff5475SWarner Losh if (debug&DEBUG_OPTIONS) 349*e7ff5475SWarner Losh tftp_log(LOG_DEBUG, 350*e7ff5475SWarner Losh "option: '%s' value: '%s'", option, value); 351*e7ff5475SWarner Losh 352*e7ff5475SWarner Losh for (c = option; *c; c++) 353*e7ff5475SWarner Losh if (isupper(*c)) 354*e7ff5475SWarner Losh *c = tolower(*c); 355*e7ff5475SWarner Losh for (i = 0; options[i].o_type != NULL; i++) { 356*e7ff5475SWarner Losh if (strcmp(option, options[i].o_type) == 0) { 357*e7ff5475SWarner Losh if (!acting_as_client) 358*e7ff5475SWarner Losh options[i].o_request = value; 359*e7ff5475SWarner Losh if (!options_extra_enabled && !options[i].rfc) { 360*e7ff5475SWarner Losh tftp_log(LOG_INFO, 361*e7ff5475SWarner Losh "Option '%s' with value '%s' found " 362*e7ff5475SWarner Losh "but it is not an RFC option", 363*e7ff5475SWarner Losh option, value); 364*e7ff5475SWarner Losh continue; 365*e7ff5475SWarner Losh } 366*e7ff5475SWarner Losh if (options[i].o_handler) 367*e7ff5475SWarner Losh options_failed += 368*e7ff5475SWarner Losh (options[i].o_handler)(peer); 369*e7ff5475SWarner Losh break; 370*e7ff5475SWarner Losh } 371*e7ff5475SWarner Losh } 372*e7ff5475SWarner Losh if (options[i].o_type == NULL) 373*e7ff5475SWarner Losh tftp_log(LOG_WARNING, 374*e7ff5475SWarner Losh "Unknown option: '%s'", option); 375*e7ff5475SWarner Losh 376*e7ff5475SWarner Losh size -= strlen(option) + strlen(value) + 2; 377*e7ff5475SWarner Losh } 378*e7ff5475SWarner Losh 379*e7ff5475SWarner Losh return (options_failed); 380*e7ff5475SWarner Losh } 381*e7ff5475SWarner Losh 382*e7ff5475SWarner Losh /* 383*e7ff5475SWarner Losh * Set some default values in the options 384*e7ff5475SWarner Losh */ 385*e7ff5475SWarner Losh void 386*e7ff5475SWarner Losh init_options(void) 387*e7ff5475SWarner Losh { 388*e7ff5475SWarner Losh 389*e7ff5475SWarner Losh options[OPT_ROLLOVER].o_request = strdup("0"); 390*e7ff5475SWarner Losh } 391