1 /* 2 * tftp.c - a simple, read-only tftp server for qemu 3 * 4 * Copyright (c) 2004 Magnus Damm <damm (at) opensource.se> 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 * THE SOFTWARE. 23 */ 24 25 #include <slirp.h> 26 #include "qemu-common.h" // for pstrcpy 27 28 struct tftp_session { 29 int in_use; 30 unsigned char filename[TFTP_FILENAME_MAX]; 31 32 struct in_addr client_ip; 33 u_int16_t client_port; 34 35 int timestamp; 36 }; 37 38 static struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX]; 39 40 const char *tftp_prefix; 41 42 static void tftp_session_update(struct tftp_session *spt) 43 { 44 spt->timestamp = curtime; 45 spt->in_use = 1; 46 } 47 48 static void tftp_session_terminate(struct tftp_session *spt) 49 { 50 spt->in_use = 0; 51 } 52 53 static int tftp_session_allocate(struct tftp_t *tp) 54 { 55 struct tftp_session *spt; 56 int k; 57 58 for (k = 0; k < TFTP_SESSIONS_MAX; k++) { 59 spt = &tftp_sessions[k]; 60 61 if (!spt->in_use) 62 goto found; 63 64 /* sessions time out after 5 inactive seconds */ 65 if ((int)(curtime - spt->timestamp) > 5000) 66 goto found; 67 } 68 69 return -1; 70 71 found: 72 memset(spt, 0, sizeof(*spt)); 73 memcpy(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip)); 74 spt->client_port = tp->udp.uh_sport; 75 76 tftp_session_update(spt); 77 78 return k; 79 } 80 81 static int tftp_session_find(struct tftp_t *tp) 82 { 83 struct tftp_session *spt; 84 int k; 85 86 for (k = 0; k < TFTP_SESSIONS_MAX; k++) { 87 spt = &tftp_sessions[k]; 88 89 if (spt->in_use) { 90 if (!memcmp(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip))) { 91 if (spt->client_port == tp->udp.uh_sport) { 92 return k; 93 } 94 } 95 } 96 } 97 98 return -1; 99 } 100 101 static int tftp_read_data(struct tftp_session *spt, u_int16_t block_nr, 102 u_int8_t *buf, int len) 103 { 104 int fd; 105 int bytes_read = 0; 106 char buffer[1024]; 107 int n; 108 109 n = snprintf(buffer, sizeof(buffer), "%s/%s", 110 tftp_prefix, spt->filename); 111 if (n >= sizeof(buffer)) 112 return -1; 113 114 fd = open(buffer, O_RDONLY | O_BINARY); 115 116 if (fd < 0) { 117 return -1; 118 } 119 120 if (len) { 121 lseek(fd, block_nr * 512, SEEK_SET); 122 123 bytes_read = read(fd, buf, len); 124 } 125 126 close(fd); 127 128 return bytes_read; 129 } 130 131 static int tftp_send_oack(struct tftp_session *spt, 132 const char *key, uint32_t value, 133 struct tftp_t *recv_tp) 134 { 135 struct sockaddr_in saddr, daddr; 136 struct mbuf *m; 137 struct tftp_t *tp; 138 int n = 0; 139 140 m = m_get(); 141 142 if (!m) 143 return -1; 144 145 memset(m->m_data, 0, m->m_size); 146 147 m->m_data += IF_MAXLINKHDR; 148 tp = (void *)m->m_data; 149 m->m_data += sizeof(struct udpiphdr); 150 151 tp->tp_op = htons(TFTP_OACK); 152 n += snprintf((char *)tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%s", 153 key) + 1; 154 n += snprintf((char *)tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%u", 155 value) + 1; 156 157 saddr.sin_addr = recv_tp->ip.ip_dst; 158 saddr.sin_port = recv_tp->udp.uh_dport; 159 160 daddr.sin_addr = spt->client_ip; 161 daddr.sin_port = spt->client_port; 162 163 m->m_len = sizeof(struct tftp_t) - 514 + n - 164 sizeof(struct ip) - sizeof(struct udphdr); 165 udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); 166 167 return 0; 168 } 169 170 171 172 static int tftp_send_error(struct tftp_session *spt, 173 u_int16_t errorcode, const char *msg, 174 struct tftp_t *recv_tp) 175 { 176 struct sockaddr_in saddr, daddr; 177 struct mbuf *m; 178 struct tftp_t *tp; 179 int nobytes; 180 181 m = m_get(); 182 183 if (!m) { 184 return -1; 185 } 186 187 memset(m->m_data, 0, m->m_size); 188 189 m->m_data += IF_MAXLINKHDR; 190 tp = (void *)m->m_data; 191 m->m_data += sizeof(struct udpiphdr); 192 193 tp->tp_op = htons(TFTP_ERROR); 194 tp->x.tp_error.tp_error_code = htons(errorcode); 195 pstrcpy((char *)tp->x.tp_error.tp_msg, sizeof(tp->x.tp_error.tp_msg), msg); 196 197 saddr.sin_addr = recv_tp->ip.ip_dst; 198 saddr.sin_port = recv_tp->udp.uh_dport; 199 200 daddr.sin_addr = spt->client_ip; 201 daddr.sin_port = spt->client_port; 202 203 nobytes = 2; 204 205 m->m_len = sizeof(struct tftp_t) - 514 + 3 + strlen(msg) - 206 sizeof(struct ip) - sizeof(struct udphdr); 207 208 udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); 209 210 tftp_session_terminate(spt); 211 212 return 0; 213 } 214 215 static int tftp_send_data(struct tftp_session *spt, 216 u_int16_t block_nr, 217 struct tftp_t *recv_tp) 218 { 219 struct sockaddr_in saddr, daddr; 220 struct mbuf *m; 221 struct tftp_t *tp; 222 int nobytes; 223 224 if (block_nr < 1) { 225 return -1; 226 } 227 228 m = m_get(); 229 230 if (!m) { 231 return -1; 232 } 233 234 memset(m->m_data, 0, m->m_size); 235 236 m->m_data += IF_MAXLINKHDR; 237 tp = (void *)m->m_data; 238 m->m_data += sizeof(struct udpiphdr); 239 240 tp->tp_op = htons(TFTP_DATA); 241 tp->x.tp_data.tp_block_nr = htons(block_nr); 242 243 saddr.sin_addr = recv_tp->ip.ip_dst; 244 saddr.sin_port = recv_tp->udp.uh_dport; 245 246 daddr.sin_addr = spt->client_ip; 247 daddr.sin_port = spt->client_port; 248 249 nobytes = tftp_read_data(spt, block_nr - 1, tp->x.tp_data.tp_buf, 512); 250 251 if (nobytes < 0) { 252 m_free(m); 253 254 /* send "file not found" error back */ 255 256 tftp_send_error(spt, 1, "File not found", tp); 257 258 return -1; 259 } 260 261 m->m_len = sizeof(struct tftp_t) - (512 - nobytes) - 262 sizeof(struct ip) - sizeof(struct udphdr); 263 264 udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); 265 266 if (nobytes == 512) { 267 tftp_session_update(spt); 268 } 269 else { 270 tftp_session_terminate(spt); 271 } 272 273 return 0; 274 } 275 276 static void tftp_handle_rrq(struct tftp_t *tp, int pktlen) 277 { 278 struct tftp_session *spt; 279 int s, k, n; 280 u_int8_t *src, *dst; 281 282 s = tftp_session_allocate(tp); 283 284 if (s < 0) { 285 return; 286 } 287 288 spt = &tftp_sessions[s]; 289 290 src = tp->x.tp_buf; 291 dst = spt->filename; 292 n = pktlen - ((uint8_t *)&tp->x.tp_buf[0] - (uint8_t *)tp); 293 294 /* get name */ 295 296 for (k = 0; k < n; k++) { 297 if (k < TFTP_FILENAME_MAX) { 298 dst[k] = src[k]; 299 } 300 else { 301 return; 302 } 303 304 if (src[k] == '\0') { 305 break; 306 } 307 } 308 309 if (k >= n) { 310 return; 311 } 312 313 k++; 314 315 /* check mode */ 316 if ((n - k) < 6) { 317 return; 318 } 319 320 if (memcmp(&src[k], "octet\0", 6) != 0) { 321 tftp_send_error(spt, 4, "Unsupported transfer mode", tp); 322 return; 323 } 324 325 k += 6; /* skipping octet */ 326 327 /* do sanity checks on the filename */ 328 329 if ((spt->filename[0] != '/') 330 || (spt->filename[strlen((char *)spt->filename) - 1] == '/') 331 || strstr((char *)spt->filename, "/../")) { 332 tftp_send_error(spt, 2, "Access violation", tp); 333 return; 334 } 335 336 /* only allow exported prefixes */ 337 338 if (!tftp_prefix) { 339 tftp_send_error(spt, 2, "Access violation", tp); 340 return; 341 } 342 343 /* check if the file exists */ 344 345 if (tftp_read_data(spt, 0, spt->filename, 0) < 0) { 346 tftp_send_error(spt, 1, "File not found", tp); 347 return; 348 } 349 350 if (src[n - 1] != 0) { 351 tftp_send_error(spt, 2, "Access violation", tp); 352 return; 353 } 354 355 while (k < n) { 356 const char *key, *value; 357 358 key = (char *)src + k; 359 k += strlen(key) + 1; 360 361 if (k >= n) { 362 tftp_send_error(spt, 2, "Access violation", tp); 363 return; 364 } 365 366 value = (char *)src + k; 367 k += strlen(value) + 1; 368 369 if (strcmp(key, "tsize") == 0) { 370 int tsize = atoi(value); 371 struct stat stat_p; 372 373 if (tsize == 0 && tftp_prefix) { 374 char buffer[1024]; 375 int len; 376 377 len = snprintf(buffer, sizeof(buffer), "%s/%s", 378 tftp_prefix, spt->filename); 379 380 if (stat(buffer, &stat_p) == 0) 381 tsize = stat_p.st_size; 382 else { 383 tftp_send_error(spt, 1, "File not found", tp); 384 return; 385 } 386 } 387 388 tftp_send_oack(spt, "tsize", tsize, tp); 389 } 390 } 391 392 tftp_send_data(spt, 1, tp); 393 } 394 395 static void tftp_handle_ack(struct tftp_t *tp, int pktlen) 396 { 397 int s; 398 399 s = tftp_session_find(tp); 400 401 if (s < 0) { 402 return; 403 } 404 405 if (tftp_send_data(&tftp_sessions[s], 406 ntohs(tp->x.tp_data.tp_block_nr) + 1, 407 tp) < 0) { 408 return; 409 } 410 } 411 412 void tftp_input(struct mbuf *m) 413 { 414 struct tftp_t *tp = (struct tftp_t *)m->m_data; 415 416 switch(ntohs(tp->tp_op)) { 417 case TFTP_RRQ: 418 tftp_handle_rrq(tp, m->m_len); 419 break; 420 421 case TFTP_ACK: 422 tftp_handle_ack(tp, m->m_len); 423 break; 424 } 425 } 426