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

Ftp客户端

开发平台:

Unix_Linux

  1. /*
  2.  * ProFTPD - FTP server daemon
  3.  * Copyright (c) 1997, 1998 Public Flood Software
  4.  *  
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or
  8.  * (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
  18.  */
  19. /* Various basic support routines for ProFTPD, used by all modules
  20.  * and not specific to one or another.
  21.  * $Id: support.c,v 1.9 1999/10/01 23:52:38 macgyver Exp $
  22.  */
  23. /* History Log:
  24.  * 10/29/97 current: 0.99.0pl9, next: 0.99.0pl10
  25.  *   Added get_fs_size(), used to determine the amount of space
  26.  *   available on a filesystem (if supported)
  27.  *
  28.  * 7/9/97 current: 0.99.0pl6, next: 0.99.0pl7
  29.  *   Added exit handler chain, works identically to libc atexit(),
  30.  *   however atexit() can't be used because proftpd often terminates
  31.  *   with _exit() rather than exit().
  32.  *
  33.  * 5/12/97 current: 0.99.0pl1, next: 0.99.0pl2
  34.  *   Added check_shutmsg function which checks for the existance
  35.  *   of the shutdown file, and returns timing information
  36.  *   about an impending shutdown.  Also added, str_interpolate,
  37.  *   to interpolate custom "%x" metas.
  38.  *
  39.  * 4/30/97 current: 0.99.0pl1, next: 0.99.0pl2
  40.  *   Fixed bug in dir_interpolate that was not 0-terminating
  41.  *   all strings.
  42.  *
  43.  * 4/24/97 current: 0.99.0pl1, next: 0.99.0pl2
  44.  *   Oops... forgot to check for empty username in dir_interpolate(),
  45.  *   so commands like "cd ~" aren't working.
  46.  *   Status: Fixed.
  47.  *
  48.  * 4/25/97 current: 0.99.0pl1, next: 0.99.0pl2
  49.  *   Added schedule() and run_schedule() to allow async routines
  50.  *   (called from an alarm or inside the _ioreq_service() to
  51.  *   schedule a function to run after the next `n' loops)
  52.  *   The function (run_schedule() is called from io.c) will
  53.  *   run at an "undetermined" later time (async), when
  54.  *   no I/O is in progress (basically, allowing the schedule
  55.  *   of a "low priority" function.  The higher the loop count
  56.  *   (via nloops), the later it will run.
  57.  */
  58. #include "conf.h"
  59. #include <signal.h>
  60. #ifdef HAVE_SYS_STATVFS_H
  61. # include <sys/statvfs.h>
  62. #elif defined(HAVE_SYS_VFS_H)
  63. # include <sys/vfs.h>
  64. #endif
  65. #ifdef AIX3
  66. #include <sys/statfs.h>
  67. #endif
  68. typedef struct _exithandler {
  69.   struct _exithandler *next,*prev;
  70.   void (*f)();
  71. } exithandler_t;
  72. typedef struct _sched {
  73.   struct _sched *next,*prev;
  74.   void (*f)(void*,void*,void*,void*);
  75.   int loops;
  76.   void *a1,*a2,*a3,*a4;
  77. } sched_t;
  78. static xaset_t *scheds = NULL;
  79. static xaset_t *exits = NULL;
  80. /* performs "hard block" of all important signals (as opposed to 
  81.  * block_alarms) */
  82. static void _block_signals(int block)
  83. {
  84.   static sigset_t sigset;
  85.   if(block) {
  86.     sigemptyset(&sigset);
  87.     sigaddset(&sigset,SIGTERM);
  88.     sigaddset(&sigset,SIGCHLD);
  89.     sigaddset(&sigset,SIGUSR1);
  90.     sigaddset(&sigset,SIGINT);
  91.     sigaddset(&sigset,SIGQUIT);
  92.     sigaddset(&sigset,SIGALRM);
  93.     sigaddset(&sigset,SIGIO);
  94. #ifdef SIGBUS
  95.     sigaddset(&sigset,SIGBUS);
  96. #endif
  97.     sigaddset(&sigset,SIGHUP);
  98.     sigprocmask(SIG_BLOCK,&sigset,NULL);
  99.   } else
  100.     sigprocmask(SIG_UNBLOCK,&sigset,NULL);
  101. }
  102. void block_signals()
  103. {
  104.   _block_signals(1);
  105. }
  106. void unblock_signals()
  107. {
  108.   _block_signals(0);
  109. }
  110. void add_exit_handler(void (*f)())
  111. {
  112.   exithandler_t *e;
  113.   if(!exits)
  114.     exits = xaset_create(permanent_pool,NULL);
  115.   e = pcalloc(permanent_pool,sizeof(exithandler_t));
  116.   e->f = f;
  117.   xaset_insert(exits,(xasetmember_t*)e);
  118. }
  119. void run_exit_handlers()
  120. {
  121.   exithandler_t *e;
  122.   if(!exits)
  123.     return;
  124.   for(e = (exithandler_t*)exits->xas_list; e; e=e->next)
  125.     e->f();
  126. }
  127. void schedule(void (*f)(void*,void*,void*,void*),int nloops,
  128.               void *a1, void *a2, void *a3, void *a4)
  129. {
  130.   pool *p;
  131.   sched_t *s;
  132.   if(!scheds) {
  133.    p = make_sub_pool(permanent_pool);
  134.    scheds = xaset_create(p,NULL);
  135.   } else
  136.    p = scheds->mempool;
  137.   s = (sched_t*)pcalloc(p,sizeof(sched_t));
  138.   s->f = f;
  139.   s->a1 = a1;
  140.   s->a2 = a2;
  141.   s->a3 = a3;
  142.   s->a4 = a4;
  143.   s->loops = nloops;
  144.   xaset_insert(scheds,(xasetmember_t*)s);
  145. }
  146. void run_schedule()
  147. {
  148.   sched_t *s,*snext;
  149.   handle_sig_alarm();
  150.   if(!scheds || !scheds->xas_list)
  151.     return;
  152.   for(s = (sched_t*)scheds->xas_list; s; s=snext) {
  153.     snext = s->next;
  154.     if(s->loops-- <= 0) {
  155.       s->f(s->a1,s->a2,s->a3,s->a4);
  156.       xaset_remove(scheds,(xasetmember_t*)s);
  157.     }
  158.   }
  159. }
  160. /* Returns TRUE if there is a scheduled function waiting */
  161. int schedulep()
  162. {
  163.   handle_sig_alarm();
  164.   return (scheds && scheds->xas_list);
  165. }
  166. /* Interpolates a pathname, expanding ~ notation if necessary
  167.  */
  168. char *dir_interpolate(pool *p, const char *path)
  169. {
  170.   struct passwd *pw;
  171.   char *user,*tmp;
  172.   char *ret = (char*)path;
  173.   if(!ret)
  174.     return NULL;
  175.   if(*ret == '~') {
  176.     user = pstrdup(p,ret+1);
  177.     tmp = index(user,'/');
  178.     if(tmp)
  179.       *tmp++ = '';
  180.     if(!*user)
  181.       user = session.user;
  182.     pw = auth_getpwnam(p,user);
  183.     if(!pw) {
  184.       errno = ENOENT;
  185.       return NULL;
  186.     }
  187.     ret = pdircat(p,pw->pw_dir,tmp,NULL);
  188.   }
  189.   return ret;
  190. }
  191. /* dir_best_path() creates the "most" fully canonicalized path possible
  192.  * (i.e. if path components at the end don't exist, they are ignored
  193.  */
  194. char *dir_best_path(pool *p, const char *path)
  195. {
  196.   char workpath[MAXPATHLEN];
  197.   char realpath[MAXPATHLEN];
  198.   char *target = NULL, *ntarget;
  199.   int fini = 0;
  200.   if(*path == '~') {
  201.     if(fs_interpolate(path,workpath,MAXPATHLEN) == -1)
  202.       fs_dircat(workpath,sizeof(workpath),fs_getcwd(),path);
  203.   } else {
  204.     fs_dircat(workpath,sizeof(workpath),fs_getcwd(),path);
  205.   }
  206.   fs_clean_path(pstrdup(p,workpath),workpath,MAXPATHLEN);
  207.   while(!fini && workpath[0]) {
  208.     if(fs_resolve_path(workpath,realpath,MAXPATHLEN,0) != -1)
  209.       break;
  210.   
  211.     ntarget = rindex(workpath,'/');
  212.     if(ntarget) {
  213.       if(target)
  214.         fs_dircat(workpath,sizeof(workpath),workpath,target);
  215.       target = ntarget;
  216.       *target++ = '';
  217.     } else
  218.       fini++;
  219.   }
  220.   if(!fini && workpath[0]) {
  221.     if(target)
  222.       fs_dircat(workpath,sizeof(workpath),realpath,target);
  223.     else
  224.       sstrncpy(workpath,realpath,sizeof(workpath));
  225.   } else
  226.     fs_dircat(workpath,sizeof(workpath),"/",target);
  227.   return pstrdup(p,workpath);
  228. }
  229. char *dir_canonical_path(pool *p, const char *path)
  230. {
  231.   char buf[MAXPATHLEN];
  232.   char work[MAXPATHLEN];
  233.   if(*path == '~') {
  234.     if(fs_interpolate(path,work,MAXPATHLEN) == -1)
  235.       fs_dircat(work, sizeof(work), fs_getcwd(), path);
  236.   } else {
  237.     fs_dircat(work, sizeof(work), fs_getcwd(), path);
  238.   }
  239.   
  240.   fs_clean_path(work, buf, MAXPATHLEN);
  241.   return pstrdup(p, buf);
  242. }
  243. /* dir_realpath() is needed to properly dereference symlinks (getcwd() may
  244.  * not work if permissions cause problems somewhere up the tree).
  245.  */
  246. char *dir_realpath(pool *p, const char *path)
  247. {
  248.   char buf[MAXPATHLEN];
  249.   if(fs_resolve_partial(path,buf,MAXPATHLEN,0) == -1)
  250.     return NULL;
  251.   return pstrdup(p,buf);
  252. }
  253. char *dir_virtual_chdir(pool *p, const char *path)
  254. {
  255.   char buf[MAXPATHLEN];
  256.   char work[MAXPATHLEN];
  257.   if(*path == '~') {
  258.     if(fs_interpolate(path,work,MAXPATHLEN) == -1)
  259.       fs_dircat(work,sizeof(work),fs_getvwd(),path);
  260.   } else
  261.     fs_dircat(work,sizeof(work),fs_getvwd(),path);
  262.   fs_clean_path(work,buf,MAXPATHLEN);
  263.   return pstrdup(p,buf);
  264. }
  265. /* Takes a directory and returns it's absolute version.  ~username
  266.  * references are appropriately interpolated.  "Absolute" includes
  267.  * a *full* reference based on the root directory, not upon a chrooted
  268.  * dir.
  269.  */
  270. char *dir_abs_path(pool *p, const char *path, int interpolate)
  271. {
  272.   char *res = NULL;
  273.   if(interpolate)
  274.     path = dir_interpolate(p,path);
  275.   
  276.   if(!path)
  277.     return NULL;  
  278.     
  279.   if(*path != '/') {
  280.     if(session.anon_root)
  281.       res = pdircat(p,session.anon_root,fs_getcwd(),path,NULL);
  282.     else
  283.       res = pdircat(p,fs_getcwd(),path,NULL);
  284.   } else if(session.anon_root)
  285.     res = pdircat(p,session.anon_root,path,NULL);
  286.   else
  287.     res = pstrdup(p,path);
  288.   return res;
  289. }
  290. static mode_t _symlink(char *path, ino_t last_inode, int rcount)
  291. {
  292.   char buf[255];
  293.   struct stat sbuf;
  294.   if(++rcount >= 32) {
  295.     errno = ELOOP;
  296.     return 0;
  297.   }
  298.   bzero(buf,sizeof(buf));
  299.   if(fs_readlink(path,buf,sizeof(buf)) == -1)
  300.     return (mode_t)0;
  301.   if(fs_lstat(buf,&sbuf) != -1) {
  302.     if(sbuf.st_ino && (ino_t)sbuf.st_ino == last_inode) {
  303.       errno = ELOOP;
  304.       return 0;
  305.     }
  306.     if(S_ISLNK(sbuf.st_mode))
  307.       return _symlink(buf,(ino_t)sbuf.st_ino,rcount);
  308.     return sbuf.st_mode;
  309.   }
  310.   return 0;
  311. }
  312. mode_t file_mode(char *path)
  313. {
  314.   struct stat sbuf;
  315.   mode_t res = 0;
  316.   if(fs_stat(path,&sbuf) != -1) {
  317.     if(S_ISLNK(sbuf.st_mode))
  318.       res = _symlink(path,(ino_t)0,0);
  319.     else
  320.       res = sbuf.st_mode;
  321.   }
  322.   return res;
  323. }
  324. /* dirp == -1, don't care if file or directory */
  325. static int _exists(char *path, int dirp)
  326. {
  327.   mode_t fmode;
  328.   if((fmode = file_mode(path)) != 0) {
  329.     if(dirp == 1 && !S_ISDIR(fmode))
  330.       return FALSE;
  331.     else if(dirp == 0 && S_ISDIR(fmode))
  332.       return FALSE;
  333.     return TRUE;
  334.   }
  335.   return FALSE;
  336. }
  337. int file_exists(char *path)
  338. {
  339.   return _exists(path,0);
  340. }
  341. int dir_exists(char *path)
  342. {
  343.   return _exists(path,1);
  344. }
  345. int exists(char *path)
  346. {
  347.   return _exists(path,-1);
  348. }
  349. char *strip_end(char *s, char *ch)
  350. {
  351.   int i = strlen(s);
  352.   while(i && strchr(ch,*(s+i-1))) {
  353.     *(s+i-1) = '';
  354.     i--;
  355.   }
  356.   return s;
  357. }
  358. /* get_token tokenizes a string, increments the src pointer to
  359.  * the next non-separator in the string.  If the src string is
  360.  * empty or NULL, the next token returned is NULL.
  361.  */
  362. char *get_token(char **s, char *sep)
  363. {
  364.   char *res;
  365.   if(!s || !*s || !**s)
  366.     return NULL;
  367.   res = *s;
  368.   while(**s && !strchr(sep,**s)) (*s)++;
  369.   if(**s) {
  370.     *(*s)++ = '';
  371.   }
  372.   return res;
  373. }
  374. /* safe_token tokenizes a string, and increments the pointer to
  375.  * the next non-white space character.  It's "safe" because it
  376.  * never returns NULL, only an empty string if no token remains
  377.  * in the source string.
  378.  */
  379. char *safe_token(char **s)
  380. {
  381.   char *res = "";
  382.   if(!s || !*s)
  383.     return res;
  384.   while(isspace((UCHAR)**s) && **s) (*s)++;
  385.   if(**s) {
  386.     res = *s;
  387.     while(!isspace((UCHAR)**s) && **s) (*s)++;
  388.     if(**s)
  389.       *(*s)++ = '';
  390.     while(isspace((UCHAR)**s) && **s) (*s)++;
  391.   }
  392.   return res;
  393. }
  394. /* Checks for the existance of SHUTMSG_PATH.  deny and disc are
  395.  * filled with the times to deny new connections and disconnect
  396.  * existing ones.
  397.  */
  398. int check_shutmsg(time_t *shut, time_t *deny, time_t *disc, char *msg, 
  399.                   size_t msg_size)
  400. {
  401.   FILE *fp;
  402.   char *deny_str,*disc_str,*cp,buf[1025];
  403.   char hr[3],mn[3];
  404.   time_t now,shuttime = (time_t)0;
  405.   struct tm tm;
  406.   if(file_exists(SHUTMSG_PATH) && (fp = fopen(SHUTMSG_PATH,"r"))) {
  407.     if((cp = fgets(buf,sizeof(buf),fp)) != NULL) {
  408.       buf[1024] = ''; CHOP(cp);
  409.       /* We use this to fill in dst, timezone, etc */
  410.       time(&now);
  411.       tm = *(localtime(&now));
  412.       tm.tm_year = atoi(safe_token(&cp)) % 100;
  413.       tm.tm_mon = atoi(safe_token(&cp));
  414.       tm.tm_mday = atoi(safe_token(&cp));
  415.       tm.tm_hour = atoi(safe_token(&cp));
  416.       tm.tm_min = atoi(safe_token(&cp));
  417.       tm.tm_sec = atoi(safe_token(&cp));
  418.       deny_str = safe_token(&cp);
  419.       disc_str = safe_token(&cp);
  420.       if((shuttime = mktime(&tm)) == (time_t)-1) {
  421.         fclose(fp);
  422.         return 0;
  423.       }
  424.       if(deny) {
  425.         if(strlen(deny_str) == 4) {
  426.           sstrncpy(hr,deny_str,sizeof(hr)); hr[2] = ''; deny_str += 2;
  427.           sstrncpy(mn,deny_str,sizeof(mn)); mn[2] = '';
  428.           
  429.           *deny = shuttime - ((atoi(hr) * 3600) + (atoi(mn) * 60));
  430.         } else
  431.           *deny = shuttime;
  432.       }
  433.       if(disc) {
  434.         if(strlen(disc_str) == 4) {
  435.           sstrncpy(hr,disc_str,sizeof(hr)); hr[2] = ''; disc_str += 2;
  436.           sstrncpy(mn,disc_str,sizeof(mn)); mn[2] = '';
  437.           *disc = shuttime - ((atoi(hr) * 3600) + (atoi(mn) * 60));
  438.         } else
  439.           *disc = shuttime;
  440.       }
  441.       if(fgets(buf,sizeof(buf),fp) && msg) {
  442.         buf[255] = '';
  443. CHOP(buf);
  444.         sstrncpy(msg,buf,msg_size-1);
  445.       }
  446.     }
  447.     fclose(fp);
  448.     if(shut)
  449.       *shut = shuttime;
  450.     return 1;
  451.   }
  452.   return 0;
  453. }
  454. char *make_arg_str(pool *p,int argc,char **argv)
  455. {
  456.   char *res = "";
  457.   while(argc--)
  458.     if(*res)
  459.       res = pstrcat(p,res," ",*argv++,NULL);
  460.     else
  461.       res = pstrcat(p,res,*argv++,NULL);
  462.   return res;
  463. }
  464. char *sreplace(pool *p, char *s, ...)
  465. {
  466.   va_list args;
  467.   char *m,*r,*src = s,*cp;
  468.   char **mptr,**rptr;
  469.   char *marr[33],*rarr[33];
  470.   char buf[2048];
  471.   int mlen = 0,rlen = 0;
  472.   cp = buf;
  473.   *cp = '';
  474.   
  475.   bzero(marr,sizeof(marr));
  476.   va_start(args,s);
  477.   while((m = va_arg(args,char*)) != NULL && mlen < 32) {
  478.     if((r = va_arg(args,char*)) == NULL)
  479.       break;
  480.     marr[mlen] = m;
  481.     rarr[mlen++] = r;
  482.   }
  483.   va_end(args);
  484.   while(*src) {
  485.     for(mptr = marr, rptr = rarr; *mptr; mptr++, rptr++) {
  486.       mlen = strlen(*mptr);
  487.       rlen = strlen(*rptr);
  488.       if(strncmp(src,*mptr,mlen) == 0) {
  489.         sstrncpy(cp,*rptr,sizeof(buf) - strlen(buf));
  490. if(((cp + rlen) - buf + 1) > sizeof(buf)) {
  491.   log_pri(LOG_ERR,
  492.   "Warning, attempt to overflow internal ProFTPD buffers.");
  493.   cp = buf + sizeof(buf) - 1;
  494.   goto done;
  495. } else {
  496.   cp += rlen;
  497. }
  498.         src += mlen;
  499.         break;
  500.       }
  501.     }
  502.     
  503.     if(!*mptr) {
  504.       if((cp - buf + 1) > sizeof(buf)) {
  505. log_pri(LOG_ERR,
  506. "Warning, attempt to overflow internal ProFTPD buffers.");
  507. cp = buf + sizeof(buf) - 1;
  508.       }
  509.       *cp++ = *src++;
  510.     }
  511.   }
  512.   
  513.  done:
  514.   *cp = '';
  515.   return pstrdup(p,buf);
  516. }
  517. /* Simple multiplication & division doesn't work with very large
  518.  * filesystems (overflows 32 bits).  This code should handle it.
  519.  */
  520. static
  521. unsigned long _calc_fs(unsigned long blocks, unsigned long bsize)
  522. {
  523.   unsigned long bl_lo,bl_hi;
  524.   unsigned long res_lo,res_hi,tmp;
  525.   bl_lo = blocks & 0x0000ffff;
  526.   bl_hi = blocks & 0xffff0000;
  527.   tmp = (bl_hi >> 16) * bsize;
  528.   res_hi = tmp & 0xffff0000;
  529.   res_lo = (tmp & 0x0000ffff) << 16;
  530.   res_lo += bl_lo * bsize;
  531.   if(res_hi & 0xfc000000) /* overflow */
  532. return 0;
  533.   return (res_lo >> 10) | (res_hi << 6);
  534. }
  535. #ifdef HAVE_SYS_STATVFS_H
  536. unsigned long get_fs_size(char *s)
  537. {
  538.   struct statvfs vfs;
  539.   if(statvfs(s,&vfs) != 0)
  540.     return 0;
  541.   return _calc_fs(vfs.f_bavail,vfs.f_bsize);
  542. }
  543. #elif defined(HAVE_SYS_VFS_H)
  544. unsigned long get_fs_size(char *s)
  545. {
  546.   struct statfs vfs;
  547.   if(statfs(s,&vfs) != 0)
  548.     return 0;
  549.   return _calc_fs(vfs.f_bavail,vfs.f_bsize);
  550. }
  551. #endif /* HAVE_SYS_STATVFS/HAVE_SYS_VFS */
  552. /* "safe" strcat, saves room for  at end of dest, and refuses to copy
  553.  * more than "n" bytes.
  554.  */
  555. char *sstrcat(char *dest, const char *src, size_t n) {
  556.   register char *d;
  557.   
  558.   for(d = dest; *d && n > 1; d++, n--) ;
  559.   
  560.   while(n-- > 1 && *src)
  561.     *d++ = *src++;
  562.   
  563.   *d = 0;
  564.   return dest;
  565. }
  566. /* "safe" strncpy, saves room for  at end of dest, and refuses to copy
  567.  * more than "n" bytes.
  568.  */
  569. char *sstrncpy(char *dest, const char *src, size_t n) {
  570.   register char *d;
  571.   
  572.   if(!dest || !src)
  573.     return NULL;
  574.   
  575.   for(d = dest; *src && n > 1; n--)
  576.     *d++ = *src++;
  577.   
  578.   *d = 0;
  579.   
  580.   return dest;
  581. }