improve bloom filter on send
[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, see <http://www.gnu.org/licenses/>.
17  *
18  * Author: David Zeuthen <davidz@redhat.com>
19  */
20
21 #include "config.h"
22
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include <gobject/gvaluecollector.h>
27
28 #include "gcredentials.h"
29 #include "gcredentialsprivate.h"
30 #include "gnetworking.h"
31 #include "gioerror.h"
32 #include "gioenumtypes.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 struct ucred - see the
55  * unix(7) man page for details. This corresponds to
56  * %G_CREDENTIALS_TYPE_LINUX_UCRED.
57  *
58  * On FreeBSD, Debian GNU/kFreeBSD, and GNU/Hurd, the native
59  * credential type is a struct cmsgcred. This corresponds
60  * to %G_CREDENTIALS_TYPE_FREEBSD_CMSGCRED.
61  *
62  * On NetBSD, the native credential type is a struct unpcbid.
63  * This corresponds to %G_CREDENTIALS_TYPE_NETBSD_UNPCBID.
64  *
65  * On OpenBSD, the native credential type is a struct sockpeercred.
66  * This corresponds to %G_CREDENTIALS_TYPE_OPENBSD_SOCKPEERCRED.
67  *
68  * On Solaris (including OpenSolaris and its derivatives), the native
69  * credential type is a ucred_t. This corresponds to
70  * %G_CREDENTIALS_TYPE_SOLARIS_UCRED.
71  */
72
73 /**
74  * GCredentials:
75  *
76  * The #GCredentials structure contains only private data and
77  * should only be accessed using the provided API.
78  *
79  * Since: 2.26
80  */
81 struct _GCredentials
82 {
83   /*< private >*/
84   GObject parent_instance;
85
86 #if G_CREDENTIALS_USE_LINUX_UCRED
87   struct ucred native;
88 #elif G_CREDENTIALS_USE_FREEBSD_CMSGCRED
89   struct cmsgcred native;
90 #elif G_CREDENTIALS_USE_NETBSD_UNPCBID
91   struct unpcbid native;
92 #elif G_CREDENTIALS_USE_OPENBSD_SOCKPEERCRED
93   struct sockpeercred native;
94 #elif G_CREDENTIALS_USE_SOLARIS_UCRED
95   ucred_t *native;
96 #else
97   #ifdef __GNUC__
98   #warning Please add GCredentials support for your OS
99   #endif
100 #endif
101 };
102
103 /**
104  * GCredentialsClass:
105  *
106  * Class structure for #GCredentials.
107  *
108  * Since: 2.26
109  */
110 struct _GCredentialsClass
111 {
112   /*< private >*/
113   GObjectClass parent_class;
114 };
115
116 G_DEFINE_TYPE (GCredentials, g_credentials, G_TYPE_OBJECT);
117
118 static void
119 g_credentials_finalize (GObject *object)
120 {
121 #if G_CREDENTIALS_USE_SOLARIS_UCRED
122   GCredentials *credentials = G_CREDENTIALS (object);
123
124   ucred_free (credentials->native);
125 #endif
126
127   if (G_OBJECT_CLASS (g_credentials_parent_class)->finalize != NULL)
128     G_OBJECT_CLASS (g_credentials_parent_class)->finalize (object);
129 }
130
131
132 static void
133 g_credentials_class_init (GCredentialsClass *klass)
134 {
135   GObjectClass *gobject_class;
136
137   gobject_class = G_OBJECT_CLASS (klass);
138   gobject_class->finalize = g_credentials_finalize;
139 }
140
141 static void
142 g_credentials_init (GCredentials *credentials)
143 {
144 #if G_CREDENTIALS_USE_LINUX_UCRED
145   credentials->native.pid = getpid ();
146   credentials->native.uid = geteuid ();
147   credentials->native.gid = getegid ();
148 #elif G_CREDENTIALS_USE_FREEBSD_CMSGCRED
149   memset (&credentials->native, 0, sizeof (struct cmsgcred));
150   credentials->native.cmcred_pid  = getpid ();
151   credentials->native.cmcred_euid = geteuid ();
152   credentials->native.cmcred_gid  = getegid ();
153 #elif G_CREDENTIALS_USE_NETBSD_UNPCBID
154   credentials->native.unp_pid = getpid ();
155   credentials->native.unp_euid = geteuid ();
156   credentials->native.unp_egid = getegid ();
157 #elif G_CREDENTIALS_USE_OPENBSD_SOCKPEERCRED
158   credentials->native.pid = getpid ();
159   credentials->native.uid = geteuid ();
160   credentials->native.gid = getegid ();
161 #elif G_CREDENTIALS_USE_SOLARIS_UCRED
162   credentials->native = ucred_get (P_MYID);
163 #endif
164 }
165
166 /* ---------------------------------------------------------------------------------------------------- */
167
168 /**
169  * g_credentials_new:
170  *
171  * Creates a new #GCredentials object with credentials matching the
172  * the current process.
173  *
174  * Returns: A #GCredentials. Free with g_object_unref().
175  *
176  * Since: 2.26
177  */
178 GCredentials *
179 g_credentials_new (void)
180 {
181   return g_object_new (G_TYPE_CREDENTIALS, NULL);
182 }
183
184 /* ---------------------------------------------------------------------------------------------------- */
185
186 /**
187  * g_credentials_to_string:
188  * @credentials: A #GCredentials object.
189  *
190  * Creates a human-readable textual representation of @credentials
191  * that can be used in logging and debug messages. The format of the
192  * returned string may change in future GLib release.
193  *
194  * Returns: A string that should be freed with g_free().
195  *
196  * Since: 2.26
197  */
198 gchar *
199 g_credentials_to_string (GCredentials *credentials)
200 {
201   GString *ret;
202
203   g_return_val_if_fail (G_IS_CREDENTIALS (credentials), NULL);
204
205   ret = g_string_new ("GCredentials:");
206 #if G_CREDENTIALS_USE_LINUX_UCRED
207   g_string_append (ret, "linux-ucred:");
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 #elif G_CREDENTIALS_USE_FREEBSD_CMSGCRED
217   g_string_append (ret, "freebsd-cmsgcred:");
218   if (credentials->native.cmcred_pid != -1)
219     g_string_append_printf (ret, "pid=%" G_GINT64_FORMAT ",", (gint64) credentials->native.cmcred_pid);
220   if (credentials->native.cmcred_euid != -1)
221     g_string_append_printf (ret, "uid=%" G_GINT64_FORMAT ",", (gint64) credentials->native.cmcred_euid);
222   if (credentials->native.cmcred_gid != -1)
223     g_string_append_printf (ret, "gid=%" G_GINT64_FORMAT ",", (gint64) credentials->native.cmcred_gid);
224 #elif G_CREDENTIALS_USE_NETBSD_UNPCBID
225   g_string_append (ret, "netbsd-unpcbid:");
226   if (credentials->native.unp_pid != -1)
227     g_string_append_printf (ret, "pid=%" G_GINT64_FORMAT ",", (gint64) credentials->native.unp_pid);
228   if (credentials->native.unp_euid != -1)
229     g_string_append_printf (ret, "uid=%" G_GINT64_FORMAT ",", (gint64) credentials->native.unp_euid);
230   if (credentials->native.unp_egid != -1)
231     g_string_append_printf (ret, "gid=%" G_GINT64_FORMAT ",", (gint64) credentials->native.unp_egid);
232   ret->str[ret->len - 1] = '\0';
233 #elif G_CREDENTIALS_USE_OPENBSD_SOCKPEERCRED
234   g_string_append (ret, "openbsd-sockpeercred:");
235   if (credentials->native.pid != -1)
236     g_string_append_printf (ret, "pid=%" G_GINT64_FORMAT ",", (gint64) credentials->native.pid);
237   if (credentials->native.uid != -1)
238     g_string_append_printf (ret, "uid=%" G_GINT64_FORMAT ",", (gint64) credentials->native.uid);
239   if (credentials->native.gid != -1)
240     g_string_append_printf (ret, "gid=%" G_GINT64_FORMAT ",", (gint64) credentials->native.gid);
241   if (ret->str[ret->len - 1] == ',')
242     ret->str[ret->len - 1] = '\0';
243 #elif G_CREDENTIALS_USE_SOLARIS_UCRED
244   g_string_append (ret, "solaris-ucred:");
245   {
246     id_t id;
247     if ((id = ucred_getpid (credentials->native)) != -1)
248       g_string_append_printf (ret, "pid=%" G_GINT64_FORMAT ",", (gint64) id);
249     if ((id = ucred_geteuid (credentials->native)) != -1)
250       g_string_append_printf (ret, "uid=%" G_GINT64_FORMAT ",", (gint64) id);
251     if ((id = ucred_getegid (credentials->native)) != -1)
252       g_string_append_printf (ret, "gid=%" G_GINT64_FORMAT ",", (gint64) id);
253     if (ret->str[ret->len - 1] == ',')
254       ret->str[ret->len - 1] = '\0';
255   }
256 #else
257   g_string_append (ret, "unknown");
258 #endif
259
260   return g_string_free (ret, FALSE);
261 }
262
263 /* ---------------------------------------------------------------------------------------------------- */
264
265 /**
266  * g_credentials_is_same_user:
267  * @credentials: A #GCredentials.
268  * @other_credentials: A #GCredentials.
269  * @error: Return location for error or %NULL.
270  *
271  * Checks if @credentials and @other_credentials is the same user.
272  *
273  * This operation can fail if #GCredentials is not supported on the
274  * the OS.
275  *
276  * Returns: %TRUE if @credentials and @other_credentials has the same
277  * user, %FALSE otherwise or if @error is set.
278  *
279  * Since: 2.26
280  */
281 gboolean
282 g_credentials_is_same_user (GCredentials  *credentials,
283                             GCredentials  *other_credentials,
284                             GError       **error)
285 {
286   gboolean ret;
287
288   g_return_val_if_fail (G_IS_CREDENTIALS (credentials), FALSE);
289   g_return_val_if_fail (G_IS_CREDENTIALS (other_credentials), FALSE);
290   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
291
292   ret = FALSE;
293 #if G_CREDENTIALS_USE_LINUX_UCRED
294   if (credentials->native.uid == other_credentials->native.uid)
295     ret = TRUE;
296 #elif G_CREDENTIALS_USE_FREEBSD_CMSGCRED
297   if (credentials->native.cmcred_euid == other_credentials->native.cmcred_euid)
298     ret = TRUE;
299 #elif G_CREDENTIALS_USE_NETBSD_UNPCBID
300   if (credentials->native.unp_euid == other_credentials->native.unp_euid)
301     ret = TRUE;
302 #elif G_CREDENTIALS_USE_OPENBSD_SOCKPEERCRED
303   if (credentials->native.uid == other_credentials->native.uid)
304     ret = TRUE;
305 #elif G_CREDENTIALS_USE_SOLARIS_UCRED
306   if (ucred_geteuid (credentials->native) == ucred_geteuid (other_credentials->native))
307     ret = TRUE;
308 #else
309   g_set_error_literal (error,
310                        G_IO_ERROR,
311                        G_IO_ERROR_NOT_SUPPORTED,
312                        _("GCredentials is not implemented on this OS"));
313 #endif
314
315   return ret;
316 }
317
318 static gboolean
319 credentials_native_type_check (GCredentialsType  requested_type,
320                                const char       *op)
321 {
322   GEnumClass *enum_class;
323   GEnumValue *requested;
324 #if G_CREDENTIALS_SUPPORTED
325   GEnumValue *supported;
326 #endif
327
328 #if G_CREDENTIALS_SUPPORTED
329   if (requested_type == G_CREDENTIALS_NATIVE_TYPE)
330     return TRUE;
331 #endif
332
333   enum_class = g_type_class_ref (g_credentials_type_get_type ());
334   requested = g_enum_get_value (enum_class, requested_type);
335
336 #if G_CREDENTIALS_SUPPORTED
337   supported = g_enum_get_value (enum_class, G_CREDENTIALS_NATIVE_TYPE);
338   g_assert (supported);
339   g_warning ("g_credentials_%s_native: Trying to %s credentials of type %s "
340              "but only %s is supported on this platform.",
341              op, op,
342              requested ? requested->value_name : "(unknown)",
343              supported->value_name);
344 #else
345   g_warning ("g_credentials_%s_native: Trying to %s credentials of type %s "
346              "but there is no support for GCredentials on this platform.",
347              op, op,
348              requested ? requested->value_name : "(unknown)");
349 #endif
350
351   g_type_class_unref (enum_class);
352   return FALSE;
353 }
354
355 /**
356  * g_credentials_get_native: (skip)
357  * @credentials: A #GCredentials.
358  * @native_type: The type of native credentials to get.
359  *
360  * Gets a pointer to native credentials of type @native_type from
361  * @credentials.
362  *
363  * It is a programming error (which will cause an warning to be
364  * logged) to use this method if there is no #GCredentials support for
365  * the OS or if @native_type isn't supported by the OS.
366  *
367  * Returns: The pointer to native credentials or %NULL if the
368  * operation there is no #GCredentials support for the OS or if
369  * @native_type isn't supported by the OS. Do not free the returned
370  * data, it is owned by @credentials.
371  *
372  * Since: 2.26
373  */
374 gpointer
375 g_credentials_get_native (GCredentials     *credentials,
376                           GCredentialsType  native_type)
377 {
378   g_return_val_if_fail (G_IS_CREDENTIALS (credentials), NULL);
379
380   if (!credentials_native_type_check (native_type, "get"))
381     return NULL;
382
383 #if G_CREDENTIALS_USE_SOLARIS_UCRED
384   return credentials->native;
385 #elif G_CREDENTIALS_SUPPORTED
386   return &credentials->native;
387 #else
388   g_assert_not_reached ();
389 #endif
390 }
391
392 /**
393  * g_credentials_set_native:
394  * @credentials: A #GCredentials.
395  * @native_type: The type of native credentials to set.
396  * @native: A pointer to native credentials.
397  *
398  * Copies the native credentials of type @native_type from @native
399  * into @credentials.
400  *
401  * It is a programming error (which will cause an warning to be
402  * logged) to use this method if there is no #GCredentials support for
403  * the OS or if @native_type isn't supported by the OS.
404  *
405  * Since: 2.26
406  */
407 void
408 g_credentials_set_native (GCredentials     *credentials,
409                           GCredentialsType  native_type,
410                           gpointer          native)
411 {
412   if (!credentials_native_type_check (native_type, "set"))
413     return;
414
415 #if G_CREDENTIALS_USE_SOLARIS_UCRED
416   memcpy (credentials->native, native, ucred_size ());
417 #elif G_CREDENTIALS_SUPPORTED
418   memcpy (&credentials->native, native, sizeof (credentials->native));
419 #else
420   g_assert_not_reached ();
421 #endif
422 }
423
424 /* ---------------------------------------------------------------------------------------------------- */
425
426 #ifdef G_OS_UNIX
427 /**
428  * g_credentials_get_unix_user:
429  * @credentials: A #GCredentials
430  * @error: Return location for error or %NULL.
431  *
432  * Tries to get the UNIX user identifier from @credentials. This
433  * method is only available on UNIX platforms.
434  *
435  * This operation can fail if #GCredentials is not supported on the
436  * OS or if the native credentials type does not contain information
437  * about the UNIX user.
438  *
439  * Returns: The UNIX user identifier or -1 if @error is set.
440  *
441  * Since: 2.26
442  */
443 uid_t
444 g_credentials_get_unix_user (GCredentials    *credentials,
445                              GError         **error)
446 {
447   uid_t ret;
448
449   g_return_val_if_fail (G_IS_CREDENTIALS (credentials), -1);
450   g_return_val_if_fail (error == NULL || *error == NULL, -1);
451
452 #if G_CREDENTIALS_USE_LINUX_UCRED
453   ret = credentials->native.uid;
454 #elif G_CREDENTIALS_USE_FREEBSD_CMSGCRED
455   ret = credentials->native.cmcred_euid;
456 #elif G_CREDENTIALS_USE_NETBSD_UNPCBID
457   ret = credentials->native.unp_euid;
458 #elif G_CREDENTIALS_USE_OPENBSD_SOCKPEERCRED
459   ret = credentials->native.uid;
460 #elif G_CREDENTIALS_USE_SOLARIS_UCRED
461   ret = ucred_geteuid (credentials->native);
462 #else
463   ret = -1;
464   g_set_error_literal (error,
465                        G_IO_ERROR,
466                        G_IO_ERROR_NOT_SUPPORTED,
467                        _("There is no GCredentials support for your platform"));
468 #endif
469
470   return ret;
471 }
472
473 /**
474  * g_credentials_get_unix_pid:
475  * @credentials: A #GCredentials
476  * @error: Return location for error or %NULL.
477  *
478  * Tries to get the UNIX process identifier from @credentials. This
479  * method is only available on UNIX platforms.
480  *
481  * This operation can fail if #GCredentials is not supported on the
482  * OS or if the native credentials type does not contain information
483  * about the UNIX process ID.
484  *
485  * Returns: The UNIX process ID, or -1 if @error is set.
486  *
487  * Since: 2.36
488  */
489 pid_t
490 g_credentials_get_unix_pid (GCredentials    *credentials,
491                             GError         **error)
492 {
493   pid_t ret;
494
495   g_return_val_if_fail (G_IS_CREDENTIALS (credentials), -1);
496   g_return_val_if_fail (error == NULL || *error == NULL, -1);
497
498 #if G_CREDENTIALS_USE_LINUX_UCRED
499   ret = credentials->native.pid;
500 #elif G_CREDENTIALS_USE_FREEBSD_CMSGCRED
501   ret = credentials->native.cmcred_pid;
502 #elif G_CREDENTIALS_USE_NETBSD_UNPCBID
503   ret = credentials->native.unp_pid;
504 #elif G_CREDENTIALS_USE_OPENBSD_SOCKPEERCRED
505   ret = credentials->native.pid;
506 #elif G_CREDENTIALS_USE_SOLARIS_UCRED
507   ret = ucred_getpid (credentials->native);
508 #else
509   ret = -1;
510   g_set_error_literal (error,
511                        G_IO_ERROR,
512                        G_IO_ERROR_NOT_SUPPORTED,
513                        _("GCredentials does not contain a process ID on this OS"));
514 #endif
515
516   return ret;
517 }
518
519 /**
520  * g_credentials_set_unix_user:
521  * @credentials: A #GCredentials.
522  * @uid: The UNIX user identifier to set.
523  * @error: Return location for error or %NULL.
524  *
525  * Tries to set the UNIX user identifier on @credentials. This method
526  * is only available on UNIX platforms.
527  *
528  * This operation can fail if #GCredentials is not supported on the
529  * OS or if the native credentials type does not contain information
530  * about the UNIX user. It can also fail if the OS does not allow the
531  * use of "spoofed" credentials.
532  *
533  * Returns: %TRUE if @uid was set, %FALSE if error is set.
534  *
535  * Since: 2.26
536  */
537 gboolean
538 g_credentials_set_unix_user (GCredentials    *credentials,
539                              uid_t            uid,
540                              GError         **error)
541 {
542   gboolean ret;
543
544   g_return_val_if_fail (G_IS_CREDENTIALS (credentials), FALSE);
545   g_return_val_if_fail (uid != -1, FALSE);
546   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
547
548   ret = FALSE;
549 #if G_CREDENTIALS_USE_LINUX_UCRED
550   credentials->native.uid = uid;
551   ret = TRUE;
552 #elif G_CREDENTIALS_USE_FREEBSD_CMSGCRED
553   credentials->native.cmcred_euid = uid;
554   ret = TRUE;
555 #elif G_CREDENTIALS_USE_NETBSD_UNPCBID
556   credentials->native.unp_euid = uid;
557   ret = TRUE;
558 #elif G_CREDENTIALS_USE_OPENBSD_SOCKPEERCRED
559   credentials->native.uid = uid;
560   ret = TRUE;
561 #elif !G_CREDENTIALS_SPOOFING_SUPPORTED
562   g_set_error_literal (error,
563                        G_IO_ERROR,
564                        G_IO_ERROR_PERMISSION_DENIED,
565                        _("Credentials spoofing is not possible on this OS"));
566   ret = FALSE;
567 #else
568   g_set_error_literal (error,
569                        G_IO_ERROR,
570                        G_IO_ERROR_NOT_SUPPORTED,
571                        _("GCredentials is not implemented on this OS"));
572   ret = FALSE;
573 #endif
574
575   return ret;
576 }
577
578 #endif /* G_OS_UNIX */