~azzar1/snapd-glib-fork/glib-2-40

« back to all changes in this revision

Viewing changes to snapd-login-service/snapd-login-service.c

  • Committer: Robert Ancell
  • Date: 2016-08-30 04:23:53 UTC
  • Revision ID: git-v1:286dc90ad146fa4df2ba64e0382eaf91340ef721
Make a D-Bus service to allow non-root users to login

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2016 Canonical Ltd.
 
3
 *
 
4
 * This library is free software; you can redistribute it and/or modify it under
 
5
 * the terms of the GNU Lesser General Public License as published by the Free
 
6
 * Software Foundation; either version 2 or version 3 of the License.
 
7
 * See http://www.gnu.org/copyleft/lgpl.html the full text of the license.
 
8
 */
 
9
 
 
10
#include <stdlib.h>
 
11
#include <gio/gio.h>
 
12
#include <snapd-glib/snapd-glib.h>
 
13
#include <polkit/polkit.h>
 
14
 
 
15
#include "login-service.h"
 
16
 
 
17
#if !defined(POLKIT_HAS_AUTOPTR_MACROS)
 
18
G_DEFINE_AUTOPTR_CLEANUP_FUNC(PolkitAuthorizationResult, g_object_unref)
 
19
G_DEFINE_AUTOPTR_CLEANUP_FUNC(PolkitSubject, g_object_unref)
 
20
#endif
 
21
 
 
22
static GMainLoop *loop;
 
23
static int result = EXIT_SUCCESS;
 
24
 
 
25
static PolkitAuthority *authority = NULL;
 
26
static IoSnapcraftSnapdLoginService *service = NULL;
 
27
 
 
28
typedef struct
 
29
{
 
30
    GDBusMethodInvocation *invocation;
 
31
    gchar *username;
 
32
    gchar *password;
 
33
    gchar *otp;
 
34
    GPermission *permission;
 
35
    SnapdClient *client;
 
36
} LoginRequest;
 
37
 
 
38
static void
 
39
free_login_request (LoginRequest *request)
 
40
{
 
41
    g_object_unref (request->invocation);
 
42
    g_free (request->username);
 
43
    g_free (request->password);
 
44
    g_free (request->otp);
 
45
    if (request->permission != NULL)
 
46
        g_object_unref (request->permission);
 
47
    if (request->client != NULL)
 
48
        g_object_unref (request->client);
 
49
    g_slice_free (LoginRequest, request);
 
50
}
 
51
 
 
52
G_DEFINE_AUTOPTR_CLEANUP_FUNC (LoginRequest, free_login_request);
 
53
 
 
54
static void
 
55
login_result_cb (GObject *object, GAsyncResult *result, gpointer user_data)
 
56
{
 
57
    g_autoptr(LoginRequest) request = user_data;
 
58
    SnapdAuthData *auth_data;
 
59
    g_autoptr(GError) error = NULL;
 
60
 
 
61
    if (!snapd_client_login_finish (request->client, result, &error)) {
 
62
        g_dbus_method_invocation_return_gerror (request->invocation, error);
 
63
        return;
 
64
    }
 
65
 
 
66
    auth_data = snapd_client_get_auth_data (request->client);
 
67
    io_snapcraft_snapd_login_service_complete_login (service, request->invocation,
 
68
                                                     snapd_auth_data_get_macaroon (auth_data),
 
69
                                                     (const gchar *const *) snapd_auth_data_get_discharges (auth_data));
 
70
}
 
71
 
 
72
static void
 
73
auth_cb (GObject *object, GAsyncResult *result, gpointer user_data)
 
74
{
 
75
    g_autoptr(LoginRequest) request = user_data;
 
76
    g_autoptr(PolkitAuthorizationResult) r = NULL;
 
77
    g_autoptr(GError) error = NULL;
 
78
 
 
79
    r = polkit_authority_check_authorization_finish (authority, result, &error);
 
80
    if (r == NULL) {
 
81
        g_dbus_method_invocation_return_error (request->invocation,
 
82
                                               SNAPD_ERROR,
 
83
                                               SNAPD_ERROR_PERMISSION_DENIED,
 
84
                                               "Failed to get permission from Polkit: %s", error->message);
 
85
        return;
 
86
    }
 
87
 
 
88
    if (!polkit_authorization_result_get_is_authorized (r)) {
 
89
        g_dbus_method_invocation_return_error (request->invocation,
 
90
                                               SNAPD_ERROR,
 
91
                                               SNAPD_ERROR_PERMISSION_DENIED,
 
92
                                               "Permission denied by Polkit");
 
93
        return;
 
94
    }
 
95
 
 
96
    g_debug ("Requesting login from snapd...");
 
97
 
 
98
    request->client = snapd_client_new ();
 
99
    if (!snapd_client_connect_sync (request->client, NULL, &error)) {
 
100
        g_dbus_method_invocation_return_gerror (request->invocation, error);
 
101
        return;
 
102
    }
 
103
 
 
104
    snapd_client_login_async (request->client,
 
105
                              request->username, request->password, request->otp, NULL,
 
106
                              login_result_cb, request);
 
107
    g_steal_pointer (&request);
 
108
}
 
