gcredentials.c 16.8 KB
Newer Older
1 2
/* GDBus - GLib D-Bus Library
 *
3
 * Copyright (C) 2008-2010 Red Hat, Inc.
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General
 * Public License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 * Author: David Zeuthen <davidz@redhat.com>
 */

#include "config.h"

#include <stdlib.h>
Dan Winship's avatar
Dan Winship committed
26
#include <string.h>
27

Matthias Clasen's avatar
Matthias Clasen committed
28 29 30
#include <gobject/gvaluecollector.h>

#include "gcredentials.h"
31
#include "gcredentialsprivate.h"
Dan Winship's avatar
Dan Winship committed
32
#include "gnetworking.h"
Matthias Clasen's avatar
Matthias Clasen committed
33
#include "gioerror.h"
34
#include "gioenumtypes.h"
Matthias Clasen's avatar
Matthias Clasen committed
35

David Zeuthen's avatar
David Zeuthen committed
36 37
#include "glibintl.h"

38 39
/**
 * SECTION:gcredentials
David Zeuthen's avatar
David Zeuthen committed
40 41
 * @short_description: An object containing credentials
 * @include: gio/gio.h
42
 *
43 44 45
 * The #GCredentials type is a reference-counted wrapper for native
 * credentials. This information is typically used for identifying,
 * authenticating and authorizing other processes.
46 47 48 49
 *
 * Some operating systems supports looking up the credentials of the
 * remote peer of a communication endpoint - see e.g.
 * g_socket_get_credentials().
50
 *
51 52
 * Some operating systems supports securely sending and receiving
 * credentials over a Unix Domain Socket, see
53 54
 * #GUnixCredentialsMessage, g_unix_connection_send_credentials() and
 * g_unix_connection_receive_credentials() for details.
55
 *
56 57
 * On Linux, the native credential type is a struct ucred - see the
 * unix(7) man page for details. This corresponds to
58
 * %G_CREDENTIALS_TYPE_LINUX_UCRED.
59
 *
60
 * On FreeBSD, Debian GNU/kFreeBSD, and GNU/Hurd, the native
61
 * credential type is a struct cmsgcred. This corresponds
62
 * to %G_CREDENTIALS_TYPE_FREEBSD_CMSGCRED.
63
 *
64
 * On OpenBSD, the native credential type is a struct sockpeercred.
65
 * This corresponds to %G_CREDENTIALS_TYPE_OPENBSD_SOCKPEERCRED.
66 67
 *
 * On Solaris (including OpenSolaris and its derivatives), the native
68
 * credential type is a ucred_t. This corresponds to
69
 * %G_CREDENTIALS_TYPE_SOLARIS_UCRED.
70 71
 */

72 73 74 75 76 77 78 79 80
/**
 * GCredentials:
 *
 * The #GCredentials structure contains only private data and
 * should only be accessed using the provided API.
 *
 * Since: 2.26
 */
struct _GCredentials
81
{
82 83 84
  /*< private >*/
  GObject parent_instance;

85
#if G_CREDENTIALS_USE_LINUX_UCRED
86
  struct ucred native;
87
#elif G_CREDENTIALS_USE_FREEBSD_CMSGCRED
88
  struct cmsgcred native;
89
#elif G_CREDENTIALS_USE_OPENBSD_SOCKPEERCRED
90
  struct sockpeercred native;
91 92
#elif G_CREDENTIALS_USE_SOLARIS_UCRED
  ucred_t *native;
93
#else
94 95 96
  #ifdef __GNUC__
  #warning Please add GCredentials support for your OS
  #endif
97
#endif
98 99
};

100 101 102 103 104 105 106 107 108 109 110 111 112
/**
 * GCredentialsClass:
 *
 * Class structure for #GCredentials.
 *
 * Since: 2.26
 */
struct _GCredentialsClass
{
  /*< private >*/
  GObjectClass parent_class;
};

113 114 115 116 117
G_DEFINE_TYPE (GCredentials, g_credentials, G_TYPE_OBJECT);

static void
g_credentials_finalize (GObject *object)
{
118 119 120 121 122
#if G_CREDENTIALS_USE_SOLARIS_UCRED
  GCredentials *credentials = G_CREDENTIALS (object);

  ucred_free (credentials->native);
#endif
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140

  if (G_OBJECT_CLASS (g_credentials_parent_class)->finalize != NULL)
    G_OBJECT_CLASS (g_credentials_parent_class)->finalize (object);
}


