소스 검색

Ensure Linux, BSD, Solaris, Darwin function with security authentication in
IPC system.


git-svn-id: http://svn.fedorahosted.org/svn/corosync/trunk@2259 fd59a12c-fef9-0310-b244-a6a79926bd2f

Steven Dake 16 년 전
부모
커밋
4620ca4e0b
3개의 변경된 파일78개의 추가작업 그리고 40개의 파일을 삭제
  1. 2 4
      configure.ac
  2. 68 32
      exec/coroipcs.c
  3. 8 4
      lib/coroipcc.c

+ 2 - 4
configure.ac

@@ -56,8 +56,6 @@ AC_CHECK_PROGS([PKGCONFIG], [pkg-config])
 # Checks for libraries.
 # Checks for libraries.
 AC_CHECK_LIB([dl], [dlopen])
 AC_CHECK_LIB([dl], [dlopen])
 AC_CHECK_LIB([pthread], [pthread_create])
 AC_CHECK_LIB([pthread], [pthread_create])
-AC_CHECK_LIB([c], [getpeereid])
-AC_CHECK_LIB([c], [getpeerucred])
 AC_CHECK_LIB([socket], [socket])
 AC_CHECK_LIB([socket], [socket])
 AC_CHECK_LIB([nsl], [t_open])
 AC_CHECK_LIB([nsl], [t_open])
 AC_CHECK_LIB([rt], [sched_getscheduler])
 AC_CHECK_LIB([rt], [sched_getscheduler])
@@ -103,8 +101,8 @@ AC_TYPE_SIGNAL
 AC_FUNC_STRFTIME
 AC_FUNC_STRFTIME
 AC_FUNC_VPRINTF
 AC_FUNC_VPRINTF
 AC_CHECK_FUNCS([alarm alphasort atexit bzero dup2 endgrent endpwent fcntl \
 AC_CHECK_FUNCS([alarm alphasort atexit bzero dup2 endgrent endpwent fcntl \
-		getcwd getpeerucred gettimeofday inet_ntoa memmove memset \
-		mkdir scandir select socket strcasecmp strchr strdup \
+		getcwd getpeerucred getpeereid gettimeofday inet_ntoa memmove \
+		memset mkdir scandir select socket strcasecmp strchr strdup \
 		strerror strrchr strspn strstr pthread_spin_lock \
 		strerror strrchr strspn strstr pthread_spin_lock \
 		pthread_spin_unlock])
 		pthread_spin_unlock])
 
 

+ 68 - 32
exec/coroipcs.c

@@ -50,6 +50,7 @@
 #include <sys/time.h>
 #include <sys/time.h>
 #include <sys/resource.h>
 #include <sys/resource.h>
 #include <sys/wait.h>
 #include <sys/wait.h>
+#include <sys/stat.h>
 #include <netinet/in.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <arpa/inet.h>
 #include <unistd.h>
 #include <unistd.h>
