예제 #1
0
파일: tls_verify.c 프로젝트: 1514louluo/acl
char   *tls_fingerprint(X509 *peercert, const char *dgst)
{
    const char *myname = "tls_fingerprint";
    const EVP_MD *md_alg;
    unsigned char md_buf[EVP_MAX_MD_SIZE];
    unsigned int md_len;
    int     i;
    char   *result = 0;

    /* Previously available in "init" routine. */
    if ((md_alg = EVP_get_digestbyname(dgst)) == 0)
	acl_msg_panic("%s: digest algorithm \"%s\" not found", myname, dgst);

    /* Fails when serialization to ASN.1 runs out of memory */
    if (X509_digest(peercert, md_alg, md_buf, &md_len) == 0)
	acl_msg_fatal("%s: error computing certificate %s digest (out of memory?)",
		  myname, dgst);

    /* Check for OpenSSL contract violation */
    if (md_len > EVP_MAX_MD_SIZE || (int) md_len >= INT_MAX / 3)
	acl_msg_panic("%s: unexpectedly large %s digest size: %u",
		  myname, dgst, md_len);

    result = acl_mymalloc(md_len * 3);
    for (i = 0; i < (int) md_len; i++) {
	result[i * 3] = hexcodes[(md_buf[i] & 0xf0) >> 4U];
	result[(i * 3) + 1] = hexcodes[(md_buf[i] & 0x0f)];
	result[(i * 3) + 2] = (i + 1 != (int) md_len) ? ':' : '\0';
    }
    return (result);
}
예제 #2
0
파일: tls_client.c 프로젝트: 1514louluo/acl
static int new_client_session_cb(SSL *ssl, SSL_SESSION *session)
{
    const char *myname = "new_client_session_cb";
    TLS_SESS_STATE *TLScontext;
    ACL_VSTRING *session_data;

    /*
     * The cache name (if caching is enabled in tlsmgr(8)) and the cache ID
     * string for this session are stored in the TLScontext. It cannot be
     * null at this point.
     */
    if ((TLScontext = SSL_get_ex_data(ssl, TLScontext_index)) == 0)
	acl_msg_panic("%s: null TLScontext in new session callback", myname);

    /*
     * We only get here if the cache_type is not empty. This callback is not
     * set unless caching is enabled and the cache_type is stored in the
     * server SSL context.
     */
    if (TLScontext->cache_type == 0)
	acl_msg_panic("%s: null session cache type in new session callback", myname);

    if (TLScontext->log_level >= 2)
	acl_msg_info("save session %s to %s cache", TLScontext->serverid, TLScontext->cache_type);

#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.
     */
    session->verify_result = SSL_get_verify_result(TLScontext->con);
#endif

    /*
     * Passivate and save the session object. Errors are non-fatal, since
     * caching is only an optimization.
     */
    if ((session_data = tls_session_passivate(session)) != 0) {
	tls_mgr_update(TLScontext->cache_type, TLScontext->serverid,
		STR(session_data), (int) LEN(session_data));
	acl_vstring_free(session_data);
    }

    /*
     * Clean up.
     */
    SSL_SESSION_free(session);			/* 200502 */

    return (1);
}
예제 #3
0
ACL_WATCHDOG *acl_watchdog_create(unsigned timeout,
	ACL_WATCHDOG_FN action, char *context)
{
	const char* myname = "acl_watchdog_create";
	struct sigaction sig_action;
	ACL_WATCHDOG *wp;

	wp = (ACL_WATCHDOG *) acl_mymalloc(sizeof(*wp));
	if ((wp->timeout = timeout / ACL_WATCHDOG_STEPS) == 0)
		acl_msg_panic("%s: timeout %d too small", myname, timeout);
	wp->action = action;
	wp->context = context;
	wp->saved_watchdog = acl_watchdog_curr;
	wp->saved_time = alarm(0);
	sigemptyset(&sig_action.sa_mask);
#ifdef SA_RESTART
	sig_action.sa_flags = SA_RESTART;
#else
	sig_action.sa_flags = 0;
#endif
	sig_action.sa_handler = acl_watchdog_event;
	if (sigaction(SIGALRM, &sig_action, &wp->saved_action) < 0)
		acl_msg_fatal("%s: sigaction(SIGALRM): %s",
			myname, acl_last_serror());
	if (acl_msg_verbose > 1)
		acl_msg_info("%s: %p %d", myname, (void *) wp, timeout);
	return (acl_watchdog_curr = wp);
}
예제 #4
0
void    acl_master_status_init(ACL_MASTER_SERV *serv)
{
	const char *myname = "acl_master_status_init";

	/*
	 * Sanity checks.
	 */
	if (serv->status_fd[0] >= 0 || serv->status_fd[1] >= 0)
		acl_msg_panic("%s: status events already enabled", myname);
	if (acl_msg_verbose)
		acl_msg_info("%s: %s", myname, serv->name);

	/*
	 * Make the read end of this service's status pipe non-blocking so that
	 * we can detect partial writes on the child side. We use a duplex pipe
	 * so that the child side becomes readable when the master goes away.
	 */
	if (acl_duplex_pipe(serv->status_fd) < 0)
		acl_msg_fatal("pipe: %s", strerror(errno));
	acl_non_blocking(serv->status_fd[0], ACL_BLOCKING);
	acl_close_on_exec(serv->status_fd[0], ACL_CLOSE_ON_EXEC);
	acl_close_on_exec(serv->status_fd[1], ACL_CLOSE_ON_EXEC);
	serv->status_read_stream = acl_vstream_fdopen(serv->status_fd[0],
		O_RDWR, acl_var_master_buf_size,
		acl_var_master_rw_timeout, ACL_VSTREAM_TYPE_SOCK);

	if (acl_msg_verbose)
		acl_msg_info("%s(%d)->%s: call acl_event_enable_read, "
			"status_fd = %d", __FILE__, __LINE__,
			myname, serv->status_fd[0]);

	acl_event_enable_read(acl_var_master_global_event,
		serv->status_read_stream, 0, master_status_event,
		(void *) serv);
}
예제 #5
0
파일: tls_dh.c 프로젝트: 10jschen/acl
void    tls_set_dh_from_file(const char *path, int bits)
{
    const char *myname = "tls_set_dh_from_file";
    FILE   *paramfile;
    DH    **dhPtr = 0;

    switch (bits) {
    case 512:
	dhPtr = &dh_512;
	break;
    case 1024:
	dhPtr = &dh_1024;
	break;
    default:
	acl_msg_panic("Invalid DH parameters size %d, file %s", bits, path);
    }

    if (*dhPtr != 0)
	return;

    if ((paramfile = fopen(path, "r")) != 0) {
	if ((*dhPtr = PEM_read_DHparams(paramfile, 0, 0, 0)) == 0) {
	    acl_msg_warn("%s: cannot load %d-bit DH parameters from file %s"
		    " -- using compiled-in defaults", myname, bits, path);
	    tls_print_errors();
	}
	(void) fclose(paramfile);		/* 200411 */
    } else {
	acl_msg_warn("%s: cannot load %d-bit DH parameters from file %s: %s"
		" -- using compiled-in defaults", myname, bits, path, acl_last_serror());
    }
}
예제 #6
0
void acl_mempool_ctl(int name, ...)
{
	const char *myname = "acl_mempool_ctl";
	va_list ap;
	int   n;

	if (__var_allocator == NULL)
		acl_msg_fatal("%s(%d): call acl_mempool_create first", myname, __LINE__);

	va_start(ap, name);

	for (; name != ACL_MEMPOOL_CTL_END; name = va_arg(ap, int)) {
		switch (name) {
		case ACL_MEMPOOL_CTL_MUTEX:
			n = va_arg(ap, int);
			if (n)
				mempool_init_with_mutex();
			else
				mempool_init_no_mutex();
			break;
		case ACL_MEMPOOL_CTL_DISABLE:
			n = va_arg(ap, int);
			if (n)
				mempool_close();
			break;
		default:
			acl_msg_panic("%s: bad name %d", myname, name);
		}
	}
	va_end(ap);
}
예제 #7
0
void    acl_master_status_cleanup(ACL_MASTER_SERV *serv)
{
	const char *myname = "acl_master_status_cleanup";

	/*
	 * Sanity checks.
	 */
	if (serv->status_fd[0] < 0 || serv->status_fd[1] < 0)
		acl_msg_panic("%s: status events not enabled", myname);
	if (acl_msg_verbose)
		acl_msg_info("%s: %s", myname, serv->name);

	/*
	 * Dispose of this service's status pipe after disabling read events.
	 */

	acl_event_disable_readwrite(acl_var_master_global_event,
		serv->status_read_stream);

	if (close(serv->status_fd[0]) != 0)
		acl_msg_warn("%s: close status descriptor (read side): %s",
			myname, strerror(errno));
	if (close(serv->status_fd[1]) != 0)
		acl_msg_warn("%s: close status descriptor (write side): %s",
			myname, strerror(errno));
	serv->status_fd[0] = serv->status_fd[1] = -1;
	if (serv->status_read_stream)
		acl_vstream_free(serv->status_read_stream);
	serv->status_read_stream = NULL;
}
예제 #8
0
ssize_t tls_prng_dev_read(TLS_PRNG_SRC *dev, size_t len)
{
    const char *myname = "tls_prng_dev_read";
    unsigned char buffer[UCHAR_MAX];
    ssize_t count;
    size_t  rand_bytes;

    if (len <= 0)
	acl_msg_panic("%s: bad read length: %ld", myname, (long) len);

    if (len > sizeof(buffer))
	rand_bytes = sizeof(buffer);
    else
	rand_bytes = len;
    errno = 0;
#ifdef ACL_UNIX
    count = acl_timed_read(dev->fd.file, buffer, (int) rand_bytes, dev->timeout,
		NULL);
#elif defined(WIN32)
	count = acl_file_read(dev->fd.file, buffer, (int) rand_bytes,
		dev->timeout, NULL);
#endif
    if (count > 0) {
	if (acl_msg_verbose)
	    acl_msg_info("%s: read %ld bytes from entropy device %s",
		     myname, (long) count, dev->name);
	RAND_seed(buffer, count);
    } else {
	if (acl_msg_verbose)
	    acl_msg_info("%s: cannot read %ld bytes from entropy device %s: %s",
		     myname, (long) rand_bytes, dev->name, acl_last_serror());
    }
    return (count);
}
예제 #9
0
static void event_enable_write(ACL_EVENT *eventp, ACL_VSTREAM *stream,
	int timeout, ACL_EVENT_NOTIFY_RDWR callback, void *context)
{
	const char *myname = "event_enable_write";
	EVENT_POLL_THR *event_thr = (EVENT_POLL_THR *) eventp;
	ACL_EVENT_FDTABLE *fdp;
	ACL_SOCKET sockfd;

	sockfd = ACL_VSTREAM_SOCK(stream);
	fdp = (ACL_EVENT_FDTABLE*) stream->fdp;
	if (fdp == NULL) {
		fdp = event_fdtable_alloc();
		fdp->listener = 0;
		fdp->stream = stream;
		stream->fdp = (void *) fdp;
	} else if (fdp->flag & EVENT_FDTABLE_FLAG_READ)
		acl_msg_panic("%s(%d)->%s: fd %d: multiple I/O request",
			__FILE__, __LINE__, myname, sockfd);
	else {
		fdp->listener = 0;
		fdp->stream = stream;
	}

	if (fdp->w_callback != callback || fdp->w_context != context) {
		fdp->w_callback = callback;
		fdp->w_context = context;
	}

	if (timeout > 0) {
		fdp->w_timeout = timeout * 1000000;
		fdp->w_ttl = eventp->present + fdp->w_timeout;
	} else {
		fdp->w_ttl = 0;
		fdp->w_timeout = 0;
	}

	if ((fdp->flag & EVENT_FDTABLE_FLAG_WRITE) != 0)
		return;

	stream->nrefer++;
	fdp->flag = EVENT_FDTABLE_FLAG_WRITE | EVENT_FDTABLE_FLAG_EXPT;

	THREAD_LOCK(&event_thr->event.tb_mutex);

	fdp->fdidx = eventp->fdcnt;
	eventp->fdtabs[eventp->fdcnt++] = fdp;

	event_thr->fds[fdp->fdidx].fd = sockfd;
	event_thr->fds[fdp->fdidx].events = POLLOUT | POLLHUP | POLLERR;
	if (eventp->maxfd == ACL_SOCKET_INVALID || eventp->maxfd < sockfd)
		eventp->maxfd = sockfd;

	acl_fdmap_add(event_thr->fdmap, sockfd, fdp);

	THREAD_UNLOCK(&event_thr->event.tb_mutex);

	if (event_thr->event.blocked && event_thr->event.evdog
	    && event_dog_client(event_thr->event.evdog) != stream)
		event_dog_notify(event_thr->event.evdog);
}
예제 #10
0
int acl_timed_connect(ACL_SOCKET sock, const struct sockaddr * sa,
	socklen_t len, int timeout)
{
	int   err;

	/*
	 * Sanity check. Just like with timed_wait(), the timeout must be a
	 * positive number.
	 */
	if (timeout < 0)
		acl_msg_panic("timed_connect: bad timeout: %d", timeout);

	/*
	 * Start the connection, and handle all possible results.
	 */
	if (acl_sane_connect(sock, sa, len) == 0)
		return (0);

	errno = acl_last_error();

#ifdef	ACL_UNIX
	if (errno != ACL_EINPROGRESS)
		return (-1);
#elif defined(ACL_WINDOWS)
	if (errno != ACL_EINPROGRESS && errno != ACL_EWOULDBLOCK)
		return (-1);
#endif

	/*
	 * A connection is in progress. Wait for a limited amount of time for
	 * something to happen. If nothing happens, report an error.
	 */
	if (acl_write_wait(sock, timeout) < 0)
		return (-1);

	/*
	 * Something happened. Some Solaris 2 versions have getsockopt() itself
	 * return the error, instead of returning it via the parameter list.
	 */
	len = sizeof(err);
	if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *) &err, &len) < 0) {
#ifdef  SUNOS5
	/*
	 * Solaris 2.4's socket emulation doesn't allow you
	 * to determine the error from a failed non-blocking
	 * connect and just returns EPIPE.  Create a fake
	 * error message for connect.   -- [email protected]
	 */
		if (errno == EPIPE)
			acl_set_error(ACL_ENOTCONN);
#endif
		return (-1);
	}

	if (err != 0) {
		acl_set_error(err);
		return (-1);
	} else
		return (0);
}
예제 #11
0
int acl_master_flow_put(int len)
{
	char  myname[] = "acl_master_flow_put";
	char  buf[BUFFER_SIZE];
	int   count;
	int   n = 0;

	/*
	 * Sanity check.
	 */
	if (len <= 0)
		acl_msg_panic("%s: bad length %d", myname, len);

	/*
	 * Write or discard N bytes.
	 */
	memset(buf, 0, len > BUFFER_SIZE ? BUFFER_SIZE : len);

	for (count = len; count > 0; count -= n) {
		n = write(ACL_MASTER_FLOW_WRITE,
				buf,
				count > BUFFER_SIZE ?  BUFFER_SIZE : count);
		if (n < 0)
			return (-1);
	}

	if (acl_msg_verbose)
		acl_msg_info("%s: %d %d", myname, len, len - count);
	return (len - count);
}
예제 #12
0
파일: tls_verify.c 프로젝트: 1514louluo/acl
const char *tls_dns_name(const GENERAL_NAME *gn, const TLS_SESS_STATE *TLScontext)
{
    const char *myname = "tls_dns_name";
    char   *cp;
    const char *dnsname;
    int     len;

    /*
     * Peername checks are security sensitive, carefully scrutinize the
     * input!
     */
    if (gn->type != GEN_DNS)
	acl_msg_panic("%s: Non DNS input argument", myname);

    /*
     * We expect the OpenSSL library to construct GEN_DNS extesion objects as
     * ASN1_IA5STRING values. Check we got the right union member.
     */
    if (ASN1_STRING_type(gn->d.ia5) != V_ASN1_IA5STRING) {
	acl_msg_warn("%s: %s: invalid ASN1 value type in subjectAltName",
		 myname, TLScontext->namaddr);
	return (0);
    }

    /*
     * Safe to treat as an ASCII string possibly holding a DNS name
     */
    dnsname = (char *) ASN1_STRING_data(gn->d.ia5);
    len = ASN1_STRING_length(gn->d.ia5);
    TRIM0(dnsname, len);

    /*
     * Per Dr. Steven Henson of the OpenSSL development team, ASN1_IA5STRING
     * values can have internal ASCII NUL values in this context because
     * their length is taken from the decoded ASN1 buffer, a trailing NUL is
     * always appended to make sure that the string is terminated, but the
     * ASN.1 length may differ from strlen().
     */
    if (len != (int) strlen(dnsname)) {
	acl_msg_warn("%s: %s: internal NUL in subjectAltName",
		 myname, TLScontext->namaddr);
	return 0;
    }

    /*
     * XXX: Should we be more strict and call valid_hostname()? So long as
     * the name is safe to handle, if it is not a valid hostname, it will not
     * compare equal to the expected peername, so being more strict than
     * "printable" is likely excessive...
     */
    if (*dnsname && !allprint(dnsname)) {
	cp = acl_mystrdup(dnsname);
	acl_msg_warn("%s: %s: non-printable characters in subjectAltName: %.100s",
		 myname, TLScontext->namaddr, printable(cp, '?'));
	acl_myfree(cp);
	return 0;
    }
    return (dnsname);
}
예제 #13
0
파일: acl_myflock.c 프로젝트: 10jschen/acl
/* use LockFileEx/UnlockFileEx */
int acl_myflock(ACL_FILE_HANDLE fd, int lock_style acl_unused, int operation)
{
	const char *myname = "acl_myflock";
	DWORD size = 0xFFFFFFFF;
	char  ebuf[256];
	unsigned char lock_op;
	OVERLAPPED ovlp;
	DWORD flags;

	if ((operation & (ACL_FLOCK_OP_BITS)) != operation)
		acl_msg_panic("myflock: improper operation type: 0x%x", operation);

	memset(&ovlp, 0, sizeof(ovlp));

	ovlp.Offset = 0;
	lock_op = operation & ~ACL_FLOCK_OP_NOWAIT;
	if (lock_op == ACL_FLOCK_OP_NONE) {
		if(UnlockFileEx(fd, 0, 1, 0, &ovlp))
			return (0);
		acl_msg_error("%s(%d): unlock error(%s)",
			myname, __LINE__, acl_last_strerror(ebuf,sizeof(ebuf)));
		return (-1);
	} else if (lock_op == ACL_FLOCK_OP_SHARED) {
		while (1) {
			flags = 0;
			if ((operation & ACL_FLOCK_OP_NOWAIT))
				flags |= LOCKFILE_FAIL_IMMEDIATELY;

			if(LockFileEx(fd, flags, 0, 1, 0, &ovlp))
				return (0);
			if ((operation & ACL_FLOCK_OP_NOWAIT)) {
				acl_msg_error("%s(%d): lock error(%s)", myname, __LINE__,
					acl_last_strerror(ebuf,sizeof(ebuf)));
				return (-1);
			}
			sleep(1);
		}
	} else if (lock_op == ACL_FLOCK_OP_EXCLUSIVE) {
		while (1) {
			flags = LOCKFILE_EXCLUSIVE_LOCK;
			if ((operation & ACL_FLOCK_OP_NOWAIT))
				flags |= LOCKFILE_FAIL_IMMEDIATELY;

			if(LockFileEx(fd, flags, 0, 1, 0, &ovlp))
				return (0);

			if ((operation & ACL_FLOCK_OP_NOWAIT)) {
				acl_msg_error("%s(%d): lock error(%s)", myname, __LINE__,
					acl_last_strerror(ebuf,sizeof(ebuf)));
				return (-1);
			}
			sleep(1);
		}
	}

	acl_msg_error("%s(%d): invalid lock_op(%d)", myname, __LINE__, lock_op);
	return (-1);
}
예제 #14
0
void    acl_watchdog_stop(ACL_WATCHDOG *wp)
{
	const char* myname = "acl_watchdog_stop";

	if (wp != acl_watchdog_curr)
		acl_msg_panic("%s: wrong watchdog instance", myname);
	alarm(0);
	if (acl_msg_verbose > 1)
		acl_msg_info("%s: %p", myname, (void *) wp);
}
예제 #15
0
void    acl_watchdog_start(ACL_WATCHDOG *wp)
{
	const char* myname = "acl_watchdog_start";

	if (wp != acl_watchdog_curr)
		acl_msg_panic("%s: wrong watchdog instance", myname);
	wp->trip_run = 0;
	alarm(wp->timeout);
	if (acl_msg_verbose > 1)
		acl_msg_info("%s: %p", myname, (void *) wp);
}
예제 #16
0
파일: acl_events.c 프로젝트: 10jschen/acl
acl_int64 acl_event_request_timer(ACL_EVENT *eventp,
	ACL_EVENT_NOTIFY_TIME callback, void *context,
	acl_int64 delay, int keep)
{
	const char *myname = "acl_event_request_timer";

	if (delay < 0)
		acl_msg_panic("%s: invalid delay: %lld", myname, delay);

	return eventp->timer_request(eventp, callback, context, delay, keep);
}
예제 #17
0
파일: tls_stream.c 프로젝트: 10jschen/acl
static ssize_t tls_timed_write(int fd, void *buf, size_t len,
	int timeout, void *context)
{
    const char *myname = "tls_timed_write";
    TLS_SESS_STATE *TLScontext;

    TLScontext = (TLS_SESS_STATE *) context;
    if (!TLScontext)
	acl_msg_panic("%s: no context, buf(%s), len(%d)", myname, (char*) buf, (int) len);

    if (TLScontext->log_level >= 4)
	acl_msg_info("Write %ld chars: %.*s",
		 (long) len, (int) (len > 40 ? 40 : len), (char *) buf);
    return (tls_bio_write(fd, buf, (int) len, timeout, TLScontext));
}
예제 #18
0
파일: tls_stream.c 프로젝트: 10jschen/acl
static ssize_t tls_timed_read(int fd, void *buf, size_t len,
	int timeout, void *context)
{
    const char *myname = "tls_timed_read";
    ssize_t ret;
    TLS_SESS_STATE *TLScontext;

    TLScontext = (TLS_SESS_STATE *) context;
    if (!TLScontext)
	acl_msg_panic("%s: no context", myname);

    ret = tls_bio_read(fd, buf, (int) len, timeout, TLScontext);
    if (ret > 0 && TLScontext->log_level >= 4)
	acl_msg_info("Read %ld chars: %.*s",
		 (long) ret, (int) (ret > 40 ? 40 : ret), (char *) buf);
    return (ret);
}
예제 #19
0
int acl_timed_waitpid(pid_t pid, ACL_WAIT_STATUS_T *statusp, int options,
	int time_limit)
{
	const char *myname = "timed_waitpid";
	struct sigaction action;
	struct sigaction old_action;
	int     time_left;
	int     wpid;
	char    tbuf[256];

	/*
	 * Sanity checks.
	 */
	if (time_limit <= 0)
		acl_msg_panic("%s: bad time limit: %d", myname, time_limit);

	/*
	 * Set up a timer.
	 */
	sigemptyset(&action.sa_mask);
	action.sa_flags = 0;
	action.sa_handler = timed_wait_alarm;
	if (sigaction(SIGALRM, &action, &old_action) < 0)
		acl_msg_fatal("%s: sigaction(SIGALRM): %s", myname,
			acl_last_strerror(tbuf, sizeof(tbuf)));
	timed_wait_expired = 0;
	time_left = alarm(time_limit);

	/*
	 * Wait for only a limited amount of time.
	 */
	if ((wpid = waitpid(pid, statusp, options)) < 0 && timed_wait_expired)
		acl_set_error(ETIMEDOUT);

	/*
	 * Cleanup.
	 */
	alarm(0);
	if (sigaction(SIGALRM, &old_action, (struct sigaction *) 0) < 0)
		acl_msg_fatal("%s: sigaction(SIGALRM): %s", myname,
			acl_last_strerror(tbuf, sizeof(tbuf)));
	if (time_left)
		alarm(time_left);

	return (wpid);
}
예제 #20
0
ACL_VSTRING *tok822_internalize(ACL_VSTRING *vp, TOK822 *tree, int flags)
{
	TOK822 *tp;

	if (flags & TOK822_STR_WIPE)
		ACL_VSTRING_RESET(vp);

	for (tp = tree; tp; tp = tp->next) {
		switch (tp->type) {
		case ',':
			ACL_VSTRING_ADDCH(vp, tp->type);
			if (flags & TOK822_STR_LINE) {
				ACL_VSTRING_ADDCH(vp, '\n');
				continue;
			}
			break;
		case TOK822_ADDR:
			tok822_internalize(vp, tp->head, TOK822_STR_NONE);
			break;
		case TOK822_COMMENT:
		case TOK822_ATOM:
		case TOK822_QSTRING:
			acl_vstring_strcat(vp, acl_vstring_str(tp->vstr));
			break;
		case TOK822_DOMLIT:
			ACL_VSTRING_ADDCH(vp, '[');
			acl_vstring_strcat(vp, acl_vstring_str(tp->vstr));
			ACL_VSTRING_ADDCH(vp, ']');
			break;
		case TOK822_STARTGRP:
			ACL_VSTRING_ADDCH(vp, ':');
			break;
		default:
			if (tp->type >= TOK822_MINTOK)
				acl_msg_panic("tok822_internalize: unknown operator %d", tp->type);
			ACL_VSTRING_ADDCH(vp, tp->type);
		}
		if (tok822_append_space(tp))
			ACL_VSTRING_ADDCH(vp, ' ');
	}
	if (flags & TOK822_STR_TERM)
		ACL_VSTRING_TERMINATE(vp);
	return (vp);
}
예제 #21
0
파일: tls_client.c 프로젝트: 1514louluo/acl
static SSL_SESSION *load_clnt_session(TLS_SESS_STATE *TLScontext)
{
    const char *myname = "load_clnt_session";
    SSL_SESSION *session = 0;
    ACL_VSTRING *session_data = acl_vstring_alloc(2048);

    /*
     * Prepare the query.
     */
    if (TLScontext->log_level >= 2)
	acl_msg_info("looking for session %s in %s cache",
		TLScontext->serverid, TLScontext->cache_type);

    /*
     * We only get here if the cache_type is not empty. This code is not
     * called unless caching is enabled and the cache_type is stored in the
     * server SSL context.
     */
    if (TLScontext->cache_type == 0)
	acl_msg_panic("%s: null client session cache type in session lookup", myname);

    /*
     * Look up and activate the SSL_SESSION object. Errors are non-fatal,
     * since caching is only an optimization.
     */
    if (tls_mgr_lookup(TLScontext->cache_type, TLScontext->serverid,
		session_data) == TLS_MGR_STAT_OK) {
	session = tls_session_activate(STR(session_data), (int) LEN(session_data));
	if (session) {
	    if (TLScontext->log_level >= 2)
		acl_msg_info("reloaded session %s from %s cache",
			TLScontext->serverid, TLScontext->cache_type);
	}
    }

    /*
     * Clean up.
     */
    acl_vstring_free(session_data);

    return (session);
}
예제 #22
0
파일: acl_myflock.c 프로젝트: 10jschen/acl
/* use LockFile/UnlockFile */
int acl_myflock(ACL_FILE_HANDLE fd, int lock_style acl_unused, int operation)
{
	const char *myname = "acl_myflock";
	DWORD size = 0xFFFFFFFF;
	char  ebuf[256];
	unsigned char lock_op;

	if ((operation & (ACL_FLOCK_OP_BITS)) != operation)
		acl_msg_panic("myflock: improper operation type: 0x%x", operation);

	lock_op = operation & ~ACL_FLOCK_OP_NOWAIT;

	if (lock_op == ACL_FLOCK_OP_NONE) {
		if(UnlockFile(fd, 0, 0, size, 0))
			return (0);

		acl_msg_error("%s(%d): unlock error(%s)",
			myname, __LINE__, acl_last_strerror(ebuf,sizeof(ebuf)));
		return (-1);
	} else if (lock_op == ACL_FLOCK_OP_SHARED) {
		while (1) {
			if(LockFile(fd, 0, 0, size, 0))
				return (0);

			if ((operation & ACL_FLOCK_OP_NOWAIT))
				return (-1);
			sleep(1);
		}
	} else if (lock_op == ACL_FLOCK_OP_EXCLUSIVE) {
		while (1) {
			if(LockFile(fd, 0, 0, size, 0))
				return (0);

			if ((operation & ACL_FLOCK_OP_NOWAIT))
				return (-1);
			sleep(1);
		}
	}

	acl_msg_error("%s(%d): invalid lock_op(%d)", myname, __LINE__, lock_op);
	return (-1);
}
예제 #23
0
파일: tls_prng_egd.c 프로젝트: 10jschen/acl
ssize_t tls_prng_egd_read(TLS_PRNG_SRC *egd, size_t len)
{
    const char *myname = "tls_prng_egd_read";
    unsigned char buffer[UCHAR_MAX];
    ssize_t count;

    if (len <= 0)
	acl_msg_panic("%s: bad length %ld", myname, (long) len);

    buffer[0] = 1;
    buffer[1] = (unsigned char) (len > UCHAR_MAX ? UCHAR_MAX : len);

    if (acl_timed_write(egd->fd.sock, buffer, 2, egd->timeout, (void *) 0) != 2) {
	acl_msg_info("%s: cannot write to EGD server %s: %s",
		myname, egd->name, acl_last_serror());
	return (-1);
    }
    if (acl_timed_read(egd->fd.sock, buffer, 1, egd->timeout, (void *) 0) != 1) {
	acl_msg_info("%s: cannot read from EGD server %s: %s",
		myname, egd->name, acl_last_serror());
	return (-1);
    }
    count = buffer[0];
    if (count > (ssize_t) sizeof(buffer))
	count = sizeof(buffer);
    if (count == 0) {
	acl_msg_info("EGD server %s reports zero bytes available", egd->name);
	return (-1);
    }
    if (acl_timed_read(egd->fd.sock, buffer, count, egd->timeout, (void *) 0) != count) {
	acl_msg_info("%s: cannot read %ld bytes from EGD server %s: %s",
		 myname, (long) count, egd->name, acl_last_serror());
	return (-1);
    }
    if (acl_msg_verbose)
	acl_msg_info("%s: got %ld bytes from EGD server %s", myname,
		 (long) count, egd->name);
    RAND_seed(buffer, count);
    return (count);
}
예제 #24
0
static void acl_watchdog_event(int unused_sig acl_unused)
{
	const char* myname = "acl_watchdog_event";
	ACL_WATCHDOG *wp;

	/*
	 * This routine runs as a signal handler. We should not do anything
	 * that could involve memory allocation/deallocation, but exiting
	 * without proper explanation would be unacceptable.
	 */
	if ((wp = acl_watchdog_curr) == 0)
		acl_msg_panic("%s: no instance", myname);
	if (acl_msg_verbose > 1)
		acl_msg_info("%s: %p %d", myname, (void *) wp, wp->trip_run);
	if (++(wp->trip_run) < ACL_WATCHDOG_STEPS)
		alarm(wp->timeout);
	else {
		if (wp->action)
			wp->action(wp, wp->context);
		else
			acl_msg_fatal("watchdog timeout");
	}
}
예제 #25
0
int acl_master_flow_get(int len)
{
	char  myname[] = "acl_master_flow_get";
	char  buf[BUFFER_SIZE];
	struct stat st;
	int   count;
	int   n = 0;

	/*
	 * Sanity check.
	 */
	if (len <= 0)
		acl_msg_panic("%s: bad length %d", myname, len);

	/*
	 * Silence some wild claims.
	 */
	if (fstat(ACL_MASTER_FLOW_WRITE, &st) < 0)
		acl_msg_fatal("fstat flow pipe write descriptor: %s", strerror(errno));

	/*
	 * Read and discard N bytes. XXX AIX read() can return 0 when an open
	 * pipe is empty.
	 */
	for (count = len; count > 0; count -= n) {
		n = read(ACL_MASTER_FLOW_READ,
			buf,
			count > BUFFER_SIZE ? BUFFER_SIZE : count);
		if (n <= 0)
			return (-1);
	}

	if (acl_msg_verbose)
		acl_msg_info("%s: %d %d", myname, len, len - count);
	return (len - count);
}
예제 #26
0
void http_chat_sync_resctl(HTTP_RES *respond, int name, ...)
{
	const char *myname = "http_chat_sync_resctl";
	va_list ap;
	int   n;

	va_start(ap, name);
	for (; name != HTTP_CHAT_SYNC_CTL_END; name = va_arg(ap, int)) {
		switch (name) {
		case HTTP_CHAT_CTL_BUFF_ONOFF:
			n = va_arg(ap, int);
			if (n)
				respond->flag |= HTTP_CHAT_FLAG_BUFFED;
			else
				respond->flag &= ~HTTP_CHAT_FLAG_BUFFED;
			break;
		default:
			acl_msg_panic("%s, %s(%d): bad name %d",
				myname, __FILE__, __LINE__, name);
			break;
		}
	}
	va_end(ap);
}
예제 #27
0
파일: tls_bio_ops.c 프로젝트: 10jschen/acl
int     tls_bio(ACL_SOCKET fd, int timeout, TLS_SESS_STATE *TLScontext,
	int (*hsfunc) (SSL *),
	int (*rfunc) (SSL *, void *, int),
	int (*wfunc) (SSL *, const void *, int),
	void *buf, int num)
{
    const char *myname = "tls_bio";
    int     status = 0;
    int     err;
    int     retval = 0;
    int     biop_retval;
    int     done;

    /*
     * If necessary, retry the SSL handshake or read/write operation after
     * handling any pending network I/O.
     */
    for (done = 0; done == 0; /* void */ ) {
	if (hsfunc) {
#if 1
	    status = hsfunc(TLScontext->con);
#else
	    status = SSL_do_handshake(TLScontext->con);
#endif
	} else if (rfunc)
	    status = rfunc(TLScontext->con, buf, num);
	else if (wfunc)
	    status = wfunc(TLScontext->con, buf, num);
	else
	    acl_msg_panic("%s: nothing to do here", myname);
	err = SSL_get_error(TLScontext->con, status);

#if (OPENSSL_VERSION_NUMBER <= 0x0090581fL)

	/*
	 * There is a bug up to and including OpenSSL-0.9.5a: if an error
	 * occurs while checking the peers certificate due to some
	 * certificate error (e.g. as happend with a RSA-padding error), the
	 * error is put onto the error stack. If verification is not
	 * enforced, this error should be ignored, but the error-queue is not
	 * cleared, so we can find this error here. The bug has been fixed on
	 * May 28, 2000.
	 * 
	 * This bug so far has only manifested as 4800:error:0407006A:rsa
	 * routines:RSA_padding_check_PKCS1_type_1:block type is not
	 * 01:rsa_pk1.c:100: 4800:error:04067072:rsa
	 * routines:RSA_EAY_PUBLIC_DECRYPT:padding check
	 * failed:rsa_eay.c:396: 4800:error:0D079006:asn1 encoding
	 * routines:ASN1_verify:bad get asn1 object call:a_verify.c:109: so
	 * that we specifically test for this error. We print the errors to
	 * the logfile and automatically clear the error queue. Then we retry
	 * to get another error code. We cannot do better, since we can only
	 * retrieve the last entry of the error-queue without actually
	 * cleaning it on the way.
	 * 
	 * This workaround is secure, as verify_result is set to "failed"
	 * anyway.
	 */
	if (err == SSL_ERROR_SSL) {
	    if (ERR_peek_error() == 0x0407006AL) {
		tls_print_errors();
		acl_msg_info("OpenSSL <= 0.9.5a workaround called: certificate errors ignored");
		err = SSL_get_error(TLScontext->con, status);
	    }
	}
#endif

	/*
	 * Find out if we must retry the operation and/or if there is pending
	 * network I/O.
	 * 
	 * XXX If we're the first to invoke SSL_shutdown(), then the operation
	 * isn't really complete when the call returns. We could hide that
	 * anomaly here and repeat the call.
	 */
	switch (err) {
	case SSL_ERROR_NONE:			/* success */
	    retval = status;
	    done = 1;
	    /* FALLTHROUGH */
	case SSL_ERROR_WANT_WRITE:		/* flush/update buffers */
	case SSL_ERROR_WANT_READ:
	    biop_retval = network_biopair_interop(fd, timeout, TLScontext->network_bio);
	    if (biop_retval < 0)
		return (-1);		/* network read/write error */
	    break;

	    /*
	     * With tls_timed_read() and tls_timed_write() the caller is the
	     * VSTREAM library module which is unaware of TLS, so we log the
	     * TLS error stack here. In a better world, each VSTREAM I/O
	     * object would provide an error reporting method in addition to
	     * the timed_read and timed_write methods, so that we would not
	     * need to have ad-hoc code like this.
	     */
	case SSL_ERROR_SSL:
	    if (rfunc || wfunc)
		tls_print_errors();
	    /* FALLTHROUGH */
	default:
	    retval = status;
	    done = 1;
	    break;
	}
    }
    return (retval);
}
예제 #28
0
파일: tls_bio_ops.c 프로젝트: 10jschen/acl
static int network_biopair_interop(ACL_SOCKET fd, int timeout, BIO *network_bio)
{
    const char *myname = "network_biopair_interop";
    int     want_write;
    int     num_write;
    int     write_pos;
    int     from_bio;
    int     want_read;
    int     num_read;
    int     to_bio;
    char    buffer[NETLAYER_BUFFERSIZE];

    /*
     * To avoid deadlock, write all pending data to the network before
     * attempting to read from the network.
     */
    while ((want_write = (int) BIO_ctrl_pending(network_bio)) > 0) {
	if (want_write > (int) sizeof(buffer))
	    want_write = (int) sizeof(buffer);
	from_bio = BIO_read(network_bio, buffer, want_write);

	/*
	 * Write the complete buffer contents to the network.
	 */
	for (write_pos = 0; write_pos < from_bio; /* see below */ ) {
	    if (timeout > 0 && acl_write_wait(fd, timeout) < 0)
		return (-1);
	    num_write = acl_socket_write(fd, buffer + write_pos, from_bio - write_pos, 0, 0, 0);
	    if (num_write <= 0) {
		if ((num_write < 0) && (timeout > 0) && (errno == ACL_EAGAIN || errno == ACL_EINTR)) {
		    acl_msg_warn("%s: write() returns EAGAIN on a writable file descriptor!", myname);
		    acl_msg_warn("%s: pausing to avoid going into a tight select/write loop!", myname);
		    sleep(1);
		} else {
		    acl_msg_warn("%s: error writing %d bytes to the network: %s",
			    myname, from_bio - write_pos, acl_last_serror());
		    return (-1);
		}
	    } else {
		write_pos += num_write;
	    }
	}
    }

    /*
     * Read data from the network into the BIO pair.
     */
    while ((want_read = (int) BIO_ctrl_get_read_request(network_bio)) > 0) {
	if (want_read > (int) sizeof(buffer))
	    want_read = (int) sizeof(buffer);
	if (timeout > 0 && acl_read_wait(fd, timeout) < 0)
	    return (-1);
	num_read = acl_socket_read(fd, buffer, want_read, 0, 0, 0);
	if (num_read == 0)
	    /* FIX 200412 Cannot return a zero read count. */
	    return (-1);
	if (num_read < 0) {
	    if ((num_read < 0) && (timeout > 0) && (errno == ACL_EAGAIN || errno == ACL_EINTR)) {
		acl_msg_warn("%s: read() returns EAGAIN on a readable file descriptor!", myname);
		acl_msg_warn("%s: pausing to avoid going into a tight select/write loop!", myname);
		sleep(1);
	    } else {
		acl_msg_warn("%s: error reading %d bytes from the network: %s",
			myname, want_read, acl_last_serror());
		return (-1);
	    }
	} else {
	    to_bio = BIO_write(network_bio, buffer, num_read);
	    if (to_bio != num_read)
		acl_msg_panic("%s: BIO_write error: to_bio != num_read", myname);
	}
    }
    return (0);
}
예제 #29
0
ACL_VSTRING *tok822_externalize(ACL_VSTRING *vp, TOK822 *tree, int flags)
{
	ACL_VSTRING *tmp;
	TOK822 *tp;
	ssize_t start = 0;
	TOK822 *addr = 0;
	ssize_t addr_len = 0;

	/*
	 * Guard against a Sendmail buffer overflow (CERT advisory CA-2003-07).
	 * The problem was that Sendmail could store too much non-address text
	 * (comments, phrases, etc.) into a static 256-byte buffer.
	 * 
	 * When the buffer fills up, fixed Sendmail versions remove comments etc.
	 * and reduce the information to just <$g>, which expands to <address>.
	 * No change is made when an address expression (text separated by
	 * commas) contains no address. This fix reportedly also protects
	 * Sendmail systems that are still vulnerable to this problem.
	 * 
	 * Postfix takes the same approach, grudgingly. To avoid unnecessary damage,
	 * Postfix removes comments etc. only when the amount of non-address text
	 * in an address expression (text separated by commas) exceeds 250 bytes.
	 * 
	 * With Sendmail, the address part of an address expression is the
	 * right-most <> instance in that expression. If an address expression
	 * contains no <>, then Postfix guarantees that it contains at most one
	 * non-comment string; that string is the address part of the address
	 * expression, so there is no ambiguity.
	 * 
	 * Finally, we note that stress testing shows that other code in Sendmail
	 * 8.12.8 bluntly truncates ``text <address>'' to 256 bytes even when
	 * this means chopping the <address> somewhere in the middle. This is a
	 * loss of control that we're not entirely comfortable with. However,
	 * unbalanced quotes and dangling backslash do not seem to influence the
	 * way that Sendmail parses headers, so this is not an urgent problem.
	 */
#define MAX_NONADDR_LENGTH 250

#define RESET_NONADDR_LENGTH { \
	start = ACL_VSTRING_LEN(vp); \
	addr = 0; \
	addr_len = 0; \
}