static void
g_credentials_class_init (GCredentialsClass *klass)
{
  GObjectClass *gobject_class;

  gobject_class = G_OBJECT_CLASS (klass);
  gobject_class->finalize = g_credentials_finalize;
}

static void
g_credentials_init (GCredentials *credentials)
{
141
#if G_CREDENTIALS_USE_LINUX_UCRED
142
  credentials->native.pid = getpid ();
143 144
  credentials->native.uid = geteuid ();
  credentials->native.gid = getegid ();
145
#elif G_CREDENTIALS_USE_FREEBSD_CMSGCRED
146 147 148 149
  memset (&credentials->native, 0, sizeof (struct cmsgcred));
  credentials->native.cmcred_pid  = getpid ();
  credentials->native.cmcred_euid = geteuid ();
  credentials->native.cmcred_gid  = getegid ();
150
#elif G_CREDENTIALS_USE_OPENBSD_SOCKPEERCRED
151 152 153
  credentials->native.pid = getpid ();
  credentials->native.uid = geteuid ();
  credentials->native.gid = getegid ();
154 155
#elif G_CREDENTIALS_USE_SOLARIS_UCRED
  credentials->native = ucred_get (P_MYID);
156
#endif
157 158 159 160 161 162 163
}

/* ---------------------------------------------------------------------------------------------------- */

/**
 * g_credentials_new:
 *
164 165
 * Creates a new #GCredentials object with credentials matching the
 * the current process.
166 167
 *
 * Returns: A #GCredentials. Free with g_object_unref().
168 169
 *
 * Since: 2.26
170 171 172 173 174 175 176 177 178 179 180 181 182
 */
GCredentials *
g_credentials_new (void)
{
  return g_object_new (G_TYPE_CREDENTIALS, NULL);
}

/* ---------------------------------------------------------------------------------------------------- */

/**
 * g_credentials_to_string:
 * @credentials: A #GCredentials object.
 *
183 184 185
 * Creates a human-readable textual representation of @credentials
 * that can be used in logging and debug messages. The format of the
 * returned string may change in future GLib release.
186 187
 *
 * Returns: A string that should be freed with g_free().
188 189
 *
 * Since: 2.26
190 191 192 193 194 195 196 197 198
 */
gchar *
g_credentials_to_string (GCredentials *credentials)
{
  GString *ret;

  g_return_val_if_fail (G_IS_CREDENTIALS (credentials), NULL);

  ret = g_string_new ("GCredentials:");
199
#if G_CREDENTIALS_USE_LINUX_UCRED
200 201 202 203 204 205 206
  g_string_append (ret, "linux-ucred:");
  if (credentials->native.pid != -1)
    g_string_append_printf (ret, "pid=%" G_GINT64_FORMAT ",", (gint64) credentials->native.pid);
  if (credentials->native.uid != -1)
    g_string_append_printf (ret, "uid=%" G_GINT64_FORMAT ",", (gint64) credentials->native.uid);
  if (credentials->native.gid != -1)
    g_string_append_printf (ret, "gid=%" G_GINT64_FORMAT ",", (gint64) credentials->native.gid);
207 208
  if (ret->str[ret->len - 1] == ',')
    ret->str[ret->len - 1] = '\0';
209
#elif G_CREDENTIALS_USE_FREEBSD_CMSGCRED
210 211 212 213 214 215 216
  g_string_append (ret, "freebsd-cmsgcred:");
  if (credentials->native.cmcred_pid != -1)
    g_string_append_printf (ret, "pid=%" G_GINT64_FORMAT ",", (gint64) credentials->native.cmcred_pid);
  if (credentials->native.cmcred_euid != -1)
    g_string_append_printf (ret, "uid=%" G_GINT64_FORMAT ",", (gint64) credentials->native.cmcred_euid);
  if (credentials->native.cmcred_gid != -1)
    g_string_append_printf (ret, "gid=%" G_GINT64_FORMAT ",", (gint64) credentials->native.cmcred_gid);
217
#elif G_CREDENTIALS_USE_OPENBSD_SOCKPEERCRED
218 219 220 221 222 223 224 225 226
  g_string_append (ret, "openbsd-sockpeercred:");
  if (credentials->native.pid != -1)
    g_string_append_printf (ret, "pid=%" G_GINT64_FORMAT ",", (gint64) credentials->native.pid);
  if (credentials->native.uid != -1)
    g_string_append_printf (ret, "uid=%" G_GINT64_FORMAT ",", (gint64) credentials->native.uid);
  if (credentials->native.gid != -1)
    g_string_append_printf (ret, "gid=%" G_GINT64_FORMAT ",", (gint64) credentials->native.gid);
  if (ret->str[ret->len - 1] == ',')
    ret->str[ret->len - 1] = '\0';
227 228 229 230 231 232 233 234 235 236 237 238 239
#elif G_CREDENTIALS_USE_SOLARIS_UCRED
  g_string_append (ret, "solaris-ucred:");
  {
    id_t id;
    if ((id = ucred_getpid (credentials->native)) != -1)
      g_string_append_printf (ret, "pid=%" G_GINT64_FORMAT ",", (gint64) id);
    if ((id = ucred_geteuid (credentials->native)) != -1)
      g_string_append_printf (ret, "uid=%" G_GINT64_FORMAT ",", (gint64) id);
    if ((id = ucred_getegid (credentials->native)) != -1)
      g_string_append_printf (ret, "gid=%" G_GINT64_FORMAT ",", (gint64) id);
    if (ret->str[ret->len - 1] == ',')
      ret->str[ret->len - 1] = '\0';
  }
240 241 242
#else
  g_string_append (ret, "unknown");
#endif
243 244 245 246 247 248 249

  return g_string_free (ret, FALSE);
}

