Ejemplo n.º 1
0
static void check_other_work(sec_mod_st *sec)
{
	if (need_exit) {
		unsigned i;

		for (i = 0; i < sec->key_size; i++) {
			gnutls_privkey_deinit(sec->key[i]);
		}

		sec_mod_client_db_deinit(sec);
		tls_cache_deinit(&sec->tls_db);
		talloc_free(sec);
		exit(0);
	}

	if (need_reload) {
		seclog(sec, LOG_DEBUG, "reloading configuration");
		reload_cfg_file(sec, sec->perm_config, 0);
		sec->config = sec->perm_config->config;
		load_keys(sec, 0);
		need_reload = 0;
	}

	if (need_maintainance) {
		seclog(sec, LOG_DEBUG, "performing maintenance");
		cleanup_client_entries(sec);
		expire_tls_sessions(sec);
		seclog(sec, LOG_DEBUG, "active sessions %d", 
			sec_mod_client_db_elems(sec));
		alarm(MAINTAINANCE_TIME);
		need_maintainance = 0;
	}
}
Ejemplo n.º 2
0
static
int send_sec_auth_reply(int cfd, sec_mod_st * sec, client_entry_st * entry, AUTHREP r)
{
	SecAuthReplyMsg msg = SEC_AUTH_REPLY_MSG__INIT;
	int ret;

	if (r == AUTH__REP__OK) {
		/* fill message */
		ret = generate_cookie(sec, entry);
		if (ret < 0) {
			seclog(sec, LOG_INFO, "cannot generate cookie");
			return ret;
		}

		msg.reply = AUTH__REP__OK;
		msg.has_cookie = 1;
		msg.cookie.data = entry->cookie;
		msg.cookie.len = entry->cookie_size;

		msg.user_name = entry->auth_info.username;

		if (entry->msg_str != NULL) {
			msg.msg = entry->msg_str;
		}

		msg.has_sid = 1;
		msg.sid.data = entry->sid;
		msg.sid.len = sizeof(entry->sid);

		msg.has_dtls_session_id = 1;
		msg.dtls_session_id.data = entry->dtls_session_id;
		msg.dtls_session_id.len = sizeof(entry->dtls_session_id);

		ret = send_msg(entry, cfd, SM_CMD_AUTH_REP,
			       &msg,
			       (pack_size_func)
			       sec_auth_reply_msg__get_packed_size,
			       (pack_func) sec_auth_reply_msg__pack);
	} else {
		msg.reply = AUTH__REP__FAILED;

		ret = send_msg(entry, cfd, SM_CMD_AUTH_REP,
			       &msg,
			       (pack_size_func)
			       sec_auth_reply_msg__get_packed_size,
			       (pack_func) sec_auth_reply_msg__pack);
	}

	if (ret < 0) {
		int e = errno;
		seclog(sec, LOG_ERR, "send_msg: %s", strerror(e));
		return ret;
	}

	talloc_free(entry->msg_str);
	entry->msg_str = NULL;

	return 0;
}
Ejemplo n.º 3
0
static int check_user_group_status(sec_mod_st * sec, client_entry_st * e,
				   int tls_auth_ok, const char *cert_user,
				   char **cert_groups,
				   unsigned cert_groups_size)
{
	unsigned found, i;

	if (e->auth_type & AUTH_TYPE_CERTIFICATE) {
		if (tls_auth_ok == 0) {
			seclog(sec, LOG_INFO, "user %s "SESSION_STR" presented no certificate",
			       e->auth_info.username, e->auth_info.psid);
			return -1;
		}

		e->tls_auth_ok = tls_auth_ok;
		if (tls_auth_ok != 0) {
			if (e->auth_info.username[0] == 0 && sec->config->cert_user_oid != NULL) {
				if (cert_user == NULL) {
					seclog(sec, LOG_INFO, "no username in the certificate!");
					return -1;
				}

				strlcpy(e->auth_info.username, cert_user, sizeof(e->auth_info.username));
				if (cert_groups_size > 0 && sec->config->cert_group_oid != NULL && e->auth_info.groupname[0] == 0)
					strlcpy(e->auth_info.groupname, cert_groups[0], sizeof(e->auth_info.groupname));
			} else {
				if (sec->config->cert_user_oid != NULL && cert_user && strcmp(e->auth_info.username, cert_user) != 0) {
					seclog(sec, LOG_INFO,
					       "user '%s' "SESSION_STR" presented a certificate from user '%s'",
					       e->auth_info.username, e->auth_info.psid, cert_user);
					return -1;
				}

				if (sec->config->cert_group_oid != NULL) {
					found = 0;
					for (i=0;i<cert_groups_size;i++) {
						if (strcmp(e->auth_info.groupname, cert_groups[i]) == 0) {
							found++;
							break;
						}
					}
					if (found == 0) {
						seclog(sec, LOG_INFO,
							"user '%s' "SESSION_STR" presented a certificate from group '%s' but he isn't a member of it",
							e->auth_info.username, e->auth_info.psid, e->auth_info.groupname);
							return -1;
					}
				}
			}
		}
	}

	return 0;
}
Ejemplo n.º 4
0
int handle_sec_auth_stats_cmd(sec_mod_st * sec, const CliStatsMsg * req)
{
	client_entry_st *e;
	stats_st totals;

	if (req->sid.len != SID_SIZE) {
		seclog(sec, LOG_ERR, "auth session stats but with illegal sid size (%d)!",
		       (int)req->sid.len);
		return -1;
	}

	e = find_client_entry(sec, req->sid.data);
	if (e == NULL) {
		char tmp[BASE64_LENGTH(SID_SIZE) + 1];
		base64_encode((char *)req->sid.data, req->sid.len, (char *)tmp, sizeof(tmp));
		seclog(sec, LOG_INFO, "session stats but with non-existing SID: %s", tmp);
		return -1;
	}

	if (e->status != PS_AUTH_COMPLETED) {
		seclog(sec, LOG_ERR, "session stats received in unauthenticated client %s "SESSION_STR"!", e->auth_info.username, e->auth_info.psid);
		return -1;
	}

	/* stats only increase */
	if (req->bytes_in > e->stats.bytes_in)
		e->stats.bytes_in = req->bytes_in;
	if (req->bytes_out > e->stats.bytes_out)
		e->stats.bytes_out = req->bytes_out;
	if (req->uptime > e->stats.uptime)
		e->stats.uptime = req->uptime;

	if (req->has_discon_reason && req->discon_reason != 0) {
		e->discon_reason = req->discon_reason;
	}

	if (sec->perm_config->acct.amod == NULL || sec->perm_config->acct.amod->session_stats == NULL)
		return 0;

	stats_add_to(&totals, &e->stats, &e->saved_stats);
	if (req->remote_ip)
		strlcpy(e->auth_info.remote_ip, req->remote_ip, sizeof(e->auth_info.remote_ip));
	if (req->ipv4)
		strlcpy(e->auth_info.ipv4, req->ipv4, sizeof(e->auth_info.ipv4));
	if (req->ipv6)
		strlcpy(e->auth_info.ipv6, req->ipv6, sizeof(e->auth_info.ipv6));

	sec->perm_config->acct.amod->session_stats(e->auth_type, e->auth_ctx, &e->auth_info, &totals);

	return 0;
}
Ejemplo n.º 5
0
static
int send_failed_session_open_reply(sec_mod_st *sec, int fd)
{
	SecAuthSessionReplyMsg rep = SEC_AUTH_SESSION_REPLY_MSG__INIT;
	void *lpool;
	int ret;

	rep.reply = AUTH__REP__FAILED;

	lpool = talloc_new(sec);
	if (lpool == NULL) {
		return ERR_BAD_COMMAND;
	}

	ret = send_msg(lpool, fd, SM_CMD_AUTH_SESSION_REPLY, &rep,
			(pack_size_func) sec_auth_session_reply_msg__get_packed_size,
			(pack_func) sec_auth_session_reply_msg__pack);
	if (ret < 0) {
		seclog(sec, LOG_WARNING, "error in sending session reply");
		ret = ERR_BAD_COMMAND; /* we desynced */
	}
	talloc_free(lpool);

	return ret;
}
Ejemplo n.º 6
0
/* returns a negative number if we have reached the score for this client.
 */