#define ENFORCE_NONADDR_LENGTH do { \
	if (addr && (ssize_t) ACL_VSTRING_LEN(vp) - addr_len > start + MAX_NONADDR_LENGTH) \
		strip_address(vp, start, addr->head); \
} while(0)

	if (flags & TOK822_STR_WIPE)
		ACL_VSTRING_RESET(vp);

	if (flags & TOK822_STR_TRNC)
		RESET_NONADDR_LENGTH;

	for (tp = tree; tp; tp = tp->next) {
		switch (tp->type) {
		case ',':
			if (flags & TOK822_STR_TRNC)
				ENFORCE_NONADDR_LENGTH;
			ACL_VSTRING_ADDCH(vp, tp->type);
			ACL_VSTRING_ADDCH(vp, (flags & TOK822_STR_LINE) ? '\n' : ' ');
			if (flags & TOK822_STR_TRNC)
				RESET_NONADDR_LENGTH;
			continue;

			/*
			 * XXX In order to correctly externalize an address, it is not
			 * sufficient to quote individual atoms. There are higher-level
			 * rules that say when an address localpart needs to be quoted.
			 * We wing it with the quote_822_local() routine, which ignores
			 * the issue of atoms in the domain part that would need quoting.
			 */
		case TOK822_ADDR:
			addr = tp;
			tmp = acl_vstring_alloc(100);
			tok822_internalize(tmp, tp->head, TOK822_STR_TERM);
			addr_len = ACL_VSTRING_LEN(vp);
			quote_822_local_flags(vp, acl_vstring_str(tmp),
				QUOTE_FLAG_8BITCLEAN | QUOTE_FLAG_APPEND);
			addr_len = ACL_VSTRING_LEN(vp) - addr_len;
			acl_vstring_free(tmp);
			break;
		case TOK822_ATOM:
		case TOK822_COMMENT:
			acl_vstring_strcat(vp, acl_vstring_str(tp->vstr));
			break;
		case TOK822_QSTRING:
			ACL_VSTRING_ADDCH(vp, '"');
			tok822_copy_quoted(vp, acl_vstring_str(tp->vstr), "\"\\\r\n");
			ACL_VSTRING_ADDCH(vp, '"');
			break;
		case TOK822_DOMLIT:
			ACL_VSTRING_ADDCH(vp, '[');
			tok822_copy_quoted(vp, acl_vstring_str(tp->vstr), "\\\r\n");
			ACL_VSTRING_ADDCH(vp, ']');
			break;
		case TOK822_STARTGRP:
			ACL_VSTRING_ADDCH(vp, ':');
			break;
		case '<':
			if (tp->next && tp->next->type == '>') {
				addr = tp;
				addr_len = 0;
			}
			ACL_VSTRING_ADDCH(vp, '<');
			break;
		default:
			if (tp->type >= TOK822_MINTOK)
				acl_msg_panic("tok822_externalize: unknown operator %d", tp->type);
			ACL_VSTRING_ADDCH(vp, tp->type);
		}
		if (tok822_append_space(tp))
			ACL_VSTRING_ADDCH(vp, ' ');
	}
	if (flags & TOK822_STR_TRNC)
		ENFORCE_NONADDR_LENGTH;

	if (flags & TOK822_STR_TERM)
		ACL_VSTRING_TERMINATE(vp);
	return (vp);
}
예제 #30
0
static void event_enable_read(ACL_EVENT *eventp,
			ACL_VSTREAM *stream,
			int timeout,
			ACL_EVENT_NOTIFY_RDWR callback,
			void *context)
{
	const char *myname = "event_enable_read";
	EVENT_SELECT_THR *event_thr = (EVENT_SELECT_THR *) eventp;
	ACL_EVENT_FDTABLE *fdp;
	ACL_SOCKET sockfd;

	sockfd = ACL_VSTREAM_SOCK(stream);

	THREAD_LOCK(&event_thr->event.tb_mutex);

	/*
	* Disallow multiple requests on the same file descriptor.
	* Allow duplicates of the same request.
	*/
	if (FD_ISSET(sockfd, &event_thr->wmask))
		acl_msg_panic("%s(%d), %s: fd %d: multiple I/O request",
			__FILE__, __LINE__, myname, sockfd);

	fdp = stream->fdp;
	if (fdp == NULL)
		fdp = event_fdtable_alloc();

	if (fdp->flag & EVENT_FDTABLE_FLAG_WRITE)
		acl_msg_panic("%s(%d)->%s: fd %d: multiple I/O request",
			__FILE__, __LINE__, myname, sockfd);

	if ((fdp->flag & EVENT_FDTABLE_FLAG_READ) == 0) {
		fdp->flag = EVENT_FDTABLE_FLAG_READ | EVENT_FDTABLE_FLAG_EXPT;

		if (FD_ISSET(sockfd, &event_thr->rmask))
			acl_msg_fatal("%s, %s(%d): sockfd(%d) has been in rmask",
				myname, __FILE__, __LINE__, sockfd);

		FD_SET(sockfd, &event_thr->xmask);
		FD_SET(sockfd, &event_thr->rmask);

		stream->fdp = (void *) fdp;
		stream->nrefer++;
		fdp->stream = stream;
		fdp->listener = 0;
		fdp->fdidx = eventp->fdcnt;
		eventp->fdtabs[eventp->fdcnt] = fdp;
		eventp->fdcnt++;

		if (eventp->maxfd != ACL_SOCKET_INVALID && eventp->maxfd < sockfd)
			eventp->maxfd = sockfd;
	}

	if (fdp->r_callback != callback || fdp->r_context != context) {
		fdp->r_callback = callback;
		fdp->r_context = context;
	}

	if (timeout > 0) {
		fdp->r_timeout = timeout * 1000000;
		fdp->r_ttl = eventp->event_present + fdp->r_timeout;
	} else {
		fdp->r_ttl = 0;
		fdp->r_timeout = 0;
	}

	THREAD_UNLOCK(&event_thr->event.tb_mutex);

	/* 主要是为了减少通知次数 */
	if (event_thr->event.blocked && event_thr->event.evdog
	    && event_dog_client(event_thr->event.evdog) != stream)
		event_dog_notify(event_thr->event.evdog);
}