Annotation of tftpd/src/srv.c, revision 1.2.2.6
1.1 misho 1: #include "global.h"
1.2 misho 2: #include "exec.h"
3: #include "srv.h"
1.1 misho 4:
5:
6: static void *
7: timeoutSession(sched_task_t *task)
8: {
9: ETRACE();
10:
11: /* drop session */
12: if (cli.fd > 2)
13: close(cli.fd);
14: memset(&cli, 0, sizeof cli);
15:
16: taskExit(task, NULL);
17: }
18:
19: static void *
20: txPkt(sched_task_t *task)
21: {
22: int wlen;
23: rpack_t *pkt = TASK_DATA(task);
24: struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
25:
26: ETRACE();
27:
28: wlen = sendto(TASK_FD(task), RPACK_BUF(pkt), TASK_DATLEN(task),
29: 0, &cli.addr.sa, cli.addr.sa.sa_len);
30: if (wlen == -1)
31: ESYSERR(0);
32: else if (wlen != TASK_DATLEN(task)) {
33: EERROR(EIO, "Sended %d bytes != packet %d bytes",
34: wlen, TASK_DATLEN(task));
1.2 misho 35: schedEvent(TASK_ROOT(task), execProg, "error", 0, NULL, TFTP_OPC_ERROR);
1.1 misho 36: schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_CALL,
37: timeoutSession, NULL);
1.2 misho 38: schedEvent(TASK_ROOT(task), timeoutSession, NULL, 0, NULL, 0);
1.1 misho 39: } else
40: EVERBOSE(2, "Sended %d bytes", wlen);
41: /* on error or argument, drop session */
42: if (TASK_ARG(task) == (void*) -1 || ntohs(tftp->tftp_opc) == TFTP_OPC_ERROR) {
1.2 misho 43: schedEvent(TASK_ROOT(task), execProg, "error", 0, NULL, TFTP_OPC_ERROR);
1.1 misho 44: schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_CALL,
45: timeoutSession, NULL);
1.2 misho 46: schedEvent(TASK_ROOT(task), timeoutSession, NULL, 0, NULL, 0);
1.1 misho 47: }
48:
49: taskExit(task, NULL);
50: }
51:
52: static void *
53: txData(sched_task_t *task)
54: {
55: rpack_t *pkt = TASK_DATA(task);
56: u_short code = 0, n = htons(TFTP_OPC_DATA);
57: int len;
58:
59: ETRACE();
60:
61: RPACK_REWIND(pkt);
62: rpack_uint16(pkt, &n, 0);
63: n = htons(cli.seq);
64: rpack_uint16(pkt, &n, 0);
65:
1.2.2.4 misho 66: /* max file size check */
1.2.2.6 ! misho 67: if (cli.tsiz && cli.tsiz < cli.seq * cli.siz) {
! 68: len = cli.tsiz - (cli.seq - 1) * cli.siz;
1.2.2.4 misho 69: cli.close = 42; /* last sended packet, should be close! */
70: } else
71: len = cli.siz;
72:
73: len = pread(cli.fd, RPACK_NEXT(pkt), len, (cli.seq - 1) * cli.siz);
1.1 misho 74: if (len == -1) {
75: ESYSERR(0);
76: code = htole16(3);
77: goto end;
78: } else {
79: rpack_rnext(pkt, len);
80: EVERBOSE(3, "Read from file %s %d bytes", cli.file, len);
81: }
82:
83: if (cli.siz - len)
84: cli.close = 42; /* last sended packet, should be close! */
85:
86: schedEvent(TASK_ROOT(task), txPkt, NULL, TASK_FD(task),
87: TASK_DATA(task), RPACK_OFF(pkt));
88: taskExit(task, NULL);
89: end:
90: RPACK_REWIND(pkt);
91: n = htons(TFTP_OPC_ERROR);
92: rpack_uint16(pkt, &n, 0);
93: rpack_uint16(pkt, &code, 0);
94: rpack_rdata(pkt, errs[le16toh(code)].err_msg, strlen(errs[le16toh(code)].err_msg) + 1);
95:
96: schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task),
97: TASK_DATA(task), RPACK_OFF(pkt));
98: taskExit(task, NULL);
99: }
100:
101: static void *
102: txAck(sched_task_t *task)
103: {
104: rpack_t *pkt = TASK_DATA(task);
105: u_short n = htons(TFTP_OPC_ACK);
106:
107: ETRACE();
108:
109: RPACK_REWIND(pkt);
110: rpack_uint16(pkt, &n, 0);
111: n = htons(cli.seq);
112: rpack_uint16(pkt, &n, 0);
113:
114: schedEvent(TASK_ROOT(task), txPkt, NULL, TASK_FD(task),
115: TASK_DATA(task), RPACK_OFF(pkt));
116:
117: if (cli.close) {
1.2 misho 118: schedEvent(TASK_ROOT(task), execProg, "complete", 0, NULL, TFTP_OPC_WRQ);
1.1 misho 119: schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_CALL, timeoutSession, NULL);
120: schedEvent(TASK_ROOT(task), timeoutSession, NULL, 0, NULL, 0);
121: EVERBOSE(2, "Finish WRQ request");
122: }
123: taskExit(task, NULL);
124: }
125:
1.2.2.1 misho 126: static int
1.2.2.6 ! misho 127: getOpts(rpack_t * __restrict pkt, int rlen)
1.2.2.1 misho 128: {
1.2.2.2 misho 129: char *opt, *val;
130: int len;
131:
132: do {
133: /* option */
134: len = str_getString(RPACK_NEXT(pkt), RPACK_REMAIN(pkt), NULL);
135: if (len == -1)
136: return -1;
1.2.2.6 ! misho 137: else
! 138: rlen -= len;
1.2.2.2 misho 139: opt = (char*) rpack_rnext(pkt, len);
140: if (!opt)
141: return -1;
142: /* value */
143: len = str_getString(RPACK_NEXT(pkt), RPACK_REMAIN(pkt), NULL);
144: if (len == -1)
145: return -1;
1.2.2.6 ! misho 146: else
! 147: rlen -= len;
1.2.2.2 misho 148: val = (char*) rpack_rnext(pkt, len);
149: if (!val)
150: return -1;
151:
152: if (!strcasecmp(opt, TFTP_OPT_BLKSIZE)) {
153: len = strtol(val, NULL, 10);
1.2.2.6 ! misho 154: if (len > TFTP_LOAD_MAX) {
1.2.2.2 misho 155: cli.siz = len;
1.2.2.6 ! misho 156: if (rpack_resize(pkt, cli.siz + 4))
! 157: cli.siz = TFTP_PKT_MAX;
! 158: }
1.2.2.2 misho 159: } else if (!strcasecmp(opt, TFTP_OPT_TSIZE))
160: cli.tsiz = strtoll(val, NULL, 10);
161: else if (!strcasecmp(opt, TFTP_OPT_TIMEOUT))
162: cli.tout = strtol(val, NULL, 10);
1.2.2.6 ! misho 163: else if (!strcasecmp(opt, TFTP_OPT_ROLLOVER))
! 164: cli.roll = strtol(val, NULL, 10);
1.2.2.2 misho 165: else
166: return -1;
1.2.2.6 ! misho 167: } while (rlen > 0);
1.2.2.2 misho 168:
1.2.2.6 ! misho 169: EVERBOSE(4, "blksize=%u tsize=%llu timeout=%u rollover=%u",
! 170: cli.siz, cli.tsiz, cli.tout, cli.roll);
1.2.2.1 misho 171: return 0;
172: }
173:
174: static void *
175: txOack(sched_task_t *task)
176: {
177: rpack_t *pkt = TASK_DATA(task);
178: u_short n = htons(TFTP_OPC_OACK);
179: struct stat sb;
180: char szStr[STRSIZ];
181:
182: ETRACE();
183:
184: RPACK_REWIND(pkt);
185: rpack_uint16(pkt, &n, 0);
186:
187: /* if opcode is RRQ and tsize is 0 then we must return file size to client */
188: if (cli.opc == TFTP_OPC_RRQ && !cli.tsiz && stat(cli.file, &sb) != -1)
189: cli.tsiz = sb.st_size;
190:
191: if (cli.siz > TFTP_LOAD_MAX) {
192: memset(szStr, 0, sizeof szStr);
193: snprintf(szStr, sizeof szStr, "%u", cli.siz);
194: rpack_rdata(pkt, TFTP_OPT_BLKSIZE, strlen(TFTP_OPT_BLKSIZE) + 1);
195: rpack_rdata(pkt, szStr, strlen(szStr) + 1);
196: }
197: if (cli.tsiz) {
198: memset(szStr, 0, sizeof szStr);
199: snprintf(szStr, sizeof szStr, "%llu", cli.tsiz);
200: rpack_rdata(pkt, TFTP_OPT_TSIZE, strlen(TFTP_OPT_TSIZE) + 1);
201: rpack_rdata(pkt, szStr, strlen(szStr) + 1);
202: }
203: if (cli.tout) {
204: memset(szStr, 0, sizeof szStr);
205: snprintf(szStr, sizeof szStr, "%u", cli.tout);
206: rpack_rdata(pkt, TFTP_OPT_TIMEOUT, strlen(TFTP_OPT_TIMEOUT) + 1);
207: rpack_rdata(pkt, szStr, strlen(szStr) + 1);
208: }
1.2.2.6 ! misho 209: if (cli.roll) {
! 210: memset(szStr, 0, sizeof szStr);
! 211: snprintf(szStr, sizeof szStr, "%u", cli.roll);
! 212: rpack_rdata(pkt, TFTP_OPT_ROLLOVER, strlen(TFTP_OPT_ROLLOVER) + 1);
! 213: rpack_rdata(pkt, szStr, strlen(szStr) + 1);
! 214: }
1.2.2.1 misho 215:
1.2.2.6 ! misho 216: EVERBOSE(4, "blksize=%u tsize=%llu timeout=%u rollover=%u",
! 217: cli.siz, cli.tsiz, cli.tout, cli.roll);
1.2.2.1 misho 218: schedEvent(TASK_ROOT(task), txPkt, NULL, TASK_FD(task),
219: TASK_DATA(task), RPACK_OFF(pkt));
220: taskExit(task, NULL);
221: }
222:
1.1 misho 223: static void *
224: RQ(sched_task_t *task)
225: {
226: rpack_t *pkt = TASK_DATA(task);
227: struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
228: int len, rlen = TASK_DATLEN(task) - 2;
229: char *str;
230: u_short code = 0;
231:
232: ETRACE();
233:
234: cli.siz = TFTP_LOAD_MAX;
1.2.2.6 ! misho 235: cli.opc = ntohs(rpack_uint16(pkt, NULL, 0));
1.1 misho 236: len = str_getString(tftp->tftp_data, rlen, &str);
237: if (len == -1)
238: goto end;
239: else {
240: rlen -= len;
1.2.2.6 ! misho 241: rpack_rnext(pkt, len);
1.1 misho 242: strlcpy(cli.file, (char*) tftp->tftp_data, sizeof cli.file);
243: }
244: len = str_getString((const u_char*) str, rlen, NULL);
245: if (len == -1)
246: goto end;
247: else {
248: rlen -= len;
1.2.2.6 ! misho 249: rpack_rnext(pkt, len);
1.1 misho 250: if (!strcasecmp(str, TFTP_MODE_ASCII))
251: strlcpy(cli.mode, TFTP_MODE_ASCII, sizeof cli.mode);
252: else if (!strcasecmp(str, TFTP_MODE_OCTET))
253: strlcpy(cli.mode, TFTP_MODE_OCTET, sizeof cli.mode);
254: else if (!strcasecmp(str, TFTP_MODE_MAIL)) {
255: strlcpy(cli.mode, TFTP_MODE_MAIL, sizeof cli.mode);
256: code = htole16(4);
257: goto end;
258: } else {
259: code = htole16(1);
260: goto end;
261: }
262: }
263:
264: switch (cli.opc) {
265: case TFTP_OPC_RRQ:
266: code = O_RDONLY;
267: EVERBOSE(2, "RRQ:: file=%s mode=%s\n", cli.file, cli.mode);
268: break;
269: case TFTP_OPC_WRQ:
270: code = O_WRONLY | O_CREAT;
271: str = (char*) cfg_getAttribute(&cfg, "tftpd", "override");
272: if (!str || tolower(*str) != 'y')
273: code |= O_EXCL;
274: EVERBOSE(2, "WRQ:: file=%s mode=%s\n", cli.file, cli.mode);
275: break;
276: }
1.2.2.1 misho 277:
1.1 misho 278: cli.fd = open(cli.file, code, 0644);
279: if (cli.fd == -1) {
280: if (errno == EACCES)
281: code = htole16(2);
282: else if (errno == ENFILE)
283: code = htole16(3);
284: else if (errno == EEXIST)
285: code = htole16(6);
286: else
287: code = htole16(0);
288: ESYSERR(0);
289: goto end;
290: } else
291: cli.seq = 0;
292:
1.2 misho 293: schedEvent(TASK_ROOT(task), execProg, "request", 0, NULL, cli.opc);
294:
1.2.2.6 ! misho 295: if (!RPACK_ISEND(pkt) && !getOpts(pkt, rlen))
! 296: schedEvent(TASK_ROOT(task), txOack, NULL, TASK_FD(task),
! 297: TASK_DATA(task), 0);
! 298: else if (cli.opc == TFTP_OPC_WRQ) {
1.1 misho 299: /* ack */
300: tftp->tftp_opc = htons(TFTP_OPC_ACK);
301: RPACK_REWIND(pkt);
302: rpack_uint16(pkt, NULL, 0);
303: rpack_uint16(pkt, &cli.seq, 0);
304:
305: schedEvent(TASK_ROOT(task), txPkt, NULL, TASK_FD(task),
306: TASK_DATA(task), RPACK_OFF(pkt));
307: } else
308: schedEvent(TASK_ROOT(task), txData, NULL, TASK_FD(task),
309: TASK_DATA(task), 0);
310:
311: cli.seq = 1; /* 1st ack */
312: taskExit(task, NULL);
313: end:
314: tftp->tftp_opc = htons(TFTP_OPC_ERROR);
315: RPACK_REWIND(pkt);
316: rpack_uint16(pkt, NULL, 0);
317: rpack_uint16(pkt, &code, 0);
318: rpack_rdata(pkt, errs[le16toh(code)].err_msg, strlen(errs[le16toh(code)].err_msg) + 1);
319:
320: schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task),
321: TASK_DATA(task), RPACK_OFF(pkt));
322: taskExit(task, NULL);
323: }
324:
325: static void *
326: ACK(sched_task_t *task)
327: {
328: rpack_t *pkt = TASK_DATA(task);
329: struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
330: u_short code;
331:
332: ETRACE();
333:
334: RPACK_REWIND(pkt);
335: code = rpack_uint16(pkt, NULL, 0);
336: if (ntohs(code) != TFTP_OPC_ACK) {
337: code = htole16(5);
338: goto end;
339: }
340:
341: code = rpack_uint16(pkt, NULL, 0);
342: if (ntohs(code) > cli.seq || (ntohs(code) < (cli.seq - 1))) {
343: code = htole16(5);
344: goto end;
345: } else if (ntohs(code) == cli.seq)
346: cli.seq++;
347:
348: EVERBOSE(3, "ACK:: seq=%hu; my new seq=%hu;", ntohs(code), cli.seq);
349:
350: if (!cli.close)
351: schedEvent(TASK_ROOT(task), txData, NULL, TASK_FD(task),
352: TASK_DATA(task), 0);
353: else {
1.2 misho 354: schedEvent(TASK_ROOT(task), execProg, "complete", 0, NULL, TFTP_OPC_RRQ);
1.1 misho 355: schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_CALL, timeoutSession, NULL);
356: schedEvent(TASK_ROOT(task), timeoutSession, NULL, 0, NULL, 0);
357: EVERBOSE(2, "Finish RRQ request");
358: }
359: taskExit(task, NULL);
360: end:
361: tftp->tftp_opc = htons(TFTP_OPC_ERROR);
362: RPACK_REWIND(pkt);
363: rpack_uint16(pkt, NULL, 0);
364: rpack_uint16(pkt, &code, 0);
365: rpack_rdata(pkt, errs[le16toh(code)].err_msg, strlen(errs[le16toh(code)].err_msg) + 1);
366:
367: schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task),
368: TASK_DATA(task), RPACK_OFF(pkt));
369: taskExit(task, NULL);
370: }
371:
372: static void *
373: DATA(sched_task_t *task)
374: {
375: rpack_t *pkt = TASK_DATA(task);
376: struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
377: u_short code;
378: int len;
379:
380: ETRACE();
381:
382: RPACK_REWIND(pkt);
383: code = rpack_uint16(pkt, NULL, 0);
384: if (ntohs(code) != TFTP_OPC_DATA) {
385: code = htole16(5);
386: goto end;
387: }
388:
389: code = rpack_uint16(pkt, NULL, 0);
390: if (ntohs(code) < cli.seq || ntohs(code) > cli.seq + 1) {
391: code = htole16(5);
392: goto end;
393: } else
394: cli.seq = ntohs(code);
395:
1.2.2.4 misho 396: /* max file size check */
1.1 misho 397: len = TASK_DATLEN(task) - RPACK_OFF(pkt);
1.2.2.6 ! misho 398: if (cli.tsiz && cli.tsiz < cli.seq * cli.siz)
1.2.2.4 misho 399: len = MIN(len, cli.tsiz - (cli.seq - 1) * cli.siz);
1.1 misho 400: if (len < cli.siz)
401: cli.close = 42; /* last received packet, should be close! */
402:
403: EVERBOSE(3, "DATA:: seq=%hu; len=%d", cli.seq, len);
404:
405: len = pwrite(cli.fd, RPACK_NEXT(pkt), len, (cli.seq - 1) * cli.siz);
406: if (len == -1) {
407: ESYSERR(0);
408: code = htole16(3);
409: goto end;
410: } else {
411: rpack_rnext(pkt, len);
412: EVERBOSE(3, "Written to file %s %d bytes", cli.file, len);
413: }
414:
415: schedEvent(TASK_ROOT(task), txAck, NULL, TASK_FD(task), TASK_DATA(task), 0);
416: taskExit(task, NULL);
417: end:
418: tftp->tftp_opc = htons(TFTP_OPC_ERROR);
419: RPACK_REWIND(pkt);
420: rpack_uint16(pkt, NULL, 0);
421: rpack_uint16(pkt, &code, 0);
422: rpack_rdata(pkt, errs[le16toh(code)].err_msg, strlen(errs[le16toh(code)].err_msg) + 1);
423:
424: schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task),
425: TASK_DATA(task), RPACK_OFF(pkt));
426: taskExit(task, NULL);
427: }
428:
429: void *
430: rxPkt(sched_task_t *task)
431: {
432: sockaddr_t sa;
433: socklen_t salen = sizeof sa;
434: int rlen;
435: rpack_t *pkt = TASK_DATA(task);
436: struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
437: u_short code;
438:
439: ETRACE();
440:
441: memset(RPACK_BUF(pkt), 0, RPACK_LEN(pkt));
442: rlen = recvfrom(TASK_FD(task), RPACK_BUF(pkt), RPACK_LEN(pkt), 0, &sa.sa, &salen);
443: if (rlen == -1) {
444: ESYSERR(0);
445: goto end;
446: } else if (!cli.addr.sa.sa_len) {
447: cli.addr = sa;
448: switch (ntohs(tftp->tftp_opc)) {
449: case TFTP_OPC_RRQ:
450: case TFTP_OPC_WRQ:
451: schedEvent(TASK_ROOT(task), RQ, NULL, TASK_FD(task),
452: TASK_DATA(task), rlen);
453: break;
454: case TFTP_OPC_ERROR:
455: default:
456: RPACK_REWIND(pkt);
457: code = htons(TFTP_OPC_ERROR);
458: rpack_uint16(pkt, &code, 0);
459: code = htole16(4);
460: rpack_uint16(pkt, &code, 0);
461: rpack_rdata(pkt, errs[4].err_msg, strlen(errs[4].err_msg) + 1);
462:
463: schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task),
464: TASK_DATA(task), RPACK_OFF(pkt));
465: goto end;
466: }
467: } else if (memcmp(&cli.addr, &sa, salen)) {
468: EERROR(LOG_WARNING, "Packet dropped!!!\n"
469: "Get frame from different address for this session");
470: goto end;
471: } else
472: switch (ntohs(tftp->tftp_opc)) {
473: case TFTP_OPC_ACK:
474: schedEvent(TASK_ROOT(task), ACK, NULL, TASK_FD(task),
475: TASK_DATA(task), rlen);
476: break;
477: case TFTP_OPC_DATA:
478: schedEvent(TASK_ROOT(task), DATA, NULL, TASK_FD(task),
479: TASK_DATA(task), rlen);
480: break;
481: case TFTP_OPC_OACK:
482: case TFTP_OPC_ERROR:
483: default:
484: RPACK_REWIND(pkt);
485: code = htons(TFTP_OPC_ERROR);
486: rpack_uint16(pkt, &code, 0);
487: code = htole16(4);
488: rpack_uint16(pkt, &code, 0);
489: rpack_rdata(pkt, errs[4].err_msg, strlen(errs[4].err_msg) + 1);
490:
491: schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task),
492: TASK_DATA(task), RPACK_OFF(pkt));
493: goto end;
494: }
495:
496: schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_CALL, timeoutSession, NULL);
497: schedTimer(TASK_ROOT(task), timeoutSession, NULL, timeout, NULL, 0);
498: end:
499: schedReadSelf(task);
500: taskExit(task, NULL);
501: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>