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