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

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. /*
  20.  * "SITE" commands module for ProFTPD
  21.  * $Id: mod_site.c,v 1.2 1999/09/07 23:09:10 macgyver Exp $
  22.  */
  23. #include "conf.h"
  24. #ifdef HAVE_REGEX_H
  25. #include <regex.h>
  26. #endif
  27. /* From mod_core.c */
  28. extern int core_chmod(cmd_rec *cmd, char *dir, mode_t mode);
  29. static struct {
  30.   char *cmd;
  31.   char *syntax;
  32.   int implemented;
  33. } _help[] = {
  34.   { "HELP", "[<sp> site-command]", TRUE },
  35.   { "CHMOD", "<sp> mode <sp> pathname", TRUE },
  36.   { NULL, NULL, FALSE }
  37. };
  38. static char *_get_full_cmd(cmd_rec *cmd)
  39. {
  40.   char *res = "";
  41.   int i;
  42.   for(i = 0; i < cmd->argc; i++)
  43.     res = pstrcat(cmd->tmp_pool,res,cmd->argv[i]," ",NULL);
  44.   while(res[strlen(res)-1] == ' ')
  45.     res[strlen(res)-1] = '';
  46.   return res;
  47. }
  48. MODRET site_chmod(cmd_rec *cmd)
  49. {
  50.   mode_t mode = 0;
  51.   char *dir,*endp,*tmp;
  52. #if defined(HAVE_REGEX_H) && defined(HAVE_REGCOMP)
  53.   regex_t *preg;
  54. #endif
  55.   if(cmd->argc != 3) {
  56.     add_response_err(R_500,"'SITE %s' not understood.",_get_full_cmd(cmd));
  57.     return NULL;
  58.   }
  59. #if defined(HAVE_REGEX_H) && defined(HAVE_REGCOMP)
  60.   preg = (regex_t*)get_param_ptr(TOPLEVEL_CONF,"PathAllowFilter",FALSE);
  61.   if(preg && regexec(preg,cmd->argv[2],0,NULL,0) != 0) {
  62.     add_response_err(R_550,"%s: Forbidden filename",cmd->argv[2]);
  63.     return ERROR(cmd);
  64.   }
  65.   preg = (regex_t*)get_param_ptr(TOPLEVEL_CONF,"PathDenyFilter",FALSE);
  66.   if(preg && regexec(preg,cmd->argv[2],0,NULL,0) == 0) {
  67.     add_response_err(R_550,"%s: Forbidden filename",cmd->argv[2]);
  68.     return ERROR(cmd);
  69.   }
  70. #endif
  71.   dir = dir_realpath(cmd->tmp_pool,cmd->argv[2]);
  72.   if(!dir) {
  73.     add_response_err(R_550,"%s: %s",cmd->argv[2],strerror(errno));
  74.     return ERROR(cmd);
  75.   }
  76.   /* If the first character isn't '0', prepend it and attempt conversion.
  77.    * This will fail if the chmod is a symbolic, but takes care of the
  78.    * case where an octal number is sent without the leading '0'.
  79.    */
  80.   if(cmd->argv[1][0] != '0')
  81.     tmp = pstrcat(cmd->tmp_pool,"0",cmd->argv[1],NULL);
  82.   else
  83.     tmp = cmd->argv[1];
  84.   mode = strtol(tmp,&endp,0);
  85.   if(endp && *endp) {
  86.     /* It's not an absolute number, try symbolic */
  87.     char *cp = cmd->argv[1];
  88.     int mask = 0,mode_op = 0,curmode = 0,curumask = umask(0);
  89.     int invalid = 0; 
  90.     char *who,*how,*what,*tmp;
  91.     struct stat sbuf;
  92.     umask(curumask);
  93.     mode = 0; 
  94.     if(stat(dir,&sbuf) != -1)
  95.       curmode = sbuf.st_mode;
  96.     while(1) {
  97.       who = pstrdup(cmd->tmp_pool,cp);
  98.       if((tmp = strpbrk(who,"+-=")) != NULL) {
  99.         how = pstrdup(cmd->tmp_pool,tmp);
  100.         if(*how != '=')
  101.           mode = curmode;
  102.         *tmp = '';
  103.       } else {
  104.         invalid++;
  105.         break;
  106.       }
  107.       if((tmp = strpbrk(how,"rwxXstugo")) != NULL) {
  108.         what = pstrdup(cmd->tmp_pool,tmp);
  109.         *tmp = '';
  110.       } else {
  111.         invalid++;
  112.         break;
  113.       }
  114.       cp = what;
  115.       while(cp) {
  116.         switch(*who) {
  117.         case 'u':
  118.           mask = 0077;
  119.           break;
  120.         case 'g':
  121.           mask = 0707;
  122.           break;
  123.         case 'o':
  124.           mask = 0770;
  125.           break;
  126.         case 'a':
  127.           mask = 0000;
  128.           break;
  129.         case '':
  130.           mask = curumask;
  131.           break;
  132.         default:
  133.           invalid++;
  134.           break;
  135.         }
  136.         if(invalid) break;
  137.         switch(*how) {
  138.         case '+':
  139.         case '-':
  140.         case '=':
  141.           break;
  142.         default:
  143.           invalid++;
  144.         }
  145.         if(invalid) break;
  146.         switch(*cp) {
  147.         case 'r':
  148.           mode_op |= (S_IRUSR|S_IRGRP|S_IROTH);
  149.           break;
  150.         case 'w':
  151.           mode_op |= (S_IWUSR|S_IWGRP|S_IWOTH);
  152.           break;
  153.         case 'x':
  154.           mode_op |= (S_IXUSR|S_IXGRP|S_IXOTH);
  155.           break;
  156.         /* 'X' not implemented */
  157.         case 's':
  158.   /* setuid */
  159.           mode_op |= S_ISUID;
  160.           break;
  161.         case 't':
  162.           /* sticky */
  163.           mode_op |= S_ISVTX;
  164.           break;
  165.         case 'o':
  166.           mode_op |= curmode & S_IRWXO;
  167.           mode_op |= (curmode & S_IRWXO) << 3;
  168.           mode_op |= (curmode & S_IRWXO) << 6;
  169.           break;
  170.         case 'g':
  171.           mode_op |= (curmode & S_IRWXG) >> 3;
  172.           mode_op |= curmode & S_IRWXG;
  173.           mode_op |= (curmode & S_IRWXG) << 3;
  174.           break;
  175.         case 'u':
  176.           mode_op |= (curmode & S_IRWXO) >> 6;
  177.           mode_op |= (curmode & S_IRWXO) >> 3;
  178.           mode_op |= curmode & S_IRWXU;
  179.           break;
  180.         case '':
  181.           /* Apply the mode and move on */
  182.           switch(*how) {
  183.           case '+':
  184.           case '=':
  185.             mode |= (mode_op & ~mask);
  186.             break;
  187.           case '-':
  188.             mode &= ~(mode_op & ~mask);
  189.             break;
  190.           }
  191.           mode_op = 0;
  192.           if(*who && *(who+1)) {
  193.             who++;
  194.             cp = what;
  195.             continue;
  196.           } else
  197.             cp = NULL;
  198.           break;
  199.         default:
  200.           invalid++;
  201.         }
  202.         if(invalid) break;
  203.         if(cp) cp++;
  204.       }
  205.       break;
  206.     }
  207.     if(invalid) {
  208.       add_response_err(R_550,"'%s': invalid mode.",cmd->argv[1]);
  209.       return ERROR(cmd);
  210.     }
  211.   }
  212.   if(core_chmod(cmd,dir,mode) == -1) {
  213.     add_response_err(R_550,"%s: %s",cmd->argv[2],strerror(errno));
  214.     return ERROR(cmd);
  215.   } else
  216.     add_response(R_200,"SITE %s command successful.",cmd->argv[0]);
  217.   return HANDLED(cmd);
  218. }
  219. MODRET site_help(cmd_rec *cmd)
  220. {
  221.   int i,c = 0;
  222.   char buf[9];
  223.   if(cmd->argc == 1 || (cmd->argc == 2 && !strcasecmp(cmd->argv[1],"SITE"))) {
  224.     char *outa[8];
  225.     char *outs = "";
  226.     bzero(outa,sizeof(outa));
  227.     add_response(R_214,
  228.     "The following SITE commands are recognized (* =>'s unimplemented).");
  229.     for(i = 0; _help[i].cmd; i++) {
  230.       if(_help[i].implemented)
  231.         outa[c++] = _help[i].cmd;
  232.       else
  233.         outa[c++] = pstrcat(cmd->tmp_pool,_help[i].cmd,"*",NULL);
  234.       /* 8 rows */
  235.       if(((i+1) % 8 == 0) || !_help[i+1].cmd) {
  236.         int j;
  237.         for(j = 0; j < 8; j++) {
  238.           if(outa[j]) {
  239.             snprintf(buf, sizeof(buf), "%-8s",outa[j]);
  240.             outs = pstrcat(cmd->tmp_pool,outs,buf,NULL);
  241.           } else
  242.             break;
  243.         }
  244.         if(*outs)
  245.           add_response(R_214,"%s",outs);
  246.         outs = "";
  247.         c = 0;
  248.         bzero(outa,sizeof(outa));
  249.       }
  250.     }
  251.     add_response(R_214,"Direct comments to %s.",
  252.                          (cmd->server->ServerAdmin ? cmd->server->ServerAdmin :
  253.                           "ftp-admin"));
  254.   } else {
  255.     char *cp;
  256.     for(cp = cmd->argv[1]; *cp; cp++)
  257.       *cp = toupper(*cp);
  258.     for(i = 0; _help[i].cmd; i++)
  259.       if(!strcasecmp(cmd->argv[1],_help[i].cmd)) {
  260.         add_response(R_214,"Syntax: SITE %s %s",cmd->argv[1],
  261.                             _help[i].syntax);
  262.         return HANDLED(cmd);
  263.       }
  264.     add_response_err(R_502,"Unknown command 'SITE %s'.",cmd->argv[2]);
  265.     return ERROR(cmd);
  266.   }
  267.   return HANDLED(cmd);
  268. }
  269. /* The site_commands table is local only, and not registered with our
  270.  * module.
  271.  */
  272. cmdtable site_commands[] = {
  273.   { CMD, "HELP", G_NONE, site_help, FALSE, FALSE },
  274.   { CMD, "CHMOD", G_NONE, site_chmod, FALSE, FALSE },
  275.   { 0, NULL }
  276. };
  277. modret_t *site_dispatch(cmd_rec *cmd)
  278. {
  279.   int i;
  280.   if (!cmd->argc) {
  281.     add_response_err(R_500,"'SITE' requires argument.");
  282.     return ERROR(cmd);
  283.   }
  284.   for(i = 0; site_commands[i].command; i++)
  285.     if(!strcmp(cmd->argv[0],site_commands[i].command))
  286.       return site_commands[i].handler(cmd);
  287.   add_response_err(R_500,"'SITE %s' not understood.",cmd->argv[0]);
  288.   return ERROR(cmd);
  289. }
  290. /* Module interface */
  291. module site_module = {
  292.   NULL,NULL, /* Always NULL */
  293.   0x20, /* API Version 1.0 */
  294.   "site",
  295.   NULL, /* No configuration table */
  296.   NULL, /* Our command table is for local use only */
  297.   NULL,
  298.   NULL,NULL /* No initialization needed */
  299. };