|
|
1.1 root 1: /*
2: * tftp.c - a simple, read-only tftp server for qemu
1.1.1.2 root 3: *
1.1 root 4: * Copyright (c) 2004 Magnus Damm <[email protected]>
1.1.1.2 root 5: *
1.1 root 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>
1.1.1.3 ! root 26: #include "qemu-common.h" // for pstrcpy
1.1 root 27:
28: struct tftp_session {
29: int in_use;
30: unsigned char filename[TFTP_FILENAME_MAX];
1.1.1.2 root 31:
1.1 root 32: struct in_addr client_ip;
33: u_int16_t client_port;
1.1.1.2 root 34:
1.1 root 35: int timestamp;
36: };
37:
1.1.1.2 root 38: static struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX];
1.1 root 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;
1.1.1.2 root 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;
1.1 root 113:
1.1.1.2 root 114: fd = open(buffer, O_RDONLY | O_BINARY);
1.1 root 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:
1.1.1.2 root 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);
1.1.1.3 ! root 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;
1.1.1.2 root 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,
1.1 root 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:
1.1.1.2 root 189: m->m_data += IF_MAXLINKHDR;
1.1 root 190: tp = (void *)m->m_data;
191: m->m_data += sizeof(struct udpiphdr);
1.1.1.2 root 192:
1.1 root 193: tp->tp_op = htons(TFTP_ERROR);
194: tp->x.tp_error.tp_error_code = htons(errorcode);
1.1.1.3 ! root 195: pstrcpy((char *)tp->x.tp_error.tp_msg, sizeof(tp->x.tp_error.tp_msg), msg);
1.1 root 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:
1.1.1.2 root 205: m->m_len = sizeof(struct tftp_t) - 514 + 3 + strlen(msg) -
1.1 root 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:
1.1.1.2 root 215: static int tftp_send_data(struct tftp_session *spt,
1.1 root 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:
1.1.1.2 root 236: m->m_data += IF_MAXLINKHDR;
1.1 root 237: tp = (void *)m->m_data;
238: m->m_data += sizeof(struct udpiphdr);
1.1.1.2 root 239:
1.1 root 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:
1.1.1.2 root 261: m->m_len = sizeof(struct tftp_t) - (512 - nobytes) -
1.1 root 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: }
1.1.1.2 root 303:
1.1 root 304: if (src[k] == '\0') {
305: break;
306: }
307: }
1.1.1.2 root 308:
1.1 root 309: if (k >= n) {
310: return;
311: }
1.1.1.2 root 312:
1.1 root 313: k++;
1.1.1.2 root 314:
1.1 root 315: /* check mode */
316: if ((n - k) < 6) {
317: return;
318: }
1.1.1.2 root 319:
1.1 root 320: if (memcmp(&src[k], "octet\0", 6) != 0) {
321: tftp_send_error(spt, 4, "Unsupported transfer mode", tp);
322: return;
323: }
324:
1.1.1.2 root 325: k += 6; /* skipping octet */
326:
1.1 root 327: /* do sanity checks on the filename */
328:
329: if ((spt->filename[0] != '/')
1.1.1.3 ! root 330: || (spt->filename[strlen((char *)spt->filename) - 1] == '/')
! 331: || strstr((char *)spt->filename, "/../")) {
1.1 root 332: tftp_send_error(spt, 2, "Access violation", tp);
333: return;
334: }
335:
336: /* only allow exported prefixes */
337:
1.1.1.2 root 338: if (!tftp_prefix) {
1.1 root 339: tftp_send_error(spt, 2, "Access violation", tp);
340: return;
341: }
342:
343: /* check if the file exists */
1.1.1.2 root 344:
1.1 root 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:
1.1.1.2 root 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:
1.1.1.3 ! root 358: key = (char *)src + k;
1.1.1.2 root 359: k += strlen(key) + 1;
360:
361: if (k >= n) {
362: tftp_send_error(spt, 2, "Access violation", tp);
363: return;
364: }
365:
1.1.1.3 ! root 366: value = (char *)src + k;
1.1.1.2 root 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:
1.1 root 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:
1.1.1.2 root 405: if (tftp_send_data(&tftp_sessions[s],
406: ntohs(tp->x.tp_data.tp_block_nr) + 1,
1.1 root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.