int auth_tls_server(auth_instance *ablock, uschar *data) { auth_tls_options_block * ob = (auth_tls_options_block *)ablock->options_block; if (ob->server_param1) auth_vars[expand_nmax++] = expand_string(ob->server_param1); if (ob->server_param2) auth_vars[expand_nmax++] = expand_string(ob->server_param2); if (ob->server_param3) auth_vars[expand_nmax++] = expand_string(ob->server_param3); return auth_check_serv_cond(ablock); }
symbol Block::name (const symbol key) const { const Frame& frame = find_frame (key); if (frame.is_reference (key)) return name (expand_reference (key)); //Handle primitive names. Attribute::type type = lookup (key); if (type != Attribute::Model) return expand_string (frame.name (key)); // Handle stringer objects. daisy_assert (type == Attribute::Model); daisy_assert (frame.component (key) == Stringer::component); daisy_assert (frame.check (*this)); std::unique_ptr<Stringer> stringer (Librarian::build_frame<Stringer> (*this, frame.model (key), key)); daisy_assert (stringer.get ()); daisy_assert (stringer->initialize (units (), *this, msg ())); daisy_assert (stringer->check (units (), *this, msg ())); stringer->tick (units (), *this, msg ()); daisy_assert (!stringer->missing (*this)); return symbol (stringer->value (*this)); }
static char * getcwd_syscall (char *buf, size_t size) { int dynamic_buf = 0; if (buf == NULL) { dynamic_buf = 1; if (initial_string (&buf, &size, MAXPATHLEN) < 0) return NULL; } for (;;) { int ret; ret = sys_getcwd (buf, size); if (ret >= 0) return buf; else if (errno == ERANGE) { if (!dynamic_buf) return NULL; if (expand_string (&buf, &size, size * 2) < 0) return NULL; } else return NULL; } }
//-------------------------------- int fill_char_matrix()//int unicode_point) { current_line=0; current_line_pos=0; if(current_char_index==-1) { fprintf(stderr,"/!\\ char not found. this should not happen.\n"); return -1; } //for all lines int i=0; for(i=0;i<LINES_PER_CHAR;i++) { expand_string(spf_chars[current_char_index][i]); //eol //printf("\n"); spf_char_line[current_line_pos]='\0'; spf_char[current_line]=strdup(spf_char_line); current_line++; current_line_pos=0; } return 0; } //end fill_char_matrix
void parser_t::expand_argument_list(const wcstring &arg_list_src, expand_flags_t eflags, std::vector<completion_t> *output_arg_list) { assert(output_arg_list != NULL); /* Parse the string as an argument list */ parse_node_tree_t tree; if (! parse_tree_from_string(arg_list_src, parse_flag_none, &tree, NULL /* errors */, symbol_freestanding_argument_list)) { /* Failed to parse. Here we expect to have reported any errors in test_args */ return; } /* Get the root argument list */ assert(! tree.empty()); const parse_node_t *arg_list = &tree.at(0); assert(arg_list->type == symbol_freestanding_argument_list); /* Extract arguments from it */ while (arg_list != NULL) { const parse_node_t *arg_node = tree.next_node_in_node_list(*arg_list, symbol_argument, &arg_list); if (arg_node != NULL) { const wcstring arg_src = arg_node->get_source(arg_list_src); if (expand_string(arg_src, output_arg_list, eflags, NULL) == EXPAND_ERROR) { /* Failed to expand a string */ break; } } } }
static uschar * checkexpand(uschar *s, address_item *addr, uschar *name, int type) { uschar *t; uschar *ss = expand_string(s); if (ss == NULL) { addr->transport_return = FAIL; addr->message = string_sprintf("Expansion of \"%s\" failed in %s transport: " "%s", s, name, expand_string_message); return NULL; } if (type != cke_text) for (t = ss; *t != 0; t++) { int c = *t; if (mac_isprint(c)) continue; if (type == cke_hdr && c == '\n' && (t[1] == ' ' || t[1] == '\t')) continue; s = string_printing(s); addr->transport_return = FAIL; addr->message = string_sprintf("Expansion of \"%s\" in %s transport " "contains non-printing character %d", s, name, c); return NULL; } return ss; }
static int guarantee_room (char **buf, size_t *size, size_t len) { if (*size > len) return 0; return expand_string (buf, size, min(*size * 2, len)); }
symbol Block::name (const symbol key, const symbol default_value) const { const Frame& frame = find_frame (key); if (frame.is_reference (key)) return name (expand_reference (key), default_value); return expand_string (frame.name (key, default_value)); }
gchar *unescape_string(const gchar *original, gboolean escape_colon) { gchar *string, *tmp=NULL; DEBUG_MSG("unescape_string, started\n"); if (!escape_colon) { tmp = standardescapetable[9].my_char; standardescapetable[9].my_char = NULL; } string = expand_string(original,'\\',standardescapetable); if (!escape_colon) { standardescapetable[9].my_char = tmp; } return string; }
const std::vector<symbol> Block::name_sequence (const symbol key) const { const Frame& frame = find_frame (key); if (frame.is_reference (key)) return name_sequence (expand_reference (key)); const std::vector<symbol>& value = frame.name_sequence (key); std::vector<symbol> result; for (size_t i = 0; i < value.size (); i++) result.push_back (expand_string (value[i])); return result; }
gstring * authres_spf(gstring * g) { uschar * s; if (!spf_result) return g; g = string_append(g, 2, US";\n\tspf=", spf_result); if (spf_result_guessed) g = string_cat(g, US" (best guess record for domain)"); s = expand_string(US"$sender_address_domain"); return s && *s ? string_append(g, 2, US" smtp.mailfrom=", s) : string_cat(g, US" smtp.mailfrom=<>"); }
static BOOL expand_check(const uschar *s, const uschar *name, uschar **result) { if (s == NULL) *result = NULL; else { *result = expand_string(US s); /* need to clean up const some more */ if (*result == NULL && !expand_string_forcedfail) { log_write(0, LOG_MAIN|LOG_PANIC, "expansion of %s failed: %s", name, expand_string_message); return FALSE; } } return TRUE; }
void parser_t::expand_argument_list(const wcstring &arg_list_src, std::vector<completion_t> *output_arg_list) { assert(output_arg_list != NULL); expand_flags_t eflags = 0; if (! show_errors) eflags |= EXPAND_NO_DESCRIPTIONS; if (this->parser_type != PARSER_TYPE_GENERAL) eflags |= EXPAND_SKIP_CMDSUBST; /* Suppress calling proc_push_interactive off of the main thread. */ if (this->parser_type == PARSER_TYPE_GENERAL) { proc_push_interactive(0); } /* Parse the string as an argument list */ parse_node_tree_t tree; if (! parse_tree_from_string(arg_list_src, parse_flag_none, &tree, NULL /* errors */, symbol_freestanding_argument_list)) { /* Failed to parse. Here we expect to have reported any errors in test_args */ return; } /* Get the root argument list */ assert(! tree.empty()); const parse_node_t *arg_list = &tree.at(0); assert(arg_list->type == symbol_freestanding_argument_list); /* Extract arguments from it */ while (arg_list != NULL) { const parse_node_t *arg_node = tree.next_node_in_node_list(*arg_list, symbol_argument, &arg_list); if (arg_node != NULL) { const wcstring arg_src = arg_node->get_source(arg_list_src); if (expand_string(arg_src, output_arg_list, eflags, NULL) == EXPAND_ERROR) { /* Failed to expand a string */ break; } } } if (this->parser_type == PARSER_TYPE_GENERAL) { proc_pop_interactive(); } }
BOOL rf_get_transport(uschar *tpname, transport_instance **tpptr, address_item *addr, uschar *router_name, uschar *require_name) { uschar *ss; BOOL expandable; transport_instance *tp; if (tpname == NULL) { if (require_name == NULL) return TRUE; addr->basic_errno = ERRNO_BADTRANSPORT; addr->message = string_sprintf("%s unset in %s router", require_name, router_name); return FALSE; } expandable = Ustrchr(tpname, '$') != NULL; if (*tpptr != NULL && !expandable) return TRUE; if (expandable) { ss = expand_string(tpname); if (ss == NULL) { addr->basic_errno = ERRNO_BADTRANSPORT; addr->message = string_sprintf("failed to expand transport " "\"%s\" in %s router: %s", tpname, router_name, expand_string_message); return FALSE; } } else ss = tpname; for (tp = transports; tp != NULL; tp = tp->next) { if (Ustrcmp(tp->name, ss) == 0) { DEBUG(D_route) debug_printf("set transport %s\n", ss); *tpptr = tp; return TRUE; } } addr->basic_errno = ERRNO_BADTRANSPORT; addr->message = string_sprintf("transport \"%s\" not found in %s router", ss, router_name); return FALSE; }
static BOOL expand_check(const uschar *s, const uschar *name, uschar **result, uschar ** errstr) { if (!s) *result = NULL; else if ( !(*result = expand_string(US s)) /* need to clean up const more */ && !expand_string_forcedfail ) { *errstr = US"Internal error"; log_write(0, LOG_MAIN|LOG_PANIC, "expansion of %s failed: %s", name, expand_string_message); return FALSE; } return TRUE; }
std::string courier::auth::config_file::parse_custom_query(const std::string &s, const std::string &login, const std::string &defdomain, std::map<std::string, std::string> ¶meters) { std::string::const_iterator b=login.begin(), e=login.end(), p=std::find(b, e, '@'); parameters["local_part"]=std::string(b, p); parameters["domain"]=p == e ? defdomain:std::string(p+1, e); return expand_string(s, parameters); }
//-------------------------------- void expand_char(char c) { /* printf("<div class=\"spfc_row\">\n"); printf("</div>\n"); printf("<div class=\"spfc_fg\"> </div>\n"); printf("<div class=\"spfc_bg\"> </div>\n"); */ //no further expansion, "primitive" pixel 0/1 #/. if(c==SPF_FG) { //printf("line %d pos %d",current_line,current_line_pos); spf_char_line[current_line_pos]=SPF_FG; current_line_pos++; return; } else if(c==SPF_BG) { //printf("line %d pos %d",current_line,current_line_pos); spf_char_line[current_line_pos]=SPF_BG; current_line_pos++; return; } //further expansion, check if pattern matches (single char) int match=0; int k=0; for(k=0;k<PATTERNS_TOTAL;k++) { //printf("%d %d %c. ",k,index_to_char_dec(k),index_to_char_dec(k)); if(c==index_to_char_dec(k)) { //second pass expand_string(spf_encoding_patterns[k]); match=1; break; } } if(match==0) { fprintf(stderr,"/!\\ encoding pattern not found: '%c'. this is an internal issue that should not happen.\n",c); } }//end expand_char
/* * Have Exim do a string expansion, will raise * a Python ValueError exception if the expansion fails */ static PyObject *expy_expand_string(PyObject *self, PyObject *args) { char *str; char *result; if (!PyArg_ParseTuple(args, "s", &str)) return NULL; result = expand_string(str); if (!result) { PyErr_Format(PyExc_ValueError, "expansion [%s] failed: %s", str, expand_string_message); return NULL; } return PyString_FromString(result); }
srs_result eximsrs_db_lookup(srs_t *srs, char *data, uint data_len, char *result, uint result_len) { uschar *res; if(srs_db_reverse == NULL) return SRS_RESULT_DBERROR; srs_db_key = string_copyn(data, data_len); if((res = expand_string(srs_db_reverse)) == NULL) return SRS_RESULT_DBERROR; if(Ustrlen(res) >= result_len) return SRS_RESULT_ADDRESSTOOLONG; strncpy(result, res, result_len); return SRS_RESULT_OK; }
uschar * rf_expand_data(address_item *addr, uschar *s, int *prc) { uschar *yield = expand_string(s); if (yield != NULL) return yield; if (expand_string_forcedfail) { DEBUG(D_route) debug_printf("forced failure for expansion of \"%s\"\n", s); *prc = DECLINE; } else { addr->message = string_sprintf("failed to expand \"%s\": %s", s, expand_string_message); *prc = DEFER; } return NULL; }
static char * getcwd_proc (char *buf, size_t size) { int dynamic_buf = 0; if (buf == NULL) { dynamic_buf = 1; if (initial_string (&buf, &size, MAXPATHLEN) < 0) return NULL; } else if (size <= 1) { errno = ERANGE; return NULL; } for (;;) { int ret; ret = readlink ("/proc/self/cwd", buf, size); if (ret == -1) goto err_ret; if (buf[0] != '/') { errno = EINVAL; goto err_ret; } if (buf[ret-1] != '\0' && ret >= size) { if (!dynamic_buf) { errno = ERANGE; goto err_ret; } if (expand_string (&buf, &size, size * 2) < 0) goto err_ret; } else { if (buf[ret - 1] != '\0') buf[ret] = '\0'; return buf; } } err_ret: if (dynamic_buf) free (buf); return NULL; }
bool expand_one(wcstring &string, expand_flags_t flags) { std::vector<completion_t> completions; bool result = false; if ((!(flags & ACCEPT_INCOMPLETE)) && expand_is_clean(string.c_str())) { return true; } if (expand_string(string, completions, flags)) { if (completions.size() == 1) { string = completions.at(0).completion; result = true; } } return result; }
void parser_t::expand_argument_list(const wcstring &arg_list_src, expand_flags_t eflags, std::vector<completion_t> *output_arg_list) { assert(output_arg_list != NULL); // Parse the string as an argument list. parse_node_tree_t tree; if (!parse_tree_from_string(arg_list_src, parse_flag_none, &tree, NULL /* errors */, symbol_freestanding_argument_list)) { // Failed to parse. Here we expect to have reported any errors in test_args. return; } // Get the root argument list and extract arguments from it. assert(!tree.empty()); //!OCLINT(multiple unary operator) tnode_t<grammar::freestanding_argument_list> arg_list(&tree, &tree.at(0)); while (auto arg = arg_list.next_in_list<grammar::argument>()) { const wcstring arg_src = arg.get_source(arg_list_src); if (expand_string(arg_src, output_arg_list, eflags, NULL) == EXPAND_ERROR) { break; // failed to expand a string } } }
static int expand_test( const wchar_t *in, int flags, ... ) { array_list_t out; va_list va; int i=0; int res=1; wchar_t *arg; al_init( &out ); if( expand_string( 0, wcsdup(in), &out, flags) ) { } va_start( va, flags ); while( (arg=va_arg(va, wchar_t *) )!= 0 ) { if( al_get_count( &out ) == i ) { res=0; break; } if( wcscmp( al_get( &out, i ),arg) != 0 ) { res=0; break; } i++; } va_end( va ); al_foreach( &out, &free ); return res; }
BOOL dns_is_secure(const dns_answer * dnsa) { #ifdef DISABLE_DNSSEC DEBUG(D_dns) debug_printf("DNSSEC support disabled at build-time; dns_is_secure() false\n"); return FALSE; #else HEADER * h = (HEADER *) dnsa->answer; const uschar * auth_name; const uschar * trusted; if (h->ad) return TRUE; /* If the resolver we ask is authoritive for the domain in question, it * may not set the AD but the AA bit. If we explicitly trust * the resolver for that domain (via a domainlist in dns_trust_aa), * we return TRUE to indicate a secure answer. */ if ( !h->aa || !dns_trust_aa || !(trusted = expand_string(dns_trust_aa)) || !*trusted || !(auth_name = dns_extract_auth_name(dnsa)) || OK != match_isinlist(auth_name, &trusted, 0, NULL, NULL, MCL_DOMAIN, TRUE, NULL) ) return FALSE; DEBUG(D_dns) debug_printf("DNS faked the AD bit " "(got AA and matched with dns_trust_aa (%s in %s))\n", auth_name, dns_trust_aa); return TRUE; #endif }
uschar * dmarc_auth_results_header(header_line *from_header, uschar *hostname) { uschar *hdr_tmp = US""; /* Allow a server hostname to be passed to this function, but is * currently unused */ if (!hostname) hostname = primary_hostname; hdr_tmp = string_sprintf("%s %s;", DMARC_AR_HEADER, hostname); #if 0 /* I don't think this belongs here, but left it here commented out * because it was a lot of work to get working right. */ if (spf_response != NULL) { uschar *dmarc_ar_spf = US""; int sr = 0; sr = spf_response->result; dmarc_ar_spf = (sr == SPF_RESULT_NEUTRAL) ? US"neutral" : (sr == SPF_RESULT_PASS) ? US"pass" : (sr == SPF_RESULT_FAIL) ? US"fail" : (sr == SPF_RESULT_SOFTFAIL) ? US"softfail" : US"none"; hdr_tmp = string_sprintf("%s spf=%s (%s) smtp.mail=%s;", hdr_tmp, dmarc_ar_spf_result, spf_response->header_comment, expand_string(US"$sender_address") ); } #endif hdr_tmp = string_sprintf("%s dmarc=%s", hdr_tmp, dmarc_pass_fail); if (header_from_sender) hdr_tmp = string_sprintf("%s header.from=%s", hdr_tmp, header_from_sender); return hdr_tmp; }
srs_result eximsrs_db_insert(srs_t *srs, char *data, uint data_len, char *result, uint result_len) { uschar *res; uschar buf[64]; if(srs_db_forward == NULL) return SRS_RESULT_DBERROR; srs_db_address = string_copyn(data, data_len); if(srs_generate_unique_id(srs, srs_db_address, buf, 64) & SRS_RESULT_FAIL) return SRS_RESULT_DBERROR; srs_db_key = string_copyn(buf, 16); if((res = expand_string(srs_db_forward)) == NULL) return SRS_RESULT_DBERROR; if(result_len < 17) return SRS_RESULT_DBERROR; Ustrncpy(result, srs_db_key, result_len); return SRS_RESULT_OK; }
BOOL autoreply_transport_entry( transport_instance *tblock, /* data for this instantiation */ address_item *addr) /* address we are working on */ { int fd, pid, rc; int cache_fd = -1; int log_fd = -1; int cache_size = 0; int add_size = 0; EXIM_DB *dbm_file = NULL; BOOL file_expand, return_message; uschar *from, *reply_to, *to, *cc, *bcc, *subject, *headers, *text, *file; uschar *logfile, *oncelog; uschar *cache_buff = NULL; uschar *cache_time = NULL; uschar *message_id = NULL; header_line *h; time_t now = time(NULL); time_t once_repeat_sec = 0; FILE *f; FILE *ff = NULL; autoreply_transport_options_block *ob = (autoreply_transport_options_block *)(tblock->options_block); DEBUG(D_transport) debug_printf("%s transport entered\n", tblock->name); /* Set up for the good case */ addr->transport_return = OK; addr->basic_errno = 0; /* If the address is pointing to a reply block, then take all the data from that block. It has typically been set up by a mail filter processing router. Otherwise, the data must be supplied by this transport, and it has to be expanded here. */ if (addr->reply != NULL) { DEBUG(D_transport) debug_printf("taking data from address\n"); from = addr->reply->from; reply_to = addr->reply->reply_to; to = addr->reply->to; cc = addr->reply->cc; bcc = addr->reply->bcc; subject = addr->reply->subject; headers = addr->reply->headers; text = addr->reply->text; file = addr->reply->file; logfile = addr->reply->logfile; oncelog = addr->reply->oncelog; once_repeat_sec = addr->reply->once_repeat; file_expand = addr->reply->file_expand; expand_forbid = addr->reply->expand_forbid; return_message = addr->reply->return_message; } else { uschar *oncerepeat = ob->once_repeat; DEBUG(D_transport) debug_printf("taking data from transport\n"); from = ob->from; reply_to = ob->reply_to; to = ob->to; cc = ob->cc; bcc = ob->bcc; subject = ob->subject; headers = ob->headers; text = ob->text; file = ob->file; logfile = ob->logfile; oncelog = ob->oncelog; file_expand = ob->file_expand; return_message = ob->return_message; if ((from != NULL && (from = checkexpand(from, addr, tblock->name, cke_hdr)) == NULL) || (reply_to != NULL && (reply_to = checkexpand(reply_to, addr, tblock->name, cke_hdr)) == NULL) || (to != NULL && (to = checkexpand(to, addr, tblock->name, cke_hdr)) == NULL) || (cc != NULL && (cc = checkexpand(cc, addr, tblock->name, cke_hdr)) == NULL) || (bcc != NULL && (bcc = checkexpand(bcc, addr, tblock->name, cke_hdr)) == NULL) || (subject != NULL && (subject = checkexpand(subject, addr, tblock->name, cke_hdr)) == NULL) || (headers != NULL && (headers = checkexpand(headers, addr, tblock->name, cke_text)) == NULL) || (text != NULL && (text = checkexpand(text, addr, tblock->name, cke_text)) == NULL) || (file != NULL && (file = checkexpand(file, addr, tblock->name, cke_file)) == NULL) || (logfile != NULL && (logfile = checkexpand(logfile, addr, tblock->name, cke_file)) == NULL) || (oncelog != NULL && (oncelog = checkexpand(oncelog, addr, tblock->name, cke_file)) == NULL) || (oncerepeat != NULL && (oncerepeat = checkexpand(oncerepeat, addr, tblock->name, cke_file)) == NULL)) return FALSE; if (oncerepeat != NULL) { once_repeat_sec = readconf_readtime(oncerepeat, 0, FALSE); if (once_repeat_sec < 0) { addr->transport_return = FAIL; addr->message = string_sprintf("Invalid time value \"%s\" for " "\"once_repeat\" in %s transport", oncerepeat, tblock->name); return FALSE; } } } /* If the never_mail option is set, we have to scan all the recipients and remove those that match. */ if (ob->never_mail != NULL) { uschar *never_mail = expand_string(ob->never_mail); if (never_mail == NULL) { addr->transport_return = FAIL; addr->message = string_sprintf("Failed to expand \"%s\" for " "\"never_mail\" in %s transport", ob->never_mail, tblock->name); return FALSE; } if (to != NULL) check_never_mail(&to, never_mail); if (cc != NULL) check_never_mail(&cc, never_mail); if (bcc != NULL) check_never_mail(&bcc, never_mail); if (to == NULL && cc == NULL && bcc == NULL) { DEBUG(D_transport) debug_printf("*** all recipients removed by never_mail\n"); return OK; } } /* If the -N option is set, can't do any more. */ if (dont_deliver) { DEBUG(D_transport) debug_printf("*** delivery by %s transport bypassed by -N option\n", tblock->name); return FALSE; } /* If the oncelog field is set, we send want to send only one message to the given recipient(s). This works only on the "To" field. If there is no "To" field, the message is always sent. If the To: field contains more than one recipient, the effect might not be quite as envisaged. If once_file_size is set, instead of a dbm file, we use a regular file containing a circular buffer recipient cache. */ if (oncelog != NULL && *oncelog != 0 && to != NULL) { time_t then = 0; /* Handle fixed-size cache file. */ if (ob->once_file_size > 0) { uschar *p; struct stat statbuf; cache_fd = Uopen(oncelog, O_CREAT|O_RDWR, ob->mode); if (cache_fd < 0 || fstat(cache_fd, &statbuf) != 0) { addr->transport_return = DEFER; addr->message = string_sprintf("Failed to %s \"once\" file %s when " "sending message from %s transport: %s", (cache_fd < 0)? "open" : "stat", oncelog, tblock->name, strerror(errno)); goto END_OFF; } /* Get store in the temporary pool and read the entire file into it. We get an amount of store that is big enough to add the new entry on the end if we need to do that. */ cache_size = statbuf.st_size; add_size = sizeof(time_t) + Ustrlen(to) + 1; cache_buff = store_get(cache_size + add_size); if (read(cache_fd, cache_buff, cache_size) != cache_size) { addr->transport_return = DEFER; addr->basic_errno = errno; addr->message = US"error while reading \"once\" file"; goto END_OFF; } DEBUG(D_transport) debug_printf("%d bytes read from %s\n", cache_size, oncelog); /* Scan the data for this recipient. Each entry in the file starts with a time_t sized time value, followed by the address, followed by a binary zero. If we find a match, put the time into "then", and the place where it was found into "cache_time". Otherwise, "then" is left at zero. */ p = cache_buff; while (p < cache_buff + cache_size) { uschar *s = p + sizeof(time_t); uschar *nextp = s + Ustrlen(s) + 1; if (Ustrcmp(to, s) == 0) { memcpy(&then, p, sizeof(time_t)); cache_time = p; break; } p = nextp; } } /* Use a DBM file for the list of previous recipients. */ else { EXIM_DATUM key_datum, result_datum; EXIM_DBOPEN(oncelog, O_RDWR|O_CREAT, ob->mode, &dbm_file); if (dbm_file == NULL) { addr->transport_return = DEFER; addr->message = string_sprintf("Failed to open %s file %s when sending " "message from %s transport: %s", EXIM_DBTYPE, oncelog, tblock->name, strerror(errno)); goto END_OFF; } EXIM_DATUM_INIT(key_datum); /* Some DBM libraries need datums */ EXIM_DATUM_INIT(result_datum); /* to be cleared */ EXIM_DATUM_DATA(key_datum) = CS to; EXIM_DATUM_SIZE(key_datum) = Ustrlen(to) + 1; if (EXIM_DBGET(dbm_file, key_datum, result_datum)) { /* If the datum size is that of a binary time, we are in the new world where messages are sent periodically. Otherwise the file is an old one, where the datum was filled with a tod_log time, which is assumed to be different in size. For that, only one message is ever sent. This change introduced at Exim 3.00. In a couple of years' time the test on the size can be abolished. */ if (EXIM_DATUM_SIZE(result_datum) == sizeof(time_t)) { memcpy(&then, EXIM_DATUM_DATA(result_datum), sizeof(time_t)); } else then = now; } } /* Either "then" is set zero, if no message has yet been sent, or it is set to the time of the last sending. */ if (then != 0 && (once_repeat_sec <= 0 || now - then < once_repeat_sec)) { DEBUG(D_transport) debug_printf("message previously sent to %s%s\n", to, (once_repeat_sec > 0)? " and repeat time not reached" : ""); log_fd = Uopen(logfile, O_WRONLY|O_APPEND|O_CREAT, ob->mode); if (log_fd >= 0) { uschar *ptr = log_buffer; sprintf(CS ptr, "%s\n previously sent to %.200s\n", tod_stamp(tod_log), to); while(*ptr) ptr++; if(write(log_fd, log_buffer, ptr - log_buffer) != ptr-log_buffer || close(log_fd)) DEBUG(D_transport) debug_printf("Problem writing log file %s for %s " "transport\n", logfile, tblock->name); } goto END_OFF; } DEBUG(D_transport) debug_printf("%s %s\n", (then <= 0)? "no previous message sent to" : "repeat time reached for", to); } /* We are going to send a message. Ensure any requested file is available. */ if (file != NULL) { ff = Ufopen(file, "rb"); if (ff == NULL && !ob->file_optional) { addr->transport_return = DEFER; addr->message = string_sprintf("Failed to open file %s when sending " "message from %s transport: %s", file, tblock->name, strerror(errno)); return FALSE; } } /* Make a subprocess to send the message */ pid = child_open_exim(&fd); /* Creation of child failed; defer this delivery. */ if (pid < 0) { addr->transport_return = DEFER; addr->message = string_sprintf("Failed to create child process to send " "message from %s transport: %s", tblock->name, strerror(errno)); DEBUG(D_transport) debug_printf("%s\n", addr->message); return FALSE; } /* Create the message to be sent - recipients are taken from the headers, as the -t option is used. The "headers" stuff *must* be last in case there are newlines in it which might, if placed earlier, screw up other headers. */ f = fdopen(fd, "wb"); if (from != NULL) fprintf(f, "From: %s\n", from); if (reply_to != NULL) fprintf(f, "Reply-To: %s\n", reply_to); if (to != NULL) fprintf(f, "To: %s\n", to); if (cc != NULL) fprintf(f, "Cc: %s\n", cc); if (bcc != NULL) fprintf(f, "Bcc: %s\n", bcc); if (subject != NULL) fprintf(f, "Subject: %s\n", subject); /* Generate In-Reply-To from the message_id header; there should always be one, but code defensively. */ for (h = header_list; h != NULL; h = h->next) if (h->type == htype_id) break; if (h != NULL) { message_id = Ustrchr(h->text, ':') + 1; while (isspace(*message_id)) message_id++; fprintf(f, "In-Reply-To: %s", message_id); } /* Generate a References header if there is at least one of Message-ID:, References:, or In-Reply-To: (see RFC 2822). */ for (h = header_list; h != NULL; h = h->next) if (h->type != htype_old && strncmpic(US"References:", h->text, 11) == 0) break; if (h == NULL) for (h = header_list; h != NULL; h = h->next) if (h->type != htype_old && strncmpic(US"In-Reply-To:", h->text, 12) == 0) break; /* We limit the total length of references. Although there is no fixed limit, some systems do not like headers growing beyond recognition. Keep the first message ID for the thread root and the last few for the position inside the thread, up to a maximum of 12 altogether. */ if (h != NULL || message_id != NULL) { fprintf(f, "References:"); if (h != NULL) { uschar *s, *id, *error; uschar *referenced_ids[12]; int reference_count = 0; int i; s = Ustrchr(h->text, ':') + 1; parse_allow_group = FALSE; while (*s != 0 && (s = parse_message_id(s, &id, &error)) != NULL) { if (reference_count == sizeof(referenced_ids)/sizeof(uschar *)) { memmove(referenced_ids + 1, referenced_ids + 2, sizeof(referenced_ids) - 2*sizeof(uschar *)); referenced_ids[reference_count - 1] = id; } else referenced_ids[reference_count++] = id; } for (i = 0; i < reference_count; ++i) fprintf(f, " %s", referenced_ids[i]); } /* The message id will have a newline on the end of it. */ if (message_id != NULL) fprintf(f, " %s", message_id); else fprintf(f, "\n"); } /* Add an Auto-Submitted: header */ fprintf(f, "Auto-Submitted: auto-replied\n"); /* Add any specially requested headers */ if (headers != NULL) fprintf(f, "%s\n", headers); fprintf(f, "\n"); if (text != NULL) { fprintf(f, "%s", CS text); if (text[Ustrlen(text)-1] != '\n') fprintf(f, "\n"); } if (ff != NULL) { while (Ufgets(big_buffer, big_buffer_size, ff) != NULL) { if (file_expand) { uschar *s = expand_string(big_buffer); DEBUG(D_transport) { if (s == NULL) debug_printf("error while expanding line from file:\n %s\n %s\n", big_buffer, expand_string_message); } fprintf(f, "%s", (s == NULL)? CS big_buffer : CS s); } else fprintf(f, "%s", CS big_buffer); } }
int auth_cram_md5_client( auth_instance *ablock, /* authenticator block */ smtp_inblock *inblock, /* input connection */ smtp_outblock *outblock, /* output connection */ int timeout, /* command timeout */ uschar *buffer, /* for reading response */ int buffsize) /* size of buffer */ { auth_cram_md5_options_block *ob = (auth_cram_md5_options_block *)(ablock->options_block); uschar *secret = expand_string(ob->client_secret); uschar *name = expand_string(ob->client_name); uschar *challenge, *p; int i; uschar digest[16]; /* If expansion of either the secret or the user name failed, return CANCELLED or ERROR, as approriate. */ if (!secret || !name) { if (expand_string_forcedfail) { *buffer = 0; /* No message */ return CANCELLED; } string_format(buffer, buffsize, "expansion of \"%s\" failed in " "%s authenticator: %s", !secret ? ob->client_secret : ob->client_name, ablock->name, expand_string_message); return ERROR; } /* Initiate the authentication exchange and read the challenge, which arrives in base 64. */ if (smtp_write_command(outblock, FALSE, "AUTH %s\r\n", ablock->public_name) < 0) return FAIL_SEND; if (!smtp_read_response(inblock, buffer, buffsize, '3', timeout)) return FAIL; if (b64decode(buffer + 4, &challenge) < 0) { string_format(buffer, buffsize, "bad base 64 string in challenge: %s", big_buffer + 4); return ERROR; } /* Run the CRAM-MD5 algorithm on the secret and the challenge */ compute_cram_md5(secret, challenge, digest); /* Create the response from the user name plus the CRAM-MD5 digest */ string_format(big_buffer, big_buffer_size - 36, "%s", name); for (p = big_buffer; *p; ) p++; *p++ = ' '; for (i = 0; i < 16; i++) { sprintf(CS p, "%02x", digest[i]); p += 2; } /* Send the response, in base 64, and check the result. The response is in big_buffer, but b64encode() returns its result in working store, so calling smtp_write_command(), which uses big_buffer, is OK. */ buffer[0] = 0; if (smtp_write_command(outblock, FALSE, "%s\r\n", b64encode(big_buffer, p - big_buffer)) < 0) return FAIL_SEND; return smtp_read_response(inblock, (uschar *)buffer, buffsize, '2', timeout) ? OK : FAIL; }
int auth_cram_md5_server(auth_instance *ablock, uschar *data) { auth_cram_md5_options_block *ob = (auth_cram_md5_options_block *)(ablock->options_block); uschar *challenge = string_sprintf("<%d.%ld@%s>", getpid(), (long int) time(NULL), primary_hostname); uschar *clear, *secret; uschar digest[16]; int i, rc, len; /* If we are running in the test harness, always send the same challenge, an example string taken from the RFC. */ if (running_in_test_harness) challenge = US"<*****@*****.**>"; /* No data should have been sent with the AUTH command */ if (*data != 0) return UNEXPECTED; /* Send the challenge, read the return */ if ((rc = auth_get_data(&data, challenge, Ustrlen(challenge))) != OK) return rc; if ((len = b64decode(data, &clear)) < 0) return BAD64; /* The return consists of a user name, space-separated from the CRAM-MD5 digest, expressed in hex. Extract the user name and put it in $auth1 and $1. The former is now the preferred variable; the latter is the original one. Then check that the remaining length is 32. */ auth_vars[0] = expand_nstring[1] = clear; while (*clear != 0 && !isspace(*clear)) clear++; if (!isspace(*clear)) return FAIL; *clear++ = 0; expand_nlength[1] = clear - expand_nstring[1] - 1; if (len - expand_nlength[1] - 1 != 32) return FAIL; expand_nmax = 1; /* Expand the server_secret string so that it can compute a value dependent on the user name if necessary. */ debug_print_string(ablock->server_debug_string); /* customized debugging */ secret = expand_string(ob->server_secret); /* A forced fail implies failure of authentication - i.e. we have no secret for the given name. */ if (secret == NULL) { if (expand_string_forcedfail) return FAIL; auth_defer_msg = expand_string_message; return DEFER; } /* Compute the CRAM-MD5 digest that we should have received from the client. */ compute_cram_md5(secret, challenge, digest); HDEBUG(D_auth) { uschar buff[64]; debug_printf("CRAM-MD5: user name = %s\n", auth_vars[0]); debug_printf(" challenge = %s\n", challenge); debug_printf(" received = %s\n", clear); Ustrcpy(buff," digest = "); for (i = 0; i < 16; i++) sprintf(CS buff+22+2*i, "%02x", digest[i]); debug_printf("%.54s\n", buff); } /* We now have to compare the digest, which is 16 bytes in binary, with the data received, which is expressed in lower case hex. We checked above that there were 32 characters of data left. */ for (i = 0; i < 16; i++) { int a = *clear++; int b = *clear++; if (((((a >= 'a')? a - 'a' + 10 : a - '0') << 4) + ((b >= 'a')? b - 'a' + 10 : b - '0')) != digest[i]) return FAIL; } /* Expand server_condition as an authorization check */ return auth_check_serv_cond(ablock); }