static
void sec_mod_add_score_to_ip(sec_mod_st *sec, client_entry_st *e, const char *ip, unsigned points)
{
	void *lpool = talloc_new(e);
	int ret, err;
	BanIpMsg msg = BAN_IP_MSG__INIT;

	/* no reporting if banning is disabled */
	if (sec->config->max_ban_score == 0)
		return;

	msg.ip = (char*)ip;
	msg.score = points;
	msg.sid.data = e->sid;
	msg.sid.len = sizeof(e->sid);
	msg.has_sid = 1;

	if (lpool == NULL) {
		return;
	}

	ret = send_msg(lpool, sec->cmd_fd, SM_CMD_AUTH_BAN_IP, &msg,
				(pack_size_func) ban_ip_msg__get_packed_size,
				(pack_func) ban_ip_msg__pack);
	if (ret < 0) {
		err = errno;
		seclog(sec, LOG_WARNING, "error in sending BAN IP message: %s", strerror(err));
		goto fail;
	}

 fail:
	talloc_free(lpool);

	return;
}
Ejemplo n.º 7
0
static
int send_sec_auth_reply_msg(int cfd, sec_mod_st * sec, client_entry_st * e)
{
	SecAuthReplyMsg msg = SEC_AUTH_REPLY_MSG__INIT;
	int ret;

	msg.msg = e->msg_str;
	msg.passwd_counter = e->passwd_counter;
	if (e->passwd_counter > 0)
		msg.has_passwd_counter = 1;

	msg.reply = AUTH__REP__MSG;

	msg.has_sid = 1;
	msg.sid.data = e->sid;
	msg.sid.len = sizeof(e->sid);

	ret = send_msg(e, cfd, SM_CMD_AUTH_REP, &msg,
		       (pack_size_func) sec_auth_reply_msg__get_packed_size,
		       (pack_func) sec_auth_reply_msg__pack);
	if (ret < 0) {
		seclog(sec, LOG_ERR, "send_auth_reply_msg error");
	}

	talloc_free(e->msg_str);
	e->msg_str = NULL;

	return ret;
}
Ejemplo n.º 8
0
client_entry_st *new_client_entry(sec_mod_st *sec, const char *ip)
{
	struct htable *db = sec->client_db;
	client_entry_st *e, *te;
	int ret;
	int retries = 3;

	e = talloc_zero(db, client_entry_st);
	if (e == NULL) {
		return NULL;
	}

	strlcpy(e->auth_info.remote_ip, ip, sizeof(e->auth_info.remote_ip));

	do {
		ret = gnutls_rnd(GNUTLS_RND_RANDOM, e->sid, sizeof(e->sid));
		if (ret < 0) {
			seclog(sec, LOG_ERR, "error generating SID");
			goto fail;
		}

		/* check if in use */
		te = find_client_entry(sec, e->sid);
	} while(te != NULL && retries-- >= 0);

	if (te != NULL) {
		seclog(sec, LOG_ERR,
		       "could not generate a unique SID!");
		goto fail;
	}

	base64_encode((char *)e->sid, SID_SIZE, (char *)e->auth_info.psid, sizeof(e->auth_info.psid));
	e->time = time(0);

	if (htable_add(db, rehash(e, NULL), e) == 0) {
		seclog(sec, LOG_ERR,
		       "could not add client entry to hash table");
		goto fail;
	}

	return e;

 fail:
	talloc_free(e);
	return NULL;
}
Ejemplo n.º 9
0
static
int serve_request_worker(sec_mod_st *sec, int cfd, pid_t pid, uint8_t *buffer, unsigned buffer_size)
{
	int ret, e;
	uint8_t cmd;
	size_t length;
	void *pool = buffer;

	/* read request */
	ret = recv_msg_headers(cfd, &cmd, MAX_WAIT_SECS);
	if (ret < 0) {
		seclog(sec, LOG_DEBUG, "error receiving msg head from worker");
		goto leave;
	}

	length = ret;

	if (length > buffer_size) {
		seclog(sec, LOG_INFO, "too big message (%d)", (int)length);
		ret = -1;
		goto leave;
	}

	/* read the body */
	ret = force_read_timeout(cfd, buffer, length, MAX_WAIT_SECS);
	if (ret < 0) {
		e = errno;
		seclog(sec, LOG_INFO, "error receiving msg body: %s",
		       strerror(e));
		ret = -1;
		goto leave;
	}

	ret = process_worker_packet(pool, cfd, pid, sec, cmd, buffer, ret);
	if (ret < 0) {
		seclog(sec, LOG_INFO, "error processing data for '%s' command (%d)", cmd_request_to_str(cmd), ret);
	}
	
 leave:
	return ret;
}
Ejemplo n.º 10
0
int handle_sec_auth_cont(int cfd, sec_mod_st * sec, const SecAuthContMsg * req)
{
	client_entry_st *e;
	int ret;

	if (req->sid.len != SID_SIZE) {
		seclog(sec, LOG_ERR, "auth cont but with illegal sid size (%d)!",
		       (int)req->sid.len);
		return -1;
	}

	e = find_client_entry(sec, req->sid.data);
	if (e == NULL) {
		seclog(sec, LOG_ERR, "auth cont but with non-existing sid!");
		return -1;
	}

	if (e->status != PS_AUTH_INIT && e->status != PS_AUTH_CONT) {
		seclog(sec, LOG_ERR, "auth cont received for %s "SESSION_STR" but we are on state %u!",
		       e->auth_info.username, e->auth_info.psid, e->status);
		ret = -1;
		goto cleanup;
	}

	seclog(sec, LOG_DEBUG, "auth cont for user '%s' "SESSION_STR, e->auth_info.username, e->auth_info.psid);

	if (req->password == NULL) {
		seclog(sec, LOG_ERR, "no password given in auth cont for user '%s' "SESSION_STR,
			e->auth_info.username, e->auth_info.psid);
		ret = -1;
		goto cleanup;
	}

	if (e->module == NULL) {
		seclog(sec, LOG_ERR, "no module available!");
		ret = -1;
		goto cleanup;
	}

	e->status = PS_AUTH_CONT;

	ret =
	    e->module->auth_pass(e->auth_ctx, req->password,
			      strlen(req->password));
	if (ret < 0) {
		if (ret != ERR_AUTH_CONTINUE) {
			seclog(sec, LOG_DEBUG,
			       "error in password given in auth cont for user '%s' "SESSION_STR,
			       e->auth_info.username, e->auth_info.psid);
		}
		goto cleanup;
	}

 cleanup:
	return handle_sec_auth_res(cfd, sec, e, ret);
}
Ejemplo n.º 11
0
static void send_empty_reply(void *pool, int fd, sec_mod_st *sec)
{
	SecmListCookiesReplyMsg msg = SECM_LIST_COOKIES_REPLY_MSG__INIT;
	int ret;
	
	ret = send_msg(pool, fd, CMD_SECM_LIST_COOKIES_REPLY, &msg,
		(pack_size_func) secm_list_cookies_reply_msg__get_packed_size,
		(pack_func) secm_list_cookies_reply_msg__pack);
	if (ret < 0) {
		seclog(sec, LOG_ERR, "Error sending empty show cookies reply to main");
	}
}
Ejemplo n.º 12
0
void sec_auth_user_deinit(sec_mod_st *sec, client_entry_st *e)
{
	seclog(sec, LOG_DEBUG, "permamently closing session of user '%s' "SESSION_STR, e->auth_info.username, e->auth_info.psid);
	if (sec->perm_config->acct.amod != NULL && sec->perm_config->acct.amod->close_session != NULL && e->session_is_open != 0) {
		sec->perm_config->acct.amod->close_session(e->auth_type, e->auth_ctx, &e->auth_info, &e->saved_stats, e->discon_reason);
	}

	if (e->auth_ctx != NULL) {
		if (e->module)
			e->module->auth_deinit(e->auth_ctx);
		e->auth_ctx = NULL;
	}
}
Ejemplo n.º 13
0
static int handle_op(void *pool, int cfd, sec_mod_st * sec, uint8_t type, uint8_t * rep,
		     size_t rep_size)
{
	SecOpMsg msg = SEC_OP_MSG__INIT;
	int ret;

	msg.data.data = rep;
	msg.data.len = rep_size;

	ret = send_msg(pool, cfd, type, &msg,
		       (pack_size_func) sec_op_msg__get_packed_size,
		       (pack_func) sec_op_msg__pack);
	if (ret < 0) {
		seclog(sec, LOG_WARNING, "sec-mod error in sending reply");
	}

	return 0;
}
Ejemplo n.º 14
0
static
int serve_request_main(sec_mod_st *sec, int fd, uint8_t *buffer, unsigned buffer_size)
{
	int ret, e;
	uint8_t cmd;
	size_t length;
	void *pool = buffer;

	/* read request */
	ret = recv_msg_headers(fd, &cmd, MAIN_SEC_MOD_TIMEOUT);
	if (ret < 0) {
		seclog(sec, LOG_ERR, "error receiving msg head from main");
		ret = ERR_BAD_COMMAND;
		goto leave;
	}

	length = ret;

	seclog(sec, LOG_DEBUG, "received request %s", cmd_request_to_str(cmd));
	if (cmd <= MIN_SECM_CMD || cmd >= MAX_SECM_CMD) {
		seclog(sec, LOG_ERR, "received invalid message from main of %u bytes (cmd: %u)\n",
		      (unsigned)length, (unsigned)cmd);
		return ERR_BAD_COMMAND;
	}

	if (length > buffer_size) {
		seclog(sec, LOG_ERR, "received too big message (%d)", (int)length);
		ret = ERR_BAD_COMMAND;
		goto leave;
	}

	/* read the body */
	ret = force_read_timeout(fd, buffer, length, MAIN_SEC_MOD_TIMEOUT);
	if (ret < 0) {
		e = errno;
		seclog(sec, LOG_ERR, "error receiving msg body of cmd %u with length %u: %s",
		       cmd, (unsigned)length, strerror(e));
		ret = ERR_BAD_COMMAND;
		goto leave;
	}

	ret = process_packet_from_main(pool, fd, sec, cmd, buffer, ret);
	if (ret < 0) {
		seclog(sec, LOG_ERR, "error processing data for '%s' command (%d)", cmd_request_to_str(cmd), ret);
	}
	
 leave:
	return ret;
}
Ejemplo n.º 15
0
void handle_sec_auth_ban_ip_reply(sec_mod_st *sec, const BanIpReplyMsg *msg)
{
	client_entry_st *e;

	if (msg->sid.len != SID_SIZE) {
		seclog(sec, LOG_ERR, "ban IP reply but with illegal sid size (%d)!",
		       (int)msg->sid.len);
		return;
	}

	e = find_client_entry(sec, msg->sid.data);
	if (e == NULL) {
		return;
	}

	if (msg->reply != AUTH__REP__OK) {
		e->status = PS_AUTH_FAILED;
	}

	return;
}
Ejemplo n.º 16
0
static
int set_module(sec_mod_st * sec, client_entry_st *e, unsigned auth_type)
{
	unsigned i;

	if (auth_type == 0)
		return -1;

	/* Find the first configured authentication method which contains
	 * the method asked by the worker, and use that. */
	for (i=0;i<sec->perm_config->auth_methods;i++) {
		if (sec->perm_config->auth[i].enabled && (sec->perm_config->auth[i].type & auth_type) == auth_type) {
			e->module = sec->perm_config->auth[i].amod;
			e->auth_type = sec->perm_config->auth[i].type;

			seclog(sec, LOG_INFO, "using '%s' authentication to authenticate user "SESSION_STR, sec->perm_config->auth[i].name, e->auth_info.psid);
			return 0;
		}
	}

	return -1;
}
Ejemplo n.º 17
0
Archivo: log.c Proyecto: fqtools/ocserv
void  seclog_hex(const struct sec_mod_st* sec, int priority,
		const char *prefix, uint8_t* bin, unsigned bin_size, unsigned b64)
{
	char buf[512];
	int ret;
	size_t buf_size;
	gnutls_datum_t data = {bin, bin_size};

	if (priority == LOG_DEBUG && sec->perm_config->debug == 0)
		return;

	if (b64) {
		oc_base64_encode((char*)bin, bin_size, (char*)buf, sizeof(buf));
	} else {
		buf_size = sizeof(buf);
		ret = gnutls_hex_encode(&data, buf, &buf_size);
		if (ret < 0)
			return;
	}

	seclog(sec, priority, "%s %s", prefix, buf);

	return;
}
Ejemplo n.º 18
0
int handle_sec_auth_init(int cfd, sec_mod_st *sec, const SecAuthInitMsg *req, pid_t pid)
{
	int ret = -1;
	client_entry_st *e;
	unsigned need_continue = 0;

	e = new_client_entry(sec, req->ip, pid);
	if (e == NULL) {
		seclog(sec, LOG_ERR, "cannot initialize memory");
		return -1;
	}

	ret = set_module(sec, e, req->auth_type);
	if (ret < 0) {
		seclog(sec, LOG_ERR, "no module found for auth type %u", (unsigned)req->auth_type);
		goto cleanup;
	}

	if (req->hostname != NULL) {
		strlcpy(e->hostname, req->hostname, sizeof(e->hostname));
	}

	if (e->module) {
		ret =
		    e->module->auth_init(&e->auth_ctx, e, req->user_name, req->ip, req->our_ip, pid);
		if (ret == ERR_AUTH_CONTINUE) {
			need_continue = 1;
		} else if (ret < 0) {
			goto cleanup;
		}

		ret =
		    e->module->auth_group(e->auth_ctx, req->group_name, e->auth_info.groupname,
				       sizeof(e->auth_info.groupname));
		if (ret != 0) {
			ret = -1;
			goto cleanup;
		}
		e->auth_info.groupname[sizeof(e->auth_info.groupname) - 1] = 0;

	}

	if (req->user_name != NULL) {
		strlcpy(e->auth_info.username, req->user_name, sizeof(e->auth_info.username));
	}

	if (req->our_ip != NULL) {
		strlcpy(e->auth_info.our_ip, req->our_ip, sizeof(e->auth_info.our_ip));
	}

	if (e->auth_type & AUTH_TYPE_CERTIFICATE) {
		if (e->auth_info.groupname[0] == 0 && req->group_name != NULL && sec->config->cert_group_oid != NULL) {
			unsigned i, found = 0;

			for (i=0;i<req->n_cert_group_names;i++) {
				if (strcmp(req->group_name, req->cert_group_names[i]) == 0) {
					strlcpy(e->auth_info.groupname, req->cert_group_names[i], sizeof(e->auth_info.groupname));
					found = 1;
					break;
				}
			}

			if (found == 0) {
				seclog(sec, LOG_AUTH, "user '%s' requested group '%s' but is not included on his certificate groups",
					req->user_name, req->group_name);
				ret = -1;
				goto cleanup;
			}
		}
	}

	ret =
	    check_user_group_status(sec, e, req->tls_auth_ok,
				    req->cert_user_name, req->cert_group_names,
				    req->n_cert_group_names);
	if (ret < 0) {
		goto cleanup;
	}

	e->status = PS_AUTH_INIT;
	seclog(sec, LOG_DEBUG, "auth init %sfor user '%s' "SESSION_STR" of group: '%s' from '%s'", 
	       req->tls_auth_ok?"(with cert) ":"",
	       e->auth_info.username, e->auth_info.psid, e->auth_info.groupname, req->ip);

	if (need_continue != 0) {
		ret = ERR_AUTH_CONTINUE;
		goto cleanup;
	}

	ret = 0;
 cleanup:
	return handle_sec_auth_res(cfd, sec, e, ret);
}
Ejemplo n.º 19
0
static
int process_worker_packet(void *pool, int cfd, pid_t pid, sec_mod_st * sec, cmd_request_t cmd,
		   uint8_t * buffer, size_t buffer_size)
{
	unsigned i;
	gnutls_datum_t data, out;
	int ret;
	SecOpMsg *op;
	PROTOBUF_ALLOCATOR(pa, pool);

	seclog(sec, LOG_DEBUG, "cmd [size=%d] %s\n", (int)buffer_size,
	       cmd_request_to_str(cmd));
	data.data = buffer;
	data.size = buffer_size;

	switch (cmd) {
	case CMD_SEC_SIGN:
	case CMD_SEC_DECRYPT:
		op = sec_op_msg__unpack(&pa, data.size, data.data);
		if (op == NULL) {
			seclog(sec, LOG_INFO, "error unpacking sec op\n");
			return -1;
		}

		i = op->key_idx;
		if (op->has_key_idx == 0 || i >= sec->key_size) {
			seclog(sec, LOG_INFO,
			       "received out-of-bounds key index (%d)", i);
			return -1;
		}

		data.data = op->data.data;
		data.size = op->data.len;

		if (cmd == CMD_SEC_DECRYPT) {
			ret =
			    gnutls_privkey_decrypt_data(sec->key[i], 0, &data,
							&out);
		} else {
#if GNUTLS_VERSION_NUMBER >= 0x030200
			ret =
			    gnutls_privkey_sign_hash(sec->key[i], 0,
						     GNUTLS_PRIVKEY_SIGN_FLAG_TLS1_RSA,
						     &data, &out);
#else
			ret =
			    gnutls_privkey_sign_raw_data(sec->key[i], 0, &data,
							 &out);
#endif
		}
		sec_op_msg__free_unpacked(op, &pa);

		if (ret < 0) {
			seclog(sec, LOG_INFO, "error in crypto operation: %s",
			       gnutls_strerror(ret));
			return -1;
		}

		ret = handle_op(pool, cfd, sec, cmd, out.data, out.size);
		gnutls_free(out.data);

		return ret;

	case CMD_SEC_CLI_STATS:{
			CliStatsMsg *tmsg;

			tmsg = cli_stats_msg__unpack(&pa, data.size, data.data);
			if (tmsg == NULL) {
				seclog(sec, LOG_ERR, "error unpacking data");
				return -1;
			}

			ret = handle_sec_auth_stats_cmd(sec, tmsg, pid);
			cli_stats_msg__free_unpacked(tmsg, &pa);
			return ret;
		}
		break;

	case CMD_SEC_AUTH_INIT:{
			SecAuthInitMsg *auth_init;

			auth_init =
			    sec_auth_init_msg__unpack(&pa, data.size,
						      data.data);
			if (auth_init == NULL) {
				seclog(sec, LOG_INFO, "error unpacking auth init\n");
				return -1;
			}

			ret = handle_sec_auth_init(cfd, sec, auth_init, pid);
			sec_auth_init_msg__free_unpacked(auth_init, &pa);
			return ret;
		}
	case CMD_SEC_AUTH_CONT:{
			SecAuthContMsg *auth_cont;

			auth_cont =
			    sec_auth_cont_msg__unpack(&pa, data.size,
						      data.data);
			if (auth_cont == NULL) {
				seclog(sec, LOG_INFO, "error unpacking auth cont\n");
				return -1;
			}

			ret = handle_sec_auth_cont(cfd, sec, auth_cont);
			sec_auth_cont_msg__free_unpacked(auth_cont, &pa);
			return ret;
		}
	case RESUME_STORE_REQ:{
			SessionResumeStoreReqMsg *smsg;

			smsg =
			    session_resume_store_req_msg__unpack(&pa, buffer_size,
								 buffer);
			if (smsg == NULL) {
				seclog(sec, LOG_ERR, "error unpacking data");
				return ERR_BAD_COMMAND;
			}

			ret = handle_resume_store_req(sec, smsg);

			/* zeroize the data */
			safe_memset(buffer, 0, buffer_size);
			safe_memset(smsg->session_data.data, 0, smsg->session_data.len);

			session_resume_store_req_msg__free_unpacked(smsg, &pa);

			if (ret < 0) {
				seclog(sec, LOG_DEBUG,
				      "could not store resumption data");
			}
		}

		break;

	case RESUME_DELETE_REQ:{
			SessionResumeFetchMsg *fmsg;

			fmsg =
			    session_resume_fetch_msg__unpack(&pa, buffer_size,
							     buffer);
			if (fmsg == NULL) {
				seclog(sec, LOG_ERR, "error unpacking data");
				return ERR_BAD_COMMAND;
			}

			ret = handle_resume_delete_req(sec, fmsg);

			session_resume_fetch_msg__free_unpacked(fmsg, &pa);

			if (ret < 0) {
				seclog(sec, LOG_DEBUG,
				      "could not delete resumption data.");
			}
		}

		break;
	case RESUME_FETCH_REQ:{
			SessionResumeReplyMsg msg =
			    SESSION_RESUME_REPLY_MSG__INIT;
			SessionResumeFetchMsg *fmsg;

			/* FIXME: rate limit that */

			fmsg =
			    session_resume_fetch_msg__unpack(&pa, buffer_size,
							     buffer);
			if (fmsg == NULL) {
				seclog(sec, LOG_ERR, "error unpacking data");
				return ERR_BAD_COMMAND;
			}

			ret = handle_resume_fetch_req(sec, fmsg, &msg);

			session_resume_fetch_msg__free_unpacked(fmsg, &pa);

			if (ret < 0) {
				msg.reply =
				    SESSION_RESUME_REPLY_MSG__RESUME__REP__FAILED;
				seclog(sec, LOG_DEBUG,
				      "could not fetch resumption data.");
			} else {
				msg.reply =
				    SESSION_RESUME_REPLY_MSG__RESUME__REP__OK;
			}

			ret =
			    send_msg(pool, cfd, RESUME_FETCH_REP, &msg,
					       (pack_size_func)
					       session_resume_reply_msg__get_packed_size,
					       (pack_func)
					       session_resume_reply_msg__pack);

			if (ret < 0) {
				seclog(sec, LOG_ERR,
				      "could not send reply cmd %d.",
				      (unsigned)cmd);
				return ERR_BAD_COMMAND;
			}

		}

		break;

	default:
		seclog(sec, LOG_WARNING, "unknown type 0x%.2x", cmd);
		return -1;
	}

	return 0;
}
Ejemplo n.º 20
0
static
int handle_sec_auth_session_close(sec_mod_st *sec, int fd, const SecAuthSessionMsg *req)
{
	client_entry_st *e;
	int ret;
	CliStatsMsg rep = CLI_STATS_MSG__INIT;

	if (req->sid.len != SID_SIZE) {
		seclog(sec, LOG_ERR, "auth session close but with illegal sid size (%d)!",
		       (int)req->sid.len);
		return ERR_BAD_COMMAND;
	}

	e = find_client_entry(sec, req->sid.data);
	if (e == NULL) {
		char tmp[BASE64_LENGTH(SID_SIZE) + 1];
		base64_encode((char *)req->sid.data, req->sid.len, (char *)tmp, sizeof(tmp));
		seclog(sec, LOG_INFO, "session close but with non-existing SID: %s", tmp);
		return send_msg(e, fd, SM_CMD_AUTH_CLI_STATS, &rep,
		                (pack_size_func) cli_stats_msg__get_packed_size,
		                (pack_func) cli_stats_msg__pack);
	}

	if (e->status < PS_AUTH_COMPLETED) {
		seclog(sec, LOG_DEBUG, "session close received in unauthenticated client %s "SESSION_STR"!", e->auth_info.username, e->auth_info.psid);
		return send_msg(e, fd, SM_CMD_AUTH_CLI_STATS, &rep,
		                (pack_size_func) cli_stats_msg__get_packed_size,
		                (pack_func) cli_stats_msg__pack);
	}


	if (req->has_uptime && req->uptime > e->stats.uptime) {
			e->stats.uptime = req->uptime;
	}
	if (req->has_bytes_in && req->bytes_in > e->stats.bytes_in) {
			e->stats.bytes_in = req->bytes_in;
	}
	if (req->has_bytes_out && req->bytes_out > e->stats.bytes_out) {
			e->stats.bytes_out = req->bytes_out;
	}

	/* send reply */
	rep.bytes_in = e->stats.bytes_in;
	rep.bytes_out = e->stats.bytes_out;
	rep.has_secmod_client_entries = 1;
	rep.secmod_client_entries = sec_mod_client_db_elems(sec);

	ret = send_msg(e, fd, SM_CMD_AUTH_CLI_STATS, &rep,
			(pack_size_func) cli_stats_msg__get_packed_size,
			(pack_func) cli_stats_msg__pack);
	if (ret < 0) {
		seclog(sec, LOG_ERR, "error in sending session stats");
		return ERR_BAD_COMMAND;
	}

	/* save total stats */
	stats_add_to(&e->saved_stats, &e->saved_stats, &e->stats);
	memset(&e->stats, 0, sizeof(e->stats));
	expire_client_entry(sec, e);

	return 0;
}
Ejemplo n.º 21
0
static
int handle_sec_auth_session_open(sec_mod_st *sec, int fd, const SecAuthSessionMsg *req)
{
	client_entry_st *e;
	void *lpool;
	int ret;
	SecAuthSessionReplyMsg rep = SEC_AUTH_SESSION_REPLY_MSG__INIT;

	if (req->sid.len != SID_SIZE) {
		seclog(sec, LOG_ERR, "auth session open but with illegal sid size (%d)!",
		       (int)req->sid.len);
		return send_failed_session_open_reply(sec, fd);
	}

	e = find_client_entry(sec, req->sid.data);
	if (e == NULL) {
		char tmp[BASE64_LENGTH(SID_SIZE) + 1];
		base64_encode((char *)req->sid.data, req->sid.len, (char *)tmp, sizeof(tmp));
		seclog(sec, LOG_INFO, "session open but with non-existing SID: %s!", tmp);
		return send_failed_session_open_reply(sec, fd);
	}

	if (e->status != PS_AUTH_COMPLETED) {
		seclog(sec, LOG_ERR, "session open received in unauthenticated client %s "SESSION_STR"!", e->auth_info.username, e->auth_info.psid);
		return send_failed_session_open_reply(sec, fd);
	}

	if (e->time != -1 && time(0) > e->time + sec->config->cookie_timeout) {
		seclog(sec, LOG_ERR, "session expired; denied session for user '%s' "SESSION_STR, e->auth_info.username, e->auth_info.psid);
		e->status = PS_AUTH_FAILED;
		return send_failed_session_open_reply(sec, fd);
	}

	if (req->has_cookie == 0 || (req->cookie.len != e->cookie_size) ||
	    memcmp(req->cookie.data, e->cookie, e->cookie_size) != 0) {
		seclog(sec, LOG_ERR, "cookie error; denied session for user '%s' "SESSION_STR, e->auth_info.username, e->auth_info.psid);
		e->status = PS_AUTH_FAILED;
		return send_failed_session_open_reply(sec, fd);
	}

	if (req->ipv4)
		strlcpy(e->auth_info.ipv4, req->ipv4, sizeof(e->auth_info.ipv4));
	if (req->ipv6)
		strlcpy(e->auth_info.ipv6, req->ipv6, sizeof(e->auth_info.ipv6));

	if (sec->perm_config->acct.amod != NULL && sec->perm_config->acct.amod->open_session != NULL && e->session_is_open == 0) {
		ret = sec->perm_config->acct.amod->open_session(e->auth_type, e->auth_ctx, &e->auth_info, req->sid.data, req->sid.len);
		if (ret < 0) {
			e->status = PS_AUTH_FAILED;
			seclog(sec, LOG_INFO, "denied session for user '%s' "SESSION_STR, e->auth_info.username, e->auth_info.psid);
			return send_failed_session_open_reply(sec, fd);
		} else {
			e->session_is_open = 1;
		}
	}

	rep.reply = AUTH__REP__OK;

	lpool = talloc_new(e);
	if (lpool == NULL) {
		return ERR_BAD_COMMAND; /* we desync */
	}

	if (sec->config_module && sec->config_module->get_sup_config) {
		ret = sec->config_module->get_sup_config(sec->config, e, &rep, lpool);
		if (ret < 0) {
			seclog(sec, LOG_ERR, "error reading additional configuration for '%s' "SESSION_STR, e->auth_info.username, e->auth_info.psid);
			talloc_free(lpool);
			return send_failed_session_open_reply(sec, fd);
		}
	}

	ret = send_msg(lpool, fd, SM_CMD_AUTH_SESSION_REPLY, &rep,
			(pack_size_func) sec_auth_session_reply_msg__get_packed_size,
			(pack_func) sec_auth_session_reply_msg__pack);
	if (ret < 0) {
		seclog(sec, LOG_ERR, "error in sending session reply");
		return ERR_BAD_COMMAND; /* we desync */
	}
	talloc_free(lpool);

	seclog(sec, LOG_INFO, "initiating session for user '%s' "SESSION_STR, e->auth_info.username, e->auth_info.psid);
	e->time = -1;
	e->in_use++;

	return 0;
}
Ejemplo n.º 22
0
static
int process_packet_from_main(void *pool, int fd, sec_mod_st * sec, cmd_request_t cmd,
		   uint8_t * buffer, size_t buffer_size)
{
	gnutls_datum_t data;
	int ret;
	PROTOBUF_ALLOCATOR(pa, pool);

	seclog(sec, LOG_DEBUG, "cmd [size=%d] %s\n", (int)buffer_size,
	       cmd_request_to_str(cmd));
	data.data = buffer;
	data.size = buffer_size;

	switch (cmd) {
	case CMD_SECM_LIST_COOKIES:
		handle_secm_list_cookies_reply(pool, fd, sec);

		return 0;
	case CMD_SECM_BAN_IP_REPLY:{
		BanIpReplyMsg *msg = NULL;

		msg =
		    ban_ip_reply_msg__unpack(&pa, data.size,
					     data.data);
		if (msg == NULL) {
			seclog(sec, LOG_INFO, "error unpacking auth ban ip reply\n");
			return ERR_BAD_COMMAND;
		}

		handle_sec_auth_ban_ip_reply(sec, msg);
		ban_ip_reply_msg__free_unpacked(msg, &pa);

		return 0;
	}
	case CMD_SECM_SESSION_OPEN:{
			SecmSessionOpenMsg *msg;

			msg =
			    secm_session_open_msg__unpack(&pa, data.size,
						      data.data);
			if (msg == NULL) {
				seclog(sec, LOG_INFO, "error unpacking session open\n");
				return ERR_BAD_COMMAND;
			}

			ret = handle_secm_session_open_cmd(sec, fd, msg);
			secm_session_open_msg__free_unpacked(msg, &pa);

			return ret;
		}
	case CMD_SECM_SESSION_CLOSE:{
			SecmSessionCloseMsg *msg;

			msg =
			    secm_session_close_msg__unpack(&pa, data.size,
						      data.data);
			if (msg == NULL) {
				seclog(sec, LOG_INFO, "error unpacking session close\n");
				return ERR_BAD_COMMAND;
			}

			ret = handle_secm_session_close_cmd(sec, fd, msg);
			secm_session_close_msg__free_unpacked(msg, &pa);

			return ret;
		}
	default:
		seclog(sec, LOG_WARNING, "unknown type 0x%.2x", cmd);
		return ERR_BAD_COMMAND;
	}

	return 0;
}
Ejemplo n.º 23
0
/* Performs the required steps based on the result from the 
 * authentication function (e.g. handle_auth_init).
 *
 * @cmd: the command received
 * @result: the auth result
 */
