]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-bus/bus-convenience.c
util-lib: split our string related calls from util.[ch] into its own file string...
[thirdparty/systemd.git] / src / libsystemd / sd-bus / bus-convenience.c
CommitLineData
992c052c
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include "bus-internal.h"
23#include "bus-message.h"
24#include "bus-signature.h"
e5609878 25#include "bus-type.h"
07630cea
LP
26#include "bus-util.h"
27#include "string-util.h"
992c052c 28
d9f644e2 29_public_ int sd_bus_emit_signal(
992c052c
LP
30 sd_bus *bus,
31 const char *path,
32 const char *interface,
33 const char *member,
34 const char *types, ...) {
35
36 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
37 int r;
38
f69dc9a3 39 assert_return(bus, -EINVAL);
f69dc9a3 40 assert_return(!bus_pid_changed(bus), -ECHILD);
992c052c 41
a3d59cd1
LP
42 if (!BUS_IS_OPEN(bus->state))
43 return -ENOTCONN;
44
151b9b96 45 r = sd_bus_message_new_signal(bus, &m, path, interface, member);
992c052c
LP
46 if (r < 0)
47 return r;
48
49 if (!isempty(types)) {
50 va_list ap;
51
52 va_start(ap, types);
53 r = bus_message_append_ap(m, types, ap);
54 va_end(ap);
55 if (r < 0)
56 return r;
57 }
58
59 return sd_bus_send(bus, m, NULL);
60}
61
5d941c92
UTL
62_public_ int sd_bus_call_method_async(
63 sd_bus *bus,
64 sd_bus_slot **slot,
65 const char *destination,
66 const char *path,
67 const char *interface,
68 const char *member,
69 sd_bus_message_handler_t callback,
70 void *userdata,
71 const char *types, ...) {
72
73 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
74 int r;
75
76 assert_return(bus, -EINVAL);
77 assert_return(!bus_pid_changed(bus), -ECHILD);
78
79 if (!BUS_IS_OPEN(bus->state))
80 return -ENOTCONN;
81
82 r = sd_bus_message_new_method_call(bus, &m, destination, path, interface, member);
83 if (r < 0)
84 return r;
85
86 if (!isempty(types)) {
87 va_list ap;
88
89 va_start(ap, types);
90 r = bus_message_append_ap(m, types, ap);
91 va_end(ap);
92 if (r < 0)
93 return r;
94 }
95
96 return sd_bus_call_async(bus, slot, m, callback, userdata, 0);
97}
98
d9f644e2 99_public_ int sd_bus_call_method(
992c052c
LP
100 sd_bus *bus,
101 const char *destination,
102 const char *path,
103 const char *interface,
104 const char *member,
105 sd_bus_error *error,
106 sd_bus_message **reply,
107 const char *types, ...) {
108
109 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
110 int r;
111
759e02e7
LP
112 bus_assert_return(bus, -EINVAL, error);
113 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
992c052c 114
759e02e7
LP
115 if (!BUS_IS_OPEN(bus->state)) {
116 r = -ENOTCONN;
117 goto fail;
118 }
a3d59cd1 119
151b9b96 120 r = sd_bus_message_new_method_call(bus, &m, destination, path, interface, member);
992c052c 121 if (r < 0)
759e02e7 122 goto fail;
992c052c
LP
123
124 if (!isempty(types)) {
125 va_list ap;
126
127 va_start(ap, types);
128 r = bus_message_append_ap(m, types, ap);
129 va_end(ap);
130 if (r < 0)
759e02e7 131 goto fail;
992c052c
LP
132 }
133
c49b30a2 134 return sd_bus_call(bus, m, 0, error, reply);
759e02e7
LP
135
136fail:
137 return sd_bus_error_set_errno(error, r);
992c052c
LP
138}
139
d9f644e2 140_public_ int sd_bus_reply_method_return(
992c052c
LP
141 sd_bus_message *call,
142 const char *types, ...) {
143
144 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
145 int r;
146
f69dc9a3
LP
147 assert_return(call, -EINVAL);
148 assert_return(call->sealed, -EPERM);
40ca29a1 149 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
a3d59cd1 150 assert_return(call->bus, -EINVAL);
df2d202e 151 assert_return(!bus_pid_changed(call->bus), -ECHILD);
992c052c 152
a3d59cd1
LP
153 if (!BUS_IS_OPEN(call->bus->state))
154 return -ENOTCONN;
155
0461f8cd 156 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
992c052c
LP
157 return 0;
158
df2d202e 159 r = sd_bus_message_new_method_return(call, &m);
992c052c
LP
160 if (r < 0)
161 return r;
162
163 if (!isempty(types)) {
164 va_list ap;
165
166 va_start(ap, types);
167 r = bus_message_append_ap(m, types, ap);
168 va_end(ap);
169 if (r < 0)
170 return r;
171 }
172
df2d202e 173 return sd_bus_send(call->bus, m, NULL);
992c052c
LP
174}
175
d9f644e2 176_public_ int sd_bus_reply_method_error(
992c052c
LP
177 sd_bus_message *call,
178 const sd_bus_error *e) {
179
180 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
181 int r;
182
f69dc9a3
LP
183 assert_return(call, -EINVAL);
184 assert_return(call->sealed, -EPERM);
40ca29a1 185 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
f69dc9a3 186 assert_return(sd_bus_error_is_set(e), -EINVAL);
a3d59cd1 187 assert_return(call->bus, -EINVAL);
df2d202e 188 assert_return(!bus_pid_changed(call->bus), -ECHILD);
992c052c 189
a3d59cd1
LP
190 if (!BUS_IS_OPEN(call->bus->state))
191 return -ENOTCONN;
192
0461f8cd 193 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
992c052c
LP
194 return 0;
195
151b9b96 196 r = sd_bus_message_new_method_error(call, &m, e);
992c052c
LP
197 if (r < 0)
198 return r;
199
df2d202e 200 return sd_bus_send(call->bus, m, NULL);
992c052c
LP
201}
202
d9f644e2 203_public_ int sd_bus_reply_method_errorf(
992c052c
LP
204 sd_bus_message *call,
205 const char *name,
206 const char *format,
207 ...) {
208
209 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
210 va_list ap;
992c052c 211
f69dc9a3
LP
212 assert_return(call, -EINVAL);
213 assert_return(call->sealed, -EPERM);
40ca29a1 214 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
a3d59cd1 215 assert_return(call->bus, -EINVAL);
df2d202e 216 assert_return(!bus_pid_changed(call->bus), -ECHILD);
f69dc9a3 217
a3d59cd1
LP
218 if (!BUS_IS_OPEN(call->bus->state))
219 return -ENOTCONN;
220
0461f8cd 221 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
f69dc9a3
LP
222 return 0;
223
40ca29a1 224 va_start(ap, format);
780896a4 225 bus_error_setfv(&error, name, format, ap);
40ca29a1 226 va_end(ap);
992c052c 227
df2d202e 228 return sd_bus_reply_method_error(call, &error);
40ca29a1 229}
992c052c 230
d9f644e2 231_public_ int sd_bus_reply_method_errno(
40ca29a1
LP
232 sd_bus_message *call,
233 int error,
234 const sd_bus_error *p) {
992c052c 235
40ca29a1
LP
236 _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
237
40ca29a1
LP
238 assert_return(call, -EINVAL);
239 assert_return(call->sealed, -EPERM);
240 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
a3d59cd1 241 assert_return(call->bus, -EINVAL);
df2d202e 242 assert_return(!bus_pid_changed(call->bus), -ECHILD);
40ca29a1 243
a3d59cd1
LP
244 if (!BUS_IS_OPEN(call->bus->state))
245 return -ENOTCONN;
246
0461f8cd 247 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
40ca29a1
LP
248 return 0;
249
250 if (sd_bus_error_is_set(p))
df2d202e 251 return sd_bus_reply_method_error(call, p);
40ca29a1
LP
252
253 sd_bus_error_set_errno(&berror, error);
254
df2d202e 255 return sd_bus_reply_method_error(call, &berror);
40ca29a1
LP
256}
257
d9f644e2 258_public_ int sd_bus_reply_method_errnof(
40ca29a1
LP
259 sd_bus_message *call,
260 int error,
261 const char *format,
262 ...) {
263
264 _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
265 va_list ap;
266
40ca29a1
LP
267 assert_return(call, -EINVAL);
268 assert_return(call->sealed, -EPERM);
269 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
a3d59cd1 270 assert_return(call->bus, -EINVAL);
df2d202e 271 assert_return(!bus_pid_changed(call->bus), -ECHILD);
40ca29a1 272
a3d59cd1
LP
273 if (!BUS_IS_OPEN(call->bus->state))
274 return -ENOTCONN;
275
0461f8cd 276 if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
40ca29a1
LP
277 return 0;
278
279 va_start(ap, format);
07a0d22f 280 sd_bus_error_set_errnofv(&berror, error, format, ap);
40ca29a1
LP
281 va_end(ap);
282
df2d202e 283 return sd_bus_reply_method_error(call, &berror);
992c052c
LP
284}
285
d9f644e2 286_public_ int sd_bus_get_property(
992c052c
LP
287 sd_bus *bus,
288 const char *destination,
289 const char *path,
290 const char *interface,
291 const char *member,
292 sd_bus_error *error,
293 sd_bus_message **reply,
294 const char *type) {
295
296 sd_bus_message *rep = NULL;
297 int r;
298
759e02e7
LP
299 bus_assert_return(bus, -EINVAL, error);
300 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
301 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
302 bus_assert_return(reply, -EINVAL, error);
303 bus_assert_return(signature_is_single(type, false), -EINVAL, error);
304 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
992c052c 305
759e02e7
LP
306 if (!BUS_IS_OPEN(bus->state)) {
307 r = -ENOTCONN;
308 goto fail;
309 }
a3d59cd1 310
992c052c
LP
311 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &rep, "ss", strempty(interface), member);
312 if (r < 0)
313 return r;
314
315 r = sd_bus_message_enter_container(rep, 'v', type);
316 if (r < 0) {
317 sd_bus_message_unref(rep);
759e02e7 318 goto fail;
992c052c
LP
319 }
320
321 *reply = rep;
322 return 0;
759e02e7
LP
323
324fail:
325 return sd_bus_error_set_errno(error, r);
992c052c
LP
326}
327
d9f644e2 328_public_ int sd_bus_get_property_trivial(
e5609878
LP
329 sd_bus *bus,
330 const char *destination,
331 const char *path,
332 const char *interface,
333 const char *member,
334 sd_bus_error *error,
335 char type, void *ptr) {
336
337 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
338 int r;
339
759e02e7
LP
340 bus_assert_return(bus, -EINVAL, error);
341 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
342 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
343 bus_assert_return(bus_type_is_trivial(type), -EINVAL, error);
344 bus_assert_return(ptr, -EINVAL, error);
345 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
e5609878 346
759e02e7
LP
347 if (!BUS_IS_OPEN(bus->state)) {
348 r = -ENOTCONN;
349 goto fail;
350 }
a3d59cd1 351
e5609878
LP
352 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
353 if (r < 0)
354 return r;
355
356 r = sd_bus_message_enter_container(reply, 'v', CHAR_TO_STR(type));
357 if (r < 0)
759e02e7 358 goto fail;
e5609878
LP
359
360 r = sd_bus_message_read_basic(reply, type, ptr);
361 if (r < 0)
759e02e7 362 goto fail;
e5609878
LP
363
364 return 0;
759e02e7
LP
365
366fail:
367 return sd_bus_error_set_errno(error, r);
e5609878
LP
368}
369
63be1989
LP
370_public_ int sd_bus_get_property_string(
371 sd_bus *bus,
372 const char *destination,
373 const char *path,
374 const char *interface,
375 const char *member,
376 sd_bus_error *error,
377 char **ret) {
378
379 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
380 const char *s;
381 char *n;
382 int r;
383
759e02e7
LP
384 bus_assert_return(bus, -EINVAL, error);
385 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
386 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
387 bus_assert_return(ret, -EINVAL, error);
388 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
63be1989 389
759e02e7
LP
390 if (!BUS_IS_OPEN(bus->state)) {
391 r = -ENOTCONN;
392 goto fail;
393 }
a3d59cd1 394
63be1989
LP
395 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
396 if (r < 0)
397 return r;
398
399 r = sd_bus_message_enter_container(reply, 'v', "s");
400 if (r < 0)
759e02e7 401 goto fail;
63be1989
LP
402
403 r = sd_bus_message_read_basic(reply, 's', &s);
404 if (r < 0)
759e02e7 405 goto fail;
63be1989
LP
406
407 n = strdup(s);
759e02e7
LP
408 if (!n) {
409 r = -ENOMEM;
410 goto fail;
411 }
63be1989
LP
412
413 *ret = n;
414 return 0;
759e02e7
LP
415
416fail:
417 return sd_bus_error_set_errno(error, r);
63be1989
LP
418}
419
420_public_ int sd_bus_get_property_strv(
421 sd_bus *bus,
422 const char *destination,
423 const char *path,
424 const char *interface,
425 const char *member,
426 sd_bus_error *error,
427 char ***ret) {
428
429 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
430 int r;
431
759e02e7
LP
432 bus_assert_return(bus, -EINVAL, error);
433 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
434 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
435 bus_assert_return(ret, -EINVAL, error);
436 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
63be1989 437
759e02e7
LP
438 if (!BUS_IS_OPEN(bus->state)) {
439 r = -ENOTCONN;
440 goto fail;
441 }
a3d59cd1 442
63be1989
LP
443 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
444 if (r < 0)
445 return r;
446
447 r = sd_bus_message_enter_container(reply, 'v', NULL);
448 if (r < 0)
759e02e7 449 goto fail;
63be1989
LP
450
451 r = sd_bus_message_read_strv(reply, ret);
452 if (r < 0)
759e02e7 453 goto fail;
63be1989
LP
454
455 return 0;
759e02e7
LP
456
457fail:
458 return sd_bus_error_set_errno(error, r);
63be1989
LP
459}
460
d9f644e2 461_public_ int sd_bus_set_property(
992c052c
LP
462 sd_bus *bus,
463 const char *destination,
464 const char *path,
465 const char *interface,
466 const char *member,
467 sd_bus_error *error,
468 const char *type, ...) {
469
470 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
471 va_list ap;
472 int r;
473
759e02e7
LP
474 bus_assert_return(bus, -EINVAL, error);
475 bus_assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL, error);
476 bus_assert_return(member_name_is_valid(member), -EINVAL, error);
477 bus_assert_return(signature_is_single(type, false), -EINVAL, error);
478 bus_assert_return(!bus_pid_changed(bus), -ECHILD, error);
992c052c 479
759e02e7
LP
480 if (!BUS_IS_OPEN(bus->state)) {
481 r = -ENOTCONN;
482 goto fail;
483 }
a3d59cd1 484
151b9b96 485 r = sd_bus_message_new_method_call(bus, &m, destination, path, "org.freedesktop.DBus.Properties", "Set");
992c052c 486 if (r < 0)
759e02e7 487 goto fail;
992c052c
LP
488
489 r = sd_bus_message_append(m, "ss", strempty(interface), member);
490 if (r < 0)
759e02e7 491 goto fail;
992c052c
LP
492
493 r = sd_bus_message_open_container(m, 'v', type);
494 if (r < 0)
759e02e7 495 goto fail;
992c052c
LP
496
497 va_start(ap, type);
498 r = bus_message_append_ap(m, type, ap);
499 va_end(ap);
500 if (r < 0)
759e02e7 501 goto fail;
992c052c
LP
502
503 r = sd_bus_message_close_container(m);
504 if (r < 0)
759e02e7 505 goto fail;
992c052c 506
c49b30a2 507 return sd_bus_call(bus, m, 0, error, NULL);
759e02e7
LP
508
509fail:
510 return sd_bus_error_set_errno(error, r);
992c052c 511}
5b12334d
LP
512
513_public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **creds) {
514 sd_bus_creds *c;
515
516 assert_return(call, -EINVAL);
517 assert_return(call->sealed, -EPERM);
a3d59cd1 518 assert_return(call->bus, -EINVAL);
5b12334d
LP
519 assert_return(!bus_pid_changed(call->bus), -ECHILD);
520
a3d59cd1
LP
521 if (!BUS_IS_OPEN(call->bus->state))
522 return -ENOTCONN;
523
5b12334d
LP
524 c = sd_bus_message_get_creds(call);
525
526 /* All data we need? */
527 if (c && (mask & ~c->mask) == 0) {
528 *creds = sd_bus_creds_ref(c);
529 return 0;
530 }
531
532 /* No data passed? Or not enough data passed to retrieve the missing bits? */
533 if (!c || !(c->mask & SD_BUS_CREDS_PID)) {
534 /* We couldn't read anything from the call, let's try
2d0c1561 535 * to get it from the sender or peer. */
5b12334d
LP
536
537 if (call->sender)
2d0c1561
LP
538 /* There's a sender, but the creds are
539 * missing. This means we are talking via
540 * dbus1, or are getting a message that was
541 * sent to us via kdbus, but was converted
542 * from a dbus1 message by the bus-proxy and
543 * thus also lacks the creds. */
056f95d0 544 return sd_bus_get_name_creds(call->bus, call->sender, mask, creds);
5b12334d 545 else
2d0c1561
LP
546 /* There's no sender, hence we are on a dbus1
547 * direct connection. For direct connections
548 * the credentials of the AF_UNIX peer matter,
549 * which may be queried via
550 * sd_bus_get_owner_creds(). */
056f95d0 551 return sd_bus_get_owner_creds(call->bus, mask, creds);
5b12334d
LP
552 }
553
49b832c5 554 return bus_creds_extend_by_pid(c, mask, creds);
5b12334d 555}
def9a7aa
LP
556
557_public_ int sd_bus_query_sender_privilege(sd_bus_message *call, int capability) {
558 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
559 uid_t our_uid;
705a415f 560 bool know_caps = false;
def9a7aa
LP
561 int r;
562
563 assert_return(call, -EINVAL);
564 assert_return(call->sealed, -EPERM);
565 assert_return(call->bus, -EINVAL);
566 assert_return(!bus_pid_changed(call->bus), -ECHILD);
567
568 if (!BUS_IS_OPEN(call->bus->state))
569 return -ENOTCONN;
570
705a415f 571 if (capability >= 0) {
0f514420 572
705a415f 573 r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS, &creds);
def9a7aa
LP
574 if (r < 0)
575 return r;
576
0f514420
LP
577 /* We cannot use augmented caps for authorization,
578 * since then data is acquired raceful from
579 * /proc. This can never actually happen, but let's
580 * better be safe than sorry, and do an extra check
581 * here. */
582 assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_EFFECTIVE_CAPS) == 0, -EPERM);
583
705a415f
LP
584 /* Note that not even on kdbus we might have the caps
585 * field, due to faked identities, or namespace
586 * translation issues. */
def9a7aa
LP
587 r = sd_bus_creds_has_effective_cap(creds, capability);
588 if (r > 0)
589 return 1;
705a415f
LP
590 if (r == 0)
591 know_caps = true;
def9a7aa 592 } else {
705a415f 593 r = sd_bus_query_sender_creds(call, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID, &creds);
def9a7aa
LP
594 if (r < 0)
595 return r;
596 }
597
598 /* Now, check the UID, but only if the capability check wasn't
599 * sufficient */
600 our_uid = getuid();
705a415f 601 if (our_uid != 0 || !know_caps || capability < 0) {
def9a7aa
LP
602 uid_t sender_uid;
603
0f514420
LP
604 /* We cannot use augmented uid/euid for authorization,
605 * since then data is acquired raceful from
606 * /proc. This can never actually happen, but let's
607 * better be safe than sorry, and do an extra check
608 * here. */
609 assert_return((sd_bus_creds_get_augmented_mask(creds) & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID)) == 0, -EPERM);
610
705a415f
LP
611 /* Try to use the EUID, if we have it. */
612 r = sd_bus_creds_get_euid(creds, &sender_uid);
613 if (r < 0)
614 r = sd_bus_creds_get_uid(creds, &sender_uid);
615
def9a7aa
LP
616 if (r >= 0) {
617 /* Sender has same UID as us, then let's grant access */
618 if (sender_uid == our_uid)
619 return 1;
620
621 /* Sender is root, we are not root. */
622 if (our_uid != 0 && sender_uid == 0)
623 return 1;
624 }
625 }
626
627 return 0;
628}