1 |
|
|
2 |
/* Copyright 2000 Beau Kuiper |
/* Copyright 2000 Beau Kuiper |
3 |
|
|
4 |
This program is free software; you can redistribute it and/or modify |
This program is free software; you can redistribute it and/or modify |
18 |
#include "ftpd.h" |
#include "ftpd.h" |
19 |
#include "reply.h" |
#include "reply.h" |
20 |
|
|
21 |
extern int nummalloc; /* number of areas malloced at once */ |
extern int nummalloc; /* number of areas malloced at once */ |
22 |
int signumber; |
int signumber; |
23 |
pid_t *deadlist; |
pid_t *deadlist; |
24 |
int deadcount; |
int deadcount; |
25 |
|
|
26 |
void logfullmessage(int error, unsigned int ip) |
void logfullmessage(int error, |
27 |
|
unsigned int ip) |
28 |
{ |
{ |
29 |
switch(error) |
switch (error) |
30 |
{ |
{ |
31 |
case HOSTFULL: |
case HOSTFULL: |
32 |
log_addentry(MYLOG_INFO, NULL, "main maxusers limit reached. Server full"); |
log_addentry(MYLOG_INFO, NULL, |
33 |
break; |
"main maxusers limit reached. Server full"); |
34 |
case GROUPFULL: |
break; |
35 |
log_addentry(MYLOG_INFO, NULL, "group maxusers limit reached. User denied"); |
case GROUPFULL: |
36 |
break; |
log_addentry(MYLOG_INFO, NULL, |
37 |
case VSERVERFULL: |
"group maxusers limit reached. User denied"); |
38 |
log_addentry(MYLOG_INFO, NULL, "virtual server maxusers limit reached. User denied"); |
break; |
39 |
break; |
case VSERVERFULL: |
40 |
case IPHOSTFULL: |
log_addentry(MYLOG_INFO, NULL, |
41 |
log_giveentry(MYLOG_INFO, NULL, safe_snprintf("main connections per ip reached for %s", getipstr(ip))); |
"virtual server maxusers limit reached. User denied"); |
42 |
break; |
break; |
43 |
case IPVSERVERFULL: |
case IPHOSTFULL: |
44 |
log_giveentry(MYLOG_INFO, NULL, safe_snprintf("virtual server maximum connections per ip reached for %s", getipstr(ip))); |
log_giveentry(MYLOG_INFO, NULL, |
45 |
break; |
safe_snprintf("main connections per ip reached for %s", |
46 |
default: |
getipstr(ip))); |
47 |
log_addentry(MYLOG_INFO, NULL, "Unknown host error."); |
break; |
48 |
|
case IPVSERVERFULL: |
49 |
|
log_giveentry(MYLOG_INFO, NULL, |
50 |
|
safe_snprintf |
51 |
|
("virtual server maximum connections per ip reached for %s", |
52 |
|
getipstr(ip))); |
53 |
|
break; |
54 |
|
default: |
55 |
|
log_addentry(MYLOG_INFO, NULL, "Unknown host error."); |
56 |
} |
} |
57 |
} |
} |
58 |
|
|
59 |
VSERVER *findvserver(unsigned int ip, int port) |
VSERVER *findvserver(unsigned int ip, |
60 |
|
int port) |
61 |
{ |
{ |
62 |
VSERVERCONN *vs; |
VSERVERCONN *vs; |
63 |
|
|
64 |
vs = config->inports; |
vs = config->inports; |
65 |
while (vs != NULL) |
while (vs != NULL) |
66 |
{ |
{ |
67 |
if (vs->port == port) |
if (vs->port == port) |
68 |
if ((vs->ip == 0) || (vs->ip == ip)) |
if ((vs->ip == 0) || (vs->ip == ip)) |
69 |
return(vs->vptr); |
return (vs->vptr); |
70 |
vs = vs->next; |
vs = vs->next; |
71 |
} |
} |
72 |
return(NULL); |
return (NULL); |
73 |
} |
} |
74 |
|
|
75 |
/* this function finds all ports binding to multiple ip and uses a single |
/* this function finds all ports binding to multiple ip and uses a single |
76 |
bind to use fewer fd's. It runs in N^2 time, but shouldn't be too slow |
bind to use fewer fd's. It runs in N^2 time, but shouldn't be too slow |
77 |
even for very large sites. */ |
even for very large sites. */ |
78 |
|
|
79 |
void smartbind(SELECTER *selset, VSERVERCONN *list, int dodie) |
void smartbind(SELECTER * selset, |
80 |
|
VSERVERCONN * list, |
81 |
|
int dodie) |
82 |
{ |
{ |
83 |
VSERVERCONN *pos, *spos; |
VSERVERCONN *pos, *spos; |
84 |
int dobind, fd; |
int dobind, fd; |
85 |
unsigned int bindip; |
unsigned int bindip; |
86 |
|
|
87 |
pos = list; |
pos = list; |
88 |
|
|
89 |
while(pos != NULL) |
while (pos != NULL) |
90 |
{ |
{ |
91 |
/* make sure port hasn't already been bound */ |
/* |
92 |
|
* make sure port hasn't already been bound |
93 |
|
*/ |
94 |
spos = list; |
spos = list; |
95 |
dobind = TRUE; /* assume the bind goes ahead */ |
dobind = TRUE; /* assume the bind goes ahead */ |
96 |
bindip = pos->ip; /* assume binding to a single port */ |
bindip = pos->ip; /* assume binding to a single port */ |
97 |
fd = -1; |
fd = -1; |
98 |
|
|
99 |
/* see if port number is in any ealier binds. If so, then |
/* |
100 |
no need to bind this address */ |
* see if port number is in any ealier binds. If so, then |
101 |
while((spos != pos) && (dobind)) |
* no need to bind this address |
102 |
|
*/ |
103 |
|
while ((spos != pos) && (dobind)) |
104 |
{ |
{ |
105 |
if (spos->port == pos->port) |
if (spos->port == pos->port) |
106 |
{ |
{ |
109 |
} |
} |
110 |
spos = spos->next; |
spos = spos->next; |
111 |
} |
} |
112 |
|
|
113 |
if (dobind) |
if (dobind) |
114 |
{ |
{ |
115 |
unsigned int zeroip; |
unsigned int zeroip; |
116 |
|
|
117 |
getnetworkint("0.0.0.0", &zeroip); |
getnetworkint("0.0.0.0", &zeroip); |
118 |
spos = pos->next; |
spos = pos->next; |
119 |
|
|
120 |
/* now search for binds to this address later in the |
/* |
121 |
chain. Set ip to 0.0.0.0 if this is the case */ |
* now search for binds to this address later in the |
122 |
while((spos != NULL) && (bindip != zeroip)) |
* chain. Set ip to 0.0.0.0 if this is the case |
123 |
|
*/ |
124 |
|
while ((spos != NULL) && (bindip != zeroip)) |
125 |
{ |
{ |
126 |
if (spos->port == pos->port) |
if (spos->port == pos->port) |
127 |
bindip = zeroip; |
bindip = zeroip; |
128 |
spos = spos->next; |
spos = spos->next; |
129 |
} |
} |
130 |
/* see if we need to bind to zero instead of |
/* |
131 |
bindip */ |
* see if we need to bind to zero instead of |
132 |
|
* bindip |
133 |
|
*/ |
134 |
|
|
135 |
if ((config->zerobind) && (bindip != zeroip)) |
if ((config->zerobind) && (bindip != zeroip)) |
136 |
{ |
{ |
137 |
bindip = zeroip; |
bindip = zeroip; |
138 |
} |
} |
139 |
/* now actually bind it */ |
/* |
140 |
|
* now actually bind it |
141 |
|
*/ |
142 |
|
|
143 |
pos->fd = inport_bind(pos->port, bindip, dodie); |
pos->fd = inport_bind(pos->port, bindip, dodie); |
144 |
if (pos->fd != -1) |
if (pos->fd != -1) |
152 |
} |
} |
153 |
else |
else |
154 |
pos->fd = fd; |
pos->fd = fd; |
155 |
|
|
156 |
pos = pos->next; |
pos = pos->next; |
157 |
} |
} |
158 |
} |
} |
159 |
|
|
160 |
/* This function does binding the dumb way. It runs in N time, but consumes |
/* This function does binding the dumb way. It runs in N time, but consumes |
161 |
more file descriptors. However, it also doesn't bind to unneeded ip/port |
more file descriptors. However, it also doesn't bind to unneeded ip/port |
162 |
combinations and is more robust. */ |
combinations and is more robust. */ |
163 |
|
|
164 |
void dumbbind(SELECTER *selset, VSERVERCONN *list, int dodie) |
void dumbbind(SELECTER * selset, |
165 |
|
VSERVERCONN * list, |
166 |
|
int dodie) |
167 |
{ |
{ |
168 |
VSERVERCONN *pos = list; |
VSERVERCONN *pos = list; |
169 |
|
|
170 |
while(pos != NULL) |
while (pos != NULL) |
171 |
{ |
{ |
172 |
pos->fd = inport_bind(pos->port, pos->ip, dodie); |
pos->fd = inport_bind(pos->port, pos->ip, dodie); |
173 |
if (pos->fd != -1) |
if (pos->fd != -1) |
177 |
} |
} |
178 |
pos = pos->next; |
pos = pos->next; |
179 |
} |
} |
180 |
} |
} |
181 |
|
|
182 |
void sighandler(int signum) |
void sighandler(int signum) |
183 |
{ |
{ |
186 |
|
|
187 |
if (signum == SIGCHLD) |
if (signum == SIGCHLD) |
188 |
{ |
{ |
189 |
int errno2, result; |
int errno2, result; |
190 |
pid_t deadpid; |
pid_t deadpid; |
191 |
|
|
192 |
debuglog("sighandler - main waiting for child!"); |
debuglog("sighandler - main waiting for child!"); |
193 |
|
|
194 |
errno2 = errno; |
errno2 = errno; |
195 |
while((deadpid = waitpid(0, &result, WNOHANG)) > 0) |
while ((deadpid = waitpid(0, &result, WNOHANG)) > 0) |
196 |
{ |
{ |
197 |
debuglog("pid %d died with result %d!", deadpid, result); |
debuglog("pid %d died with result %d!", deadpid, result); |
198 |
deadlist[deadcount] = deadpid; |
deadlist[deadcount] = deadpid; |
200 |
} |
} |
201 |
errno = errno2; |
errno = errno2; |
202 |
|
|
203 |
debuglog("sighandler - main child %d finished!", (int)deadpid); |
debuglog("sighandler - main child %d finished!", (int) deadpid); |
204 |
|
|
205 |
signal(SIGCHLD, sighandler); |
signal(SIGCHLD, sighandler); |
206 |
} |
} |
207 |
else |
else if (signum == SIGUSR1) |
|
if (signum == SIGUSR1) |
|
208 |
{ |
{ |
209 |
signal(SIGUSR1, sighandler); |
signal(SIGUSR1, sighandler); |
210 |
} |
} |
211 |
} |
} |
212 |
|
|
213 |
int mainprog(char *fconfig, int runforeground, int verbose) |
int mainprog(char *fconfig, |
214 |
|
int runforeground, |
215 |
|
int verbose) |
216 |
{ |
{ |
217 |
int signum = 0; |
int signum = 0; |
218 |
SELECTER *mainports; |
SELECTER *mainports; |
219 |
struct rlimit newlimit; |
struct rlimit newlimit; |
220 |
|
|
221 |
test_libc(verbose); |
test_libc(verbose); |
222 |
|
|
223 |
setsid(); |
setsid(); |
224 |
|
|
225 |
signal(SIGIO, SIG_IGN); |
signal(SIGIO, SIG_IGN); |
226 |
signal(SIGPIPE, SIG_IGN); |
signal(SIGPIPE, SIG_IGN); |
227 |
signal(SIGTERM, sighandler); |
signal(SIGTERM, sighandler); |
230 |
signal(SIGUSR1, sighandler); |
signal(SIGUSR1, sighandler); |
231 |
signal(SIGINT, sighandler); |
signal(SIGINT, sighandler); |
232 |
|
|
233 |
logerrors = TERMINAL; |
logerrors = TERMINAL; |
234 |
init_pwgrfiles(); |
init_pwgrfiles(); |
235 |
|
|
236 |
ftpd_init(fconfig, verbose); |
ftpd_init(fconfig, verbose); |
237 |
config->toobusycount = 0; |
config->toobusycount = 0; |
238 |
|
|
239 |
deadlist = mallocwrapper(sizeof(pid_t) * config->defaults->maxusers + 1); |
deadlist = mallocwrapper(sizeof(pid_t) * config->defaults->maxusers + 1); |
240 |
deadcount = 0; |
deadcount = 0; |
241 |
|
|
242 |
logerrors = MUDLOG; |
logerrors = MUDLOG; |
243 |
mainports = select_new(); |
mainports = select_new(); |
244 |
|
|
245 |
/* Set process limit very high so that the 'poor user' doesn't |
/* |
246 |
need to worry about setting it */ |
* Set process limit very high so that the 'poor user' doesn't |
247 |
|
* need to worry about setting it |
248 |
|
*/ |
249 |
|
|
250 |
#ifdef RLIMIT_NPROC |
#ifdef RLIMIT_NPROC |
251 |
getrlimit(RLIMIT_NPROC, &newlimit); |
getrlimit(RLIMIT_NPROC, &newlimit); |
254 |
setrlimit(RLIMIT_NPROC, &newlimit); |
setrlimit(RLIMIT_NPROC, &newlimit); |
255 |
#endif |
#endif |
256 |
|
|
257 |
/* Listen to all the input sockets, they are changed to the fd */ |
/* |
258 |
|
* Listen to all the input sockets, they are changed to the fd |
259 |
|
*/ |
260 |
|
|
261 |
if (config->smartbind) |
if (config->smartbind) |
262 |
smartbind(mainports, config->inports, TRUE); |
smartbind(mainports, config->inports, TRUE); |
263 |
else |
else |
264 |
dumbbind(mainports, config->inports, TRUE); |
dumbbind(mainports, config->inports, TRUE); |
265 |
|
|
266 |
if (((int)config->uidt_asuid != (int)getuid()) || |
if (((int) config->uidt_asuid != (int) getuid()) || |
267 |
((int)config->gidt_asgid != (int)getgid())) |
((int) config->gidt_asgid != (int) getgid())) |
268 |
{ |
{ |
269 |
if ((int)getuid() == 0) |
if ((int) getuid() == 0) |
270 |
{ |
{ |
271 |
if (verbose) |
if (verbose) |
272 |
printf("Switching to user '%s' (UID: %d, GID %d)\n", |
printf("Switching to user '%s' (UID: %d, GID %d)\n", |
273 |
config->username, |
config->username, |
274 |
(int)config->uidt_asuid, (int)config->gidt_asgid); |
(int) config->uidt_asuid, (int) config->gidt_asgid); |
275 |
|
|
276 |
/* Tell the parent the terminal can be given back! */ |
/* |
277 |
/* It must be done before we change uid because we |
* Tell the parent the terminal can be given back! |
278 |
lose permission to do so after the setuid! */ |
*/ |
279 |
|
/* |
280 |
|
* It must be done before we change uid because we |
281 |
|
* lose permission to do so after the setuid! |
282 |
|
*/ |
283 |
if (!runforeground) |
if (!runforeground) |
284 |
kill(getppid(), SIGHUP); |
kill(getppid(), SIGHUP); |
285 |
|
|
286 |
/* Changing user to the one the user wanted */ |
/* |
287 |
|
* Changing user to the one the user wanted |
288 |
|
*/ |
289 |
setgid(config->gidt_asgid); |
setgid(config->gidt_asgid); |
290 |
setuid(config->uidt_asuid); |
setuid(config->uidt_asuid); |
291 |
} |
} |
292 |
else |
else |
293 |
ERRORMSGFATAL("The server does not have permission to switch to the specified user."); |
ERRORMSGFATAL |
294 |
|
("The server does not have permission to switch to the specified user."); |
295 |
} |
} |
296 |
else |
else |
297 |
{ |
{ |
298 |
if (!runforeground) |
if (!runforeground) |
299 |
/* Tell the parent the terminal can be given back! */ |
/* |
300 |
|
* Tell the parent the terminal can be given back! |
301 |
|
*/ |
302 |
kill(getppid(), SIGHUP); |
kill(getppid(), SIGHUP); |
303 |
} |
} |
304 |
|
|
305 |
log_addentry(MYLOG_INFO, NULL, PROGNAME" ("VERSTR") server started. Waiting on connections."); |
log_addentry(MYLOG_INFO, NULL, |
306 |
|
PACKAGE_NAME " (" PACKAGE_VERSION |
307 |
|
") server started. Waiting on connections."); |
308 |
|
|
309 |
while ((signum != SIGTERM) && (signum != SIGINT)) |
while ((signum != SIGTERM) && (signum != SIGINT)) |
310 |
{ |
{ |
311 |
select_do(mainports, &signum, -1); |
select_do(mainports, &signum, -1); |
312 |
|
|
313 |
blockallsignals(); |
blockallsignals(); |
314 |
if (deadcount > 0) |
if (deadcount > 0) |
315 |
{ |
{ |
318 |
} |
} |
319 |
if ((signum == SIGHUP) && (config->username == NULL)) |
if ((signum == SIGHUP) && (config->username == NULL)) |
320 |
{ |
{ |
321 |
/* rebuild configuration */ |
/* |
322 |
|
* rebuild configuration |
323 |
|
*/ |
324 |
CONFIGDATA *newdata; |
CONFIGDATA *newdata; |
325 |
int result; |
int result; |
326 |
|
|
327 |
log_addentry(MYLOG_INFO, NULL, "Received SIGHUP, reloading configuration"); |
log_addentry(MYLOG_INFO, NULL, |
328 |
|
"Received SIGHUP, reloading configuration"); |
329 |
newdata = ftpd_loadconfig(fconfig, FALSE, config->defaults->umask); |
|
330 |
|
newdata = |
331 |
|
ftpd_loadconfig(fconfig, FALSE, config->defaults->umask); |
332 |
|
|
333 |
if (newdata) |
if (newdata) |
334 |
result = ftpd_checkconfig(newdata); |
result = ftpd_checkconfig(newdata); |
335 |
|
|
336 |
if ((!newdata) || (!result)) |
if ((!newdata) || (!result)) |
337 |
{ |
{ |
338 |
log_addentry(MYLOG_INFO, NULL, "Errors reloading config file, resuming old config"); |
log_addentry(MYLOG_INFO, NULL, |
339 |
|
"Errors reloading config file, resuming old config"); |
340 |
if (newdata) |
if (newdata) |
341 |
ftpd_killconfig(newdata); |
ftpd_killconfig(newdata); |
342 |
} |
} |
343 |
else |
else |
344 |
{ |
{ |
345 |
int t = config->toobusycount; |
int t = config->toobusycount; |
346 |
|
|
347 |
ftpd_killconfig(config); |
ftpd_killconfig(config); |
348 |
config = newdata; |
config = newdata; |
349 |
config->toobusycount = t; |
config->toobusycount = t; |
350 |
log_shutdown(); |
log_shutdown(); |
351 |
log_setcontext(config->logout, config->defaults->loglevel); |
log_setcontext(config->logout, config->defaults->loglevel); |
352 |
log_addentry(MYLOG_INFO, NULL, "New configuration loaded, using new configuration"); |
log_addentry(MYLOG_INFO, NULL, |
353 |
|
"New configuration loaded, using new configuration"); |
354 |
select_shutdown(mainports); |
select_shutdown(mainports); |
355 |
mainports = select_new(); |
mainports = select_new(); |
356 |
|
|
357 |
if (config->smartbind) |
if (config->smartbind) |
358 |
smartbind(mainports, config->inports, FALSE); |
smartbind(mainports, config->inports, FALSE); |
359 |
else |
else |
363 |
signal(SIGHUP, sighandler); |
signal(SIGHUP, sighandler); |
364 |
} |
} |
365 |
else if ((signum == SIGHUP) && (config->username != NULL)) |
else if ((signum == SIGHUP) && (config->username != NULL)) |
366 |
log_addentry(MYLOG_INFO, NULL, "You cannot reload the configuration while using the runasuser directive"); |
log_addentry(MYLOG_INFO, NULL, |
367 |
|
"You cannot reload the configuration while using the runasuser directive"); |
368 |
else if (signum == SIGUSR1) |
else if (signum == SIGUSR1) |
369 |
{ |
{ |
370 |
int newcontext = log_initcontext(config->defaults->logfile); |
int newcontext = log_initcontext(config->defaults->logfile); |
371 |
|
|
372 |
if (newcontext == -1) |
if (newcontext == -1) |
373 |
log_giveentry(MYLOG_INFO, NULL, safe_snprintf("Could not open logfile '%s', couldn't reopen.", config->defaults->logfile)); |
log_giveentry(MYLOG_INFO, NULL, |
374 |
|
safe_snprintf |
375 |
|
("Could not open logfile '%s', couldn't reopen.", |
376 |
|
config->defaults->logfile)); |
377 |
else |
else |
378 |
{ |
{ |
379 |
config->logout = newcontext; |
config->logout = newcontext; |
380 |
log_shutdown(); |
log_shutdown(); |
381 |
pnums_signalchildren(SIGUSR1); |
pnums_signalchildren(SIGUSR1); |
382 |
log_setcontext(config->logout, config->defaults->loglevel); |
log_setcontext(config->logout, config->defaults->loglevel); |
383 |
log_addentry(MYLOG_INFO, NULL, "Log file reopened after SIGUSR1."); |
log_addentry(MYLOG_INFO, NULL, |
384 |
|
"Log file reopened after SIGUSR1."); |
385 |
} |
} |
386 |
} |
} |
387 |
unblockallsignals(); |
unblockallsignals(); |
393 |
shinfo_shutdown(); |
shinfo_shutdown(); |
394 |
|
|
395 |
select_shutdown(mainports); |
select_shutdown(mainports); |
396 |
|
|
397 |
log_addentry(MYLOG_INFO, NULL, PROGNAME" ("VERSTR") server shutting down."); |
log_addentry(MYLOG_INFO, NULL, |
398 |
|
PACKAGE_NAME " (" PACKAGE_VERSION ") server shutting down."); |
399 |
|
|
400 |
freewrapper(deadlist); |
freewrapper(deadlist); |
401 |
ftpd_killconfig(config); |
ftpd_killconfig(config); |
402 |
log_shutdown(); |
log_shutdown(); |
403 |
kill_uidgidfiles(); |
kill_uidgidfiles(); |
404 |
exit(0); |
exit(0); |
405 |
} |
} |
406 |
|
|
407 |
void mainprog_inetd(char *fconfig, unsigned int ip) |
void mainprog_inetd(char *fconfig, |
408 |
|
unsigned int ip) |
409 |
{ |
{ |
410 |
char *scratchfile; |
char *scratchfile; |
411 |
int tnum, port, result; |
int tnum, port, result; |
412 |
unsigned int ipl; |
unsigned int ipl; |
413 |
VSERVER *vserver; |
VSERVER *vserver; |
414 |
int error; |
int error; |
415 |
|
|
416 |
test_libc(0); |
test_libc(0); |
417 |
|
|
418 |
inetd = TRUE; |
inetd = TRUE; |
419 |
signal(SIGUSR1, sighandler); |
signal(SIGUSR1, sighandler); |
420 |
|
|
426 |
if (config) |
if (config) |
427 |
result = ftpd_checkconfig(config); |
result = ftpd_checkconfig(config); |
428 |
if ((!config) || (!result)) |
if ((!config) || (!result)) |
429 |
ERRORMSGFATAL("Errors loading config file, cannot continue!"); |
ERRORMSGFATAL("Errors loading config file, cannot continue!"); |
430 |
|
|
431 |
log_setcontext(config->logout, config->defaults->loglevel); |
log_setcontext(config->logout, config->defaults->loglevel); |
432 |
|
|
433 |
result = getsectionid(config->configfile, "main"); |
result = getsectionid(config->configfile, "main"); |
434 |
loadstrfromconfig(config->configfile, result, "scratchfile", |
loadstrfromconfig(config->configfile, result, "scratchfile", |
435 |
&scratchfile, SCRATCHFILE); |
&scratchfile, SCRATCHFILE); |
436 |
if (scratchfile[0] != '/') |
if (scratchfile[0] != '/') |
437 |
ERRORMSGFATAL("Scratchfile is not a valid absolute filename"); |
ERRORMSGFATAL("Scratchfile is not a valid absolute filename"); |
438 |
|
|
439 |
ftpd_setnogroups(); |
ftpd_setnogroups(); |
440 |
signal(SIGPIPE, SIG_IGN); |
signal(SIGPIPE, SIG_IGN); |
441 |
signal(SIGTERM, sighandler); |
signal(SIGTERM, sighandler); |
442 |
signal(SIGHUP, sighandler); |
signal(SIGHUP, sighandler); |
443 |
|
|
444 |
inetd_init(scratchfile); |
inetd_init(scratchfile); |
445 |
|
|
446 |
if (((int)config->uidt_asuid != (int)getuid()) || |
if (((int) config->uidt_asuid != (int) getuid()) || |
447 |
((int)config->gidt_asgid != (int)getgid())) |
((int) config->gidt_asgid != (int) getgid())) |
448 |
{ |
{ |
449 |
if (getuid() == 0) |
if (getuid() == 0) |
450 |
{ |
{ |
452 |
setuid(config->uidt_asuid); |
setuid(config->uidt_asuid); |
453 |
} |
} |
454 |
} |
} |
455 |
|
|
456 |
/* get the virtual server the user connected to! */ |
/* |
457 |
|
* get the virtual server the user connected to! |
458 |
|
*/ |
459 |
|
|
460 |
getsockinfo(0, &ipl, &port); |
getsockinfo(0, &ipl, &port); |
461 |
vserver = findvserver(ipl, port); |
vserver = findvserver(ipl, port); |
462 |
|
|
463 |
if (vserver == NULL) |
if (vserver == NULL) |
464 |
exit(0); |
exit(0); |
465 |
|
|
466 |
tnum = shinfo_adduser_inetd(ip, config->defaults->maxusers, |
tnum = shinfo_adduser_inetd(ip, config->defaults->maxusers, |
467 |
config->defaults->maxperip, &error); |
config->defaults->maxperip, &error); |
468 |
|
|
469 |
if (tnum != -1) |
if (tnum != -1) |
470 |
result = shinfo_setvserver(tnum, vserver->sectionname, ip, |
result = shinfo_setvserver(tnum, vserver->sectionname, ip, |
471 |
vserver->maxusers, |
vserver->maxusers, |
472 |
vserver->maxperip, |
vserver->maxperip, &error); |
473 |
&error); |
|
|
|
|
474 |
if ((result) && (tnum != -1)) |
if ((result) && (tnum != -1)) |
475 |
ftpserverside_main(0, ip, tnum, port, vserver); |
ftpserverside_main(0, ip, tnum, port, vserver); |
476 |
else |
else |
479 |
write(0, vserver->toobusy, strlen(vserver->toobusy)); |
write(0, vserver->toobusy, strlen(vserver->toobusy)); |
480 |
else |
else |
481 |
write(0, REPLY_SERVERBUSY, strlen(REPLY_SERVERBUSY)); |
write(0, REPLY_SERVERBUSY, strlen(REPLY_SERVERBUSY)); |
482 |
|
|
483 |
logfullmessage(error, ip); |
logfullmessage(error, ip); |
484 |
} |
} |
485 |
|
|
486 |
ftpd_killconfig(config); |
ftpd_killconfig(config); |
487 |
kill_uidgidfiles(); |
kill_uidgidfiles(); |
488 |
|
|
496 |
|
|
497 |
void usage(char *name) |
void usage(char *name) |
498 |
{ |
{ |
499 |
printf(PROGNAME": ftp daemon.\n\n"); |
printf(PACKAGE_NAME ": ftp daemon.\n\n"); |
500 |
printf("Usage: %s [-V][-d][-h][-c configfile]\n\n", name); |
printf("Usage: %s [-V][-d][-h][-c configfile]\n\n", name); |
501 |
printf(" -V Show version information.\n"); |
printf(" -V Show version information.\n"); |
502 |
printf(" -v Verbose startup.\n"); |
printf(" -v Verbose startup.\n"); |
503 |
printf(" -d Debug mode. Does not fork into background.\n"); |
printf(" -d Debug mode. Does not fork into background.\n"); |
504 |
printf(" -h Show usage information.\n"); |
printf(" -h Show usage information.\n"); |
505 |
printf(" -c configfile Specify an alternative config file.\n\n"); |
printf(" -c configfile Specify an alternative config file.\n\n"); |
506 |
exit(1); |
exit(1); |
507 |
} |
} |
508 |
|
|
509 |
int main(int argc, char **argv) |
int main(int argc, |
510 |
|
char **argv) |
511 |
{ |
{ |
512 |
unsigned int ip; |
unsigned int ip; |
513 |
pid_t forkresult; |
pid_t forkresult; |
516 |
int runforeground = FALSE; |
int runforeground = FALSE; |
517 |
char *fconfig = NULL; |
char *fconfig = NULL; |
518 |
extern char *optarg; |
extern char *optarg; |
519 |
|
|
520 |
while((ch = getopt(argc, argv, "Vvc:hd")) != EOF) |
while ((ch = getopt(argc, argv, "Vvc:hd")) != EOF) |
521 |
{ |
{ |
522 |
switch(ch) |
switch (ch) |
523 |
{ |
{ |
524 |
case 'V': |
case 'V': |
525 |
showversion(PROGNAME); |
showversion(PACKAGE_NAME); |
526 |
case 'v': |
case 'v': |
527 |
verbose = TRUE; |
verbose = TRUE; |
528 |
break; |
break; |
536 |
default: |
default: |
537 |
usage(argv[0]); |
usage(argv[0]); |
538 |
} |
} |
539 |
|
|
540 |
} |
} |
541 |
|
|
542 |
if (fconfig == NULL) |
if (fconfig == NULL) |
543 |
fconfig = CONFIGFILE; |
fconfig = CONFIGFILE; |
544 |
|
|
545 |
if ((ip = getremoteip(fileno(stdin))) != 1) |
if ((ip = getremoteip(fileno(stdin))) != 1) |
546 |
mainprog_inetd(fconfig, ip); |
mainprog_inetd(fconfig, ip); |
547 |
|
|
548 |
inetd = FALSE; |
inetd = FALSE; |
549 |
signal(SIGCHLD, diehandler); |
signal(SIGCHLD, diehandler); |
550 |
signal(SIGHUP, diehandler); |
signal(SIGHUP, diehandler); |
551 |
|
|
552 |
if (!runforeground) |
if (!runforeground) |
553 |
{ |
{ |
554 |
forkresult = fork(); |
forkresult = fork(); |
555 |
|
|
556 |
if ((int)forkresult == -1) |
if ((int) forkresult == -1) |
557 |
ERRORMSGFATAL("Could not fork into background"); |
ERRORMSGFATAL("Could not fork into background"); |
558 |
|
|
559 |
if ((int)forkresult == 0) |
if ((int) forkresult == 0) |
560 |
mainprog(fconfig, FALSE, verbose); |
mainprog(fconfig, FALSE, verbose); |
561 |
|
|
562 |
/* wait forever for the child to die or give us a Hangup signal */ |
/* |
563 |
|
* wait forever for the child to die or give us a Hangup signal |
564 |
while(TRUE) |
*/ |
565 |
|
|
566 |
|
while (TRUE) |
567 |
pause(); |
pause(); |
568 |
} |
} |
569 |
else |
else |
570 |
mainprog(fconfig, TRUE, verbose); |
mainprog(fconfig, TRUE, verbose); |
571 |
|
|
572 |
return(0); |
return (0); |
573 |
} |
} |