示例#1
0
/* initialize the network 
 * we talk on unix sockets
 */
static struct backend *init_net(const char *unixpath)
{
  int lmtpdsock;
  struct sockaddr_un addr;
  struct backend *conn;

  if ((lmtpdsock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
      just_exit("socket failed");
  }

  addr.sun_family = AF_UNIX;
  strlcpy(addr.sun_path, unixpath, sizeof(addr.sun_path));

  if (connect(lmtpdsock, (struct sockaddr *) &addr, 
	      sizeof(addr.sun_family) + strlen(addr.sun_path) + 1) < 0) {
      just_exit("connect failed");
  }

  conn = xzmalloc(sizeof(struct backend));
  conn->timeout = NULL;
  conn->in = prot_new(lmtpdsock, 0);
  conn->out = prot_new(lmtpdsock, 1);
  conn->sock = lmtpdsock;
  prot_setflushonread(conn->in, conn->out);
  conn->prot = &lmtp_protocol;

  return conn;
}
示例#2
0
/* initialize the network */
int init_net(char *serverFQDN, int port, isieve_t **obj)
{
  struct addrinfo hints, *res0, *res;
  int err;
  char portstr[6];
  int sock = -1;
    
  snprintf(portstr, sizeof(portstr), "%d", port);
  memset(&hints, 0, sizeof(hints));
  hints.ai_family = PF_UNSPEC;
  hints.ai_socktype = SOCK_STREAM;
  if ((err = getaddrinfo(serverFQDN, portstr, &hints, &res0)) != 0) {
      fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(err)); 
      return -1;
  }
    
  for (res = res0; res; res = res->ai_next) {
      sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
      if (sock < 0)
	  continue;
      if (connect(sock, res->ai_addr, res->ai_addrlen) >= 0)
	  break;
      close(sock);
      sock = -1;
  }

  freeaddrinfo(res0);
  if (sock < 0) {
    perror("connect");
    return -1;
  }

  *obj = (isieve_t *) xzmalloc(sizeof(isieve_t));

  (*obj)->sock = sock;
  (*obj)->serverFQDN = xstrdup(serverFQDN);
  (*obj)->port = port;

  /* set up the prot layer */
  (*obj)->pin = prot_new(sock, 0);
  (*obj)->pout = prot_new(sock, 1); 

  return 0;
}
示例#3
0
int init_net(const char *host, char *port,
	     struct protstream **in, struct protstream **out)
{
    int sock = -1, err;
    struct addrinfo hints, *res, *res0;

    memset(&hints, 0, sizeof(hints));
    hints.ai_family = PF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = 0;
    if ((err = getaddrinfo(host, port, &hints, &res0)) != 0) {
	syslog(LOG_ERR, "getaddrinfo(%s, %s) failed: %m", host, port);
	return -1;
    }

    for (res = res0; res; res = res->ai_next) {
	if ((sock = socket(res->ai_family, res->ai_socktype,
			   res->ai_protocol)) < 0)
	    continue;
	if (connect(sock, res->ai_addr, res->ai_addrlen) >= 0)
	    break;
	close(sock);
	sock = -1;
    }
    freeaddrinfo(res0);
    if(sock < 0) {
	syslog(LOG_ERR, "connect(%s:%s) failed: %m", host, port);
	return -1;
    }
    
    *in = prot_new(sock, 0);
    *out = prot_new(sock, 1);
    prot_setflushonread(*in, *out);

