static void verify_extract_name(TLS_SESS_STATE *TLScontext, X509 *peercert, const TLS_CLIENT_START_PROPS *props) { int i; int r; int matched = 0; int dnsname_match; int verify_peername = 0; int log_certmatch; int verbose; const char *dnsname; const GENERAL_NAME *gn; STACK_OF(GENERAL_NAME) * gens; /* * On exit both peer_CN and issuer_CN should be set. */ TLScontext->issuer_CN = tls_issuer_CN(peercert, TLScontext); /* * Is the certificate trust chain valid and trusted? */ if (SSL_get_verify_result(TLScontext->con) == X509_V_OK) TLScontext->peer_status |= TLS_CERT_FLAG_TRUSTED; if (TLS_CERT_IS_TRUSTED(TLScontext) && props->tls_level >= TLS_LEV_VERIFY) verify_peername = 1; /* Force cert processing so we can log the data? */ log_certmatch = TLScontext->log_mask & TLS_LOG_CERTMATCH; /* Log cert details when processing? */ verbose = log_certmatch || (TLScontext->log_mask & TLS_LOG_VERBOSE); if (verify_peername || log_certmatch) { /* * Verify the dNSName(s) in the peer certificate against the nexthop * and hostname. * * If DNS names are present, we use the first matching (or else simply * the first) DNS name as the subject CN. The CommonName in the * issuer DN is obsolete when SubjectAltName is available. This * yields much less surprising logs, because we log the name we * verified or a name we checked and failed to match. * * XXX: The nexthop and host name may both be the same network address * rather than a DNS name. In this case we really should be looking * for GEN_IPADD entries, not GEN_DNS entries. * * XXX: In ideal world the caller who used the address to build the * connection would tell us that the nexthop is the connection * address, but if that is not practical, we can parse the nexthop * again here. */ gens = X509_get_ext_d2i(peercert, NID_subject_alt_name, 0, 0); if (gens) { r = sk_GENERAL_NAME_num(gens); for (i = 0; i < r; ++i) { gn = sk_GENERAL_NAME_value(gens, i); if (gn->type != GEN_DNS) continue; /* * Even if we have an invalid DNS name, we still ultimately * ignore the CommonName, because subjectAltName:DNS is * present (though malformed). Replace any previous peer_CN * if empty or we get a match. * * We always set at least an empty peer_CN if the ALTNAME cert * flag is set. If not, we set peer_CN from the cert * CommonName below, so peer_CN is always non-null on return. */ TLScontext->peer_status |= TLS_CERT_FLAG_ALTNAME; dnsname = tls_dns_name(gn, TLScontext); if (dnsname && *dnsname) { if ((dnsname_match = match_hostname(dnsname, props)) != 0) matched++; /* Keep the first matched name. */ if (TLScontext->peer_CN && ((dnsname_match && matched == 1) || *TLScontext->peer_CN == 0)) { myfree(TLScontext->peer_CN); TLScontext->peer_CN = 0; } if (verbose) msg_info("%s: %ssubjectAltName: %s", props->namaddr, dnsname_match ? "Matched " : "", dnsname); } if (TLScontext->peer_CN == 0) TLScontext->peer_CN = mystrdup(dnsname ? dnsname : ""); if (matched && !log_certmatch) break; } if (verify_peername && matched) TLScontext->peer_status |= TLS_CERT_FLAG_MATCHED; /* * (Sam Rushing, Ironport) Free stack *and* member GENERAL_NAME * objects */ sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); } /* * No subjectAltNames, peer_CN is taken from CommonName. */ if (TLScontext->peer_CN == 0) { TLScontext->peer_CN = tls_peer_CN(peercert, TLScontext); if (*TLScontext->peer_CN) matched = match_hostname(TLScontext->peer_CN, props); if (verify_peername && matched) TLScontext->peer_status |= TLS_CERT_FLAG_MATCHED; if (verbose) msg_info("%s %sCommonName %s", props->namaddr, matched ? "Matched " : "", TLScontext->peer_CN); } else if (verbose) { char *tmpcn = tls_peer_CN(peercert, TLScontext); /* * Though the CommonName was superceded by a subjectAltName, log * it when certificate match debugging was requested. */ msg_info("%s CommonName %s", TLScontext->namaddr, tmpcn); myfree(tmpcn); } } else TLScontext->peer_CN = tls_peer_CN(peercert, TLScontext); /* * Give them a clue. Problems with trust chain verification were logged * when the session was first negotiated, before the session was stored * into the cache. We don't want mystery failures, so log the fact the * real problem is to be found in the past. */ if (TLScontext->session_reused && !TLS_CERT_IS_TRUSTED(TLScontext) && (TLScontext->log_mask & TLS_LOG_UNTRUSTED)) msg_info("%s: re-using session with untrusted certificate, " "look for details earlier in the log", props->namaddr); }
char *http_multipart_post(char *uri, char **names, char **parts, int *plens, char *user, char *pass, int *ret, int *len) { void *ctx; char *data = NULL, *tmp, *p; int dlen = 0, i, j; unsigned char hash[16]; unsigned char boundary[32], ch; int blen = 0; unsigned int map[62], m; struct md5_context md5; //struct md5_context md52; int own_plen = 0; if(names) { if(!plens) { own_plen = 1; for(i=0;names[i];i++) ; plens = calloc(i, sizeof(int)); for(i=0;names[i];i++) plens[i] = strlen(parts[i]); } retry: if(blen >= 31) goto fail; memset(map, 0, 62*sizeof(int)); for(i=0;names[i];i++) { for(j=0;j<plens[i]-blen;j++) if(!blen || !memcmp(parts[i]+j, boundary, blen)) { ch = parts[i][j+blen]; if(ch>='0' && ch<='9') map[ch-'0']++; else if(ch>='A' && ch<='Z') map[ch-'A'+10]++; else if(ch>='a' && ch<='z') map[ch-'a'+36]++; } } m = ~0; j = 61; for(i=0;i<62;i++) if(map[i]<m) { m = map[i]; j = i; } if(j<10) boundary[blen] = '0'+j; else if(j<36) boundary[blen] = 'A'+(j-10); else boundary[blen] = 'a'+(j-36); blen++; if(map[j]) goto retry; boundary[blen] = 0; for(i=0;names[i];i++) dlen += blen+strlen(names[i])+plens[i]+128; dlen += blen+8; data = malloc(dlen); dlen = 0; for(i=0;names[i];i++) { dlen += sprintf(data+dlen, "--%s\r\n", boundary); dlen += sprintf(data+dlen, "Content-transfer-encoding: binary\r\n"); if(strchr(names[i], ':')) { tmp = mystrdup(names[i]); p = strchr(tmp, ':'); *p = 0; dlen += sprintf(data+dlen, "content-disposition: form-data; name=\"%s\"; ", tmp); free(tmp); p = strchr(names[i], ':'); dlen += sprintf(data+dlen, "filename=\"%s\"\r\n\r\n", p+1); } else dlen += sprintf(data+dlen, "content-disposition: form-data; name=\"%s\"\r\n\r\n", names[i]); memcpy(data+dlen, parts[i], plens[i]); dlen += plens[i]; dlen += sprintf(data+dlen, "\r\n"); } dlen += sprintf(data+dlen, "--%s--\r\n", boundary); } ctx = http_async_req_start(NULL, uri, data, dlen, 0); if(!ctx) goto fail; if(user) { http_async_add_header(ctx, "X-Auth-User", user); if(pass) { md5_init(&md5); md5_update(&md5, (unsigned char *)user, strlen(user)); md5_update(&md5, (unsigned char *)"-", 1); m = 0; if(names) { for(i=0;names[i];i++) { //md5_update(&md5, (unsigned char *)parts[i], plens[i]); //WHY? //md5_update(&md5, (unsigned char *)"-", 1); p = strchr(names[i], ':'); if(p) m += (p - names[i]) + 1; else m += strlen(names[i])+1; } tmp = malloc(m); m = 0; for(i=0;names[i];i++) { p = strchr(names[i], ':'); if(m) { tmp[m] = ' '; m ++; } if(p) { memcpy(tmp+m, names[i], p-names[i]); m += p - names[i]; } else { strcpy(tmp+m, names[i]); m += strlen(names[i]); } } tmp[m] = 0; http_async_add_header(ctx, "X-Auth-Objects", tmp); free(tmp); } md5_update(&md5, (unsigned char *)pass, strlen(pass)); md5_final(hash, &md5); tmp = malloc(33); for(i=0;i<16;i++) { tmp[i*2] = hex[hash[i]>>4]; tmp[i*2+1] = hex[hash[i]&15]; } tmp[32] = 0; http_async_add_header(ctx, "X-Auth-Hash", tmp); free(tmp); } } if(data) { tmp = malloc(32+strlen((char *)boundary)); sprintf(tmp, "multipart/form-data, boundary=%s", boundary); http_async_add_header(ctx, "Content-type", tmp); free(tmp); free(data); } if(own_plen) free(plens); return http_async_req_stop(ctx, ret, len); fail: if(data) free(data); if(own_plen) free(plens); if(ret) *ret = 600; if(len) *len = 0; return NULL; }
void * dnsprchild(void * data) { #define param ((struct clientparam*)data) unsigned long ip = 0; unsigned char *buf, *s1, *s2; char * host = NULL; unsigned char c; SASIZETYPE size; int res, i; int len; unsigned type=0; unsigned ttl; #ifdef _WIN32 unsigned long ul; #endif if(!(buf = myalloc(BUFSIZE))){ param->srvfds->events = POLLIN; RETURN (21); } size = sizeof(struct sockaddr_in); i = recvfrom(param->srvsock, buf, BUFSIZE, 0, (struct sockaddr *)¶m->sinc, &size); #ifdef _WIN32 if((param->clisock=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) { RETURN(818); } if(setsockopt(param->clisock, SOL_SOCKET, SO_REUSEADDR, (unsigned char *)&ul, sizeof(int))) {RETURN(820);}; ioctlsocket(param->clisock, FIONBIO, &ul); size = sizeof(struct sockaddr_in); if(getsockname(param->srvsock, (struct sockaddr *)¶m->sins, &size)) {RETURN(21);}; if(bind(param->clisock,(struct sockaddr *)¶m->sins,sizeof(struct sockaddr_in))) { RETURN(822); } #else param->clisock = param->srvsock; #endif param->srvfds->events = POLLIN; if(i < 0) { RETURN(813); } buf[BUFSIZE - 1] = 0; if(i<=13 || i>1000){ RETURN (814); } param->operation = DNSRESOLVE; if((res = (*param->authfunc)(param))) {RETURN(res);} if(buf[4]!=0 || buf[5]!=1) RETURN(816); for(len = 12; len<i; len+=(c+1)){ c = buf[len]; if(!c)break; buf[len] = '.'; } if(len > (i-4)) {RETURN(817);} host = mystrdup((char *)buf+13); if(!host) {RETURN(21);} for(s2 = buf + 12; (s1 = (unsigned char *)strchr((char *)s2 + 1, '.')); s2 = s1)*s2 = (unsigned char)((s1 - s2) - 1); *s2 = (len - (s2 - buf)) - 1; type = ((unsigned)buf[len+1])*256 + (unsigned)buf[len+2]; if(type==1){ ip = udpresolve((unsigned char *)host, &ttl, param); } len+=5; if(ip){ buf[2] = 0x85; buf[3] = 0x80; buf[6] = 0; buf[7] = 1; buf[8] = buf[9] = buf[10] = buf[11] = 0; memset(buf+len, 0, 16); buf[len] = 0xc0; buf[len+1] = 0x0c; buf[len+3] = 1; buf[len+5] = 1; ttl = htonl(ttl); memcpy(buf + len + 6, &ttl, 4); buf[len+11] = 4; memcpy(buf+len+12,(void *)&ip,4); len+=16; } if(type == 0x0c) { unsigned a, b, c, d; sscanf(host, "%u.%u.%u.%u", &a, &b, &c, &d); ip = htonl((d<<24) ^ (c<<16) ^ (b<<8) ^ a); if(ip == param->intip){ buf[2] = 0x85; buf[3] = 0x80; buf[6] = 0; buf[7] = 1; buf[8] = buf[9] = buf[10] = buf[11] = 0; memset(buf+len, 0, 20); buf[len] = 0xc0; buf[len+1] = 0x0c; buf[len+3] = 0x0c; buf[len+5] = 1; ttl = htonl(3600); memcpy(buf + len + 6, &ttl, 4); buf[len+11] = 7; buf[len+12] = 6; memcpy(buf+len+13,(void *)"3proxy",6); len+=20; } else ip = 0; } if(!ip && nservers[0] && type!=1){ if((param->remsock=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) { RETURN(818); } #ifdef _WIN32 ioctlsocket(param->remsock, FIONBIO, &ul); #else fcntl(param->remsock,F_SETFL,O_NONBLOCK); #endif param->sins.sin_family = AF_INET; param->sins.sin_port = htons(0); param->sins.sin_addr.s_addr = htonl(0); if(bind(param->remsock,(struct sockaddr *)¶m->sins,sizeof(struct sockaddr_in))) { RETURN(819); } param->sins.sin_addr.s_addr = nservers[0]; param->sins.sin_port = htons(53); if(socksendto(param->remsock, ¶m->sins, buf, i, conf.timeouts[SINGLEBYTE_L]*1000) != i){ RETURN(820); } param->statscli += i; len = sockrecvfrom(param->remsock, ¶m->sins, buf, BUFSIZE, 15000); if(len <= 13) { RETURN(821); } param->statssrv += len; if(buf[6] || buf[7]){ if(socksendto(param->clisock, ¶m->sinc, buf, len, conf.timeouts[SINGLEBYTE_L]*1000) != len){ RETURN(822); } RETURN(0); } } if(!ip) { buf[2] = 0x85; buf[3] = 0x83; } usleep(SLEEPTIME); res = socksendto(param->clisock, ¶m->sinc, buf, len, conf.timeouts[SINGLEBYTE_L]*1000); if(res != len){RETURN(819);} if(!ip) {RETURN(888);} CLEANRET: if(param->res!=813){ sprintf((char *)buf, "%04x/%s(%u.%u.%u.%u) ", (unsigned)type, host, (unsigned)(ntohl(ip)&0xff000000)>>24, (unsigned)(ntohl(ip)&0x00ff0000)>>16, (unsigned)(ntohl(ip)&0x0000ff00)>>8, (unsigned)(ntohl(ip)&0x000000ff) ); (*param->logfunc)(param, buf); }
/****************************************************************** Opens a read window *******************************************************************/ int read_window_open(char *folder, struct mail *mail, int window) { int num; struct Read_Data *data; for (num=0; num < MAX_READ_OPEN; num++) if (!read_open[num]) break; if (num == MAX_READ_OPEN) return -1; if ((data = (struct Read_Data*)malloc(sizeof(struct Read_Data)))) { GtkWidget *vbox; memset(data,0,sizeof(struct Read_Data)); data->folder_path = mystrdup(folder); data->num = num; read_open[num] = data; data->wnd = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(data->wnd), "SimpleMail - Read mail"); gtk_window_set_default_size(GTK_WINDOW(data->wnd),640,400); gtk_window_set_position(GTK_WINDOW(data->wnd),GTK_WIN_POS_CENTER); gtk_signal_connect(GTK_OBJECT(data->wnd), "destroy",GTK_SIGNAL_FUNC (read_window_dispose), data); vbox = gtk_vbox_new(0,4); gtk_container_add(GTK_CONTAINER(data->wnd), vbox); data->toolbar = gtk_toolbar_new(); gtk_box_pack_start(GTK_BOX(vbox), data->toolbar, FALSE, FALSE, 0 /* Padding */); /* only use minimal height */ gtk_toolbar_append_item(GTK_TOOLBAR(data->toolbar), "Prev", "", NULL /* private TT */, create_pixmap(data->wnd,"MailPrev.xpm"), NULL /* CALLBACK */, NULL /* UDATA */); gtk_toolbar_append_item(GTK_TOOLBAR(data->toolbar), "Next", "", NULL /* private TT */, create_pixmap(data->wnd,"MailNext.xpm"), NULL/* CALLBACK */, NULL /* UDATA */); gtk_toolbar_append_space(GTK_TOOLBAR(data->toolbar)); gtk_toolbar_append_item(GTK_TOOLBAR(data->toolbar), "Save", "", NULL /* private TT */, create_pixmap(data->wnd,"MailSave.xpm"), NULL /* CALLBACK */, NULL /* UDATA */); gtk_toolbar_append_item(GTK_TOOLBAR(data->toolbar), "Print", "", NULL /* private TT */, create_pixmap(data->wnd,"Print.xpm"), NULL /* CALLBACK */, NULL /* UDATA */); gtk_toolbar_append_space(GTK_TOOLBAR(data->toolbar)); gtk_toolbar_append_item(GTK_TOOLBAR(data->toolbar), "Delete", "", NULL /* private TT */, create_pixmap(data->wnd,"MailDelete.xpm"), NULL /* CALLBACK */, NULL /* UDATA */); gtk_toolbar_append_item(GTK_TOOLBAR(data->toolbar), "Reply", "", NULL /* private TT */, create_pixmap(data->wnd,"MailReply.xpm"), NULL /* CALLBACK */, NULL /* UDATA */); gtk_toolbar_append_item(GTK_TOOLBAR(data->toolbar), "Forward", "", NULL /* private TT */, create_pixmap(data->wnd,"MailForward.xpm"), NULL /* CALLBACK */, NULL /* UDATA */); data->text_scrolled_window = gtk_scrolled_window_new(NULL,NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(data->text_scrolled_window),GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC); /* create the html document */ data->html_document = html_document_new(); data->html_view = html_view_new(); gtk_container_add (GTK_CONTAINER (data->text_scrolled_window), data->html_view); gtk_box_pack_start(GTK_BOX(vbox), data->text_scrolled_window, TRUE, TRUE, 0 /* Padding */); /* only use minimal height */ /* FIXME: ugly ugly! sba: ??? */ html_view_set_document (HTML_VIEW (data->html_view), data->html_document); #if 0 data->text_view = gtk_text_view_new(); g_object_set(data->text_view, "editable", FALSE, NULL); gtk_container_add(GTK_CONTAINER(data->text_scrolled_window), data->text_view); gtk_box_pack_start(GTK_BOX(vbox), data->text_scrolled_window, TRUE, TRUE, 0 /* Padding */); /* only use minimal height */ #endif read_window_display_mail(data,mail); gtk_widget_show_all(data->wnd); } return num; }
void *http_async_req_start(void *ctx, char *uri, char *data, int dlen, int keep) { struct http_ctx *cx = ctx; if(!ctx) { ctx = calloc(1, sizeof(struct http_ctx)); cx = ctx; cx->fd = PERROR; } if(!cx->hbuf) { cx->hbuf = malloc(256); cx->hlen = 256; } if(!http_up) { cx->ret = 604; cx->state = HTS_DONE; return ctx; } if(cx->state!=HTS_STRT && cx->state!=HTS_IDLE) { fprintf(stderr, "HTTP: unclean request restart state.\n"); exit(1); } cx->keep = keep; cx->ret = 600; if(splituri(uri, &cx->host, &cx->path)) { cx->ret = 601; cx->state = HTS_DONE; return ctx; } if(http_use_proxy) { free(cx->path); cx->path = mystrdup(uri); } if(cx->fdhost && strcmp(cx->host, cx->fdhost)) { free(cx->fdhost); cx->fdhost = NULL; PCLOSE(cx->fd); cx->fd = PERROR; cx->state = HTS_STRT; } if(data) { if(!dlen) dlen = strlen(data); cx->txd = malloc(dlen); memcpy(cx->txd, data, dlen); cx->txdl = dlen; } else cx->txdl = 0; cx->contlen = 0; cx->chunked = 0; cx->chunkhdr = 0; cx->rxtogo = 0; cx->cclose = 0; cx->tptr = 0; cx->tlen = 0; cx->last = time(NULL); return ctx; }
void register_builtin_parameters(const char *procname, pid_t pid) { const char *myname = "register_builtin_parameters"; const CONFIG_TIME_TABLE *ctt; const CONFIG_BOOL_TABLE *cbt; const CONFIG_INT_TABLE *cit; const CONFIG_STR_TABLE *cst; const CONFIG_STR_FN_TABLE *cft; const CONFIG_RAW_TABLE *rst; const CONFIG_NINT_TABLE *nst; const CONFIG_NBOOL_TABLE *bst; const CONFIG_LONG_TABLE *lst; /* * Sanity checks. */ if (param_table != 0) msg_panic("%s: global parameter table is already initialized", myname); /* * Initialize the global parameter table. */ param_table = PC_PARAM_TABLE_CREATE(1000); /* * Add the built-in parameters to the global name space. The class * (built-in) is tentative; some parameters are actually service-defined, * but they have their own default value. */ for (ctt = time_table; ctt->name; ctt++) PC_PARAM_TABLE_ENTER(param_table, ctt->name, PC_PARAM_FLAG_BUILTIN, (char *) ctt, convert_time_parameter); for (cbt = bool_table; cbt->name; cbt++) PC_PARAM_TABLE_ENTER(param_table, cbt->name, PC_PARAM_FLAG_BUILTIN, (char *) cbt, convert_bool_parameter); for (cit = int_table; cit->name; cit++) PC_PARAM_TABLE_ENTER(param_table, cit->name, PC_PARAM_FLAG_BUILTIN, (char *) cit, convert_int_parameter); for (cst = str_table; cst->name; cst++) PC_PARAM_TABLE_ENTER(param_table, cst->name, PC_PARAM_FLAG_BUILTIN, (char *) cst, convert_str_parameter); for (cft = str_fn_table; cft->name; cft++) PC_PARAM_TABLE_ENTER(param_table, cft->name, PC_PARAM_FLAG_BUILTIN, (char *) cft, convert_str_fn_parameter); for (rst = raw_table; rst->name; rst++) PC_PARAM_TABLE_ENTER(param_table, rst->name, PC_PARAM_FLAG_BUILTIN | PC_PARAM_FLAG_RAW, (char *) rst, convert_raw_parameter); for (nst = nint_table; nst->name; nst++) PC_PARAM_TABLE_ENTER(param_table, nst->name, PC_PARAM_FLAG_BUILTIN, (char *) nst, convert_nint_parameter); for (bst = nbool_table; bst->name; bst++) PC_PARAM_TABLE_ENTER(param_table, bst->name, PC_PARAM_FLAG_BUILTIN, (char *) bst, convert_nbool_parameter); for (lst = long_table; lst->name; lst++) PC_PARAM_TABLE_ENTER(param_table, lst->name, PC_PARAM_FLAG_BUILTIN, (char *) lst, convert_long_parameter); /* * Register legacy parameters (used as a backwards-compatible migration * aid). */ for (cst = legacy_str_table; cst->name; cst++) PC_PARAM_TABLE_ENTER(param_table, cst->name, PC_PARAM_FLAG_LEGACY, (char *) cst, convert_str_parameter); /* * Register parameters whose default value is normally initialized by * ad-hoc code. */ adhoc_procname.defval = mystrdup(procname); PC_PARAM_TABLE_ENTER(param_table, adhoc_procname.name, PC_PARAM_FLAG_BUILTIN | PC_PARAM_FLAG_READONLY, (char *) &adhoc_procname, convert_str_parameter); adhoc_pid.defval = pid; PC_PARAM_TABLE_ENTER(param_table, adhoc_pid.name, PC_PARAM_FLAG_BUILTIN | PC_PARAM_FLAG_READONLY, (char *) &adhoc_pid, convert_int_parameter); }
NORETURN event_server_main(int argc, char **argv, MULTI_SERVER_FN service,...) { const char *myname = "event_server_main"; VSTREAM *stream = 0; char *root_dir = 0; char *user_name = 0; int debug_me = 0; int daemon_mode = 1; char *service_name = basename(argv[0]); int delay; int c; int fd; va_list ap; MAIL_SERVER_INIT_FN pre_init = 0; MAIL_SERVER_INIT_FN post_init = 0; MAIL_SERVER_LOOP_FN loop = 0; int key; char *transport = 0; #if 0 char *lock_path; VSTRING *why; #endif int alone = 0; int zerolimit = 0; WATCHDOG *watchdog; char *oname_val; char *oname; char *oval; const char *err; char *generation; int msg_vstream_needed = 0; int redo_syslog_init = 0; /* * Process environment options as early as we can. */ if (getenv(CONF_ENV_VERB)) msg_verbose = 1; if (getenv(CONF_ENV_DEBUG)) debug_me = 1; /* * Don't die when a process goes away unexpectedly. */ signal(SIGPIPE, SIG_IGN); /* * Don't die for frivolous reasons. */ #ifdef SIGXFSZ signal(SIGXFSZ, SIG_IGN); #endif /* * May need this every now and then. */ var_procname = mystrdup(basename(argv[0])); set_mail_conf_str(VAR_PROCNAME, var_procname); /* * Initialize logging and exit handler. Do the syslog first, so that its * initialization completes before we enter the optional chroot jail. */ msg_syslog_init(mail_task(var_procname), LOG_PID, LOG_FACILITY); if (msg_verbose) msg_info("daemon started"); /* * Check the Postfix library version as soon as we enable logging. */ MAIL_VERSION_CHECK; /* * Initialize from the configuration file. Allow command-line options to * override compiled-in defaults or configured parameter values. */ mail_conf_suck(); /* * Register dictionaries that use higher-level interfaces and protocols. */ mail_dict_init(); /* * After database open error, continue execution with reduced * functionality. */ dict_allow_surrogate = 1; /* * Pick up policy settings from master process. Shut up error messages to * stderr, because no-one is going to see them. */ opterr = 0; while ((c = GETOPT(argc, argv, "cdDi:lm:n:o:s:St:uvVz")) > 0) { switch (c) { case 'c': root_dir = "setme"; break; case 'd': daemon_mode = 0; break; case 'D': debug_me = 1; break; case 'i': mail_conf_update(VAR_MAX_IDLE, optarg); break; case 'l': alone = 1; break; case 'm': mail_conf_update(VAR_MAX_USE, optarg); break; case 'n': service_name = optarg; break; case 'o': oname_val = mystrdup(optarg); if ((err = split_nameval(oname_val, &oname, &oval)) != 0) msg_fatal("invalid \"-o %s\" option value: %s", optarg, err); mail_conf_update(oname, oval); if (strcmp(oname, VAR_SYSLOG_NAME) == 0) redo_syslog_init = 1; myfree(oname_val); break; case 's': if ((socket_count = atoi(optarg)) <= 0) msg_fatal("invalid socket_count: %s", optarg); break; case 'S': stream = VSTREAM_IN; break; case 'u': user_name = "setme"; break; case 't': transport = optarg; break; case 'v': msg_verbose++; break; case 'V': if (++msg_vstream_needed == 1) msg_vstream_init(mail_task(var_procname), VSTREAM_ERR); break; case 'z': zerolimit = 1; break; default: msg_fatal("invalid option: %c", c); break; } } /* * Initialize generic parameters. */ mail_params_init(); if (redo_syslog_init) msg_syslog_init(mail_task(var_procname), LOG_PID, LOG_FACILITY); /* * If not connected to stdin, stdin must not be a terminal. */ if (daemon_mode && stream == 0 && isatty(STDIN_FILENO)) { msg_vstream_init(var_procname, VSTREAM_ERR); msg_fatal("do not run this command by hand"); } /* * Application-specific initialization. */ va_start(ap, service); while ((key = va_arg(ap, int)) != 0) { switch (key) { case MAIL_SERVER_INT_TABLE: get_mail_conf_int_table(va_arg(ap, CONFIG_INT_TABLE *)); break; case MAIL_SERVER_LONG_TABLE: get_mail_conf_long_table(va_arg(ap, CONFIG_LONG_TABLE *)); break; case MAIL_SERVER_STR_TABLE: get_mail_conf_str_table(va_arg(ap, CONFIG_STR_TABLE *)); break; case MAIL_SERVER_BOOL_TABLE: get_mail_conf_bool_table(va_arg(ap, CONFIG_BOOL_TABLE *)); break; case MAIL_SERVER_TIME_TABLE: get_mail_conf_time_table(va_arg(ap, CONFIG_TIME_TABLE *)); break; case MAIL_SERVER_RAW_TABLE: get_mail_conf_raw_table(va_arg(ap, CONFIG_RAW_TABLE *)); break; case MAIL_SERVER_NINT_TABLE: get_mail_conf_nint_table(va_arg(ap, CONFIG_NINT_TABLE *)); break; case MAIL_SERVER_NBOOL_TABLE: get_mail_conf_nbool_table(va_arg(ap, CONFIG_NBOOL_TABLE *)); break; case MAIL_SERVER_PRE_INIT: pre_init = va_arg(ap, MAIL_SERVER_INIT_FN); break; case MAIL_SERVER_POST_INIT: post_init = va_arg(ap, MAIL_SERVER_INIT_FN); break; case MAIL_SERVER_LOOP: loop = va_arg(ap, MAIL_SERVER_LOOP_FN); break; case MAIL_SERVER_EXIT: event_server_onexit = va_arg(ap, MAIL_SERVER_EXIT_FN); break; case MAIL_SERVER_PRE_ACCEPT: event_server_pre_accept = va_arg(ap, MAIL_SERVER_ACCEPT_FN); break; case MAIL_SERVER_PRE_DISCONN: event_server_pre_disconn = va_arg(ap, MAIL_SERVER_DISCONN_FN); break; case MAIL_SERVER_IN_FLOW_DELAY: event_server_in_flow_delay = 1; break; case MAIL_SERVER_SOLITARY: if (stream == 0 && !alone) msg_fatal("service %s requires a process limit of 1", service_name); break; case MAIL_SERVER_UNLIMITED: if (stream == 0 && !zerolimit) msg_fatal("service %s requires a process limit of 0", service_name); break; case MAIL_SERVER_PRIVILEGED: if (user_name) msg_fatal("service %s requires privileged operation", service_name); break; case MAIL_SERVER_WATCHDOG: event_server_watchdog = *va_arg(ap, int *); break; case MAIL_SERVER_SLOW_EXIT: event_server_slow_exit = va_arg(ap, MAIL_SERVER_SLOW_EXIT_FN); break; default: msg_panic("%s: unknown argument type: %d", myname, key); } } va_end(ap); if (root_dir) root_dir = var_queue_dir; if (user_name) user_name = var_mail_owner; /* * Can options be required? */ if (stream == 0) { if (transport == 0) msg_fatal("no transport type specified"); if (strcasecmp(transport, MASTER_XPORT_NAME_INET) == 0) event_server_accept = event_server_accept_inet; else if (strcasecmp(transport, MASTER_XPORT_NAME_UNIX) == 0) event_server_accept = event_server_accept_local; #ifdef MASTER_XPORT_NAME_PASS else if (strcasecmp(transport, MASTER_XPORT_NAME_PASS) == 0) event_server_accept = event_server_accept_pass; #endif else msg_fatal("unsupported transport type: %s", transport); } /* * Retrieve process generation from environment. */ if ((generation = getenv(MASTER_GEN_NAME)) != 0) { if (!alldig(generation)) msg_fatal("bad generation: %s", generation); OCTAL_TO_UNSIGNED(event_server_generation, generation); if (msg_verbose) msg_info("process generation: %s (%o)", generation, event_server_generation); } /* * Optionally start the debugger on ourself. */ if (debug_me) debug_process(); /* * Traditionally, BSD select() can't handle multiple processes selecting * on the same socket, and wakes up every process in select(). See TCP/IP * Illustrated volume 2 page 532. We avoid select() collisions with an * external lock file. */ /* * XXX Can't compete for exclusive access to the listen socket because we * also have to monitor existing client connections for service requests. */ #if 0 if (stream == 0 && !alone) { lock_path = concatenate(DEF_PID_DIR, "/", transport, ".", service_name, (char *) 0); why = vstring_alloc(1); if ((event_server_lock = safe_open(lock_path, O_CREAT | O_RDWR, 0600, (struct stat *) 0, -1, -1, why)) == 0) msg_fatal("open lock file %s: %s", lock_path, vstring_str(why)); close_on_exec(vstream_fileno(event_server_lock), CLOSE_ON_EXEC); myfree(lock_path); vstring_free(why); } #endif /* * Set up call-back info. */ event_server_service = service; event_server_name = service_name; event_server_argv = argv + optind; /* * Run pre-jail initialization. */ if (chdir(var_queue_dir) < 0) msg_fatal("chdir(\"%s\"): %m", var_queue_dir); if (pre_init) pre_init(event_server_name, event_server_argv); /* * Optionally, restrict the damage that this process can do. */ resolve_local_init(); tzset(); chroot_uid(root_dir, user_name); /* * Run post-jail initialization. */ if (post_init) post_init(event_server_name, event_server_argv); /* * Are we running as a one-shot server with the client connection on * standard input? If so, make sure the output is written to stdout so as * to satisfy common expectation. */ if (stream != 0) { vstream_control(stream, VSTREAM_CTL_DOUBLE, VSTREAM_CTL_WRITE_FD, STDOUT_FILENO, VSTREAM_CTL_END); service(stream, event_server_name, event_server_argv); vstream_fflush(stream); event_server_exit(); } /* * Running as a semi-resident server. Service connection requests. * Terminate when we have serviced a sufficient number of clients, when * no-one has been talking to us for a configurable amount of time, or * when the master process terminated abnormally. */ if (var_idle_limit > 0) event_request_timer(event_server_timeout, (char *) 0, var_idle_limit); for (fd = MASTER_LISTEN_FD; fd < MASTER_LISTEN_FD + socket_count; fd++) { event_enable_read(fd, event_server_accept, CAST_INT_TO_CHAR_PTR(fd)); close_on_exec(fd, CLOSE_ON_EXEC); } event_enable_read(MASTER_STATUS_FD, event_server_abort, (char *) 0); close_on_exec(MASTER_STATUS_FD, CLOSE_ON_EXEC); close_on_exec(MASTER_FLOW_READ, CLOSE_ON_EXEC); close_on_exec(MASTER_FLOW_WRITE, CLOSE_ON_EXEC); watchdog = watchdog_create(event_server_watchdog, (WATCHDOG_FN) 0, (char *) 0); /* * The event loop, at last. */ while (var_use_limit == 0 || use_count < var_use_limit || client_count > 0) { if (event_server_lock != 0) { watchdog_stop(watchdog); if (myflock(vstream_fileno(event_server_lock), INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0) msg_fatal("select lock: %m"); } watchdog_start(watchdog); delay = loop ? loop(event_server_name, event_server_argv) : -1; event_loop(delay); } event_server_exit(); }
/** * FOLDERINFO ARexx command * * @param rxmsg the message defining the ARexx context * @param args the command's arguments */ static void arexx_folderinfo(struct RexxMsg *rxmsg, STRPTR args) { APTR arg_handle; struct { STRPTR var; STRPTR stem; STRPTR folder; } folderinfo_arg; memset(&folderinfo_arg,0,sizeof(folderinfo_arg)); if ((arg_handle = ParseTemplate("VAR/K,STEM/K,FOLDER",args,&folderinfo_arg))) { struct folder *folder; if (folderinfo_arg.folder) folder = folder_find_by_name(folderinfo_arg.folder); else folder = main_get_folder(); if (folder) { int folder_size = folder_size_of_mails(folder); int folder_type; if (folder == folder_incoming()) folder_type = 1; else if (folder == folder_outgoing()) folder_type = 2; else if (folder == folder_sent()) folder_type = 3; else if (folder == folder_deleted()) folder_type = 4; else if (folder->type == FOLDER_TYPE_SEND) folder_type = 5; else if (folder->type == FOLDER_TYPE_SENDRECV) folder_type = 6; else if (folder->special == FOLDER_SPECIAL_GROUP) folder_type = 7; else if (folder == folder_spam()) folder_type = 8; else folder_type = 0; if (folderinfo_arg.stem) { int stem_len = strlen(folderinfo_arg.stem); char *stem_buf = (char *)malloc(stem_len+20); if (stem_buf) { strcpy(stem_buf,folderinfo_arg.stem); strcpy(&stem_buf[stem_len],"NUMBER"); arexx_set_var_int(rxmsg,stem_buf,folder_position(folder)); strcpy(&stem_buf[stem_len],"NAME"); MySetRexxVarFromMsg(stem_buf,folder->name,rxmsg); strcpy(&stem_buf[stem_len],"PATH"); MySetRexxVarFromMsg(stem_buf,folder->path,rxmsg); strcpy(&stem_buf[stem_len],"TOTAL"); arexx_set_var_int(rxmsg,stem_buf,folder->num_mails); strcpy(&stem_buf[stem_len],"NEW"); arexx_set_var_int(rxmsg,stem_buf,folder->new_mails); strcpy(&stem_buf[stem_len],"UNREAD"); arexx_set_var_int(rxmsg,stem_buf,folder->unread_mails); strcpy(&stem_buf[stem_len],"SIZE"); arexx_set_var_int(rxmsg,stem_buf,folder_size); strcpy(&stem_buf[stem_len],"TYPE"); arexx_set_var_int(rxmsg,stem_buf,folder_type); free(stem_buf); } } else { char *str; char num_buf[24]; sprintf(num_buf,"%d",folder_position(folder)); str = mystrdup(num_buf); str = stradd(str," \""); str = stradd(str,folder->name); str = stradd(str,"\" \""); str = stradd(str,folder->path); str = stradd(str,"\" "); sprintf(num_buf,"%d",folder->num_mails); str = stradd(str,num_buf); str = stradd(str," "); sprintf(num_buf,"%d",folder->new_mails); str = stradd(str,num_buf); str = stradd(str," "); sprintf(num_buf,"%d",folder->unread_mails); str = stradd(str,num_buf); str = stradd(str," "); sprintf(num_buf,"%d",folder_size); str = stradd(str,num_buf); str = stradd(str," "); sprintf(num_buf,"%d",folder_type); str = stradd(str,num_buf); if (folderinfo_arg.var) MySetRexxVarFromMsg(folderinfo_arg.var,str,rxmsg); else arexx_set_result(rxmsg,str); free(str); } } FreeTemplate(arg_handle); } }
static void resolve_addr(RES_CONTEXT *rp, char *sender, char *addr, VSTRING *channel, VSTRING *nexthop, VSTRING *nextrcpt, int *flags) { const char *myname = "resolve_addr"; VSTRING *addr_buf = vstring_alloc(100); TOK822 *tree = 0; TOK822 *saved_domain = 0; TOK822 *domain = 0; char *destination; const char *blame = 0; const char *rcpt_domain; ssize_t addr_len; ssize_t loop_count; ssize_t loop_max; char *local; char *oper; char *junk; const char *relay; const char *xport; const char *sender_key; int rc; *flags = 0; vstring_strcpy(channel, "CHANNEL NOT UPDATED"); vstring_strcpy(nexthop, "NEXTHOP NOT UPDATED"); vstring_strcpy(nextrcpt, "NEXTRCPT NOT UPDATED"); /* * The address is in internalized (unquoted) form. * * In an ideal world we would parse the externalized address form as given * to us by the sender. * * However, in the real world we have to look for routing characters like * %@! in the address local-part, even when that information is quoted * due to the presence of special characters or whitespace. Although * technically incorrect, this is needed to stop user@domain@domain relay * attempts when forwarding mail to a Sendmail MX host. * * This suggests that we parse the address in internalized (unquoted) form. * Unfortunately, if we do that, the unparser generates incorrect white * space between adjacent non-operator tokens. Example: ``first last'' * needs white space, but ``stuff[stuff]'' does not. This is is not a * problem when unparsing the result from parsing externalized forms, * because the parser/unparser were designed for valid externalized forms * where ``stuff[stuff]'' does not happen. * * As a workaround we start with the quoted form and then dequote the * local-part only where needed. This will do the right thing in most * (but not all) cases. */ addr_len = strlen(addr); quote_822_local(addr_buf, addr); tree = tok822_scan_addr(vstring_str(addr_buf)); /* * The optimizer will eliminate tests that always fail, and will replace * multiple expansions of this macro by a GOTO to a single instance. */ #define FREE_MEMORY_AND_RETURN { \ if (saved_domain) \ tok822_free_tree(saved_domain); \ if(tree) \ tok822_free_tree(tree); \ if (addr_buf) \ vstring_free(addr_buf); \ return; \ } /* * Preliminary resolver: strip off all instances of the local domain. * Terminate when no destination domain is left over, or when the * destination domain is remote. * * XXX To whom it may concern. If you change the resolver loop below, or * quote_822_local.c, or tok822_parse.c, be sure to re-run the tests * under "make resolve_clnt_test" in the global directory. */ #define RESOLVE_LOCAL(domain) \ resolve_local(STR(tok822_internalize(addr_buf, domain, TOK822_STR_DEFL))) for (loop_count = 0, loop_max = addr_len + 100; /* void */ ; loop_count++) { /* * XXX Should never happen, but if this happens with some * pathological address, then that is not sufficient reason to * disrupt the operation of an MTA. */ if (loop_count > loop_max) { msg_warn("resolve_addr: <%s>: giving up after %ld iterations", addr, (long) loop_count); *flags |= RESOLVE_FLAG_FAIL; FREE_MEMORY_AND_RETURN; break; } /* * Strip trailing dot at end of domain, but not dot-dot or at-dot. * This merely makes diagnostics more accurate by leaving bogus * addresses alone. */ if (tree->tail && tree->tail->type == '.' && tok822_rfind_type(tree->tail, '@') != 0 && tree->tail->prev->type != '.' && tree->tail->prev->type != '@') tok822_free_tree(tok822_sub_keep_before(tree, tree->tail)); /* * Strip trailing @. */ if (var_resolve_nulldom && tree->tail && tree->tail->type == '@') tok822_free_tree(tok822_sub_keep_before(tree, tree->tail)); /* * Strip (and save) @domain if local. * * Grr. resolve_local() table lookups may fail. It may be OK for local * file lookup code to abort upon failure, but with network-based * tables it is preferable to return an error indication to the * requestor. */ if ((domain = tok822_rfind_type(tree->tail, '@')) != 0) { if (domain->next && (rc = RESOLVE_LOCAL(domain->next)) <= 0) { if (rc < 0) { *flags |= RESOLVE_FLAG_FAIL; FREE_MEMORY_AND_RETURN; } break; } tok822_sub_keep_before(tree, domain); if (saved_domain) tok822_free_tree(saved_domain); saved_domain = domain; domain = 0; /* safety for future change */ } /* * After stripping the local domain, if any, replace foo%bar by * foo@bar, site!user by user@site, rewrite to canonical form, and * retry. */ if (tok822_rfind_type(tree->tail, '@') || (var_swap_bangpath && tok822_rfind_type(tree->tail, '!')) || (var_percent_hack && tok822_rfind_type(tree->tail, '%'))) { rewrite_tree(&local_context, tree); continue; } /* * If the local-part is a quoted string, crack it open when we're * permitted to do so and look for routing operators. This is * technically incorrect, but is needed to stop relaying problems. * * XXX Do another feeble attempt to keep local-part info quoted. */ if (var_resolve_dequoted && tree->head && tree->head == tree->tail && tree->head->type == TOK822_QSTRING && ((oper = strrchr(local = STR(tree->head->vstr), '@')) != 0 || (var_percent_hack && (oper = strrchr(local, '%')) != 0) || (var_swap_bangpath && (oper = strrchr(local, '!')) != 0))) { if (*oper == '%') *oper = '@'; tok822_internalize(addr_buf, tree->head, TOK822_STR_DEFL); if (*oper == '@') { junk = mystrdup(STR(addr_buf)); quote_822_local(addr_buf, junk); myfree(junk); } tok822_free(tree->head); tree->head = tok822_scan(STR(addr_buf), &tree->tail); rewrite_tree(&local_context, tree); continue; } /* * An empty local-part or an empty quoted string local-part becomes * the local MAILER-DAEMON, for consistency with our own From: * message headers. */ if (tree->head && tree->head == tree->tail && tree->head->type == TOK822_QSTRING && VSTRING_LEN(tree->head->vstr) == 0) { tok822_free(tree->head); tree->head = 0; } /* XXX Re-resolve the surrogate, in case already in user@domain form. */ if (tree->head == 0) { tree->head = tok822_scan(var_empty_addr, &tree->tail); continue; } /* XXX Re-resolve with @$myhostname for backwards compatibility. */ if (domain == 0 && saved_domain == 0) { tok822_sub_append(tree, tok822_alloc('@', (char *) 0)); tok822_sub_append(tree, tok822_scan(var_myhostname, (TOK822 **) 0)); continue; } /* * We're done. There are no domains left to strip off the address, * and all null local-part information is sanitized. */ domain = 0; break; } vstring_free(addr_buf); addr_buf = 0; /* * Make sure the resolved envelope recipient has the user@domain form. If * no domain was specified in the address, assume the local machine. See * above for what happens with an empty address. */ if (domain == 0) { if (saved_domain) { tok822_sub_append(tree, saved_domain); saved_domain = 0; } else { tok822_sub_append(tree, tok822_alloc('@', (char *) 0)); tok822_sub_append(tree, tok822_scan(var_myhostname, (TOK822 **) 0)); } } /* * Transform the recipient address back to internal form. * * XXX This may produce incorrect results if we cracked open a quoted * local-part with routing operators; see discussion above at the top of * the big loop. * * XXX We explicitly disallow domain names in bare network address form. A * network address destination should be formatted according to RFC 2821: * it should be enclosed in [], and an IPv6 address should have an IPv6: * prefix. */ tok822_internalize(nextrcpt, tree, TOK822_STR_DEFL); rcpt_domain = strrchr(STR(nextrcpt), '@') + 1; if (rcpt_domain == 0) msg_panic("no @ in address: \"%s\"", STR(nextrcpt)); if (*rcpt_domain == '[') { if (!valid_mailhost_literal(rcpt_domain, DONT_GRIPE)) *flags |= RESOLVE_FLAG_ERROR; } else if (!valid_utf8_hostname(var_smtputf8_enable, rcpt_domain, DONT_GRIPE)) { if (var_resolve_num_dom && valid_hostaddr(rcpt_domain, DONT_GRIPE)) { vstring_insert(nextrcpt, rcpt_domain - STR(nextrcpt), "[", 1); vstring_strcat(nextrcpt, "]"); rcpt_domain = strrchr(STR(nextrcpt), '@') + 1; if ((rc = resolve_local(rcpt_domain)) > 0) /* XXX */ domain = 0; else if (rc < 0) { *flags |= RESOLVE_FLAG_FAIL; FREE_MEMORY_AND_RETURN; } } else { *flags |= RESOLVE_FLAG_ERROR; } } tok822_free_tree(tree); tree = 0; /* * XXX Short-cut invalid address forms. */ if (*flags & RESOLVE_FLAG_ERROR) { *flags |= RESOLVE_CLASS_DEFAULT; FREE_MEMORY_AND_RETURN; } /* * Recognize routing operators in the local-part, even when we do not * recognize ! or % as valid routing operators locally. This is needed to * prevent backup MX hosts from relaying third-party destinations through * primary MX hosts, otherwise the backup host could end up on black * lists. Ignore local swap_bangpath and percent_hack settings because we * can't know how the next MX host is set up. */ if (strcmp(STR(nextrcpt) + strcspn(STR(nextrcpt), "@!%") + 1, rcpt_domain)) *flags |= RESOLVE_FLAG_ROUTED; /* * With local, virtual, relay, or other non-local destinations, give the * highest precedence to transport associated nexthop information. * * Otherwise, with relay or other non-local destinations, the relayhost * setting overrides the recipient domain name, and the sender-dependent * relayhost overrides both. * * XXX Nag if the recipient domain is listed in multiple domain lists. The * result is implementation defined, and may break when internals change. * * For now, we distinguish only a fixed number of address classes. * Eventually this may become extensible, so that new classes can be * configured with their own domain list, delivery transport, and * recipient table. */ #define STREQ(x,y) (strcmp((x), (y)) == 0) if (domain != 0) { /* * Virtual alias domain. */ if (virt_alias_doms && string_list_match(virt_alias_doms, rcpt_domain)) { if (var_helpful_warnings) { if (virt_mailbox_doms && string_list_match(virt_mailbox_doms, rcpt_domain)) msg_warn("do not list domain %s in BOTH %s and %s", rcpt_domain, VAR_VIRT_ALIAS_DOMS, VAR_VIRT_MAILBOX_DOMS); if (relay_domains && domain_list_match(relay_domains, rcpt_domain)) msg_warn("do not list domain %s in BOTH %s and %s", rcpt_domain, VAR_VIRT_ALIAS_DOMS, VAR_RELAY_DOMAINS); #if 0 if (strcasecmp(rcpt_domain, var_myorigin) == 0) msg_warn("do not list $%s (%s) in %s", VAR_MYORIGIN, var_myorigin, VAR_VIRT_ALIAS_DOMS); #endif } vstring_strcpy(channel, MAIL_SERVICE_ERROR); vstring_sprintf(nexthop, "5.1.1 User unknown%s", var_show_unk_rcpt_table ? " in virtual alias table" : ""); *flags |= RESOLVE_CLASS_ALIAS; } else if (virt_alias_doms && virt_alias_doms->error != 0) { msg_warn("%s lookup failure", VAR_VIRT_ALIAS_DOMS); *flags |= RESOLVE_FLAG_FAIL; FREE_MEMORY_AND_RETURN; } /* * Virtual mailbox domain. */ else if (virt_mailbox_doms && string_list_match(virt_mailbox_doms, rcpt_domain)) { if (var_helpful_warnings) { if (relay_domains && domain_list_match(relay_domains, rcpt_domain)) msg_warn("do not list domain %s in BOTH %s and %s", rcpt_domain, VAR_VIRT_MAILBOX_DOMS, VAR_RELAY_DOMAINS); } vstring_strcpy(channel, RES_PARAM_VALUE(rp->virt_transport)); vstring_strcpy(nexthop, rcpt_domain); blame = rp->virt_transport_name; *flags |= RESOLVE_CLASS_VIRTUAL; } else if (virt_mailbox_doms && virt_mailbox_doms->error != 0) { msg_warn("%s lookup failure", VAR_VIRT_MAILBOX_DOMS); *flags |= RESOLVE_FLAG_FAIL; FREE_MEMORY_AND_RETURN; } else { /* * Off-host relay destination. */ if (relay_domains && domain_list_match(relay_domains, rcpt_domain)) { vstring_strcpy(channel, RES_PARAM_VALUE(rp->relay_transport)); blame = rp->relay_transport_name; *flags |= RESOLVE_CLASS_RELAY; } else if (relay_domains && relay_domains->error != 0) { msg_warn("%s lookup failure", VAR_RELAY_DOMAINS); *flags |= RESOLVE_FLAG_FAIL; FREE_MEMORY_AND_RETURN; } /* * Other off-host destination. */ else { if (rp->snd_def_xp_info && (xport = mail_addr_find(rp->snd_def_xp_info, sender_key = (*sender ? sender : var_null_def_xport_maps_key), (char **) 0)) != 0) { if (*xport == 0) { msg_warn("%s: ignoring null lookup result for %s", rp->snd_def_xp_maps_name, sender_key); xport = "DUNNO"; } vstring_strcpy(channel, strcasecmp(xport, "DUNNO") == 0 ? RES_PARAM_VALUE(rp->def_transport) : xport); blame = rp->snd_def_xp_maps_name; } else if (rp->snd_def_xp_info && rp->snd_def_xp_info->error != 0) { msg_warn("%s lookup failure", rp->snd_def_xp_maps_name); *flags |= RESOLVE_FLAG_FAIL; FREE_MEMORY_AND_RETURN; } else { vstring_strcpy(channel, RES_PARAM_VALUE(rp->def_transport)); blame = rp->def_transport_name; } *flags |= RESOLVE_CLASS_DEFAULT; } /* * With off-host delivery, sender-dependent or global relayhost * override the recipient domain. */ if (rp->snd_relay_info && (relay = mail_addr_find(rp->snd_relay_info, sender_key = (*sender ? sender : var_null_relay_maps_key), (char **) 0)) != 0) { if (*relay == 0) { msg_warn("%s: ignoring null lookup result for %s", rp->snd_relay_maps_name, sender_key); relay = "DUNNO"; } vstring_strcpy(nexthop, strcasecmp(relay, "DUNNO") == 0 ? rcpt_domain : relay); } else if (rp->snd_relay_info && rp->snd_relay_info->error != 0) { msg_warn("%s lookup failure", rp->snd_relay_maps_name); *flags |= RESOLVE_FLAG_FAIL; FREE_MEMORY_AND_RETURN; } else if (*RES_PARAM_VALUE(rp->relayhost)) vstring_strcpy(nexthop, RES_PARAM_VALUE(rp->relayhost)); else vstring_strcpy(nexthop, rcpt_domain); } } /* * Local delivery. * * XXX Nag if the domain is listed in multiple domain lists. The effect is * implementation defined, and may break when internals change. */ else { if (var_helpful_warnings) { if (virt_alias_doms && string_list_match(virt_alias_doms, rcpt_domain)) msg_warn("do not list domain %s in BOTH %s and %s", rcpt_domain, VAR_MYDEST, VAR_VIRT_ALIAS_DOMS); if (virt_mailbox_doms && string_list_match(virt_mailbox_doms, rcpt_domain)) msg_warn("do not list domain %s in BOTH %s and %s", rcpt_domain, VAR_MYDEST, VAR_VIRT_MAILBOX_DOMS); } vstring_strcpy(channel, RES_PARAM_VALUE(rp->local_transport)); vstring_strcpy(nexthop, rcpt_domain); blame = rp->local_transport_name; *flags |= RESOLVE_CLASS_LOCAL; } /* * An explicit main.cf transport:nexthop setting overrides the nexthop. * * XXX We depend on this mechanism to enforce per-recipient concurrencies * for local recipients. With "local_transport = local:$myhostname" we * force mail for any domain in $mydestination/${proxy,inet}_interfaces * to share the same queue. */ if ((destination = split_at(STR(channel), ':')) != 0 && *destination) vstring_strcpy(nexthop, destination); /* * Sanity checks. */ if (*STR(channel) == 0) { if (blame == 0) msg_panic("%s: null blame", myname); msg_warn("file %s/%s: parameter %s: null transport is not allowed", var_config_dir, MAIN_CONF_FILE, blame); *flags |= RESOLVE_FLAG_FAIL; FREE_MEMORY_AND_RETURN; } if (*STR(nexthop) == 0) msg_panic("%s: null nexthop", myname); /* * The transport map can selectively override any transport and/or * nexthop host info that is set up above. Unfortunately, the syntax for * nexthop information is transport specific. We therefore need sane and * intuitive semantics for transport map entries that specify a channel * but no nexthop. * * With non-error transports, the initial nexthop information is the * recipient domain. However, specific main.cf transport definitions may * specify a transport-specific destination, such as a host + TCP socket, * or the pathname of a UNIX-domain socket. With less precedence than * main.cf transport definitions, a main.cf relayhost definition may also * override nexthop information for off-host deliveries. * * With the error transport, the nexthop information is free text that * specifies the reason for non-delivery. * * Because nexthop syntax is transport specific we reset the nexthop * information to the recipient domain when the transport table specifies * a transport without also specifying the nexthop information. * * Subtle note: reset nexthop even when the transport table does not change * the transport. Otherwise it is hard to get rid of main.cf specified * nexthop information. * * XXX Don't override the virtual alias class (error:User unknown) result. */ if (rp->transport_info && !(*flags & RESOLVE_CLASS_ALIAS)) { if (transport_lookup(rp->transport_info, STR(nextrcpt), rcpt_domain, channel, nexthop) == 0 && rp->transport_info->transport_path->error != 0) { msg_warn("%s lookup failure", rp->transport_maps_name); *flags |= RESOLVE_FLAG_FAIL; FREE_MEMORY_AND_RETURN; } } /* * Bounce recipients that have moved, regardless of domain address class. * We do this last, in anticipation of transport maps that can override * the recipient address. * * The downside of not doing this in delivery agents is that this table has * no effect on local alias expansion results. Such mail will have to * make almost an entire iteration through the mail system. */ #define IGNORE_ADDR_EXTENSION ((char **) 0) if (relocated_maps != 0) { const char *newloc; if ((newloc = mail_addr_find(relocated_maps, STR(nextrcpt), IGNORE_ADDR_EXTENSION)) != 0) { vstring_strcpy(channel, MAIL_SERVICE_ERROR); /* 5.1.6 is the closest match, but not perfect. */ vstring_sprintf(nexthop, "5.1.6 User has moved to %s", newloc); } else if (relocated_maps->error != 0) { msg_warn("%s lookup failure", VAR_RELOCATED_MAPS); *flags |= RESOLVE_FLAG_FAIL; FREE_MEMORY_AND_RETURN; } } /* * Bounce recipient addresses that start with `-'. External commands may * misinterpret such addresses as command-line options. * * In theory I could say people should always carefully set up their * master.cf pipe mailer entries with `--' before the first non-option * argument, but mistakes will happen regardless. * * Therefore the protection is put in place here, where it cannot be * bypassed. */ if (var_allow_min_user == 0 && STR(nextrcpt)[0] == '-') { *flags |= RESOLVE_FLAG_ERROR; FREE_MEMORY_AND_RETURN; } /* * Clean up. */ FREE_MEMORY_AND_RETURN; }
/** * READINFO ARexx command * * @param rxmsg the message defining the ARexx context * @param args the command's arguments */ static void arexx_readinfo(struct RexxMsg *rxmsg, STRPTR args) { APTR arg_handle; struct { STRPTR var; STRPTR stem; } readinfo_arg; memset(&readinfo_arg,0,sizeof(readinfo_arg)); if ((arg_handle = ParseTemplate("VAR/K,STEM/K",args,&readinfo_arg))) { char num_buf[20]; struct mail_complete *mail; if ((mail = read_window_get_displayed_mail(read_active_window))) { mail = mail_get_root(mail); if (readinfo_arg.stem) { int stem_len = strlen(readinfo_arg.stem); char *stem_buf = (char *)malloc(stem_len+20); if (stem_buf) { int i, count = 0; struct mail_complete *t = mail; while (t) { mail_decode(t); t = mail_get_next(t); count++; } strcpy(stem_buf,readinfo_arg.stem); strcpy(&stem_buf[stem_len],"FILENAME.COUNT"); sprintf(num_buf,"%d",count); MySetRexxVarFromMsg(stem_buf,num_buf,rxmsg); strcpy(&stem_buf[stem_len],"FILETYPE.COUNT"); sprintf(num_buf,"%d",count); MySetRexxVarFromMsg(stem_buf,num_buf,rxmsg); strcpy(&stem_buf[stem_len],"FILESIZE.COUNT"); sprintf(num_buf,"%d",count); MySetRexxVarFromMsg(stem_buf,num_buf,rxmsg); i = 0; while (mail) { char *char_buf; int mail_size; if (mail->decoded_data) mail_size = mail->decoded_len; else mail_size = mail->text_len; sprintf(&stem_buf[stem_len],"FILENAME.%d",i); char_buf = mystrdup(mail->content_name); if (char_buf) MySetRexxVarFromMsg(stem_buf,char_buf,rxmsg); free(char_buf); char_buf = NULL; sprintf(&stem_buf[stem_len],"FILETYPE.%d",i); char_buf = mystrdup(mail->content_type); char_buf = stradd(char_buf,"/"); char_buf = stradd(char_buf,mail->content_subtype); if (char_buf) MySetRexxVarFromMsg(stem_buf,char_buf,rxmsg); free(char_buf); char_buf = NULL; sprintf(&stem_buf[stem_len],"FILESIZE.%d",i); sprintf(num_buf,"%d",mail_size); MySetRexxVarFromMsg(stem_buf,num_buf,rxmsg); mail = mail_get_next(mail); i++; } free(stem_buf); } } } FreeTemplate(arg_handle); } }
/** * GETSELECTED ARexx command. * * @param rxmsg the message defining the ARexx context. * @param args the command's arguments */ static void arexx_getselected(struct RexxMsg *rxmsg, STRPTR args) { APTR arg_handle; struct { STRPTR var; STRPTR stem; } getselected_arg; memset(&getselected_arg,0,sizeof(getselected_arg)); if ((arg_handle = ParseTemplate("VAR/K,STEM/K",args,&getselected_arg))) { int num = 0; struct mail_info *mail; void *handle = NULL; struct folder *folder; folder = main_get_folder(); mail = main_get_mail_first_selected(&handle); num = 0; /* Count the number of mails */ while (mail) { num++; mail = main_get_mail_next_selected(&handle); } if (folder) { char num_buf[20]; if (getselected_arg.stem) { int stem_len = strlen(getselected_arg.stem); char *stem_buf = (char *)malloc(stem_len+20); if (stem_buf) { int i = 0; strcpy(stem_buf,getselected_arg.stem); strcpy(&stem_buf[stem_len],"NUM.COUNT"); sprintf(num_buf,"%d",num); MySetRexxVarFromMsg(stem_buf,num_buf,rxmsg); mail = main_get_mail_first_selected(&handle); while (mail) { sprintf(&stem_buf[stem_len],"NUM.%d",i); sprintf(num_buf,"%d",folder_get_index_of_mail(folder,mail)); MySetRexxVarFromMsg(stem_buf,num_buf,rxmsg); i++; mail = main_get_mail_next_selected(&handle); } free(stem_buf); } } else { char *str; sprintf(num_buf,"%d",num); str = mystrdup(num_buf); mail = main_get_mail_first_selected(&handle); /* Count the number of mails */ while (mail) { sprintf(num_buf, " %d", folder_get_index_of_mail(folder,mail)); str = stradd(str,num_buf); mail = main_get_mail_next_selected(&handle); } if (getselected_arg.var) MySetRexxVarFromMsg(getselected_arg.var,str,rxmsg); else arexx_set_result(rxmsg,str); free(str); } } FreeTemplate(arg_handle); } }
static FORWARD_INFO *forward_open(DELIVER_REQUEST *request, const char *sender) { VSTRING *buffer = vstring_alloc(100); FORWARD_INFO *info; VSTREAM *cleanup; #define FORWARD_OPEN_RETURN(res) do { \ vstring_free(buffer); \ return (res); \ } while (0) /* * Contact the cleanup service and save the new mail queue id. Request * that the cleanup service bounces bad messages to the sender so that we * can avoid the trouble of bounce management. * * In case you wonder what kind of bounces, examples are "too many hops", * "message too large", perhaps some others. The reason not to bounce * ourselves is that we don't really know who the recipients are. */ cleanup = mail_connect(MAIL_CLASS_PUBLIC, var_cleanup_service, BLOCKING); if (cleanup == 0) { msg_warn("connect to %s/%s: %m", MAIL_CLASS_PUBLIC, var_cleanup_service); FORWARD_OPEN_RETURN(0); } close_on_exec(vstream_fileno(cleanup), CLOSE_ON_EXEC); if (attr_scan(cleanup, ATTR_FLAG_STRICT, RECV_ATTR_STR(MAIL_ATTR_QUEUEID, buffer), ATTR_TYPE_END) != 1) { vstream_fclose(cleanup); FORWARD_OPEN_RETURN(0); } info = (FORWARD_INFO *) mymalloc(sizeof(FORWARD_INFO)); info->cleanup = cleanup; info->queue_id = mystrdup(STR(buffer)); GETTIMEOFDAY(&info->posting_time); #define FORWARD_CLEANUP_FLAGS \ (CLEANUP_FLAG_BOUNCE | CLEANUP_FLAG_MASK_INTERNAL \ | smtputf8_autodetect(MAIL_SRC_MASK_FORWARD) \ | ((request->smtputf8 & SMTPUTF8_FLAG_REQUESTED) ? \ CLEANUP_FLAG_SMTPUTF8 : 0)) attr_print(cleanup, ATTR_FLAG_NONE, SEND_ATTR_INT(MAIL_ATTR_FLAGS, FORWARD_CLEANUP_FLAGS), ATTR_TYPE_END); /* * Send initial message envelope information. For bounces, set the * designated sender: mailing list owner, posting user, whatever. */ rec_fprintf(cleanup, REC_TYPE_TIME, REC_TYPE_TIME_FORMAT, REC_TYPE_TIME_ARG(info->posting_time)); rec_fputs(cleanup, REC_TYPE_FROM, sender); /* * Don't send the original envelope ID or full/headers return mask if it * was reset due to mailing list expansion. */ if (request->dsn_ret) rec_fprintf(cleanup, REC_TYPE_ATTR, "%s=%d", MAIL_ATTR_DSN_RET, request->dsn_ret); if (request->dsn_envid && *(request->dsn_envid)) rec_fprintf(cleanup, REC_TYPE_ATTR, "%s=%s", MAIL_ATTR_DSN_ENVID, request->dsn_envid); /* * Zero-length attribute values are place holders for unavailable * attribute values. See qmgr_message.c. They are not meant to be * propagated to queue files. */ #define PASS_ATTR(fp, name, value) do { \ if ((value) && *(value)) \ rec_fprintf((fp), REC_TYPE_ATTR, "%s=%s", (name), (value)); \ } while (0) /* * XXX encapsulate these as one object. */ PASS_ATTR(cleanup, MAIL_ATTR_LOG_CLIENT_NAME, request->client_name); PASS_ATTR(cleanup, MAIL_ATTR_LOG_CLIENT_ADDR, request->client_addr); PASS_ATTR(cleanup, MAIL_ATTR_LOG_PROTO_NAME, request->client_proto); PASS_ATTR(cleanup, MAIL_ATTR_LOG_HELO_NAME, request->client_helo); PASS_ATTR(cleanup, MAIL_ATTR_SASL_METHOD, request->sasl_method); PASS_ATTR(cleanup, MAIL_ATTR_SASL_USERNAME, request->sasl_username); PASS_ATTR(cleanup, MAIL_ATTR_SASL_SENDER, request->sasl_sender); PASS_ATTR(cleanup, MAIL_ATTR_LOG_IDENT, request->log_ident); PASS_ATTR(cleanup, MAIL_ATTR_RWR_CONTEXT, request->rewrite_context); FORWARD_OPEN_RETURN(info); }
int main(int argc, char** argv) { int i; int al, wl; FILE * wrdlst; FILE * afflst; char *wf, *af; char * ap; char ts[MAX_LN_LEN]; (void)argc; /* first parse the command line options */ /* arg1 - munched wordlist, arg2 - affix file */ if (argv[1]) { wf = mystrdup(argv[1]); } else { fprintf(stderr,"correct syntax is:\n"); fprintf(stderr,"unmunch dic_file affix_file\n"); exit(1); } if (argv[2]) { af = mystrdup(argv[2]); } else { fprintf(stderr,"correct syntax is:\n"); fprintf(stderr,"unmunch dic_file affix_file\n"); exit(1); } /* open the affix file */ afflst = fopen(af,"r"); if (!afflst) { fprintf(stderr,"Error - could not open affix description file\n"); exit(1); } /* step one is to parse the affix file building up the internal affix data structures */ numpfx = 0; numsfx = 0; fullstrip = 0; if (parse_aff_file(afflst)) { fprintf(stderr,"Error - in affix file loading\n"); exit(1); } fclose(afflst); fprintf(stderr,"parsed in %d prefixes and %d suffixes\n",numpfx,numsfx); /* affix file is now parsed so create hash table of wordlist on the fly */ /* open the wordlist */ wrdlst = fopen(wf,"r"); if (!wrdlst) { fprintf(stderr,"Error - could not open word list file\n"); exit(1); } /* skip over the hash table size */ if (! fgets(ts, MAX_LN_LEN-1,wrdlst)) { fclose(wrdlst); return 2; } mychomp(ts); while (fgets(ts,MAX_LN_LEN-1,wrdlst)) { mychomp(ts); /* split each line into word and affix char strings */ ap = strchr(ts,'/'); if (ap) { *ap = '\0'; ap++; al = strlen(ap); } else { al = 0; ap = NULL; } wl = strlen(ts); numwords = 0; wlist[numwords].word = mystrdup(ts); wlist[numwords].pallow = 0; numwords++; if (al) expand_rootword(ts,wl,ap); for (i=0; i < numwords; i++) { fprintf(stdout,"%s\n",wlist[i].word); free(wlist[i].word); wlist[i].word = NULL; wlist[i].pallow = 0; } } fclose(wrdlst); return 0; }
/* * This is the actual startup routine for the connection. We expect that the * buffers are flushed and the "220 Ready to start TLS" was received by us, * so that we can immediately start the TLS handshake process. */ TLS_SESS_STATE *tls_client_start(const TLS_CLIENT_START_PROPS *props) { int sts; int protomask; const char *cipher_list; SSL_SESSION *session; const SSL_CIPHER *cipher; X509 *peercert; TLS_SESS_STATE *TLScontext; TLS_APPL_STATE *app_ctx = props->ctx; VSTRING *myserverid; int log_mask = app_ctx->log_mask; /* * When certificate verification is required, log trust chain validation * errors even when disabled by default for opportunistic sessions. */ if (props->tls_level >= TLS_LEV_VERIFY) log_mask |= TLS_LOG_UNTRUSTED; if (log_mask & TLS_LOG_VERBOSE) msg_info("setting up TLS connection to %s", props->namaddr); /* * First make sure we have valid protocol and cipher parameters * * The cipherlist will be applied to the global SSL context, where it can be * repeatedly reset if necessary, but the protocol restrictions will be * is applied to the SSL connection, because protocol restrictions in the * global context cannot be cleared. */ /* * OpenSSL will ignore cached sessions that use the wrong protocol. So we * do not need to filter out cached sessions with the "wrong" protocol, * rather OpenSSL will simply negotiate a new session. * * Still, we salt the session lookup key with the protocol list, so that * sessions found in the cache are always acceptable. */ protomask = tls_protocol_mask(props->protocols); if (protomask == TLS_PROTOCOL_INVALID) { /* tls_protocol_mask() logs no warning. */ msg_warn("%s: Invalid TLS protocol list \"%s\": aborting TLS session", props->namaddr, props->protocols); return (0); } myserverid = vstring_alloc(100); vstring_sprintf_append(myserverid, "%s&p=%d", props->serverid, protomask); /* * Per session cipher selection for sessions with mandatory encryption * * By the time a TLS client is negotiating ciphers it has already offered to * re-use a session, it is too late to renege on the offer. So we must * not attempt to re-use sessions whose ciphers are too weak. We salt the * session lookup key with the cipher list, so that sessions found in the * cache are always acceptable. */ cipher_list = tls_set_ciphers(app_ctx, "TLS", props->cipher_grade, props->cipher_exclusions); if (cipher_list == 0) { msg_warn("%s: %s: aborting TLS session", props->namaddr, vstring_str(app_ctx->why)); vstring_free(myserverid); return (0); } if (log_mask & TLS_LOG_VERBOSE) msg_info("%s: TLS cipher list \"%s\"", props->namaddr, cipher_list); vstring_sprintf_append(myserverid, "&c=%s", cipher_list); /* * Allocate a new TLScontext for the new connection and get an SSL * structure. Add the location of TLScontext to the SSL to later retrieve * the information inside the tls_verify_certificate_callback(). * * If session caching was enabled when TLS was initialized, the cache type * is stored in the client SSL context. */ TLScontext = tls_alloc_sess_context(log_mask, props->namaddr); TLScontext->cache_type = app_ctx->cache_type; TLScontext->serverid = vstring_export(myserverid); TLScontext->stream = props->stream; if ((TLScontext->con = SSL_new(app_ctx->ssl_ctx)) == NULL) { msg_warn("Could not allocate 'TLScontext->con' with SSL_new()"); tls_print_errors(); tls_free_context(TLScontext); return (0); } if (!SSL_set_ex_data(TLScontext->con, TLScontext_index, TLScontext)) { msg_warn("Could not set application data for 'TLScontext->con'"); tls_print_errors(); tls_free_context(TLScontext); return (0); } /* * Apply session protocol restrictions. */ if (protomask != 0) SSL_set_options(TLScontext->con, ((protomask & TLS_PROTOCOL_TLSv1) ? SSL_OP_NO_TLSv1 : 0L) #ifdef SSL_OP_NO_TLSv1_1 | ((protomask & TLS_PROTOCOL_TLSv1_1) ? SSL_OP_NO_TLSv1_1 : 0L) #endif #ifdef SSL_OP_NO_TLSv1_2 | ((protomask & TLS_PROTOCOL_TLSv1_2) ? SSL_OP_NO_TLSv1_2 : 0L) #endif | ((protomask & TLS_PROTOCOL_SSLv3) ? SSL_OP_NO_SSLv3 : 0L) | ((protomask & TLS_PROTOCOL_SSLv2) ? SSL_OP_NO_SSLv2 : 0L)); /* * XXX To avoid memory leaks we must always call SSL_SESSION_free() after * calling SSL_set_session(), regardless of whether or not the session * will be reused. */ if (TLScontext->cache_type) { session = load_clnt_session(TLScontext); if (session) { SSL_set_session(TLScontext->con, session); SSL_SESSION_free(session); /* 200411 */ #if (OPENSSL_VERSION_NUMBER < 0x00906011L) || (OPENSSL_VERSION_NUMBER == 0x00907000L) /* * Ugly Hack: OpenSSL before 0.9.6a does not store the verify * result in sessions for the client side. We modify the session * directly which is version specific, but this bug is version * specific, too. * * READ: 0-09-06-01-1 = 0-9-6-a-beta1: all versions before beta1 * have this bug, it has been fixed during development of 0.9.6a. * The development version of 0.9.7 can have this bug, too. It * has been fixed on 2000/11/29. */ SSL_set_verify_result(TLScontext->con, session->verify_result); #endif } } /* * Before really starting anything, try to seed the PRNG a little bit * more. */ tls_int_seed(); (void) tls_ext_seed(var_tls_daemon_rand_bytes); /* * Initialize the SSL connection to connect state. This should not be * necessary anymore since 0.9.3, but the call is still in the library * and maintaining compatibility never hurts. */ SSL_set_connect_state(TLScontext->con); /* * Connect the SSL connection with the network socket. */ if (SSL_set_fd(TLScontext->con, vstream_fileno(props->stream)) != 1) { msg_info("SSL_set_fd error to %s", props->namaddr); tls_print_errors(); uncache_session(app_ctx->ssl_ctx, TLScontext); tls_free_context(TLScontext); return (0); } /* * Turn on non-blocking I/O so that we can enforce timeouts on network * I/O. */ non_blocking(vstream_fileno(props->stream), NON_BLOCKING); /* * If the debug level selected is high enough, all of the data is dumped: * TLS_LOG_TLSPKTS will dump the SSL negotiation, TLS_LOG_ALLPKTS will * dump everything. * * We do have an SSL_set_fd() and now suddenly a BIO_ routine is called? * Well there is a BIO below the SSL routines that is automatically * created for us, so we can use it for debugging purposes. */ if (log_mask & TLS_LOG_TLSPKTS) BIO_set_callback(SSL_get_rbio(TLScontext->con), tls_bio_dump_cb); /* * Start TLS negotiations. This process is a black box that invokes our * call-backs for certificate verification. * * Error handling: If the SSL handhake fails, we print out an error message * and remove all TLS state concerning this session. */ sts = tls_bio_connect(vstream_fileno(props->stream), props->timeout, TLScontext); if (sts <= 0) { if (ERR_peek_error() != 0) { msg_info("SSL_connect error to %s: %d", props->namaddr, sts); tls_print_errors(); } else if (errno != 0) { msg_info("SSL_connect error to %s: %m", props->namaddr); } else { msg_info("SSL_connect error to %s: lost connection", props->namaddr); } uncache_session(app_ctx->ssl_ctx, TLScontext); tls_free_context(TLScontext); return (0); } /* Turn off packet dump if only dumping the handshake */ if ((log_mask & TLS_LOG_ALLPKTS) == 0) BIO_set_callback(SSL_get_rbio(TLScontext->con), 0); /* * The caller may want to know if this session was reused or if a new * session was negotiated. */ TLScontext->session_reused = SSL_session_reused(TLScontext->con); if ((log_mask & TLS_LOG_CACHE) && TLScontext->session_reused) msg_info("%s: Reusing old session", TLScontext->namaddr); /* * Do peername verification if requested and extract useful information * from the certificate for later use. */ if ((peercert = SSL_get_peer_certificate(TLScontext->con)) != 0) { TLScontext->peer_status |= TLS_CERT_FLAG_PRESENT; /* * Peer name or fingerprint verification as requested. * Unconditionally set peer_CN, issuer_CN and peer_fingerprint. */ verify_extract_name(TLScontext, peercert, props); verify_extract_print(TLScontext, peercert, props); if (TLScontext->log_mask & (TLS_LOG_CERTMATCH | TLS_LOG_VERBOSE | TLS_LOG_PEERCERT)) msg_info("%s: subject_CN=%s, issuer_CN=%s, " "fingerprint %s, pkey_fingerprint=%s", props->namaddr, TLScontext->peer_CN, TLScontext->issuer_CN, TLScontext->peer_fingerprint, TLScontext->peer_pkey_fprint); X509_free(peercert); } else { TLScontext->issuer_CN = mystrdup(""); TLScontext->peer_CN = mystrdup(""); TLScontext->peer_fingerprint = mystrdup(""); TLScontext->peer_pkey_fprint = mystrdup(""); } /* * Finally, collect information about protocol and cipher for logging */ TLScontext->protocol = SSL_get_version(TLScontext->con); cipher = SSL_get_current_cipher(TLScontext->con); TLScontext->cipher_name = SSL_CIPHER_get_name(cipher); TLScontext->cipher_usebits = SSL_CIPHER_get_bits(cipher, &(TLScontext->cipher_algbits)); /* * The TLS engine is active. Switch to the tls_timed_read/write() * functions and make the TLScontext available to those functions. */ tls_stream_start(props->stream, TLScontext); /* * All the key facts in a single log entry. */ if (log_mask & TLS_LOG_SUMMARY) msg_info("%s TLS connection established to %s: %s with cipher %s " "(%d/%d bits)", TLS_CERT_IS_MATCHED(TLScontext) ? "Verified" : TLS_CERT_IS_TRUSTED(TLScontext) ? "Trusted" : "Untrusted", props->namaddr, TLScontext->protocol, TLScontext->cipher_name, TLScontext->cipher_usebits, TLScontext->cipher_algbits); tls_int_seed(); return (TLScontext); }
/* * This is the actual startup routine for a new connection. We expect that * the SMTP buffers are flushed and the "220 Ready to start TLS" was sent to * the client, so that we can immediately start the TLS handshake process. */ TLS_SESS_STATE *tls_server_start(const TLS_SERVER_START_PROPS *props) { int sts; TLS_SESS_STATE *TLScontext; const char *cipher_list; TLS_APPL_STATE *app_ctx = props->ctx; int log_mask = app_ctx->log_mask; /* * Implicitly enable logging of trust chain errors when verified certs * are required. */ if (props->requirecert) log_mask |= TLS_LOG_UNTRUSTED; if (log_mask & TLS_LOG_VERBOSE) msg_info("setting up TLS connection from %s", props->namaddr); cipher_list = tls_set_ciphers(app_ctx, "TLS", props->cipher_grade, props->cipher_exclusions); if (cipher_list == 0) { msg_warn("%s: %s: aborting TLS session", props->namaddr, vstring_str(app_ctx->why)); return (0); } if (log_mask & TLS_LOG_VERBOSE) msg_info("%s: TLS cipher list \"%s\"", props->namaddr, cipher_list); /* * Allocate a new TLScontext for the new connection and get an SSL * structure. Add the location of TLScontext to the SSL to later retrieve * the information inside the tls_verify_certificate_callback(). */ TLScontext = tls_alloc_sess_context(log_mask, props->namaddr); TLScontext->cache_type = app_ctx->cache_type; TLScontext->serverid = mystrdup(props->serverid); TLScontext->am_server = 1; TLScontext->stream = props->stream; TLScontext->mdalg = props->mdalg; ERR_clear_error(); if ((TLScontext->con = (SSL *) SSL_new(app_ctx->ssl_ctx)) == 0) { msg_warn("Could not allocate 'TLScontext->con' with SSL_new()"); tls_print_errors(); tls_free_context(TLScontext); return (0); } if (!SSL_set_ex_data(TLScontext->con, TLScontext_index, TLScontext)) { msg_warn("Could not set application data for 'TLScontext->con'"); tls_print_errors(); tls_free_context(TLScontext); return (0); } /* * Before really starting anything, try to seed the PRNG a little bit * more. */ tls_int_seed(); (void) tls_ext_seed(var_tls_daemon_rand_bytes); /* * Initialize the SSL connection to accept state. This should not be * necessary anymore since 0.9.3, but the call is still in the library * and maintaining compatibility never hurts. */ SSL_set_accept_state(TLScontext->con); /* * Connect the SSL connection with the network socket. */ if (SSL_set_fd(TLScontext->con, props->stream == 0 ? props->fd : vstream_fileno(props->stream)) != 1) { msg_info("SSL_set_fd error to %s", props->namaddr); tls_print_errors(); uncache_session(app_ctx->ssl_ctx, TLScontext); tls_free_context(TLScontext); return (0); } /* * If the debug level selected is high enough, all of the data is dumped: * TLS_LOG_TLSPKTS will dump the SSL negotiation, TLS_LOG_ALLPKTS will * dump everything. * * We do have an SSL_set_fd() and now suddenly a BIO_ routine is called? * Well there is a BIO below the SSL routines that is automatically * created for us, so we can use it for debugging purposes. */ if (log_mask & TLS_LOG_TLSPKTS) BIO_set_callback(SSL_get_rbio(TLScontext->con), tls_bio_dump_cb); /* * If we don't trigger the handshake in the library, leave control over * SSL_accept/read/write/etc with the application. */ if (props->stream == 0) return (TLScontext); /* * Turn on non-blocking I/O so that we can enforce timeouts on network * I/O. */ non_blocking(vstream_fileno(props->stream), NON_BLOCKING); /* * Start TLS negotiations. This process is a black box that invokes our * call-backs for session caching and certificate verification. * * Error handling: If the SSL handhake fails, we print out an error message * and remove all TLS state concerning this session. */ sts = tls_bio_accept(vstream_fileno(props->stream), props->timeout, TLScontext); if (sts <= 0) { if (ERR_peek_error() != 0) { msg_info("SSL_accept error from %s: %d", props->namaddr, sts); tls_print_errors(); } else if (errno != 0) { msg_info("SSL_accept error from %s: %m", props->namaddr); } else { msg_info("SSL_accept error from %s: lost connection", props->namaddr); } tls_free_context(TLScontext); return (0); } return (tls_server_post_accept(TLScontext)); }
static DICT_PCRE_RULE *dict_pcre_parse_rule(const char *mapname, int lineno, char *line, int nesting, int dict_flags) { char *p; int actual_sub; p = line; /* * An ordinary match rule takes one pattern and replacement text. */ if (!ISALNUM(*p)) { DICT_PCRE_REGEXP regexp; DICT_PCRE_ENGINE engine; DICT_PCRE_PRESCAN_CONTEXT prescan_context; DICT_PCRE_MATCH_RULE *match_rule; /* * Get the pattern string and options. */ if (dict_pcre_get_pattern(mapname, lineno, &p, ®exp) == 0) return (0); /* * Get the replacement text. */ while (*p && ISSPACE(*p)) ++p; if (!*p) msg_warn("%s, line %d: no replacement text: using empty string", mapname, lineno); /* * Sanity check the $number instances in the replacement text. */ prescan_context.mapname = mapname; prescan_context.lineno = lineno; prescan_context.max_sub = 0; prescan_context.literal = 0; /* * The optimizer will eliminate code duplication and/or dead code. */ #define CREATE_MATCHOP_ERROR_RETURN(rval) do { \ if (prescan_context.literal) \ myfree(prescan_context.literal); \ return (rval); \ } while (0) if (mac_parse(p, dict_pcre_prescan, (char *) &prescan_context) & MAC_PARSE_ERROR) { msg_warn("pcre map %s, line %d: bad replacement syntax: " "skipping this rule", mapname, lineno); CREATE_MATCHOP_ERROR_RETURN(0); } /* * Substring replacement not possible with negative regexps. */ if (prescan_context.max_sub > 0 && regexp.match == 0) { msg_warn("pcre map %s, line %d: $number found in negative match " "replacement text: skipping this rule", mapname, lineno); CREATE_MATCHOP_ERROR_RETURN(0); } if (prescan_context.max_sub > 0 && (dict_flags & DICT_FLAG_NO_REGSUB)) { msg_warn("pcre map %s, line %d: " "regular expression substitution is not allowed: " "skipping this rule", mapname, lineno); CREATE_MATCHOP_ERROR_RETURN(0); } /* * Compile the pattern. */ if (dict_pcre_compile(mapname, lineno, ®exp, &engine) == 0) CREATE_MATCHOP_ERROR_RETURN(0); #ifdef PCRE_INFO_CAPTURECOUNT if (pcre_fullinfo(engine.pattern, engine.hints, PCRE_INFO_CAPTURECOUNT, (void *) &actual_sub) != 0) msg_panic("pcre map %s, line %d: pcre_fullinfo failed", mapname, lineno); if (prescan_context.max_sub > actual_sub) { msg_warn("pcre map %s, line %d: out of range replacement index \"%d\": " "skipping this rule", mapname, lineno, (int) prescan_context.max_sub); if (engine.pattern) myfree((char *) engine.pattern); if (engine.hints) DICT_PCRE_FREE_STUDY(engine.hints); CREATE_MATCHOP_ERROR_RETURN(0); } #endif /* * Save the result. */ match_rule = (DICT_PCRE_MATCH_RULE *) dict_pcre_rule_alloc(DICT_PCRE_OP_MATCH, nesting, lineno, sizeof(DICT_PCRE_MATCH_RULE)); match_rule->match = regexp.match; match_rule->max_sub = prescan_context.max_sub; if (prescan_context.literal) match_rule->replacement = prescan_context.literal; else match_rule->replacement = mystrdup(p); match_rule->pattern = engine.pattern; match_rule->hints = engine.hints; return ((DICT_PCRE_RULE *) match_rule); } /* * The IF operator takes one pattern but no replacement text. */ else if (strncasecmp(p, "IF", 2) == 0 && !ISALNUM(p[2])) { DICT_PCRE_REGEXP regexp; DICT_PCRE_ENGINE engine; DICT_PCRE_IF_RULE *if_rule; p += 2; /* * Get the pattern. */ while (*p && ISSPACE(*p)) p++; if (!dict_pcre_get_pattern(mapname, lineno, &p, ®exp)) return (0); /* * Warn about out-of-place text. */ while (*p && ISSPACE(*p)) ++p; if (*p) { msg_warn("pcre map %s, line %d: ignoring extra text after " "IF statement: \"%s\"", mapname, lineno, p); msg_warn("pcre map %s, line %d: do not prepend whitespace" " to statements between IF and ENDIF", mapname, lineno); } /* * Compile the pattern. */ if (dict_pcre_compile(mapname, lineno, ®exp, &engine) == 0) return (0); /* * Save the result. */ if_rule = (DICT_PCRE_IF_RULE *) dict_pcre_rule_alloc(DICT_PCRE_OP_IF, nesting, lineno, sizeof(DICT_PCRE_IF_RULE)); if_rule->match = regexp.match; if_rule->pattern = engine.pattern; if_rule->hints = engine.hints; return ((DICT_PCRE_RULE *) if_rule); } /* * The ENDIF operator takes no patterns and no replacement text. */ else if (strncasecmp(p, "ENDIF", 5) == 0 && !ISALNUM(p[5])) { DICT_PCRE_RULE *rule; p += 5; /* * Warn about out-of-place ENDIFs. */ if (nesting == 0) { msg_warn("pcre map %s, line %d: ignoring ENDIF without matching IF", mapname, lineno); return (0); } /* * Warn about out-of-place text. */ while (*p && ISSPACE(*p)) ++p; if (*p) msg_warn("pcre map %s, line %d: ignoring extra text after ENDIF", mapname, lineno); /* * Save the result. */ rule = dict_pcre_rule_alloc(DICT_PCRE_OP_ENDIF, nesting, lineno, sizeof(DICT_PCRE_RULE)); return (rule); } /* * Unrecognized input. */ else { msg_warn("pcre map %s, line %d: ignoring unrecognized request", mapname, lineno); return (0); } }
TLS_SESS_STATE *tls_server_post_accept(TLS_SESS_STATE *TLScontext) { SSL_CIPHER_const SSL_CIPHER *cipher; X509 *peer; char buf[CCERT_BUFSIZ]; /* Turn off packet dump if only dumping the handshake */ if ((TLScontext->log_mask & TLS_LOG_ALLPKTS) == 0) BIO_set_callback(SSL_get_rbio(TLScontext->con), 0); /* * The caller may want to know if this session was reused or if a new * session was negotiated. */ TLScontext->session_reused = SSL_session_reused(TLScontext->con); if ((TLScontext->log_mask & TLS_LOG_CACHE) && TLScontext->session_reused) msg_info("%s: Reusing old session%s", TLScontext->namaddr, TLScontext->ticketed ? " (RFC 5077 session ticket)" : ""); /* * Let's see whether a peer certificate is available and what is the * actual information. We want to save it for later use. */ peer = SSL_get_peer_certificate(TLScontext->con); if (peer != NULL) { TLScontext->peer_status |= TLS_CERT_FLAG_PRESENT; if (SSL_get_verify_result(TLScontext->con) == X509_V_OK) TLScontext->peer_status |= TLS_CERT_FLAG_TRUSTED; if (TLScontext->log_mask & TLS_LOG_VERBOSE) { X509_NAME_oneline(X509_get_subject_name(peer), buf, sizeof(buf)); msg_info("subject=%s", buf); X509_NAME_oneline(X509_get_issuer_name(peer), buf, sizeof(buf)); msg_info("issuer=%s", buf); } TLScontext->peer_CN = tls_peer_CN(peer, TLScontext); TLScontext->issuer_CN = tls_issuer_CN(peer, TLScontext); TLScontext->peer_cert_fprint = tls_cert_fprint(peer, TLScontext->mdalg); TLScontext->peer_pkey_fprint = tls_pkey_fprint(peer, TLScontext->mdalg); if (TLScontext->log_mask & (TLS_LOG_VERBOSE | TLS_LOG_PEERCERT)) { msg_info("%s: subject_CN=%s, issuer=%s, fingerprint=%s" ", pkey_fingerprint=%s", TLScontext->namaddr, TLScontext->peer_CN, TLScontext->issuer_CN, TLScontext->peer_cert_fprint, TLScontext->peer_pkey_fprint); } X509_free(peer); } else { TLScontext->peer_CN = mystrdup(""); TLScontext->issuer_CN = mystrdup(""); TLScontext->peer_cert_fprint = mystrdup(""); TLScontext->peer_pkey_fprint = mystrdup(""); } /* * Finally, collect information about protocol and cipher for logging */ TLScontext->protocol = SSL_get_version(TLScontext->con); cipher = SSL_get_current_cipher(TLScontext->con); TLScontext->cipher_name = SSL_CIPHER_get_name(cipher); TLScontext->cipher_usebits = SSL_CIPHER_get_bits(cipher, &(TLScontext->cipher_algbits)); /* * If the library triggered the SSL handshake, switch to the * tls_timed_read/write() functions and make the TLScontext available to * those functions. Otherwise, leave control over SSL_read/write/etc. * with the application. */ if (TLScontext->stream != 0) tls_stream_start(TLScontext->stream, TLScontext); /* * All the key facts in a single log entry. */ if (TLScontext->log_mask & TLS_LOG_SUMMARY) msg_info("%s TLS connection established from %s: %s with cipher %s " "(%d/%d bits)", !TLS_CERT_IS_PRESENT(TLScontext) ? "Anonymous" : TLS_CERT_IS_TRUSTED(TLScontext) ? "Trusted" : "Untrusted", TLScontext->namaddr, TLScontext->protocol, TLScontext->cipher_name, TLScontext->cipher_usebits, TLScontext->cipher_algbits); tls_int_seed(); return (TLScontext); }
int i; free(opt->model); for (i = 0;i < opt->num_params;++i) { free(opt->params[i]); } free(opt->params); } BEGIN_OPTION_MAP(parse_learn_options, learn_option_t) ON_OPTION_WITH_ARG(SHORTOPT('t') || LONGOPT("type")) if (strcmp(arg, "1d") == 0) { free(opt->type); opt->type = mystrdup("crf1d"); } else { fprintf(stderr, "ERROR: Unknown graphical model: %s\n", arg); return -1; } ON_OPTION_WITH_ARG(SHORTOPT('a') || LONGOPT("algorithm")) if (strcmp(arg, "lbfgs") == 0) { free(opt->algorithm); opt->algorithm = mystrdup("lbfgs"); } else if (strcmp(arg, "l2sgd") == 0) { free(opt->algorithm); opt->algorithm = mystrdup("l2sgd"); } else if (strcmp(arg, "ap") == 0 || strcmp(arg, "averaged-perceptron") == 0) { free(opt->algorithm); opt->algorithm = mystrdup("averaged-perceptron");
/* function to parse command line options and check for some usage errors. */ void get_opts(int argc, char **argv, struct options * my_opts) { int c; /* set the defaults */ my_opts->quiet = false; my_opts->systables = false; my_opts->indexes = false; my_opts->nodb = false; my_opts->extended = false; my_opts->tablespaces = false; my_opts->dbname = NULL; my_opts->hostname = NULL; my_opts->port = NULL; my_opts->username = NULL; my_opts->password = NULL; /* get opts */ while ((c = getopt(argc, argv, "H:p:U:P:d:t:o:f:qSxish?")) != -1) { switch (c) { /* specify the database */ case 'd': my_opts->dbname = mystrdup(optarg); break; /* specify one tablename to show */ case 't': add_one_elt(optarg, my_opts->tables); break; /* specify one Oid to show */ case 'o': add_one_elt(optarg, my_opts->oids); break; /* specify one filenode to show */ case 'f': add_one_elt(optarg, my_opts->filenodes); break; /* don't show headers */ case 'q': my_opts->quiet = true; break; /* host to connect to */ case 'H': my_opts->hostname = mystrdup(optarg); break; /* port to connect to on remote host */ case 'p': my_opts->port = mystrdup(optarg); break; /* username */ case 'U': my_opts->username = mystrdup(optarg); break; /* password */ case 'P': my_opts->password = mystrdup(optarg); break; /* display system tables */ case 'S': my_opts->systables = true; break; /* also display indexes */ case 'i': my_opts->indexes = true; break; /* display extra columns */ case 'x': my_opts->extended = true; break; /* dump tablespaces only */ case 's': my_opts->tablespaces = true; break; /* help! (ugly in code for easier editing) */ case '?': case 'h': fprintf(stderr, "Usage: oid2name [-s|-d database] [-S][-i][-q][-x] [-t table|-o oid|-f file] ...\n" " default action show all database Oids\n" " -d database database to connect to\n" " -s show all tablespaces\n" " -S show system objects too\n" " -i show indexes and sequences too\n" " -x extended (show additional columns)\n" " -q quiet (don't show headers)\n" " -t <table> show info for table named <table>\n" " -o <oid> show info for table with Oid <oid>\n" " -f <filenode> show info for table with filenode <filenode>\n" " -H host connect to remote host\n" " -p port host port to connect to\n" " -U username username to connect with\n" " -P password password for username\n" " (see also $PGPASSWORD and ~/.pgpass)\n" ); exit(1); break; } } }
static void post_jail_init(char *unused_name, char **unused_argv) { const NAME_CODE actions[] = { PSC_NAME_ACT_DROP, PSC_ACT_DROP, PSC_NAME_ACT_ENFORCE, PSC_ACT_ENFORCE, PSC_NAME_ACT_IGNORE, PSC_ACT_IGNORE, PSC_NAME_ACT_CONT, PSC_ACT_IGNORE, /* compatibility */ 0, -1, }; int cache_flags; const char *tmp; /* * This routine runs after the skeleton code has entered the chroot jail. * Prevent automatic process suicide after a limited number of client * requests. It is OK to terminate after a limited amount of idle time. */ var_use_limit = 0; /* * Workaround for parameters whose values may contain "$", and that have * a default of "$parametername". Not sure if it would be a good idea to * always to this in the mail_conf_raw(3) module. */ if (*var_psc_rej_footer == '$' && mail_conf_lookup(var_psc_rej_footer + 1)) { tmp = mail_conf_eval_once(var_psc_rej_footer); myfree(var_psc_rej_footer); var_psc_rej_footer = mystrdup(tmp); } if (*var_psc_exp_filter == '$' && mail_conf_lookup(var_psc_exp_filter + 1)) { tmp = mail_conf_eval_once(var_psc_exp_filter); myfree(var_psc_exp_filter); var_psc_exp_filter = mystrdup(tmp); } /* * Other one-time initialization. */ psc_temp = vstring_alloc(10); vstring_sprintf(psc_temp, "%s/%s", MAIL_CLASS_PRIVATE, var_smtpd_service); psc_smtpd_service_name = mystrdup(STR(psc_temp)); psc_dnsbl_init(); psc_early_init(); psc_smtpd_init(); if ((psc_blist_action = name_code(actions, NAME_CODE_FLAG_NONE, var_psc_blist_action)) < 0) msg_fatal("bad %s value: %s", VAR_PSC_BLIST_ACTION, var_psc_blist_action); if ((psc_dnsbl_action = name_code(actions, NAME_CODE_FLAG_NONE, var_psc_dnsbl_action)) < 0) msg_fatal("bad %s value: %s", VAR_PSC_DNSBL_ACTION, var_psc_dnsbl_action); if ((psc_pregr_action = name_code(actions, NAME_CODE_FLAG_NONE, var_psc_pregr_action)) < 0) msg_fatal("bad %s value: %s", VAR_PSC_PREGR_ACTION, var_psc_pregr_action); if ((psc_pipel_action = name_code(actions, NAME_CODE_FLAG_NONE, var_psc_pipel_action)) < 0) msg_fatal("bad %s value: %s", VAR_PSC_PIPEL_ACTION, var_psc_pipel_action); if ((psc_nsmtp_action = name_code(actions, NAME_CODE_FLAG_NONE, var_psc_nsmtp_action)) < 0) msg_fatal("bad %s value: %s", VAR_PSC_NSMTP_ACTION, var_psc_nsmtp_action); if ((psc_barlf_action = name_code(actions, NAME_CODE_FLAG_NONE, var_psc_barlf_action)) < 0) msg_fatal("bad %s value: %s", VAR_PSC_BARLF_ACTION, var_psc_barlf_action); /* Fail "closed" on error. */ psc_wlist_if = addr_match_list_init(MATCH_FLAG_RETURN, var_psc_wlist_if); /* * Start the cache maintenance pseudo thread last. Early cleanup makes * verbose logging more informative (we get positive confirmation that * the cleanup thread runs). */ cache_flags = DICT_CACHE_FLAG_STATISTICS; if (msg_verbose > 1) cache_flags |= DICT_CACHE_FLAG_VERBOSE; if (psc_cache_map != 0 && var_psc_cache_scan > 0) dict_cache_control(psc_cache_map, DICT_CACHE_CTL_FLAGS, cache_flags, DICT_CACHE_CTL_INTERVAL, var_psc_cache_scan, DICT_CACHE_CTL_VALIDATOR, psc_cache_validator, DICT_CACHE_CTL_CONTEXT, (char *) 0, DICT_CACHE_CTL_END); /* * Pre-compute the minimal and maximal TTL. */ psc_min_ttl = PSC_MIN(PSC_MIN(var_psc_pregr_ttl, var_psc_dnsbl_ttl), PSC_MIN(PSC_MIN(var_psc_pipel_ttl, var_psc_nsmtp_ttl), var_psc_barlf_ttl)); psc_max_ttl = PSC_MAX(PSC_MAX(var_psc_pregr_ttl, var_psc_dnsbl_ttl), PSC_MAX(PSC_MAX(var_psc_pipel_ttl, var_psc_nsmtp_ttl), var_psc_barlf_ttl)); /* * Pre-compute the stress and normal command time limits. */ mail_conf_update(VAR_STRESS, "yes"); psc_stress_cmd_time_limit = get_mail_conf_time(VAR_PSC_CMD_TIME, DEF_PSC_CMD_TIME, 1, 0); psc_stress_greet_wait = get_mail_conf_time(VAR_PSC_GREET_WAIT, DEF_PSC_GREET_WAIT, 1, 0); mail_conf_update(VAR_STRESS, ""); psc_normal_cmd_time_limit = get_mail_conf_time(VAR_PSC_CMD_TIME, DEF_PSC_CMD_TIME, 1, 0); psc_normal_greet_wait = get_mail_conf_time(VAR_PSC_GREET_WAIT, DEF_PSC_GREET_WAIT, 1, 0); psc_lowat_check_queue_length = .7 * var_psc_pre_queue_limit; psc_hiwat_check_queue_length = .9 * var_psc_pre_queue_limit; if (msg_verbose) msg_info(VAR_PSC_CMD_TIME ": stress=%d normal=%d lowat=%d hiwat=%d", psc_stress_cmd_time_limit, psc_normal_cmd_time_limit, psc_lowat_check_queue_length, psc_hiwat_check_queue_length); if (psc_lowat_check_queue_length == 0) msg_panic("compiler error: 0.7 * %d = %d", var_psc_pre_queue_limit, psc_lowat_check_queue_length); if (psc_hiwat_check_queue_length == 0) msg_panic("compiler error: 0.9 * %d = %d", var_psc_pre_queue_limit, psc_hiwat_check_queue_length); /* * Per-client concurrency. */ psc_client_concurrency = htable_create(var_psc_pre_queue_limit); }
/****************************************************************** inserts the text of the mail into the given nlist object *******************************************************************/ static void insert_text(struct Read_Data *data, struct mail *mail) { char *buf; char *buf_end; if (!mail->text) return; if (mail->decoded_data) { if (stricmp(mail->content_type,"text")) { SetAttrs(data->datatype_datatypes, MUIA_DataTypes_Buffer, mail->decoded_data, MUIA_DataTypes_BufferLen, mail->decoded_len, TAG_DONE); set(data->contents_page, MUIA_Group_ActivePage, PAGE_DATATYPE); return; } buf = mail->decoded_data; buf_end = buf + mail->decoded_len; } else { buf = mail->text + mail->text_begin; buf_end = buf + mail->text_len; } if (!stricmp(mail->content_subtype, "html")) { SetAttrs(data->html_simplehtml, MUIA_SimpleHTML_Buffer, buf, MUIA_SimpleHTML_BufferLen, buf_end - buf, TAG_DONE); set(data->contents_page, MUIA_Group_ActivePage, PAGE_HTML); } else { char *html_mail; char *font_buf; SetAttrs(data->html_simplehtml, MUIA_SimpleHTML_Buffer,data->mail->html_header, MUIA_SimpleHTML_BufferLen,strstr(data->mail->html_header,"</BODY></HTML>") - data->mail->html_header, TAG_DONE); if (font_buf = mystrdup(user.config.read_fixedfont)) { char *end = strchr(font_buf,'/'); if (end) { int size = atoi(end+1); *end = 0; DoMethod(data->html_simplehtml,MUIM_SimpleHTML_FontSubst,"fixedmail",3,font_buf,size); } free(font_buf); } if (font_buf = mystrdup(user.config.read_propfont)) { char *end = strchr(font_buf,'/'); if (end) { int size = atoi(end+1); *end = 0; DoMethod(data->html_simplehtml,MUIM_SimpleHTML_FontSubst,"normal",2,font_buf,size); DoMethod(data->html_simplehtml,MUIM_SimpleHTML_FontSubst,"normal",3,font_buf,size); DoMethod(data->html_simplehtml,MUIM_SimpleHTML_FontSubst,"normal",4,font_buf,size); } free(font_buf); } html_mail = text2html(buf, buf_end - buf, TEXT2HTML_ENDBODY_TAG|TEXT2HTML_FIXED_FONT|(user.config.read_wordwrap?0:TEXT2HTML_NOWRAP),"<FONT FACE=\"fixedmail\" SIZE=\"+1\">"); DoMethod(data->html_simplehtml, MUIM_SimpleHTML_AppendBuffer, html_mail, strlen(html_mail)); set(data->wnd, MUIA_Window_DefaultObject, data->html_simplehtml); set(data->contents_page, MUIA_Group_ActivePage, PAGE_HTML); set(data->print_button, MUIA_Disabled, FALSE); } }
static int deliver_request_get(VSTREAM *stream, DELIVER_REQUEST *request) { const char *myname = "deliver_request_get"; const char *path; struct stat st; static VSTRING *queue_name; static VSTRING *queue_id; static VSTRING *nexthop; static VSTRING *encoding; static VSTRING *address; static VSTRING *client_name; static VSTRING *client_addr; static VSTRING *client_port; static VSTRING *client_proto; static VSTRING *client_helo; static VSTRING *sasl_method; static VSTRING *sasl_username; static VSTRING *sasl_sender; static VSTRING *rewrite_context; static VSTRING *dsn_envid; static RCPT_BUF *rcpt_buf; int rcpt_count; int dsn_ret; /* * Initialize. For some reason I wanted to allow for multiple instances * of a deliver_request structure, thus the hoopla with string * initialization and copying. */ if (queue_name == 0) { queue_name = vstring_alloc(10); queue_id = vstring_alloc(10); nexthop = vstring_alloc(10); encoding = vstring_alloc(10); address = vstring_alloc(10); client_name = vstring_alloc(10); client_addr = vstring_alloc(10); client_port = vstring_alloc(10); client_proto = vstring_alloc(10); client_helo = vstring_alloc(10); sasl_method = vstring_alloc(10); sasl_username = vstring_alloc(10); sasl_sender = vstring_alloc(10); rewrite_context = vstring_alloc(10); dsn_envid = vstring_alloc(10); rcpt_buf = rcpb_create(); } /* * Extract the queue file name, data offset, and sender address. Abort * the conversation when they send bad information. */ if (attr_scan(stream, ATTR_FLAG_STRICT, ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &request->flags, ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name, ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id, ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, &request->data_offset, ATTR_TYPE_LONG, MAIL_ATTR_SIZE, &request->data_size, ATTR_TYPE_STR, MAIL_ATTR_NEXTHOP, nexthop, ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding, ATTR_TYPE_STR, MAIL_ATTR_SENDER, address, ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, dsn_envid, ATTR_TYPE_INT, MAIL_ATTR_DSN_RET, &dsn_ret, ATTR_TYPE_FUNC, msg_stats_scan, (void *) &request->msg_stats, /* XXX Should be encapsulated with ATTR_TYPE_FUNC. */ ATTR_TYPE_STR, MAIL_ATTR_LOG_CLIENT_NAME, client_name, ATTR_TYPE_STR, MAIL_ATTR_LOG_CLIENT_ADDR, client_addr, ATTR_TYPE_STR, MAIL_ATTR_LOG_CLIENT_PORT, client_port, ATTR_TYPE_STR, MAIL_ATTR_LOG_PROTO_NAME, client_proto, ATTR_TYPE_STR, MAIL_ATTR_LOG_HELO_NAME, client_helo, /* XXX Should be encapsulated with ATTR_TYPE_FUNC. */ ATTR_TYPE_STR, MAIL_ATTR_SASL_METHOD, sasl_method, ATTR_TYPE_STR, MAIL_ATTR_SASL_USERNAME, sasl_username, ATTR_TYPE_STR, MAIL_ATTR_SASL_SENDER, sasl_sender, /* XXX Ditto if we want to pass TLS certificate info. */ ATTR_TYPE_STR, MAIL_ATTR_RWR_CONTEXT, rewrite_context, ATTR_TYPE_INT, MAIL_ATTR_RCPT_COUNT, &rcpt_count, ATTR_TYPE_END) != 21) { msg_warn("%s: error receiving common attributes", myname); return (-1); } if (mail_open_ok(vstring_str(queue_name), vstring_str(queue_id), &st, &path) == 0) return (-1); /* Don't override hand-off time after deliver_pass() delegation. */ if (request->msg_stats.agent_handoff.tv_sec == 0) GETTIMEOFDAY(&request->msg_stats.agent_handoff); request->queue_name = mystrdup(vstring_str(queue_name)); request->queue_id = mystrdup(vstring_str(queue_id)); request->nexthop = mystrdup(vstring_str(nexthop)); request->encoding = mystrdup(vstring_str(encoding)); request->sender = mystrdup(vstring_str(address)); request->client_name = mystrdup(vstring_str(client_name)); request->client_addr = mystrdup(vstring_str(client_addr)); request->client_port = mystrdup(vstring_str(client_port)); request->client_proto = mystrdup(vstring_str(client_proto)); request->client_helo = mystrdup(vstring_str(client_helo)); request->sasl_method = mystrdup(vstring_str(sasl_method)); request->sasl_username = mystrdup(vstring_str(sasl_username)); request->sasl_sender = mystrdup(vstring_str(sasl_sender)); request->rewrite_context = mystrdup(vstring_str(rewrite_context)); request->dsn_envid = mystrdup(vstring_str(dsn_envid)); request->dsn_ret = dsn_ret; /* * Extract the recipient offset and address list. Skip over any * attributes from the sender that we do not understand. */ while (rcpt_count-- > 0) { if (attr_scan(stream, ATTR_FLAG_STRICT, ATTR_TYPE_FUNC, rcpb_scan, (void *) rcpt_buf, ATTR_TYPE_END) != 1) { msg_warn("%s: error receiving recipient attributes", myname); return (-1); } recipient_list_add(&request->rcpt_list, rcpt_buf->offset, vstring_str(rcpt_buf->dsn_orcpt), rcpt_buf->dsn_notify, vstring_str(rcpt_buf->orig_addr), vstring_str(rcpt_buf->address)); } if (request->rcpt_list.len <= 0) { msg_warn("%s: no recipients in delivery request for destination %s", request->queue_id, request->nexthop); return (-1); } /* * Open the queue file and set a shared lock, in order to prevent * duplicate deliveries when the queue is flushed immediately after queue * manager restart. * * The queue manager locks the file exclusively when it enters the active * queue, and releases the lock before starting deliveries from that * file. The queue manager does not lock the file again when reading more * recipients into memory. When the queue manager is restarted, the new * process moves files from the active queue to the incoming queue to cool * off for a while. Delivery agents should therefore never try to open a * file that is locked by a queue manager process. * * Opening the queue file can fail for a variety of reasons, such as the * system running out of resources. Instead of throwing away mail, we're * raising a fatal error which forces the mail system to back off, and * retry later. */ #define DELIVER_LOCK_MODE (MYFLOCK_OP_SHARED | MYFLOCK_OP_NOWAIT) request->fp = mail_queue_open(request->queue_name, request->queue_id, O_RDWR, 0); if (request->fp == 0) { if (errno != ENOENT) msg_fatal("open %s %s: %m", request->queue_name, request->queue_id); msg_warn("open %s %s: %m", request->queue_name, request->queue_id); return (-1); } if (msg_verbose) msg_info("%s: file %s", myname, VSTREAM_PATH(request->fp)); if (myflock(vstream_fileno(request->fp), INTERNAL_LOCK, DELIVER_LOCK_MODE) < 0) msg_fatal("shared lock %s: %m", VSTREAM_PATH(request->fp)); close_on_exec(vstream_fileno(request->fp), CLOSE_ON_EXEC); return (0); }
static void init_nullses(void) { struct timeval tv; gettimeofday(&tv, 0); time0 = tv.tv_sec; utime0 = tv.tv_usec; nullsession=TALLOC(struct session); nullsession->name=mystrdup("main"); nullsession->address=0; nullsession->tickstatus = false; nullsession->tick_size = DEFAULT_TICK_SIZE; nullsession->pretick = DEFAULT_PRETICK; nullsession->time0 = 0; nullsession->snoopstatus = true; nullsession->logfile = 0; nullsession->logname = 0; nullsession->logtype = DEFAULT_LOGTYPE; nullsession->loginputprefix=mystrdup(LOG_INPUT_PREFIX); nullsession->loginputsuffix=mystrdup(LOG_INPUT_SUFFIX); nullsession->blank = DEFAULT_DISPLAY_BLANK; nullsession->echo = ui_sep_input?DEFAULT_ECHO_SEPINPUT :DEFAULT_ECHO_NOSEPINPUT; nullsession->speedwalk = DEFAULT_SPEEDWALK; nullsession->togglesubs = DEFAULT_TOGGLESUBS; nullsession->presub = DEFAULT_PRESUB; nullsession->verbatim = false; nullsession->ignore = DEFAULT_IGNORE; nullsession->partial_line_marker = mystrdup(DEFAULT_PARTIAL_LINE_MARKER); nullsession->aliases = init_hash(); nullsession->actions = init_list(); nullsession->prompts = init_list(); nullsession->subs = init_list(); nullsession->myvars = init_hash(); nullsession->highs = init_list(); nullsession->pathdirs = init_hash(); nullsession->socket = 0; nullsession->issocket = false; nullsession->naws = false; #ifdef HAVE_ZLIB nullsession->can_mccp = false; nullsession->mccp = 0; nullsession->mccp_more = false; #endif nullsession->last_term_type=0; nullsession->server_echo = 0; nullsession->nagle = false; nullsession->antisubs = init_list(); nullsession->binds = init_hash(); nullsession->next = 0; nullsession->sessionstart=nullsession->idle_since= nullsession->server_idle_since=time(0); nullsession->debuglogfile=0; nullsession->debuglogname=0; for (int i=0;i<HISTORY_SIZE;i++) history[i]=0; for (int i=0;i<MAX_LOCATIONS;i++) { nullsession->routes[i]=0; nullsession->locations[i]=0; } for (int i=0;i<NHOOKS;i++) nullsession->hooks[i]=0; nullsession->path = init_list(); nullsession->no_return = 0; nullsession->path_length = 0; nullsession->last_line[0] = 0; nullsession->events = NULL; nullsession->verbose=false; nullsession->closing=false; sessionlist = nullsession; activesession = nullsession; pvars=0; nullsession->mesvar[MSG_ALIAS] = DEFAULT_ALIAS_MESS; nullsession->mesvar[MSG_ACTION] = DEFAULT_ACTION_MESS; nullsession->mesvar[MSG_SUBSTITUTE] = DEFAULT_SUB_MESS; nullsession->mesvar[MSG_EVENT] = DEFAULT_EVENT_MESS; nullsession->mesvar[MSG_HIGHLIGHT] = DEFAULT_HIGHLIGHT_MESS; nullsession->mesvar[MSG_VARIABLE] = DEFAULT_VARIABLE_MESS; nullsession->mesvar[MSG_ROUTE] = DEFAULT_ROUTE_MESS; nullsession->mesvar[MSG_GOTO] = DEFAULT_GOTO_MESS; nullsession->mesvar[MSG_BIND] = DEFAULT_BIND_MESS; nullsession->mesvar[MSG_SYSTEM] = DEFAULT_SYSTEM_MESS; nullsession->mesvar[MSG_PATH]= DEFAULT_PATH_MESS; nullsession->mesvar[MSG_ERROR]= DEFAULT_ERROR_MESS; nullsession->mesvar[MSG_HOOK]= DEFAULT_HOOK_MESS; nullsession->mesvar[MSG_LOG]= DEFAULT_LOG_MESS; nullsession->charset=mystrdup(DEFAULT_CHARSET); nullsession->logcharset=logcs_is_special(DEFAULT_LOGCHARSET) ? DEFAULT_LOGCHARSET : mystrdup(DEFAULT_LOGCHARSET); nullify_conv(&nullsession->c_io); nullify_conv(&nullsession->c_log); nullsession->line_time.tv_sec=0; nullsession->line_time.tv_usec=0; #ifdef HAVE_GNUTLS nullsession->ssl=0; #endif }
SoundConfig * ParseSoundOptions (const char *filename, char *myname) { ConfigData cd ; ConfigDef *SoundConfigReader; SoundConfig *config = CreateSoundConfig (); FreeStorageElem *Storage = NULL, *pCurr; ConfigItem item; cd.filename = filename ; SoundConfigReader = InitConfigReader (myname, &SoundSyntax, CDT_Filename, cd, NULL); if (!SoundConfigReader) return config; item.memory = NULL; PrintConfigReader (SoundConfigReader); ParseConfig (SoundConfigReader, &Storage); /* getting rid of all the crap first */ StorageCleanUp (&Storage, &(config->more_stuff), CF_DISABLED_OPTION); for (pCurr = Storage; pCurr; pCurr = pCurr->next) { if (pCurr->term == NULL) continue; { if (!ReadConfigItem (&item, pCurr)) continue; switch (pCurr->term->id) { case SOUND_SOUND_ID: if( pCurr->sub ) { if( pCurr->sub->term && pCurr->sub->argv ) if( pCurr->sub->term->id >= EVENT_ID_START && pCurr->sub->term->id < EVENT_ID_END ) set_string( &(config->sounds[pCurr->sub->term->id-EVENT_ID_START]), mystrdup( pCurr->sub->argv[0] )); } break; case SOUND_PCMDEVICE_ID: //set_string( &(config->pcmdevice), item.data.string ); config->pcmdevice = item.data.string; break; case SOUND_PATH_ID: config->path = item.data.string; break; case SOUND_DEBUG_ID: config->debug = (int)item.data.integer; break; /* case SOUND_DELAY_ID: set_flags( config->set_flags, SOUND_SET_DELAY ); config->delay = (int)item.data.integer; break; */ /* case SOUND_RPLAY_HOST_ID: set_string_value( &(config->rplay_host), item.data.string, &(config->set_flags), SOUND_SET_RPLAY_HOST ); break; case SOUND_RPLAY_PRI_ID: set_flags( config->set_flags, SOUND_SET_RPLAY_PRIORITY ); config->rplay_priority = (int)item.data.integer; break; case SOUND_RPLAY_VOL_ID: set_flags( config->set_flags, SOUND_SET_RPLAY_VOLUME ); config->rplay_volume = (int)item.data.integer; break; */ default: item.ok_to_free = 1; } } } ReadConfigItem (&item, NULL); DestroyConfig (SoundConfigReader); DestroyFreeStorage (&Storage); return config; }
int http_async_req_status(void *ctx) { struct http_ctx *cx = ctx; char *dns,*srv,buf[CHUNK]; int tmp, i; time_t now = time(NULL); #ifdef WIN32 unsigned long tmp2; #endif switch(cx->state) { case HTS_STRT: dns = getserv(cx->host); srv = getport(cx->host); if(resolve(dns, srv, &cx->addr)) { free(dns); free(srv); cx->state = HTS_DONE; cx->ret = 602; return 1; } free(dns); free(srv); cx->state = HTS_RSLV; return 0; case HTS_RSLV: cx->state = HTS_CONN; cx->last = now; return 0; case HTS_CONN: if(cx->fd == PERROR) { cx->fd = socket(AF_INET, SOCK_STREAM, 0); if(cx->fd == PERROR) goto fail; cx->fdhost = mystrdup(cx->host); #ifdef WIN32 tmp2 = 1; if(ioctlsocket(cx->fd, FIONBIO, &tmp2) == SOCKET_ERROR) goto fail; #else tmp = fcntl(cx->fd, F_GETFL); if(tmp < 0) goto fail; if(fcntl(cx->fd, F_SETFL, tmp|O_NONBLOCK) < 0) goto fail; #endif } if(!connect(cx->fd, (struct sockaddr *)&cx->addr, sizeof(cx->addr))) cx->state = HTS_IDLE; #ifdef WIN32 else if(PERRNO==WSAEISCONN) cx->state = HTS_IDLE; #endif #ifdef MACOSX else if(PERRNO==EISCONN) cx->state = HTS_IDLE; #endif else if(PERRNO!=PEINPROGRESS && PERRNO!=PEALREADY #ifdef WIN32 && PERRNO!=PEAGAIN && PERRNO!=WSAEINVAL #endif ) goto fail; if(now-cx->last>http_timeout) goto timeout; return 0; case HTS_IDLE: if(cx->txdl) { // generate POST cx->tbuf = malloc(strlen(cx->host) + strlen(cx->path) + 121 + cx->txdl + cx->thlen); cx->tptr = 0; cx->tlen = 0; cx->tlen += sprintf(cx->tbuf+cx->tlen, "POST %s HTTP/1.1\n", cx->path); cx->tlen += sprintf(cx->tbuf+cx->tlen, "Host: %s\n", cx->host); if(!cx->keep) cx->tlen += sprintf(cx->tbuf+cx->tlen, "Connection: close\n"); if(cx->thdr) { memcpy(cx->tbuf+cx->tlen, cx->thdr, cx->thlen); cx->tlen += cx->thlen; free(cx->thdr); cx->thdr = NULL; cx->thlen = 0; } cx->tlen += sprintf(cx->tbuf+cx->tlen, "Content-Length: %d\n", cx->txdl); #ifdef BETA cx->tlen += sprintf(cx->tbuf+cx->tlen, "X-Powder-Version: %s%dB%d\n", IDENT_VERSION, SAVE_VERSION, MINOR_VERSION); #else cx->tlen += sprintf(cx->tbuf+cx->tlen, "X-Powder-Version: %s%dS%d\n", IDENT_VERSION, SAVE_VERSION, MINOR_VERSION); #endif cx->tlen += sprintf(cx->tbuf+cx->tlen, "\n"); memcpy(cx->tbuf+cx->tlen, cx->txd, cx->txdl); cx->tlen += cx->txdl; free(cx->txd); cx->txd = NULL; cx->txdl = 0; } else { // generate GET cx->tbuf = malloc(strlen(cx->host) + strlen(cx->path) + 89 + cx->thlen); cx->tptr = 0; cx->tlen = 0; cx->tlen += sprintf(cx->tbuf+cx->tlen, "GET %s HTTP/1.1\n", cx->path); cx->tlen += sprintf(cx->tbuf+cx->tlen, "Host: %s\n", cx->host); if(cx->thdr) { memcpy(cx->tbuf+cx->tlen, cx->thdr, cx->thlen); cx->tlen += cx->thlen; free(cx->thdr); cx->thdr = NULL; cx->thlen = 0; } if(!cx->keep) cx->tlen += sprintf(cx->tbuf+cx->tlen, "Connection: close\n"); #ifdef BETA cx->tlen += sprintf(cx->tbuf+cx->tlen, "X-Powder-Version: %s%dB%d\n", IDENT_VERSION, SAVE_VERSION, MINOR_VERSION); #else cx->tlen += sprintf(cx->tbuf+cx->tlen, "X-Powder-Version: %s%dS%d\n", IDENT_VERSION, SAVE_VERSION, MINOR_VERSION); #endif cx->tlen += sprintf(cx->tbuf+cx->tlen, "\n"); } cx->state = HTS_XMIT; cx->last = now; return 0; case HTS_XMIT: tmp = send(cx->fd, cx->tbuf+cx->tptr, cx->tlen-cx->tptr, 0); if(tmp==PERROR && PERRNO!=PEAGAIN && PERRNO!=PEINTR) goto fail; if(tmp!=PERROR) { cx->tptr += tmp; if(cx->tptr == cx->tlen) { cx->tptr = 0; cx->tlen = 0; if(cx->tbuf) free(cx->tbuf); cx->state = HTS_RECV; } cx->last = now; } if(now-cx->last>http_timeout) goto timeout; return 0; case HTS_RECV: tmp = recv(cx->fd, buf, CHUNK, 0); if(tmp==PERROR && PERRNO!=PEAGAIN && PERRNO!=PEINTR) goto fail; if(tmp!=PERROR) { for(i=0;i<tmp;i++) { process_byte(cx, buf[i]); if(cx->state == HTS_DONE) return 1; } cx->last = now; } if(now-cx->last>http_timeout) goto timeout; return 0; case HTS_DONE: return 1; } return 0; fail: cx->ret = 600; cx->state = HTS_DONE; return 1; timeout: cx->ret = 605; cx->state = HTS_DONE; return 1; }
/* function to parse command line options and check for some usage errors. */ void get_opts(int argc, char **argv, struct options * my_opts) { int c; const char *progname; progname = get_progname(argv[0]); /* set the defaults */ my_opts->quiet = false; my_opts->systables = false; my_opts->indexes = false; my_opts->nodb = false; my_opts->extended = false; my_opts->tablespaces = false; my_opts->dbname = NULL; my_opts->hostname = NULL; my_opts->port = NULL; my_opts->username = NULL; if (argc > 1) { if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0) { help(progname); exit(0); } if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0) { puts("oid2name (PostgreSQL) " PG_VERSION); exit(0); } } /* get opts */ while ((c = getopt(argc, argv, "H:p:U:d:t:o:f:qSxish")) != -1) { switch (c) { /* specify the database */ case 'd': my_opts->dbname = mystrdup(optarg); break; /* specify one tablename to show */ case 't': add_one_elt(optarg, my_opts->tables); break; /* specify one oid_t to show */ case 'o': add_one_elt(optarg, my_opts->oids); break; /* specify one filenode to show */ case 'f': add_one_elt(optarg, my_opts->filenodes); break; /* don't show headers */ case 'q': my_opts->quiet = true; break; /* host to connect to */ case 'H': my_opts->hostname = mystrdup(optarg); break; /* port to connect to on remote host */ case 'p': my_opts->port = mystrdup(optarg); break; /* username */ case 'U': my_opts->username = mystrdup(optarg); break; /* display system tables */ case 'S': my_opts->systables = true; break; /* also display indexes */ case 'i': my_opts->indexes = true; break; /* display extra columns */ case 'x': my_opts->extended = true; break; /* dump tablespaces only */ case 's': my_opts->tablespaces = true; break; case 'h': help(progname); exit(0); break; default: fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); } } }
cue_t *cue_new(const char *file) { cue_t *r = (cue_t *) mc_malloc(sizeof(cue_t)); r->audio_file = NULL; r->album_title = NULL; r->album_performer = NULL; r->album_composer = NULL; r->genre = NULL; r->cuefile = mystrdup(file); r->count = 0; r->entries = NULL; r->_errno = 0; FILE *f = fopen(file, "rt"); time_t _audio_mtime=0; if (f == NULL) { r->_errno = ENOFILECUE; } else { char *line; char *image = NULL; char *year = NULL; cue_entry_t *entry = NULL; int in_tracks = 0; while ((line = readline(f)) != NULL) { trim_replace(&line); if (strcmp(line, "") != 0) { if (!in_tracks) { if (eq(line, "performer")) { mc_free(r->album_performer); r->album_performer = unquote(line, "performer"); } else if (eq(line, "title")) { mc_free(r->album_title); r->album_title = unquote(line, "title"); } else if (eq(line, "file")) { mc_free(r->audio_file); char *fl = getFilePart(line); char *af = unquote(fl, ""); if (strlen(af) > 0) { if (af[0] == '/') { r->audio_file = af; } else { char *cf = mc_strdup(r->cuefile); int ii; for (ii = strlen(cf) - 1; ii >= 0 && cf[ii] != '/'; ii--) ; if (ii >= 0) { cf[ii] = '\0'; char *aaf = (char *)mc_malloc(strlen(cf) + strlen(af) + strlen("/") + 1); sprintf(aaf, "%s/%s", cf, af); r->audio_file = aaf; mc_free(cf); mc_free(af); } else { r->audio_file = af; } } } else { r->audio_file = af; } // We have a full path audio file now. // get the mtime. { struct stat st; stat(r->audio_file,&st); _audio_mtime=st.st_mtime; } mc_free(fl); } else if (eq(line, "rem")) { if (eq(&line[3], "date")) { mc_free(year); year = unquote(&line[3], "date"); } else if (eq(&line[3], "image")) { mc_free(image); image = unquote(&line[3], "image"); } else if (eq(&line[3], "composer")) { mc_free(r->album_composer); r->album_performer = unquote(&line[3], "composer"); } else if (eq(&line[3], "genre")) { mc_free(r->genre); r->genre = unquote(&line[3], "genre"); } } else if (eq(line, "track")) { in_tracks = 1; } } if (in_tracks) { if (eq(line, "track")) { log_debug2("track: entry=%p", entry); if (entry != NULL) { addEntry(r, entry); } entry = cue_entry_new(r); entry->audio_mtime=_audio_mtime; entry->year = mystrdup(year); entry->performer = mystrdup(r->album_performer); entry->composer = mystrdup(r->album_composer); entry->piece = NULL; log_debug2("track: created new entry %p", entry); } else if (eq(line, "title")) { mc_free(entry->title); entry->title = unquote(line, "title"); } else if (eq(line, "performer")) { mc_free(entry->performer); entry->performer = unquote(line, "performer"); } else if (eq(line, "index")) { char *index = unquote(line, "index"); entry->begin_offset_in_ms = calculateOffset(index); mc_free(index); } else if (eq(line, "rem")) { if (eq(&line[3], "composer")) { mc_free(entry->composer); entry->composer = unquote(&line[3], "composer"); } else if (eq(&line[3], "piece")) { mc_free(entry->piece); entry->piece = unquote(&line[3], "piece"); } else if (eq(&line[3], "year")) { mc_free(year); year = unquote(&line[3], "year"); mc_free(entry->year); entry->year = mystrdup(year); } } } } mc_free(line); } if (entry != NULL) { addEntry(r, entry); } mc_free(year); mc_free(image); { int i, N; for (i = 0, N = r->count; i < N - 1; i++) { r->entries[i]->end_offset_in_ms = r->entries[i + 1]->begin_offset_in_ms; r->entries[i]->tracknr = i + 1; } r->entries[i]->tracknr = i + 1; } fclose(f); } return r; }
TLS_APPL_STATE *tls_server_init(const TLS_SERVER_INIT_PROPS *props) { SSL_CTX *server_ctx; long off = 0; int verify_flags = SSL_VERIFY_NONE; int cachable; int scache_timeout; int ticketable = 0; int protomask; TLS_APPL_STATE *app_ctx; int log_mask; /* * Convert user loglevel to internal logmask. */ log_mask = tls_log_mask(props->log_param, props->log_level); if (log_mask & TLS_LOG_VERBOSE) msg_info("initializing the server-side TLS engine"); /* * Load (mostly cipher related) TLS-library internal main.cf parameters. */ tls_param_init(); /* * Detect mismatch between compile-time headers and run-time library. */ tls_check_version(); /* * Initialize the OpenSSL library by the book! To start with, we must * initialize the algorithms. We want cleartext error messages instead of * just error codes, so we load the error_strings. */ SSL_load_error_strings(); OpenSSL_add_ssl_algorithms(); /* * First validate the protocols. If these are invalid, we can't continue. */ protomask = tls_protocol_mask(props->protocols); if (protomask == TLS_PROTOCOL_INVALID) { /* tls_protocol_mask() logs no warning. */ msg_warn("Invalid TLS protocol list \"%s\": disabling TLS support", props->protocols); return (0); } /* * Create an application data index for SSL objects, so that we can * attach TLScontext information; this information is needed inside * tls_verify_certificate_callback(). */ if (TLScontext_index < 0) { if ((TLScontext_index = SSL_get_ex_new_index(0, 0, 0, 0, 0)) < 0) { msg_warn("Cannot allocate SSL application data index: " "disabling TLS support"); return (0); } } /* * If the administrator specifies an unsupported digest algorithm, fail * now, rather than in the middle of a TLS handshake. */ if (!tls_validate_digest(props->mdalg)) { msg_warn("disabling TLS support"); return (0); } /* * Initialize the PRNG (Pseudo Random Number Generator) with some seed * from external and internal sources. Don't enable TLS without some real * entropy. */ if (tls_ext_seed(var_tls_daemon_rand_bytes) < 0) { msg_warn("no entropy for TLS key generation: disabling TLS support"); return (0); } tls_int_seed(); /* * The SSL/TLS specifications require the client to send a message in the * oldest specification it understands with the highest level it * understands in the message. Netscape communicator can still * communicate with SSLv2 servers, so it sends out a SSLv2 client hello. * To deal with it, our server must be SSLv2 aware (even if we don't like * SSLv2), so we need to have the SSLv23 server here. If we want to limit * the protocol level, we can add an option to not use SSLv2/v3/TLSv1 * later. */ ERR_clear_error(); if ((server_ctx = SSL_CTX_new(SSLv23_server_method())) == 0) { msg_warn("cannot allocate server SSL_CTX: disabling TLS support"); tls_print_errors(); return (0); } /* * See the verify callback in tls_verify.c */ SSL_CTX_set_verify_depth(server_ctx, props->verifydepth + 1); /* * The session cache is implemented by the tlsmgr(8) server. * * XXX 200502 Surprise: when OpenSSL purges an entry from the in-memory * cache, it also attempts to purge the entry from the on-disk cache. * This is undesirable, especially when we set the in-memory cache size * to 1. For this reason we don't allow OpenSSL to purge on-disk cache * entries, and leave it up to the tlsmgr process instead. Found by * Victor Duchovni. */ if (tls_mgr_policy(props->cache_type, &cachable, &scache_timeout) != TLS_MGR_STAT_OK) scache_timeout = 0; if (scache_timeout <= 0) cachable = 0; /* * Protocol work-arounds, OpenSSL version dependent. */ off |= tls_bug_bits(); /* * Add SSL_OP_NO_TICKET when the timeout is zero or library support is * incomplete. The SSL_CTX_set_tlsext_ticket_key_cb feature was added in * OpenSSL 0.9.8h, while SSL_NO_TICKET was added in 0.9.8f. */ #ifdef SSL_OP_NO_TICKET #if !defined(OPENSSL_NO_TLSEXT) && OPENSSL_VERSION_NUMBER >= 0x0090808fL ticketable = (scache_timeout > 0 && !(off & SSL_OP_NO_TICKET)); if (ticketable) SSL_CTX_set_tlsext_ticket_key_cb(server_ctx, ticket_cb); #endif if (!ticketable) off |= SSL_OP_NO_TICKET; #endif SSL_CTX_set_options(server_ctx, off); /* * Global protocol selection. */ if (protomask != 0) SSL_CTX_set_options(server_ctx, ((protomask & TLS_PROTOCOL_TLSv1) ? SSL_OP_NO_TLSv1 : 0L) | ((protomask & TLS_PROTOCOL_TLSv1_1) ? SSL_OP_NO_TLSv1_1 : 0L) | ((protomask & TLS_PROTOCOL_TLSv1_2) ? SSL_OP_NO_TLSv1_2 : 0L) | ((protomask & TLS_PROTOCOL_SSLv3) ? SSL_OP_NO_SSLv3 : 0L) | ((protomask & TLS_PROTOCOL_SSLv2) ? SSL_OP_NO_SSLv2 : 0L)); /* * Some sites may want to give the client less rope. On the other hand, * this could trigger inter-operability issues, the client should not * offer ciphers it implements poorly, but this hasn't stopped some * vendors from getting it wrong. * * XXX: Given OpenSSL's security history, nobody should still be using * 0.9.7, let alone 0.9.6 or earlier. Warning added to TLS_README.html. */ if (var_tls_preempt_clist) SSL_CTX_set_options(server_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); /* * Set the call-back routine to debug handshake progress. */ if (log_mask & TLS_LOG_DEBUG) SSL_CTX_set_info_callback(server_ctx, tls_info_callback); /* * Load the CA public key certificates for both the server cert and for * the verification of client certificates. As provided by OpenSSL we * support two types of CA certificate handling: One possibility is to * add all CA certificates to one large CAfile, the other possibility is * a directory pointed to by CApath, containing separate files for each * CA with softlinks named after the hash values of the certificate. The * first alternative has the advantage that the file is opened and read * at startup time, so that you don't have the hassle to maintain another * copy of the CApath directory for chroot-jail. */ if (tls_set_ca_certificate_info(server_ctx, props->CAfile, props->CApath) < 0) { /* tls_set_ca_certificate_info() already logs a warning. */ SSL_CTX_free(server_ctx); /* 200411 */ return (0); } /* * Load the server public key certificate and private key from file and * check whether the cert matches the key. We can use RSA certificates * ("cert") DSA certificates ("dcert") or ECDSA certificates ("eccert"). * All three can be made available at the same time. The CA certificates * for all three are handled in the same setup already finished. Which * one is used depends on the cipher negotiated (that is: the first * cipher listed by the client which does match the server). A client * with RSA only (e.g. Netscape) will use the RSA certificate only. A * client with openssl-library will use RSA first if not especially * changed in the cipher setup. */ if (tls_set_my_certificate_key_info(server_ctx, props->cert_file, props->key_file, props->dcert_file, props->dkey_file, props->eccert_file, props->eckey_file) < 0) { /* tls_set_my_certificate_key_info() already logs a warning. */ SSL_CTX_free(server_ctx); /* 200411 */ return (0); } /* * According to OpenSSL documentation, a temporary RSA key is needed when * export ciphers are in use, because the certified key cannot be * directly used. */ SSL_CTX_set_tmp_rsa_callback(server_ctx, tls_tmp_rsa_cb); /* * Diffie-Hellman key generation parameters can either be loaded from * files (preferred) or taken from compiled in values. First, set the * callback that will select the values when requested, then load the * (possibly) available DH parameters from files. We are generous with * the error handling, since we do have default values compiled in, so we * will not abort but just log the error message. */ SSL_CTX_set_tmp_dh_callback(server_ctx, tls_tmp_dh_cb); if (*props->dh1024_param_file != 0) tls_set_dh_from_file(props->dh1024_param_file, 1024); if (*props->dh512_param_file != 0) tls_set_dh_from_file(props->dh512_param_file, 512); /* * Enable EECDH if available, errors are not fatal, we just keep going * with any remaining key-exchange algorithms. */ (void) tls_set_eecdh_curve(server_ctx, props->eecdh_grade); /* * If we want to check client certificates, we have to indicate it in * advance. By now we only allow to decide on a global basis. If we want * to allow certificate based relaying, we must ask the client to provide * one with SSL_VERIFY_PEER. The client now can decide, whether it * provides one or not. We can enforce a failure of the negotiation with * SSL_VERIFY_FAIL_IF_NO_PEER_CERT, if we do not allow a connection * without one. In the "server hello" following the initialization by the * "client hello" the server must provide a list of CAs it is willing to * accept. Some clever clients will then select one from the list of * available certificates matching these CAs. Netscape Communicator will * present the list of certificates for selecting the one to be sent, or * it will issue a warning, if there is no certificate matching the * available CAs. * * With regard to the purpose of the certificate for relaying, we might like * a later negotiation, maybe relaying would already be allowed for other * reasons, but this would involve severe changes in the internal postfix * logic, so we have to live with it the way it is. */ if (props->ask_ccert) verify_flags = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE; SSL_CTX_set_verify(server_ctx, verify_flags, tls_verify_certificate_callback); if (*props->CAfile) SSL_CTX_set_client_CA_list(server_ctx, SSL_load_client_CA_file(props->CAfile)); /* * Initialize our own TLS server handle, before diving into the details * of TLS session cache management. */ app_ctx = tls_alloc_app_context(server_ctx, log_mask); if (cachable || ticketable || props->set_sessid) { /* * Initialize the session cache. * * With a large number of concurrent smtpd(8) processes, it is not a * good idea to cache multiple large session objects in each process. * We set the internal cache size to 1, and don't register a * "remove_cb" so as to avoid deleting good sessions from the * external cache prematurely (when the internal cache is full, * OpenSSL removes sessions from the external cache also)! * * This makes SSL_CTX_remove_session() not useful for flushing broken * sessions from the external cache, so we must delete them directly * (not via a callback). * * Set a session id context to identify to what type of server process * created a session. In our case, the context is simply the name of * the mail system: "Postfix/TLS". */ SSL_CTX_sess_set_cache_size(server_ctx, 1); SSL_CTX_set_session_id_context(server_ctx, (void *) &server_session_id_context, sizeof(server_session_id_context)); SSL_CTX_set_session_cache_mode(server_ctx, SSL_SESS_CACHE_SERVER | SSL_SESS_CACHE_NO_AUTO_CLEAR); if (cachable) { app_ctx->cache_type = mystrdup(props->cache_type); SSL_CTX_sess_set_get_cb(server_ctx, get_server_session_cb); SSL_CTX_sess_set_new_cb(server_ctx, new_server_session_cb); } /* * OpenSSL ignores timed-out sessions. We need to set the internal * cache timeout at least as high as the external cache timeout. This * applies even if no internal cache is used. We set the session * lifetime to twice the cache lifetime, which is also the issuing * and retired key validation lifetime of session tickets keys. This * way a session always lasts longer than the server's ability to * decrypt its session ticket. Otherwise, a bug in OpenSSL may fail * to re-issue tickets when sessions decrypt, but are expired. */ SSL_CTX_set_timeout(server_ctx, 2 * scache_timeout); } else { /* * If we have no external cache, disable all caching. No use wasting * server memory resources with sessions they are unlikely to be able * to reuse. */ SSL_CTX_set_session_cache_mode(server_ctx, SSL_SESS_CACHE_OFF); } return (app_ctx); }
int parse_aff_file(FILE * afflst) { int i, j; int numents=0; char achar='\0'; short ff=0; char ft; struct affent * ptr= NULL; struct affent * nptr= NULL; char * line = malloc(MAX_LN_LEN); while (fgets(line,MAX_LN_LEN,afflst)) { mychomp(line); ft = ' '; fprintf(stderr,"parsing line: %s\n",line); if (strncmp(line,"FULLSTRIP",9) == 0) fullstrip = 1; if (strncmp(line,"PFX",3) == 0) ft = 'P'; if (strncmp(line,"SFX",3) == 0) ft = 'S'; if (ft != ' ') { char * tp = line; char * piece; ff = 0; i = 0; while ((piece=mystrsep(&tp,' '))) { if (*piece != '\0') { switch(i) { case 0: break; case 1: { achar = *piece; break; } case 2: { if (*piece == 'Y') ff = XPRODUCT; break; } case 3: { numents = atoi(piece); ptr = malloc(numents * sizeof(struct affent)); ptr->achar = achar; ptr->xpflg = ff; fprintf(stderr,"parsing %c entries %d\n",achar,numents); break; } default: break; } i++; } free(piece); } /* now parse all of the sub entries*/ nptr = ptr; for (j=0; j < numents; j++) { if (!fgets(line,MAX_LN_LEN,afflst)) return 1; mychomp(line); tp = line; i = 0; while ((piece=mystrsep(&tp,' '))) { if (*piece != '\0') { switch(i) { case 0: { if (nptr != ptr) { nptr->achar = ptr->achar; nptr->xpflg = ptr->xpflg; } break; } case 1: break; case 2: { nptr->strip = mystrdup(piece); nptr->stripl = strlen(nptr->strip); if (strcmp(nptr->strip,"0") == 0) { free(nptr->strip); nptr->strip=mystrdup(""); nptr->stripl = 0; } break; } case 3: { nptr->appnd = mystrdup(piece); nptr->appndl = strlen(nptr->appnd); if (strcmp(nptr->appnd,"0") == 0) { free(nptr->appnd); nptr->appnd=mystrdup(""); nptr->appndl = 0; } break; } case 4: { encodeit(nptr,piece);} fprintf(stderr, " affix: %s %d, strip: %s %d\n",nptr->appnd, nptr->appndl,nptr->strip,nptr->stripl); default: break; } i++; } free(piece); } nptr++; } if (ft == 'P') { ptable[numpfx].aep = ptr; ptable[numpfx].num = numents; fprintf(stderr,"ptable %d num is %d flag %c\n",numpfx,ptable[numpfx].num,ptr->achar); numpfx++; } else { stable[numsfx].aep = ptr; stable[numsfx].num = numents; fprintf(stderr,"stable %d num is %d flag %c\n",numsfx,stable[numsfx].num,ptr->achar); numsfx++; } ptr = NULL; nptr = NULL; numents = 0; achar='\0'; } } free(line); return 0; }
TLS_APPL_STATE *tls_client_init(const TLS_CLIENT_INIT_PROPS *props) { long off = 0; int cachable; SSL_CTX *client_ctx; TLS_APPL_STATE *app_ctx; const EVP_MD *md_alg; unsigned int md_len; int log_mask; /* * Convert user loglevel to internal logmask. */ log_mask = tls_log_mask(props->log_param, props->log_level); if (log_mask & TLS_LOG_VERBOSE) msg_info("initializing the client-side TLS engine"); /* * Load (mostly cipher related) TLS-library internal main.cf parameters. */ tls_param_init(); /* * Detect mismatch between compile-time headers and run-time library. */ tls_check_version(); /* * Initialize the OpenSSL library by the book! To start with, we must * initialize the algorithms. We want cleartext error messages instead of * just error codes, so we load the error_strings. */ SSL_load_error_strings(); OpenSSL_add_ssl_algorithms(); /* * Create an application data index for SSL objects, so that we can * attach TLScontext information; this information is needed inside * tls_verify_certificate_callback(). */ if (TLScontext_index < 0) { if ((TLScontext_index = SSL_get_ex_new_index(0, 0, 0, 0, 0)) < 0) { msg_warn("Cannot allocate SSL application data index: " "disabling TLS support"); return (0); } } /* * If the administrator specifies an unsupported digest algorithm, fail * now, rather than in the middle of a TLS handshake. */ if ((md_alg = EVP_get_digestbyname(props->fpt_dgst)) == 0) { msg_warn("Digest algorithm \"%s\" not found: disabling TLS support", props->fpt_dgst); return (0); } /* * Sanity check: Newer shared libraries may use larger digests. */ if ((md_len = EVP_MD_size(md_alg)) > EVP_MAX_MD_SIZE) { msg_warn("Digest algorithm \"%s\" output size %u too large:" " disabling TLS support", props->fpt_dgst, md_len); return (0); } /* * Initialize the PRNG (Pseudo Random Number Generator) with some seed * from external and internal sources. Don't enable TLS without some real * entropy. */ if (tls_ext_seed(var_tls_daemon_rand_bytes) < 0) { msg_warn("no entropy for TLS key generation: disabling TLS support"); return (0); } tls_int_seed(); /* * The SSL/TLS specifications require the client to send a message in the * oldest specification it understands with the highest level it * understands in the message. RFC2487 is only specified for TLSv1, but * we want to be as compatible as possible, so we will start off with a * SSLv2 greeting allowing the best we can offer: TLSv1. We can restrict * this with the options setting later, anyhow. */ ERR_clear_error(); if ((client_ctx = SSL_CTX_new(SSLv23_client_method())) == 0) { msg_warn("cannot allocate client SSL_CTX: disabling TLS support"); tls_print_errors(); return (0); } /* * See the verify callback in tls_verify.c */ SSL_CTX_set_verify_depth(client_ctx, props->verifydepth + 1); /* * Protocol selection is destination dependent, so we delay the protocol * selection options to the per-session SSL object. */ off |= tls_bug_bits(); SSL_CTX_set_options(client_ctx, off); /* * Set the call-back routine for verbose logging. */ if (log_mask & TLS_LOG_DEBUG) SSL_CTX_set_info_callback(client_ctx, tls_info_callback); /* * Load the CA public key certificates for both the client cert and for * the verification of server certificates. As provided by OpenSSL we * support two types of CA certificate handling: One possibility is to * add all CA certificates to one large CAfile, the other possibility is * a directory pointed to by CApath, containing separate files for each * CA with softlinks named after the hash values of the certificate. The * first alternative has the advantage that the file is opened and read * at startup time, so that you don't have the hassle to maintain another * copy of the CApath directory for chroot-jail. */ if (tls_set_ca_certificate_info(client_ctx, props->CAfile, props->CApath) < 0) { /* tls_set_ca_certificate_info() already logs a warning. */ SSL_CTX_free(client_ctx); /* 200411 */ return (0); } /* * We do not need a client certificate, so the certificates are only * loaded (and checked) if supplied. A clever client would handle * multiple client certificates and decide based on the list of * acceptable CAs, sent by the server, which certificate to submit. * OpenSSL does however not do this and also has no call-back hooks to * easily implement it. * * Load the client public key certificate and private key from file and * check whether the cert matches the key. We can use RSA certificates * ("cert") DSA certificates ("dcert") or ECDSA certificates ("eccert"). * All three can be made available at the same time. The CA certificates * for all three are handled in the same setup already finished. Which * one is used depends on the cipher negotiated (that is: the first * cipher listed by the client which does match the server). The client * certificate is presented after the server chooses the session cipher, * so we will just present the right cert for the chosen cipher (if it * uses certificates). */ if (tls_set_my_certificate_key_info(client_ctx, props->cert_file, props->key_file, props->dcert_file, props->dkey_file, props->eccert_file, props->eckey_file) < 0) { /* tls_set_my_certificate_key_info() already logs a warning. */ SSL_CTX_free(client_ctx); /* 200411 */ return (0); } /* * According to the OpenSSL documentation, temporary RSA key is needed * export ciphers are in use. We have to provide one, so well, we just do * it. */ SSL_CTX_set_tmp_rsa_callback(client_ctx, tls_tmp_rsa_cb); /* * Finally, the setup for the server certificate checking, done "by the * book". */ SSL_CTX_set_verify(client_ctx, SSL_VERIFY_NONE, tls_verify_certificate_callback); /* * Initialize the session cache. * * Since the client does not search an internal cache, we simply disable it. * It is only useful for expiring old sessions, but we do that in the * tlsmgr(8). * * This makes SSL_CTX_remove_session() not useful for flushing broken * sessions from the external cache, so we must delete them directly (not * via a callback). */ if (tls_mgr_policy(props->cache_type, &cachable) != TLS_MGR_STAT_OK) cachable = 0; /* * Allocate an application context, and populate with mandatory protocol * and cipher data. */ app_ctx = tls_alloc_app_context(client_ctx, log_mask); /* * The external session cache is implemented by the tlsmgr(8) process. */ if (cachable) { app_ctx->cache_type = mystrdup(props->cache_type); /* * OpenSSL does not use callbacks to load sessions from a client * cache, so we must invoke that function directly. Apparently, * OpenSSL does not provide a way to pass session names from here to * call-back routines that do session lookup. * * OpenSSL can, however, automatically save newly created sessions for * us by callback (we create the session name in the call-back * function). * * XXX gcc 2.95 can't compile #ifdef .. #endif in the expansion of * SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL_STORE | * SSL_SESS_CACHE_NO_AUTO_CLEAR. */ #ifndef SSL_SESS_CACHE_NO_INTERNAL_STORE #define SSL_SESS_CACHE_NO_INTERNAL_STORE 0 #endif SSL_CTX_set_session_cache_mode(client_ctx, SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_NO_INTERNAL_STORE | SSL_SESS_CACHE_NO_AUTO_CLEAR); SSL_CTX_sess_set_new_cb(client_ctx, new_client_session_cb); } return (app_ctx); }