static
int handle_sec_auth_res(int cfd, sec_mod_st * sec, client_entry_st * e, int result)
{
	int ret;
	passwd_msg_st pst;

	if ((result == ERR_AUTH_CONTINUE || result == 0) && e->module) {
		memset(&pst, 0, sizeof(pst));
		ret = e->module->auth_msg(e->auth_ctx, e, &pst);
		if (ret < 0) {
			e->status = PS_AUTH_FAILED;
			seclog(sec, LOG_ERR, "error getting auth msg");
			return ret;
		}
		e->msg_str = pst.msg_str;
		e->passwd_counter = pst.counter;
	}

	if (result == ERR_AUTH_CONTINUE) {
		/* if the module allows multiple retries for the password */
		if (e->status != PS_AUTH_INIT && e->module && e->module->allows_retries) {
			sec_mod_add_score_to_ip(sec, e, e->auth_info.remote_ip, sec->config->ban_points_wrong_password);
		}

		ret = send_sec_auth_reply_msg(cfd, sec, e);
		if (ret < 0) {
			e->status = PS_AUTH_FAILED;
			seclog(sec, LOG_ERR, "could not send reply auth cmd.");
			return ret;
		}
		return 0;	/* wait for another command */
	} else if (result == 0 && e->status != PS_AUTH_FAILED) {
		/* we check status for PS_AUTH_FAILED, because status may
		 * change async if we receive a message from main that the
		 * user is banned */
		e->status = PS_AUTH_COMPLETED;

		if (e->module) {
			e->module->auth_user(e->auth_ctx, e->auth_info.username,
					     sizeof(e->auth_info.username));
		}

		ret = send_sec_auth_reply(cfd, sec, e, AUTH__REP__OK);
		if (ret < 0) {
			e->status = PS_AUTH_FAILED;
			seclog(sec, LOG_ERR, "could not send reply auth cmd.");
			return ret;
		}

		ret = 0;
	} else {
		e->status = PS_AUTH_FAILED;

		sec_mod_add_score_to_ip(sec, e, e->auth_info.remote_ip, sec->config->ban_points_wrong_password);

		ret = send_sec_auth_reply(cfd, sec, e, AUTH__REP__FAILED);
		if (ret < 0) {
			seclog(sec, LOG_ERR, "could not send reply auth cmd.");
			return ret;
		}

		if (result < 0) {
			ret = result;
		} else {
			seclog(sec, LOG_ERR, "unexpected auth result: %d\n", result);
			ret = ERR_BAD_COMMAND;
		}
	}

	return ret;
}
Ejemplo n.º 24
0
void handle_secm_list_cookies_reply(void *pool, int fd, sec_mod_st *sec)
{
	SecmListCookiesReplyMsg msg = SECM_LIST_COOKIES_REPLY_MSG__INIT;
	struct htable *db = sec->client_db;
	client_entry_st *t;
	struct htable_iter iter;
	CookieIntMsg *cookies;
	int ret;
	time_t now = time(0);

	if (db == NULL) {
		send_empty_reply(pool, fd, sec);
		return;
	}

	seclog(sec, LOG_DEBUG, "sending list cookies reply to main");

	msg.cookies = talloc_size(pool, sizeof(CookieIntMsg*)*db->elems);
	if (msg.cookies == NULL) {
		send_empty_reply(pool, fd, sec);
		return;
	}

	cookies = talloc_size(pool, sizeof(CookieIntMsg)*db->elems);
	if (cookies == NULL) {
		send_empty_reply(pool, fd, sec);
		return;
	}

	t = htable_first(db, &iter);
	while (t != NULL) {
		if IS_CLIENT_ENTRY_EXPIRED(sec, t, now)
			goto cont;

		if (msg.n_cookies >= db->elems)
			break;

		cookie_int_msg__init(&cookies[msg.n_cookies]);
		cookies[msg.n_cookies].safe_id.data = (void*)t->acct_info.safe_id;
		cookies[msg.n_cookies].safe_id.len = sizeof(t->acct_info.safe_id);

		cookies[msg.n_cookies].session_is_open = t->session_is_open;
		cookies[msg.n_cookies].tls_auth_ok = t->tls_auth_ok;

		if (t->created > 0)
			cookies[msg.n_cookies].created = t->created;
		else
			cookies[msg.n_cookies].created = 0;

		/* a session which is in use, does not expire */
		if (t->exptime > 0 && t->in_use == 0)
			cookies[msg.n_cookies].expires = t->exptime;
		else
			cookies[msg.n_cookies].expires = 0;
		cookies[msg.n_cookies].username = t->acct_info.username;
		cookies[msg.n_cookies].groupname = t->acct_info.groupname;
		cookies[msg.n_cookies].user_agent = t->acct_info.user_agent;
		cookies[msg.n_cookies].remote_ip = t->acct_info.remote_ip;
		cookies[msg.n_cookies].status = t->status;
		cookies[msg.n_cookies].in_use = t->in_use;
		cookies[msg.n_cookies].vhost = VHOSTNAME(t->vhost);

		msg.cookies[msg.n_cookies] = &cookies[msg.n_cookies];
		msg.n_cookies++;

 cont:
		t = htable_next(db, &iter);
	}

	ret = send_msg(pool, fd, CMD_SECM_LIST_COOKIES_REPLY, &msg,
		(pack_size_func) secm_list_cookies_reply_msg__get_packed_size,
		(pack_func) secm_list_cookies_reply_msg__pack);
	if (ret < 0) {
		seclog(sec, LOG_ERR, "Error sending show cookies reply to main");
	}

	talloc_free(msg.cookies);
	talloc_free(cookies);
}
Ejemplo n.º 25
0
static int load_keys(sec_mod_st *sec, unsigned force)
{
	unsigned i, need_reload = 0;
	int ret;
	struct pin_st pins;
	static time_t last_access = 0;

	for (i = 0; i < sec->perm_config->key_size; i++) {
		if (need_file_reload(sec->perm_config->key[i], last_access) != 0) {
			need_reload = 1;
			break;
		}
	}

	if (need_reload == 0)
		return 0;

	last_access = time(0);

	ret = load_pins(sec->perm_config, &pins);
	if (ret < 0) {
		seclog(sec, LOG_ERR, "error loading PIN files");
		exit(1);
	}

	/* Reminder: the number of private keys or their filenames cannot be changed on reload
	 */
	if (sec->key == NULL) {
		sec->key_size = sec->perm_config->key_size;
		sec->key = talloc_zero_size(sec, sizeof(*sec->key) * sec->perm_config->key_size);
		if (sec->key == NULL) {
			seclog(sec, LOG_ERR, "error in memory allocation");
			exit(1);
		}
	}

	/* read private keys */
	for (i = 0; i < sec->key_size; i++) {
		gnutls_privkey_t p;

		ret = gnutls_privkey_init(&p);
		CHECK_LOOP_ERR(ret);
		/* load the private key */
		if (gnutls_url_is_supported(sec->perm_config->key[i]) != 0) {
			gnutls_privkey_set_pin_function(p,
							pin_callback, &pins);
			ret =
			    gnutls_privkey_import_url(p,
						      sec->perm_config->key[i], 0);
			CHECK_LOOP_ERR(ret);
		} else {
			gnutls_datum_t data;
			ret = gnutls_load_file(sec->perm_config->key[i], &data);
			if (ret < 0) {
				seclog(sec, LOG_ERR, "error loading file '%s'",
				       sec->perm_config->key[i]);
				CHECK_LOOP_ERR(ret);
			}

			ret =
			    gnutls_privkey_import_x509_raw(p, &data,
							   GNUTLS_X509_FMT_PEM,
							   NULL, 0);
			if (ret == GNUTLS_E_DECRYPTION_FAILED && pins.pin[0]) {
				ret =
				    gnutls_privkey_import_x509_raw(p, &data,
								   GNUTLS_X509_FMT_PEM,
								   pins.pin, 0);
			}
			CHECK_LOOP_ERR(ret);

			gnutls_free(data.data);
		}

		if (sec->key[i] != NULL) {
			gnutls_privkey_deinit(sec->key[i]);
		}
		sec->key[i] = p;
	}

	return 0;
}
Ejemplo n.º 26
0
/* sec_mod_server:
 * @config: server configuration
 * @socket_file: the name of the socket
 * @cmd_fd: socket to exchange commands with main
 * @cmd_fd_sync: socket to received sync commands from main
 *
 * This is the main part of the security module.
 * It creates the unix domain socket identified by @socket_file
 * and then accepts connections from the workers to it. Then 
 * it serves commands requested on the server's private key.
 *
 * When the operation is decrypt the provided data are
 * decrypted and sent back to worker. The sign operation
 * signs the provided data.
 *
 * The security module's reply to the worker has the
 * following format:
 * byte[0-5]: length (uint32_t)
 * byte[5-total]: data (signature or decrypted data)
 *
 * The reason for having this as a separate process
 * is to avoid any bug on the workers to leak the key.
 * It is not part of main because workers are spawned
 * from main, and thus should be prevented from accessing
 * parts the key in stack or heap that was not zeroized.
 * Other than that it allows the main server to spawn
 * clients fast without becoming a bottleneck due to private 
 * key operations.
 */
