From 23832672266bb4ff23b66247c0cfa1a2ed0cc97b Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Sat, 9 Jun 2007 21:53:20 +0000 Subject: 2007-06-09 Havoc Pennington * bus/dispatch.c (check_get_connection_unix_process_id): adapt since sysdeps-unix.h stuff isn't included anymore * bus/bus.c (bus_context_new): use more abstract functions to change user, so they can be no-ops on Windows * dbus/dbus-credentials.c, dbus/dbus-credentials.h, dbus/dbus-credentials-util.c: new files containing a fully opaque DBusCredentials data type to replace the old not opaque one. * configure.in (DBUS_UNIX): define DBUS_UNIX to match DBUS_WIN on windows * dbus/dbus-userdb.h: prohibit on Windows, next step is to clean up the uses of it in bus/*.c and factor out the parts of cookie auth that depend on it --- dbus/dbus-sysdeps-unix.c | 225 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 179 insertions(+), 46 deletions(-) (limited to 'dbus/dbus-sysdeps-unix.c') diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c index 80732a79..135f7c9f 100644 --- a/dbus/dbus-sysdeps-unix.c +++ b/dbus/dbus-sysdeps-unix.c @@ -31,6 +31,7 @@ #include "dbus-string.h" #include "dbus-userdb.h" #include "dbus-list.h" +#include "dbus-credentials.h" #include #include #include @@ -85,6 +86,7 @@ _dbus_open_socket (int *fd_p, *fd_p = socket (domain, type, protocol); if (*fd_p >= 0) { + _dbus_verbose ("socket fd %d opened\n", *fd_p); return TRUE; } else @@ -949,11 +951,14 @@ write_credentials_byte (int server_fd, /** * Reads a single byte which must be nul (an error occurs otherwise), - * and reads unix credentials if available. Fills in pid/uid/gid with - * -1 if no credentials are available. Return value indicates whether - * a byte was read, not whether we got valid credentials. On some - * systems, such as Linux, reading/writing the byte isn't actually - * required, but we do it anyway just to avoid multiple codepaths. + * and reads unix credentials if available. Clears the credentials + * object, then adds pid/uid if available, so any previous credentials + * stored in the object are lost. + * + * Return value indicates whether a byte was read, not whether + * we got valid credentials. On some systems, such as Linux, + * reading/writing the byte isn't actually required, but we do it + * anyway just to avoid multiple codepaths. * * Fails if no byte is available, so you must select() first. * @@ -961,19 +966,24 @@ write_credentials_byte (int server_fd, * use sendmsg()/recvmsg() to transmit credentials. * * @param client_fd the client file descriptor - * @param credentials struct to fill with credentials of client + * @param credentials object to add client credentials to * @param error location to store error code * @returns #TRUE on success */ dbus_bool_t -_dbus_read_credentials_unix_socket (int client_fd, - DBusCredentials *credentials, - DBusError *error) +_dbus_read_credentials_socket (int client_fd, + DBusCredentials *credentials, + DBusError *error) { struct msghdr msg; struct iovec iov; char buf; + dbus_uid_t uid_read; + dbus_pid_t pid_read; + uid_read = DBUS_UID_UNSET; + pid_read = DBUS_PID_UNSET; + #ifdef HAVE_CMSGCRED struct { struct cmsghdr hdr; @@ -993,9 +1003,9 @@ _dbus_read_credentials_unix_socket (int client_fd, * we need these assertions to fail as soon as we're wrong about * it so we can do the porting fixups */ - _dbus_assert (sizeof (pid_t) <= sizeof (credentials->pid)); - _dbus_assert (sizeof (uid_t) <= sizeof (credentials->uid)); - _dbus_assert (sizeof (gid_t) <= sizeof (credentials->gid)); + _dbus_assert (sizeof (pid_t) <= sizeof (dbus_pid_t)); + _dbus_assert (sizeof (uid_t) <= sizeof (dbus_uid_t)); + _dbus_assert (sizeof (gid_t) <= sizeof (dbus_gid_t)); _dbus_credentials_clear (credentials); @@ -1056,9 +1066,8 @@ _dbus_read_credentials_unix_socket (int client_fd, if (getsockopt (client_fd, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) == 0 && cr_len == sizeof (cr)) { - credentials->pid = cr.pid; - credentials->uid = cr.uid; - credentials->gid = cr.gid; + pid_read = cr.pid; + uid_read = cr.uid; } else { @@ -1066,13 +1075,11 @@ _dbus_read_credentials_unix_socket (int client_fd, cr_len, (int) sizeof (cr), _dbus_strerror (errno)); } #elif defined(HAVE_CMSGCRED) - credentials->pid = cmsg.cred.cmcred_pid; - credentials->uid = cmsg.cred.cmcred_euid; - credentials->gid = cmsg.cred.cmcred_groups[0]; + pid_read = cmsg.cred.cmcred_pid; + uid_read = cmsg.cred.cmcred_euid; #elif defined(LOCAL_CREDS) - credentials->pid = DBUS_PID_UNSET; - credentials->uid = cmsg.cred.sc_uid; - credentials->gid = cmsg.cred.sc_gid; + pid_read = DBUS_PID_UNSET; + uid_read = cmsg.cred.sc_uid; /* Since we have already got the credentials from this socket, we can * disable its LOCAL_CREDS flag if it was ever set. */ _dbus_set_local_creds (client_fd, FALSE); @@ -1081,8 +1088,7 @@ _dbus_read_credentials_unix_socket (int client_fd, gid_t egid; if (getpeereid (client_fd, &euid, &egid) == 0) { - credentials->uid = euid; - credentials->gid = egid; + uid_read = euid; } else { @@ -1092,9 +1098,8 @@ _dbus_read_credentials_unix_socket (int client_fd, ucred_t * ucred = NULL; if (getpeerucred (client_fd, &ucred) == 0) { - credentials->pid = ucred_getpid (ucred); - credentials->uid = ucred_geteuid (ucred); - credentials->gid = ucred_getegid (ucred); + pid_read = ucred_getpid (ucred); + uid_read = ucred_geteuid (ucred); } else { @@ -1110,11 +1115,28 @@ _dbus_read_credentials_unix_socket (int client_fd, _dbus_verbose ("Credentials:" " pid "DBUS_PID_FORMAT " uid "DBUS_UID_FORMAT - " gid "DBUS_GID_FORMAT"\n", - credentials->pid, - credentials->uid, - credentials->gid); - + "\n", + pid_read, + uid_read); + + if (pid_read != DBUS_PID_UNSET) + { + if (!_dbus_credentials_add_unix_pid (credentials, pid_read)) + { + _DBUS_SET_OOM (error); + return FALSE; + } + } + + if (uid_read != DBUS_UID_UNSET) + { + if (!_dbus_credentials_add_unix_uid (credentials, uid_read)) + { + _DBUS_SET_OOM (error); + return FALSE; + } + } + return TRUE; } @@ -1136,8 +1158,8 @@ _dbus_read_credentials_unix_socket (int client_fd, * @returns #TRUE if the byte was sent */ dbus_bool_t -_dbus_send_credentials_unix_socket (int server_fd, - DBusError *error) +_dbus_send_credentials_socket (int server_fd, + DBusError *error) { _DBUS_ASSERT_ERROR_IS_CLEAR (error); @@ -1171,6 +1193,8 @@ _dbus_accept (int listen_fd) if (errno == EINTR) goto retry; } + + _dbus_verbose ("client fd %d accepted\n", client_fd); return client_fd; } @@ -1446,31 +1470,77 @@ _dbus_user_info_fill_uid (DBusUserInfo *info, } /** - * Gets the credentials of the current process. + * Adds the credentials of the current process to the + * passed-in credentials object. * - * @param credentials credentials to fill in. + * @param credentials credentials to add to + * @returns #FALSE if no memory; does not properly roll back on failure, so only some credentials may have been added */ -void -_dbus_credentials_from_current_process (DBusCredentials *credentials) +dbus_bool_t +_dbus_credentials_add_from_current_process (DBusCredentials *credentials) { /* The POSIX spec certainly doesn't promise this, but * we need these assertions to fail as soon as we're wrong about * it so we can do the porting fixups */ - _dbus_assert (sizeof (pid_t) <= sizeof (credentials->pid)); - _dbus_assert (sizeof (uid_t) <= sizeof (credentials->uid)); - _dbus_assert (sizeof (gid_t) <= sizeof (credentials->gid)); - - credentials->pid = getpid (); - credentials->uid = getuid (); - credentials->gid = getgid (); + _dbus_assert (sizeof (pid_t) <= sizeof (dbus_pid_t)); + _dbus_assert (sizeof (uid_t) <= sizeof (dbus_uid_t)); + _dbus_assert (sizeof (gid_t) <= sizeof (dbus_gid_t)); + + if (!_dbus_credentials_add_unix_pid(credentials, _dbus_getpid())) + return FALSE; + if (!_dbus_credentials_add_unix_uid(credentials, _dbus_getuid())) + return FALSE; + + return TRUE; +} + +/** + * Parses a desired identity provided from a client in the auth protocol. + * On UNIX this means parsing a UID. + * + * @todo this is broken because it treats OOM and parse error + * the same way. Needs a #DBusError. + * + * @param credentials the credentials to add what we parse to + * @param desired_identity the string to parse + * @returns #TRUE if we successfully parsed something + */ +dbus_bool_t +_dbus_credentials_parse_and_add_desired (DBusCredentials *credentials, + const DBusString *desired_identity) +{ + dbus_uid_t uid; + + if (!_dbus_parse_uid (desired_identity, &uid)) + return FALSE; + + if (!_dbus_credentials_add_unix_uid (credentials, uid)) + return FALSE; + + return TRUE; +} + +/** + * Append to the string the identity we would like to have when we authenticate, + * on UNIX this is the current process UID and on Windows something else. + * No escaping is required, that is done in dbus-auth.c. + * + * @param str the string to append to + * @returns #FALSE on no memory + */ +dbus_bool_t +_dbus_append_desired_identity (DBusString *str) +{ + return _dbus_string_append_uint (str, + _dbus_getuid ()); } /** * Gets our process ID * @returns process ID */ -unsigned long +dbus_pid_t _dbus_getpid (void) { return getpid (); @@ -1485,6 +1555,59 @@ _dbus_getuid (void) return getuid (); } +/** + * The only reason this is separate from _dbus_getpid() is to allow it + * on Windows for logging but not for other purposes. + * + * @returns process ID to put in log messages + */ +unsigned long +_dbus_pid_for_log (void) +{ + return getpid (); +} + +/** + * Gets a UID from a UID string. + * + * @param uid_str the UID in string form + * @param uid UID to fill in + * @returns #TRUE if successfully filled in UID + */ +dbus_bool_t +_dbus_parse_uid (const DBusString *uid_str, + dbus_uid_t *uid) +{ + int end; + long val; + + if (_dbus_string_get_length (uid_str) == 0) + { + _dbus_verbose ("UID string was zero length\n"); + return FALSE; + } + + val = -1; + end = 0; + if (!_dbus_string_parse_int (uid_str, 0, &val, + &end)) + { + _dbus_verbose ("could not parse string as a UID\n"); + return FALSE; + } + + if (end != _dbus_string_get_length (uid_str)) + { + _dbus_verbose ("string contained trailing stuff after UID\n"); + return FALSE; + } + + *uid = val; + + return TRUE; +} + + _DBUS_DEFINE_GLOBAL_LOCK (atomic); #ifdef DBUS_USE_ATOMIC_INT_486 @@ -1717,6 +1840,8 @@ _dbus_file_get_contents (DBusString *str, return FALSE; } + _dbus_verbose ("file fd %d opened\n", fd); + if (fstat (fd, &sb) < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), @@ -1858,6 +1983,8 @@ _dbus_string_save_to_file (const DBusString *str, goto out; } + _dbus_verbose ("tmp file fd %d opened\n", fd); + need_unlink = TRUE; total = 0; @@ -1983,6 +2110,8 @@ _dbus_create_file_exclusively (const DBusString *filename, return FALSE; } + _dbus_verbose ("exclusive file fd %d opened\n", fd); + if (!_dbus_close (fd, NULL)) { dbus_set_error (error, @@ -2181,6 +2310,8 @@ _dbus_generate_random_bytes (DBusString *str, if (fd < 0) return _dbus_generate_pseudorandom_bytes (str, n_bytes); + _dbus_verbose ("/dev/urandom fd %d opened\n", fd); + if (_dbus_read (fd, str, n_bytes) != n_bytes) { _dbus_close (fd, NULL); @@ -2571,6 +2702,8 @@ _dbus_get_autolaunch_address (DBusString *address, /* huh?! can't open /dev/null? */ _exit (1); + _dbus_verbose ("/dev/null fd %d opened\n", fd); + /* set-up stdXXX */ close (address_pipe[READ_END]); close (errors_pipe[READ_END]); @@ -2757,7 +2890,7 @@ _dbus_get_standard_session_servicedirs (DBusList **dirs) else { const DBusString *homedir; - const DBusString local_share; + DBusString local_share; if (!_dbus_homedir_from_current_process (&homedir)) goto oom; -- cgit