GCredentials: add getter/setter for the Unix process ID
[platform/upstream/glib.git] / gio / gcredentials.c
1 /* GDBus - GLib D-Bus Library
2  *
3  * Copyright (C) 2008-2010 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author: David Zeuthen <davidz@redhat.com>
21  */
22
23 #include "config.h"
24
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include <gobject/gvaluecollector.h>
29
30 #include "gcredentials.h"
31 #include "gnetworking.h"
32 #include "gioerror.h"
33
34 #include "glibintl.h"
35
36 /**
37  * SECTION:gcredentials
38  * @short_description: An object containing credentials
39  * @include: gio/gio.h
40  *
41  * The #GCredentials type is a reference-counted wrapper for native
42  * credentials. This information is typically used for identifying,
43  * authenticating and authorizing other processes.
44  *
45  * Some operating systems supports looking up the credentials of the
46  * remote peer of a communication endpoint - see e.g.
47  * g_socket_get_credentials().
48  *
49  * Some operating systems supports securely sending and receiving
50  * credentials over a Unix Domain Socket, see
51  * #GUnixCredentialsMessage, g_unix_connection_send_credentials() and
52  * g_unix_connection_receive_credentials() for details.
53  *
54  * On Linux, the native credential type is a <type>struct ucred</type>
55  * - see the
56  * <citerefentry><refentrytitle>unix</refentrytitle><manvolnum>7</manvolnum></citerefentry>
57  * man page for details. This corresponds to
58  * %G_CREDENTIALS_TYPE_LINUX_UCRED.
59  *
60  * On FreeBSD, the native credential type is a <type>struct cmsgcred</type>.
61  * This corresponds to %G_CREDENTIALS_TYPE_FREEBSD_CMSGCRED.
62  *
63  * On OpenBSD, the native credential type is a <type>struct sockpeercred</type>.
64  * This corresponds to %G_CREDENTIALS_TYPE_OPENBSD_SOCKPEERCRED.
65  */
66
67 /**
68  * GCredentials:
69  *
70  * The #GCredentials structure contains only private data and
71  * should only be accessed using the provided API.
72  *
73  * Since: 2.26
74  */
75 struct _GCredentials
76 {
77   /*< private >*/
78   GObject parent_instance;
79
80 #ifdef __linux__
81   struct ucred native;
82 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
83   struct cmsgcred native;
84 #elif defined(__OpenBSD__)
85   struct sockpeercred native;
86 #else
87 #ifdef __GNUC__
88 #warning Please add GCredentials support for your OS
89 #endif
90 #endif
91 };
92
93 /**
94  * GCredentialsClass:
95  *
96  * Class structure for #GCredentials.
97  *
98  * Since: 2.26
99  */
100 struct _GCredentialsClass
101 {
102   /*< private >*/
103   GObjectClass parent_class;
104 };
105
106 G_DEFINE_TYPE (GCredentials, g_credentials, G_TYPE_OBJECT);
107
108 static void
109 g_credentials_finalize (GObject *object)
110 {
111   G_GNUC_UNUSED GCredentials *credentials = G_CREDENTIALS (object);
112
113   if (G_OBJECT_CLASS (g_credentials_parent_class)->finalize != NULL)
114     G_OBJECT_CLASS (g_credentials_parent_class)->finalize (object);
115 }
116
117
118 static void
119 g_credentials_class_init (GCredentialsClass *klass)
120 {
121   GObjectClass *gobject_class;
122
123   gobject_class = G_OBJECT_CLASS (klass);
124   gobject_class->finalize = g_credentials_finalize;
125 }
126
127 static void
128 g_credentials_init (GCredentials *credentials)
129 {
130 #ifdef __linux__
131   credentials->native.pid = getpid ();
132   credentials->native.uid = geteuid ();
133   credentials->native.gid = getegid ();
134 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
135   memset (&credentials->native, 0, sizeof (struct cmsgcred));
136   credentials->native.cmcred_pid  = getpid ();
137   credentials->native.cmcred_euid = geteuid ();
138   credentials->native.cmcred_gid  = getegid ();
139 #elif defined(__OpenBSD__)
140   credentials->native.pid = getpid ();
141   credentials->native.uid = geteuid ();
142   credentials->native.gid = getegid ();
143 #endif
144 }
145
146 /* ---------------------------------------------------------------------------------------------------- */
147
148 /**
149  * g_credentials_new:
150  *
151  * Creates a new #GCredentials object with credentials matching the
152  * the current process.
153  *
154  * Returns: A #GCredentials. Free with g_object_unref().
155  *
156  * Since: 2.26
157  */
158 GCredentials *
159 g_credentials_new (void)
160 {
161   return g_object_new (G_TYPE_CREDENTIALS, NULL);
162 }
163
164 /* ---------------------------------------------------------------------------------------------------- */
165
166 /**
167  * g_credentials_to_string:
168  * @credentials: A #GCredentials object.
169  *
170  * Creates a human-readable textual representation of @credentials
171  * that can be used in logging and debug messages. The format of the
172  * returned string may change in future GLib release.
173  *
174  * Returns: A string that should be freed with g_free().
175  *
176  * Since: 2.26
177  */
178 gchar *
179 g_credentials_to_string (GCredentials *credentials)
180 {
181   GString *ret;
182
183   g_return_val_if_fail (G_IS_CREDENTIALS (credentials), NULL);
184
185   ret = g_string_new ("GCredentials:");
186 #ifdef __linux__
187   g_string_append (ret, "linux-ucred:");
188   if (credentials->native.pid != -1)
189     g_string_append_printf (ret, "pid=%" G_GINT64_FORMAT ",", (gint64) credentials->native.pid);
190   if (credentials->native.uid != -1)
191     g_string_append_printf (ret, "uid=%" G_GINT64_FORMAT ",", (gint64) credentials->native.uid);
192   if (credentials->native.gid != -1)
193     g_string_append_printf (ret, "gid=%" G_GINT64_FORMAT ",", (gint64) credentials->native.gid);
194   if (ret->str[ret->len - 1] == ',')
195     ret->str[ret->len - 1] = '\0';
196 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
197   g_string_append (ret, "freebsd-cmsgcred:");
198   if (credentials->native.cmcred_pid != -1)
199     g_string_append_printf (ret, "pid=%" G_GINT64_FORMAT ",", (gint64) credentials->native.cmcred_pid);
200   if (credentials->native.cmcred_euid != -1)
201     g_string_append_printf (ret, "uid=%" G_GINT64_FORMAT ",", (gint64) credentials->native.cmcred_euid);
202   if (credentials->native.cmcred_gid != -1)
203     g_string_append_printf (ret, "gid=%" G_GINT64_FORMAT ",", (gint64) credentials->native.cmcred_gid);
204 #elif defined(__OpenBSD__)
205   g_string_append (ret, "openbsd-sockpeercred:");
206   if (credentials->native.pid != -1)
207     g_string_append_printf (ret, "pid=%" G_GINT64_FORMAT ",", (gint64) credentials->native.pid);
208   if (credentials->native.uid != -1)
209     g_string_append_printf (ret, "uid=%" G_GINT64_FORMAT ",", (gint64) credentials->native.uid);
210   if (credentials->native.gid != -1)
211     g_string_append_printf (ret, "gid=%" G_GINT64_FORMAT ",", (gint64) credentials->native.gid);
212   if (ret->str[ret->len - 1] == ',')
213     ret->str[ret->len - 1] = '\0';
214 #else
215   g_string_append (ret, "unknown");
216 #endif
217
218   return g_string_free (ret, FALSE);
219 }
220
221 /* ---------------------------------------------------------------------------------------------------- */
222
223 /**
224  * g_credentials_is_same_user:
225  * @credentials: A #GCredentials.
226  * @other_credentials: A #GCredentials.
227  * @error: Return location for error or %NULL.
228  *
229  * Checks if @credentials and @other_credentials is the same user.
230  *
231  * This operation can fail if #GCredentials is not supported on the
232  * the OS.
233  *
234  * Returns: %TRUE if @credentials and @other_credentials has the same
235  * user, %FALSE otherwise or if @error is set.
236  *
237  * Since: 2.26
238  */
239 gboolean
240 g_credentials_is_same_user (GCredentials  *credentials,
241                             GCredentials  *other_credentials,
242                             GError       **error)
243 {
244   gboolean ret;
245
246   g_return_val_if_fail (G_IS_CREDENTIALS (credentials), FALSE);
247   g_return_val_if_fail (G_IS_CREDENTIALS (other_credentials), FALSE);
248   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
249
250   ret = FALSE;
251 #ifdef __linux__
252   if (credentials->native.uid == other_credentials->native.uid)
253     ret = TRUE;
254 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
255   if (credentials->native.cmcred_euid == other_credentials->native.cmcred_euid)
256     ret = TRUE;
257 #elif defined(__OpenBSD__)
258   if (credentials->native.uid == other_credentials->native.uid)
259     ret = TRUE;
260 #else
261   g_set_error_literal (error,
262                        G_IO_ERROR,
263                        G_IO_ERROR_NOT_SUPPORTED,
264                        _("GCredentials is not implemented on this OS"));
265 #endif
266
267   return ret;
268 }
269
270 /**
271  * g_credentials_get_native: (skip)
272  * @credentials: A #GCredentials.
273  * @native_type: The type of native credentials to get.
274  *
275  * Gets a pointer to native credentials of type @native_type from
276  * @credentials.
277  *
278  * It is a programming error (which will cause an warning to be
279  * logged) to use this method if there is no #GCredentials support for
280  * the OS or if @native_type isn't supported by the OS.
281  *
282  * Returns: The pointer to native credentials or %NULL if the
283  * operation there is no #GCredentials support for the OS or if
284  * @native_type isn't supported by the OS. Do not free the returned
285  * data, it is owned by @credentials.
286  *
287  * Since: 2.26
288  */
289 gpointer
290 g_credentials_get_native (GCredentials     *credentials,
291                           GCredentialsType  native_type)
292 {
293   gpointer ret;
294
295   g_return_val_if_fail (G_IS_CREDENTIALS (credentials), NULL);
296
297   ret = NULL;
298
299 #ifdef __linux__
300   if (native_type != G_CREDENTIALS_TYPE_LINUX_UCRED)
301     {
302       g_warning ("g_credentials_get_native: Trying to get credentials of type %d but only "
303                  "G_CREDENTIALS_TYPE_LINUX_UCRED is supported.",
304                  native_type);
305     }
306   else
307     {
308       ret = &credentials->native;
309     }
310 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
311   if (native_type != G_CREDENTIALS_TYPE_FREEBSD_CMSGCRED)
312     {
313       g_warning ("g_credentials_get_native: Trying to get credentials of type %d but only "
314                  "G_CREDENTIALS_TYPE_FREEBSD_CMSGCRED is supported.",
315                  native_type);
316     }
317   else
318     {
319       ret = &credentials->native;
320     }
321 #elif defined(__OpenBSD__)
322   if (native_type != G_CREDENTIALS_TYPE_OPENBSD_SOCKPEERCRED)
323     {
324       g_warning ("g_credentials_get_native: Trying to get credentials of type %d but only "
325                  "G_CREDENTIALS_TYPE_OPENBSD_SOCKPEERCRED is supported.",
326                  native_type);
327     }
328   else
329     {
330       ret = &credentials->native;
331     }
332 #else
333   g_warning ("g_credentials_get_native: Trying to get credentials but GLib has no support "
334              "for the native credentials type. Please add support.");
335 #endif
336
337   return ret;
338 }
339
340 /**
341  * g_credentials_set_native:
342  * @credentials: A #GCredentials.
343  * @native_type: The type of native credentials to set.
344  * @native: A pointer to native credentials.
345  *
346  * Copies the native credentials of type @native_type from @native
347  * into @credentials.
348  *
349  * It is a programming error (which will cause an warning to be
350  * logged) to use this method if there is no #GCredentials support for
351  * the OS or if @native_type isn't supported by the OS.
352  *
353  * Since: 2.26
354  */
355 void
356 g_credentials_set_native (GCredentials     *credentials,
357                           GCredentialsType  native_type,
358                           gpointer          native)
359 {
360 #ifdef __linux__
361   if (native_type != G_CREDENTIALS_TYPE_LINUX_UCRED)
362     {
363       g_warning ("g_credentials_set_native: Trying to set credentials of type %d "
364                  "but only G_CREDENTIALS_TYPE_LINUX_UCRED is supported.",
365                  native_type);
366     }
367   else
368     {
369       memcpy (&credentials->native, native, sizeof (struct ucred));
370     }
371 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
372   if (native_type != G_CREDENTIALS_TYPE_FREEBSD_CMSGCRED)
373     {
374       g_warning ("g_credentials_set_native: Trying to set credentials of type %d "
375                   "but only G_CREDENTIALS_TYPE_FREEBSD_CMSGCRED is supported.",
376                   native_type);
377     }
378   else
379     {
380       memcpy (&credentials->native, native, sizeof (struct cmsgcred));
381     }
382 #elif defined(__OpenBSD__)
383   if (native_type != G_CREDENTIALS_TYPE_OPENBSD_SOCKPEERCRED)
384     {
385       g_warning ("g_credentials_set_native: Trying to set credentials of type %d "
386                  "but only G_CREDENTIALS_TYPE_OPENBSD_SOCKPEERCRED is supported.",
387                  native_type);
388     }
389   else
390     {
391       memcpy (&credentials->native, native, sizeof (struct sockpeercred));
392     }
393 #else
394   g_warning ("g_credentials_set_native: Trying to set credentials but GLib has no support "
395              "for the native credentials type. Please add support.");
396 #endif
397 }
398
399 /* ---------------------------------------------------------------------------------------------------- */
400
401 #ifdef G_OS_UNIX
402 /**
403  * g_credentials_get_unix_user:
404  * @credentials: A #GCredentials
405  * @error: Return location for error or %NULL.
406  *
407  * Tries to get the UNIX user identifier from @credentials. This
408  * method is only available on UNIX platforms.
409  *
410  * This operation can fail if #GCredentials is not supported on the
411  * OS or if the native credentials type does not contain information
412  * about the UNIX user.
413  *
414  * Returns: The UNIX user identifier or -1 if @error is set.
415  *
416  * Since: 2.26
417  */
418 uid_t
419 g_credentials_get_unix_user (GCredentials    *credentials,
420                              GError         **error)
421 {
422   uid_t ret;
423
424   g_return_val_if_fail (G_IS_CREDENTIALS (credentials), -1);
425   g_return_val_if_fail (error == NULL || *error == NULL, -1);
426
427 #ifdef __linux__
428   ret = credentials->native.uid;
429 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
430   ret = credentials->native.cmcred_euid;
431 #elif defined(__OpenBSD__)
432   ret = credentials->native.uid;
433 #else
434   ret = -1;
435   g_set_error_literal (error,
436                        G_IO_ERROR,
437                        G_IO_ERROR_NOT_SUPPORTED,
438                        _("There is no GCredentials support for your platform"));
439 #endif
440
441   return ret;
442 }
443
444 /**
445  * g_credentials_get_unix_pid:
446  * @credentials: A #GCredentials
447  * @error: Return location for error or %NULL.
448  *
449  * Tries to get the UNIX process identifier from @credentials. This
450  * method is only available on UNIX platforms.
451  *
452  * This operation can fail if #GCredentials is not supported on the
453  * OS or if the native credentials type does not contain information
454  * about the UNIX process ID.
455  *
456  * Returns: The UNIX process ID, or -1 if @error is set.
457  *
458  * Since: 2.36
459  */
460 pid_t
461 g_credentials_get_unix_pid (GCredentials    *credentials,
462                             GError         **error)
463 {
464   pid_t ret;
465
466   g_return_val_if_fail (G_IS_CREDENTIALS (credentials), -1);
467   g_return_val_if_fail (error == NULL || *error == NULL, -1);
468
469 #ifdef __linux__
470   ret = credentials->native.pid;
471 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
472   ret = credentials->native.cmcred_pid;
473 #elif defined(__OpenBSD__)
474   ret = credentials->native.pid;
475 #else
476   ret = -1;
477   g_set_error_literal (error,
478                        G_IO_ERROR,
479                        G_IO_ERROR_NOT_SUPPORTED,
480                        _("GCredentials does not contain a process ID on this OS"));
481 #endif
482
483   return ret;
484 }
485
486 /**
487  * g_credentials_set_unix_user:
488  * @credentials: A #GCredentials.
489  * @uid: The UNIX user identifier to set.
490  * @error: Return location for error or %NULL.
491  *
492  * Tries to set the UNIX user identifier on @credentials. This method
493  * is only available on UNIX platforms.
494  *
495  * This operation can fail if #GCredentials is not supported on the
496  * OS or if the native credentials type does not contain information
497  * about the UNIX user.
498  *
499  * Returns: %TRUE if @uid was set, %FALSE if error is set.
500  *
501  * Since: 2.26
502  */
503 gboolean
504 g_credentials_set_unix_user (GCredentials    *credentials,
505                              uid_t            uid,
506                              GError         **error)
507 {
508   gboolean ret;
509
510   g_return_val_if_fail (G_IS_CREDENTIALS (credentials), FALSE);
511   g_return_val_if_fail (uid != -1, FALSE);
512   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
513
514   ret = FALSE;
515 #ifdef __linux__
516   credentials->native.uid = uid;
517   ret = TRUE;
518 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
519   credentials->native.cmcred_euid = uid;
520   ret = TRUE;
521 #elif defined(__OpenBSD__)
522   credentials->native.uid = uid;
523   ret = TRUE;
524 #else
525   g_set_error_literal (error,
526                        G_IO_ERROR,
527                        G_IO_ERROR_NOT_SUPPORTED,
528                        _("GCredentials is not implemented on this OS"));
529 #endif
530
531   return ret;
532 }
533
534 #endif /* G_OS_UNIX */