1 /*
2  * Copyright (C) 2013, 2014, 2016 Red Hat, Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library.  If not, see
16  * <http://www.gnu.org/licenses/>.
17  */
18 
19 #include <config.h>
20 
21 #include "testutils.h"
22 
23 #if defined(__ELF__)
24 
25 # include "virpolkit.h"
26 # include "virgdbus.h"
27 # include "virlog.h"
28 # include "virmock.h"
29 # define VIR_FROM_THIS VIR_FROM_NONE
30 
31 VIR_LOG_INIT("tests.systemdtest");
32 
33 /* Some interesting numbers */
34 # define THE_PID 1458
35 # define THE_TIME 11011000001
36 # define THE_UID 1729
37 
VIR_MOCK_WRAP_RET_ARGS(g_dbus_connection_call_sync,GVariant *,GDBusConnection *,connection,const gchar *,bus_name,const gchar *,object_path,const gchar *,interface_name,const gchar *,method_name,GVariant *,parameters,const GVariantType *,reply_type,GDBusCallFlags,flags,gint,timeout_msec,GCancellable *,cancellable,GError **,error)38 VIR_MOCK_WRAP_RET_ARGS(g_dbus_connection_call_sync,
39                        GVariant *,
40                        GDBusConnection *, connection,
41                        const gchar *, bus_name,
42                        const gchar *, object_path,
43                        const gchar *, interface_name,
44                        const gchar *, method_name,
45                        GVariant *, parameters,
46                        const GVariantType *, reply_type,
47                        GDBusCallFlags, flags,
48                        gint, timeout_msec,
49                        GCancellable *, cancellable,
50                        GError **, error)
51 {
52     GVariant *reply = NULL;
53     g_autoptr(GVariant) params = parameters;
54 
55     if (params)
56         g_variant_ref_sink(params);
57 
58     VIR_MOCK_REAL_INIT(g_dbus_connection_call_sync);
59 
60     if (STREQ(bus_name, "org.freedesktop.PolicyKit1") &&
61         STREQ(method_name, "CheckAuthorization")) {
62         g_autoptr(GVariantIter) iter = NULL;
63         GVariantBuilder builder;
64         char *type;
65         char *actionid;
66         int is_authorized = 1;
67         int is_challenge = 0;
68 
69         g_variant_get(params, "((&s@a{sv})&sa{ss}@u@s)",
70                       &type,
71                       NULL,
72                       &actionid,
73                       &iter,
74                       NULL,
75                       NULL);
76 
77         g_variant_builder_init(&builder, G_VARIANT_TYPE("a{ss}"));
78 
79         if (STREQ(actionid, "org.libvirt.test.success")) {
80             is_authorized = 1;
81             is_challenge = 0;
82         } else if (STREQ(actionid, "org.libvirt.test.challenge")) {
83             is_authorized = 0;
84             is_challenge = 1;
85         } else if (STREQ(actionid, "org.libvirt.test.cancelled")) {
86             is_authorized = 0;
87             is_challenge = 0;
88             g_variant_builder_add(&builder, "{ss}", "polkit.dismissed", "true");
89         } else if (STREQ(actionid, "org.libvirt.test.details")) {
90             char *key;
91             char *val;
92             is_authorized = 0;
93             is_challenge = 0;
94 
95             while (g_variant_iter_loop(iter, "{ss}", &key, &val)) {
96                 if (STREQ(key, "org.libvirt.test.person") && STREQ(val, "Fred")) {
97                     is_authorized = 1;
98                     is_challenge = 0;
99                 }
100             }
101         } else {
102             is_authorized = 0;
103             is_challenge = 0;
104         }
105 
106         reply = g_variant_new("((bb@a{ss}))", is_authorized, is_challenge,
107                               g_variant_builder_end(&builder));
108     } else {
109         reply = g_variant_new("()");
110     }
111 
112     return reply;
113 }
114 
115 
116 
testPolkitAuthSuccess(const void * opaque G_GNUC_UNUSED)117 static int testPolkitAuthSuccess(const void *opaque G_GNUC_UNUSED)
118 {
119     if (virPolkitCheckAuth("org.libvirt.test.success",
120                            THE_PID,
121                            THE_TIME,
122                            THE_UID,
123                            NULL,
124                            true) < 0)
125         return -1;
126 
127     return 0;
128 }
129 
130 
testPolkitAuthDenied(const void * opaque G_GNUC_UNUSED)131 static int testPolkitAuthDenied(const void *opaque G_GNUC_UNUSED)
132 {
133     int rv;
134     virErrorPtr err;
135 
136     rv = virPolkitCheckAuth("org.libvirt.test.deny",
137                             THE_PID,
138                             THE_TIME,
139                             THE_UID,
140                             NULL,
141                             true);
142 
143     if (rv == 0) {
144         fprintf(stderr, "Unexpected auth success\n");
145         return -1;
146     } else if (rv != -2) {
147         return -1;
148     }
149 
150     err = virGetLastError();
151     if (!err || !strstr(err->message,
152                         _("access denied by policy"))) {
153         fprintf(stderr, "Incorrect error response\n");
154         return -1;
155     }
156 
157     return 0;
158 }
159 
160 
testPolkitAuthChallenge(const void * opaque G_GNUC_UNUSED)161 static int testPolkitAuthChallenge(const void *opaque G_GNUC_UNUSED)
162 {
163     int rv;
164     virErrorPtr err;
165 
166     rv = virPolkitCheckAuth("org.libvirt.test.challenge",
167                             THE_PID,
168                             THE_TIME,
169                             THE_UID,
170                             NULL,
171                             true);
172 
173     if (rv == 0) {
174         fprintf(stderr, "Unexpected auth success\n");
175         return -1;
176     } else if (rv != -2) {
177         return -1;
178     }
179 
180     err = virGetLastError();
181     if (!err || err->domain != VIR_FROM_POLKIT ||
182         err->code != VIR_ERR_AUTH_UNAVAILABLE ||
183         !strstr(err->message, _("no polkit agent available to authenticate"))) {
184         fprintf(stderr, "Incorrect error response\n");
185         return -1;
186     }
187 
188     return 0;
189 }
190 
191 
testPolkitAuthCancelled(const void * opaque G_GNUC_UNUSED)192 static int testPolkitAuthCancelled(const void *opaque G_GNUC_UNUSED)
193 {
194     int rv;
195     virErrorPtr err;
196 
197     rv = virPolkitCheckAuth("org.libvirt.test.cancelled",
198                             THE_PID,
199                             THE_TIME,
200                             THE_UID,
201                             NULL,
202                             true);
203 
204     if (rv == 0) {
205         fprintf(stderr, "Unexpected auth success\n");
206         return -1;
207     } else if (rv != -2) {
208         return -1;
209     }
210 
211     err = virGetLastError();
212     if (!err || !strstr(err->message,
213                        _("user cancelled authentication process"))) {
214         fprintf(stderr, "Incorrect error response\n");
215         return -1;
216     }
217 
218     return 0;
219 }
220 
221 
testPolkitAuthDetailsSuccess(const void * opaque G_GNUC_UNUSED)222 static int testPolkitAuthDetailsSuccess(const void *opaque G_GNUC_UNUSED)
223 {
224     const char *details[] = {
225         "org.libvirt.test.person", "Fred",
226         NULL,
227     };
228 
229     if (virPolkitCheckAuth("org.libvirt.test.details",
230                            THE_PID,
231                            THE_TIME,
232                            THE_UID,
233                            details,
234                            true) < 0)
235         return -1;
236 
237     return 0;
238 }
239 
240 
testPolkitAuthDetailsDenied(const void * opaque G_GNUC_UNUSED)241 static int testPolkitAuthDetailsDenied(const void *opaque G_GNUC_UNUSED)
242 {
243     int rv;
244     virErrorPtr err;
245     const char *details[] = {
246         "org.libvirt.test.person", "Joe",
247         NULL,
248     };
249 
250     rv = virPolkitCheckAuth("org.libvirt.test.details",
251                             THE_PID,
252                             THE_TIME,
253                             THE_UID,
254                             details,
255                             true);
256 
257     if (rv == 0) {
258         fprintf(stderr, "Unexpected auth success\n");
259         return -1;
260     } else if (rv != -2) {
261         return -1;
262     }
263 
264     err = virGetLastError();
265     if (!err || !strstr(err->message,
266                         _("access denied by policy"))) {
267         fprintf(stderr, "Incorrect error response\n");
268         return -1;
269     }
270 
271     return 0;
272 }
273 
274 
275 static int
mymain(void)276 mymain(void)
277 {
278     int ret = 0;
279 
280     if (virTestRun("Polkit auth success ", testPolkitAuthSuccess, NULL) < 0)
281         ret = -1;
282     if (virTestRun("Polkit auth deny ", testPolkitAuthDenied, NULL) < 0)
283         ret = -1;
284     if (virTestRun("Polkit auth challenge ", testPolkitAuthChallenge, NULL) < 0)
285         ret = -1;
286     if (virTestRun("Polkit auth cancel ", testPolkitAuthCancelled, NULL) < 0)
287         ret = -1;
288     if (virTestRun("Polkit auth details success ", testPolkitAuthDetailsSuccess, NULL) < 0)
289         ret = -1;
290     if (virTestRun("Polkit auth details deny ", testPolkitAuthDetailsDenied, NULL) < 0)
291         ret = -1;
292 
293     return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
294 }
295 
296 VIR_TEST_MAIN_PRELOAD(mymain, VIR_TEST_MOCK("virgdbus"))
297 
298 #else /* ! __ELF__ */
299 int
300 main(void)
301 {
302     return EXIT_AM_SKIP;
303 }
304 #endif /* ! __ELF__ */
305