gsocket: Set SO_NOSIGPIPE on sockets on Darwin
[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_warning ("g_credentials_%s_native: Trying to %s credentials of type %s "
339              "but only %s is supported on this platform.",
340              op, op,
341              requested ? requested->value_name : "(unknown)",
342              supported->value_name);
343 #else
344   g_warning ("g_credentials_%s_native: Trying to %s credentials of type %s "
345              "but there is no support for GCredentials on this platform.",
346              op, op,
347              requested ? requested->value_name : "(unknown)");
348 #endif
349
350   g_type_class_unref (enum_class);
351   return FALSE;
352 }
353
354 /**
355  * g_credentials_get_native: (skip)
356  * @credentials: A #GCredentials.
357  * @native_type: The type of native credentials to get.
358  *
359  * Gets a pointer to native credentials of type @native_type from
360  * @credentials.
361  *
362  * It is a programming error (which will cause an warning to be
363  * logged) to use this method if there is no #GCredentials support for
364  * the OS or if @native_type isn't supported by the OS.
365  *
366  * Returns: The pointer to native credentials or %NULL if the
367  * operation there is no #GCredentials support for the OS or if
368  * @native_type isn't supported by the OS. Do not free the returned
369  * data, it is owned by @credentials.
370  *
371  * Since: 2.26
372  */
373 gpointer
374 g_credentials_get_native (GCredentials     *credentials,
375                           GCredentialsType  native_type)
376 {
377   g_return_val_if_fail (G_IS_CREDENTIALS (credentials), NULL);
378
379   if (!credentials_native_type_check (native_type, "get"))
380     return NULL;
381
382 #if G_CREDENTIALS_USE_SOLARIS_UCRED
383   return credentials->native;
384 #elif G_CREDENTIALS_SUPPORTED
385   return &credentials->native;
386 #else
387   g_assert_not_reached ();
388 #endif
389 }
390
391 /**
392  * g_credentials_set_native:
393  * @credentials: A #GCredentials.
394  * @native_type: The type of native credentials to set.
395  * @native: A pointer to native credentials.
396  *
397  * Copies the native credentials of type @native_type from @native
398  * into @credentials.
399  *
400  * It is a programming error (which will cause an warning to be
401  * logged) to use this method if there is no #GCredentials support for
402  * the OS or if @native_type isn't supported by the OS.
403  *
404  * Since: 2.26
405  */
406 void
407 g_credentials_set_native (GCredentials     *credentials,
408                           GCredentialsType  native_type,
409                           gpointer          native)
410 {
411   if (!credentials_native_type_check (native_type, "set"))
412     return;
413
414 #if G_CREDENTIALS_USE_SOLARIS_UCRED
415   memcpy (credentials->native, native, ucred_size ());
416 #elif G_CREDENTIALS_SUPPORTED
417   memcpy (&credentials->native, native, sizeof (credentials->native));
418 #else
419   g_assert_not_reached ();
420 #endif
421 }
422
423 /* ---------------------------------------------------------------------------------------------------- */
424
425 #ifdef G_OS_UNIX
426 /**
427  * g_credentials_get_unix_user:
428  * @credentials: A #GCredentials
429  * @error: Return location for error or %NULL.
430  *
431  * Tries to get the UNIX user identifier from @credentials. This
432  * method is only available on UNIX platforms.
433  *
434  * This operation can fail if #GCredentials is not supported on the
435  * OS or if the native credentials type does not contain information
436  * about the UNIX user.
437  *
438  * Returns: The UNIX user identifier or -1 if @error is set.
439  *
440  * Since: 2.26
441  */
442 uid_t
443 g_credentials_get_unix_user (GCredentials    *credentials,
444                              GError         **error)
445 {
446   uid_t ret;
447
448   g_return_val_if_fail (G_IS_CREDENTIALS (credentials), -1);
449   g_return_val_if_fail (error == NULL || *error == NULL, -1);
450
451 #if G_CREDENTIALS_USE_LINUX_UCRED
452   ret = credentials->native.uid;
453 #elif G_CREDENTIALS_USE_FREEBSD_CMSGCRED
454   ret = credentials->native.cmcred_euid;
455 #elif G_CREDENTIALS_USE_NETBSD_UNPCBID
456   ret = credentials->native.unp_euid;
457 #elif G_CREDENTIALS_USE_OPENBSD_SOCKPEERCRED
458   ret = credentials->native.uid;
459 #elif G_CREDENTIALS_USE_SOLARIS_UCRED
460   ret = ucred_geteuid (credentials->native);
461 #else
462   ret = -1;
463   g_set_error_literal (error,
464                        G_IO_ERROR,
465                        G_IO_ERROR_NOT_SUPPORTED,
466                        _("There is no GCredentials support for your platform"));
467 #endif
468
469   return ret;
470 }
471
472 /**
473  * g_credentials_get_unix_pid:
474  * @credentials: A #GCredentials
475  * @error: Return location for error or %NULL.
476  *
477  * Tries to get the UNIX process identifier from @credentials. This
478  * method is only available on UNIX platforms.
479  *
480  * This operation can fail if #GCredentials is not supported on the
481  * OS or if the native credentials type does not contain information
482  * about the UNIX process ID.
483  *
484  * Returns: The UNIX process ID, or -1 if @error is set.
485  *
486  * Since: 2.36
487  */
488 pid_t
489 g_credentials_get_unix_pid (GCredentials    *credentials,
490                             GError         **error)
491 {
492   pid_t ret;
493
494   g_return_val_if_fail (G_IS_CREDENTIALS (credentials), -1);
495   g_return_val_if_fail (error == NULL || *error == NULL, -1);
496
497 #if G_CREDENTIALS_USE_LINUX_UCRED
498   ret = credentials->native.pid;
499 #elif G_CREDENTIALS_USE_FREEBSD_CMSGCRED
500   ret = credentials->native.cmcred_pid;
501 #elif G_CREDENTIALS_USE_NETBSD_UNPCBID
502   ret = credentials->native.unp_pid;
503 #elif G_CREDENTIALS_USE_OPENBSD_SOCKPEERCRED
504   ret = credentials->native.pid;
505 #elif G_CREDENTIALS_USE_SOLARIS_UCRED
506   ret = ucred_getpid (credentials->native);
507 #else
508   ret = -1;
509   g_set_error_literal (error,
510                        G_IO_ERROR,
511                        G_IO_ERROR_NOT_SUPPORTED,
512                        _("GCredentials does not contain a process ID on this OS"));
513 #endif
514
515   return ret;
516 }
517
518 /**
519  * g_credentials_set_unix_user:
520  * @credentials: A #GCredentials.
521  * @uid: The UNIX user identifier to set.
522  * @error: Return location for error or %NULL.
523  *
524  * Tries to set the UNIX user identifier on @credentials. This method
525  * is only available on UNIX platforms.
526  *
527  * This operation can fail if #GCredentials is not supported on the
528  * OS or if the native credentials type does not contain information
529  * about the UNIX user. It can also fail if the OS does not allow the
530  * use of "spoofed" credentials.
531  *
532  * Returns: %TRUE if @uid was set, %FALSE if error is set.
533  *
534  * Since: 2.26
535  */
536 gboolean
537 g_credentials_set_unix_user (GCredentials    *credentials,
538                              uid_t            uid,
539                              GError         **error)
540 {
541   gboolean ret;
542
543   g_return_val_if_fail (G_IS_CREDENTIALS (credentials), FALSE);
544   g_return_val_if_fail (uid != -1, FALSE);
545   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
546
547   ret = FALSE;
548 #if G_CREDENTIALS_USE_LINUX_UCRED
549   credentials->native.uid = uid;
550   ret = TRUE;
551 #elif G_CREDENTIALS_USE_FREEBSD_CMSGCRED
552   credentials->native.cmcred_euid = uid;
553   ret = TRUE;
554 #elif G_CREDENTIALS_USE_NETBSD_UNPCBID
555   credentials->native.unp_euid = uid;
556   ret = TRUE;
557 #elif G_CREDENTIALS_USE_OPENBSD_SOCKPEERCRED
558   credentials->native.uid = uid;
559   ret = TRUE;
560 #elif !G_CREDENTIALS_SPOOFING_SUPPORTED
561   g_set_error_literal (error,
562                        G_IO_ERROR,
563                        G_IO_ERROR_PERMISSION_DENIED,
564                        _("Credentials spoofing is not possible on this OS"));
565   ret = FALSE;
566 #else
567   g_set_error_literal (error,
568                        G_IO_ERROR,
569                        G_IO_ERROR_NOT_SUPPORTED,
570                        _("GCredentials is not implemented on this OS"));
571   ret = FALSE;
572 #endif
573
574   return ret;
575 }
576
577 #endif /* G_OS_UNIX */