@@ -615,12 +616,14 @@ req_setup_recv (
 	int res;
 	int res;
 	struct msghdr msg_recv;
 	struct msghdr msg_recv;
 	struct iovec iov_recv;
 	struct iovec iov_recv;
+	int authenticated = 0;
+
 #ifdef COROSYNC_LINUX
 #ifdef COROSYNC_LINUX
 	struct cmsghdr *cmsg;
 	struct cmsghdr *cmsg;
 	char cmsg_cred[CMSG_SPACE (sizeof (struct ucred))];
 	char cmsg_cred[CMSG_SPACE (sizeof (struct ucred))];
-	struct ucred *cred;
 	int off = 0;
 	int off = 0;
 	int on = 1;
 	int on = 1;
+	struct ucred *cred;
 #endif
 #endif
 
 
 	msg_recv.msg_iov = &iov_recv;
 	msg_recv.msg_iov = &iov_recv;
@@ -631,34 +634,9 @@ req_setup_recv (
 	msg_recv.msg_control = (void *)cmsg_cred;
 	msg_recv.msg_control = (void *)cmsg_cred;
 	msg_recv.msg_controllen = sizeof (cmsg_cred);
 	msg_recv.msg_controllen = sizeof (cmsg_cred);
 #endif
 #endif
-
 #ifdef COROSYNC_SOLARIS
 #ifdef COROSYNC_SOLARIS
 	msg_recv.msg_accrights = 0;
 	msg_recv.msg_accrights = 0;
 	msg_recv.msg_accrightslen = 0;
 	msg_recv.msg_accrightslen = 0;
-#else /* COROSYNC_SOLARIS */
-
-#ifdef HAVE_GETPEERUCRED
-	ucred_t *uc;
-	uid_t euid = -1;
-	gid_t egid = -1;
-
-	if (getpeerucred (conn_info->fd, &uc) == 0) {
-		euid = ucred_geteuid (uc);
-		egid = ucred_getegid (uc);
-		if (api->security_valid (euid, egid) {
-			conn_info->authenticated = 1;
-		}
-		ucred_free(uc);
-	}
-	if (conn_info->authenticated == 0) {
-		api->log_printf ("Invalid security authentication\n");
- 	}
-#else /* HAVE_GETPEERUCRED */
- 	api->log_printf ("Connection not authenticated "
- 		"because platform does not support "
- 		"authentication with sockets, continuing "
- 		"with a fake authentication\n");
-#endif /* HAVE_GETPEERUCRED */
 #endif /* COROSYNC_SOLARIS */
 #endif /* COROSYNC_SOLARIS */
 
 
 	iov_recv.iov_base = &conn_info->setup_msg[conn_info->setup_bytes_read];
 	iov_recv.iov_base = &conn_info->setup_msg[conn_info->setup_bytes_read];
@@ -686,20 +664,70 @@ retry_recv:
 	}
 	}
 	conn_info->setup_bytes_read += res;
 	conn_info->setup_bytes_read += res;
 
 
-#ifdef COROSYNC_LINUX
+/*
+ * currently support getpeerucred, getpeereid, and SO_PASSCRED credential
+ * retrieval mechanisms for various Platforms
+ */
+#ifdef HAVE_GETPEERUCRED
+/*
+ * Solaris and some BSD systems
+ */
+	{
+		ucred_t *uc;
+		uid_t euid = -1;
+		gid_t egid = -1;
+
+		if (getpeerucred (conn_info->fd, &uc) == 0) {
+			euid = ucred_geteuid (uc);
+			egid = ucred_getegid (uc);
+			if (api->security_valid (euid, egid)) {
+				authenticated = 1;
+			}
+			ucred_free(uc);
+		}
+	}
+#elif HAVE_GETPEEREID
+/*
+ * Usually MacOSX systems
+ */
+
+	{
+		uid_t euid;
+		gid_t egid;
 
 
+		euid = -1;
+		egid = -1;
+		if (getpeereid (conn_info->fd, &euid, &egid) == 0) {
+			if (api->security_valid (euid, egid)) {
+				authenticated = 1;
+			}
+		}
+	}
+
+#elif SO_PASSCRED
+/*
+ * Usually Linux systems
+ */
 	cmsg = CMSG_FIRSTHDR (&msg_recv);
 	cmsg = CMSG_FIRSTHDR (&msg_recv);
 	assert (cmsg);
 	assert (cmsg);
 	cred = (struct ucred *)CMSG_DATA (cmsg);
 	cred = (struct ucred *)CMSG_DATA (cmsg);
 	if (cred) {
 	if (cred) {
 		if (api->security_valid (cred->uid, cred->gid)) {
 		if (api->security_valid (cred->uid, cred->gid)) {
-		} else {
-			ipc_disconnect (conn_info);
-			api->log_printf ("Invalid security authentication\n");
-			return (-1);
+			authenticated = 1;
 		}
 		}
 	}
 	}
-#endif
+
+#else /* no credentials */
+	authenticated = 1;
+ 	api->log_printf ("Platform does not support IPC authentication.  Using no authentication\n");
+#endif /* no credentials */
+
+	if (authenticated == 0) {
+		api->log_printf ("Invalid IPC credentials.\n");
+		ipc_disconnect (conn_info);
+		return (-1);
+ 	}
+
 	if (conn_info->setup_bytes_read == sizeof (mar_req_setup_t)) {
 	if (conn_info->setup_bytes_read == sizeof (mar_req_setup_t)) {
 #ifdef COROSYNC_LINUX
 #ifdef COROSYNC_LINUX
 		setsockopt(conn_info->fd, SOL_SOCKET, SO_PASSCRED,
 		setsockopt(conn_info->fd, SOL_SOCKET, SO_PASSCRED,
@@ -807,6 +835,14 @@ extern void coroipcs_ipc_init (
 		api->log_printf ("Could not bind AF_UNIX (%s): %s.\n", un_addr.sun_path, strerror (errno));
 		api->log_printf ("Could not bind AF_UNIX (%s): %s.\n", un_addr.sun_path, strerror (errno));
 		api->fatal_error ("Could not bind to AF_UNIX socket\n");
 		api->fatal_error ("Could not bind to AF_UNIX socket\n");
 	}
 	}
+
+	/*
+	 * Allow eveyrone to write to the socket since the IPC layer handles
+	 * security automatically
+	 */
+#if !defined(COROSYNC_LINUX)
+	res = chmod (un_addr.sun_path, S_IRWXU|S_IRWXG|S_IRWXO);
+#endif
 	listen (server_fd, SERVER_BACKLOG);
 	listen (server_fd, SERVER_BACKLOG);
 
 
         /*
         /*

+ 8 - 4
lib/coroipcc.c

@@ -561,9 +561,6 @@ coroipcc_service_connect (
 	sys_res = connect (request_fd, (struct sockaddr *)&address,
 	sys_res = connect (request_fd, (struct sockaddr *)&address,
 		COROSYNC_SUN_LEN(&address));
 		COROSYNC_SUN_LEN(&address));
 	if (sys_res == -1) {
 	if (sys_res == -1) {
-#ifdef DEBUG
-		fprintf(stderr, "Coroipcc: Can't connect: %d : %s\n", errno, strerror(errno));
-#endif
 		close (request_fd);
 		close (request_fd);
 		return (CS_ERR_TRY_AGAIN);
 		return (CS_ERR_TRY_AGAIN);
 	}
 	}
@@ -578,7 +575,14 @@ coroipcc_service_connect (
 		     = semget (semkey, 3, IPC_CREAT|IPC_EXCL|0600)) != -1) {
 		     = semget (semkey, 3, IPC_CREAT|IPC_EXCL|0600)) != -1) {
 		      break;
 		      break;
 		}
 		}
-		if (errno != EEXIST) {
+		/*
+		 * EACCESS can be returned as non root user when opening a different
+		 * users semaphore.
+		 *
+		 * EEXIST can happen when we are a root or nonroot user opening
+		 * an existing shared memory segment for which we have access
+		 */
+		if (errno != EEXIST && errno != EACCES) {
 			goto res_exit;
 			goto res_exit;
 		}
 		}
 	}
 	}