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