void sec_mod_server(void *main_pool, struct perm_cfg_st *perm_config, const char *socket_file,
		    int cmd_fd, int cmd_fd_sync)
{
	struct sockaddr_un sa;
	socklen_t sa_len;
	int cfd, ret, e, n;
	unsigned buffer_size;
	uid_t uid;
	uint8_t *buffer;
	int sd;
	sec_mod_st *sec;
	void *sec_mod_pool;
	fd_set rd_set;
	pid_t pid;
#ifdef HAVE_PSELECT
	struct timespec ts;
#else
	struct timeval ts;
#endif
	sigset_t emptyset, blockset;

#ifdef DEBUG_LEAKS
	talloc_enable_leak_report_full();
#endif
	sigemptyset(&blockset);
	sigemptyset(&emptyset);
	sigaddset(&blockset, SIGALRM);
	sigaddset(&blockset, SIGTERM);
	sigaddset(&blockset, SIGINT);
	sigaddset(&blockset, SIGHUP);

	sec_mod_pool = talloc_init("sec-mod");
	if (sec_mod_pool == NULL) {
		seclog(sec, LOG_ERR, "error in memory allocation");
		exit(1);
	}

	sec = talloc_zero(sec_mod_pool, sec_mod_st);
	if (sec == NULL) {
		seclog(sec, LOG_ERR, "error in memory allocation");
		exit(1);
	}

	sec->perm_config = talloc_steal(sec, perm_config);
	sec->config = sec->perm_config->config;

	tls_cache_init(sec, &sec->tls_db);
	sup_config_init(sec);

	memset(&sa, 0, sizeof(sa));
	sa.sun_family = AF_UNIX;
	strlcpy(sa.sun_path, socket_file, sizeof(sa.sun_path));
	remove(socket_file);

#define SOCKET_FILE sa.sun_path

	/* we no longer need the main pool after this point. */
	talloc_free(main_pool);

	ocsignal(SIGHUP, handle_sighup);
	ocsignal(SIGINT, handle_sigterm);
	ocsignal(SIGTERM, handle_sigterm);
	ocsignal(SIGALRM, handle_alarm);

	sec_auth_init(sec, perm_config);
	sec->cmd_fd = cmd_fd;
	sec->cmd_fd_sync = cmd_fd_sync;

#ifdef HAVE_PKCS11
	ret = gnutls_pkcs11_reinit();
	if (ret < 0) {
		seclog(sec, LOG_WARNING, "error in PKCS #11 reinitialization: %s",
		       gnutls_strerror(ret));
	}
#endif

	if (sec_mod_client_db_init(sec) == NULL) {
		seclog(sec, LOG_ERR, "error in client db initialization");
		exit(1);
	}

	sd = socket(AF_UNIX, SOCK_STREAM, 0);
	if (sd == -1) {
		e = errno;
		seclog(sec, LOG_ERR, "could not create socket '%s': %s", SOCKET_FILE,
		       strerror(e));
		exit(1);
	}
	set_cloexec_flag(sd, 1);

	umask(066);
	ret = bind(sd, (struct sockaddr *)&sa, SUN_LEN(&sa));
	if (ret == -1) {
		e = errno;
		seclog(sec, LOG_ERR, "could not bind socket '%s': %s", SOCKET_FILE,
		       strerror(e));
		exit(1);
	}

	ret = chown(SOCKET_FILE, perm_config->uid, perm_config->gid);
	if (ret == -1) {
		e = errno;
		seclog(sec, LOG_INFO, "could not chown socket '%s': %s", SOCKET_FILE,
		       strerror(e));
	}

	ret = listen(sd, 1024);
	if (ret == -1) {
		e = errno;
		seclog(sec, LOG_ERR, "could not listen to socket '%s': %s",
		       SOCKET_FILE, strerror(e));
		exit(1);
	}

	ret = load_keys(sec, 1);
	if (ret < 0) {
		seclog(sec, LOG_ERR, "error loading private key files");
		exit(1);
	}

	sigprocmask(SIG_BLOCK, &blockset, &sig_default_set);
	alarm(MAINTAINANCE_TIME);
	seclog(sec, LOG_INFO, "sec-mod initialized (socket: %s)", SOCKET_FILE);


	for (;;) {
		check_other_work(sec);

		FD_ZERO(&rd_set);
		n = 0;

		FD_SET(cmd_fd, &rd_set);
		n = MAX(n, cmd_fd);

		FD_SET(cmd_fd_sync, &rd_set);
		n = MAX(n, cmd_fd_sync);

		FD_SET(sd, &rd_set);
		n = MAX(n, sd);

#ifdef HAVE_PSELECT
		ts.tv_nsec = 0;
		ts.tv_sec = 120;
		ret = pselect(n + 1, &rd_set, NULL, NULL, &ts, &emptyset);
#else
		ts.tv_usec = 0;
		ts.tv_sec = 120;
		sigprocmask(SIG_UNBLOCK, &blockset, NULL);
		ret = select(n + 1, &rd_set, NULL, NULL, &ts);
		sigprocmask(SIG_BLOCK, &blockset, NULL);
#endif
		if (ret == 0 || (ret == -1 && errno == EINTR))
			continue;

		if (ret < 0) {
			e = errno;
			seclog(sec, LOG_ERR, "Error in pselect(): %s",
			       strerror(e));
			exit(1);
		}

		/* we do a new allocation, to also use it as pool for the
		 * parsers to use */
		buffer_size = MAX_MSG_SIZE;
		buffer = talloc_size(sec, buffer_size);
		if (buffer == NULL) {
			seclog(sec, LOG_ERR, "error in memory allocation");
			exit(1);
		}

		/* we use two fds for communication with main. The synchronous is for
		 * ping-pong communication which each request is answered immediated. The
		 * async is for messages sent back and forth in no particular order */
		if (FD_ISSET(cmd_fd_sync, &rd_set)) {
			ret = serve_request_main(sec, cmd_fd_sync, buffer, buffer_size);
			if (ret < 0 && ret == ERR_BAD_COMMAND) {
				seclog(sec, LOG_ERR, "error processing sync command from main");
				exit(1);
			}
		}

		if (FD_ISSET(cmd_fd, &rd_set)) {
			ret = serve_request_main(sec, cmd_fd, buffer, buffer_size);
			if (ret < 0 && ret == ERR_BAD_COMMAND) {
				seclog(sec, LOG_ERR, "error processing async command from main");
				exit(1);
			}
		}
		
		if (FD_ISSET(sd, &rd_set)) {
			sa_len = sizeof(sa);
			cfd = accept(sd, (struct sockaddr *)&sa, &sa_len);
			if (cfd == -1) {
				e = errno;
				if (e != EINTR) {
					seclog(sec, LOG_DEBUG,
					       "sec-mod error accepting connection: %s",
					       strerror(e));
					goto cont;
				}
			}
			set_cloexec_flag (cfd, 1);

			/* do not allow unauthorized processes to issue commands
			 */
			ret = check_upeer_id("sec-mod", sec->perm_config->debug, cfd, perm_config->uid, perm_config->gid, &uid, &pid);
			if (ret < 0) {
				seclog(sec, LOG_INFO, "rejected unauthorized connection");
			} else {
				memset(buffer, 0, buffer_size);
				serve_request_worker(sec, cfd, pid, buffer, buffer_size);
			}
			close(cfd);
		}
 cont:
		talloc_free(buffer);
#ifdef DEBUG_LEAKS
		talloc_report_full(sec, stderr);
#endif
	}
}