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