Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/gnome-keyring/ChangeLog,v
retrieving revision 1.198
diff -u -p -u -r1.198 ChangeLog
--- ChangeLog	23 Aug 2006 19:52:35 -0000	1.198
+++ ChangeLog	27 Aug 2006 16:03:37 -0000
@@ -1,3 +1,9 @@
+2006-08-27  Julio M. Merino Vidal  <jmmv@NetBSD.org>
+
+	* gnome-keyring.c, gnome-keyring-daemon.c, gnome-keyring-daemon-io.c:
+	Add support for LOCAL_CREDS socket credentials so that the keyring
+	works under NetBSD.
+
 2006-08-23  Dan Williams  <dcbw@redhat.com>
 
 	* gnome-keyring.c: (gnome_keyring_find_network_password_sync):
Index: gnome-keyring-daemon-io.c
===================================================================
RCS file: /cvs/gnome/gnome-keyring/gnome-keyring-daemon-io.c,v
retrieving revision 1.13
diff -u -p -u -r1.13 gnome-keyring-daemon-io.c
--- gnome-keyring-daemon-io.c	14 Apr 2006 13:20:37 -0000	1.13
+++ gnome-keyring-daemon-io.c	27 Aug 2006 16:03:37 -0000
@@ -47,6 +47,7 @@
 #endif
 
 typedef enum {
+	GNOME_CLIENT_STATE_INIT,
 	GNOME_CLIENT_STATE_CREDENTIALS,
 	GNOME_CLIENT_STATE_READ_DISPLAYNAME,
 	GNOME_CLIENT_STATE_READ_PACKET,
@@ -93,6 +94,38 @@ static void gnome_keyring_client_state_m
 
 
 static gboolean
+init_connection (int fd)
+{
+	char buf = '\0';
+        ssize_t len;
+
+#if defined(LOCAL_CREDS) && !defined(HAVE_CMSGCRED)
+	/* Set the socket to receive credentials on the next message,
+	 * which must be the nul-byte credentials message expected by
+	 * read_unix_socket_credentials().
+	 * CMSGCRED is preferred over LOCAL_CREDS because it provides
+	 * the remote PID. */
+	{
+		int on = 1;
+		if (setsockopt (fd, 0, LOCAL_CREDS, &on, sizeof (on)) < 0) {
+			g_warning ("Unable to set LOCAL_CREDS socket option\n");
+			return FALSE;
+		}
+	}
+#endif
+
+	len = write (fd, &buf, sizeof (buf));
+	if (len != sizeof (buf)) {
+		g_warning ("Failed to write initialization byte: %s",
+		           len == 0 ? "No data written" : strerror (errno));
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+
+static gboolean
 read_unix_socket_credentials (int fd,
 			      pid_t *pid,
 			      uid_t *uid)
@@ -101,27 +134,30 @@ read_unix_socket_credentials (int fd,
 	struct iovec iov;
 	char buf;
 	
-#ifdef HAVE_CMSGCRED 
+#if defined(HAVE_CMSGCRED) || defined(LOCAL_CREDS)
+	/* Prefer CMSGCRED over LOCAL_CREDS because the former provides the
+	 * remote PID. */
+#if defined(HAVE_CMSGCRED)
 	struct cmsgcred *cred;
+	const size_t cmsglen = CMSG_LEN (sizeof (struct cmsgcred));
+	const size_t cmsgspace = CMSG_SPACE (sizeof (struct cmsgcred));
+#else /* defined(LOCAL_CREDS) */
+	struct sockcred *cred;
+	const size_t cmsglen = CMSG_LEN (sizeof (struct sockcred));
+	const size_t cmsgspace = CMSG_SPACE (sizeof (struct sockcred));
+#endif
 	union {
 		struct cmsghdr hdr;
-		char cred[CMSG_SPACE (sizeof (struct cmsgcred))];
+		char cred[cmsgspace];
 	} cmsg;
 #endif
 	
 	*pid = 0;
 	*uid = 0;
 	
-#if defined(LOCAL_CREDS) && defined(HAVE_CMSGCRED) && !defined(__FreeBSD__)
-	/* Set the socket to receive credentials on the next message */
-	{
-		int on = 1;
-		if (setsockopt (fd, 0, LOCAL_CREDS, &on, sizeof (on)) < 0) {
-			g_warning ("Unable to set LOCAL_CREDS socket option\n");
-			return FALSE;
-		}
-	}
-#endif
+	/* If LOCAL_CREDS are used in this platform, they have already been
+	 * initialized by init_connection prior to sending of the credentials
+	 * byte we receive below. */
 	
 	iov.iov_base = &buf;
 	iov.iov_len = 1;
@@ -130,10 +166,10 @@ read_unix_socket_credentials (int fd,
 	msg.msg_iov = &iov;
 	msg.msg_iovlen = 1;
 	
-#ifdef HAVE_CMSGCRED
+#if defined(HAVE_CMSGCRED) || defined(LOCAL_CREDS)
 	memset (&cmsg, 0, sizeof (cmsg));
 	msg.msg_control = (caddr_t) &cmsg;
-	msg.msg_controllen = CMSG_SPACE (sizeof (struct cmsgcred));
+	msg.msg_controllen = cmsgspace;
 #endif
 
  again:
@@ -151,9 +187,8 @@ read_unix_socket_credentials (int fd,
 		return FALSE;
 	}
 
-#ifdef HAVE_CMSGCRED
-	if (cmsg.hdr.cmsg_len < CMSG_LEN (sizeof (struct cmsgcred)) ||
-	    cmsg.hdr.cmsg_type != SCM_CREDS) {
+#if defined(HAVE_CMSGCRED) || defined(LOCAL_CREDS)
+	if (cmsg.hdr.cmsg_len < cmsglen || cmsg.hdr.cmsg_type != SCM_CREDS) {
 		g_warning ("Message from recvmsg() was not SCM_CREDS\n");
 		return FALSE;
 	}
@@ -177,6 +212,10 @@ read_unix_socket_credentials (int fd,
 		cred = (struct cmsgcred *) CMSG_DATA (&cmsg);
 		*pid = cred->cmcred_pid;
 		*uid = cred->cmcred_euid;
+#elif defined(LOCAL_CREDS)
+		cred = (struct sockcred *) CMSG_DATA (&cmsg);
+		*pid = 0;
+		*uid = cred->sc_euid;
 #elif defined(HAVE_GETPEERUCRED)
 		ucred_t *uc = NULL;
 
@@ -359,6 +398,12 @@ gnome_keyring_client_state_machine (Gnom
 	
  new_state:
 	switch (client->state) {
+	case GNOME_CLIENT_STATE_INIT:
+		debug_print (("GNOME_CLIENT_STATE_INIT %p\n", client));
+                if (init_connection (client->sock))
+			client->state = GNOME_CLIENT_STATE_CREDENTIALS;
+		break;
+
 	case GNOME_CLIENT_STATE_CREDENTIALS:
 		debug_print (("GNOME_CLIENT_STATE_CREDENTIALS %p\n", client));
 		if (!read_unix_socket_credentials (client->sock, &pid, &uid)) {
@@ -554,13 +599,15 @@ gnome_keyring_client_new (int fd)
 					      gnome_keyring_client_hup, client);
 	g_io_channel_unref (channel);
 
-	client->state = GNOME_CLIENT_STATE_CREDENTIALS;
+	client->state = GNOME_CLIENT_STATE_INIT;
 	client->sock = fd;
 	client->input_channel = channel;
 	client->input_buffer = g_string_new (NULL);
 	client->input_pos = 0;
 
 	clients = g_list_prepend (clients, client);
+
+	gnome_keyring_client_state_machine (client);
 }
 
 
Index: gnome-keyring-daemon.c
===================================================================
RCS file: /cvs/gnome/gnome-keyring/gnome-keyring-daemon.c,v
retrieving revision 1.37
diff -u -p -u -r1.37 gnome-keyring-daemon.c
--- gnome-keyring-daemon.c	11 Aug 2006 09:09:48 -0000	1.37
+++ gnome-keyring-daemon.c	27 Aug 2006 16:03:37 -0000
@@ -340,6 +340,7 @@ gnome_keyring_application_ref_new_from_p
 	app_ref = g_new0 (GnomeKeyringApplicationRef, 1);
 
 #if defined(__linux__) || defined(__FreeBSD__)
+	g_assert (pid > 0);
 	{
 		char *buffer;
 		int len;
Index: gnome-keyring.c
===================================================================
RCS file: /cvs/gnome/gnome-keyring/gnome-keyring.c,v
retrieving revision 1.27
diff -u -p -u -r1.27 gnome-keyring.c
--- gnome-keyring.c	23 Aug 2006 19:52:35 -0000	1.27
+++ gnome-keyring.c	27 Aug 2006 16:03:38 -0000
@@ -53,6 +53,7 @@ typedef enum {
 
 typedef enum {
 	STATE_FAILED,
+	STATE_INITIALIZING,
 	STATE_WRITING_CREDS,
 	STATE_WRITING_PACKET,
 	STATE_READING_REPLY
@@ -249,6 +250,24 @@ write_all (int fd, const char *buf, size
 	return 0;
 }
 
+static void
+init_connection (GnomeKeyringOperation *op)
+{
+	char buf;
+	ssize_t len;
+
+	len = read (op->socket, &buf, sizeof (buf));
+	if (len == sizeof (buf)) {
+		if (buf != '\0')
+			g_warning ("Invalid initialization byte: %d\n", buf);
+		else
+			op->state = STATE_WRITING_CREDS;
+	} else
+		g_warning ("Failed to read initialization byte: %s",
+		           len == 0 ? "No data available" : strerror (errno));
+}
+
+
 static GnomeKeyringResult
 write_credentials_byte_sync (int socket)
 {
@@ -371,6 +390,9 @@ operation_io (GIOChannel  *io_channel,
 		schedule_op_failed (op, GNOME_KEYRING_RESULT_IO_ERROR);
 	}
 
+	if (op->state == STATE_INITIALIZING && (cond & G_IO_IN)) {
+		init_connection (op);
+	}
 	if (op->state == STATE_WRITING_CREDS && (cond & G_IO_OUT)) {
 		write_credentials_byte (op);
 	}
@@ -477,13 +499,13 @@ start_operation (gpointer callback, Keyr
 	if (op->socket < 0) {
 		schedule_op_failed (op, GNOME_KEYRING_RESULT_NO_KEYRING_DAEMON);
 	} else  {
-		op->state = STATE_WRITING_CREDS;
+		op->state = STATE_INITIALIZING;
 		op->send_buffer = g_string_new (NULL);
 		op->send_pos = 0;
 		
 		channel = g_io_channel_unix_new (op->socket);
 		op->io_watch = g_io_add_watch (channel,
-					       G_IO_OUT | G_IO_HUP,
+					       G_IO_IN | G_IO_OUT | G_IO_HUP,
 					       operation_io, op);
 		g_io_channel_unref (channel);
 	} 
