main.c
上传用户:pycemail
上传日期:2007-01-04
资源大小:329k
文件大小:53k
源码类别:

Ftp客户端

开发平台:

Unix_Linux

  1. /*
  2.  * ProFTPD - FTP server daemon
  3.  * Copyright (c) 1997, 1998 Public Flood Software
  4.  * Copyright (C) 1999, MacGyver aka Habeeb J. Dihu <macgyver@tos.net>
  5.  *  
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 2 of the License, or
  9.  * (at your option) any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, write to the Free Software
  18.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
  19.  */
  20. /*
  21.  * House initialization and main program loop
  22.  * $Id: main.c,v 1.18 1999/10/01 07:57:32 macgyver Exp $
  23.  */
  24. /*
  25.  * History Log:
  26.  *
  27.  * 9/21/97 current: 0.99.0pl6, next: 0.99.0pl7
  28.  *   Removed the -o (--core) option, because some kernels won't
  29.  *   produce a core dump after the euid/egid have changed.  If
  30.  *   anyone knows a way around this, please let me know.
  31.  * 4/28/97 current: 0.99.0pl1, next: 0.99.0pl2
  32.  *   Added checking for <Limit LOGIN> in fork_server(), in order
  33.  *   to disconnect any connections which can never be authorized.
  34.  * 4/24/97 current: 0.99.0pl1, next: 0.99.0pl2
  35.  *   Removed include/proftpd_conf.h; unnecessary header file
  36.  */
  37. #include "conf.h"
  38. #include <signal.h>
  39. #include <sys/resource.h>
  40. #ifdef HAVE_GETOPT_H
  41. # include <getopt.h>
  42. #endif
  43. #ifdef HAVE_LIBUTIL_H
  44. # include <libutil.h>
  45. #endif /* HAVE_LIBUTIL_H */
  46. #if PF_ARGV_TYPE == PF_ARGV_PSTAT
  47. # ifdef HAVE_SYS_PSTAT_H
  48. #  include <sys/pstat.h>
  49. # else
  50. #  undef PF_ARGV_TYPE
  51. #  define PF_ARGV_TYPE PF_ARGV_WRITEABLE
  52. # endif /* HAVE_SYS_PSTAT_H */
  53. #endif /* PF_ARGV_PSTAT */
  54. #if PF_ARGV_TYPE == PF_ARGV_PSSTRINGS
  55. # ifndef HAVE_SYS_EXEC_H
  56. #  undef PF_ARGV_TYPE
  57. #  define PF_ARGV_TYPE PF_ARGV_WRITEABLE
  58. # else
  59. #  include <machine/vmparam.h>
  60. #  include <sys/exec.h>
  61. # endif /* HAVE_SYS_EXEC_H */
  62. #endif /* PF_ARGV_PSSTRINGS */
  63. #ifdef HAVE_REGEX_H
  64. #include <regex.h>
  65. #endif
  66. #ifdef HAVE_REGEXP_H
  67. # include <regexp.h>
  68. #endif /* HAVE_REGEXP_H */
  69. #include "privs.h"
  70. /* From mod_core.c
  71.  */
  72. extern int core_display_file(const char *numeric, const char *fn);
  73. struct rehash {
  74.   struct rehash *next;
  75.   void *data;
  76.   void (*rehash)(void*);
  77. };
  78. typedef struct _pidrec {
  79.   struct _pidrec *next,*prev;
  80.   pid_t pid;
  81.   int dead;
  82. } pidrec_t;
  83. typedef struct _binding {
  84.   struct _binding *next;
  85.   server_rec *server; /* server to handle request */
  86.   p_in_addr_t ipaddr; /* ip address "bound" to */
  87.   int        port;
  88.   conn_t     *listen; /* listen connection (if separate) */
  89.   char       isdefault; /* if default connection */
  90.   char       islocalhost; /* if handles localhost */
  91. } binding_t;
  92. void addl_bindings(server_rec*);
  93. extern xaset_t *servers;
  94. session_t session;
  95. int master = TRUE; /* Master daemon in standalone mode */
  96. int standalone = 0; /* If in standalone mode */
  97. pid_t mpid = 0; /* Master pid */
  98. int rehash = 0; /* Performing rehash? */
  99. struct rehash *rehash_list = NULL; /* Pre-rehash callbacks */
  100. binding_t *bind_list = NULL;
  101. pool *bind_pool = NULL;
  102. time_t shut = (time_t)0,deny = (time_t)0, disc = (time_t)0;
  103. char shutmsg[81] = "";
  104. xaset_t *children = NULL;
  105. static int child_count = 0,child_flag = 0;
  106. response_t *resp_list = NULL,*resp_err_list = NULL;
  107. static pool *resp_pool = NULL;
  108. static int (*main_check_auth)(cmd_rec*) = NULL;
  109. static char sbuf[1024];
  110. static char _ml_numeric[4];
  111. static char **Argv = NULL;
  112. static char *LastArgv = NULL;
  113. static int shutdownp = 0;
  114. static int abort_core = 0;
  115. static RETSIGTYPE sig_disconnect(int);
  116. static RETSIGTYPE sig_debug(int);
  117. char *config_filename = CONFIG_FILE_PATH;
  118. #if 0
  119. void test_fs()
  120. {
  121.   glob_t pglob;
  122.   char buf[1024];
  123.   char **cp;
  124.   int fd;
  125.   fsdir_t *f;
  126.   size_t l;
  127.   bzero(&pglob,sizeof(pglob));
  128.   chdir("/");
  129.   fs_setcwd("/");
  130.   if(fs_chdir("~flood/test",TRUE) == -1)
  131.     perror("fs_chdir [tmp]");
  132.   fs_chdir("test.tar/foo",1);
  133.   printf("cwd: %sn",fs_getcwd());
  134.   printf("vwd: %sn",fs_getvwd());
  135.   f = fs_open("TESTFILE",O_RDONLY,&fd);
  136.   if(!f) {
  137.     perror("fs_open");
  138.     exit(1);
  139.   }
  140.   fs_lseek(f,fd,-1024,SEEK_END);
  141.   while((l = fs_read(f,fd,buf,sizeof(buf)-1)) > 0) {
  142.     buf[l] = '';
  143.     printf("%s",buf);
  144.   }
  145.   fs_close(f,fd);
  146.   exit(0);
  147.   if(fs_glob("*",GLOB_PERIOD,0,&pglob) == -1)
  148.     perror("fs_glob");
  149.   else {
  150.     cp = pglob.gl_pathv;
  151.     while(pglob.gl_pathc--) {
  152.       printf("matched: %sn",*cp);
  153.       cp++;
  154.     }
  155.   }
  156.   exit(0);
  157. }
  158. #endif
  159. int add_binding(server_rec *server, p_in_addr_t *ipaddr, conn_t *listen,
  160.                 char isdefault, char islocalhost)
  161. {
  162.   binding_t *b;
  163.   for(b = bind_list; b; b=b->next)
  164.     if(b->ipaddr.s_addr == ipaddr->s_addr &&
  165.        b->port == server->ServerPort) {
  166.       /* binding already exists for this IP */
  167.       log_pri(LOG_NOTICE,"cannot bind %s:%d to server '%s', already bound to '%s'.",
  168.               inet_ntoa(*ipaddr),server->ServerPort,
  169.               server->ServerName,b->server->ServerName);
  170.       return -1;
  171.     }
  172.   if(!bind_pool)
  173.     bind_pool = make_sub_pool(permanent_pool);
  174.   b = palloc(bind_pool,sizeof(binding_t));
  175.   b->server = server;
  176.   b->port = server->ServerPort;
  177.   b->ipaddr = *ipaddr;
  178.   b->listen = listen;
  179.   b->isdefault = isdefault;
  180.   b->islocalhost = islocalhost;
  181.   b->next = bind_list;
  182.   bind_list = b;
  183.   return 0;
  184. }
  185. server_rec *find_binding(p_in_addr_t *ipaddr, int port)
  186. {
  187.   binding_t *b,*local_b = NULL,*default_b = NULL;
  188.   for(b = bind_list; b; b=b->next) {
  189.     if(b->ipaddr.s_addr == ipaddr->s_addr && (!b->port || b->port == port))
  190.       return b->server;
  191.     if(b->islocalhost)
  192.       local_b = b;
  193.     if(b->isdefault)
  194.       default_b = b;
  195.   }
  196.   /* Not found in binding list, so see if it's the loopback address */
  197.   if(local_b) {
  198.     p_in_addr_t loopback,loopmask,tmp;
  199. #ifdef HAVE_INET_ATON
  200.     inet_aton(LOOPBACK_NET,&loopback);
  201.     inet_aton(LOOPBACK_MASK,&loopmask);
  202. #else
  203.     loopback.s_addr = inet_addr(LOOPBACK_NET);
  204.     loopmask.s_addr = inet_addr(LOOPBACK_MASK);
  205. #endif
  206.     loopback.s_addr = ntohl(loopback.s_addr);
  207.     loopmask.s_addr = ntohl(loopmask.s_addr);
  208.     tmp.s_addr = ntohl(ipaddr->s_addr);
  209.     if((tmp.s_addr & loopmask.s_addr) == loopback.s_addr &&
  210.        (!local_b->port || port == local_b->port))
  211.       return local_b->server;
  212.   }
  213.   /* otherwise, use the default server, if set */
  214.   if(default_b)
  215.     return default_b->server;
  216.   return NULL;
  217. }
  218. conn_t *accept_binding(fd_set *rfd, int *lfd)
  219. {
  220.   binding_t *b;
  221.   int fd;
  222.   for(b = bind_list; b; b=b->next) {
  223.     if(b->listen && FD_ISSET(b->listen->listen_fd,rfd) &&
  224.        b->listen->mode == CM_LISTEN) {
  225.       if((fd = inet_accept_nowait(b->listen->pool,b->listen)) == -1) {
  226. /* Handle errors gracefully.  If we're here, then b->listen contains
  227.  * either error information, or we just got caught in a blocking
  228.  * condition. - MacGyver
  229.  */
  230. if(b->listen->mode == CM_ERROR) {
  231.   log_pri(LOG_ERR, "Error: unable to accept an incoming connection (%s)",
  232.   strerror(b->listen->xerrno));
  233.   b->listen->xerrno = 0;
  234.   b->listen->mode = CM_LISTEN;
  235.   return NULL;
  236. }
  237.       }
  238.       
  239.       *lfd = fd;
  240.       return b->listen;
  241.     }
  242.   }
  243.   return NULL;
  244. }
  245. int listen_binding(fd_set *rfd)
  246. {
  247.   int max_fd = 0;
  248.   binding_t *b;
  249.   FD_ZERO(rfd);
  250.   for(b = bind_list; b; b=b->next) {
  251.     if(b->listen) {
  252.       if(b->listen->mode == CM_NONE)
  253.         inet_listen(b->listen->pool,b->listen,tcpBackLog);
  254.       if(b->listen->mode == CM_ACCEPT)
  255.         inet_resetlisten(b->listen->pool,b->listen);
  256.       if(b->listen->mode == CM_LISTEN) {
  257.         FD_SET(b->listen->listen_fd,rfd);
  258. if (b->listen->listen_fd > max_fd)
  259. max_fd = b->listen->listen_fd;
  260.       }
  261.     }
  262.   }
  263.   return max_fd;
  264. }
  265. static void init_set_proc_title(int argc, char *argv[], char *envp[])
  266. {
  267. #ifdef HAVE___PROGNAME
  268.   extern char *__progname, *__progname_full;
  269. #endif /* HAVE___PROGNAME */
  270.   int i;
  271.   
  272.   Argv = argv;
  273.   
  274.   for(i = 0; i < argc; i++) {
  275.     if(!i || (LastArgv + 1 == argv[i]))
  276.       LastArgv = argv[i] + strlen(argv[i]);
  277.   }
  278.   
  279.   for(i = 0; envp[i] != NULL; i++) {
  280.     if((LastArgv + 1) == envp[i])
  281.       LastArgv = envp[i] + strlen(envp[i]);
  282.   }
  283.   
  284. #ifdef HAVE___PROGNAME
  285.   /* Set the __progname and __progname_full variables so glibc and company don't
  286.    * go nuts. - MacGyver
  287.    */
  288.   __progname = strdup("proftpd");
  289.   __progname_full = strdup(argv[0]);
  290. #endif /* HAVE___PROGNAME */
  291.   
  292. #if 0
  293.   /* Save argument/environment globals for use by set_proc_title */
  294.   Argv = argv;
  295.   while(*envp)
  296.     envp++;
  297.   LastArgv = envp[-1] + strlen(envp[-1]);
  298. #endif
  299. }    
  300. void set_proc_title(char *fmt,...)
  301. {
  302.   va_list msg;
  303.   static char statbuf[BUFSIZ];
  304.   
  305. #ifndef HAVE_SETPROCTITLE
  306. #if PF_ARGV_TYPE == PF_ARGV_PSTAT
  307.    union pstun pst;
  308. #endif /* PF_ARGV_PSTAT */
  309.   char *p;
  310.   int i,maxlen = (LastArgv - Argv[0]) - 2;
  311. #endif /* HAVE_SETPROCTITLE */
  312.   va_start(msg,fmt);
  313.   memset(statbuf, 0, sizeof(statbuf));
  314.   vsnprintf(statbuf, sizeof(statbuf), fmt, msg);
  315. #ifdef HAVE_SETPROCTITLE
  316.   setproctitle(statbuf);
  317. #endif /* HAVE_SETPROCTITLE */
  318.   va_end(msg);
  319.   
  320. #ifdef HAVE_SETPROCTITLE
  321.   return;
  322. #else
  323.   i = strlen(statbuf);
  324. #if PF_ARGV_TYPE == PF_ARGV_NEW
  325.   /* We can just replace argv[] arguments.  Nice and easy.
  326.    */
  327.   Argv[0] = statbuf;
  328.   Argv[1] = NULL;
  329. #endif /* PF_ARGV_NEW */
  330. #if PF_ARGV_TYPE == PF_ARGV_WRITEABLE
  331.   /* We can overwrite individual argv[] arguments.  Semi-nice.
  332.    */
  333.   snprintf(Argv[0], maxlen, "%s", statbuf);
  334.   p = &Argv[0][i];
  335.   
  336.   while(p < LastArgv)
  337.     *p++ = '';
  338.   Argv[1] = NULL;
  339. #endif /* PF_ARGV_WRITEABLE */
  340. #if PF_ARGV_TYPE == PF_ARGV_PSTAT
  341.   pst.pst_command = statbuf;
  342.   pstat(PSTAT_SETCMD, pst, i, 0, 0);
  343. #endif /* PF_ARGV_PSTAT */
  344. #if PF_ARGV_TYPE == PF_ARGV_PSSTRINGS
  345.   PS_STRINGS->ps_nargvstr = 1;
  346.   PS_STRINGS->ps_argvstr = statbuf;
  347. #endif /* PF_ARGV_PSSTRINGS */
  348. #endif /* HAVE_SETPROCTITLE */
  349. }
  350.   
  351. void main_set_idle()
  352. {
  353.   time_t now;
  354.   time(&now);
  355.   log_add_run(mpid, &now,session.user,
  356.       (session.class && session.class->name) ?
  357.       session.class->name : "",
  358.               main_server->ipaddr, (unsigned short) main_server->ServerPort,
  359.               0, 0, "proftpd: %s - %s: IDLE",
  360.       session.user,session.proc_prefix);
  361.   set_proc_title("proftpd: %s - %s: IDLE", session.user, session.proc_prefix);
  362. }
  363. static void send_response_list(response_t **head)
  364. {
  365.   int ml = 0;
  366.   char *last_numeric = NULL;
  367.   response_t *t;
  368.   for(t = *head; t; t=t->next) {
  369.     if(ml) {
  370.       /* look for end of multiline */
  371.       if(!t->next || (t->num && strcmp(t->num,last_numeric) != 0)) {
  372.         io_printf(session.c->outf,"%s %srn",last_numeric,t->msg);
  373.         ml = 0;
  374.       } else {
  375. if(MultilineRFC2228)
  376.   io_printf(session.c->outf,"%s-%srn",last_numeric,t->msg);
  377. else
  378.   io_printf(session.c->outf," %srn",t->msg);
  379.       }
  380.     } else {
  381.       /* look for start of multiline */
  382.       if(t->next && (!t->next->num || strcmp(t->num,t->next->num) == 0)) {
  383.         io_printf(session.c->outf,"%s-%srn",t->num,t->msg);
  384.         ml = 1;
  385.         last_numeric = t->num;
  386.       } else
  387.         io_printf(session.c->outf,"%s %srn",t->num,t->msg);
  388.     }
  389.   }
  390.   *head = NULL;
  391. }
  392. void add_response_err(const char *numeric, const char *fmt, ...)
  393. {
  394.   va_list msg;
  395.   response_t *t,**head;
  396.   va_start(msg,fmt);
  397.   vsnprintf(sbuf, sizeof(sbuf), fmt, msg);
  398.   va_end(msg);
  399.   
  400.   sbuf[sizeof(sbuf) - 1] = '';
  401.   
  402.   t = (response_t*) pcalloc(resp_pool, sizeof(response_t));
  403.   t->num = (numeric ? pstrdup(resp_pool, numeric) : NULL);
  404.   t->msg = pstrdup(resp_pool, sbuf);
  405.   
  406.   for(head = &resp_err_list; *head && (!numeric || !(*head)->num ||
  407.       strcmp((*head)->num,numeric) <= 0); head = &(*head)->next) ;
  408.   t->next = *head;
  409.   *head = t;
  410. }
  411. void add_response(const char *numeric, const char *fmt, ...)
  412. {
  413.   va_list msg;
  414.   response_t *t,**head;
  415.   va_start(msg,fmt);
  416.   vsnprintf(sbuf, sizeof(sbuf), fmt, msg);
  417.   va_end(msg);
  418.   sbuf[sizeof(sbuf) - 1] = '';
  419.   
  420.   t = (response_t*) pcalloc(resp_pool, sizeof(response_t));
  421.   t->num = (numeric ? pstrdup(resp_pool, numeric) : NULL);
  422.   t->msg = pstrdup(resp_pool, sbuf);
  423.   
  424.   for(head = &resp_list; *head && (!numeric || !(*head)->num ||
  425.       strcmp((*head)->num,numeric) <= 0); head = &(*head)->next) ;
  426.   t->next = *head;
  427.   *head = t;
  428. }
  429. void send_response_raw(const char *fmt, ...)
  430. {
  431.   va_list msg;
  432.   va_start(msg,fmt);
  433.   vsnprintf(sbuf, sizeof(sbuf), fmt, msg);
  434.   va_end(msg);
  435.   sbuf[sizeof(sbuf) - 1] = '';
  436.   io_printf(session.c->outf, "%srn", sbuf);
  437. }
  438. void send_response_async(const char *resp_numeric, const char *fmt, ...)
  439. {
  440.   char buf[1024];
  441.   va_list msg;
  442.   int maxlen;
  443.   sstrncpy(buf, resp_numeric, sizeof(buf));
  444.   sstrcat(buf, " ", sizeof(buf));
  445.   
  446.   maxlen = sizeof(buf) - strlen(buf) - 1;
  447.   
  448.   va_start(msg, fmt);
  449.   vsnprintf(buf + strlen(buf), maxlen, fmt, msg);
  450.   va_end(msg);
  451.   
  452.   buf[sizeof(buf) - 1] = '';
  453.   sstrcat(buf, "rn", sizeof(buf));
  454.   io_write_async(session.c->outf, buf, strlen(buf));
  455. }
  456. void send_response(const char *resp_numeric, const char *fmt, ...)
  457. {
  458.   va_list msg;
  459.   va_start(msg,fmt);
  460.   vsnprintf(sbuf, sizeof(sbuf), fmt, msg);
  461.   va_end(msg);
  462.   
  463.   sbuf[sizeof(sbuf) - 1] = '';
  464.   io_printf(session.c->outf,"%s %srn",resp_numeric, sbuf);
  465. }
  466. void send_response_ml_start(const char *resp_numeric, const char *fmt, ...)
  467. {
  468.   va_list msg;
  469.   va_start(msg,fmt);
  470.   vsnprintf(sbuf, sizeof(sbuf), fmt, msg);
  471.   va_end(msg);
  472.   sbuf[sizeof(sbuf) - 1] = '';
  473.   sstrncpy(_ml_numeric, resp_numeric, sizeof(_ml_numeric));
  474.   
  475.   io_printf(session.c->outf, "%s-%srn", _ml_numeric, sbuf);
  476. }
  477. void send_response_ml(const char *fmt, ...)
  478. {
  479.   va_list msg;
  480.   va_start(msg,fmt);
  481.   vsnprintf(sbuf, sizeof(sbuf), fmt, msg);
  482.   va_end(msg);
  483.   sbuf[sizeof(sbuf) - 1] = '';
  484.   io_printf(session.c->outf, " %srn", sbuf);
  485. }
  486. void send_response_ml_end(const char *fmt, ...)
  487. {
  488.   va_list msg;
  489.  
  490.   va_start(msg,fmt);
  491.   vsnprintf(sbuf, sizeof(sbuf), fmt, msg);
  492.   va_end(msg);
  493.   sbuf[sizeof(sbuf) - 1] = '';
  494.   io_printf(session.c->outf, "%s %srn", _ml_numeric, sbuf);
  495. }
  496. void set_auth_check(int (*ck)(cmd_rec*))
  497. {
  498.   main_check_auth = ck;
  499. }
  500. void end_login_noexit()
  501. {
  502.   /* Run all the exit handlers */
  503.   run_exit_handlers();
  504.   /* If session.user is set, we have a valid login */
  505.   if(session.user) {
  506. #if (defined(BSD) && (BSD >= 199103))
  507.     snprintf(sbuf, sizeof(sbuf), "ftp%ld",(long)getpid());
  508. #else
  509.     snprintf(sbuf, sizeof(sbuf), "ftpd%d",(int)getpid());
  510. #endif
  511.     sbuf[sizeof(sbuf) - 1] = '';
  512.     
  513.     if(session.wtmp_log)
  514.       log_wtmp(sbuf,"",
  515.         (session.c && session.c->remote_name ? session.c->remote_name : ""),
  516.         (session.c && session.c->remote_ipaddr ? session.c->remote_ipaddr : NULL));
  517.     log_add_run(mpid,NULL,NULL,NULL,NULL,0,0,0,NULL);
  518.     log_close_run();
  519.   }
  520. }
  521. /* Finish any cleaning up, mark utmp as closed and exit
  522.  * without flushing buffers
  523.  */
  524. void end_login(int exitcode)
  525. {
  526.   end_login_noexit();
  527.   _exit(exitcode);
  528. }
  529. void main_exit(void *pv, void *lv, void *ev, void *dummy)
  530. {
  531.   int pri = (int)pv;
  532.   char *log = (char*)lv;
  533.   int exitcode = (int)ev;
  534.   log_pri(pri,log);
  535.   if(standalone && master)
  536.     log_pri(LOG_NOTICE,"ProFTPD %s standalone mode SHUTDOWN",VERSION);
  537.   end_login(exitcode);
  538. }
  539. void shutdown_exit(void *d1, void *d2, void *d3, void *d4)
  540. {
  541.   char *msg;
  542.   if(check_shutmsg(&shut,&deny,&disc,shutmsg,sizeof(shutmsg)) == 1) {
  543.     char *user;
  544.     time_t now;
  545.     time(&now);
  546.     if(get_param_int(main_server->conf,"authenticated",FALSE) == 1)
  547.       user = get_param_ptr(main_server->conf,"USER",FALSE);
  548.     else
  549.       user = "NONE";
  550.     msg = sreplace(permanent_pool,shutmsg,
  551.                    "%s",pstrdup(permanent_pool,fmt_time(shut)),
  552.                    "%r",pstrdup(permanent_pool,fmt_time(deny)),
  553.                    "%d",pstrdup(permanent_pool,fmt_time(disc)),
  554.    "%C",(session.cwd[0] ? session.cwd : "(none)"),
  555.    "%L",main_server->ServerAddress,
  556.    "%R",(session.c && session.c->remote_name ?
  557.                          session.c->remote_name : "(unknown)"),
  558.    "%T",pstrdup(permanent_pool,fmt_time(now)),
  559.    "%U",user,
  560.    "%V",main_server->ServerName,
  561.                    NULL );
  562.     send_response_async(R_421,"FTP server shutting down - %s",msg);
  563.     main_exit((void*)LOG_NOTICE,msg,(void*)0,NULL);
  564.   }
  565.   signal(SIGUSR1,sig_disconnect);
  566. }
  567. static int _dispatch(cmd_rec *cmd, int cmd_type, int validate, char *match)
  568. {
  569.   char *argstr;
  570.   cmdtable *c;
  571.   modret_t *mr;
  572.   int success = 0;
  573.   int send_error = 0;
  574.   static int match_index_cache = -1;
  575.   static char *last_match = NULL;
  576.   int *index_cache;
  577.   send_error = (cmd_type == CMD || cmd_type == PRE_CMD);
  578.   if(!match) {
  579.     match = cmd->argv[0];
  580.     index_cache = &cmd->symtable_index;
  581.   } else {
  582.     if(last_match != match) {
  583.       match_index_cache = -1;
  584.       last_match = match;
  585.     }
  586.     index_cache = &match_index_cache;
  587.   }
  588.   c = mod_find_cmd_symbol(match,index_cache,NULL);
  589.   while(c && !success) {
  590.     if(c->cmd_type == cmd_type) {
  591.       if(c->group)
  592.         cmd->group = pstrdup(cmd->pool,c->group);
  593.       if(c->requires_auth && main_check_auth && !main_check_auth(cmd))
  594.         return -1;
  595. #if 0
  596.       if(!c->interrupt_xfer && (session.flags & SF_XFER)) {
  597.         if(send_error)
  598.           add_response_err(R_451,"Cannot accept command, transfer is in progress.");
  599.         success = -1;
  600.         break;
  601.       }
  602. #endif
  603.       cmd->tmp_pool = make_named_sub_pool(cmd->pool,"temp - dispatch pool");
  604.       argstr = make_arg_str(cmd->tmp_pool,cmd->argc,cmd->argv);
  605.       if(session.user && (session.flags & SF_XFER) == 0 &&
  606.          cmd_type == CMD) {
  607.         log_add_run(mpid, NULL, session.user,
  608.     (session.class && session.class->name) ?
  609.     session.class->name : "",
  610.     NULL, 0, 0, 0, "proftpd: %s - %s: %s",
  611.                     session.user,session.proc_prefix,
  612.                     make_arg_str(cmd->tmp_pool,cmd->argc,cmd->argv));
  613.         set_proc_title("proftpd: %s - %s: %s",
  614.                        session.user,session.proc_prefix,
  615.                        argstr);
  616.       }
  617.       /* Hack to hide passwords */
  618.       if(send_error) {
  619.         if(!strcasecmp(cmd->argv[0],"PASS"))
  620.           log_debug(DEBUG4,"received: PASS (hidden)");
  621.         else
  622.           log_debug(DEBUG4,"received: %s",argstr);
  623.       }
  624.       cmd->class |= c->class;
  625.       /* KLUDGE: disable umask() for not G_WRITE operations.  Config/
  626.        * Directory walking code will be completely redesigned in 1.3,
  627.        * this is only necessary for perfomance reasons in 1.1/1.2
  628.        */
  629.       if(!c->group || strcmp(c->group,G_WRITE) != 0)
  630.         kludge_disable_umask();
  631.       mr = call_module_cmd(c->m,c->handler,cmd);
  632.       kludge_enable_umask();
  633.       if(MODRET_ISHANDLED(mr))
  634.         success = 1;
  635.       else if(MODRET_ISERROR(mr)) {
  636.         if(cmd_type == POST_CMD || cmd_type == LOG_CMD || 
  637.                                    cmd_type == LOG_CMD_ERR) {
  638.           if(MODRET_ERRMSG(mr))
  639.             log_pri(LOG_NOTICE,"%s",MODRET_ERRMSG(mr));
  640.         } else if(send_error) {
  641.           if(MODRET_ERRNUM(mr) && MODRET_ERRMSG(mr))
  642.             add_response_err(MODRET_ERRNUM(mr),MODRET_ERRMSG(mr));
  643.           else if(MODRET_ERRMSG(mr))
  644.             send_response_raw(MODRET_ERRMSG(mr));
  645.         }
  646.         success = -1;
  647.       }
  648.       if(session.user && (session.flags & SF_XFER) == 0 && cmd_type == CMD)
  649.         main_set_idle();
  650.       destroy_pool(cmd->tmp_pool);
  651.     }
  652.     if(!success)
  653.       c = mod_find_cmd_symbol(match,index_cache,c);
  654.   }
  655.   if(!c && !success && validate) {
  656.     add_response_err("500", "%s not understood.", cmd->argv[0]);
  657.     success = -1;
  658.   }
  659.   return success;
  660. }
  661. static void dispatch_cmd(cmd_rec *cmd)
  662. {
  663.   char *cp;
  664.   int success = 0;
  665. #if defined(HAVE_REGEX_H) && defined(HAVE_REGCOMP)
  666.   regex_t *preg;
  667.   int ret;
  668. #endif
  669.   
  670.   cmd->server = main_server;
  671.   resp_list = resp_err_list = NULL;
  672.   resp_pool = cmd->pool;
  673.   
  674. #if defined(HAVE_REGEX_H) && defined(HAVE_REGCOMP)
  675.   /* Check for valid arguments.
  676.    */
  677.   preg = (regex_t*) get_param_ptr(TOPLEVEL_CONF, "AllowFilter", FALSE);
  678.   
  679.   if(preg && ((ret = regexec(preg, cmd->arg, 0, NULL, 0)) != 0)) {
  680.     char errmsg[200];
  681.     
  682.     regerror(ret, preg, errmsg, 200);
  683.     log_debug(DEBUG2, "'%s' didn't pass regex: %s", cmd->arg, errmsg);
  684.     add_response_err(R_550,"%s: Forbidden command argument", cmd->arg);
  685.     send_response_list(&resp_err_list);
  686.     return;
  687.   }
  688.   
  689.   preg = (regex_t*)get_param_ptr(TOPLEVEL_CONF,"DenyFilter",FALSE);
  690.   
  691.   if(preg && ((ret = regexec(preg, cmd->arg, 0, NULL, 0)) == 0)) {
  692.     add_response_err(R_550,"%s: Forbidden command argument", cmd->arg);
  693.     send_response_list(&resp_err_list);
  694.     return;
  695.   }
  696. #endif
  697.   
  698.   for(cp = cmd->argv[0]; *cp; cp++)
  699.     *cp = toupper(*cp);
  700.   /* debug_print_dispatch(cmd); */
  701.   /* first dispatch PRE_CMD with wildcard */
  702.   success = _dispatch(cmd,PRE_CMD,FALSE,"*");
  703.   if(!success) /* run other pre_cmd */
  704.     success = _dispatch(cmd,PRE_CMD,FALSE,NULL);
  705.   if(success < 0) {
  706.     send_response_list(&resp_err_list);
  707.     return;
  708.   }
  709.   success = _dispatch(cmd,CMD,FALSE,"*");
  710.   if(!success)
  711.     success = _dispatch(cmd,CMD,TRUE,NULL);
  712.   if(success == 1) {
  713.     success = _dispatch(cmd,POST_CMD,FALSE,"*");
  714.     if(!success)
  715.       success = _dispatch(cmd,POST_CMD,FALSE,NULL);
  716.     _dispatch(cmd,LOG_CMD,FALSE,"*");
  717.     _dispatch(cmd,LOG_CMD,FALSE,NULL);
  718.     send_response_list(&resp_list);
  719.   } else if(success < 0) {
  720.     _dispatch(cmd,LOG_CMD_ERR,FALSE,"*");
  721.     _dispatch(cmd,LOG_CMD_ERR,FALSE,NULL);
  722.     send_response_list(&resp_err_list);
  723.   }
  724. }
  725. cmd_rec *make_cmd(pool *p, char *buf)
  726. {
  727.   char *cp = buf, *wrd;
  728.   cmd_rec *newcmd;
  729.   pool *newpool;
  730.   array_header *tarr;
  731.   newpool = make_sub_pool(p);
  732.   newcmd = (cmd_rec*)pcalloc(newpool,sizeof(cmd_rec));
  733.   newcmd->pool = newpool;
  734.   newcmd->symtable_index = -1;
  735.   
  736.   tarr = make_array(newpool,2,sizeof(char*));
  737.   if((wrd = get_word(&cp)) != NULL) {
  738.     *((char**)push_array(tarr)) = pstrdup(newpool,wrd);
  739.     newcmd->argc++;
  740.     newcmd->arg = pstrdup(newpool,cp);
  741.  
  742.     while((wrd = get_word(&cp)) != NULL) {
  743.       *((char**)push_array(tarr)) = pstrdup(newpool,wrd);
  744.       newcmd->argc++;
  745.     }
  746.   }
  747.   *((char**)push_array(tarr)) = NULL;
  748.   newcmd->argv = (char**)tarr->elts;
  749.   return newcmd;
  750. }
  751. static int _idle_timeout(CALLBACK_FRAME)
  752. {
  753.   /* we don't want to quit in the middle of a transfer */
  754.   if(session.flags & SF_XFER)
  755.     return 1; /* auto-restart the timer */
  756.   send_response_async(R_421,"Idle Timeout (%d seconds): closing control connection.", 
  757.                       TimeoutIdle);
  758.   main_exit((void*)LOG_NOTICE,
  759.   "FTP session idle timeout, disconnected.",
  760.   (void*)0,NULL);
  761.   remove_timer(TIMER_LOGIN,ANY_MODULE);
  762.   remove_timer(TIMER_NOXFER,ANY_MODULE);
  763.   return 0;
  764. }
  765. void cmd_loop(server_rec *server, conn_t *c)
  766. {
  767.   static int CmdBufSize = -1;
  768.   config_rec *id;
  769.   char buf[1024];
  770.   char *cp;
  771.   char *display;
  772.   int i;
  773.   /* Setup the main idle timer */
  774.   if(TimeoutIdle)
  775.     add_timer(TimeoutIdle,TIMER_IDLE,NULL,_idle_timeout);
  776.   display = (char*)get_param_ptr(server->conf,"DisplayConnect",FALSE);
  777.   if(display) {
  778.       core_display_file(R_220,display);
  779.   }
  780.   if((id = find_config(server->conf,CONF_PARAM,"ServerIdent",FALSE)) == NULL ||
  781.   !id->argv[0]) {
  782.     if(id && id->argc > 1)
  783.       send_response("220","%s",(char*)id->argv[1]);
  784.     else if(get_param_int(server->conf,"DeferWelcome",FALSE) == 1)
  785.       send_response("220", "ProFTPD " VERSION " Server ready.");
  786.     else
  787.       send_response("220", "ProFTPD " VERSION " Server (%s) [%s]",
  788.            server->ServerName,server->ServerAddress);
  789.   }
  790.   else
  791.   {
  792.     send_response("220", "%s FTP server ready.", server->ServerAddress);
  793.   }
  794.   /* make sure we can receive OOB data */
  795.   inet_setasync(session.pool,session.c);
  796.   while(1) {
  797.     if(io_telnet_gets(buf,sizeof(buf)-1,session.c->inf,session.c->outf) == NULL) {
  798.       if(session.c->inf->xerrno == EINTR)
  799. continue; /* Simple interrupted syscall */
  800.       
  801.       /* Otherwise, EOF */
  802.       log_pri(LOG_NOTICE,"FTP session closed.");
  803.       end_login(0);
  804.     }
  805.     /* Data received, reset idle timer */
  806.     if(TimeoutIdle)
  807.       reset_timer(TIMER_IDLE,NULL);
  808.     if(CmdBufSize == -1) {
  809.       if((CmdBufSize = get_param_int(main_server->conf,
  810.      "CommandBufferSize", FALSE)) <= 0) {
  811. CmdBufSize = 512;
  812.       } else if(CmdBufSize + 1 > sizeof(buf)) {
  813. log_pri(LOG_WARNING,
  814. "Invalid CommandBufferSize size given.  Resetting to 512.");
  815. CmdBufSize = 512;
  816.       }
  817.     }
  818.     
  819.     buf[CmdBufSize - 1] = '';
  820.     i = strlen(buf);
  821.     if(i && (buf[i-1] == 'n' || buf[i-1] == 'r')) {
  822.       buf[i-1] = ''; i--;
  823.       if(i && (buf[i-1] == 'n' || buf[i-1] =='r'))
  824.         buf[i-1] = '';
  825.     }
  826.     cp = buf;
  827.     if(*cp == 'r') cp++;
  828.     if(*cp) {
  829.       cmd_rec *cmd;
  830.       cmd = make_cmd(permanent_pool,cp);
  831.       if(cmd) {
  832.         dispatch_cmd(cmd);
  833.         destroy_pool(cmd->pool);
  834.       }
  835.     }
  836.   }
  837. }
  838. static void _server_conn_cleanup(void *connp)
  839. {
  840.   *((conn_t**)connp) = NULL;
  841. }
  842. void register_rehash(void *data, void (*fp)(void*))
  843. {
  844.   struct rehash *r = (struct rehash*)pcalloc(permanent_pool,
  845.    sizeof(struct rehash));
  846.   r->data = data;
  847.   r->rehash = fp;
  848.   r->next = rehash_list;
  849.   rehash_list = r;
  850. }
  851. void main_rehash(void *d1,void *d2,void *d3,void *d4)
  852. {
  853.   struct rehash *rh;
  854.   server_rec *s,*snext,*old_main;
  855.   xaset_t *old_servers;
  856.   int isdefault;
  857.   rehash++;
  858.   old_servers = servers;
  859.   old_main = main_server;
  860.   if(master && mpid) {
  861.     log_pri(LOG_NOTICE,"received SIGHUP -- master server rehashing configuration file.");
  862.     for(rh = rehash_list; rh; rh=rh->next)
  863.       rh->rehash(rh->data);
  864.     
  865.     init_config();
  866.     init_conf_stacks();
  867.     PRIVS_ROOT
  868.     if(parse_config_file(config_filename) == -1) {
  869.       PRIVS_RELINQUISH
  870.       log_pri(LOG_ERR,"Fatal: unable to read configuration file '%s'.",
  871.               config_filename);
  872.       end_login(1);
  873.     }
  874.     PRIVS_RELINQUISH
  875.     free_conf_stacks();
  876.     fixup_servers();
  877.     /* Free old configuration completely */
  878.     for(s = (server_rec*)old_servers->xas_list; s; s=snext) {
  879.       snext = s->next;
  880.       destroy_pool(s->pool);
  881.     }
  882.     destroy_pool(old_servers->mempool);
  883.     /* Destroy the old bind list */
  884.     if(bind_pool) {
  885.       destroy_pool(bind_pool);
  886.       bind_pool = NULL;
  887.     }
  888.     bind_list = NULL;
  889.     /* Recreate the listen connection */
  890.     if(main_server->ServerPort)
  891.       main_server->listen =
  892.         inet_create_connection(main_server->pool,servers,-1,
  893.                                (SocketBindTight ? main_server->ipaddr : NULL),
  894.               main_server->ServerPort,FALSE);
  895.     else
  896.       main_server->listen = NULL;
  897.     isdefault = get_param_int(main_server->conf,"DefaultServer",FALSE);
  898.     if(isdefault != 1)
  899.       isdefault = 0;
  900.     if(main_server->ServerPort || isdefault) {
  901.       add_binding(main_server,main_server->ipaddr,main_server->listen,
  902.                   isdefault,1);
  903.       addl_bindings(main_server);
  904.     }
  905.     for(s = main_server->next; s; s=s->next) {
  906.       if(s->ServerPort != main_server->ServerPort || SocketBindTight ||
  907.          !main_server->listen) {
  908.         isdefault = get_param_int(s->conf,"DefaultServer",FALSE);
  909.         if(isdefault != 1)
  910.           isdefault = 0;
  911.         if(s->ServerPort) {
  912.           s->listen = inet_create_connection(
  913.                         s->pool,servers,-1,
  914.                         (SocketBindTight ? s->ipaddr : NULL),
  915.                         s->ServerPort, FALSE);
  916.           add_binding(s,s->ipaddr,s->listen,isdefault,0);
  917.           addl_bindings(s);
  918.         } else if(isdefault) {
  919.           s->listen = NULL;
  920.           add_binding(s,s->ipaddr,s->listen,isdefault,0);
  921.           addl_bindings(s);
  922.         } else
  923.           s->listen = NULL;
  924.       } else {
  925.         isdefault = get_param_int(s->conf,"DefaultServer",FALSE);
  926.         if(isdefault != 1)
  927.           isdefault = 0;
  928.         s->listen = main_server->listen;
  929.         register_cleanup(s->listen->pool,&s->listen,
  930.                          _server_conn_cleanup,
  931.                          _server_conn_cleanup);
  932.         add_binding(s,s->ipaddr,NULL,isdefault,0);
  933.         addl_bindings(s);
  934.       }
  935.     }
  936.   } else
  937.     /* Child process -- cannot rehash, log error */
  938.     log_pri(LOG_ERR,"received SIGHUP, cannot rehash child process");
  939. }
  940. void fork_server(int fd,conn_t *l,int nofork)
  941. {
  942.   server_rec *s,*serv = NULL;
  943.   conn_t *conn;
  944.   int i;
  945. #ifndef DEBUG_NOFORK
  946.   pid_t pid;
  947.   sigset_t sigset;
  948.   pool *p;
  949.   if(!nofork) {
  950.     pidrec_t *cpid;
  951.     /* We block SIGCHLD to prevent a race condition if the child
  952.      * dies before we can record it's pid.  Also block SIGTERM to
  953.      * prevent sig_terminate() from examining the child list
  954.      */
  955.     sigemptyset(&sigset);
  956.     sigaddset(&sigset,SIGTERM);
  957.     sigaddset(&sigset,SIGCHLD);
  958.     sigaddset(&sigset,SIGUSR1);
  959.     sigaddset(&sigset,SIGUSR2);
  960.     sigprocmask(SIG_BLOCK,&sigset,NULL);
  961.     switch((pid = fork())) {
  962.     case 0: /* child */
  963.       master = FALSE; /* We aren't the master anymore */
  964.       sigprocmask(SIG_UNBLOCK,&sigset,NULL);
  965.       break;
  966.     case -1:
  967.       sigprocmask(SIG_UNBLOCK,&sigset,NULL);
  968.       log_pri(LOG_ERR,"fork(): %s",strerror(errno));
  969.       return;
  970.     default: /* parent */
  971.       /* The parent doesn't need the socket open */
  972.       close(fd);
  973.       if(!children) {
  974.         p = make_sub_pool(permanent_pool);
  975.         children = xaset_create(p,NULL);
  976.       } else
  977.         p = children->mempool;
  978.       cpid = (pidrec_t*)pcalloc(p,sizeof(pidrec_t));
  979.       cpid->pid = pid;
  980.       xaset_insert(children,(xasetmember_t*)cpid);
  981.       child_count++;
  982.       /* Unblock the signals now as sig_child() will catch
  983.        * an "immediate" death and remove the pid from the children list
  984.        */
  985.       sigprocmask(SIG_UNBLOCK,&sigset,NULL);
  986.       return;
  987.     }
  988.   }
  989. #ifdef HAVE_SETPGID
  990.   setpgid(0,getpid());
  991. #else
  992. # ifdef SETPGRP_VOID
  993.   setpgrp();
  994. # else
  995.    setpgrp(0,getpid());
  996. # endif
  997. #endif
  998. #endif /* DEBUG_NOFORK */
  999.   /* Child is running here */
  1000.   signal(SIGUSR1,sig_disconnect);
  1001.   signal(SIGUSR2,sig_debug);
  1002.   signal(SIGCHLD,SIG_DFL);
  1003.   signal(SIGHUP,SIG_IGN);
  1004.   /* From this point on, syslog stays open */
  1005.   /* We close it first so that the logger will pick up our
  1006.    * new pid.
  1007.    */
  1008.   block_signals();
  1009.   PRIVS_ROOT
  1010.   log_closesyslog();
  1011.   log_opensyslog(NULL);
  1012.   PRIVS_RELINQUISH
  1013.   unblock_signals();
  1014.   /* It's safe to call inet_openrw now (it might block),
  1015.    * because the parent is off answering new connections
  1016.    */
  1017.   conn = inet_openrw(permanent_pool,l,NULL,fd,
  1018.                      STDIN_FILENO,STDOUT_FILENO,TRUE);
  1019.   if(!conn) {
  1020.     log_pri(LOG_ERR,"Fatal: unable to open incoming connection: %s",
  1021.                    strerror(errno));
  1022.     exit(1);
  1023.   }
  1024.   inet_set_proto_options(permanent_pool,conn,1,1,0,0);
  1025.   serv = find_binding(conn->local_ipaddr,conn->local_port);
  1026.   /* If no server is configured to specifically handle the destination
  1027.    * address, search for the first server with DefaultServer set.
  1028.    */
  1029. #if 0
  1030.   if(!serv) {
  1031.     for(s = main_server; s; s=s->next)
  1032.       if(s->listen == l && 
  1033.          get_param_int(s->conf,"DefaultServer",FALSE) == 1) {
  1034.         serv = s;
  1035.         break;
  1036.       }
  1037.   }
  1038. #endif
  1039.   /* To conserve memory, free all other servers and associated
  1040.    * configurations
  1041.    */
  1042.   for(s = main_server; s; s=s->next)
  1043.     if(s != serv) {
  1044.       if(s->listen && s->listen != l) {
  1045. /* If our former listen socket was stdin or stdout (0 or 1),
  1046.          * inet_close() will attempt to close it, and in the process
  1047.          * close our read/write sockets for this connection.
  1048.          */
  1049.         if(s->listen->listen_fd == conn->rfd ||
  1050.            s->listen->listen_fd == conn->wfd)
  1051.           s->listen->listen_fd = -1;
  1052.         else
  1053.           inet_close(s->pool,s->listen);
  1054.       }
  1055.       if(s->listen) {
  1056.         if(s->listen->listen_fd == conn->rfd ||
  1057.            s->listen->listen_fd == conn->wfd)
  1058.              s->listen->listen_fd = -1;
  1059.       }
  1060.       xaset_remove(servers,(xasetmember_t*)s);
  1061.       destroy_pool(s->pool);
  1062.     }
  1063.   main_server = serv;
  1064.     
  1065.   session.pool = permanent_pool;
  1066.   session.c = conn;
  1067.   session.data_port = conn->remote_port - 1;
  1068.   /* Check and see if we are shutdown */
  1069.   if(shutdownp) {
  1070.     time_t now;
  1071.     time(&now);
  1072.     if(!deny || deny <= now) {
  1073.       char *reason =
  1074.           sreplace(permanent_pool,shutmsg,
  1075.                    "%s",pstrdup(permanent_pool,fmt_time(shut)),
  1076.                    "%r",pstrdup(permanent_pool,fmt_time(deny)),
  1077.                    "%d",pstrdup(permanent_pool,fmt_time(disc)),
  1078.    "%C",(session.cwd[0] ? session.cwd : "(none)"),
  1079.    "%L",main_server->ServerAddress,
  1080.    "%R",(session.c && session.c->remote_name ?
  1081.                          session.c->remote_name : "(unknown)"),
  1082.    "%T",pstrdup(permanent_pool,fmt_time(now)),
  1083.    "%U","NONE",
  1084.    "%V",main_server->ServerName,
  1085.                    NULL );
  1086.       log_auth(LOG_NOTICE,"connection refused (%s) from %s [%s]",
  1087.                reason,session.c->remote_name,
  1088.                inet_ntoa(*session.c->remote_ipaddr));
  1089.       printf("500 FTP server shut down (%s) -- please try again later.rn",
  1090.              reason); 
  1091.       fflush(stdout);
  1092.       exit(0);
  1093.     }
  1094.   }
  1095.   /* If no server is configured to handle the addr the user is
  1096.    * connected to, drop them.
  1097.    */
  1098.   if(!serv) {
  1099.     printf("500 Sorry, no server available to handle request on %s.rn",
  1100.            inet_getname(conn->pool,conn->local_ipaddr));
  1101.     fflush(stdout);
  1102.     exit(0);
  1103.   }
  1104.   if(serv->listen) {
  1105.     if(serv->listen->listen_fd == conn->rfd ||
  1106.         serv->listen->listen_fd == conn->wfd)
  1107.           serv->listen->listen_fd = -1;
  1108.     destroy_pool(serv->listen->pool);
  1109.     serv->listen = NULL;
  1110.   }
  1111.   /* Check config tree for <Limit LOGIN> directives */
  1112.   if(!login_check_limits(serv->conf,TRUE,FALSE,&i)) {
  1113.     log_pri(LOG_NOTICE,"Connection from %s [%s] denied.",
  1114.             session.c->remote_name,inet_ntoa(*session.c->remote_ipaddr));
  1115.     exit(0);
  1116.   }
  1117.   log_debug(DEBUG4,"connected - local  : %s:%d",
  1118.                     inet_ntoa(*session.c->local_ipaddr),
  1119.                     session.c->local_port);
  1120.   log_debug(DEBUG4,"connected - remote : %s:%d",
  1121.        inet_ntoa(*session.c->remote_ipaddr),
  1122.        session.c->remote_port);
  1123.   /* Use the ident protocol (RFC1413) to try to get remote ident_user
  1124.    */
  1125.   if(get_param_int(main_server->conf,"IdentLookups",FALSE) != 0)
  1126.     session.ident_user = get_ident(session.pool,conn);
  1127.   else
  1128.     session.ident_user = "UNKNOWN";
  1129.   /* Inform all the modules that we are now a child */
  1130.   init_child_modules();
  1131.   /* find class */
  1132.   session.class = (class_t *) find_class(conn->remote_ipaddr, conn->remote_name);
  1133.   /* xfer_set_data_port(conn->local_ipaddr,conn->local_port-1); */
  1134.   cmd_loop(serv,conn);
  1135. }
  1136. void disc_children()
  1137. {
  1138.   sigset_t sigset;
  1139.   pidrec_t *cp;
  1140.   if(disc && disc <= time(NULL) && children) {
  1141.     sigemptyset(&sigset);
  1142.     sigaddset(&sigset,SIGTERM);
  1143.     sigaddset(&sigset,SIGCHLD);
  1144.     sigaddset(&sigset,SIGUSR1);
  1145.     sigaddset(&sigset,SIGUSR2);
  1146.     sigprocmask(SIG_BLOCK,&sigset,NULL);
  1147.     PRIVS_ROOT
  1148.     for(cp = (pidrec_t*)children->xas_list; cp; cp=cp->next)
  1149.       kill(cp->pid,SIGUSR1);
  1150.     PRIVS_RELINQUISH
  1151.     sigprocmask(SIG_UNBLOCK,&sigset,NULL);
  1152.   }
  1153. }
  1154. void server_loop()
  1155. {
  1156.   fd_set rfd;
  1157.   conn_t *listen;
  1158.   int fd, max_fd;
  1159.   int i,err_count = 0;
  1160.   time_t last_error;
  1161.   struct timeval tv;
  1162.   set_proc_title("proftpd (accepting connections)");
  1163.   time(&last_error);
  1164.   while(1) {
  1165.     run_schedule();
  1166.     max_fd = listen_binding(&rfd);
  1167.     /* Check for ftp shutdown message file */
  1168.     switch(check_shutmsg(&shut,&deny,&disc,shutmsg,sizeof(shutmsg))) {
  1169.     case 1: if(!shutdownp) disc_children(); shutdownp = 1; break;
  1170.     case 0: shutdownp = 0; deny = disc = (time_t)0; break;
  1171.     }
  1172.     if(shutdownp) {
  1173.       tv.tv_usec = 0L;
  1174.       tv.tv_sec = 5L;
  1175.     } else {
  1176.       tv.tv_usec = 0L;
  1177.       tv.tv_sec = 30L;
  1178.     }
  1179.     i = select(max_fd + 1, &rfd, NULL, NULL,&tv);
  1180.     if(child_flag) {
  1181.       sigset_t sigset;
  1182.       pidrec_t *cp,*cpnext;
  1183.       sigemptyset(&sigset);
  1184.       sigaddset(&sigset,SIGCHLD);
  1185.       sigaddset(&sigset,SIGTERM);
  1186.       block_alarms();
  1187.       sigprocmask(SIG_BLOCK,&sigset,NULL);
  1188.       child_flag = 0;
  1189.       if(children) {
  1190.         for(cp = (pidrec_t*)children->xas_list; cp; cp=cpnext) {
  1191.           cpnext = cp->next;
  1192.           if(cp->dead)
  1193.             xaset_remove(children,(xasetmember_t*)cp);
  1194.         }
  1195.       }
  1196.       /* Don't need the pool anymore */
  1197.       if(!children->xas_list) {
  1198.         destroy_pool(children->mempool);
  1199.         children = NULL;
  1200.       }
  1201.       sigprocmask(SIG_UNBLOCK,&sigset,NULL);
  1202.       unblock_alarms();
  1203.     }
  1204.     if(i == -1) {
  1205.       time_t this_error;
  1206.       if(errno == EINTR)
  1207.         continue;
  1208.       time(&this_error);
  1209.       if((this_error - last_error) <= 5 && err_count++ > 10) {
  1210.         log_pri(LOG_ERR,"Fatal: select() failing repeatedly, shutting down.");
  1211.         exit(1);
  1212.       } else if((this_error - last_error) > 5) {
  1213.         last_error = this_error;
  1214.         err_count = 0;
  1215.       }
  1216.       log_pri(LOG_NOTICE,"select() failed in server_loop(): %s",
  1217.               strerror(errno));
  1218.     }
  1219.     if(i == 0)
  1220.       continue;
  1221.     /* fork off servers to handle each connection
  1222.      * our job is to get back to answering connections asap,
  1223.      * so leave the work of determining which server the connection
  1224.      * is for to our child.
  1225.      */
  1226.     listen = accept_binding(&rfd, &fd);
  1227.     if(listen) {
  1228.       if(ServerMaxInstances && child_count >= ServerMaxInstances) {
  1229.         log_pri(LOG_WARNING,"MaxInstances (%d) reached, new connection denied.",ServerMaxInstances);
  1230.         close(fd);
  1231.       } else
  1232.         fork_server(fd,listen,FALSE);
  1233.     }
  1234.   }
  1235. }
  1236. /* sig_rehash occurs in the master daemon when manually "kill -HUP"
  1237.  * in order to re-read configuration files, and is sent to all
  1238.  * children by the master.
  1239.  */
  1240. static RETSIGTYPE sig_rehash(int sig)
  1241. {
  1242.   schedule(main_rehash,0,NULL,NULL,NULL,NULL);
  1243.   signal(SIGHUP,sig_rehash);
  1244. }
  1245. /* sig_debug outputs some basic debugging info
  1246.  */
  1247. static RETSIGTYPE sig_debug(int sig)
  1248. {
  1249.   debug_walk_pools();
  1250. }
  1251. /* sig_disconnect is called in children when the parent daemon
  1252.  * detects that shutmsg has been created and ftp sessions should
  1253.  * be destroyed.  If a file transfer is underway, the process simply
  1254.  * dies, otherwise a function is scheduled to attempt to display
  1255.  * the shutdown reason.
  1256.  */
  1257. static RETSIGTYPE sig_disconnect(int sig)
  1258. {
  1259.   if((session.flags & SF_ANON) || (session.flags & SF_XFER))
  1260.     schedule(main_exit,0,(void*)LOG_NOTICE,
  1261.              "Parent process requested shutdown",
  1262.              (void*)0,NULL);
  1263.   else
  1264.     schedule(shutdown_exit,0,NULL,NULL,NULL,NULL);
  1265.   signal(SIGUSR1,SIG_IGN);
  1266. }
  1267. static RETSIGTYPE sig_child(int sig)
  1268. {
  1269.   sigset_t sigset;
  1270.   pid_t cpid;
  1271.   pidrec_t *cp,*cpnext;
  1272.   sigemptyset(&sigset);
  1273.   sigaddset(&sigset,SIGTERM);
  1274.   block_alarms();
  1275.   sigprocmask(SIG_BLOCK,&sigset,NULL);
  1276.   /* block SIGTERM in here, so we don't create screw with the
  1277.    * child list while modifying it.
  1278.    */
  1279.   while((cpid = waitpid(-1,NULL,WNOHANG)) > 0) {
  1280.     child_count--; child_flag = 1;
  1281.     if(children) {
  1282.       for(cp = (pidrec_t*)children->xas_list; cp; cp=cpnext) {
  1283.         cpnext = cp->next;
  1284.         if(cp->pid == cpid) {
  1285.           child_flag++;
  1286.           cp->dead = 1;
  1287.         }
  1288.       }
  1289.     }
  1290.   }
  1291.   sigprocmask(SIG_UNBLOCK,&sigset,NULL);
  1292.   unblock_alarms();
  1293.   signal(SIGCHLD,sig_child);
  1294. }
  1295. static RETSIGTYPE sig_abort(int sig)
  1296. {
  1297. #if 0
  1298.   if(abort_core)
  1299.     log_pri(LOG_NOTICE,"ProFTPD received SIGABRT signal, generating core file in %s",_prepare_core());
  1300.   else
  1301. #endif
  1302.     log_pri(LOG_NOTICE,"ProFTPD received SIGABRT signal, no core dump.");
  1303.   
  1304.   signal(SIGABRT,SIG_DFL);
  1305.   end_login_noexit();
  1306.   abort();
  1307. }  
  1308. static void _internal_abort()
  1309. {
  1310.   if(abort_core) {
  1311. #if 0
  1312.     log_pri(LOG_NOTICE,"core file dumped to %s",_prepare_core());
  1313. #endif
  1314.     signal(SIGABRT,SIG_DFL);
  1315.     end_login_noexit();
  1316.     abort();
  1317.   }
  1318. }
  1319. static RETSIGTYPE sig_terminate(int sig)
  1320. {
  1321.   pidrec_t *pid;
  1322.   if(sig == SIGTERM) {
  1323.     /* Don't log if we are a child that has been terminated */
  1324.     if(master) {
  1325.       /* Send a SIGKILL to all our children */
  1326.       if(children) {
  1327.         PRIVS_ROOT
  1328.         for(pid = (pidrec_t*)children->xas_list; pid; pid=pid->next)
  1329.           kill(pid->pid,SIGTERM);
  1330.         PRIVS_RELINQUISH
  1331.       }
  1332.       log_pri(LOG_NOTICE,"ProFTPD killed (signal %d)",sig);
  1333.     }
  1334.   } else
  1335.     log_pri(LOG_ERR,"ProFTPD terminating (signal %d)",sig);
  1336.   if(master && mpid == getpid()) {
  1337.     PRIVS_ROOT
  1338.     log_close_run();
  1339.     log_rm_run();
  1340.     PRIVS_RELINQUISH
  1341.     if(standalone)
  1342.       log_pri(LOG_NOTICE,"ProFTPD %s standalone mode SHUTDOWN",VERSION);
  1343.   }
  1344.   _internal_abort();  
  1345.   end_login(1);
  1346. }
  1347. static void install_signal_handlers()
  1348. {
  1349.   sigset_t sigset;
  1350.   /* Should the master server (only applicable in standalone mode)
  1351.    * kill off children if we receive a signal that causes termination?
  1352.    * hmmmm... Maybe this needs to be rethought, but I've done it in
  1353.    * such a way as to only kill off our children if we receive a SIGTERM,
  1354.    * meaning that the admin wants us dead (and prolly our kids too).
  1355.    */
  1356.   /* The sub-pool for the child list is created the first time we fork
  1357.    * off a child.  To conserve memory, the pool and list is destroyed
  1358.    * when our last child dies (to prevent the list from eating more and
  1359.    * more memory on long uptimes)
  1360.    */
  1361.   sigemptyset(&sigset);
  1362.   sigaddset(&sigset,SIGCHLD);
  1363.   sigaddset(&sigset,SIGINT);
  1364.   sigaddset(&sigset,SIGQUIT);
  1365.   sigaddset(&sigset,SIGILL);
  1366.   sigaddset(&sigset,SIGABRT);
  1367.   sigaddset(&sigset,SIGFPE);
  1368.   sigaddset(&sigset,SIGSEGV);
  1369.   sigaddset(&sigset,SIGALRM);
  1370.   sigaddset(&sigset,SIGTERM);
  1371. #ifdef SIGSTKFLT
  1372.   sigaddset(&sigset,SIGSTKFLT);
  1373. #endif
  1374.   sigaddset(&sigset,SIGIO);
  1375. #ifdef SIGBUS
  1376.   sigaddset(&sigset,SIGBUS);
  1377. #endif
  1378.   sigaddset(&sigset,SIGHUP);
  1379.   sigaddset(&sigset,SIGUSR2);
  1380.   
  1381.   signal(SIGCHLD,sig_child);
  1382.   signal(SIGHUP,sig_rehash);
  1383.   signal(SIGUSR2,sig_debug);
  1384. #ifndef DEBUG_NOSIG
  1385.   signal(SIGINT,sig_terminate);
  1386.   signal(SIGQUIT,sig_terminate);
  1387.   signal(SIGILL,sig_terminate);
  1388.   signal(SIGABRT,sig_abort);
  1389.   signal(SIGFPE,sig_terminate);
  1390.   signal(SIGSEGV,sig_terminate);
  1391.   signal(SIGTERM,sig_terminate);
  1392. #ifdef SIGSTKFLT
  1393.   signal(SIGSTKFLT,sig_terminate);
  1394. #endif /* SIGSTKFLT */
  1395.   signal(SIGIO,sig_terminate);
  1396. #ifdef SIGBUS
  1397.   signal(SIGBUS,sig_terminate);
  1398. #endif /* SIGBUS */
  1399. #endif /* DEBUG_NOSIG */
  1400.   signal(SIGIO,SIG_IGN);
  1401.   signal(SIGURG,SIG_IGN);
  1402.   /* In case our parent left signals blocked (as happens under some
  1403.    * poor inetd implementations)
  1404.    */
  1405.   sigprocmask(SIG_UNBLOCK,&sigset,NULL);
  1406. }
  1407. static void set_rlimits()
  1408. {
  1409.   struct rlimit rlim;
  1410.   if(getrlimit(RLIMIT_CORE,&rlim) == -1)
  1411.     log_pri(LOG_ERR,"getrlimit(): %s",strerror(errno));
  1412.   else {
  1413.     if(abort_core)
  1414.       rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
  1415.     else
  1416.       rlim.rlim_cur = rlim.rlim_max = 0;
  1417.     PRIVS_ROOT
  1418.     if(setrlimit(RLIMIT_CORE,&rlim) == -1) {
  1419.       PRIVS_RELINQUISH
  1420.       log_pri(LOG_ERR,"setrlimit(): %s",strerror(errno));
  1421.       return;
  1422.     }
  1423.     PRIVS_RELINQUISH
  1424.   }
  1425. }
  1426. void start_daemon()
  1427. {
  1428. #ifndef HAVE_SETSID
  1429.   int ttyfd;
  1430. #endif
  1431.   /* Fork off and have parent exit */
  1432.   switch(fork()) {
  1433.     case -1: perror("fork"); exit(1);
  1434.     case 0: break;
  1435.     default: exit(0);
  1436.   }
  1437. #ifdef HAVE_SETSID
  1438.   /* setsid() is the preferred way to disassociate from the 
  1439.    * controlling terminal
  1440.    */
  1441.   setsid();
  1442. #else
  1443.   /* Open /dev/tty to access our controlling tty (if any) */
  1444.   if( (ttyfd = open("/dev/tty",O_RDWR)) != -1)
  1445.   {
  1446.     if(ioctl(ttyfd,TIOCNOTTY,NULL) == -1) {
  1447.       perror("ioctl"); exit(1);
  1448.     }
  1449.     close(ttyfd);
  1450.   }
  1451. #endif /* HAVE_SETSID */
  1452.   /* Close the three big boys */
  1453.   close(fileno(stdin));
  1454.   close(fileno(stdout));
  1455.   close(fileno(stderr));
  1456.   /* Portable way to prevent re-acquiring a tty in the future */
  1457. #ifdef HAVE_SETPGID
  1458.   setpgid(0,getpid());
  1459. #else
  1460. # ifdef SETPGRP_VOID
  1461.   setpgrp();
  1462. # else
  1463.   setpgrp(0,getpid());
  1464. # endif
  1465. #endif
  1466.   fs_chdir("/",0);
  1467. }
  1468. void addl_bindings(server_rec *s)
  1469. {
  1470.   config_rec *c;
  1471.   conn_t *listen;
  1472.   p_in_addr_t *ipaddr;
  1473.   c = find_config(s->conf,CONF_PARAM,"Bind",FALSE);
  1474.   while(c) {
  1475.     listen = NULL;
  1476.     /* If SocketBindTight is set, we create an additional listen
  1477.      * connection for each binding.
  1478.      */
  1479.     ipaddr = inet_getaddr(s->pool,c->argv[0]);
  1480.     if(!ipaddr) {
  1481.       log_pri(LOG_NOTICE,"unable to determine IP address of `%s'.",
  1482.               c->argv[0]);
  1483.       continue;
  1484.     }
  1485.     if(SocketBindTight && s->ServerPort) {
  1486.       listen = inet_create_connection(s->pool,servers,-1,
  1487.                ipaddr,s->ServerPort,FALSE);
  1488.       add_binding(s,ipaddr,listen,0,0);
  1489.     } else
  1490.       add_binding(s,ipaddr,s->listen,0,0);
  1491.     c = find_config_next(c,c->next,CONF_PARAM,"Bind",FALSE);
  1492.   }
  1493. }
  1494. void inetd_main()
  1495. {
  1496.   server_rec *s;
  1497.   int isdefault;
  1498.   PRIVS_ROOT
  1499.   log_open_run(0,FALSE,TRUE);
  1500.   log_close_run();
  1501.   PRIVS_RELINQUISH
  1502.   main_server->listen = 
  1503.     inet_create_connection(main_server->pool,servers,STDIN_FILENO,
  1504.                            NULL,INPORT_ANY,FALSE);
  1505.   /* Fill in all the important connection info */
  1506.   if(inet_get_conn_info(main_server->listen,STDIN_FILENO) == -1) {
  1507.     log_pri(LOG_ERR,"Fatal: %s",strerror(errno));
  1508.     if(errno == ENOTSOCK)
  1509.       log_pri(LOG_ERR,"(Running from command line? "
  1510.                       "Use `ServerType standalone' in config file!)");
  1511.     exit(1);
  1512.   }
  1513.   isdefault = get_param_int(main_server->conf,"DefaultServer",FALSE);
  1514.   if(isdefault != 1)
  1515.     isdefault = 0;
  1516.   add_binding(main_server,main_server->ipaddr,main_server->listen,
  1517.                 isdefault,1);
  1518.   addl_bindings(main_server);
  1519.   /* Now attach the faked connection to all virtual servers */
  1520.   for(s = main_server->next; s; s=s->next) {
  1521.       /* Because this server is sharing the connection with the
  1522.        * main server, we need a cleanup handler to remove
  1523.        * the server's reference when the original connection's
  1524.        * pool is destroyed.
  1525.        */
  1526.       s->listen = main_server->listen;
  1527.       register_cleanup(s->listen->pool,&s->listen,
  1528.                        _server_conn_cleanup,
  1529.                        _server_conn_cleanup);
  1530.       
  1531.       isdefault = get_param_int(s->conf,"DefaultServer",FALSE);
  1532.       if(isdefault != 1)
  1533.         isdefault = 0;
  1534.       add_binding(s,s->ipaddr,s->listen,isdefault,0);
  1535.       addl_bindings(s);
  1536.   }
  1537.   /* Check our shutdown status */
  1538.   if(check_shutmsg(&shut,&deny,&disc,shutmsg,sizeof(shutmsg)) == 1)
  1539.     shutdownp = 1;
  1540.   /* Finally, call right into fork_server() to start servicing the
  1541.    * connection immediately
  1542.    */
  1543.   fork_server(STDIN_FILENO,main_server->listen,TRUE);
  1544. }
  1545. void standalone_main(int nodaemon)
  1546. {
  1547.   server_rec *s;
  1548.   int isdefault;
  1549.   standalone = 1;
  1550.   if(nodaemon) {
  1551.     log_stderr(TRUE);
  1552.     close(fileno(stdin));
  1553.     close(fileno(stdout));
  1554.   }
  1555.   else {
  1556.     log_stderr(FALSE);
  1557.     start_daemon();
  1558.   }
  1559.   mpid = getpid();
  1560.   PRIVS_ROOT
  1561.   log_open_run(mpid,TRUE,TRUE);
  1562.   log_close_run();
  1563.   PRIVS_RELINQUISH
  1564.   /* If a port is set to 0, the address/port is not bound at all */
  1565.   if(main_server->ServerPort)
  1566.     main_server->listen =
  1567.       inet_create_connection(main_server->pool,servers,-1,
  1568.                              (SocketBindTight ? main_server->ipaddr :  NULL),
  1569.                              main_server->ServerPort,FALSE);
  1570.   else
  1571.     main_server->listen = NULL;
  1572.   isdefault = get_param_int(main_server->conf,"DefaultServer",FALSE);
  1573.   if(isdefault != 1)
  1574.     isdefault = 0;
  1575.   if(main_server->ServerPort || isdefault) {
  1576.     add_binding(main_server,main_server->ipaddr,main_server->listen,
  1577.                 isdefault,1);
  1578.     addl_bindings(main_server);
  1579.   }
  1580.   for(s = main_server->next; s; s=s->next)
  1581.     if(s->ServerPort != main_server->ServerPort || SocketBindTight ||
  1582.        !main_server->listen) {
  1583.       isdefault = get_param_int(s->conf,"DefaultServer",FALSE);
  1584.       if(isdefault != 1)
  1585.         isdefault = 0;
  1586.       if(s->ServerPort) {
  1587.         s->listen = inet_create_connection(
  1588.                       s->pool,servers,-1,
  1589.          (SocketBindTight ? s->ipaddr : NULL),
  1590.                       s->ServerPort,FALSE);        
  1591.         add_binding(s,s->ipaddr,s->listen,isdefault,0);
  1592.         addl_bindings(s);
  1593.       } else if(isdefault) {
  1594.         s->listen = NULL;
  1595.         add_binding(s,s->ipaddr,s->listen,isdefault,0);
  1596.         addl_bindings(s);
  1597.       } else
  1598.         s->listen = NULL;
  1599.     } else {
  1600.       /* Because this server is sharing the connection with the
  1601.        * main server, we need a cleanup handler to remove
  1602.        * the server's reference when the original connection's
  1603.        * pool is destroyed.
  1604.        */
  1605.       isdefault = get_param_int(s->conf,"DefaultServer",FALSE);
  1606.       if(isdefault != 1)
  1607.         isdefault = 0;
  1608.        
  1609.       s->listen = main_server->listen;
  1610.       register_cleanup(s->listen->pool,&s->listen,
  1611.                        _server_conn_cleanup,
  1612.                        _server_conn_cleanup);
  1613.       add_binding(s,s->ipaddr,NULL,isdefault,0);
  1614.       addl_bindings(s);
  1615.     }
  1616.   log_pri(LOG_NOTICE,"ProFTPD %s standalone mode STARTUP",VERSION);
  1617.   server_loop();
  1618. }
  1619. extern char *optarg;
  1620. extern int optind,opterr,optopt;
  1621. struct option opts[] = {
  1622.   { "nodaemon", 0, NULL, 'n' },
  1623.   { "debug", 1, NULL, 'd' },
  1624.   { "config", 1, NULL, 'c' },
  1625.   { "persistent",1,NULL, 'p' },
  1626.   { "list",     0, NULL, 'l' },
  1627.   { "version",  0, NULL, 'v' },
  1628. /*
  1629.   { "core",     0, NULL, 'o' },
  1630. */
  1631.   { "help", 0, NULL, 'h' },
  1632.   { NULL, 0, NULL,  0  }
  1633. };
  1634. struct option_help {
  1635.   char *long_opt,*short_opt,*desc;
  1636. } opts_help[] = {
  1637.   { "--help","-h","display proftpd usage"},
  1638.   { "--nodaemon","-n","disable background daemon mode (all output goes to tty, instead of syslog)" },
  1639.   { "--debug","-d [level]","set debugging level (0-5, 5 == most debugging)" },
  1640.   { "--config","-c [config-file]","specify alternate configuration file" },
  1641.   { "--persistent","-p [0|1]","enable/disable default persistent passwd support" },
  1642.   { "--list","-l","list all compiled-in modules" },
  1643. /*
  1644.   { "--core","-o","enable core dump for profiling/debugging on serious errors"},
  1645. */
  1646.   { "--version","-v","print version number and exit" },
  1647.   { NULL,NULL,NULL }
  1648. };
  1649. void show_usage(int exit_code)
  1650. {
  1651.   struct option_help *h;
  1652.   printf("usage: proftpd [options]n");
  1653.   for(h = opts_help; h->long_opt; h++) {
  1654.     printf("  %s,%sn",h->long_opt,h->short_opt);
  1655.     printf("    %sn",h->desc);
  1656.   }
  1657.   exit(exit_code);
  1658. }
  1659. int main(int argc, char **argv, char **envp)
  1660. {
  1661.   int daemon_uid,daemon_gid,socketp;
  1662.   int _umask = 0,nodaemon = 0,c;
  1663.   struct sockaddr peer;
  1664. #ifdef DEBUG_MEMORY
  1665.   int logfd;
  1666.   extern int EF_PROTECT_BELOW;
  1667.   extern int EF_PROTECT_FREE;
  1668.   extern int EF_ALIGNMENT;
  1669.   EF_PROTECT_BELOW = 1;/* */
  1670.   EF_PROTECT_FREE = 1; /* */
  1671.   EF_ALIGNMENT = 0; /* */
  1672.   /* Redirect stderr to somewhere appropriate.
  1673.    * Ideally, this would be syslog, but alas...
  1674.    */
  1675.   if((logfd = open(RUN_DIR "/proftpd-memory.log",
  1676.    O_WRONLY | O_CREAT | O_APPEND, 0644))< 0) {
  1677. log_pri(LOG_ERR, "Error opening error logfile: %s", strerror(errno));
  1678. exit(1);
  1679.   }
  1680.   close(fileno(stderr));
  1681.   if(dup2(logfd, fileno(stderr)) == -1) {
  1682. log_pri(LOG_ERR, "Error converting standard error to a logfile: %s",
  1683. strerror(errno));
  1684. exit(1);
  1685.   }
  1686.   close(logfd);
  1687. #endif /* DEBUG_MEMORY */
  1688. #ifdef HAVE_SET_AUTH_PARAMETERS
  1689.   (void) set_auth_parameters(argc, argv);
  1690. #endif
  1691.   bzero(&session,sizeof(session));
  1692.   /* Initialize stuff for set_proc_title.
  1693.    */
  1694.   init_set_proc_title(argc, argv, envp);
  1695.   /* getpeername() fails if the fd isn't a socket */
  1696.   socketp = sizeof(peer);
  1697.   if(getpeername(fileno(stdin),&peer,&socketp) != -1) {
  1698.     log_stderr(FALSE);
  1699.     socketp = TRUE;
  1700.   } else
  1701.     socketp = FALSE;
  1702.   /* Open the syslog */
  1703.   log_opensyslog(NULL);
  1704.   /* Command line options supported:
  1705.    * -n,--nodaemon standalone server doesn't background itself,
  1706.    *                    all logging dumped to stderr
  1707.    *
  1708.    * -d n,--debug n set debug level
  1709.    *
  1710.    * -c, --config path  set the configuration path
  1711.    *
  1712.    * -v, --version      report version number
  1713.    */
  1714.   opterr = 0;
  1715.   while((c = getopt_long(argc,argv,"nd:c:p:lhv",opts,NULL)) != -1) {
  1716.     switch(c) {
  1717.     case 'n': 
  1718.       nodaemon++; break;
  1719.     case 'd': 
  1720.       if(!optarg) {
  1721.         log_pri(LOG_ERR,"Fatal: -d requires debugging level argument.");
  1722.         exit(1);
  1723.       }
  1724.       log_setdebuglevel(atoi(optarg));
  1725.       break;
  1726.     case 'c':
  1727.       if(!optarg) {
  1728.         log_pri(LOG_ERR,"Fatal: -c requires configuration path argument.");
  1729.         exit(1);
  1730.       }
  1731.       config_filename = strdup(optarg);
  1732.       break;
  1733.     case 'l':
  1734.       list_modules();
  1735.       exit(0);
  1736.     case 'p':
  1737.     {
  1738.       extern int persistent;
  1739.       if(!optarg || ((persistent = atoi(optarg)) != 1 && persistent != 0)) {
  1740.         log_pri(LOG_ERR,"Fatal: -p requires boolean (0|1) argument.");
  1741.         exit(1);
  1742.       }
  1743.       break;
  1744.     }
  1745.     /*
  1746.     case 'o':
  1747.       abort_core++;
  1748.       break;
  1749.     */
  1750.     case 'v':
  1751.       log_pri(LOG_NOTICE,"ProFTPD Version " VERSION);
  1752.       exit(0);
  1753.     case 'h':
  1754.       show_usage(0);
  1755.     case '?':
  1756.       log_pri(LOG_ERR,"Unknown option: %c",(char)optopt);
  1757.       show_usage(1);
  1758.     }
  1759.   }
  1760.  
  1761.   /* Initialize sub-systems */
  1762.   init_alloc();
  1763.   init_log();
  1764.   init_inet();
  1765.   init_io();
  1766.   init_fs();
  1767.   init_config();
  1768.   init_modules();
  1769.   init_conf_stacks();
  1770.   if(parse_config_file(config_filename) == -1) {
  1771.     log_pri(LOG_ERR,"Fatal: unable to read configuration file '%s'.",
  1772.             config_filename);
  1773.     exit(1);
  1774.   }
  1775.   free_conf_stacks();
  1776.   fixup_servers();
  1777.   /* After configuration is complete, make sure that passwd, group
  1778.    * aren't held open (unnecessary fds for master daemon)
  1779.    */
  1780.   endpwent();
  1781.   endgrent();
  1782.   /* Security */
  1783.   daemon_uid = get_param_int(main_server->conf,"User",FALSE);
  1784.   if(daemon_uid == -1)
  1785.     daemon_uid = 0;
  1786.   daemon_gid = get_param_int(main_server->conf,"Group",FALSE);
  1787.   if(daemon_gid == -1)
  1788.     daemon_gid = 0;
  1789.   if(daemon_uid)
  1790.     initgroups((const char*)get_param_ptr(main_server->conf,"UserName",
  1791.                   FALSE),daemon_gid);
  1792.   
  1793.    if((_umask = get_param_int(main_server->conf,"Umask",FALSE)) == -1)
  1794.     _umask = 0022;
  1795.   umask(_umask);
  1796.   /* Give up root and save our uid/gid for later use (if supported)
  1797.    * If we aren't currently root, PRIVS_SETUP will get rid of setuid
  1798.    * granted root and prevent further uid switching from being attempted.
  1799.    */
  1800.   PRIVS_SETUP(daemon_uid,daemon_gid)
  1801.   /* Install a signal handlers/abort handler */
  1802.   install_signal_handlers();
  1803.   set_rlimits();
  1804.   switch(ServerType) {
  1805.   case SERVER_STANDALONE: standalone_main(nodaemon);
  1806.   case SERVER_INETD:      inetd_main();
  1807.   }
  1808.   return 0;
  1809. }