1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 2/* dbus-credentials.c Credentials provable through authentication 3 * 4 * Copyright (C) 2007 Red Hat Inc. 5 * 6 * Licensed under the Academic Free License version 2.1 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 * 22 */ 23#include <config.h> 24#include <string.h> 25#include "dbus-credentials.h" 26#include "dbus-internals.h" 27 28/** 29 * @defgroup DBusCredentials Credentials provable through authentication 30 * @ingroup DBusInternals 31 * @brief DBusCredentials object 32 * 33 * Credentials are what you have to prove you have in order to 34 * authenticate. The main credentials right now are a unix user 35 * account, a Windows user account, or a UNIX process ID. 36 */ 37 38/** 39 * @defgroup DBusCredentialsInternals Credentials implementation details 40 * @ingroup DBusInternals 41 * @brief DBusCredentials implementation details 42 * 43 * Private details of credentials code. 44 * 45 * @{ 46 */ 47 48struct DBusCredentials { 49 int refcount; 50 dbus_uid_t unix_uid; 51 dbus_pid_t unix_pid; 52 char *windows_sid; 53 void *adt_audit_data; 54 dbus_int32_t adt_audit_data_size; 55}; 56 57/** @} */ 58 59/** 60 * @addtogroup DBusCredentials 61 * @{ 62 */ 63 64/** 65 * Creates a new credentials object. 66 * 67 * @returns the new object or #NULL if no memory 68 */ 69DBusCredentials* 70_dbus_credentials_new (void) 71{ 72 DBusCredentials *creds; 73 74 creds = dbus_new (DBusCredentials, 1); 75 if (creds == NULL) 76 return NULL; 77 78 creds->refcount = 1; 79 creds->unix_uid = DBUS_UID_UNSET; 80 creds->unix_pid = DBUS_PID_UNSET; 81 creds->windows_sid = NULL; 82 creds->adt_audit_data = NULL; 83 creds->adt_audit_data_size = 0; 84 85 return creds; 86} 87 88/** 89 * Creates a new object with credentials (user ID and process ID) from the current process. 90 * @returns the new object or #NULL if no memory 91 */ 92DBusCredentials* 93_dbus_credentials_new_from_current_process (void) 94{ 95 DBusCredentials *creds; 96 97 creds = _dbus_credentials_new (); 98 if (creds == NULL) 99 return NULL; 100 101 if (!_dbus_credentials_add_from_current_process (creds)) 102 { 103 _dbus_credentials_unref (creds); 104 return NULL; 105 } 106 107 return creds; 108} 109 110/** 111 * Increment refcount on credentials. 112 * 113 * @param credentials the object 114 */ 115void 116_dbus_credentials_ref (DBusCredentials *credentials) 117{ 118 _dbus_assert (credentials->refcount > 0); 119 credentials->refcount += 1; 120} 121 122/** 123 * Decrement refcount on credentials. 124 * 125 * @param credentials the object 126 */ 127void 128_dbus_credentials_unref (DBusCredentials *credentials) 129{ 130 _dbus_assert (credentials->refcount > 0); 131 132 credentials->refcount -= 1; 133 if (credentials->refcount == 0) 134 { 135 dbus_free (credentials->windows_sid); 136 dbus_free (credentials->adt_audit_data); 137 dbus_free (credentials); 138 } 139} 140 141/** 142 * Add a UNIX process ID to the credentials. 143 * 144 * @param credentials the object 145 * @param pid the process ID 146 * @returns #FALSE if no memory 147 */ 148dbus_bool_t 149_dbus_credentials_add_unix_pid (DBusCredentials *credentials, 150 dbus_pid_t pid) 151{ 152 credentials->unix_pid = pid; 153 return TRUE; 154} 155 156/** 157 * Add a UNIX user ID to the credentials. 158 * 159 * @param credentials the object 160 * @param uid the user ID 161 * @returns #FALSE if no memory 162 */ 163dbus_bool_t 164_dbus_credentials_add_unix_uid(DBusCredentials *credentials, 165 dbus_uid_t uid) 166{ 167 credentials->unix_uid = uid; 168 return TRUE; 169 170} 171 172/** 173 * Add a Windows user SID to the credentials. 174 * 175 * @param credentials the object 176 * @param windows_sid the user SID 177 * @returns #FALSE if no memory 178 */ 179dbus_bool_t 180_dbus_credentials_add_windows_sid (DBusCredentials *credentials, 181 const char *windows_sid) 182{ 183 char *copy; 184 185 copy = _dbus_strdup (windows_sid); 186 if (copy == NULL) 187 return FALSE; 188 189 dbus_free (credentials->windows_sid); 190 credentials->windows_sid = copy; 191 192 return TRUE; 193} 194 195/** 196 * Add ADT audit data to the credentials. 197 * 198 * @param credentials the object 199 * @param audit_data the audit data 200 * @param size the length of audit data 201 * @returns #FALSE if no memory 202 */ 203dbus_bool_t 204_dbus_credentials_add_adt_audit_data (DBusCredentials *credentials, 205 void *audit_data, 206 dbus_int32_t size) 207{ 208 void *copy; 209 copy = _dbus_memdup (audit_data, size); 210 if (copy == NULL) 211 return FALSE; 212 213 dbus_free (credentials->adt_audit_data); 214 credentials->adt_audit_data = copy; 215 credentials->adt_audit_data_size = size; 216 217 return TRUE; 218} 219 220/** 221 * Checks whether the given credential is present. 222 * 223 * @param credentials the object 224 * @param type the credential to check for 225 * @returns #TRUE if the credential is present 226 */ 227dbus_bool_t 228_dbus_credentials_include (DBusCredentials *credentials, 229 DBusCredentialType type) 230{ 231 switch (type) 232 { 233 case DBUS_CREDENTIAL_UNIX_PROCESS_ID: 234 return credentials->unix_pid != DBUS_PID_UNSET; 235 case DBUS_CREDENTIAL_UNIX_USER_ID: 236 return credentials->unix_uid != DBUS_UID_UNSET; 237 case DBUS_CREDENTIAL_WINDOWS_SID: 238 return credentials->windows_sid != NULL; 239 case DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID: 240 return credentials->adt_audit_data != NULL; 241 } 242 243 _dbus_assert_not_reached ("Unknown credential enum value"); 244 return FALSE; 245} 246 247/** 248 * Gets the UNIX process ID in the credentials, or #DBUS_PID_UNSET if 249 * the credentials object doesn't contain a process ID. 250 * 251 * @param credentials the object 252 * @returns UNIX process ID 253 */ 254dbus_pid_t 255_dbus_credentials_get_unix_pid (DBusCredentials *credentials) 256{ 257 return credentials->unix_pid; 258} 259 260/** 261 * Gets the UNIX user ID in the credentials, or #DBUS_UID_UNSET if 262 * the credentials object doesn't contain a user ID. 263 * 264 * @param credentials the object 265 * @returns UNIX user ID 266 */ 267dbus_uid_t 268_dbus_credentials_get_unix_uid (DBusCredentials *credentials) 269{ 270 return credentials->unix_uid; 271} 272 273/** 274 * Gets the Windows user SID in the credentials, or #NULL if 275 * the credentials object doesn't contain a Windows user SID. 276 * 277 * @param credentials the object 278 * @returns Windows user SID 279 */ 280const char* 281_dbus_credentials_get_windows_sid (DBusCredentials *credentials) 282{ 283 return credentials->windows_sid; 284} 285 286/** 287 * Gets the ADT audit data in the credentials, or #NULL if 288 * the credentials object doesn't contain ADT audit data. 289 * 290 * @param credentials the object 291 * @returns Solaris ADT audit data 292 */ 293void * 294_dbus_credentials_get_adt_audit_data (DBusCredentials *credentials) 295{ 296 return credentials->adt_audit_data; 297} 298 299/** 300 * Gets the ADT audit data size in the credentials, or 0 if 301 * the credentials object doesn't contain ADT audit data. 302 * 303 * @param credentials the object 304 * @returns Solaris ADT audit data size 305 */ 306dbus_int32_t 307_dbus_credentials_get_adt_audit_data_size (DBusCredentials *credentials) 308{ 309 return credentials->adt_audit_data_size; 310} 311 312/** 313 * Checks whether the first credentials object contains 314 * all the credentials found in the second credentials object. 315 * 316 * @param credentials the object 317 * @param possible_subset see if credentials in here are also in the first arg 318 * @returns #TRUE if second arg is contained in first 319 */ 320dbus_bool_t 321_dbus_credentials_are_superset (DBusCredentials *credentials, 322 DBusCredentials *possible_subset) 323{ 324 return 325 (possible_subset->unix_pid == DBUS_PID_UNSET || 326 possible_subset->unix_pid == credentials->unix_pid) && 327 (possible_subset->unix_uid == DBUS_UID_UNSET || 328 possible_subset->unix_uid == credentials->unix_uid) && 329 (possible_subset->windows_sid == NULL || 330 (credentials->windows_sid && strcmp (possible_subset->windows_sid, 331 credentials->windows_sid) == 0)) && 332 (possible_subset->adt_audit_data == NULL || 333 (credentials->adt_audit_data && memcmp (possible_subset->adt_audit_data, 334 credentials->adt_audit_data, 335 credentials->adt_audit_data_size) == 0)); 336} 337 338/** 339 * Checks whether a credentials object contains anything. 340 * 341 * @param credentials the object 342 * @returns #TRUE if there are no credentials in the object 343 */ 344dbus_bool_t 345_dbus_credentials_are_empty (DBusCredentials *credentials) 346{ 347 return 348 credentials->unix_pid == DBUS_PID_UNSET && 349 credentials->unix_uid == DBUS_UID_UNSET && 350 credentials->windows_sid == NULL && 351 credentials->adt_audit_data == NULL; 352} 353 354/** 355 * Checks whether a credentials object contains a user identity. 356 * 357 * @param credentials the object 358 * @returns #TRUE if there are no user identities in the object 359 */ 360dbus_bool_t 361_dbus_credentials_are_anonymous (DBusCredentials *credentials) 362{ 363 return 364 credentials->unix_uid == DBUS_UID_UNSET && 365 credentials->windows_sid == NULL; 366} 367 368/** 369 * Merge all credentials found in the second object into the first object, 370 * overwriting the first object if there are any overlaps. 371 * 372 * @param credentials the object 373 * @param other_credentials credentials to merge 374 * @returns #FALSE if no memory 375 */ 376dbus_bool_t 377_dbus_credentials_add_credentials (DBusCredentials *credentials, 378 DBusCredentials *other_credentials) 379{ 380 return 381 _dbus_credentials_add_credential (credentials, 382 DBUS_CREDENTIAL_UNIX_PROCESS_ID, 383 other_credentials) && 384 _dbus_credentials_add_credential (credentials, 385 DBUS_CREDENTIAL_UNIX_USER_ID, 386 other_credentials) && 387 _dbus_credentials_add_credential (credentials, 388 DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID, 389 other_credentials) && 390 _dbus_credentials_add_credential (credentials, 391 DBUS_CREDENTIAL_WINDOWS_SID, 392 other_credentials); 393} 394 395/** 396 * Merge the given credential found in the second object into the first object, 397 * overwriting the first object's value for that credential. 398 * 399 * Does nothing if the second object does not contain the specified credential. 400 * i.e., will never delete a credential from the first object. 401 * 402 * @param credentials the object 403 * @param which the credential to overwrite 404 * @param other_credentials credentials to merge 405 * @returns #FALSE if no memory 406 */ 407dbus_bool_t 408_dbus_credentials_add_credential (DBusCredentials *credentials, 409 DBusCredentialType which, 410 DBusCredentials *other_credentials) 411{ 412 if (which == DBUS_CREDENTIAL_UNIX_PROCESS_ID && 413 other_credentials->unix_pid != DBUS_PID_UNSET) 414 { 415 if (!_dbus_credentials_add_unix_pid (credentials, other_credentials->unix_pid)) 416 return FALSE; 417 } 418 else if (which == DBUS_CREDENTIAL_UNIX_USER_ID && 419 other_credentials->unix_uid != DBUS_UID_UNSET) 420 { 421 if (!_dbus_credentials_add_unix_uid (credentials, other_credentials->unix_uid)) 422 return FALSE; 423 } 424 else if (which == DBUS_CREDENTIAL_WINDOWS_SID && 425 other_credentials->windows_sid != NULL) 426 { 427 if (!_dbus_credentials_add_windows_sid (credentials, other_credentials->windows_sid)) 428 return FALSE; 429 } 430 else if (which == DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID && 431 other_credentials->adt_audit_data != NULL) 432 { 433 if (!_dbus_credentials_add_adt_audit_data (credentials, other_credentials->adt_audit_data, other_credentials->adt_audit_data_size)) 434 return FALSE; 435 } 436 437 return TRUE; 438} 439 440/** 441 * Clear all credentials in the object. 442 * 443 * @param credentials the object 444 */ 445void 446_dbus_credentials_clear (DBusCredentials *credentials) 447{ 448 credentials->unix_pid = DBUS_PID_UNSET; 449 credentials->unix_uid = DBUS_UID_UNSET; 450 dbus_free (credentials->windows_sid); 451 credentials->windows_sid = NULL; 452 dbus_free (credentials->adt_audit_data); 453 credentials->adt_audit_data = NULL; 454 credentials->adt_audit_data_size = 0; 455} 456 457/** 458 * Copy a credentials object. 459 * 460 * @param credentials the object 461 * @returns the copy or #NULL 462 */ 463DBusCredentials* 464_dbus_credentials_copy (DBusCredentials *credentials) 465{ 466 DBusCredentials *copy; 467 468 copy = _dbus_credentials_new (); 469 if (copy == NULL) 470 return NULL; 471 472 if (!_dbus_credentials_add_credentials (copy, credentials)) 473 { 474 _dbus_credentials_unref (copy); 475 return NULL; 476 } 477 478 return copy; 479} 480 481/** 482 * Check whether the user-identifying credentials in two credentials 483 * objects are identical. Credentials that are not related to the 484 * user are ignored, but any kind of user ID credentials must be the 485 * same (UNIX user ID, Windows user SID, etc.) and present in both 486 * objects for the function to return #TRUE. 487 * 488 * @param credentials the object 489 * @param other_credentials credentials to compare 490 * @returns #TRUE if the two credentials refer to the same user 491 */ 492dbus_bool_t 493_dbus_credentials_same_user (DBusCredentials *credentials, 494 DBusCredentials *other_credentials) 495{ 496 /* both windows and unix user must be the same (though pretty much 497 * in all conceivable cases, one will be unset) 498 */ 499 return credentials->unix_uid == other_credentials->unix_uid && 500 ((!(credentials->windows_sid || other_credentials->windows_sid)) || 501 (credentials->windows_sid && other_credentials->windows_sid && 502 strcmp (credentials->windows_sid, other_credentials->windows_sid) == 0)); 503} 504 505/** 506 * Convert the credentials in this object to a human-readable 507 * string format, and append to the given string. 508 * 509 * @param credentials the object 510 * @param string append to this string 511 * @returns #FALSE if no memory 512 */ 513dbus_bool_t 514_dbus_credentials_to_string_append (DBusCredentials *credentials, 515 DBusString *string) 516{ 517 dbus_bool_t join; 518 519 join = FALSE; 520 if (credentials->unix_uid != DBUS_UID_UNSET) 521 { 522 if (!_dbus_string_append_printf (string, "uid=" DBUS_UID_FORMAT, credentials->unix_uid)) 523 goto oom; 524 join = TRUE; 525 } 526 if (credentials->unix_pid != DBUS_PID_UNSET) 527 { 528 if (!_dbus_string_append_printf (string, "%spid=" DBUS_PID_FORMAT, join ? " " : "", credentials->unix_pid)) 529 goto oom; 530 join = TRUE; 531 } 532 else 533 join = FALSE; 534 if (credentials->windows_sid != NULL) 535 { 536 if (!_dbus_string_append_printf (string, "%ssid=%s", join ? " " : "", credentials->windows_sid)) 537 goto oom; 538 join = TRUE; 539 } 540 else 541 join = FALSE; 542 543 return TRUE; 544oom: 545 return FALSE; 546} 547 548/** @} */ 549 550/* tests in dbus-credentials-util.c */ 551