    return sock;
}
示例#4
0
文件: prot.c 项目: gnb/cyrus-imapd
static void test_printstring(void)
{
    PROLOG;
    struct protstream *p;
    int len;
    struct buf b = BUF_INITIALIZER;
    int i;
    char str[2600];

    p = prot_new(_fd, 1);
    CU_ASSERT_PTR_NOT_NULL_FATAL(p);

    /* NULL string */
    BEGIN;
    prot_printstring(p, NULL);
    prot_flush(p);
    END(str, len);
    CU_ASSERT_EQUAL(len, 3);
    CU_ASSERT_STRING_EQUAL(str, "NIL");

    /* Zero length string */
    BEGIN;
    prot_printstring(p, "");
    prot_flush(p);
    END(str, len);
    CU_ASSERT_EQUAL(len, 2);
    CU_ASSERT_STRING_EQUAL(str, "\"\"");

    /* Boring string */
    BEGIN;
    prot_printstring(p, "Hello");
    prot_flush(p);
    END(str, len);
    CU_ASSERT_EQUAL(len, 7);
    CU_ASSERT_STRING_EQUAL(str, "\"Hello\"");

    /* String with non-dangerous whitespace */
    BEGIN;
    prot_printstring(p, "Hello World\tagain");
    prot_flush(p);
    END(str, len);
    CU_ASSERT_EQUAL(len, 19);
    CU_ASSERT_STRING_EQUAL(str, "\"Hello World\tagain\"");

    /* String with dangerous whitespace */
    BEGIN;
    prot_printstring(p, "Good\rBye\nEarth");
    prot_flush(p);
    END(str, len);
    CU_ASSERT_EQUAL(len, 20);
    CU_ASSERT_STRING_EQUAL(str, "{14}\r\nGood\rBye\nEarth");

    /* String with embedded dquote */
    BEGIN;
    prot_printstring(p, "Quot\"able");
    prot_flush(p);
    END(str, len);
    CU_ASSERT_EQUAL(len, 14);
    CU_ASSERT_STRING_EQUAL(str, "{9}\r\nQuot\"able");

    /* String with embedded percent */
    BEGIN;
    prot_printstring(p, "per%ent");
    prot_flush(p);
    END(str, len);
    CU_ASSERT_EQUAL(len, 12);
    CU_ASSERT(!strcmp(str, "{7}\r\nper%ent"));

    /* String with embedded backslash */
    BEGIN;
    prot_printstring(p, "slash\\dot");
    prot_flush(p);
    END(str, len);
    CU_ASSERT_EQUAL(len, 14);
    CU_ASSERT_STRING_EQUAL(str, "{9}\r\nslash\\dot");

    /* String with embedded 8-bit chars */
    BEGIN;
    prot_printstring(p, "Hi I'm \330l\345f");
    prot_flush(p);
    END(str, len);
    CU_ASSERT_EQUAL(len, 17);
    CU_ASSERT_STRING_EQUAL(str, "{11}\r\nHi I'm \330l\345f");

    /* Boring but overly long string */
    for (i = 0 ; i<500 ; i++)
	buf_appendcstr(&b, "blah ");
    buf_cstring(&b);
    BEGIN;
    prot_printstring(p, b.s);
    prot_flush(p);
    END(str, len);
    CU_ASSERT_EQUAL(len, b.len+8);
    CU_ASSERT_STRING_EQUAL(str+8, b.s);
    str[8] = '\0';
    CU_ASSERT_STRING_EQUAL(str, "{2500}\r\n");

    buf_free(&b);
    prot_free(p);
    EPILOG;
}
示例#5
0
int main(int argc, char **argv)
{
    int r = 0;
    int opt;
    int lmtpflag = 0;
    int ignorequota = 0;
    char *mailboxname = NULL;
    char *authuser = NULL;
    char *return_path = NULL;
    char buf[1024];
    char *alt_config = NULL;

    while ((opt = getopt(argc, argv, "C:df:r:m:a:F:eE:lqD")) != EOF) {
	switch(opt) {
	case 'C': /* alt config file */
	    alt_config = optarg;
	    break;

	case 'd':
	    /* Ignore -- /bin/mail compatibility flags */
	    break;

        case 'D':
	    logdebug = 1;
	    break;

	case 'r':
	case 'f':
	    return_path = optarg;
	    break;

	case 'm':
	    if (mailboxname) {
		fprintf(stderr, "deliver: multiple -m options\n");
		usage();
		/* NOTREACHED */
	    }
	    if (*optarg) mailboxname = optarg;
	    break;

	case 'a':
	    if (authuser) {
		fprintf(stderr, "deliver: multiple -a options\n");
		usage();
		/* NOTREACHED */
	    }
	    authuser = optarg;
	    break;

	case 'F': /* set IMAP flag. we no longer support this */
	    fprintf(stderr,"deliver: 'F' option no longer supported\n");
	    usage();
	    break;

	case 'e':
	    /* duplicate delivery. ignore */
	    break;

	case 'E':
	    fprintf(stderr,"deliver: 'E' option no longer supported\n");
	    usage();
	    break;

	case 'l':
	    lmtpflag = 1;
	    break;

	case 'q':
	    ignorequota = 1;
	    break;

	default:
	    usage();
	    /* NOTREACHED */
	}
    }

    deliver_in = prot_new(0, 0);
    deliver_out = prot_new(1, 1);
    prot_setflushonread(deliver_in, deliver_out);
    prot_settimeout(deliver_in, 300);

    cyrus_init(alt_config, "deliver", CYRUSINIT_NODB);

    sockaddr = config_getstring(IMAPOPT_LMTPSOCKET);
    if (!sockaddr) {	
	strlcpy(buf, config_dir, sizeof(buf));
	strlcat(buf, "/socket/lmtp", sizeof(buf));
	sockaddr = buf;
    }

    if (lmtpflag == 1) {
	struct backend *conn = init_net(sockaddr);

	pipe_through(conn);

	backend_disconnect(conn);
	free(conn);
    }
    else {
	if (return_path == NULL) {
	    uid_t me = getuid();
	    struct passwd *p = getpwuid(me);
	    return_path = p->pw_name;
	}

	/* deliver to users or global mailbox */
	r = deliver_msg(return_path,authuser, ignorequota,
			argv+optind, argc - optind, mailboxname);
    }

    cyrus_done();

    return r;
}
示例#6
0
EXPORTED int command_popen(struct command **cmdp, const char *mode,
                           const char *cwd, const char *argv0, ...)
{
    va_list va;
    const char *p;
    strarray_t argv = STRARRAY_INITIALIZER;
    pid_t pid;
    int r = 0;
    struct command *cmd;
    int do_stdin = (strchr(mode, 'w') != NULL);
    int do_stdout = (strchr(mode, 'r') != NULL);
    int stdin_pipe[2] = { -1, -1 };
    int stdout_pipe[2] = { -1, -1 };

    strarray_append(&argv, argv0);

    va_start(va, argv0);
    while ((p = va_arg(va, const char *)))
        strarray_append(&argv, p);
    va_end(va);

    if (do_stdin) {
        r = pipe(stdin_pipe);
        if (r) {
            syslog(LOG_ERR, "Failed to pipe(): %m");
            r = IMAP_SYS_ERROR;
            goto out;
        }
    }

    if (do_stdout) {
        r = pipe(stdout_pipe);
        if (r) {
            syslog(LOG_ERR, "Failed to pipe(): %m");
            r = IMAP_SYS_ERROR;
            goto out;
        }
    }

    pid = fork();
    if (pid < 0) {
        syslog(LOG_ERR, "Failed to fork: %m");
        r = IMAP_SYS_ERROR;
        goto out;
    }

    if (!pid) {
        /* in child */
        if (do_stdin) {
            close(stdin_pipe[PIPE_WRITE]);
            dup2(stdin_pipe[PIPE_READ], STDIN_FILENO);
            close(stdin_pipe[PIPE_READ]);
        }
        if (do_stdout) {
            close(stdout_pipe[PIPE_READ]);
            dup2(stdout_pipe[PIPE_WRITE], STDOUT_FILENO);
            close(stdout_pipe[PIPE_WRITE]);
        }

        if (cwd) {
            r = chdir(cwd);
            if (r) syslog(LOG_ERR, "Failed to chdir(%s): %m", cwd);
        }

        r = execv(argv0, argv.data);
        syslog(LOG_ERR, "Failed to execute %s: %m", argv0);
        exit(1);
    }

    /* in parent */
    cmd = xzmalloc(sizeof(struct command));
    cmd->argv0 = xstrdup(argv0);
    cmd->pid = pid;
    if (do_stdin)
        cmd->stdin_prot = prot_new(stdin_pipe[PIPE_WRITE], /*write*/1);
    if (do_stdout)
        cmd->stdout_prot = prot_new(stdout_pipe[PIPE_READ], /*write*/0);
    *cmdp = cmd;

out:
    if (stdin_pipe[PIPE_READ] >= 0) close(stdin_pipe[PIPE_READ]);
    if (stdout_pipe[PIPE_WRITE] >= 0) close(stdout_pipe[PIPE_WRITE]);
    if (r) {
        if (stdin_pipe[PIPE_WRITE] >= 0) close(stdin_pipe[PIPE_WRITE]);
        if (stdout_pipe[PIPE_READ] >= 0) close(stdout_pipe[PIPE_READ]);
    }
    strarray_fini(&argv);
    return r;
}
示例#7
0
struct backend *backend_connect(struct backend *ret_backend, const char *server,
				struct protocol_t *prot, const char *userid,
				sasl_callback_t *cb, const char **auth_status)
{
    /* need to (re)establish connection to server or create one */
    int sock = -1;
    int r;
    int err = -1;
    int ask = 1; /* should we explicitly ask for capabilities? */
    struct addrinfo hints, *res0 = NULL, *res;
    struct sockaddr_un sunsock;
    char buf[2048];
    struct sigaction action;
    struct backend *ret;
    char rsessionid[MAX_SESSIONID_SIZE];

    if (!ret_backend) {
	ret = xzmalloc(sizeof(struct backend));
	strlcpy(ret->hostname, server, sizeof(ret->hostname));
	ret->timeout = NULL;
    }
    else
	ret = ret_backend;

    if (server[0] == '/') { /* unix socket */
	res0 = &hints;
	memset(res0, 0, sizeof(struct addrinfo));
	res0->ai_family = PF_UNIX;
	res0->ai_socktype = SOCK_STREAM;

 	res0->ai_addr = (struct sockaddr *) &sunsock;
 	res0->ai_addrlen = sizeof(sunsock.sun_family) + strlen(server) + 1;
#ifdef SIN6_LEN
 	res0->ai_addrlen += sizeof(sunsock.sun_len);
 	sunsock.sun_len = res0->ai_addrlen;
#endif
	sunsock.sun_family = AF_UNIX;
	strlcpy(sunsock.sun_path, server, sizeof(sunsock.sun_path));

	/* XXX set that we are preauthed */

	/* change hostname to 'config_servername' */
	strlcpy(ret->hostname, config_servername, sizeof(ret->hostname));
    }
    else { /* inet socket */
	memset(&hints, 0, sizeof(hints));
	hints.ai_family = PF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	err = getaddrinfo(server, prot->service, &hints, &res0);
	if (err) {
	    syslog(LOG_ERR, "getaddrinfo(%s) failed: %s",
		   server, gai_strerror(err));
	    goto error;
	}
    }

    /* Setup timeout */
    timedout = 0;
    action.sa_flags = 0;
    action.sa_handler = timed_out;
    sigemptyset(&action.sa_mask);
    if(sigaction(SIGALRM, &action, NULL) < 0) 
    {
	syslog(LOG_ERR, "Setting timeout in backend_connect failed: sigaction: %m");
	/* continue anyway */
    }
    
    for (res = res0; res; res = res->ai_next) {
	sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
	if (sock < 0)
	    continue;
	alarm(config_getint(IMAPOPT_CLIENT_TIMEOUT));
	if (connect(sock, res->ai_addr, res->ai_addrlen) >= 0)
	    break;
	if(errno == EINTR && timedout == 1)
	    errno = ETIMEDOUT;
	close(sock);
	sock = -1;
    }

    /* Remove timeout code */
    alarm(0);
    signal(SIGALRM, SIG_IGN);
    
    if (sock < 0) {
	if (res0 != &hints)
	    freeaddrinfo(res0);
	syslog(LOG_ERR, "connect(%s) failed: %m", server);
	goto error;
    }
    memcpy(&ret->addr, res->ai_addr, res->ai_addrlen);
    if (res0 != &hints)
	freeaddrinfo(res0);

    ret->in = prot_new(sock, 0);
    ret->out = prot_new(sock, 1);
    ret->sock = sock;
    prot_setflushonread(ret->in, ret->out);
    ret->prot = prot;

    /* use literal+ to send literals */
    prot_setisclient(ret->in, 1);
    prot_setisclient(ret->out, 1);
    
    if (prot->banner.auto_capa) {
	/* try to get the capabilities from the banner */
	r = ask_capability(ret, /*dobanner*/1, AUTO_CAPA_BANNER);
	if (r) {
	    /* found capabilities in banner -> don't ask */
	    ask = 0;
	}
    }
    else {
	do { /* read the initial greeting */
	    if (!prot_fgets(buf, sizeof(buf), ret->in)) {
		syslog(LOG_ERR,
		       "backend_connect(): couldn't read initial greeting: %s",
		       ret->in->error ? ret->in->error : "(null)");
		goto error;
	    }
	} while (strncasecmp(buf, prot->banner.resp,
			     strlen(prot->banner.resp)));
	strncpy(ret->banner, buf, 2048);
    }

    if (ask) {
	/* get the capabilities */
	ask_capability(ret, /*dobanner*/0, AUTO_CAPA_NO);
    }

    /* now need to authenticate to backend server,
       unless we're doing LMTP/CSYNC on a UNIX socket (deliver/sync_client) */
    if ((server[0] != '/') ||
	(strcmp(prot->sasl_service, "lmtp") &&
	 strcmp(prot->sasl_service, "csync"))) {
	char *old_mechlist = backend_get_cap_params(ret, CAPA_AUTH);
	const char *my_status;

	if ((r = backend_authenticate(ret, userid, cb, &my_status))) {
	    syslog(LOG_ERR, "couldn't authenticate to backend server: %s",
		   sasl_errstring(r, NULL, NULL));
	    free(old_mechlist);
	    goto error;
	}
	else {
	    const void *ssf;

	    sasl_getprop(ret->saslconn, SASL_SSF, &ssf);
	    if (*((sasl_ssf_t *) ssf)) {
		/* if we have a SASL security layer, compare SASL mech lists
		   before/after AUTH to check for a MITM attack */
		char *new_mechlist;
		int auto_capa = (prot->sasl_cmd.auto_capa == AUTO_CAPA_AUTH_SSF);

		if (!strcmp(prot->service, "sieve")) {
		    /* XXX  Hack to handle ManageSieve servers.
		     * No way to tell from protocol if server will
		     * automatically send capabilities, so we treat it
		     * as optional.
		     */
		    char ch;

		    /* wait and probe for possible auto-capability response */
		    usleep(250000);
		    prot_NONBLOCK(ret->in);
		    if ((ch = prot_getc(ret->in)) != EOF) {
			prot_ungetc(ch, ret->in);
		    } else {
			auto_capa = AUTO_CAPA_AUTH_NO;
		    }
		    prot_BLOCK(ret->in);
		}

		ask_capability(ret, /*dobanner*/0, auto_capa);
		new_mechlist = backend_get_cap_params(ret, CAPA_AUTH);
		if (new_mechlist &&
		    old_mechlist &&
		    strcmp(new_mechlist, old_mechlist)) {
		    syslog(LOG_ERR, "possible MITM attack:"
			   "list of available SASL mechanisms changed");
		    free(new_mechlist);
		    free(old_mechlist);
		    goto error;
		}
		free(new_mechlist);
	    }
	    else if (prot->sasl_cmd.auto_capa == AUTO_CAPA_AUTH_OK) {
		/* try to get the capabilities from the AUTH success response */
		forget_capabilities(ret);
		parse_capability(ret, my_status);
		post_parse_capability(ret);
	    }

	    if (!(strcmp(prot->service, "imap") &&
		 (strcmp(prot->service, "pop3")))) {
		parse_sessionid(my_status, rsessionid);
		syslog(LOG_NOTICE, "proxy %s sessionid=<%s> remote=<%s>", userid, session_id(), rsessionid);
	    }
	}

	if (auth_status) *auth_status = my_status;
	free(old_mechlist);
    }

    /* start compression if requested and both client/server support it */
    if (config_getswitch(IMAPOPT_PROXY_COMPRESS) && ret &&
	CAPA(ret, CAPA_COMPRESS) &&
	prot->compress_cmd.cmd &&
	do_compress(ret, &prot->compress_cmd)) {

	syslog(LOG_ERR, "couldn't enable compression on backend server");
	goto error;
    }

    return ret;

error:
    forget_capabilities(ret);
    if (ret->in) {
	prot_free(ret->in);
	ret->in = NULL;
    }
    if (ret->out) {
	prot_free(ret->out);
	ret->out = NULL;
    }
    if (sock >= 0)
	close(sock);
    if (ret->saslconn) {
	sasl_dispose(&ret->saslconn);
	ret->saslconn = NULL;
    }
    if (!ret_backend)
	free(ret);
    return NULL;
}
示例#8
0
/*
 * file in the message structure 'm' from 'pin', assuming a dot-stuffed
 * stream a la lmtp.
 *
 * returns 0 on success, imap error code on failure
 */