109
 
 
110
static gboolean
 
111
login_cb (IoSnapcraftSnapdLoginService *service,
 
112
          GDBusMethodInvocation        *invocation,
 
113
          const gchar                  *username,
 
114
          const gchar                  *password,
 
115
          const gchar                  *otp,
 
116
          gpointer                      user_data)
 
117
{
 
118
    g_autoptr(LoginRequest) request = NULL;
 
119
    g_autoptr(PolkitSubject) subject = NULL;
 
120
 
 
121
    request = g_slice_new0 (LoginRequest);
 
122
    request->invocation = g_object_ref (invocation);
 
123
    request->username = g_strdup (username);
 
124
    request->password = g_strdup (password);
 
125
    if (otp[0] != '\0')
 
126
        request->otp = g_strdup (otp);
 
127
 
 
128
    g_debug ("Processing login request...");
 
129
 
 
130
    subject = polkit_system_bus_name_new (g_dbus_method_invocation_get_sender (invocation));
 
131
    polkit_authority_check_authorization (authority,
 
132
                                          subject, "io.snapcraft.login", NULL,
 
133
                                          POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
 
134
                                          NULL,
 
135
                                          auth_cb, g_steal_pointer (&request));
 
136
 
 
137
    return TRUE;
 
138
}
 
139
 
 
140
static void
 
141
bus_acquired_cb (GDBusConnection *connection,
 
142
                 const gchar *name,
 
143
                 gpointer user_data)
 
144
{
 
145
    g_autoptr(GError) error = NULL;
 
146
 
 
147
    g_debug ("Connected to D-Bus");
 
148
 
 
149
    service = io_snapcraft_snapd_login_service_skeleton_new ();
 
150
    g_signal_connect (service, "handle-login", G_CALLBACK (login_cb), NULL);
 
151
    if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (service),
 
152
                                           connection,
 
153
                                           "/io/snapcraft/SnapdLoginService",
 
154
                                           &error)) {
 
155
        g_warning ("Failed to register object: %s", error->message);
 
156
        result = EXIT_FAILURE;
 
157
        g_main_loop_quit (loop);
 
158
    }
 
159
}
 
160
 
 
161
static void
 
162
name_acquired_cb (GDBusConnection *connection,
 
163
                  const gchar *name,
 
164
                  gpointer user_data)
 
165
{
 
166
    g_debug ("Acquired bus name %s", name);
 
167
}
 
168
 
 
169
static void
 
170
name_lost_cb (GDBusConnection *connection,
 
171
              const gchar *name,
 
172
              gpointer user_data)
 
173
{
 
174
    if (connection == NULL) {
 
175
        g_warning ("Failed to connect to bus");
 
176
        result = EXIT_FAILURE;
 
177
    }
 
178
 
 
179
    g_info ("Lost bus name %s", name);
 
180
    g_main_loop_quit (loop);
 
181
}
 
182
 
 
183
 
 
184
int main (int argc, char **argv)
 
185
{
 
186
    g_autoptr(GError) error = NULL;
 
187
 
 
188
    loop = g_main_loop_new (NULL, FALSE);
 
189
  
 
190
    authority = polkit_authority_get_sync (NULL, &error);
 
191
    if (authority == NULL) {
 
192
        g_warning ("Failed to get Polkit authority: %s", error->message);
 
193
        return EXIT_FAILURE;
 
194
    }
 
195
    g_debug ("Connected to Polkit");
 
196
 
 
197
    g_bus_own_name (G_BUS_TYPE_SYSTEM,
 
198
                    "io.snapcraft.SnapdLoginService",
 
199
                    G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | G_BUS_NAME_OWNER_FLAGS_REPLACE,
 
200
                    bus_acquired_cb,
 
201
                    name_acquired_cb,
 
202
                    name_lost_cb,
 
203
                    NULL, NULL);
 
204
 
 
205
    g_main_loop_run (loop);
 
206
 
 
207
    return result;
 
208
}