/* ---------------------------------------------------------------------------------------------------- */

/**
250
 * g_credentials_is_same_user:
251
 * @credentials: A #GCredentials.
252 253
 * @other_credentials: A #GCredentials.
 * @error: Return location for error or %NULL.
254
 *
255
 * Checks if @credentials and @other_credentials is the same user.
256
 *
257 258 259 260 261
 * This operation can fail if #GCredentials is not supported on the
 * the OS.
 *
 * Returns: %TRUE if @credentials and @other_credentials has the same
 * user, %FALSE otherwise or if @error is set.
262 263
 *
 * Since: 2.26
264 265
 */
gboolean
266 267 268
g_credentials_is_same_user (GCredentials  *credentials,
                            GCredentials  *other_credentials,
                            GError       **error)
269
{
270 271
  gboolean ret;

272
  g_return_val_if_fail (G_IS_CREDENTIALS (credentials), FALSE);
273 274
  g_return_val_if_fail (G_IS_CREDENTIALS (other_credentials), FALSE);
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
275

276
  ret = FALSE;
277
#if G_CREDENTIALS_USE_LINUX_UCRED
278
  if (credentials->native.uid == other_credentials->native.uid)
279
    ret = TRUE;
280
#elif G_CREDENTIALS_USE_FREEBSD_CMSGCRED
281 282
  if (credentials->native.cmcred_euid == other_credentials->native.cmcred_euid)
    ret = TRUE;
283
#elif G_CREDENTIALS_USE_OPENBSD_SOCKPEERCRED
284 285
  if (credentials->native.uid == other_credentials->native.uid)
    ret = TRUE;
286 287 288
#elif G_CREDENTIALS_USE_SOLARIS_UCRED
  if (ucred_geteuid (credentials->native) == ucred_geteuid (other_credentials->native))
    ret = TRUE;
289 290 291 292 293 294
#else
  g_set_error_literal (error,
                       G_IO_ERROR,
                       G_IO_ERROR_NOT_SUPPORTED,
                       _("GCredentials is not implemented on this OS"));
#endif
295

296
  return ret;
297 298
}

299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
static gboolean
credentials_native_type_check (GCredentialsType  requested_type,
                               const char       *op)
{
  GEnumClass *enum_class;
  GEnumValue *requested;
#if G_CREDENTIALS_SUPPORTED
  GEnumValue *supported;
#endif

#if G_CREDENTIALS_SUPPORTED
  if (requested_type == G_CREDENTIALS_NATIVE_TYPE)
    return TRUE;
#endif

  enum_class = g_type_class_ref (g_credentials_type_get_type ());
  requested = g_enum_get_value (enum_class, requested_type);

#if G_CREDENTIALS_SUPPORTED
  supported = g_enum_get_value (enum_class, G_CREDENTIALS_NATIVE_TYPE);
  g_warning ("g_credentials_%s_native: Trying to %s credentials of type %s "
             "but only %s is supported on this platform.",
             op, op,
             requested ? requested->value_name : "(unknown)",
             supported->value_name);
#else
  g_warning ("g_credentials_%s_native: Trying to %s credentials of type %s "
             "but there is no support for GCredentials on this platform.",
             op, op,
             requested ? requested->value_name : "(unknown)");
#endif

  g_type_class_unref (enum_class);
  return FALSE;
}

