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.2 2014/02/21 09:09:15 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:
49:
50: intptr_t Kill;
51: struct tagCli cli;
52: cfg_root_t cfg;
53: sched_root_task_t *root;
54: char szCfgName[PATH_MAX] = DEFAULT_CFGNAME;
55: struct timespec timeout = { DEFAULT_TIMEOUT, 0 };
56: extern char compiled[], compiledby[], compilehost[];
57:
58: const struct tagErr errs[9] = {
59: { 0, "Not defined" },
60: { 1, "File not found" },
61: { 2, "Access violation" },
62: { 3, "Disk full or allocation exceeded" },
63: { 4, "Illegal TFTP operation" },
64: { 5, "Unknown transfer ID" },
65: { 6, "File already exists" },
66: { 7, "No such user" },
67: { 8, "Option not supported" },
68: };
69:
70: static void
71: Usage()
72: {
73: printf( " -= TFTPd =- ELWIX extended TFTP service\n"
74: "=== %s === %s@%s ===\n\n"
75: " Syntax: TFTPd [options]\n\n"
76: "\t-c <config>\tConfig file [default=/etc/tftpd.conf]\n"
77: "\t-w\t\tSwitch to read-write mode [default=read-only]\n"
78: "\t-b\t\tRun into batch mode (default is daemon mode)\n"
79: "\t-v\t\tVerbose (more -v, more verbosity ...)\n"
80: "\t-h\t\tThis help screen!\n"
81: "\n", compiled, compiledby, compilehost);
82: }
83:
84: static void *
85: sigHandler(sched_task_t *task)
86: {
87: int stat;
88: const char *str;
89:
90: switch (TASK_VAL(task)) {
91: case SIGHUP:
92: cfgUnloadConfig(&cfg);
93: if (cfgLoadConfig(szCfgName, &cfg)) {
94: ELIBERR(cfg);
95: Kill++;
96: } else
97: EVERBOSE(1, "Reloading config ...");
98:
99: str = cfg_getAttribute(&cfg, "tftpd", "timeout");
100: if (str)
101: timeout.tv_sec = strtol(str, NULL, 10);
102: break;
103: case SIGINT:
104: case SIGTERM:
105: EVERBOSE(1, "Terminate service ...");
106: Kill++;
107: break;
108: case SIGCHLD:
109: while (waitpid(-1, &stat, WNOHANG) > 0);
110: break;
111: default:
112: EERROR(EINVAL, "Unknown signal #%lu?", TASK_VAL(task));
113: break;
114: }
115:
116: schedSignalSelf(task);
117: taskExit(task, NULL);
118: }
119:
120: int
121: main(int argc, char **argv)
122: {
123: char ch, m = 0, b = 0;
124: const char *str;
125: int fd, uid = 0, ret = 0;
126: struct passwd *pass;
127: pid_t pid;
128: sockaddr_t sa;
129: rpack_t *pkt = NULL;
130:
131: while ((ch = getopt(argc, argv, "hvbwc:")) != -1)
132: switch (ch) {
133: case 'c':
134: strlcpy(szCfgName, optarg, sizeof szCfgName);
135: break;
136: case 'w':
137: m = 42; /* rw mode */
138: break;
139: case 'v':
140: e_incVerbose;
141: break;
142: case 'b':
143: b = 42;
144: break;
145: case 'h':
146: default:
147: Usage();
148: return 1;
149: }
150: argc -= optind;
151: argv += optind;
152:
153: openlog("TFTPd", LOG_PID | LOG_CONS, LOG_FTP);
154: if (cfgLoadConfig(szCfgName, &cfg)) {
155: ELIBERR(cfg);
156: return 2;
157: }
158:
159: str = cfg_getAttribute(&cfg, "tftpd", "user");
160: if (str) {
161: pass = getpwnam(str);
162: if (!pass) {
163: EERROR(EINVAL, "User %s not found!\n", str);
164: ret = 2;
165: goto end;
166: } else
167: uid = pass->pw_uid;
168: endpwent();
169: }
170:
171: if (!b) /* service mode */
172: switch ((pid = fork())) {
173: case -1:
174: ret = 3;
175: goto end;
176: case 0:
177: setsid();
178: chdir("/");
179:
180: fd = open(_PATH_DEVNULL, O_RDWR);
181: if (fd > 2) {
182: dup2(fd, STDIN_FILENO);
183: dup2(fd, STDOUT_FILENO);
184: dup2(fd, STDERR_FILENO);
185: close(fd);
186: }
187: EVERBOSE(1, "Welcome to the shadow-land!\n");
188: break;
189: default:
190: EVERBOSE(1, "Starting service with pid=%d ...\n", pid);
191: goto end;
192: }
193:
194: root = schedBegin();
195: if (!root) {
196: ELIBERR(sched);
197: ret = 3;
198: goto end;
199: }
200:
201: str = cfg_getAttribute(&cfg, "tftpd", "timeout");
202: if (str)
203: timeout.tv_sec = strtol(str, NULL, 10);
204:
205: str = cfg_getAttribute(&cfg, "tftpd", "port");
206: if (str)
207: fd = strtol(str, NULL, 10);
208: else
209: fd = 69;
210: str = cfg_getAttribute(&cfg, "tftpd", "bind");
211: e_gethostbyname(str ? str : "0.0.0.0", fd, &sa);
212: fd = socket(sa.sa.sa_family, SOCK_DGRAM, IPPROTO_UDP);
213: if (fd == -1) {
214: ESYSERR(0);
215: ret = 4;
216: goto end;
217: }
218: if (bind(fd, &sa.sa, sa.sa.sa_len) == -1) {
219: ESYSERR(0);
220: close(fd);
221: ret = 4;
222: goto end;
223: }
224:
225: str = cfg_getAttribute(&cfg, "tftpd", "chroot");
226: if (str && chroot(str) == -1) {
227: ESYSERR(0);
228: close(fd);
229: ret = 3;
230: goto end;
231: } else {
232: setuid(uid);
233: str = cfg_getAttribute(&cfg, "tftpd", "dir");
234: if (str)
235: chdir(str);
236: }
237:
238: if (!(pkt = rpack_create(NULL, 0))) {
239: ELIBERR(elwix);
240: close(fd);
241: ret = 5;
242: goto end;
243: }
244: if (rpack_attach(pkt, TFTP_PKT_MAX)) {
245: ELIBERR(elwix);
246: close(fd);
247: ret = 5;
248: goto end;
249: }
250:
251: memset(&cli, 0, sizeof cli);
252: schedSignal(root, sigHandler, NULL, SIGHUP, NULL, 0);
253: schedSignal(root, sigHandler, NULL, SIGTERM, NULL, 0);
254: schedSignal(root, sigHandler, NULL, SIGINT, NULL, 0);
255: schedSignal(root, sigHandler, NULL, SIGCHLD, NULL, 0);
256: schedRead(root, rxPkt, NULL, fd, pkt, sizeof(rpack_t));
257: schedRun(root, &Kill);
258:
259: close(fd);
260: end:
261: schedEnd(&root);
262: rpack_detach(pkt);
263: rpack_destroy(&pkt);
264: cfgUnloadConfig(&cfg);
265: closelog();
266: return ret;
267: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>