/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-credentials.c Credentials provable through authentication * * Copyright (C) 2007 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include "dbus-credentials.h" #include "dbus-internals.h" /** * @defgroup DBusCredentials Credentials provable through authentication * @ingroup DBusInternals * @brief DBusCredentials object * * Credentials are what you have to prove you have in order to * authenticate. The main credentials right now are a unix user * account, a Windows user account, or a UNIX process ID. */ /** * @defgroup DBusCredentialsInternals Credentials implementation details * @ingroup DBusInternals * @brief DBusCredentials implementation details * * Private details of credentials code. * * @{ */ struct DBusCredentials { int refcount; dbus_uid_t unix_uid; dbus_pid_t unix_pid; char *windows_sid; void *adt_audit_data; dbus_int32_t adt_audit_data_size; }; /** @} */ /** * @addtogroup DBusCredentials * @{ */ /** * Creates a new credentials object. * * @returns the new object or #NULL if no memory */ DBusCredentials* _dbus_credentials_new (void) { DBusCredentials *creds; creds = dbus_new (DBusCredentials, 1); if (creds == NULL) return NULL; creds->refcount = 1; creds->unix_uid = DBUS_UID_UNSET; creds->unix_pid = DBUS_PID_UNSET; creds->windows_sid = NULL; creds->adt_audit_data = NULL; creds->adt_audit_data_size = 0; return creds; } /** * Creates a new object with credentials (user ID and process ID) from the current process. * @returns the new object or #NULL if no memory */ DBusCredentials* _dbus_credentials_new_from_current_process (void) { DBusCredentials *creds; creds = _dbus_credentials_new (); if (creds == NULL) return NULL; if (!_dbus_credentials_add_from_current_process (creds)) { _dbus_credentials_unref (creds); return NULL; } return creds; } /** * Increment refcount on credentials. * * @param credentials the object */ void _dbus_credentials_ref (DBusCredentials *credentials) { _dbus_assert (credentials->refcount > 0); credentials->refcount += 1; } /** * Decrement refcount on credentials. * * @param credentials the object */ void _dbus_credentials_unref (DBusCredentials *credentials) { _dbus_assert (credentials->refcount > 0); credentials->refcount -= 1; if (credentials->refcount == 0) { dbus_free (credentials->windows_sid); dbus_free (credentials->adt_audit_data); dbus_free (credentials); } } /** * Add a UNIX process ID to the credentials. * * @param credentials the object * @param pid the process ID * @returns #FALSE if no memory */ dbus_bool_t _dbus_credentials_add_unix_pid (DBusCredentials *credentials, dbus_pid_t pid) { credentials->unix_pid = pid; return TRUE; } /** * Add a UNIX user ID to the credentials. * * @param credentials the object * @param uid the user ID * @returns #FALSE if no memory */ dbus_bool_t _dbus_credentials_add_unix_uid(DBusCredentials *credentials, dbus_uid_t uid) { credentials->unix_uid = uid; return TRUE; } /** * Add a Windows user SID to the credentials. * * @param credentials the object * @param windows_sid the user SID * @returns #FALSE if no memory */ dbus_bool_t _dbus_credentials_add_windows_sid (DBusCredentials *credentials, const char *windows_sid) { char *copy; copy = _dbus_strdup (windows_sid); if (copy == NULL) return FALSE; dbus_free (credentials->windows_sid); credentials->windows_sid = copy; return TRUE; } /** * Add ADT audit data to the credentials. * * @param credentials the object * @param audit_data the audit data * @param size the length of audit data * @returns #FALSE if no memory */ dbus_bool_t _dbus_credentials_add_adt_audit_data (DBusCredentials *credentials, void *audit_data, dbus_int32_t size) { void *copy; copy = _dbus_memdup (audit_data, size); if (copy == NULL) return FALSE; dbus_free (credentials->adt_audit_data); credentials->adt_audit_data = copy; credentials->adt_audit_data_size = size; return TRUE; } /** * Checks whether the given credential is present. * * @param credentials the object * @param type the credential to check for * @returns #TRUE if the credential is present */ dbus_bool_t _dbus_credentials_include (DBusCredentials *credentials, DBusCredentialType type) { switch (type) { case DBUS_CREDENTIAL_UNIX_PROCESS_ID: return credentials->unix_pid != DBUS_PID_UNSET; case DBUS_CREDENTIAL_UNIX_USER_ID: return credentials->unix_uid != DBUS_UID_UNSET; case DBUS_CREDENTIAL_WINDOWS_SID: return credentials->windows_sid != NULL; case DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID: return credentials->adt_audit_data != NULL; } _dbus_assert_not_reached ("Unknown credential enum value"); return FALSE; } /** * Gets the UNIX process ID in the credentials, or #DBUS_PID_UNSET if * the credentials object doesn't contain a process ID. * * @param credentials the object * @returns UNIX process ID */ dbus_pid_t _dbus_credentials_get_unix_pid (DBusCredentials *credentials) { return credentials->unix_pid; } /** * Gets the UNIX user ID in the credentials, or #DBUS_UID_UNSET if * the credentials object doesn't contain a user ID. * * @param credentials the object * @returns UNIX user ID */ dbus_uid_t _dbus_credentials_get_unix_uid (DBusCredentials *credentials) { return credentials->unix_uid; } /** * Gets the Windows user SID in the credentials, or #NULL if * the credentials object doesn't contain a Windows user SID. * * @param credentials the object * @returns Windows user SID */ const char* _dbus_credentials_get_windows_sid (DBusCredentials *credentials) { return credentials->windows_sid; } /** * Gets the ADT audit data in the credentials, or #NULL if * the credentials object doesn't contain ADT audit data. * * @param credentials the object * @returns Solaris ADT audit data */ void * _dbus_credentials_get_adt_audit_data (DBusCredentials *credentials) { return credentials->adt_audit_data; } /** * Gets the ADT audit data size in the credentials, or 0 if * the credentials object doesn't contain ADT audit data. * * @param credentials the object * @returns Solaris ADT audit data size */ dbus_int32_t _dbus_credentials_get_adt_audit_data_size (DBusCredentials *credentials) { return credentials->adt_audit_data_size; } /** * Checks whether the first credentials object contains * all the credentials found in the second credentials object. * * @param credentials the object * @param possible_subset see if credentials in here are also in the first arg * @returns #TRUE if second arg is contained in first */ dbus_bool_t _dbus_credentials_are_superset (DBusCredentials *credentials, DBusCredentials *possible_subset) { return (possible_subset->unix_pid == DBUS_PID_UNSET || possible_subset->unix_pid == credentials->unix_pid) && (possible_subset->unix_uid == DBUS_UID_UNSET || possible_subset->unix_uid == credentials->unix_uid) && (possible_subset->windows_sid == NULL || (credentials->windows_sid && strcmp (possible_subset->windows_sid, credentials->windows_sid) == 0)) && (possible_subset->adt_audit_data == NULL || (credentials->adt_audit_data && memcmp (possible_subset->adt_audit_data, credentials->adt_audit_data, credentials->adt_audit_data_size) == 0)); } /** * Checks whether a credentials object contains anything. * * @param credentials the object * @returns #TRUE if there are no credentials in the object */ dbus_bool_t _dbus_credentials_are_empty (DBusCredentials *credentials) { return credentials->unix_pid == DBUS_PID_UNSET && credentials->unix_uid == DBUS_UID_UNSET && credentials->windows_sid == NULL && credentials->adt_audit_data == NULL; } /** * Checks whether a credentials object contains a user identity. * * @param credentials the object * @returns #TRUE if there are no user identities in the object */ dbus_bool_t _dbus_credentials_are_anonymous (DBusCredentials *credentials) { return credentials->unix_uid == DBUS_UID_UNSET && credentials->windows_sid == NULL; } /** * Merge all credentials found in the second object into the first object, * overwriting the first object if there are any overlaps. * * @param credentials the object * @param other_credentials credentials to merge * @returns #FALSE if no memory */ dbus_bool_t _dbus_credentials_add_credentials (DBusCredentials *credentials, DBusCredentials *other_credentials) { return _dbus_credentials_add_credential (credentials, DBUS_CREDENTIAL_UNIX_PROCESS_ID, other_credentials) && _dbus_credentials_add_credential (credentials, DBUS_CREDENTIAL_UNIX_USER_ID, other_credentials) && _dbus_credentials_add_credential (credentials, DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID, other_credentials) && _dbus_credentials_add_credential (credentials, DBUS_CREDENTIAL_WINDOWS_SID, other_credentials); } /** * Merge the given credential found in the second object into the first object, * overwriting the first object's value for that credential. * * Does nothing if the second object does not contain the specified credential. * i.e., will never delete a credential from the first object. * * @param credentials the object * @param which the credential to overwrite * @param other_credentials credentials to merge * @returns #FALSE if no memory */ dbus_bool_t _dbus_credentials_add_credential (DBusCredentials *credentials, DBusCredentialType which, DBusCredentials *other_credentials) { if (which == DBUS_CREDENTIAL_UNIX_PROCESS_ID && other_credentials->unix_pid != DBUS_PID_UNSET) { if (!_dbus_credentials_add_unix_pid (credentials, other_credentials->unix_pid)) return FALSE; } else if (which == DBUS_CREDENTIAL_UNIX_USER_ID && other_credentials->unix_uid != DBUS_UID_UNSET) { if (!_dbus_credentials_add_unix_uid (credentials, other_credentials->unix_uid)) return FALSE; } else if (which == DBUS_CREDENTIAL_WINDOWS_SID && other_credentials->windows_sid != NULL) { if (!_dbus_credentials_add_windows_sid (credentials, other_credentials->windows_sid)) return FALSE; } else if (which == DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID && other_credentials->adt_audit_data != NULL) { if (!_dbus_credentials_add_adt_audit_data (credentials, other_credentials->adt_audit_data, other_credentials->adt_audit_data_size)) return FALSE; } return TRUE; } /** * Clear all credentials in the object. * * @param credentials the object */ void _dbus_credentials_clear (DBusCredentials *credentials) { credentials->unix_pid = DBUS_PID_UNSET; credentials->unix_uid = DBUS_UID_UNSET; dbus_free (credentials->windows_sid); credentials->windows_sid = NULL; dbus_free (credentials->adt_audit_data); credentials->adt_audit_data = NULL; credentials->adt_audit_data_size = 0; } /** * Copy a credentials object. * * @param credentials the object * @returns the copy or #NULL */ DBusCredentials* _dbus_credentials_copy (DBusCredentials *credentials) { DBusCredentials *copy; copy = _dbus_credentials_new (); if (copy == NULL) return NULL; if (!_dbus_credentials_add_credentials (copy, credentials)) { _dbus_credentials_unref (copy); return NULL; } return copy; } /** * Check whether the user-identifying credentials in two credentials * objects are identical. Credentials that are not related to the * user are ignored, but any kind of user ID credentials must be the * same (UNIX user ID, Windows user SID, etc.) and present in both * objects for the function to return #TRUE. * * @param credentials the object * @param other_credentials credentials to compare * @returns #TRUE if the two credentials refer to the same user */ dbus_bool_t _dbus_credentials_same_user (DBusCredentials *credentials, DBusCredentials *other_credentials) { /* both windows and unix user must be the same (though pretty much * in all conceivable cases, one will be unset) */ return credentials->unix_uid == other_credentials->unix_uid && ((!(credentials->windows_sid || other_credentials->windows_sid)) || (credentials->windows_sid && other_credentials->windows_sid && strcmp (credentials->windows_sid, other_credentials->windows_sid) == 0)); } /** @} */ /* tests in dbus-credentials-util.c */