335
/**
336
 * g_credentials_get_native: (skip)
337
 * @credentials: A #GCredentials.
338
 * @native_type: The type of native credentials to get.
339
 *
340
 * Gets a pointer to native credentials of type @native_type from
341
 * @credentials.
342
 *
343 344 345 346 347 348 349 350 351
 * It is a programming error (which will cause an warning to be
 * logged) to use this method if there is no #GCredentials support for
 * the OS or if @native_type isn't supported by the OS.
 *
 * Returns: The pointer to native credentials or %NULL if the
 * operation there is no #GCredentials support for the OS or if
 * @native_type isn't supported by the OS. Do not free the returned
 * data, it is owned by @credentials.
 *
352
 * Since: 2.26
353
 */
354
gpointer
355 356
g_credentials_get_native (GCredentials     *credentials,
                          GCredentialsType  native_type)
357
{
358
  g_return_val_if_fail (G_IS_CREDENTIALS (credentials), NULL);
359

360 361 362
  if (!credentials_native_type_check (native_type, "get"))
    return NULL;

363 364 365
#if G_CREDENTIALS_USE_SOLARIS_UCRED
  return credentials->native;
#elif G_CREDENTIALS_SUPPORTED
366
  return &credentials->native;
367
#else
368
  g_assert_not_reached ();
369
#endif
370 371 372
}

/**
373
 * g_credentials_set_native:
374
 * @credentials: A #GCredentials.
375
 * @native_type: The type of native credentials to set.
376
 * @native: A pointer to native credentials.
377
 *
378 379
 * Copies the native credentials of type @native_type from @native
 * into @credentials.
380 381 382
 *
 * It is a programming error (which will cause an warning to be
 * logged) to use this method if there is no #GCredentials support for
383
 * the OS or if @native_type isn't supported by the OS.
384 385
 *
 * Since: 2.26
386 387
 */
void
388 389 390
g_credentials_set_native (GCredentials     *credentials,
                          GCredentialsType  native_type,
                          gpointer          native)
391
{
392 393 394
  if (!credentials_native_type_check (native_type, "set"))
    return;

395 396 397
#if G_CREDENTIALS_USE_SOLARIS_UCRED
  memcpy (credentials->native, native, ucred_size ());
#elif G_CREDENTIALS_SUPPORTED
398
  memcpy (&credentials->native, native, sizeof (credentials->native));
399
#else
400
  g_assert_not_reached ();
401
#endif
402 403 404 405
}

/* ---------------------------------------------------------------------------------------------------- */

406
#ifdef G_OS_UNIX
407
/**
408 409 410
 * g_credentials_get_unix_user:
 * @credentials: A #GCredentials
 * @error: Return location for error or %NULL.
411
 *
412 413
 * Tries to get the UNIX user identifier from @credentials. This
 * method is only available on UNIX platforms.
414
 *
415 416 417
 * This operation can fail if #GCredentials is not supported on the
 * OS or if the native credentials type does not contain information
 * about the UNIX user.
418
 *
419
 * Returns: The UNIX user identifier or -1 if @error is set.
420 421
 *
 * Since: 2.26
422
 */
423 424 425
uid_t
g_credentials_get_unix_user (GCredentials    *credentials,
                             GError         **error)
426
{
427 428
  uid_t ret;

429
  g_return_val_if_fail (G_IS_CREDENTIALS (credentials), -1);
430
  g_return_val_if_fail (error == NULL || *error == NULL, -1);
431

432
#if G_CREDENTIALS_USE_LINUX_UCRED
433
  ret = credentials->native.uid;
434
#elif G_CREDENTIALS_USE_FREEBSD_CMSGCRED
435
  ret = credentials->native.cmcred_euid;
436
#elif G_CREDENTIALS_USE_OPENBSD_SOCKPEERCRED
437
  ret = credentials->native.uid;
438 439
#elif G_CREDENTIALS_USE_SOLARIS_UCRED
  ret = ucred_geteuid (credentials->native);
440 441 442 443 444
#else
  ret = -1;
  g_set_error_literal (error,
                       G_IO_ERROR,
                       G_IO_ERROR_NOT_SUPPORTED,
445
                       _("There is no GCredentials support for your platform"));
446
#endif
447

448 449
  return ret;
}
450