static int savemsg(struct clientdata *cd,
		   const struct lmtp_func *func,
		   message_data_t *m)
{
    FILE *f;
    struct stat sbuf;
    const char **body;
    int r;
    int nrcpts = m->rcpt_num;
    time_t now = time(NULL);
    static unsigned msgid_count = 0;
    char datestr[RFC822_DATETIME_MAX+1], tls_info[250] = "";
    const char *skipheaders[] = {
	"Return-Path",  /* need to remove (we add our own) */
	NULL
    };
    char *addbody, *fold[5], *p;
    int addlen, nfold, i;

    /* Copy to spool file */
    f = func->spoolfile(m);
    if (!f) {
	prot_printf(cd->pout, 
		    "451 4.3.%c cannot create temporary file: %s\r\n",
		    (
#ifdef EDQUOT
			errno == EDQUOT ||
#endif
			errno == ENOSPC) ? '1' : '2',
		    error_message(errno));
	return IMAP_IOERROR;
    }

    prot_printf(cd->pout, "354 go ahead\r\n");

    if (m->return_path && func->addretpath) { /* add the return path */
	char *rpath = m->return_path;
	const char *hostname = 0;

	clean_retpath(rpath);
	/* Append our hostname if there's no domain in address */
	hostname = NULL;
	if (!strchr(rpath, '@') && strlen(rpath) > 0) {
	    hostname = config_servername;
	}

	addlen = 2 + strlen(rpath) + (hostname ? 1 + strlen(hostname) : 0);
	addbody = xmalloc(addlen + 1);
	sprintf(addbody, "<%s%s%s>",
		rpath, hostname ? "@" : "", hostname ? hostname : "");
	fprintf(f, "Return-Path: %s\r\n", addbody);
	spool_cache_header(xstrdup("Return-Path"), addbody, m->hdrcache);
    }

    /* add a received header */
    time_to_rfc822(now, datestr, sizeof(datestr));
    addlen = 8 + strlen(cd->lhlo_param) + strlen(cd->clienthost);
    if (m->authuser) addlen += 28 + strlen(m->authuser) + 5; /* +5 for ssf */
    addlen += 25 + strlen(config_servername) + strlen(cyrus_version());
#ifdef HAVE_SSL
    if (cd->tls_conn) {
	addlen += 3 + tls_get_info(cd->tls_conn, tls_info, sizeof(tls_info));
    }
#endif
    addlen += 2 + strlen(datestr);
    p = addbody = xmalloc(addlen + 1);

    nfold = 0;
    p += sprintf(p, "from %s (%s)", cd->lhlo_param, cd->clienthost);
    fold[nfold++] = p;
    if (m->authuser) {
	const void *ssfp;
	sasl_ssf_t ssf;
	sasl_getprop(cd->conn, SASL_SSF, &ssfp);
	ssf = *((sasl_ssf_t *) ssfp);
	p += sprintf(p, " (authenticated user=%s bits=%d)", m->authuser, ssf);
	fold[nfold++] = p;
    }

    /* We are always atleast "with LMTPA" -- no unauth delivery */
    p += sprintf(p, " by %s", config_servername);
    if (config_serverinfo == IMAP_ENUM_SERVERINFO_ON) {
	p += sprintf(p, " (Cyrus %s)", cyrus_version());
    }
    p += sprintf(p, " with LMTP%s%s",
		 cd->starttls_done ? "S" : "",
		 cd->authenticated != NOAUTH ? "A" : "");

    if (*tls_info) {
	fold[nfold++] = p;
	p += sprintf(p, " (%s)", tls_info);
    }

    strcat(p++, ";");
    fold[nfold++] = p;
    p += sprintf(p, " %s", datestr);
 
    fprintf(f, "Received: ");
    for (i = 0, p = addbody; i < nfold; p = fold[i], i++) {
	fprintf(f, "%.*s\r\n\t", (int) (fold[i] - p), p);
    }
    fprintf(f, "%s\r\n", p);
    spool_cache_header(xstrdup("Received"), addbody, m->hdrcache);

    /* add any requested headers */
    if (func->addheaders) {
	struct addheader *h;
	for (h = func->addheaders; h && h->name; h++) {
	    fprintf(f, "%s: %s\r\n", h->name, h->body);
	    spool_cache_header(xstrdup(h->name), xstrdup(h->body), m->hdrcache);
	}
    }

    /* fill the cache */
    r = spool_fill_hdrcache(cd->pin, f, m->hdrcache, skipheaders);

    /* now, using our header cache, fill in the data that we want */

    /* first check resent-message-id */
    if ((body = msg_getheader(m, "resent-message-id")) && body[0][0]) {
	m->id = xstrdup(body[0]);
    } else if ((body = msg_getheader(m, "message-id")) && body[0][0]) {
	m->id = xstrdup(body[0]);
    } else if (body) {
	r = IMAP_MESSAGE_BADHEADER;  /* empty message-id */
    } else {
	/* no message-id, create one */
	pid_t p = getpid();

	m->id = xmalloc(40 + strlen(config_servername));
	sprintf(m->id, "<cmu-lmtpd-%d-%d-%u@%s>", p, (int) now,
		msgid_count++, config_servername);
	fprintf(f, "Message-ID: %s\r\n", m->id);
	spool_cache_header(xstrdup("Message-ID"), xstrdup(m->id), m->hdrcache);
    }

    /* get date */
    if (!(body = spool_getheader(m->hdrcache, "date"))) {
	/* no date, create one */
	addbody = xstrdup(datestr);
	m->date = xstrdup(datestr);
	fprintf(f, "Date: %s\r\n", addbody);
	spool_cache_header(xstrdup("Date"), addbody, m->hdrcache);
    }
    else {
	m->date = xstrdup(body[0]);
    }

    if (!m->return_path &&
	(body = msg_getheader(m, "return-path"))) {
	/* let's grab return_path */
	m->return_path = xstrdup(body[0]);
	clean822space(m->return_path);
	clean_retpath(m->return_path);
    }

    r |= spool_copy_msg(cd->pin, f);
    if (r) {
	fclose(f);
	if (func->removespool) {
	    /* remove the spool'd message */
	    func->removespool(m);
	}
	while (nrcpts--) {
	    send_lmtp_error(cd->pout, r);
	}
	return r;
    }

    fflush(f);
    if (ferror(f)) {
	while (nrcpts--) {
	    prot_printf(cd->pout,
	       "451 4.3.%c cannot copy message to temporary file: %s\r\n",
		   (
#ifdef EDQUOT
		    errno == EDQUOT ||
#endif
		    errno == ENOSPC) ? '1' : '2',
		   error_message(errno));
	}
	fclose(f);
	if (func->removespool) func->removespool(m);
	return IMAP_IOERROR;
    }

    if (fstat(fileno(f), &sbuf) == -1) {
	while (nrcpts--) {
	    prot_printf(cd->pout,
			"451 4.3.2 cannot stat message temporary file: %s\r\n",
			error_message(errno));
	}
	fclose(f);
	if (func->removespool) func->removespool(m);
	return IMAP_IOERROR;
    }
    m->size = sbuf.st_size;
    m->f = f;
    m->data = prot_new(fileno(f), 0);

    return 0;
}
示例#9
0
EXPORTED struct backend *backend_connect(struct backend *ret_backend, const char *server,
				struct protocol_t *prot, const char *userid,
				sasl_callback_t *cb, const char **auth_status,
				int logfd)

