⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mod_wrap2.c

📁 ProFTPd 是一款基于GPL协议的可配置的FTP服务器
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * ProFTPD: mod_wrap2 -- tcpwrappers-like access control * * Copyright (c) 2000-2007 TJ Saunders * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA. * * As a special exemption, TJ Saunders gives permission to link this program * with OpenSSL, and distribute the resulting executable, without including * the source code for OpenSSL in the source distribution. */#include "mod_wrap2.h"typedef struct regtab_obj {  struct regtab_obj *next;  /* Table source type name */  const char *regtab_name;  /* Initialization function for this type of table source */  wrap2_table_t *(*regtab_open)(pool *, char *);} wrap2_regtab_t;module wrap2_module;/* Wrap tables for the current session */static char *wrap2_allow_table = NULL;static char *wrap2_deny_table = NULL;/* Memory pool for this module */static pool *wrap2_pool = NULL;/* List of registered quotatab sources */static wrap2_regtab_t *wrap2_regtab_list = NULL;/* Logging data */static int wrap2_logfd = -1;static char *wrap2_logname = NULL;static unsigned char wrap2_engine = FALSE;static char *wrap2_service_name = WRAP2_DEFAULT_SERVICE_NAME;static char *wrap2_client_name = NULL;static config_rec *wrap2_ctxt = NULL;/* Access check variables */#define WRAP2_UNKNOWN	"unknown"#define WRAP2_PARANOID	"paranoid"#define WRAP2_IS_KNOWN_HOSTNAME(s) \  (strcasecmp((s), WRAP2_UNKNOWN) != 0 && strcasecmp((s), WRAP2_PARANOID))#define WRAP2_IS_NOT_INADDR(s) \  (s[strspn(s,"01234567890./")] != 0)#define WRAP2_GET_DAEMON(r) \  ((r)->daemon)/* Data structures */typedef struct host_info {  char name[WRAP2_BUFFER_SIZE];  char addr[WRAP2_BUFFER_SIZE];  struct sockaddr_in *sin;            /* socket address or 0 */  struct t_unitdata *unit;            /* TLI transport address or 0 */  struct conn_info *connection;       /* for shared information */} wrap2_host_t;typedef struct conn_info {  int sock_fd;                         /* socket handle */  char user[WRAP2_BUFFER_SIZE];        /* access via eval_user(request) */  char daemon[WRAP2_BUFFER_SIZE];      /* access via eval_daemon(request) */  struct host_info client[1];         /* client endpoint info */  struct host_info server[1];         /* server endpoint info */  void  (*sink) (int);                /* datagram sink function or 0 */  void  (*hostname) (struct host_info *); /* address to printable hostname */  void  (*hostaddr) (struct host_info *); /* address to printable address */  void  (*cleanup) (struct conn_info *);   /* cleanup function or 0 */  struct netconfig *config;           /* netdir handle */} wrap2_conn_t;#define WRAP2_CONN_SOCK_FD	1	/* socket descriptor */#define WRAP2_CONN_DAEMON	2	/* server process (argv[0]) */#ifndef INADDR_NONE#define INADDR_NONE 0xffffffff#endif/* Logging routines */static int wrap2_closelog(void) {  if (wrap2_logfd != -1) {    close(wrap2_logfd);    wrap2_logfd = -1;    wrap2_logname = NULL;  }  return 0;}int wrap2_log(const char *fmt, ...) {  char buf[PR_TUNABLE_BUFFER_SIZE] = {'\0'};  time_t timestamp = time(NULL);  struct tm *t = NULL;  va_list msg;  if (!wrap2_logname)    return 0;  t = pr_localtime(NULL, &timestamp);  /* Prepend the timestamp. */  strftime(buf, sizeof(buf), "%b %d %H:%M:%S ", t);  buf[sizeof(buf) - 1] = '\0';  /* Prepend a small header */  snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),           MOD_WRAP2_VERSION "[%u]: ", (unsigned int) getpid());  buf[sizeof(buf) - 1] = '\0';  /* Affix the message. */  va_start(msg, fmt);  vsnprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), fmt, msg);  va_end(msg);  buf[strlen(buf)] = '\n';  buf[sizeof(buf) - 1] = '\0';  while (write(wrap2_logfd, buf, strlen(buf)) < 0) {    if (errno == EINTR) {      pr_signals_handle();      continue;    }    return -1;  }  return 0;}static int wrap2_openlog(void) {  int res = 0;  /* Sanity check */  wrap2_logname = get_param_ptr(main_server->conf, "WrapLog", FALSE);  if (wrap2_logname == NULL)    return 0;  /* Check for "none" */  if (strcasecmp(wrap2_logname, "none") == 0) {    wrap2_logname = NULL;    return 0;  }  pr_signals_block();  PRIVS_ROOT  res = pr_log_openfile(wrap2_logname, &wrap2_logfd, 0640);  PRIVS_RELINQUISH  pr_signals_unblock();  return res;}/* Table routines */static int wrap2_close_table(wrap2_table_t *tab) {  return tab->tab_close(tab);}static wrap2_table_t *wrap2_open_table(char *name) {  char *info = NULL;  unsigned char have_type = FALSE;  register wrap2_regtab_t *regtab = NULL;  wrap2_table_t *tab = NULL;  info = strchr(name, ':');  *info++ = '\0';  /* Look up the table source open routine by name, and invoke it */  for (regtab = wrap2_regtab_list; regtab; regtab = regtab->next) {    if (strcmp(regtab->regtab_name, name) == 0) {      tab = regtab->regtab_open(wrap2_pool, info);      if (tab == NULL)        return NULL;      have_type = TRUE;      break;    }  }  if (!have_type) {    wrap2_log("unsupported table source: '%s'", name);    errno = EINVAL;    return NULL;  }  return tab;}/* Information structure routines */static wrap2_conn_t *wrap2_conn_update(wrap2_conn_t *conn, va_list ap) {  int key = 0;  char *val = NULL;  while ((key = va_arg(ap, int)) > 0) {    switch (key) {      default:        wrap2_log("invalid key: %d", key);        return conn;      case WRAP2_CONN_SOCK_FD:        conn->sock_fd = va_arg(ap, int);        continue;#if 0      case WRAP2_CONN_CLIENT_SIN:        conn->client->sin = va_arg(ap, struct sockaddr_in *);        continue;      case WRAP2_CONN_SERVER_SIN:        conn->server->sin = va_arg(ap, struct sockaddr_in *);        continue;#endif      case WRAP2_CONN_DAEMON:        val = conn->daemon;        break;#if 0      case WRAP2_CONN_USER:        val = conn->user;        break;      case WRAP2_CONN_CLIENT_NAME:        val = conn->client->name;        break;      case WRAP2_CONN_CLIENT_ADDR:        val = conn->client->addr;        break;      case WRAP2_CONN_SERVER_NAME:        val = conn->server->name;        break;      case WRAP2_CONN_SERVER_ADDR:        val = conn->server->addr;        break;#endif    }    /* Copy in the string */    sstrncpy(val, va_arg(ap, char *), WRAP2_BUFFER_SIZE);  }  return conn;}static wrap2_conn_t *wrap2_conn_set(wrap2_conn_t *conn, ...) {  static wrap2_conn_t default_conn;  wrap2_conn_t *c = NULL;  va_list ap;  /* Initialize the data members.  We do not assign default callbacks,   * to avoid pulling in the whole socket module when it is not really   * needed.   */  va_start(ap, conn);  *conn = default_conn;  conn->sock_fd = -1;  sstrncpy(conn->daemon, WRAP2_UNKNOWN, sizeof(conn->daemon));  conn->client->connection = conn;  conn->server->connection = conn;  c = wrap2_conn_update(conn, ap);  va_end(ap);  return c;}static char *wrap2_get_user(wrap2_conn_t *conn) {  if (*conn->user == '\0') {    /* RFC931 lookups may have already been done by the daemon.  Check     * to see what session.ident_lookups is.  If TRUE, use the RFC931 name     * in session.ident_user.  Otherwise, use the user name issued by the     * client, C_USER.     */    if (session.ident_lookups) {      sstrncpy(conn->user, session.ident_user, sizeof(conn->user));    } else {      char *user = get_param_ptr(main_server->conf, C_USER, FALSE);      sstrncpy(conn->user, user, sizeof(conn->user));    }  }  return conn->user;}static char *wrap2_get_hostaddr(wrap2_host_t *host) {  if (*host->addr == '\0')    sstrncpy(host->addr, pr_netaddr_get_ipstr(session.c->remote_addr),      sizeof(host->addr));  return host->addr;}static char *wrap2_get_hostname(wrap2_host_t *host) {  if (*host->name == '\0')    sstrncpy(host->name, session.c->remote_name, sizeof(host->name));  return host->name;}static char *wrap2_get_hostinfo(wrap2_host_t *host) {  char *hostname = wrap2_get_hostname(host);  if (WRAP2_IS_KNOWN_HOSTNAME(hostname))    return host->name;  return wrap2_get_hostaddr(host);}static char *wrap2_get_client(wrap2_conn_t *conn) {  static char both[WRAP2_BUFFER_SIZE] = {'\0'};  char *hostinfo = wrap2_get_hostinfo(conn->client);  if (strcasecmp(wrap2_get_user(conn), WRAP2_UNKNOWN) != 0) {    snprintf(both, sizeof(both), "%s@%s", conn->user, hostinfo);    both[sizeof(both)-1] = '\0';    return both;  }  return hostinfo;}/* Access checking routines */char *wrap2_strsplit(char *str, int delim) {  char *tmp = NULL;  tmp = strchr(str, delim);  if (tmp != NULL)    *tmp++ = '\0';  return tmp;}static char *wrap2_skip_whitespace(char *str) {  register unsigned int i;  char *tmp;  /* Skip any leading whitespace. */  tmp = str;  for (i = 0; str[i]; i++) {    if (isspace((int) str[i])) {      tmp = &str[i+1];      continue;    }    break;  }  return tmp;}static unsigned char wrap2_match_string(const char *tok, const char *str) {  size_t len = 0;  if (tok[0] == '.') {    /* Suffix */    len = strlen(str) - strlen(tok);    return (len > 0 && (strcasecmp(tok, str + len) == 0));  } else if (strcasecmp(tok, "ALL") == 0) {    /* ALL: match any */    return TRUE;  } else if (strcasecmp(tok, "KNOWN") == 0) {    /* Not unknown */    return (strcasecmp(str, WRAP2_UNKNOWN) != 0);  } else if (tok[(len = strlen(tok)) - 1] == '.') {    /* Prefix */    return (strncasecmp(tok, str, len) == 0);  } else {    /* Exact match */    return (strcasecmp(tok, str) == 0);  }  return FALSE;}static unsigned long wrap2_addr_a2n(const char *str) {  unsigned char within_run = FALSE;  unsigned int nruns = 0;  const char *cp = str;  /* Count the number of runs of non-dot characters. */  while (*cp) {    if (*cp == '.') {      within_run = FALSE;    } else if (within_run == FALSE) {      within_run = TRUE;      nruns++;    }    cp++;  }  return (nruns == 4 ? inet_addr(str) : INADDR_NONE);}static unsigned char wrap2_match_netmask(const char *net_tok,    const char *mask_tok, const char *str) {  unsigned long net = 0UL;  unsigned long mask = 0UL;  unsigned long addr = 0UL;  /* Disallow forms other than dotted quad: the treatment that inet_addr()   * gives to forms with less than four components is inconsistent with the   * access control language. John P. Rouillard <rouilj@cs.umb.edu>.   */  if ((addr = wrap2_addr_a2n(str)) == INADDR_NONE)    return FALSE;  if ((net = wrap2_addr_a2n(net_tok)) == INADDR_NONE ||      (mask = wrap2_addr_a2n(mask_tok)) == INADDR_NONE) {    wrap2_log("warning: bad net/mask expression: '%s/%s'", net_tok, mask_tok);    return FALSE;  }  return ((addr & mask) == net);}static unsigned char wrap2_match_host(char *tok, wrap2_host_t *host) {  char *mask = NULL;  tok = wrap2_skip_whitespace(tok);  /* This code looks a little hairy because we want to avoid unnecessary   * hostname lookups.   *   * The KNOWN pattern requires that both address AND name be known; some   * patterns are specific to host names or to host addresses; all other   * patterns are satisfied when either the address OR the name match.   */  if (tok[0] == '@') {#ifdef WRAP2_USE_NIS    /* netgroup: look it up. */    static char *mydomain = NULL;    if (mydomain == NULL)      yp_get_default_domain(&mydomain);    return (innetgr(tok + 1, wrap2_get_hostname(host), NULL, mydomain));#else    wrap2_log("warning: '%s': NIS support is not enabled", tok);    return FALSE;#endif  } else if (strcasecmp(tok, "KNOWN") == 0) {    /* Check address and name. */    char *name = wrap2_get_hostname(host);    return ((strcasecmp(wrap2_get_hostaddr(host), WRAP2_UNKNOWN) != 0) &&      WRAP2_IS_KNOWN_HOSTNAME(name));  } else if (strcasecmp(tok, "LOCAL") == 0) {    /* Local: no dots in name. */    char *name = wrap2_get_hostname(host);    return (strchr(name, '.') == NULL && WRAP2_IS_KNOWN_HOSTNAME(name));#ifdef PR_USE_IPV6   } else if (pr_netaddr_use_ipv6() &&             *tok == '[') {    char *cp, *tmp;    pr_netaddr_t *acl_addr;    unsigned int nmaskbits;    /* IPv6 address */    if (pr_netaddr_get_family(session.c->remote_addr) == AF_INET)      /* No need to try to match an IPv6 address against an IPv4 client. */      return FALSE;    /* Find the terminating ']'. */    cp = strchr(tok, ']');    if (cp)      *cp = '\0';    /* Lookup a netaddr for the IPv6 address. */    acl_addr = pr_netaddr_get_addr(wrap2_pool, tok, NULL);    if (!acl_addr) {      wrap2_log("unable to resolve IPv6 address '%s'", tok);      return FALSE;    }    /* Determine the number of mask bits. */    nmaskbits = strtol(cp + 1, &tmp, 10);    if (tmp && *tmp) {      wrap2_log("bad mask syntax: '%s'", tmp);      return FALSE;    }    return (pr_netaddr_ncmp(session.c->remote_addr, acl_addr, nmaskbits) == 0);#endif /* PR_USE_IPV6 */  } else if ((mask = wrap2_strsplit(tok, '/')) != 0) {    /* Net/mask */    return (wrap2_match_netmask(tok, mask, wrap2_get_hostaddr(host)));  } else {    /* Anything else */    return (wrap2_match_string(tok, wrap2_get_hostaddr(host)) ||      (WRAP2_IS_NOT_INADDR(tok) &&       wrap2_match_string(tok, wrap2_get_hostname(host))));  }  return FALSE;}static unsigned char wrap2_match_client(char *tok, wrap2_conn_t *conn) {  unsigned char match = FALSE;  char *host = NULL;  host = wrap2_strsplit(tok + 1, '@');  if (host == 0) {    /* Plain host */    match = wrap2_match_host(tok, conn->client);    if (match)      wrap2_log("client matches '%s'", tok);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -