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