Example #1
0
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);
}
Example #2
0
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;
}
Example #3
0
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 *)&param->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 *)&param->sins, &size)) {RETURN(21);};
	if(bind(param->clisock,(struct sockaddr *)&param->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 *)&param->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, &param->sins, buf, i, conf.timeouts[SINGLEBYTE_L]*1000) != i){
		RETURN(820);
	}
	param->statscli += i;
	len = sockrecvfrom(param->remsock, &param->sins, buf, BUFSIZE, 15000);
	if(len <= 13) {
		RETURN(821);
	}
	param->statssrv += len;
	if(buf[6] || buf[7]){
		if(socksendto(param->clisock, &param->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, &param->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);
 }
Example #4
0
/******************************************************************
 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;
}
Example #5
0
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;
}
Example #6
0
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);
}
Example #7
0
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();
}
Example #8
0
/**
 * 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);
	}
}
Example #9
0
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;
}
Example #10
0
/**
 * 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);
	}
}
Example #11
0
/**
 * 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);
	}
}
Example #12
0
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;
}
Example #14
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);
}
Example #15
0
 /*
  * 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));
}
Example #16
0
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, &regexp) == 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, &regexp, &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, &regexp))
	    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, &regexp, &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);
    }
}
Example #17
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);
}
Example #18
0
    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");
Example #19
0
/* 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;
		}
	}
}
Example #20
0
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);
}
Example #21
0
/******************************************************************
 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);
	}
}
Example #22
0
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);
}
Example #23
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
}
Example #24
0
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;

}
Example #25
0
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;
}
Example #26
0
/* 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);
        }
    }
}
Example #27
0
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;
}
Example #28
0
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);
}
Example #29
0
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;
}
Example #30
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);
}