Improve spec file accuracy
[profile/ivi/gsignond.git] / src / common / gsignond-access-control-manager.c
1 /* vi: set et sw=4 ts=4 cino=t0,(0: */
2 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 /*
4  * This file is part of gsignond
5  *
6  * Copyright (C) 2012-2013 Intel Corporation.
7  *
8  * Contact: Jussi Laako <jussi.laako@linux.intel.com>
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23  * 02110-1301 USA
24  */
25
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30
31 #include <gio/gio.h>
32
33 #include "config.h"
34
35 #include "gsignond/gsignond-log.h"
36 #include "gsignond/gsignond-access-control-manager.h"
37
38 /**
39  * SECTION:gsignond-access-control-manager
40  * @short_description: an object that performs access control checks
41  * @include: gsignond/gsignond-access-control-manager.h
42  *
43  * #GSignondAccessControlManager performs access control checks using
44  * available system services. gSSO can be configured to use a custom extension
45  * that provides a subclassed implementation of #GSignondAccessControlManager
46  * (see #GSignondExtension), otherwise a default implementation is used.
47  */
48 /**
49  * GSignondAccessControlManager:
50  *
51  * Opaque #GSignondAccessControlManager data structure.
52  */
53
54 #define GSIGNOND_ACCESS_CONTROL_MANAGER_GET_PRIVATE(obj) \
55     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
56                                   GSIGNOND_TYPE_ACCESS_CONTROL_MANAGER, \
57                                   GSignondAccessControlManagerPrivate))
58
59 #define DBUS_SERVICE_DBUS "org.freedesktop.DBus"
60 #define DBUS_PATH_DBUS "/org/freedesktop/DBus"
61 #define DBUS_INTERFACE_DBUS "org.freedesktop.DBus"
62 #ifndef GSIGNOND_BUS_TYPE
63 #   define GSIGNOND_BUS_TYPE G_BUS_TYPE_SESSION
64 #endif
65
66 struct _GSignondAccessControlManagerPrivate
67 {
68 };
69
70 enum
71 {
72     PROP_0,
73     PROP_CONFIG,
74     N_PROPERTIES
75 };
76
77 static GParamSpec *properties[N_PROPERTIES] = { NULL, };
78
79 G_DEFINE_TYPE (GSignondAccessControlManager, gsignond_access_control_manager,
80                G_TYPE_OBJECT);
81
82 static void
83 _set_property (GObject *object, guint prop_id, const GValue *value,
84                GParamSpec *pspec)
85 {
86     GSignondAccessControlManager *self =
87         GSIGNOND_ACCESS_CONTROL_MANAGER (object);
88
89     switch (prop_id) {
90         case PROP_CONFIG:
91             g_assert (self->config == NULL);
92             self->config = g_value_dup_object (value);
93             break;
94         default:
95             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
96     }
97 }
98
99 static void
100 _get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
101 {
102     GSignondAccessControlManager *self =
103         GSIGNOND_ACCESS_CONTROL_MANAGER (object);
104
105     switch (prop_id) {
106         case PROP_CONFIG:
107             g_value_set_object (value, self->config);
108             break;
109         default:
110             G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
111     }
112 }
113
114 static void
115 _dispose (GObject *object)
116 {
117     GSignondAccessControlManager *self =
118         GSIGNOND_ACCESS_CONTROL_MANAGER (object);
119
120     if (self->config) {
121         g_object_unref (self->config);
122         self->config = NULL;
123     }
124
125     G_OBJECT_CLASS (gsignond_access_control_manager_parent_class)->dispose (object);
126 }
127
128 static void
129 _security_context_of_peer (GSignondAccessControlManager *self,
130                            GSignondSecurityContext *peer_ctx,
131                            int peer_fd, const gchar *peer_service,
132                            const gchar *peer_app_ctx)
133 {
134     pid_t remote_pid = 0;
135     gchar *procfname;
136     char *peerpath;
137     ssize_t res;
138
139     (void) self;
140
141     gsignond_security_context_set_system_context (peer_ctx, "");
142     gsignond_security_context_set_application_context (peer_ctx,
143                                                        peer_app_ctx);
144
145     if (peer_fd >= 0) {
146         struct ucred peer_cred;
147         socklen_t cred_size = sizeof(peer_cred);
148
149         if (getsockopt (peer_fd, SOL_SOCKET, SO_PEERCRED,
150                         &peer_cred, &cred_size) != 0) {
151             WARN ("getsockopt() for SO_PEERCRED failed");
152             return;
153         }
154         DBG ("remote peer pid=%d uid=%d gid=%d",
155              peer_cred.pid, peer_cred.uid, peer_cred.gid);
156         remote_pid = peer_cred.pid;
157     } else if (peer_service) {
158         GError *error = NULL;
159         GDBusConnection *connection;
160         GVariant *response = NULL;
161         guint32 upid;
162
163         connection = g_bus_get_sync (GSIGNOND_BUS_TYPE, NULL, &error);
164         if (!connection) {
165             WARN ("failed to open connection to session bus: %s",
166                   error->message);
167             g_error_free (error);
168             return;
169         }
170
171         error = NULL;
172         response = g_dbus_connection_call_sync (connection,
173                                                 DBUS_SERVICE_DBUS,
174                                                 DBUS_PATH_DBUS,
175                                                 DBUS_INTERFACE_DBUS,
176                                                 "GetConnectionUnixProcessID",
177                                                 g_variant_new ("(s)", peer_service),
178                                                 ((const GVariantType *) "(u)"),
179                                                 G_DBUS_CALL_FLAGS_NONE,
180                                                 -1,
181                                                 NULL,
182                                                 &error);
183
184         g_object_unref (connection);
185
186         if (!response) {
187             WARN ("request for peer pid failed: %s",
188                   error->message);
189             g_error_free (error);
190             return;
191         }
192         
193         g_variant_get (response, "(u)", &upid);
194         DBG ("remote peer service=%s pid=%u", peer_service, upid);
195         remote_pid = (pid_t) upid;
196
197         g_variant_unref (response);
198     } else return;
199
200     if (!remote_pid)
201         return;
202
203     procfname = g_strdup_printf ("/proc/%d/exe", remote_pid);
204     peerpath = g_malloc0 (PATH_MAX + 1);
205     res = readlink (procfname, peerpath, PATH_MAX);
206     g_free (procfname);
207     if (res <= 0) {
208         WARN ("failed to follow link for pid %d", remote_pid);
209         g_free (peerpath);
210         return;
211     }
212
213     DBG ("identity of pid %d is [%s:%s]", remote_pid, peerpath, peer_app_ctx);
214     gsignond_security_context_set_system_context (peer_ctx, peerpath);
215
216     g_free (peerpath);
217 }
218
219 static gboolean
220 _peer_is_allowed_to_use_identity (GSignondAccessControlManager *self,
221                                 const GSignondSecurityContext *peer_ctx,
222                                 const GSignondSecurityContext *owner_ctx,
223                                 const GSignondSecurityContextList *identity_acl)
224 {
225     GSignondSecurityContext *acl_ctx;
226
227     (void) self;
228     (void) owner_ctx;
229
230     for ( ; identity_acl != NULL; identity_acl = g_list_next (identity_acl)) {
231         acl_ctx = (GSignondSecurityContext *) identity_acl->data;
232         DBG ("ACL check [%p=(%s:%s)] vs [%p=(%s:%s)]",
233              acl_ctx,
234              gsignond_security_context_get_system_context (acl_ctx),
235              gsignond_security_context_get_application_context (acl_ctx),
236              peer_ctx,
237              gsignond_security_context_get_system_context (peer_ctx),
238              gsignond_security_context_get_application_context (peer_ctx));
239         if (gsignond_security_context_check (acl_ctx, peer_ctx)) {
240             DBG (" - ACL check passed");
241             return TRUE;
242         }
243     }
244     DBG (" - ACL check failed");
245     return FALSE;
246 }
247
248 static gboolean
249 _peer_is_owner_of_identity (GSignondAccessControlManager *self,
250                             const GSignondSecurityContext *peer_ctx,
251                             const GSignondSecurityContext *owner_ctx)
252 {
253     (void) self;
254
255     DBG ("Owner check [%p=(%s:%s)] vs [%p=(%s:%s)]",
256          owner_ctx,
257          gsignond_security_context_get_system_context (owner_ctx),
258          gsignond_security_context_get_application_context (owner_ctx),
259          peer_ctx,
260          gsignond_security_context_get_system_context (peer_ctx),
261          gsignond_security_context_get_application_context (peer_ctx));
262     return gsignond_security_context_check (owner_ctx, peer_ctx);
263 }
264
265 static gboolean
266 _acl_is_valid (GSignondAccessControlManager *self,
267                const GSignondSecurityContext *peer_ctx,
268                const GSignondSecurityContextList *identity_acl)
269 {
270     (void) self;
271     (void) peer_ctx;
272     (void) identity_acl;
273
274     return TRUE;
275 }
276
277 GSignondSecurityContext *
278 _security_context_of_keychain (GSignondAccessControlManager *self)
279 {
280     g_return_val_if_fail (self != NULL, NULL);
281
282     const gchar *keychain_sysctx;
283
284     keychain_sysctx = gsignond_config_get_string (
285                                       self->config,
286                                       GSIGNOND_CONFIG_GENERAL_KEYCHAIN_SYSCTX);
287     if (!keychain_sysctx)
288 #       ifdef KEYCHAIN_SYSCTX
289         keychain_sysctx = KEYCHAIN_SYSCTX;
290 #       else
291         keychain_sysctx = "";
292 #       endif
293 #   ifdef ENABLE_DEBUG
294     const gchar *keychain_env = g_getenv ("SSO_KEYCHAIN_SYSCTX");
295     if (keychain_env)
296         keychain_sysctx = keychain_env;
297 #   endif
298
299     return gsignond_security_context_new_from_values (keychain_sysctx, NULL);
300 }
301
302 /**
303  * GSignondAccessControlManagerClass:
304  * @parent_class: parent class.
305  * @security_context_of_peer: an implementation of gsignond_access_control_manager_security_context_of_peer()
306  * @peer_is_allowed_to_use_identity: an implementation of gsignond_access_control_manager_peer_is_allowed_to_use_identity()
307  * @peer_is_owner_of_identity: an implementation of gsignond_access_control_manager_peer_is_owner_of_identity()
308  * @acl_is_valid: an implementation of gsignond_access_control_manager_acl_is_valid()
309  * @security_context_of_keychain: an implementation of gsignond_access_control_manager_security_context_of_keychain()
310  * 
311  * #GSignondAccessControlManagerClass class containing pointers to class methods.
312  */
313 static void
314 gsignond_access_control_manager_class_init (
315                                        GSignondAccessControlManagerClass *klass)
316 {
317     GObjectClass *base = G_OBJECT_CLASS (klass);
318
319     base->set_property = _set_property;
320     base->get_property = _get_property;
321     base->dispose = _dispose;
322     properties[PROP_CONFIG] = g_param_spec_object ("config",
323                                                    "config",
324                                                    "Configuration object",
325                                                    GSIGNOND_TYPE_CONFIG,
326                                                    G_PARAM_CONSTRUCT_ONLY|
327                                                    G_PARAM_READWRITE |
328                                                    G_PARAM_STATIC_STRINGS);
329     g_object_class_install_properties (base, N_PROPERTIES, properties);
330
331     /*g_type_class_add_private (klass,
332                               sizeof(GSignondAccessControlManagerPrivate));*/
333
334     klass->security_context_of_peer = _security_context_of_peer;
335     klass->peer_is_allowed_to_use_identity = _peer_is_allowed_to_use_identity;
336     klass->peer_is_owner_of_identity = _peer_is_owner_of_identity;
337     klass->acl_is_valid = _acl_is_valid;
338     klass->security_context_of_keychain = _security_context_of_keychain;
339 }
340
341 static void
342 gsignond_access_control_manager_init (GSignondAccessControlManager *self)
343 {
344     /*self->priv = GSIGNOND_ACCESS_CONTROL_MANAGER_GET_PRIVATE (self);*/
345
346     self->config = NULL;
347 }
348
349 /**
350  * gsignond_access_control_manager_security_context_of_peer:
351  * @self: object instance.
352  * @peer_ctx: instance of security context to be set.
353  * @peer_fd: file descriptor of the peer connection if using peer-to-peer dbus, -1 otherwise.
354  * @peer_service: g_dbus_method_invocation_get_sender() of the peer connection, if not using peer-to-peer dbus, NULL otherwise
355  * @peer_app_ctx: application context of the peer connection.
356  *
357  * Retrieves and sets #GSignondSecurityContext of the specified peer.
358  * 
359  * The default implementation sets the app context as it was passed, and sets 
360  * the system context to the binary path of the process that is determined from
361  * @peer_fd and @peer_service parameters.
362  */
363 void
364 gsignond_access_control_manager_security_context_of_peer (
365                             GSignondAccessControlManager *self,
366                             GSignondSecurityContext *peer_ctx,
367                             int peer_fd, const gchar *peer_service,
368                             const gchar *peer_app_ctx)
369 {
370     GSIGNOND_ACCESS_CONTROL_MANAGER_GET_CLASS (self)->
371         security_context_of_peer (self, peer_ctx, peer_fd,
372                                   peer_service, peer_app_ctx);
373 }
374
375 /**
376  * gsignond_access_control_manager_peer_is_allowed_to_use_identity:
377  * @self: object instance.
378  * @peer_ctx: security context of the peer connection.
379  * @owner_ctx: security context of the identity owner.
380  * @identity_acl: access control list for the identity in question. Includes the @owner_ctx as well.
381  *
382  * Checks if specified peer is allowed to access the specified identity.
383  * 
384  * The default implementation goes over items in @identity_acl, using 
385  * gsignond_security_context_check() to check them against @peer_ctx.
386  *
387  * Returns: access is allowed?
388  */
389 gboolean
390 gsignond_access_control_manager_peer_is_allowed_to_use_identity (
391                             GSignondAccessControlManager *self,
392                             const GSignondSecurityContext *peer_ctx,
393                             const GSignondSecurityContext *owner_ctx,
394                             const GSignondSecurityContextList *identity_acl)
395 {
396     return GSIGNOND_ACCESS_CONTROL_MANAGER_GET_CLASS (self)->
397         peer_is_allowed_to_use_identity (self, peer_ctx, owner_ctx, identity_acl);
398 }
399
400 /**
401  * gsignond_access_control_manager_peer_is_owner_of_identity:
402  * @self: object instance.
403  * @peer_ctx: security context of the peer connection.
404  * @owner_ctx: security context of the identity owner.
405  *
406  * Checks if the peer specified in @peer_ctx is the owner of the identity.
407  * 
408  * The default implementation is using gsignond_security_context_check() 
409  * to check @peer_ctx against @owner_ctx directly.
410  *
411  * Returns: is owner?
412  */
413 gboolean
414 gsignond_access_control_manager_peer_is_owner_of_identity (
415                             GSignondAccessControlManager *self,
416                             const GSignondSecurityContext *peer_ctx,
417                             const GSignondSecurityContext *owner_ctx)
418 {
419     return GSIGNOND_ACCESS_CONTROL_MANAGER_GET_CLASS (self)->
420         peer_is_owner_of_identity (self, peer_ctx, owner_ctx);
421 }
422
423 /**
424  * gsignond_access_control_manager_acl_is_valid:
425  * @self: object instance.
426  * @peer_ctx: security context of the peer connection.
427  * @identity_acl: access control list for the identity.
428  *
429  * Checks if the specified peer is allowed to set the specified access
430  * control list. gsignond_access_control_manager_peer_is_owner_of_identity()
431  * is used before calling this method to verify identity ownership.
432  * 
433  * The default implementation always returns TRUE.
434  *
435  * Returns: access control list is OK?
436  */
437 gboolean
438 gsignond_access_control_manager_acl_is_valid (
439                             GSignondAccessControlManager *self,
440                             const GSignondSecurityContext *peer_ctx,
441                             const GSignondSecurityContextList *identity_acl)
442 {
443     return GSIGNOND_ACCESS_CONTROL_MANAGER_GET_CLASS (self)->
444         acl_is_valid (self, peer_ctx, identity_acl);
445 }
446
447 /**
448  * gsignond_access_control_manager_security_context_of_keychain:
449  * @self: object instance.
450  *
451  * Retrieves security context of the keychain application. Keychain application
452  * has a special management access to all stored identities and is able to
453  * perform deletion of all identities from storage.
454  * 
455  * The default implementation returns a context either set in #GSignondConfig, 
456  * or if not set, a value specified through a configure --enable-keychain
457  * option (see
458  * <link linkend="gsignond-building">Building gsignond</link>), or if that is not
459  * set either then an empty string "" is returned. 
460  * 
461  * If gSSO was compiled
462  * with --enable-debug and SSO_KEYCHAIN_SYSCTX environment variable is set, then
463  * the value of that variable is used to set the returned system context instead.
464  *
465  * Returns: security context of the keychain application.
466  */
467 GSignondSecurityContext *
468 gsignond_access_control_manager_security_context_of_keychain (
469                             GSignondAccessControlManager *self)
470 {
471     return GSIGNOND_ACCESS_CONTROL_MANAGER_GET_CLASS (self)->
472         security_context_of_keychain (self);
473 }
474