{
    /* need to (re)establish connection to server or create one */
    int sock = -1;
    int r;
    int err = -1;
    int do_tls = 0;
    int noauth = 0;
    struct addrinfo hints, *res0 = NULL, *res;
    struct sockaddr_un sunsock;
    struct backend *ret;

    if (!ret_backend) {
	ret = xzmalloc(sizeof(struct backend));
	strlcpy(ret->hostname, server, sizeof(ret->hostname));
	ret->timeout = NULL;
    }
    else
	ret = ret_backend;

    if (server[0] == '/') { /* unix socket */
	res0 = &hints;
	memset(res0, 0, sizeof(struct addrinfo));
	res0->ai_family = PF_UNIX;
	res0->ai_socktype = SOCK_STREAM;

	res0->ai_addr = (struct sockaddr *) &sunsock;
	res0->ai_addrlen = sizeof(sunsock.sun_family) + strlen(server) + 1;
#ifdef SIN6_LEN
	res0->ai_addrlen += sizeof(sunsock.sun_len);
	sunsock.sun_len = res0->ai_addrlen;
#endif
	sunsock.sun_family = AF_UNIX;
	strlcpy(sunsock.sun_path, server, sizeof(sunsock.sun_path));

	if (!strcmp(prot->sasl_service, "lmtp") ||
	    !strcmp(prot->sasl_service, "csync")) {
	    noauth = 1;
	}
    }
    else { /* inet socket */
	char host[1024], *p;
	const char *service = prot->service;

	/* Parse server string for possible port and options */
	strlcpy(host, server, sizeof(host));
	if ((p = strchr(host, ':'))) {
	    *p++ = '\0';
	    service = p;

	    if ((p = strchr(service, '/'))) {
		tok_t tok;
		char *opt;

		*p++ = '\0';
		tok_initm(&tok, p, "/", 0);
		while ((opt = tok_next(&tok))) {
		    if (!strcmp(opt, "tls")) do_tls = 1;
		    else if (!strcmp(opt, "noauth")) noauth = 1;
		}
		tok_fini(&tok);
	    }
	}

	memset(&hints, 0, sizeof(hints));
	hints.ai_family = PF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	err = getaddrinfo(host, service, &hints, &res0);
	if (err) {
	    syslog(LOG_ERR, "getaddrinfo(%s) failed: %s",
		   server, gai_strerror(err));
	    goto error;
	}
    }

    for (res = res0; res; res = res->ai_next) {
	sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
	if (sock < 0)
	    continue;

	/* Do a non-blocking connect() */
	nonblock(sock, 1);
	if (!connect(sock, res->ai_addr, res->ai_addrlen)) {
	    /* connect() succeeded immediately */
	    break;
	}
	else if (errno == EINPROGRESS) {
	    /* connect() in progress */
	    int n;
	    fd_set wfds, rfds;
	    time_t now = time(NULL);
	    time_t timeout = now + config_getint(IMAPOPT_CLIENT_TIMEOUT);
	    struct timeval waitfor;

	    /* select() socket for writing until we succeed, fail, or timeout */
	    do {
		FD_ZERO(&wfds);
		FD_SET(sock, &wfds);
		rfds = wfds;
		waitfor.tv_sec = timeout - now;
		waitfor.tv_usec = 0;

		n = select(sock + 1, &rfds, &wfds, NULL, &waitfor);
		now = time(NULL);

		/* Retry select() if interrupted */
	    } while (n < 0 && errno == EINTR && now < timeout);

	    if (!n) {
		/* select() timed out */
		errno = ETIMEDOUT;
	    }
	    else if (FD_ISSET(sock, &rfds) || FD_ISSET(sock, &wfds)) {
		/* Socket is ready for I/O - get SO_ERROR to determine status */
		socklen_t errlen = sizeof(err);

		if (!getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &errlen) &&
		    !(errno = err)) {
		    /* connect() succeeded */
		    break;
		}
	    }
	}

	close(sock);
	sock = -1;
    }

    if (sock < 0) {
	if (res0 != &hints) freeaddrinfo(res0);
	syslog(LOG_ERR, "connect(%s) failed: %m", server);
	goto error;
    }

    /* Reset socket to blocking */
    nonblock(sock, 0);

    memcpy(&ret->addr, res->ai_addr, res->ai_addrlen);
    if (res0 != &hints)
	freeaddrinfo(res0);

    ret->in = prot_new(sock, 0);
    ret->out = prot_new(sock, 1);
    ret->sock = sock;
    prot_settimeout(ret->in, config_getint(IMAPOPT_CLIENT_TIMEOUT));
    prot_setflushonread(ret->in, ret->out);
    ret->prot = prot;

    /* use literal+ to send literals */
    prot_setisclient(ret->in, 1);
    prot_setisclient(ret->out, 1);

    /* Start TLS if required */
    if (do_tls) r = backend_starttls(ret, NULL, NULL, NULL);

    /* Login to the server */
    if (prot->type == TYPE_SPEC)
	r = prot->u.spec.login(ret, userid, cb, auth_status, noauth);
    else
	r = backend_login(ret, userid, cb, auth_status, noauth);

    if (r) goto error;

    if (logfd >= 0) {
	prot_setlog(ret->in, logfd);
	prot_setlog(ret->out, logfd);
    }
    else prot_settimeout(ret->in, 0);

    return ret;

