Annotation of tftpd/src/tftpd.c, revision 1.2.2.1
1.2 misho 1: /*************************************************************************
2: * (C) 2014 AITNET ltd - Sofia/Bulgaria - <misho@aitnet.org>
3: * by Michael Pounov <misho@elwix.org>
4: *
5: * $Author: misho $
1.2.2.1 ! misho 6: * $Id: tftpd.c,v 1.2 2014/02/21 09:09:15 misho Exp $
1.2 misho 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: */
1.1 misho 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"
1.2.2.1 ! misho 79: "\t-d\t\tDebug program\n"
1.1 misho 80: "\t-v\t\tVerbose (more -v, more verbosity ...)\n"
81: "\t-h\t\tThis help screen!\n"
82: "\n", compiled, compiledby, compilehost);
83: }
84:
85: static void *
86: sigHandler(sched_task_t *task)
87: {
88: int stat;
89: const char *str;
90:
91: switch (TASK_VAL(task)) {
92: case SIGHUP:
93: cfgUnloadConfig(&cfg);
94: if (cfgLoadConfig(szCfgName, &cfg)) {
95: ELIBERR(cfg);
96: Kill++;
97: } else
98: EVERBOSE(1, "Reloading config ...");
99:
100: str = cfg_getAttribute(&cfg, "tftpd", "timeout");
101: if (str)
102: timeout.tv_sec = strtol(str, NULL, 10);
103: break;
104: case SIGINT:
105: case SIGTERM:
106: EVERBOSE(1, "Terminate service ...");
107: Kill++;
108: break;
109: case SIGCHLD:
110: while (waitpid(-1, &stat, WNOHANG) > 0);
111: break;
112: default:
113: EERROR(EINVAL, "Unknown signal #%lu?", TASK_VAL(task));
114: break;
115: }
116:
117: schedSignalSelf(task);
118: taskExit(task, NULL);
119: }
120:
121: int
122: main(int argc, char **argv)
123: {
124: char ch, m = 0, b = 0;
125: const char *str;
126: int fd, uid = 0, ret = 0;
127: struct passwd *pass;
128: pid_t pid;
129: sockaddr_t sa;
130: rpack_t *pkt = NULL;
131:
1.2.2.1 ! misho 132: while ((ch = getopt(argc, argv, "hvdbwc:")) != -1)
1.1 misho 133: switch (ch) {
134: case 'c':
135: strlcpy(szCfgName, optarg, sizeof szCfgName);
136: break;
137: case 'w':
138: m = 42; /* rw mode */
139: break;
140: case 'v':
141: e_incVerbose;
142: break;
1.2.2.1 ! misho 143: case 'd':
! 144: elwix_Debug |= ELWIX_DEBUG_TRACE;
! 145: break;
1.1 misho 146: case 'b':
147: b = 42;
148: break;
149: case 'h':
150: default:
151: Usage();
152: return 1;
153: }
154: argc -= optind;
155: argv += optind;
156:
157: openlog("TFTPd", LOG_PID | LOG_CONS, LOG_FTP);
158: if (cfgLoadConfig(szCfgName, &cfg)) {
159: ELIBERR(cfg);
160: return 2;
161: }
162:
163: str = cfg_getAttribute(&cfg, "tftpd", "user");
164: if (str) {
165: pass = getpwnam(str);
166: if (!pass) {
167: EERROR(EINVAL, "User %s not found!\n", str);
168: ret = 2;
169: goto end;
170: } else
171: uid = pass->pw_uid;
172: endpwent();
173: }
174:
175: if (!b) /* service mode */
176: switch ((pid = fork())) {
177: case -1:
178: ret = 3;
179: goto end;
180: case 0:
181: setsid();
182: chdir("/");
183:
184: fd = open(_PATH_DEVNULL, O_RDWR);
185: if (fd > 2) {
186: dup2(fd, STDIN_FILENO);
187: dup2(fd, STDOUT_FILENO);
188: dup2(fd, STDERR_FILENO);
189: close(fd);
190: }
191: EVERBOSE(1, "Welcome to the shadow-land!\n");
192: break;
193: default:
194: EVERBOSE(1, "Starting service with pid=%d ...\n", pid);
195: goto end;
196: }
197:
198: root = schedBegin();
199: if (!root) {
200: ELIBERR(sched);
201: ret = 3;
202: goto end;
203: }
204:
205: str = cfg_getAttribute(&cfg, "tftpd", "timeout");
206: if (str)
207: timeout.tv_sec = strtol(str, NULL, 10);
208:
209: str = cfg_getAttribute(&cfg, "tftpd", "port");
210: if (str)
211: fd = strtol(str, NULL, 10);
212: else
213: fd = 69;
214: str = cfg_getAttribute(&cfg, "tftpd", "bind");
215: e_gethostbyname(str ? str : "0.0.0.0", fd, &sa);
216: fd = socket(sa.sa.sa_family, SOCK_DGRAM, IPPROTO_UDP);
217: if (fd == -1) {
218: ESYSERR(0);
219: ret = 4;
220: goto end;
221: }
222: if (bind(fd, &sa.sa, sa.sa.sa_len) == -1) {
223: ESYSERR(0);
224: close(fd);
225: ret = 4;
226: goto end;
227: }
228:
229: str = cfg_getAttribute(&cfg, "tftpd", "chroot");
230: if (str && chroot(str) == -1) {
231: ESYSERR(0);
232: close(fd);
233: ret = 3;
234: goto end;
235: } else {
236: setuid(uid);
237: str = cfg_getAttribute(&cfg, "tftpd", "dir");
238: if (str)
239: chdir(str);
240: }
241:
242: if (!(pkt = rpack_create(NULL, 0))) {
243: ELIBERR(elwix);
244: close(fd);
245: ret = 5;
246: goto end;
247: }
248: if (rpack_attach(pkt, TFTP_PKT_MAX)) {
249: ELIBERR(elwix);
250: close(fd);
251: ret = 5;
252: goto end;
253: }
254:
255: memset(&cli, 0, sizeof cli);
256: schedSignal(root, sigHandler, NULL, SIGHUP, NULL, 0);
257: schedSignal(root, sigHandler, NULL, SIGTERM, NULL, 0);
258: schedSignal(root, sigHandler, NULL, SIGINT, NULL, 0);
259: schedSignal(root, sigHandler, NULL, SIGCHLD, NULL, 0);
260: schedRead(root, rxPkt, NULL, fd, pkt, sizeof(rpack_t));
261: schedRun(root, &Kill);
262:
263: close(fd);
264: end:
265: schedEnd(&root);
266: rpack_detach(pkt);
267: rpack_destroy(&pkt);
268: cfgUnloadConfig(&cfg);
269: closelog();
270: return ret;
271: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>