uschar * string_copy_malloc(const uschar *s) { int len = Ustrlen(s) + 1; uschar *ss = store_malloc(len); memcpy(ss, s, len); return ss; }
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; }
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; }
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]); } }
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; }
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; }
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; }