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