]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
70a5db58 LP |
2 | |
3 | #include <linux/capability.h> | |
4 | ||
5 | #include "bus-common-errors.h" | |
6 | #include "bus-polkit.h" | |
7 | #include "fd-util.h" | |
8 | #include "homed-bus.h" | |
9 | #include "homed-home-bus.h" | |
10 | #include "homed-home.h" | |
11 | #include "strv.h" | |
12 | #include "user-record-util.h" | |
13 | #include "user-util.h" | |
14 | ||
15 | static int property_get_unix_record( | |
16 | sd_bus *bus, | |
17 | const char *path, | |
18 | const char *interface, | |
19 | const char *property, | |
20 | sd_bus_message *reply, | |
21 | void *userdata, | |
22 | sd_bus_error *error) { | |
23 | ||
99534007 | 24 | Home *h = ASSERT_PTR(userdata); |
70a5db58 LP |
25 | |
26 | assert(bus); | |
27 | assert(reply); | |
70a5db58 LP |
28 | |
29 | return sd_bus_message_append( | |
30 | reply, "(suusss)", | |
31 | h->user_name, | |
32 | (uint32_t) h->uid, | |
33 | h->record ? (uint32_t) user_record_gid(h->record) : GID_INVALID, | |
34 | h->record ? user_record_real_name(h->record) : NULL, | |
35 | h->record ? user_record_home_directory(h->record) : NULL, | |
36 | h->record ? user_record_shell(h->record) : NULL); | |
37 | } | |
38 | ||
39 | static int property_get_state( | |
40 | sd_bus *bus, | |
41 | const char *path, | |
42 | const char *interface, | |
43 | const char *property, | |
44 | sd_bus_message *reply, | |
45 | void *userdata, | |
46 | sd_bus_error *error) { | |
47 | ||
99534007 | 48 | Home *h = ASSERT_PTR(userdata); |
70a5db58 LP |
49 | |
50 | assert(bus); | |
51 | assert(reply); | |
70a5db58 LP |
52 | |
53 | return sd_bus_message_append(reply, "s", home_state_to_string(home_get_state(h))); | |
54 | } | |
55 | ||
56 | int bus_home_client_is_trusted(Home *h, sd_bus_message *message) { | |
57 | _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; | |
58 | uid_t euid; | |
59 | int r; | |
60 | ||
61 | assert(h); | |
62 | ||
63 | if (!message) | |
64 | return -EINVAL; | |
65 | ||
66 | r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds); | |
67 | if (r < 0) | |
68 | return r; | |
69 | ||
70 | r = sd_bus_creds_get_euid(creds, &euid); | |
71 | if (r < 0) | |
72 | return r; | |
73 | ||
74 | return euid == 0 || h->uid == euid; | |
75 | } | |
76 | ||
77 | int bus_home_get_record_json( | |
78 | Home *h, | |
79 | sd_bus_message *message, | |
80 | char **ret, | |
81 | bool *ret_incomplete) { | |
82 | ||
83 | _cleanup_(user_record_unrefp) UserRecord *augmented = NULL; | |
84 | UserRecordLoadFlags flags; | |
85 | int r, trusted; | |
86 | ||
87 | assert(h); | |
88 | assert(ret); | |
89 | ||
90 | trusted = bus_home_client_is_trusted(h, message); | |
91 | if (trusted < 0) { | |
92 | log_warning_errno(trusted, "Failed to determine whether client is trusted, assuming untrusted."); | |
93 | trusted = false; | |
94 | } | |
95 | ||
bfc0cc1a | 96 | flags = USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_BINDING|USER_RECORD_STRIP_SECRET|USER_RECORD_ALLOW_STATUS|USER_RECORD_ALLOW_SIGNATURE|USER_RECORD_PERMISSIVE; |
70a5db58 LP |
97 | if (trusted) |
98 | flags |= USER_RECORD_ALLOW_PRIVILEGED; | |
99 | else | |
100 | flags |= USER_RECORD_STRIP_PRIVILEGED; | |
101 | ||
102 | r = home_augment_status(h, flags, &augmented); | |
103 | if (r < 0) | |
104 | return r; | |
105 | ||
106 | r = json_variant_format(augmented->json, 0, ret); | |
107 | if (r < 0) | |
108 | return r; | |
109 | ||
110 | if (ret_incomplete) | |
111 | *ret_incomplete = augmented->incomplete; | |
112 | ||
113 | return 0; | |
114 | } | |
115 | ||
116 | static int property_get_user_record( | |
117 | sd_bus *bus, | |
118 | const char *path, | |
119 | const char *interface, | |
120 | const char *property, | |
121 | sd_bus_message *reply, | |
122 | void *userdata, | |
123 | sd_bus_error *error) { | |
124 | ||
125 | _cleanup_free_ char *json = NULL; | |
99534007 | 126 | Home *h = ASSERT_PTR(userdata); |
70a5db58 LP |
127 | bool incomplete; |
128 | int r; | |
129 | ||
130 | assert(bus); | |
131 | assert(reply); | |
70a5db58 LP |
132 | |
133 | r = bus_home_get_record_json(h, sd_bus_get_current_message(bus), &json, &incomplete); | |
134 | if (r < 0) | |
135 | return r; | |
136 | ||
137 | return sd_bus_message_append(reply, "(sb)", json, incomplete); | |
138 | } | |
139 | ||
140 | int bus_home_method_activate( | |
141 | sd_bus_message *message, | |
142 | void *userdata, | |
143 | sd_bus_error *error) { | |
144 | ||
145 | _cleanup_(user_record_unrefp) UserRecord *secret = NULL; | |
99534007 | 146 | Home *h = ASSERT_PTR(userdata); |
70a5db58 LP |
147 | int r; |
148 | ||
149 | assert(message); | |
70a5db58 LP |
150 | |
151 | r = bus_message_read_secret(message, &secret, error); | |
152 | if (r < 0) | |
153 | return r; | |
154 | ||
155 | r = home_activate(h, secret, error); | |
156 | if (r < 0) | |
157 | return r; | |
158 | ||
159 | assert(r == 0); | |
160 | assert(!h->current_operation); | |
161 | ||
162 | /* The operation is now in process, keep track of this message so that we can later reply to it. */ | |
163 | r = home_set_current_message(h, message); | |
164 | if (r < 0) | |
165 | return r; | |
166 | ||
167 | return 1; | |
168 | } | |
169 | ||
170 | int bus_home_method_deactivate( | |
171 | sd_bus_message *message, | |
172 | void *userdata, | |
173 | sd_bus_error *error) { | |
174 | ||
99534007 | 175 | Home *h = ASSERT_PTR(userdata); |
70a5db58 LP |
176 | int r; |
177 | ||
178 | assert(message); | |
70a5db58 LP |
179 | |
180 | r = home_deactivate(h, false, error); | |
181 | if (r < 0) | |
182 | return r; | |
183 | ||
184 | assert(r == 0); | |
185 | assert(!h->current_operation); | |
186 | ||
187 | r = home_set_current_message(h, message); | |
188 | if (r < 0) | |
189 | return r; | |
190 | ||
191 | return 1; | |
192 | } | |
193 | ||
194 | int bus_home_method_unregister( | |
195 | sd_bus_message *message, | |
196 | void *userdata, | |
197 | sd_bus_error *error) { | |
198 | ||
99534007 | 199 | Home *h = ASSERT_PTR(userdata); |
70a5db58 LP |
200 | int r; |
201 | ||
202 | assert(message); | |
70a5db58 LP |
203 | |
204 | r = bus_verify_polkit_async( | |
205 | message, | |
206 | CAP_SYS_ADMIN, | |
207 | "org.freedesktop.home1.remove-home", | |
208 | NULL, | |
209 | true, | |
210 | UID_INVALID, | |
211 | &h->manager->polkit_registry, | |
212 | error); | |
213 | if (r < 0) | |
214 | return r; | |
215 | if (r == 0) | |
216 | return 1; /* Will call us back */ | |
217 | ||
218 | r = home_unregister(h, error); | |
219 | if (r < 0) | |
220 | return r; | |
221 | ||
222 | assert(r > 0); | |
223 | ||
224 | /* Note that home_unregister() destroyed 'h' here, so no more accesses */ | |
225 | ||
226 | return sd_bus_reply_method_return(message, NULL); | |
227 | } | |
228 | ||
229 | int bus_home_method_realize( | |
230 | sd_bus_message *message, | |
231 | void *userdata, | |
232 | sd_bus_error *error) { | |
233 | ||
234 | _cleanup_(user_record_unrefp) UserRecord *secret = NULL; | |
99534007 | 235 | Home *h = ASSERT_PTR(userdata); |
70a5db58 LP |
236 | int r; |
237 | ||
238 | assert(message); | |
70a5db58 LP |
239 | |
240 | r = bus_message_read_secret(message, &secret, error); | |
241 | if (r < 0) | |
242 | return r; | |
243 | ||
244 | r = bus_verify_polkit_async( | |
245 | message, | |
246 | CAP_SYS_ADMIN, | |
247 | "org.freedesktop.home1.create-home", | |
248 | NULL, | |
249 | true, | |
250 | UID_INVALID, | |
251 | &h->manager->polkit_registry, | |
252 | error); | |
253 | if (r < 0) | |
254 | return r; | |
255 | if (r == 0) | |
256 | return 1; /* Will call us back */ | |
257 | ||
258 | r = home_create(h, secret, error); | |
259 | if (r < 0) | |
260 | return r; | |
261 | ||
262 | assert(r == 0); | |
263 | assert(!h->current_operation); | |
264 | ||
265 | h->unregister_on_failure = false; | |
266 | ||
267 | r = home_set_current_message(h, message); | |
268 | if (r < 0) | |
269 | return r; | |
270 | ||
271 | return 1; | |
272 | } | |
273 | ||
274 | int bus_home_method_remove( | |
275 | sd_bus_message *message, | |
276 | void *userdata, | |
277 | sd_bus_error *error) { | |
278 | ||
99534007 | 279 | Home *h = ASSERT_PTR(userdata); |
70a5db58 LP |
280 | int r; |
281 | ||
282 | assert(message); | |
70a5db58 LP |
283 | |
284 | r = bus_verify_polkit_async( | |
285 | message, | |
286 | CAP_SYS_ADMIN, | |
287 | "org.freedesktop.home1.remove-home", | |
288 | NULL, | |
289 | true, | |
290 | UID_INVALID, | |
291 | &h->manager->polkit_registry, | |
292 | error); | |
293 | if (r < 0) | |
294 | return r; | |
295 | if (r == 0) | |
296 | return 1; /* Will call us back */ | |
297 | ||
298 | r = home_remove(h, error); | |
299 | if (r < 0) | |
300 | return r; | |
301 | if (r > 0) /* Done already. Note that home_remove() destroyed 'h' here, so no more accesses */ | |
302 | return sd_bus_reply_method_return(message, NULL); | |
303 | ||
304 | assert(!h->current_operation); | |
305 | ||
306 | r = home_set_current_message(h, message); | |
307 | if (r < 0) | |
308 | return r; | |
309 | ||
310 | return 1; | |
311 | } | |
312 | ||
313 | int bus_home_method_fixate( | |
314 | sd_bus_message *message, | |
315 | void *userdata, | |
316 | sd_bus_error *error) { | |
317 | ||
318 | _cleanup_(user_record_unrefp) UserRecord *secret = NULL; | |
99534007 | 319 | Home *h = ASSERT_PTR(userdata); |
70a5db58 LP |
320 | int r; |
321 | ||
322 | assert(message); | |
70a5db58 LP |
323 | |
324 | r = bus_message_read_secret(message, &secret, error); | |
325 | if (r < 0) | |
326 | return r; | |
327 | ||
328 | r = home_fixate(h, secret, error); | |
329 | if (r < 0) | |
330 | return r; | |
331 | ||
332 | assert(r == 0); | |
333 | assert(!h->current_operation); | |
334 | ||
335 | r = home_set_current_message(h, message); | |
336 | if (r < 0) | |
337 | return r; | |
338 | ||
339 | return 1; | |
340 | } | |
341 | ||
342 | int bus_home_method_authenticate( | |
343 | sd_bus_message *message, | |
344 | void *userdata, | |
345 | sd_bus_error *error) { | |
346 | ||
347 | _cleanup_(user_record_unrefp) UserRecord *secret = NULL; | |
99534007 | 348 | Home *h = ASSERT_PTR(userdata); |
70a5db58 LP |
349 | int r; |
350 | ||
351 | assert(message); | |
70a5db58 LP |
352 | |
353 | r = bus_message_read_secret(message, &secret, error); | |
354 | if (r < 0) | |
355 | return r; | |
356 | ||
357 | r = bus_verify_polkit_async( | |
358 | message, | |
359 | CAP_SYS_ADMIN, | |
360 | "org.freedesktop.home1.authenticate-home", | |
361 | NULL, | |
362 | true, | |
363 | h->uid, | |
364 | &h->manager->polkit_registry, | |
365 | error); | |
366 | if (r < 0) | |
367 | return r; | |
368 | if (r == 0) | |
369 | return 1; /* Will call us back */ | |
370 | ||
371 | r = home_authenticate(h, secret, error); | |
372 | if (r < 0) | |
373 | return r; | |
374 | ||
375 | assert(r == 0); | |
376 | assert(!h->current_operation); | |
377 | ||
378 | r = home_set_current_message(h, message); | |
379 | if (r < 0) | |
380 | return r; | |
381 | ||
382 | return 1; | |
383 | } | |
384 | ||
385 | int bus_home_method_update_record(Home *h, sd_bus_message *message, UserRecord *hr, sd_bus_error *error) { | |
386 | int r; | |
387 | ||
388 | assert(h); | |
389 | assert(message); | |
390 | assert(hr); | |
391 | ||
392 | r = user_record_is_supported(hr, error); | |
393 | if (r < 0) | |
394 | return r; | |
395 | ||
396 | r = bus_verify_polkit_async( | |
397 | message, | |
398 | CAP_SYS_ADMIN, | |
399 | "org.freedesktop.home1.update-home", | |
400 | NULL, | |
401 | true, | |
402 | UID_INVALID, | |
403 | &h->manager->polkit_registry, | |
404 | error); | |
405 | if (r < 0) | |
406 | return r; | |
407 | if (r == 0) | |
408 | return 1; /* Will call us back */ | |
409 | ||
410 | r = home_update(h, hr, error); | |
411 | if (r < 0) | |
412 | return r; | |
413 | ||
414 | assert(r == 0); | |
415 | assert(!h->current_operation); | |
416 | ||
417 | r = home_set_current_message(h, message); | |
418 | if (r < 0) | |
419 | return r; | |
420 | ||
421 | return 1; | |
422 | } | |
423 | ||
424 | int bus_home_method_update( | |
425 | sd_bus_message *message, | |
426 | void *userdata, | |
427 | sd_bus_error *error) { | |
428 | ||
429 | _cleanup_(user_record_unrefp) UserRecord *hr = NULL; | |
99534007 | 430 | Home *h = ASSERT_PTR(userdata); |
70a5db58 LP |
431 | int r; |
432 | ||
433 | assert(message); | |
70a5db58 | 434 | |
bfc0cc1a | 435 | r = bus_message_read_home_record(message, USER_RECORD_REQUIRE_REGULAR|USER_RECORD_REQUIRE_SECRET|USER_RECORD_ALLOW_PRIVILEGED|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_SIGNATURE|USER_RECORD_PERMISSIVE, &hr, error); |
70a5db58 LP |
436 | if (r < 0) |
437 | return r; | |
438 | ||
439 | return bus_home_method_update_record(h, message, hr, error); | |
440 | } | |
441 | ||
442 | int bus_home_method_resize( | |
443 | sd_bus_message *message, | |
444 | void *userdata, | |
445 | sd_bus_error *error) { | |
446 | ||
447 | _cleanup_(user_record_unrefp) UserRecord *secret = NULL; | |
99534007 | 448 | Home *h = ASSERT_PTR(userdata); |
70a5db58 LP |
449 | uint64_t sz; |
450 | int r; | |
451 | ||
452 | assert(message); | |
70a5db58 LP |
453 | |
454 | r = sd_bus_message_read(message, "t", &sz); | |
455 | if (r < 0) | |
456 | return r; | |
457 | ||
458 | r = bus_message_read_secret(message, &secret, error); | |
459 | if (r < 0) | |
460 | return r; | |
461 | ||
462 | r = bus_verify_polkit_async( | |
463 | message, | |
464 | CAP_SYS_ADMIN, | |
465 | "org.freedesktop.home1.resize-home", | |
466 | NULL, | |
467 | true, | |
468 | UID_INVALID, | |
469 | &h->manager->polkit_registry, | |
470 | error); | |
471 | if (r < 0) | |
472 | return r; | |
473 | if (r == 0) | |
474 | return 1; /* Will call us back */ | |
475 | ||
d357b80d | 476 | r = home_resize(h, sz, secret, /* automatic= */ false, error); |
70a5db58 LP |
477 | if (r < 0) |
478 | return r; | |
479 | ||
480 | assert(r == 0); | |
481 | assert(!h->current_operation); | |
482 | ||
483 | r = home_set_current_message(h, message); | |
484 | if (r < 0) | |
485 | return r; | |
486 | ||
487 | return 1; | |
488 | } | |
489 | ||
490 | int bus_home_method_change_password( | |
491 | sd_bus_message *message, | |
492 | void *userdata, | |
493 | sd_bus_error *error) { | |
494 | ||
495 | _cleanup_(user_record_unrefp) UserRecord *new_secret = NULL, *old_secret = NULL; | |
99534007 | 496 | Home *h = ASSERT_PTR(userdata); |
70a5db58 LP |
497 | int r; |
498 | ||
499 | assert(message); | |
70a5db58 LP |
500 | |
501 | r = bus_message_read_secret(message, &new_secret, error); | |
502 | if (r < 0) | |
503 | return r; | |
504 | ||
505 | r = bus_message_read_secret(message, &old_secret, error); | |
506 | if (r < 0) | |
507 | return r; | |
508 | ||
509 | r = bus_verify_polkit_async( | |
510 | message, | |
511 | CAP_SYS_ADMIN, | |
512 | "org.freedesktop.home1.passwd-home", | |
513 | NULL, | |
514 | true, | |
515 | h->uid, | |
516 | &h->manager->polkit_registry, | |
517 | error); | |
518 | if (r < 0) | |
519 | return r; | |
520 | if (r == 0) | |
521 | return 1; /* Will call us back */ | |
522 | ||
523 | r = home_passwd(h, new_secret, old_secret, error); | |
524 | if (r < 0) | |
525 | return r; | |
526 | ||
527 | assert(r == 0); | |
528 | assert(!h->current_operation); | |
529 | ||
530 | r = home_set_current_message(h, message); | |
531 | if (r < 0) | |
532 | return r; | |
533 | ||
534 | return 1; | |
535 | } | |
536 | ||
537 | int bus_home_method_lock( | |
538 | sd_bus_message *message, | |
539 | void *userdata, | |
540 | sd_bus_error *error) { | |
541 | ||
99534007 | 542 | Home *h = ASSERT_PTR(userdata); |
70a5db58 LP |
543 | int r; |
544 | ||
545 | assert(message); | |
70a5db58 LP |
546 | |
547 | r = home_lock(h, error); | |
548 | if (r < 0) | |
549 | return r; | |
550 | if (r > 0) /* Done */ | |
551 | return sd_bus_reply_method_return(message, NULL); | |
552 | ||
553 | /* The operation is now in process, keep track of this message so that we can later reply to it. */ | |
554 | assert(!h->current_operation); | |
555 | ||
556 | r = home_set_current_message(h, message); | |
557 | if (r < 0) | |
558 | return r; | |
559 | ||
560 | return 1; | |
561 | } | |
562 | ||
563 | int bus_home_method_unlock( | |
564 | sd_bus_message *message, | |
565 | void *userdata, | |
566 | sd_bus_error *error) { | |
567 | ||
568 | _cleanup_(user_record_unrefp) UserRecord *secret = NULL; | |
99534007 | 569 | Home *h = ASSERT_PTR(userdata); |
70a5db58 LP |
570 | int r; |
571 | ||
572 | assert(message); | |
70a5db58 LP |
573 | |
574 | r = bus_message_read_secret(message, &secret, error); | |
575 | if (r < 0) | |
576 | return r; | |
577 | ||
578 | r = home_unlock(h, secret, error); | |
579 | if (r < 0) | |
580 | return r; | |
581 | ||
582 | assert(r == 0); | |
583 | assert(!h->current_operation); | |
584 | ||
585 | /* The operation is now in process, keep track of this message so that we can later reply to it. */ | |
586 | r = home_set_current_message(h, message); | |
587 | if (r < 0) | |
588 | return r; | |
589 | ||
590 | return 1; | |
591 | } | |
592 | ||
593 | int bus_home_method_acquire( | |
594 | sd_bus_message *message, | |
595 | void *userdata, | |
596 | sd_bus_error *error) { | |
597 | ||
598 | _cleanup_(user_record_unrefp) UserRecord *secret = NULL; | |
599 | _cleanup_(operation_unrefp) Operation *o = NULL; | |
254d1313 | 600 | _cleanup_close_ int fd = -EBADF; |
70a5db58 | 601 | int r, please_suspend; |
99534007 | 602 | Home *h = ASSERT_PTR(userdata); |
70a5db58 LP |
603 | |
604 | assert(message); | |
70a5db58 LP |
605 | |
606 | r = bus_message_read_secret(message, &secret, error); | |
607 | if (r < 0) | |
608 | return r; | |
609 | ||
610 | r = sd_bus_message_read(message, "b", &please_suspend); | |
611 | if (r < 0) | |
612 | return r; | |
613 | ||
614 | /* This operation might not be something we can executed immediately, hence queue it */ | |
615 | fd = home_create_fifo(h, please_suspend); | |
616 | if (fd < 0) | |
80ace4f2 | 617 | return sd_bus_reply_method_errnof(message, fd, "Failed to allocate FIFO for %s: %m", h->user_name); |
70a5db58 LP |
618 | |
619 | o = operation_new(OPERATION_ACQUIRE, message); | |
620 | if (!o) | |
621 | return -ENOMEM; | |
622 | ||
623 | o->secret = TAKE_PTR(secret); | |
624 | o->send_fd = TAKE_FD(fd); | |
625 | ||
626 | r = home_schedule_operation(h, o, error); | |
627 | if (r < 0) | |
628 | return r; | |
629 | ||
630 | return 1; | |
631 | } | |
632 | ||
633 | int bus_home_method_ref( | |
634 | sd_bus_message *message, | |
635 | void *userdata, | |
636 | sd_bus_error *error) { | |
637 | ||
254d1313 | 638 | _cleanup_close_ int fd = -EBADF; |
99534007 | 639 | Home *h = ASSERT_PTR(userdata); |
70a5db58 LP |
640 | HomeState state; |
641 | int please_suspend, r; | |
642 | ||
643 | assert(message); | |
70a5db58 LP |
644 | |
645 | r = sd_bus_message_read(message, "b", &please_suspend); | |
646 | if (r < 0) | |
647 | return r; | |
648 | ||
649 | state = home_get_state(h); | |
650 | switch (state) { | |
651 | case HOME_ABSENT: | |
652 | return sd_bus_error_setf(error, BUS_ERROR_HOME_ABSENT, "Home %s is currently missing or not plugged in.", h->user_name); | |
653 | case HOME_UNFIXATED: | |
654 | case HOME_INACTIVE: | |
9be99f81 | 655 | case HOME_DIRTY: |
70a5db58 LP |
656 | return sd_bus_error_setf(error, BUS_ERROR_HOME_NOT_ACTIVE, "Home %s not active.", h->user_name); |
657 | case HOME_LOCKED: | |
658 | return sd_bus_error_setf(error, BUS_ERROR_HOME_LOCKED, "Home %s is currently locked.", h->user_name); | |
659 | default: | |
660 | if (HOME_STATE_IS_ACTIVE(state)) | |
661 | break; | |
662 | ||
663 | return sd_bus_error_setf(error, BUS_ERROR_HOME_BUSY, "An operation on home %s is currently being executed.", h->user_name); | |
664 | } | |
665 | ||
666 | fd = home_create_fifo(h, please_suspend); | |
667 | if (fd < 0) | |
80ace4f2 | 668 | return sd_bus_reply_method_errnof(message, fd, "Failed to allocate FIFO for %s: %m", h->user_name); |
70a5db58 LP |
669 | |
670 | return sd_bus_reply_method_return(message, "h", fd); | |
671 | } | |
672 | ||
673 | int bus_home_method_release( | |
674 | sd_bus_message *message, | |
675 | void *userdata, | |
676 | sd_bus_error *error) { | |
677 | ||
678 | _cleanup_(operation_unrefp) Operation *o = NULL; | |
99534007 | 679 | Home *h = ASSERT_PTR(userdata); |
70a5db58 LP |
680 | int r; |
681 | ||
682 | assert(message); | |
70a5db58 LP |
683 | |
684 | o = operation_new(OPERATION_RELEASE, message); | |
685 | if (!o) | |
686 | return -ENOMEM; | |
687 | ||
688 | r = home_schedule_operation(h, o, error); | |
689 | if (r < 0) | |
690 | return r; | |
691 | ||
692 | return 1; | |
693 | } | |
694 | ||
695 | /* We map a uid_t as uint32_t bus property, let's ensure this is safe. */ | |
696 | assert_cc(sizeof(uid_t) == sizeof(uint32_t)); | |
697 | ||
70a5db58 LP |
698 | int bus_home_path(Home *h, char **ret) { |
699 | assert(ret); | |
700 | ||
701 | return sd_bus_path_encode("/org/freedesktop/home1/home", h->user_name, ret); | |
702 | } | |
703 | ||
cfd508a9 | 704 | static int bus_home_object_find( |
70a5db58 LP |
705 | sd_bus *bus, |
706 | const char *path, | |
707 | const char *interface, | |
708 | void *userdata, | |
709 | void **found, | |
710 | sd_bus_error *error) { | |
711 | ||
712 | _cleanup_free_ char *e = NULL; | |
713 | Manager *m = userdata; | |
714 | uid_t uid; | |
715 | Home *h; | |
716 | int r; | |
717 | ||
718 | r = sd_bus_path_decode(path, "/org/freedesktop/home1/home", &e); | |
719 | if (r <= 0) | |
720 | return 0; | |
721 | ||
722 | if (parse_uid(e, &uid) >= 0) | |
723 | h = hashmap_get(m->homes_by_uid, UID_TO_PTR(uid)); | |
724 | else | |
725 | h = hashmap_get(m->homes_by_name, e); | |
726 | if (!h) | |
727 | return 0; | |
728 | ||
729 | *found = h; | |
730 | return 1; | |
731 | } | |
732 | ||
cfd508a9 | 733 | static int bus_home_node_enumerator( |
70a5db58 LP |
734 | sd_bus *bus, |
735 | const char *path, | |
736 | void *userdata, | |
737 | char ***nodes, | |
738 | sd_bus_error *error) { | |
739 | ||
740 | _cleanup_strv_free_ char **l = NULL; | |
741 | Manager *m = userdata; | |
742 | size_t k = 0; | |
70a5db58 LP |
743 | Home *h; |
744 | int r; | |
745 | ||
746 | assert(nodes); | |
747 | ||
748 | l = new0(char*, hashmap_size(m->homes_by_uid) + 1); | |
749 | if (!l) | |
750 | return -ENOMEM; | |
751 | ||
90e74a66 | 752 | HASHMAP_FOREACH(h, m->homes_by_uid) { |
70a5db58 LP |
753 | r = bus_home_path(h, l + k); |
754 | if (r < 0) | |
755 | return r; | |
52023622 YW |
756 | |
757 | k++; | |
70a5db58 LP |
758 | } |
759 | ||
760 | *nodes = TAKE_PTR(l); | |
761 | return 1; | |
762 | } | |
763 | ||
cfd508a9 ZJS |
764 | const sd_bus_vtable home_vtable[] = { |
765 | SD_BUS_VTABLE_START(0), | |
766 | ||
767 | SD_BUS_PROPERTY("UserName", "s", | |
768 | NULL, offsetof(Home, user_name), | |
769 | SD_BUS_VTABLE_PROPERTY_CONST), | |
770 | SD_BUS_PROPERTY("UID", "u", | |
771 | NULL, offsetof(Home, uid), | |
772 | SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), | |
773 | SD_BUS_PROPERTY("UnixRecord", "(suusss)", | |
774 | property_get_unix_record, 0, | |
775 | SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), | |
776 | SD_BUS_PROPERTY("State", "s", | |
777 | property_get_state, 0, | |
778 | 0), | |
779 | SD_BUS_PROPERTY("UserRecord", "(sb)", | |
780 | property_get_user_record, 0, | |
781 | SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION|SD_BUS_VTABLE_SENSITIVE), | |
782 | ||
9a814166 NK |
783 | SD_BUS_METHOD_WITH_ARGS("Activate", |
784 | SD_BUS_ARGS("s", secret), | |
785 | SD_BUS_NO_RESULT, | |
786 | bus_home_method_activate, | |
787 | SD_BUS_VTABLE_SENSITIVE), | |
cfd508a9 ZJS |
788 | SD_BUS_METHOD("Deactivate", NULL, NULL, bus_home_method_deactivate, 0), |
789 | SD_BUS_METHOD("Unregister", NULL, NULL, bus_home_method_unregister, SD_BUS_VTABLE_UNPRIVILEGED), | |
9a814166 NK |
790 | SD_BUS_METHOD_WITH_ARGS("Realize", |
791 | SD_BUS_ARGS("s", secret), | |
792 | SD_BUS_NO_RESULT, | |
793 | bus_home_method_realize, | |
794 | SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE), | |
cfd508a9 ZJS |
795 | |
796 | SD_BUS_METHOD("Remove", NULL, NULL, bus_home_method_remove, SD_BUS_VTABLE_UNPRIVILEGED), | |
9a814166 NK |
797 | SD_BUS_METHOD_WITH_ARGS("Fixate", |
798 | SD_BUS_ARGS("s", secret), | |
799 | SD_BUS_NO_RESULT, | |
800 | bus_home_method_fixate, | |
801 | SD_BUS_VTABLE_SENSITIVE), | |
802 | SD_BUS_METHOD_WITH_ARGS("Authenticate", | |
803 | SD_BUS_ARGS("s", secret), | |
804 | SD_BUS_NO_RESULT, | |
805 | bus_home_method_authenticate, | |
806 | SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE), | |
807 | SD_BUS_METHOD_WITH_ARGS("Update", | |
808 | SD_BUS_ARGS("s", user_record), | |
809 | SD_BUS_NO_RESULT, | |
810 | bus_home_method_update, | |
811 | SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE), | |
812 | SD_BUS_METHOD_WITH_ARGS("Resize", | |
813 | SD_BUS_ARGS("t", size, "s", secret), | |
814 | SD_BUS_NO_RESULT, | |
815 | bus_home_method_resize, | |
816 | SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE), | |
817 | SD_BUS_METHOD_WITH_ARGS("ChangePassword", | |
818 | SD_BUS_ARGS("s", new_secret, "s", old_secret), | |
819 | SD_BUS_NO_RESULT, | |
820 | bus_home_method_change_password, | |
821 | SD_BUS_VTABLE_UNPRIVILEGED|SD_BUS_VTABLE_SENSITIVE), | |
cfd508a9 | 822 | SD_BUS_METHOD("Lock", NULL, NULL, bus_home_method_lock, 0), |
9a814166 NK |
823 | SD_BUS_METHOD_WITH_ARGS("Unlock", |
824 | SD_BUS_ARGS("s", secret), | |
825 | SD_BUS_NO_RESULT, | |
826 | bus_home_method_unlock, | |
827 | SD_BUS_VTABLE_SENSITIVE), | |
828 | SD_BUS_METHOD_WITH_ARGS("Acquire", | |
829 | SD_BUS_ARGS("s", secret, "b", please_suspend), | |
830 | SD_BUS_RESULT("h", send_fd), | |
831 | bus_home_method_acquire, | |
832 | SD_BUS_VTABLE_SENSITIVE), | |
833 | SD_BUS_METHOD_WITH_ARGS("Ref", | |
834 | SD_BUS_ARGS("b", please_suspend), | |
835 | SD_BUS_RESULT("h", send_fd), | |
836 | bus_home_method_ref, | |
837 | 0), | |
cfd508a9 ZJS |
838 | SD_BUS_METHOD("Release", NULL, NULL, bus_home_method_release, 0), |
839 | SD_BUS_VTABLE_END | |
840 | }; | |
841 | ||
842 | const BusObjectImplementation home_object = { | |
843 | "/org/freedesktop/home1/home", | |
844 | "org.freedesktop.home1.Home", | |
845 | .fallback_vtables = BUS_FALLBACK_VTABLES({home_vtable, bus_home_object_find}), | |
846 | .node_enumerator = bus_home_node_enumerator, | |
847 | .manager = true, | |
848 | }; | |
849 | ||
70a5db58 LP |
850 | static int on_deferred_change(sd_event_source *s, void *userdata) { |
851 | _cleanup_free_ char *path = NULL; | |
99534007 | 852 | Home *h = ASSERT_PTR(userdata); |
70a5db58 LP |
853 | int r; |
854 | ||
cf536638 | 855 | h->deferred_change_event_source = sd_event_source_disable_unref(h->deferred_change_event_source); |
70a5db58 LP |
856 | |
857 | r = bus_home_path(h, &path); | |
858 | if (r < 0) { | |
859 | log_warning_errno(r, "Failed to generate home bus path, ignoring: %m"); | |
860 | return 0; | |
861 | } | |
862 | ||
863 | if (h->announced) | |
864 | r = sd_bus_emit_properties_changed_strv(h->manager->bus, path, "org.freedesktop.home1.Home", NULL); | |
865 | else | |
866 | r = sd_bus_emit_object_added(h->manager->bus, path); | |
867 | if (r < 0) | |
868 | log_warning_errno(r, "Failed to send home change event, ignoring: %m"); | |
869 | else | |
870 | h->announced = true; | |
871 | ||
872 | return 0; | |
873 | } | |
874 | ||
875 | int bus_home_emit_change(Home *h) { | |
876 | int r; | |
877 | ||
878 | assert(h); | |
879 | ||
880 | if (h->deferred_change_event_source) | |
881 | return 1; | |
882 | ||
883 | if (!h->manager->event) | |
884 | return 0; | |
885 | ||
886 | if (IN_SET(sd_event_get_state(h->manager->event), SD_EVENT_FINISHED, SD_EVENT_EXITING)) | |
887 | return 0; | |
888 | ||
889 | r = sd_event_add_defer(h->manager->event, &h->deferred_change_event_source, on_deferred_change, h); | |
890 | if (r < 0) | |
891 | return log_error_errno(r, "Failed to allocate deferred change event source: %m"); | |
892 | ||
893 | r = sd_event_source_set_priority(h->deferred_change_event_source, SD_EVENT_PRIORITY_IDLE+5); | |
894 | if (r < 0) | |
895 | log_warning_errno(r, "Failed to tweak priority of event source, ignoring: %m"); | |
896 | ||
897 | (void) sd_event_source_set_description(h->deferred_change_event_source, "deferred-change-event"); | |
898 | return 1; | |
899 | } | |
900 | ||
901 | int bus_home_emit_remove(Home *h) { | |
902 | _cleanup_free_ char *path = NULL; | |
903 | int r; | |
904 | ||
905 | assert(h); | |
906 | ||
907 | if (!h->announced) | |
908 | return 0; | |
909 | ||
2ff45772 YW |
910 | if (!h->manager) |
911 | return 0; | |
912 | ||
913 | if (!h->manager->bus) | |
914 | return 0; | |
915 | ||
70a5db58 LP |
916 | r = bus_home_path(h, &path); |
917 | if (r < 0) | |
918 | return r; | |
919 | ||
920 | r = sd_bus_emit_object_removed(h->manager->bus, path); | |
921 | if (r < 0) | |
922 | return r; | |
923 | ||
924 | h->announced = false; | |
925 | return 1; | |
926 | } |