Beispiel #1
0
uschar *
string_copy_malloc(const uschar *s)
{
    int len = Ustrlen(s) + 1;
    uschar *ss = store_malloc(len);
    memcpy(ss, s, len);
    return ss;
}
Beispiel #2
0
static void addlookupmodule(void *dl, struct lookup_module_info *info)
{
  struct lookupmodulestr *p = store_malloc(sizeof(struct lookupmodulestr));
  p->dl = dl;
  p->info = info;
  p->next = lookupmodules;
  lookupmodules = p;
  lookup_list_count += info->lookupcount;
}
Beispiel #3
0
static error_block *
add_to_eblock(error_block *eblock, uschar *t1, uschar *t2)
{
error_block *eb = store_malloc(sizeof(error_block));
if (eblock == NULL)
  eblock = eb;
else
  {
  /* Find the end of the eblock struct and point it at eb */
  error_block *tmp = eblock;
  while(tmp->next != NULL)
    tmp = tmp->next;
  tmp->next = eb;
  }
eb->text1 = t1;
eb->text2 = t2;
eb->next  = NULL;
return eblock;
}
Beispiel #4
0
static void ActOnMessage(uschar *id, uschar *action, uschar *address_arg)
{
int pid;
int pipe_fd[2];
int delivery = Ustrcmp(action + Ustrlen(action) - 2, "-M") == 0;
uschar *quote = US"";
uschar *at = US"";
uschar *qualify = US"";
uschar buffer[256];
queue_item *qq;
Widget text = NULL;

/* If the address arg is not empty and does not contain @ and there is a
qualify domain, qualify it. (But don't qualify '<>'.)*/

if (address_arg[0] != 0)
  {
  quote = US"\'";
  if (Ustrchr(address_arg, '@') == NULL &&
      Ustrcmp(address_arg, "<>") != 0 &&
      qualify_domain != NULL &&
      qualify_domain[0] != 0)
    {
    at = US"@";
    qualify = qualify_domain;
    }
  }
sprintf(CS buffer, "%s %s %s %s %s %s%s%s%s%s", exim_path,
  (alternate_config == NULL)? US"" : US"-C",
  (alternate_config == NULL)? US"" : alternate_config,
  action, id, quote, address_arg, at, qualify, quote);

/* If we know we are going to need the window, create it now. */

if (action_output || delivery)
  {
  text = text_create(id, text_depth);
  text_showf(text, "%s\n", buffer);
  }

/* Create the pipe for output. Remember, on most systems pipe[0] is
for reading and pipe[1] is for writing! Solaris, with its two-way
pipes is a trap! */

if (pipe(pipe_fd) != 0)
  {
  if (text == NULL)
    {
    text = text_create(id, text_depth);
    text_showf(text, "%s\n", buffer);
    }
  text_show(text, US"*** Failed to create pipe ***\n");
  return;
  }

if (  fcntl(pipe_fd[0], F_SETFL, O_NONBLOCK)
   || fcntl(pipe_fd[1], F_SETFL, O_NONBLOCK))
  {
  perror("set nonblocking on pipe");
  exit(1);
  }

/* Delivering a message can take some time, and we want to show the
output as it goes along. This requires subprocesses and is coded below. For
other commands, we can assume an immediate response, and so need not waste
resources with subprocesses. If action_output is FALSE, don't show the
output at all. */

if (!delivery)
  {
  int count, rc;
  int save_stdout = dup(1);
  int save_stderr = dup(2);

  close(1);
  close(2);

  dup2(pipe_fd[1], 1);
  dup2(pipe_fd[1], 2);
  close(pipe_fd[1]);

  rc = system(CS buffer);

  close(1);
  close(2);

  if (action_output || rc != 0)
    {
    if (text == NULL)
      {
      text = text_create(id, text_depth);
      text_showf(text, "%s\n", buffer);
      }
    while ((count = read(pipe_fd[0], buffer, 254)) > 0)
      {
      buffer[count] = 0;
      text_show(text, buffer);
      }
    }

  close(pipe_fd[0]);

  dup2(save_stdout, 1);
  dup2(save_stderr, 2);
  close(save_stdout);
  close(save_stderr);

  /* If action was to change the sender, and it succeeded, we have to
  update the in-store data. */

  if (rc == 0 && Ustrcmp(action + Ustrlen(action) - 4, "-Mes") == 0)
    {
    queue_item *q = find_queue(id, queue_noop, 0);
    if (q)
      {
      if (q->sender) store_free(q->sender);
      q->sender = store_malloc(Ustrlen(address_arg) + 1);
      Ustrcpy(q->sender, address_arg);
      }
    }

  /* If configured, cause a display update and return */

  if (action_queue_update) tick_queue_accumulator = 999999;
  return;
  }

/* Message is to be delivered. Ensure that it is marked unfrozen,
because nothing will get written to the log to show that this has
happened. (Other freezing/unfreezings get logged and picked up from
there.) */

qq = find_queue(id, queue_noop, 0);
if (qq != NULL) qq->frozen = FALSE;

/* New, asynchronous code runs in a subprocess for commands that
will take some time. The main process does not wait. There is a
SIGCHLD handler in the main program that cleans up any terminating
sub processes. */

if ((pid = fork()) == 0)
  {
  close(1);
  close(2);

  dup2(pipe_fd[1], 1);
  dup2(pipe_fd[1], 2);
  close(pipe_fd[1]);

  system(CS buffer);

  close(1);
  close(2);
  close(pipe_fd[0]);
  _exit(0);
  }

/* Main process - set up an item for the main ticker to watch. */

if (pid < 0) text_showf(text, "Failed to fork: %s\n", strerror(errno)); else
  {
  pipe_item *p = (pipe_item *)store_malloc(sizeof(pipe_item));

  if (p == NULL)
    {
    text_show(text, US"Run out of store\n");
    return;
    }

  p->widget = text;
  p->fd = pipe_fd[0];

  p->next = pipe_chain;
  pipe_chain = p;

  close(pipe_fd[1]);
  }
}
Beispiel #5
0
void
auth_heimdal_gssapi_init(auth_instance *ablock)
{
  krb5_context context;
  krb5_keytab keytab;
  krb5_kt_cursor cursor;
  krb5_keytab_entry entry;
  krb5_error_code krc;
  char *principal, *enctype_s;
  const char *k_keytab_typed_name = NULL;
  auth_heimdal_gssapi_options_block *ob =
    (auth_heimdal_gssapi_options_block *)(ablock->options_block);

  ablock->server = FALSE;
  ablock->client = FALSE;

  if (!ob->server_service || !*ob->server_service) {
    HDEBUG(D_auth) debug_printf("heimdal: missing server_service\n");
    return;
  }

  krc = krb5_init_context(&context);
  if (krc != 0) {
    int kerr = errno;
    HDEBUG(D_auth) debug_printf("heimdal: failed to initialise krb5 context: %s\n",
        strerror(kerr));
    return;
  }

  if (ob->server_keytab) {
    k_keytab_typed_name = CCS string_sprintf("file:%s", expand_string(ob->server_keytab));
    HDEBUG(D_auth) debug_printf("heimdal: using keytab %s\n", k_keytab_typed_name);
    krc = krb5_kt_resolve(context, k_keytab_typed_name, &keytab);
    if (krc) {
      HDEBUG(D_auth) exim_heimdal_error_debug("krb5_kt_resolve", context, krc);
      return;
    }
  } else {
    HDEBUG(D_auth) debug_printf("heimdal: using system default keytab\n");
    krc = krb5_kt_default(context, &keytab);
    if (krc) {
      HDEBUG(D_auth) exim_heimdal_error_debug("krb5_kt_default", context, krc);
      return;
    }
  }

  HDEBUG(D_auth) {
    /* http://www.h5l.org/manual/HEAD/krb5/krb5_keytab_intro.html */
    krc = krb5_kt_start_seq_get(context, keytab, &cursor);
    if (krc)
      exim_heimdal_error_debug("krb5_kt_start_seq_get", context, krc);
    else {
      while ((krc = krb5_kt_next_entry(context, keytab, &entry, &cursor)) == 0) {
        principal = enctype_s = NULL;
        krb5_unparse_name(context, entry.principal, &principal);
        krb5_enctype_to_string(context, entry.keyblock.keytype, &enctype_s);
        debug_printf("heimdal: keytab principal: %s  vno=%d  type=%s\n",
            principal ? principal : "??",
            entry.vno,
            enctype_s ? enctype_s : "??");
        free(principal);
        free(enctype_s);
        krb5_kt_free_entry(context, &entry);
      }
      krc = krb5_kt_end_seq_get(context, keytab, &cursor);
      if (krc)
        exim_heimdal_error_debug("krb5_kt_end_seq_get", context, krc);
    }
  }

  krc = krb5_kt_close(context, keytab);
  if (krc)
    HDEBUG(D_auth) exim_heimdal_error_debug("krb5_kt_close", context, krc);

  krb5_free_context(context);

  /* RFC 4121 section 5.2, SHOULD support 64K input buffers */
  if (big_buffer_size < (64 * 1024)) {
    uschar *newbuf;
    big_buffer_size = 64 * 1024;
    newbuf = store_malloc(big_buffer_size);
    store_free(big_buffer);
    big_buffer = newbuf;
  }

  ablock->server = TRUE;
}
Beispiel #6
0
int
tls_server_start(uschar *require_ciphers, uschar *require_mac,
  uschar *require_kx, uschar *require_proto)
{
int rc;
const char *error;
uschar *expciphers = NULL;
uschar *expmac = NULL;
uschar *expkx = NULL;
uschar *expproto = NULL;

/* Check for previous activation */

if (tls_active >= 0)
  {
  tls_error("STARTTLS received after TLS started", NULL, "");
  smtp_printf("554 Already in TLS\r\n");
  return FAIL;
  }

/* Initialize the library. If it fails, it will already have logged the error
and sent an SMTP response. */

DEBUG(D_tls) debug_printf("initializing GnuTLS as a server\n");

rc = tls_init(NULL, tls_certificate, tls_privatekey, tls_verify_certificates,
  tls_crl);
if (rc != OK) return rc;

if (!expand_check(require_ciphers, US"tls_require_ciphers", &expciphers) ||
    !expand_check(require_mac, US"gnutls_require_mac", &expmac) ||
    !expand_check(require_kx, US"gnutls_require_kx", &expkx) ||
    !expand_check(require_proto, US"gnutls_require_proto", &expproto))
  return FAIL;

/* If this is a host for which certificate verification is mandatory or
optional, set up appropriately. */

tls_certificate_verified = FALSE;
verify_requirement = VERIFY_NONE;

if (verify_check_host(&tls_verify_hosts) == OK)
  verify_requirement = VERIFY_REQUIRED;
else if (verify_check_host(&tls_try_verify_hosts) == OK)
  verify_requirement = VERIFY_OPTIONAL;

/* Prepare for new connection */

tls_session = tls_session_init(GNUTLS_SERVER, expciphers, expmac, expkx,
  expproto);
if (tls_session == NULL)
  return tls_error(US"tls_session_init", NULL,
    gnutls_strerror(GNUTLS_E_MEMORY_ERROR));

/* Set context and tell client to go ahead, except in the case of TLS startup
on connection, where outputting anything now upsets the clients and tends to
make them disconnect. We need to have an explicit fflush() here, to force out
the response. Other smtp_printf() calls do not need it, because in non-TLS
mode, the fflush() happens when smtp_getc() is called. */

if (!tls_on_connect)
  {
  smtp_printf("220 TLS go ahead\r\n");
  fflush(smtp_out);
  }

/* Now negotiate the TLS session. We put our own timer on it, since it seems
that the GnuTLS library doesn't. */

gnutls_transport_set_ptr2(tls_session, (gnutls_transport_ptr)fileno(smtp_in),
                                       (gnutls_transport_ptr)fileno(smtp_out));

sigalrm_seen = FALSE;
if (smtp_receive_timeout > 0) alarm(smtp_receive_timeout);
rc = gnutls_handshake(tls_session);
alarm(0);

if (rc < 0)
  {
  tls_error(US"gnutls_handshake", NULL,
    sigalrm_seen ? "timed out" : gnutls_strerror(rc));

  /* It seems that, except in the case of a timeout, we have to close the
  connection right here; otherwise if the other end is running OpenSSL it hangs
  until the server times out. */

  if (!sigalrm_seen)
    {
    (void)fclose(smtp_out);
    (void)fclose(smtp_in);
    }

  return FAIL;
  }

DEBUG(D_tls) debug_printf("gnutls_handshake was successful\n");

if (verify_requirement != VERIFY_NONE &&
     !verify_certificate(tls_session, &error))
  {
  tls_error(US"certificate verification failed", NULL, error);
  return FAIL;
  }

construct_cipher_name(tls_session);

/* TLS has been set up. Adjust the input functions to read via TLS,
and initialize appropriately. */

ssl_xfer_buffer = store_malloc(ssl_xfer_buffer_size);
ssl_xfer_buffer_lwm = ssl_xfer_buffer_hwm = 0;
ssl_xfer_eof = ssl_xfer_error = 0;

receive_getc = tls_getc;
receive_ungetc = tls_ungetc;
receive_feof = tls_feof;
receive_ferror = tls_ferror;
receive_smtp_buffered = tls_smtp_buffered;

tls_active = fileno(smtp_out);

return OK;
}
Beispiel #7
0
void init_lookup_list(void)
{
#ifdef LOOKUP_MODULE_DIR
  DIR *dd;
  struct dirent *ent;
  int countmodules = 0;
  int moduleerrors = 0;
#endif
  struct lookupmodulestr *p;
  const pcre *regex_islookupmod = regex_must_compile(
      US"\\." DYNLIB_FN_EXT "$", FALSE, TRUE);

  if (lookup_list_init_done)
    return;
  lookup_list_init_done = 1;

#if defined(LOOKUP_CDB) && LOOKUP_CDB!=2
  addlookupmodule(NULL, &cdb_lookup_module_info);
#endif

#if defined(LOOKUP_DBM) && LOOKUP_DBM!=2
  addlookupmodule(NULL, &dbmdb_lookup_module_info);
#endif

#if defined(LOOKUP_DNSDB) && LOOKUP_DNSDB!=2
  addlookupmodule(NULL, &dnsdb_lookup_module_info);
#endif

#if defined(LOOKUP_DSEARCH) && LOOKUP_DSEARCH!=2
  addlookupmodule(NULL, &dsearch_lookup_module_info);
#endif

#if defined(LOOKUP_IBASE) && LOOKUP_IBASE!=2
  addlookupmodule(NULL, &ibase_lookup_module_info);
#endif

#ifdef LOOKUP_LDAP
  addlookupmodule(NULL, &ldap_lookup_module_info);
#endif

#if defined(LOOKUP_LSEARCH) && LOOKUP_LSEARCH!=2
  addlookupmodule(NULL, &lsearch_lookup_module_info);
#endif

#if defined(LOOKUP_MYSQL) && LOOKUP_MYSQL!=2
  addlookupmodule(NULL, &mysql_lookup_module_info);
#endif

#if defined(LOOKUP_NIS) && LOOKUP_NIS!=2
  addlookupmodule(NULL, &nis_lookup_module_info);
#endif

#if defined(LOOKUP_NISPLUS) && LOOKUP_NISPLUS!=2
  addlookupmodule(NULL, &nisplus_lookup_module_info);
#endif

#if defined(LOOKUP_ORACLE) && LOOKUP_ORACLE!=2
  addlookupmodule(NULL, &oracle_lookup_module_info);
#endif

#if defined(LOOKUP_PASSWD) && LOOKUP_PASSWD!=2
  addlookupmodule(NULL, &passwd_lookup_module_info);
#endif

#if defined(LOOKUP_PGSQL) && LOOKUP_PGSQL!=2
  addlookupmodule(NULL, &pgsql_lookup_module_info);
#endif

#ifdef EXPERIMENTAL_REDIS
  addlookupmodule(NULL, &redis_lookup_module_info);
#endif

#ifdef EXPERIMENTAL_SPF
  addlookupmodule(NULL, &spf_lookup_module_info);
#endif

#if defined(LOOKUP_SQLITE) && LOOKUP_SQLITE!=2
  addlookupmodule(NULL, &sqlite_lookup_module_info);
#endif

#if defined(LOOKUP_TESTDB) && LOOKUP_TESTDB!=2
  addlookupmodule(NULL, &testdb_lookup_module_info);
#endif

#if defined(LOOKUP_WHOSON) && LOOKUP_WHOSON!=2
  addlookupmodule(NULL, &whoson_lookup_module_info);
#endif

#ifdef LOOKUP_MODULE_DIR
  dd = opendir(LOOKUP_MODULE_DIR);
  if (dd == NULL) {
    DEBUG(D_lookup) debug_printf("Couldn't open %s: not loading lookup modules\n", LOOKUP_MODULE_DIR);
    log_write(0, LOG_MAIN, "Couldn't open %s: not loading lookup modules\n", LOOKUP_MODULE_DIR);
  }
  else {
    DEBUG(D_lookup) debug_printf("Loading lookup modules from %s\n", LOOKUP_MODULE_DIR);
    while ((ent = readdir(dd)) != NULL) {
      char *name = ent->d_name;
      int len = (int)strlen(name);
      if (pcre_exec(regex_islookupmod, NULL, name, len, 0, PCRE_EOPT, NULL, 0) >= 0) {
        int pathnamelen = len + (int)strlen(LOOKUP_MODULE_DIR) + 2;
        void *dl;
        struct lookup_module_info *info;
        const char *errormsg;

        /* SRH: am I being paranoid here or what? */
        if (pathnamelen > big_buffer_size) {
          fprintf(stderr, "Loading lookup modules: %s/%s: name too long\n", LOOKUP_MODULE_DIR, name);
          log_write(0, LOG_MAIN|LOG_PANIC, "%s/%s: name too long\n", LOOKUP_MODULE_DIR, name);
          continue;
        }

        /* SRH: snprintf here? */
        sprintf(CS big_buffer, "%s/%s", LOOKUP_MODULE_DIR, name);

        dl = dlopen(CS big_buffer, RTLD_NOW);// TJ was LAZY
        if (dl == NULL) {
          fprintf(stderr, "Error loading %s: %s\n", name, dlerror());
          moduleerrors++;
          log_write(0, LOG_MAIN|LOG_PANIC, "Error loading lookup module %s: %s\n", name, dlerror());
          continue;
        }

        /* FreeBSD nsdispatch() can trigger dlerror() errors about
         * _nss_cache_cycle_prevention_function; we need to clear the dlerror()
         * state before calling dlsym(), so that any error afterwards only
         * comes from dlsym().
         */
        errormsg = dlerror();

        info = (struct lookup_module_info*) dlsym(dl, "_lookup_module_info");
        if ((errormsg = dlerror()) != NULL) {
          fprintf(stderr, "%s does not appear to be a lookup module (%s)\n", name, errormsg);
          dlclose(dl);
          moduleerrors++;
          log_write(0, LOG_MAIN|LOG_PANIC, "%s does not appear to be a lookup module (%s)\n", name, errormsg);
          continue;
        }
        if (info->magic != LOOKUP_MODULE_INFO_MAGIC) {
          fprintf(stderr, "Lookup module %s is not compatible with this version of Exim\n", name);
          dlclose(dl);
          moduleerrors++;
          log_write(0, LOG_MAIN|LOG_PANIC, "Lookup module %s is not compatible with this version of Exim\n", name);
          continue;
        }

        addlookupmodule(dl, info);
        DEBUG(D_lookup) debug_printf("Loaded \"%s\" (%d lookup types)\n", name, info->lookupcount);
        countmodules++;
      }
    }
    closedir(dd);
  }

  DEBUG(D_lookup) debug_printf("Loaded %d lookup modules\n", countmodules);
#endif

  store_free((void*)regex_islookupmod);

  DEBUG(D_lookup) debug_printf("Total %d lookups\n", lookup_list_count);

  lookup_list = store_malloc(sizeof(lookup_info *) * lookup_list_count);
  memset(lookup_list, 0, sizeof(lookup_info *) * lookup_list_count);

  /* now add all lookups to the real list */
  p = lookupmodules;
  while (p) {
    int j;
    struct lookupmodulestr *pnext;

    for (j = 0; j < p->info->lookupcount; j++)
      add_lookup_to_list(p->info->lookups[j]);

    pnext = p->next;
    store_free(p);
    p = pnext;
  }
  /* just to be sure */
  lookupmodules = NULL;
}