1: /*************************************************************************
2: * (C) 2014 AITNET ltd - Sofia/Bulgaria - <misho@aitnet.org>
3: * by Michael Pounov <misho@elwix.org>
4: *
5: * $Author: misho $
6: * $Id: tftpd.c,v 1.4 2014/02/24 22:28:54 misho Exp $
7: *
8: **************************************************************************
9: The ELWIX and AITNET software is distributed under the following
10: terms:
11:
12: All of the documentation and software included in the ELWIX and AITNET
13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
14:
15: Copyright 2004 - 2014
16: by Michael Pounov <misho@elwix.org>. All rights reserved.
17:
18: Redistribution and use in source and binary forms, with or without
19: modification, are permitted provided that the following conditions
20: are met:
21: 1. Redistributions of source code must retain the above copyright
22: notice, this list of conditions and the following disclaimer.
23: 2. Redistributions in binary form must reproduce the above copyright
24: notice, this list of conditions and the following disclaimer in the
25: documentation and/or other materials provided with the distribution.
26: 3. All advertising materials mentioning features or use of this software
27: must display the following acknowledgement:
28: This product includes software developed by Michael Pounov <misho@elwix.org>
29: ELWIX - Embedded LightWeight unIX and its contributors.
30: 4. Neither the name of AITNET nor the names of its contributors
31: may be used to endorse or promote products derived from this software
32: without specific prior written permission.
33:
34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44: SUCH DAMAGE.
45: */
46: #include "global.h"
47: #include "srv.h"
48: #include "buf.h"
49: #include "exec.h"
50:
51:
52: intptr_t Kill;
53: struct tagCli cli;
54: cfg_root_t cfg;
55: sched_root_task_t *root;
56: rpack_t *bf;
57: char RW, szCfgName[PATH_MAX] = DEFAULT_CFGNAME;
58: struct timespec timeout = { DEFAULT_TIMEOUT, 0 };
59: extern char compiled[], compiledby[], compilehost[];
60:
61: const struct tagErr errs[9] = {
62: { 0, "Not defined" },
63: { 1, "File not found" },
64: { 2, "Access violation" },
65: { 3, "Disk full or allocation exceeded" },
66: { 4, "Illegal TFTP operation" },
67: { 5, "Unknown transfer ID" },
68: { 6, "File already exists" },
69: { 7, "No such user" },
70: { 8, "Option not supported" },
71: };
72:
73: static void
74: Usage()
75: {
76: printf( " -= TFTPd =- ELWIX extended TFTP service\n"
77: "=== %s === %s@%s ===\n\n"
78: " Syntax: TFTPd [options]\n\n"
79: "\t-c <config>\tConfig file [default=/etc/tftpd.conf]\n"
80: "\t-w\t\tSwitch to read-write mode [default=read-only]\n"
81: "\t-b\t\tRun into batch mode (default is daemon mode)\n"
82: "\t-R\t\tReboot after complete write file\n"
83: "\t-d\t\tDebug program\n"
84: "\t-v\t\tVerbose (more -v, more verbosity ...)\n"
85: "\t-h\t\tThis help screen!\n"
86: "\n", compiled, compiledby, compilehost);
87: }
88:
89: static void *
90: sigHandler(sched_task_t *task)
91: {
92: int stat;
93: const char *str;
94:
95: switch (TASK_VAL(task)) {
96: case SIGHUP:
97: cfgUnloadConfig(&cfg);
98: if (cfgLoadConfig(szCfgName, &cfg)) {
99: ELIBERR(cfg);
100: Kill++;
101: } else
102: EVERBOSE(1, "Reloading config ...");
103:
104: str = cfg_getAttribute(&cfg, "tftpd", "timeout");
105: if (str)
106: timeout.tv_sec = strtol(str, NULL, 10);
107:
108: endBuffer();
109: str = cfg_getAttribute(&cfg, "tftpd", "buf_io");
110: if (str)
111: initBuffer(strtol(str, NULL, 0));
112: break;
113: case SIGINT:
114: case SIGTERM:
115: EVERBOSE(1, "Terminate service ...");
116: Kill++;
117: break;
118: case SIGCHLD:
119: while (waitpid(-1, &stat, WNOHANG) > 0);
120: break;
121: default:
122: EERROR(EINVAL, "Unknown signal #%lu?", TASK_VAL(task));
123: break;
124: }
125:
126: schedSignalSelf(task);
127: taskExit(task, NULL);
128: }
129:
130: int
131: main(int argc, char **argv)
132: {
133: char ch, r = 0, b = 0;
134: const char *str;
135: int fd, uid = 0, ret = 0;
136: struct passwd *pass;
137: pid_t pid;
138: sockaddr_t sa;
139: rpack_t *pkt = NULL;
140:
141: while ((ch = getopt(argc, argv, "hvdRbwc:")) != -1)
142: switch (ch) {
143: case 'c':
144: strlcpy(szCfgName, optarg, sizeof szCfgName);
145: break;
146: case 'w':
147: RW = 42; /* rw mode */
148: break;
149: case 'v':
150: e_incVerbose;
151: break;
152: case 'd':
153: elwix_Debug |= ELWIX_DEBUG_TRACE;
154: break;
155: case 'b':
156: b = 42;
157: break;
158: case 'R':
159: r = 42;
160: break;
161: case 'h':
162: default:
163: Usage();
164: return 1;
165: }
166: argc -= optind;
167: argv += optind;
168:
169: openlog("TFTPd", LOG_PID | LOG_CONS, LOG_FTP);
170: if (cfgLoadConfig(szCfgName, &cfg)) {
171: ELIBERR(cfg);
172: return 2;
173: }
174:
175: str = cfg_getAttribute(&cfg, "tftpd", "user");
176: if (str) {
177: pass = getpwnam(str);
178: if (!pass) {
179: EERROR(EINVAL, "User %s not found!\n", str);
180: ret = 2;
181: goto end;
182: } else
183: uid = pass->pw_uid;
184: endpwent();
185: }
186:
187: if (!b) /* service mode */
188: switch ((pid = fork())) {
189: case -1:
190: ret = 3;
191: goto end;
192: case 0:
193: setsid();
194: chdir("/");
195:
196: fd = open(_PATH_DEVNULL, O_RDWR);
197: if (fd > 2) {
198: dup2(fd, STDIN_FILENO);
199: dup2(fd, STDOUT_FILENO);
200: dup2(fd, STDERR_FILENO);
201: close(fd);
202: }
203: EVERBOSE(1, "Welcome to the shadow-land!\n");
204: break;
205: default:
206: EVERBOSE(1, "Starting service with pid=%d ...\n", pid);
207: goto end;
208: }
209:
210: root = schedBegin();
211: if (!root) {
212: ELIBERR(sched);
213: ret = 3;
214: goto end;
215: }
216:
217: str = cfg_getAttribute(&cfg, "tftpd", "timeout");
218: if (str)
219: timeout.tv_sec = strtol(str, NULL, 10);
220:
221: str = cfg_getAttribute(&cfg, "tftpd", "port");
222: if (str)
223: fd = strtol(str, NULL, 10);
224: else
225: fd = 69;
226: str = cfg_getAttribute(&cfg, "tftpd", "bind");
227: e_gethostbyname(str ? str : "0.0.0.0", fd, &sa);
228: fd = socket(sa.sa.sa_family, SOCK_DGRAM, IPPROTO_UDP);
229: if (fd == -1) {
230: ESYSERR(0);
231: ret = 4;
232: goto end;
233: }
234: if (bind(fd, &sa.sa, sa.sa.sa_len) == -1) {
235: ESYSERR(0);
236: close(fd);
237: ret = 4;
238: goto end;
239: }
240:
241: str = cfg_getAttribute(&cfg, "tftpd", "chroot");
242: if (str && chroot(str) == -1) {
243: ESYSERR(0);
244: close(fd);
245: ret = 3;
246: goto end;
247: } else {
248: setuid(uid);
249: str = cfg_getAttribute(&cfg, "tftpd", "dir");
250: if (str)
251: chdir(str);
252: }
253:
254: str = cfg_getAttribute(&cfg, "tftpd", "buf_io");
255: if (str)
256: initBuffer(strtol(str, NULL, 0));
257:
258: if (!(pkt = rpack_create(NULL, 0))) {
259: ELIBERR(elwix);
260: close(fd);
261: ret = 5;
262: goto end;
263: }
264: if (rpack_attach(pkt, TFTP_PKT_MAX)) {
265: ELIBERR(elwix);
266: close(fd);
267: ret = 5;
268: goto end;
269: }
270:
271: memset(&cli, 0, sizeof cli);
272: if (r)
273: schedSuspend(root, Reboot, NULL, 0, NULL, 0);
274: schedSignal(root, sigHandler, NULL, SIGHUP, NULL, 0);
275: schedSignal(root, sigHandler, NULL, SIGTERM, NULL, 0);
276: schedSignal(root, sigHandler, NULL, SIGINT, NULL, 0);
277: schedSignal(root, sigHandler, NULL, SIGCHLD, NULL, 0);
278: schedRead(root, rxPkt, NULL, fd, pkt, sizeof(rpack_t));
279: schedRun(root, &Kill);
280:
281: close(fd);
282: end:
283: schedEnd(&root);
284: rpack_detach(pkt);
285: rpack_destroy(&pkt);
286: endBuffer();
287: cfgUnloadConfig(&cfg);
288: closelog();
289: return ret;
290: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>