Annotation of tftpd/src/srv.c, revision 1.2.2.7
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:
1.2.2.7 ! misho 132: if (!rlen)
! 133: return -1;
! 134:
1.2.2.2 misho 135: do {
136: /* option */
137: len = str_getString(RPACK_NEXT(pkt), RPACK_REMAIN(pkt), NULL);
138: if (len == -1)
139: return -1;
1.2.2.6 misho 140: else
141: rlen -= len;
1.2.2.2 misho 142: opt = (char*) rpack_rnext(pkt, len);
143: if (!opt)
144: return -1;
1.2.2.7 ! misho 145: EVERBOSE(7, "opt=%s rlen=%d", opt, rlen);
1.2.2.2 misho 146: /* value */
147: len = str_getString(RPACK_NEXT(pkt), RPACK_REMAIN(pkt), NULL);
148: if (len == -1)
149: return -1;
1.2.2.6 misho 150: else
151: rlen -= len;
1.2.2.2 misho 152: val = (char*) rpack_rnext(pkt, len);
153: if (!val)
154: return -1;
1.2.2.7 ! misho 155: EVERBOSE(7, "val=%s rlen=%d", val, rlen);
1.2.2.2 misho 156:
157: if (!strcasecmp(opt, TFTP_OPT_BLKSIZE)) {
1.2.2.7 ! misho 158: cli.tmp = strtol(val, NULL, 10);
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);
165: } while (rlen > 0);
1.2.2.2 misho 166:
1.2.2.6 misho 167: EVERBOSE(4, "blksize=%u tsize=%llu timeout=%u rollover=%u",
168: cli.siz, cli.tsiz, cli.tout, cli.roll);
1.2.2.1 misho 169: return 0;
170: }
171:
172: static void *
173: txOack(sched_task_t *task)
174: {
175: rpack_t *pkt = TASK_DATA(task);
176: u_short n = htons(TFTP_OPC_OACK);
177: struct stat sb;
178: char szStr[STRSIZ];
179:
180: ETRACE();
181:
182: RPACK_REWIND(pkt);
183: rpack_uint16(pkt, &n, 0);
184:
185: /* if opcode is RRQ and tsize is 0 then we must return file size to client */
186: if (cli.opc == TFTP_OPC_RRQ && !cli.tsiz && stat(cli.file, &sb) != -1)
187: cli.tsiz = sb.st_size;
188:
189: if (cli.siz > TFTP_LOAD_MAX) {
190: memset(szStr, 0, sizeof szStr);
191: snprintf(szStr, sizeof szStr, "%u", cli.siz);
192: rpack_rdata(pkt, TFTP_OPT_BLKSIZE, strlen(TFTP_OPT_BLKSIZE) + 1);
193: rpack_rdata(pkt, szStr, strlen(szStr) + 1);
194: }
195: if (cli.tsiz) {
196: memset(szStr, 0, sizeof szStr);
197: snprintf(szStr, sizeof szStr, "%llu", cli.tsiz);
198: rpack_rdata(pkt, TFTP_OPT_TSIZE, strlen(TFTP_OPT_TSIZE) + 1);
199: rpack_rdata(pkt, szStr, strlen(szStr) + 1);
200: }
201: if (cli.tout) {
202: memset(szStr, 0, sizeof szStr);
203: snprintf(szStr, sizeof szStr, "%u", cli.tout);
204: rpack_rdata(pkt, TFTP_OPT_TIMEOUT, strlen(TFTP_OPT_TIMEOUT) + 1);
205: rpack_rdata(pkt, szStr, strlen(szStr) + 1);
206: }
1.2.2.6 misho 207: if (cli.roll) {
208: memset(szStr, 0, sizeof szStr);
209: snprintf(szStr, sizeof szStr, "%u", cli.roll);
210: rpack_rdata(pkt, TFTP_OPT_ROLLOVER, strlen(TFTP_OPT_ROLLOVER) + 1);
211: rpack_rdata(pkt, szStr, strlen(szStr) + 1);
212: }
1.2.2.1 misho 213:
1.2.2.6 misho 214: EVERBOSE(4, "blksize=%u tsize=%llu timeout=%u rollover=%u",
215: cli.siz, cli.tsiz, cli.tout, cli.roll);
1.2.2.1 misho 216: schedEvent(TASK_ROOT(task), txPkt, NULL, TASK_FD(task),
217: TASK_DATA(task), RPACK_OFF(pkt));
218: taskExit(task, NULL);
219: }
220:
1.1 misho 221: static void *
222: RQ(sched_task_t *task)
223: {
224: rpack_t *pkt = TASK_DATA(task);
225: struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
226: int len, rlen = TASK_DATLEN(task) - 2;
227: char *str;
228: u_short code = 0;
229:
230: ETRACE();
231:
232: cli.siz = TFTP_LOAD_MAX;
1.2.2.6 misho 233: cli.opc = ntohs(rpack_uint16(pkt, NULL, 0));
1.1 misho 234: len = str_getString(tftp->tftp_data, rlen, &str);
235: if (len == -1)
236: goto end;
237: else {
238: rlen -= len;
1.2.2.6 misho 239: rpack_rnext(pkt, len);
1.1 misho 240: strlcpy(cli.file, (char*) tftp->tftp_data, sizeof cli.file);
241: }
242: len = str_getString((const u_char*) str, rlen, NULL);
243: if (len == -1)
244: goto end;
245: else {
246: rlen -= len;
1.2.2.6 misho 247: rpack_rnext(pkt, len);
1.1 misho 248: if (!strcasecmp(str, TFTP_MODE_ASCII))
249: strlcpy(cli.mode, TFTP_MODE_ASCII, sizeof cli.mode);
250: else if (!strcasecmp(str, TFTP_MODE_OCTET))
251: strlcpy(cli.mode, TFTP_MODE_OCTET, sizeof cli.mode);
252: else if (!strcasecmp(str, TFTP_MODE_MAIL)) {
253: strlcpy(cli.mode, TFTP_MODE_MAIL, sizeof cli.mode);
254: code = htole16(4);
255: goto end;
256: } else {
257: code = htole16(1);
258: goto end;
259: }
260: }
261:
262: switch (cli.opc) {
263: case TFTP_OPC_RRQ:
264: code = O_RDONLY;
265: EVERBOSE(2, "RRQ:: file=%s mode=%s\n", cli.file, cli.mode);
266: break;
267: case TFTP_OPC_WRQ:
268: code = O_WRONLY | O_CREAT;
269: str = (char*) cfg_getAttribute(&cfg, "tftpd", "override");
270: if (!str || tolower(*str) != 'y')
271: code |= O_EXCL;
272: EVERBOSE(2, "WRQ:: file=%s mode=%s\n", cli.file, cli.mode);
273: break;
274: }
1.2.2.1 misho 275:
1.1 misho 276: cli.fd = open(cli.file, code, 0644);
277: if (cli.fd == -1) {
278: if (errno == EACCES)
279: code = htole16(2);
280: else if (errno == ENFILE)
281: code = htole16(3);
282: else if (errno == EEXIST)
283: code = htole16(6);
284: else
285: code = htole16(0);
286: ESYSERR(0);
287: goto end;
288: } else
289: cli.seq = 0;
290:
1.2 misho 291: schedEvent(TASK_ROOT(task), execProg, "request", 0, NULL, cli.opc);
292:
1.2.2.7 ! misho 293: if (!getOpts(pkt, rlen)) {
! 294: if (cli.tmp > TFTP_LOAD_MAX) {
! 295: if (rpack_resize(pkt, cli.tmp + 4))
! 296: ELIBERR(elwix);
! 297: else
! 298: cli.siz = cli.tmp;
! 299: }
1.2.2.6 misho 300: schedEvent(TASK_ROOT(task), txOack, NULL, TASK_FD(task),
301: TASK_DATA(task), 0);
1.2.2.7 ! misho 302: } else if (cli.opc == TFTP_OPC_WRQ) {
1.1 misho 303: /* ack */
304: tftp->tftp_opc = htons(TFTP_OPC_ACK);
305: RPACK_REWIND(pkt);
306: rpack_uint16(pkt, NULL, 0);
307: rpack_uint16(pkt, &cli.seq, 0);
308:
309: schedEvent(TASK_ROOT(task), txPkt, NULL, TASK_FD(task),
310: TASK_DATA(task), RPACK_OFF(pkt));
311: } else
312: schedEvent(TASK_ROOT(task), txData, NULL, TASK_FD(task),
313: TASK_DATA(task), 0);
314:
315: cli.seq = 1; /* 1st ack */
316: taskExit(task, NULL);
317: end:
318: tftp->tftp_opc = htons(TFTP_OPC_ERROR);
319: RPACK_REWIND(pkt);
320: rpack_uint16(pkt, NULL, 0);
321: rpack_uint16(pkt, &code, 0);
322: rpack_rdata(pkt, errs[le16toh(code)].err_msg, strlen(errs[le16toh(code)].err_msg) + 1);
323:
324: schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task),
325: TASK_DATA(task), RPACK_OFF(pkt));
326: taskExit(task, NULL);
327: }
328:
329: static void *
330: ACK(sched_task_t *task)
331: {
332: rpack_t *pkt = TASK_DATA(task);
333: struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
334: u_short code;
335:
336: ETRACE();
337:
338: RPACK_REWIND(pkt);
339: code = rpack_uint16(pkt, NULL, 0);
340: if (ntohs(code) != TFTP_OPC_ACK) {
341: code = htole16(5);
342: goto end;
343: }
344:
345: code = rpack_uint16(pkt, NULL, 0);
346: if (ntohs(code) > cli.seq || (ntohs(code) < (cli.seq - 1))) {
347: code = htole16(5);
348: goto end;
349: } else if (ntohs(code) == cli.seq)
350: cli.seq++;
351:
352: EVERBOSE(3, "ACK:: seq=%hu; my new seq=%hu;", ntohs(code), cli.seq);
353:
354: if (!cli.close)
355: schedEvent(TASK_ROOT(task), txData, NULL, TASK_FD(task),
356: TASK_DATA(task), 0);
357: else {
1.2 misho 358: schedEvent(TASK_ROOT(task), execProg, "complete", 0, NULL, TFTP_OPC_RRQ);
1.1 misho 359: schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_CALL, timeoutSession, NULL);
360: schedEvent(TASK_ROOT(task), timeoutSession, NULL, 0, NULL, 0);
361: EVERBOSE(2, "Finish RRQ request");
362: }
363: taskExit(task, NULL);
364: end:
365: tftp->tftp_opc = htons(TFTP_OPC_ERROR);
366: RPACK_REWIND(pkt);
367: rpack_uint16(pkt, NULL, 0);
368: rpack_uint16(pkt, &code, 0);
369: rpack_rdata(pkt, errs[le16toh(code)].err_msg, strlen(errs[le16toh(code)].err_msg) + 1);
370:
371: schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task),
372: TASK_DATA(task), RPACK_OFF(pkt));
373: taskExit(task, NULL);
374: }
375:
376: static void *
377: DATA(sched_task_t *task)
378: {
379: rpack_t *pkt = TASK_DATA(task);
380: struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
381: u_short code;
382: int len;
383:
384: ETRACE();
385:
386: RPACK_REWIND(pkt);
387: code = rpack_uint16(pkt, NULL, 0);
388: if (ntohs(code) != TFTP_OPC_DATA) {
389: code = htole16(5);
390: goto end;
391: }
392:
393: code = rpack_uint16(pkt, NULL, 0);
394: if (ntohs(code) < cli.seq || ntohs(code) > cli.seq + 1) {
395: code = htole16(5);
396: goto end;
397: } else
398: cli.seq = ntohs(code);
399:
1.2.2.4 misho 400: /* max file size check */
1.1 misho 401: len = TASK_DATLEN(task) - RPACK_OFF(pkt);
1.2.2.6 misho 402: if (cli.tsiz && cli.tsiz < cli.seq * cli.siz)
1.2.2.4 misho 403: len = MIN(len, cli.tsiz - (cli.seq - 1) * cli.siz);
1.1 misho 404: if (len < cli.siz)
405: cli.close = 42; /* last received packet, should be close! */
406:
407: EVERBOSE(3, "DATA:: seq=%hu; len=%d", cli.seq, len);
408:
409: len = pwrite(cli.fd, RPACK_NEXT(pkt), len, (cli.seq - 1) * cli.siz);
410: if (len == -1) {
411: ESYSERR(0);
412: code = htole16(3);
413: goto end;
414: } else {
415: rpack_rnext(pkt, len);
416: EVERBOSE(3, "Written to file %s %d bytes", cli.file, len);
417: }
418:
419: schedEvent(TASK_ROOT(task), txAck, NULL, TASK_FD(task), TASK_DATA(task), 0);
420: taskExit(task, NULL);
421: end:
422: tftp->tftp_opc = htons(TFTP_OPC_ERROR);
423: RPACK_REWIND(pkt);
424: rpack_uint16(pkt, NULL, 0);
425: rpack_uint16(pkt, &code, 0);
426: rpack_rdata(pkt, errs[le16toh(code)].err_msg, strlen(errs[le16toh(code)].err_msg) + 1);
427:
428: schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task),
429: TASK_DATA(task), RPACK_OFF(pkt));
430: taskExit(task, NULL);
431: }
432:
433: void *
434: rxPkt(sched_task_t *task)
435: {
436: sockaddr_t sa;
437: socklen_t salen = sizeof sa;
438: int rlen;
439: rpack_t *pkt = TASK_DATA(task);
440: struct tftp_hdr *tftp = (struct tftp_hdr*) RPACK_BUF(pkt);
441: u_short code;
442:
443: ETRACE();
444:
445: memset(RPACK_BUF(pkt), 0, RPACK_LEN(pkt));
446: rlen = recvfrom(TASK_FD(task), RPACK_BUF(pkt), RPACK_LEN(pkt), 0, &sa.sa, &salen);
447: if (rlen == -1) {
448: ESYSERR(0);
449: goto end;
450: } else if (!cli.addr.sa.sa_len) {
451: cli.addr = sa;
452: switch (ntohs(tftp->tftp_opc)) {
453: case TFTP_OPC_RRQ:
454: case TFTP_OPC_WRQ:
455: schedEvent(TASK_ROOT(task), RQ, NULL, TASK_FD(task),
456: TASK_DATA(task), rlen);
457: break;
458: case TFTP_OPC_ERROR:
459: default:
460: RPACK_REWIND(pkt);
461: code = htons(TFTP_OPC_ERROR);
462: rpack_uint16(pkt, &code, 0);
463: code = htole16(4);
464: rpack_uint16(pkt, &code, 0);
465: rpack_rdata(pkt, errs[4].err_msg, strlen(errs[4].err_msg) + 1);
466:
467: schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task),
468: TASK_DATA(task), RPACK_OFF(pkt));
469: goto end;
470: }
471: } else if (memcmp(&cli.addr, &sa, salen)) {
472: EERROR(LOG_WARNING, "Packet dropped!!!\n"
473: "Get frame from different address for this session");
474: goto end;
475: } else
476: switch (ntohs(tftp->tftp_opc)) {
477: case TFTP_OPC_ACK:
478: schedEvent(TASK_ROOT(task), ACK, NULL, TASK_FD(task),
479: TASK_DATA(task), rlen);
480: break;
481: case TFTP_OPC_DATA:
482: schedEvent(TASK_ROOT(task), DATA, NULL, TASK_FD(task),
483: TASK_DATA(task), rlen);
484: break;
485: case TFTP_OPC_OACK:
486: case TFTP_OPC_ERROR:
487: default:
488: RPACK_REWIND(pkt);
489: code = htons(TFTP_OPC_ERROR);
490: rpack_uint16(pkt, &code, 0);
491: code = htole16(4);
492: rpack_uint16(pkt, &code, 0);
493: rpack_rdata(pkt, errs[4].err_msg, strlen(errs[4].err_msg) + 1);
494:
495: schedEvent(TASK_ROOT(task), txPkt, (void*) -1, TASK_FD(task),
496: TASK_DATA(task), RPACK_OFF(pkt));
497: goto end;
498: }
499:
500: schedCancelby(TASK_ROOT(task), taskTIMER, CRITERIA_CALL, timeoutSession, NULL);
501: schedTimer(TASK_ROOT(task), timeoutSession, NULL, timeout, NULL, 0);
502: end:
503: schedReadSelf(task);
504: taskExit(task, NULL);
505: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>