Beispiel #1
0
static bool pid_file_read(const char *path)
{
	char buf[32];
	int fd;
	ssize_t ret;
	pid_t pid;
	bool found = FALSE;

	fd = open(path, O_RDONLY);
	if (fd == -1) {
		if (errno != ENOENT)
			i_error("open(%s) failed: %m", path);
		return FALSE;
	}

	ret = read(fd, buf, sizeof(buf));
	if (ret < 0)
		i_error("read(%s) failed: %m", path);
	else if (ret > 0 && buf[ret-1] == '\n') {
		buf[ret-1] = '\0';
		if (str_to_pid(buf, &pid) == 0) {
			found = !(pid == getpid() ||
				  (kill(pid, 0) < 0 && errno == ESRCH));
		}
	}
	i_close_fd(&fd);
	return found;
}
Beispiel #2
0
int mail_session_connect_parse(const char *const *args, const char **error_r)
{
	struct mail_session *session;
	const char *session_id;
	pid_t pid;
	struct ip_addr ip;
	unsigned int i;

	/* <session id> <username> <service> <pid> [key=value ..] */
	if (str_array_length(args) < 4) {
		*error_r = "CONNECT: Too few parameters";
		return -1;
	}
	session_id = args[0];
	if (str_to_pid(args[3], &pid) < 0) {
		*error_r = t_strdup_printf("CONNECT: Invalid pid %s for session ID %s",
					   args[3], session_id);
		return -1;
	}

	session = hash_table_lookup(mail_sessions_hash, session_id);
	if (session != NULL) {
		*error_r = t_strdup_printf(
			"CONNECT: Duplicate session ID %s for user %s service %s",
			session_id, args[1], args[2]);
		return -1;
	}
	session = i_malloc(sizeof(struct mail_session) + stats_alloc_size());
	session->stats = (void *)(session + 1);
	session->refcount = 1; /* unrefed at disconnect */
	session->id = i_strdup(session_id);
	session->service = str_table_ref(services, args[2]);
	session->pid = pid;
	session->last_update = ioloop_timeval;
	session->to_idle = timeout_add(MAIL_SESSION_IDLE_TIMEOUT_MSECS,
				       mail_session_idle_timeout, session);

	session->user = mail_user_login(args[1]);
	for (i = 3; args[i] != NULL; i++) {
		if (strncmp(args[i], "rip=", 4) == 0 &&
		    net_addr2ip(args[i] + 4, &ip) == 0)
			session->ip = mail_ip_login(&ip);
	}

	hash_table_insert(mail_sessions_hash, session->id, session);
	DLLIST_PREPEND_FULL(&stable_mail_sessions, session,
			    stable_prev, stable_next);
	DLLIST2_APPEND_FULL(&mail_sessions_head, &mail_sessions_tail, session,
			    sorted_prev, sorted_next);
	DLLIST_PREPEND_FULL(&session->user->sessions, session,
			    user_prev, user_next);
	mail_user_ref(session->user);
	if (session->ip != NULL) {
		DLLIST_PREPEND_FULL(&session->ip->sessions, session,
				    ip_prev, ip_next);
		mail_ip_ref(session->ip);
	}
	global_memory_alloc(mail_session_memsize(session));
	return 0;
}
Beispiel #3
0
static bool pid_file_read(const char *path, pid_t *pid_r)
{
	char buf[32];
	int fd;
	ssize_t ret;
	bool found;

	fd = open(path, O_RDONLY);
	if (fd == -1) {
		if (errno == ENOENT)
			return FALSE;
		i_fatal("open(%s) failed: %m", path);
	}

	ret = read(fd, buf, sizeof(buf)-1);
	if (ret <= 0) {
		if (ret == 0)
			i_error("Empty PID file in %s", path);
		else
			i_fatal("read(%s) failed: %m", path);
		found = FALSE;
	} else {
		if (buf[ret-1] == '\n')
			ret--;
		buf[ret] = '\0';
		if (str_to_pid(buf, pid_r) < 0)
			found = FALSE;
		else {
			found = !(*pid_r == getpid() ||
				  (kill(*pid_r, 0) < 0 && errno == ESRCH));
		}
	}
	i_close_fd(&fd);
	return found;
}
Beispiel #4
0
static const char *
file_lock_find_proc_locks(int lock_fd ATTR_UNUSED)
{
	/* do anything except Linux support this? don't bother trying it for
	   OSes we don't know about. */
#ifdef __linux__
	static bool have_proc_locks = TRUE;
	struct stat st;
	char node_buf[MAX_INT_STRLEN*3 + 2 + 1];
	struct istream *input;
	const char *line, *lock_type = "";
	pid_t pid = 0;
	int fd;

	if (!have_proc_locks)
		return FALSE;

	if (fstat(lock_fd, &st) < 0)
		return "";
	i_snprintf(node_buf, sizeof(node_buf), "%02x:%02x:%llu",
		   major(st.st_dev), minor(st.st_dev),
		   (unsigned long long)st.st_ino);
	fd = open("/proc/locks", O_RDONLY);
	if (fd == -1) {
		have_proc_locks = FALSE;
		return "";
	}
	input = i_stream_create_fd_autoclose(&fd, 512);
	while (pid == 0 && (line = i_stream_read_next_line(input)) != NULL) T_BEGIN {
		const char *const *args = t_strsplit_spaces(line, " ");

		/* number: FLOCK/POSIX ADVISORY READ/WRITE pid
		   major:minor:inode region-start region-end */
		if (str_array_length(args) < 8)
			continue;
		if (strcmp(args[5], node_buf) == 0) {
			lock_type = strcmp(args[3], "READ") == 0 ?
				"READ" : "WRITE";
			if (str_to_pid(args[4], &pid) < 0)
				pid = 0;
		}
	} T_END;
	i_stream_destroy(&input);
	if (pid == 0) {
		/* not found */
		return "";
	}
	if (pid == getpid())
		return " (BUG: lock is held by our own process)";
	return t_strdup_printf(" (%s lock held by pid %ld)", lock_type, (long)pid);
#else
	return "";
#endif
}
static void master_login_auth_input(struct master_login_auth *auth)
{
	const char *line;
	bool ret;

	switch (i_stream_read(auth->input)) {
	case 0:
		return;
	case -1:
		/* disconnected. stop accepting new connections, because in
		   default configuration we no longer have permissions to
		   connect back to auth-master */
		master_service_stop_new_connections(master_service);
		master_login_auth_disconnect(auth);
		return;
	case -2:
		/* buffer full */
		i_error("Auth server sent us too long line");
		master_login_auth_disconnect(auth);
		return;
	}

	if (!auth->version_received) {
		line = i_stream_next_line(auth->input);
		if (line == NULL)
			return;

		/* make sure the major version matches */
		if (strncmp(line, "VERSION\t", 8) != 0 ||
		    !str_uint_equals(t_strcut(line + 8, '\t'),
				     AUTH_MASTER_PROTOCOL_MAJOR_VERSION)) {
			i_error("Authentication server not compatible with "
				"master process (mixed old and new binaries?)");
			master_login_auth_disconnect(auth);
			return;
		}
		auth->version_received = TRUE;
	}
	if (!auth->spid_received) {
		line = i_stream_next_line(auth->input);
		if (line == NULL)
			return;

		if (strncmp(line, "SPID\t", 5) != 0 ||
		    str_to_pid(line + 5, &auth->auth_server_pid) < 0) {
			i_error("Authentication server didn't "
				"send valid SPID as expected: %s", line);
			master_login_auth_disconnect(auth);
			return;
		}
		auth->spid_received = TRUE;
		master_login_auth_check_spids(auth);
	}

	auth->refcount++;
	while ((line = i_stream_next_line(auth->input)) != NULL) {
		if (strncmp(line, "USER\t", 5) == 0)
			ret = master_login_auth_input_user(auth, line + 5);
		else if (strncmp(line, "NOTFOUND\t", 9) == 0)
			ret = master_login_auth_input_notfound(auth, line + 9);
		else if (strncmp(line, "FAIL\t", 5) == 0)
			ret = master_login_auth_input_fail(auth, line + 5);
		else
			ret = TRUE;

		if (!ret || auth->input == NULL) {
			master_login_auth_disconnect(auth);
			break;
		}
	}
	master_login_auth_unref(&auth);
}
int mail_session_connect_parse(const char *const *args, const char **error_r)
{
	struct mail_session *session;
	guid_128_t session_guid;
	uint8_t *guid_p;
	pid_t pid;
	struct ip_addr ip;
	unsigned int i;

	/* <session guid> <username> <service> <pid> [key=value ..] */
	if (str_array_length(args) < 4) {
		*error_r = "CONNECT: Too few parameters";
		return -1;
	}
	if (guid_128_from_string(args[0], session_guid) < 0) {
		*error_r = "CONNECT: Invalid GUID";
		return -1;
	}
	if (str_to_pid(args[3], &pid) < 0) {
		*error_r = "CONNECT: Invalid pid";
		return -1;
	}

	guid_p = session_guid;
	session = hash_table_lookup(mail_sessions_hash, guid_p);
	if (session != NULL) {
		*error_r = "CONNECT: Duplicate session GUID";
		return -1;
	}
	session = i_new(struct mail_session, 1);
	session->refcount = 1; /* unrefed at disconnect */
	session->service = i_strdup(args[2]);
	memcpy(session->guid, session_guid, sizeof(session->guid));
	session->pid = pid;
	session->last_update = ioloop_timeval;
	session->to_idle = timeout_add(MAIL_SESSION_IDLE_TIMEOUT_MSECS,
				       mail_session_idle_timeout, session);

	session->user = mail_user_login(args[1]);
	for (i = 3; args[i] != NULL; i++) {
		if (strncmp(args[i], "rip=", 4) == 0 &&
		    net_addr2ip(args[i] + 4, &ip) == 0)
			session->ip = mail_ip_login(&ip);
	}

	guid_p = session->guid;
	hash_table_insert(mail_sessions_hash, guid_p, session);
	DLLIST_PREPEND_FULL(&stable_mail_sessions, session,
			    stable_prev, stable_next);
	DLLIST2_APPEND_FULL(&mail_sessions_head, &mail_sessions_tail, session,
			    sorted_prev, sorted_next);
	DLLIST_PREPEND_FULL(&session->user->sessions, session,
			    user_prev, user_next);
	mail_user_ref(session->user);
	if (session->ip != NULL) {
		DLLIST_PREPEND_FULL(&session->ip->sessions, session,
				    ip_prev, ip_next);
		mail_ip_ref(session->ip);
	}
	global_memory_alloc(mail_session_memsize(session));
	return 0;
}