diff --git a/bus/connection.c b/bus/connection.c index 95e20a6..1eadd46 100644 --- a/bus/connection.c +++ b/bus/connection.c @@ -960,7 +960,7 @@ bus_connection_get_unix_groups (DBusConnection *connection, int *n_groups, DBusError *error) { - unsigned long uid; + unsigned long uid, gid; *groups = NULL; *n_groups = 0; @@ -977,11 +977,41 @@ bus_connection_get_unix_groups (DBusConnection *connection, { _dbus_verbose ("Got %d groups for UID %lu\n", *n_groups, uid); - return TRUE; } } - else - return TRUE; /* successfully got 0 groups */ + + if (_dbus_connection_get_unix_group (connection, &gid)) + { + int i, found; + + for (i = 0, found = -1; i < *n_groups; i++) + { + if ((*groups)[i] == gid) + { + found = i; + break; + } + } + + if (found < 0) + { + unsigned long *group_ids = dbus_new (unsigned long, *n_groups + 1); + + if (group_ids) + { + if (*groups) + { + memcpy (group_ids + 1, *groups, *n_groups * sizeof (unsigned long)); + dbus_free (*groups); + } + group_ids[0] = gid; + *groups = group_ids; + *n_groups = *n_groups + 1; + } + } + } + + return TRUE; } dbus_bool_t diff --git a/dbus/dbus-auth.c b/dbus/dbus-auth.c index f222787..a034b87 100644 --- a/dbus/dbus-auth.c +++ b/dbus/dbus-auth.c @@ -765,6 +765,13 @@ sha1_handle_second_client_response (DBusAuth *auth, DBUS_CREDENTIAL_UNIX_PROCESS_ID, auth->credentials)) goto out_3; + + /* Copy group ID from the socket credentials if it's there + */ + if (!_dbus_credentials_add_credential (auth->authorized_identity, + DBUS_CREDENTIAL_UNIX_GROUP_ID, + auth->credentials)) + goto out_3; if (!send_ok (auth)) goto out_3; @@ -1138,6 +1145,11 @@ handle_server_data_external_mech (DBusAuth *auth, return FALSE; if (!_dbus_credentials_add_credential (auth->authorized_identity, + DBUS_CREDENTIAL_UNIX_GROUP_ID, + auth->credentials)) + return FALSE; + + if (!_dbus_credentials_add_credential (auth->authorized_identity, DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID, auth->credentials)) return FALSE; @@ -1251,6 +1263,13 @@ handle_server_data_anonymous_mech (DBusAuth *auth, auth->credentials)) return FALSE; + /* Copy group ID from the socket credentials + */ + if (!_dbus_credentials_add_credential (auth->authorized_identity, + DBUS_CREDENTIAL_UNIX_GROUP_ID, + auth->credentials)) + return FALSE; + /* Anonymous is always allowed */ if (!send_ok (auth)) return FALSE; diff --git a/dbus/dbus-connection-internal.h b/dbus/dbus-connection-internal.h index 4835732..a980e78 100644 --- a/dbus/dbus-connection-internal.h +++ b/dbus/dbus-connection-internal.h @@ -117,6 +117,9 @@ void _dbus_connection_set_pending_fds_function (DBusConnectio DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_connection_get_linux_security_label (DBusConnection *connection, char **label_p); +DBUS_PRIVATE_EXPORT +dbus_bool_t _dbus_connection_get_unix_group (DBusConnection *connection, + unsigned long *gid); /* if DBUS_ENABLE_STATS */ DBUS_PRIVATE_EXPORT diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index 81b3a83..2cf386d 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -5243,6 +5243,28 @@ dbus_connection_get_unix_user (DBusConnection *connection, return result; } +dbus_bool_t +_dbus_connection_get_unix_group (DBusConnection *connection, + unsigned long *gid) +{ + dbus_bool_t result; + + _dbus_return_val_if_fail (connection != NULL, FALSE); + _dbus_return_val_if_fail (gid != NULL, FALSE); + + CONNECTION_LOCK (connection); + + if (!_dbus_transport_try_to_authenticate (connection->transport)) + result = FALSE; + else + result = _dbus_transport_get_unix_group (connection->transport, gid); + + CONNECTION_UNLOCK (connection); + + return result; +} + + /** * Gets the process ID of the connection if any. * Returns #TRUE if the pid is filled in. diff --git a/dbus/dbus-credentials.c b/dbus/dbus-credentials.c index 151bb00..650c599 100644 --- a/dbus/dbus-credentials.c +++ b/dbus/dbus-credentials.c @@ -48,6 +48,7 @@ struct DBusCredentials { int refcount; dbus_uid_t unix_uid; + dbus_gid_t unix_gid; dbus_pid_t pid; char *windows_sid; char *linux_security_label; @@ -78,6 +79,7 @@ _dbus_credentials_new (void) creds->refcount = 1; creds->unix_uid = DBUS_UID_UNSET; + creds->unix_gid = DBUS_GID_UNSET; creds->pid = DBUS_PID_UNSET; creds->windows_sid = NULL; creds->linux_security_label = NULL; @@ -173,6 +175,21 @@ _dbus_credentials_add_unix_uid(DBusCredentials *credentials, } /** + * Add a UNIX group ID to the credentials. + * + * @param credentials the object + * @param gid the group ID + * @returns #FALSE if no memory + */ +dbus_bool_t +_dbus_credentials_add_unix_gid(DBusCredentials *credentials, + dbus_gid_t gid) +{ + credentials->unix_gid = gid; + return TRUE; +} + +/** * Add a Windows user SID to the credentials. * * @param credentials the object @@ -261,6 +278,8 @@ _dbus_credentials_include (DBusCredentials *credentials, return credentials->pid != DBUS_PID_UNSET; case DBUS_CREDENTIAL_UNIX_USER_ID: return credentials->unix_uid != DBUS_UID_UNSET; + case DBUS_CREDENTIAL_UNIX_GROUP_ID: + return credentials->unix_gid != DBUS_GID_UNSET; case DBUS_CREDENTIAL_WINDOWS_SID: return credentials->windows_sid != NULL; case DBUS_CREDENTIAL_LINUX_SECURITY_LABEL: @@ -300,6 +319,19 @@ _dbus_credentials_get_unix_uid (DBusCredentials *credentials) } /** + * Gets the UNIX group ID in the credentials, or #DBUS_GID_UNSET if + * the credentials object doesn't contain a group ID. + * + * @param credentials the object + * @returns UNIX group ID + */ +dbus_gid_t +_dbus_credentials_get_unix_gid (DBusCredentials *credentials) +{ + return credentials->unix_gid; +} + +/** * Gets the Windows user SID in the credentials, or #NULL if * the credentials object doesn't contain a Windows user SID. * @@ -368,6 +400,8 @@ _dbus_credentials_are_superset (DBusCredentials *credentials, possible_subset->pid == credentials->pid) && (possible_subset->unix_uid == DBUS_UID_UNSET || possible_subset->unix_uid == credentials->unix_uid) && + (possible_subset->unix_gid == DBUS_GID_UNSET || + possible_subset->unix_gid == credentials->unix_gid) && (possible_subset->windows_sid == NULL || (credentials->windows_sid && strcmp (possible_subset->windows_sid, credentials->windows_sid) == 0)) && @@ -393,6 +427,7 @@ _dbus_credentials_are_empty (DBusCredentials *credentials) return credentials->pid == DBUS_PID_UNSET && credentials->unix_uid == DBUS_UID_UNSET && + credentials->unix_gid == DBUS_GID_UNSET && credentials->windows_sid == NULL && credentials->linux_security_label == NULL && credentials->adt_audit_data == NULL; @@ -432,6 +467,9 @@ _dbus_credentials_add_credentials (DBusCredentials *credentials, DBUS_CREDENTIAL_UNIX_USER_ID, other_credentials) && _dbus_credentials_add_credential (credentials, + DBUS_CREDENTIAL_UNIX_GROUP_ID, + other_credentials) && + _dbus_credentials_add_credential (credentials, DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID, other_credentials) && _dbus_credentials_add_credential (credentials, @@ -471,6 +509,12 @@ _dbus_credentials_add_credential (DBusCredentials *credentials, if (!_dbus_credentials_add_unix_uid (credentials, other_credentials->unix_uid)) return FALSE; } + else if (which == DBUS_CREDENTIAL_UNIX_GROUP_ID && + other_credentials->unix_gid != DBUS_GID_UNSET) + { + if (!_dbus_credentials_add_unix_gid (credentials, other_credentials->unix_gid)) + return FALSE; + } else if (which == DBUS_CREDENTIAL_WINDOWS_SID && other_credentials->windows_sid != NULL) { @@ -504,6 +548,7 @@ _dbus_credentials_clear (DBusCredentials *credentials) { credentials->pid = DBUS_PID_UNSET; credentials->unix_uid = DBUS_UID_UNSET; + credentials->unix_gid = DBUS_GID_UNSET; dbus_free (credentials->windows_sid); credentials->windows_sid = NULL; dbus_free (credentials->linux_security_label); diff --git a/dbus/dbus-credentials.h b/dbus/dbus-credentials.h index 6bf6c2b..8aa2b92 100644 --- a/dbus/dbus-credentials.h +++ b/dbus/dbus-credentials.h @@ -33,6 +33,7 @@ DBUS_BEGIN_DECLS typedef enum { DBUS_CREDENTIAL_UNIX_PROCESS_ID, DBUS_CREDENTIAL_UNIX_USER_ID, + DBUS_CREDENTIAL_UNIX_GROUP_ID, DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID, DBUS_CREDENTIAL_LINUX_SECURITY_LABEL, DBUS_CREDENTIAL_WINDOWS_SID @@ -53,6 +54,9 @@ DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_credentials_add_unix_uid (DBusCredentials *credentials, dbus_uid_t uid); DBUS_PRIVATE_EXPORT +dbus_bool_t _dbus_credentials_add_unix_gid (DBusCredentials *credentials, + dbus_gid_t gid); +DBUS_PRIVATE_EXPORT dbus_bool_t _dbus_credentials_add_windows_sid (DBusCredentials *credentials, const char *windows_sid); dbus_bool_t _dbus_credentials_add_linux_security_label (DBusCredentials *credentials, @@ -68,6 +72,8 @@ dbus_pid_t _dbus_credentials_get_pid (DBusCredentials DBUS_PRIVATE_EXPORT dbus_uid_t _dbus_credentials_get_unix_uid (DBusCredentials *credentials); DBUS_PRIVATE_EXPORT +dbus_gid_t _dbus_credentials_get_unix_gid (DBusCredentials *credentials); +DBUS_PRIVATE_EXPORT const char* _dbus_credentials_get_windows_sid (DBusCredentials *credentials); const char * _dbus_credentials_get_linux_security_label (DBusCredentials *credentials); void * _dbus_credentials_get_adt_audit_data (DBusCredentials *credentials); diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c index 50ca60a..724c737 100644 --- a/dbus/dbus-sysdeps-unix.c +++ b/dbus/dbus-sysdeps-unix.c @@ -1816,6 +1816,7 @@ _dbus_read_credentials_socket (DBusSocket client_fd, struct iovec iov; char buf; dbus_uid_t uid_read; + dbus_gid_t gid_read; dbus_pid_t pid_read; int bytes_read; @@ -1835,6 +1836,7 @@ _dbus_read_credentials_socket (DBusSocket client_fd, _DBUS_STATIC_ASSERT (sizeof (gid_t) <= sizeof (dbus_gid_t)); uid_read = DBUS_UID_UNSET; + gid_read = DBUS_GID_UNSET; pid_read = DBUS_PID_UNSET; _DBUS_ASSERT_ERROR_IS_CLEAR (error); @@ -1921,6 +1923,7 @@ _dbus_read_credentials_socket (DBusSocket client_fd, { pid_read = cr.pid; uid_read = cr.uid; + gid_read = cr.gid; } #elif defined(HAVE_UNPCBID) && defined(LOCAL_PEEREID) /* Another variant of the above - used on NetBSD @@ -1942,6 +1945,7 @@ _dbus_read_credentials_socket (DBusSocket client_fd, { pid_read = cr.unp_pid; uid_read = cr.unp_euid; + gid_read = cr.unp_egid; } #elif defined(HAVE_CMSGCRED) /* We only check for HAVE_CMSGCRED, but we're really assuming that the @@ -1966,6 +1970,7 @@ _dbus_read_credentials_socket (DBusSocket client_fd, cred = (struct cmsgcred *) CMSG_DATA (cmsgp); pid_read = cred->cmcred_pid; uid_read = cred->cmcred_euid; + gid_read = cred->cmcred_gid; break; } } @@ -1979,6 +1984,7 @@ _dbus_read_credentials_socket (DBusSocket client_fd, { pid_read = ucred_getpid (ucred); uid_read = ucred_geteuid (ucred); + gid_read = ucred_getegid (ucred); #ifdef HAVE_ADT /* generate audit session data based on socket ucred */ adt_session_data_t *adth = NULL; @@ -2044,6 +2050,7 @@ _dbus_read_credentials_socket (DBusSocket client_fd, if (getpeereid (client_fd.fd, &euid, &egid) == 0) { uid_read = euid; + gid_read = egid; } else { @@ -2072,9 +2079,11 @@ _dbus_read_credentials_socket (DBusSocket client_fd, _dbus_verbose ("Credentials:" " pid "DBUS_PID_FORMAT " uid "DBUS_UID_FORMAT + " gid "DBUS_GID_FORMAT "\n", pid_read, - uid_read); + uid_read, + gid_read); if (pid_read != DBUS_PID_UNSET) { @@ -2094,6 +2103,15 @@ _dbus_read_credentials_socket (DBusSocket client_fd, } } + if (gid_read != DBUS_GID_UNSET) + { + if (!_dbus_credentials_add_unix_gid (credentials, gid_read)) + { + _DBUS_SET_OOM (error); + return FALSE; + } + } + if (!add_linux_security_label_to_credentials (client_fd.fd, credentials)) { _DBUS_SET_OOM (error); @@ -2557,6 +2575,8 @@ _dbus_credentials_add_from_current_process (DBusCredentials *credentials) return FALSE; if (!_dbus_credentials_add_unix_uid(credentials, _dbus_geteuid())) return FALSE; + if (!_dbus_credentials_add_unix_gid(credentials, getegid())) + return FALSE; return TRUE; } diff --git a/dbus/dbus-transport.c b/dbus/dbus-transport.c index 31586b1..f6c3df7 100644 --- a/dbus/dbus-transport.c +++ b/dbus/dbus-transport.c @@ -1333,6 +1333,39 @@ _dbus_transport_get_unix_user (DBusTransport *transport, } /** + * See _dbus_connection_get_unix_group(). + * + * @param transport the transport + * @param gid return location for the group ID + * @returns #TRUE if uid is filled in with a valid group ID + */ +dbus_bool_t +_dbus_transport_get_unix_group (DBusTransport *transport, + unsigned long *gid) +{ + DBusCredentials *auth_identity; + + *gid = _DBUS_INT32_MAX; /* better than some root or system user in + * case of bugs in the caller. Caller should + * never use this value on purpose, however. + */ + + if (!transport->authenticated) + return FALSE; + + auth_identity = _dbus_auth_get_identity (transport->auth); + + if (_dbus_credentials_include (auth_identity, + DBUS_CREDENTIAL_UNIX_GROUP_ID)) + { + *gid = _dbus_credentials_get_unix_gid (auth_identity); + return TRUE; + } + else + return FALSE; +} + +/** * See dbus_connection_get_unix_process_id(). * * @param transport the transport diff --git a/dbus/dbus-transport.h b/dbus/dbus-transport.h index 9e3787d..8cb3ae7 100644 --- a/dbus/dbus-transport.h +++ b/dbus/dbus-transport.h @@ -74,6 +74,8 @@ dbus_bool_t _dbus_transport_get_socket_fd (DBusTransport DBusSocket *fd_p); dbus_bool_t _dbus_transport_get_unix_user (DBusTransport *transport, unsigned long *uid); +dbus_bool_t _dbus_transport_get_unix_group (DBusTransport *transport, + unsigned long *gid); dbus_bool_t _dbus_transport_get_unix_process_id (DBusTransport *transport, unsigned long *pid); dbus_bool_t _dbus_transport_get_adt_audit_session_data (DBusTransport *transport,