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