451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475
/**
 * g_credentials_get_unix_pid:
 * @credentials: A #GCredentials
 * @error: Return location for error or %NULL.
 *
 * Tries to get the UNIX process identifier from @credentials. This
 * method is only available on UNIX platforms.
 *
 * This operation can fail if #GCredentials is not supported on the
 * OS or if the native credentials type does not contain information
 * about the UNIX process ID.
 *
 * Returns: The UNIX process ID, or -1 if @error is set.
 *
 * Since: 2.36
 */
pid_t
g_credentials_get_unix_pid (GCredentials    *credentials,
                            GError         **error)
{
  pid_t ret;

  g_return_val_if_fail (G_IS_CREDENTIALS (credentials), -1);
  g_return_val_if_fail (error == NULL || *error == NULL, -1);

476
#if G_CREDENTIALS_USE_LINUX_UCRED
477
  ret = credentials->native.pid;
478
#elif G_CREDENTIALS_USE_FREEBSD_CMSGCRED
479
  ret = credentials->native.cmcred_pid;
480
#elif G_CREDENTIALS_USE_OPENBSD_SOCKPEERCRED
481
  ret = credentials->native.pid;
482 483
#elif G_CREDENTIALS_USE_SOLARIS_UCRED
  ret = ucred_getpid (credentials->native);
484 485 486 487 488 489 490 491 492 493 494
#else
  ret = -1;
  g_set_error_literal (error,
                       G_IO_ERROR,
                       G_IO_ERROR_NOT_SUPPORTED,
                       _("GCredentials does not contain a process ID on this OS"));
#endif

  return ret;
}

495
/**
496
 * g_credentials_set_unix_user:
497
 * @credentials: A #GCredentials.
498 499 500 501 502
 * @uid: The UNIX user identifier to set.
 * @error: Return location for error or %NULL.
 *
 * Tries to set the UNIX user identifier on @credentials. This method
 * is only available on UNIX platforms.
503
 *
504 505
 * This operation can fail if #GCredentials is not supported on the
 * OS or if the native credentials type does not contain information
506 507
 * about the UNIX user. It can also fail if the OS does not allow the
 * use of "spoofed" credentials.
508
 *
509
 * Returns: %TRUE if @uid was set, %FALSE if error is set.
510 511
 *
 * Since: 2.26
512 513
 */
gboolean
514 515 516
g_credentials_set_unix_user (GCredentials    *credentials,
                             uid_t            uid,
                             GError         **error)
517
{
518 519
  gboolean ret;

520
  g_return_val_if_fail (G_IS_CREDENTIALS (credentials), FALSE);
521 522
  g_return_val_if_fail (uid != -1, FALSE);
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
523

524
  ret = FALSE;
525
#if G_CREDENTIALS_USE_LINUX_UCRED
526
  credentials->native.uid = uid;
527
  ret = TRUE;
528
#elif G_CREDENTIALS_USE_FREEBSD_CMSGCRED
529 530
  credentials->native.cmcred_euid = uid;
  ret = TRUE;
531
#elif G_CREDENTIALS_USE_OPENBSD_SOCKPEERCRED
532 533
  credentials->native.uid = uid;
  ret = TRUE;
534 535 536 537 538 539
#elif !G_CREDENTIALS_SPOOFING_SUPPORTED
  g_set_error_literal (error,
                       G_IO_ERROR,
                       G_IO_ERROR_PERMISSION_DENIED,
                       _("Credentials spoofing is not possible on this OS"));
  ret = FALSE;
540 541 542 543 544
#else
  g_set_error_literal (error,
                       G_IO_ERROR,
                       G_IO_ERROR_NOT_SUPPORTED,
                       _("GCredentials is not implemented on this OS"));
545
  ret = FALSE;
546
#endif
547

548
  return ret;
549
}
550

551
#endif /* G_OS_UNIX */