error:
    forget_capabilities(ret);
    if (ret->in) {
	prot_free(ret->in);
	ret->in = NULL;
    }
    if (ret->out) {
	prot_free(ret->out);
	ret->out = NULL;
    }
    if (sock >= 0)
	close(sock);
    if (ret->saslconn) {
	sasl_dispose(&ret->saslconn);
	ret->saslconn = NULL;
    }
    if (!ret_backend)
	free(ret);
    return NULL;
}
示例#10
0
/*
 * Begin reading a sync log file.  If the reader is reading from a
 * channel, rename the current log file so it will not be appended to by
 * the write side code, and open the file. Otherwise, just open the file
 * (note this is still necessary even when the reader is reading from a
 * file descriptor).
 *
 * When sync_log_reader_begin() returns success, you should loop calling
 * sync_log_reader_getitem() and handling the items, until it returns
 * EOF, and then call sync_log_reader_end().
 *
 * Returns zero on success, IMAP_AGAIN if reading from a channel and
 * there is no current log file, or an IMAP error code on failure.
 */
EXPORTED int sync_log_reader_begin(sync_log_reader_t *slr)
{
    struct stat sbuf;
    int r;

    if (slr->input) {
	r = sync_log_reader_end(slr);
	if (r) return r;
    }

    if (stat(slr->work_file, &sbuf) == 0) {
	/* Existing work log file - process this first */
	syslog(LOG_NOTICE,
	       "Reprocessing sync log file %s", slr->work_file);
    }
    else if (!slr->log_file) {
	syslog(LOG_ERR, "Failed to stat %s: %m",
	       slr->log_file);
	return IMAP_IOERROR;
    }
    else {
	/* Check for sync_log file */
	if (stat(slr->log_file, &sbuf) < 0) {
	    if (errno == ENOENT)
		return IMAP_AGAIN;  /* no problem, try again later */
	    syslog(LOG_ERR, "Failed to stat %s: %m",
		   slr->log_file);
	    return IMAP_IOERROR;
	}

	/* Move sync_log to our work file */
	if (rename(slr->log_file, slr->work_file) < 0) {
	    syslog(LOG_ERR, "Rename %s -> %s failed: %m",
		   slr->log_file, slr->work_file);
	    return IMAP_IOERROR;
	}
    }

    if (slr->fd < 0) {
	int fd = open(slr->work_file, O_RDWR, 0);
	if (fd < 0) {
	    syslog(LOG_ERR, "Failed to open %s: %m", slr->work_file);
	    return IMAP_IOERROR;
	}

	if (lock_blocking(fd, slr->work_file) < 0) {
	    syslog(LOG_ERR, "Failed to lock %s: %m", slr->work_file);
	    close(fd);
	    return IMAP_IOERROR;
	}

	slr->fd = fd;
	slr->fd_is_ours = 1;

	/* we can unlock immediately, since we have serialised
	 * any process which held the lock over the rename.  All
	 * future attempts to lock this inode will stat and notice
	 * the rename, so they won't write any more */
	lock_unlock(slr->fd, slr->work_file);
    }

    slr->input = prot_new(slr->fd, /*write*/0);

    return 0;
}