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