]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/home/homework-cifs.c
homework: pass header user record in home_activate_cifs()
[thirdparty/systemd.git] / src / home / homework-cifs.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
70a5db58
LP
2
3#include "dirent-util.h"
4#include "fd-util.h"
5#include "fileio.h"
6#include "format-util.h"
7#include "fs-util.h"
8#include "homework-cifs.h"
9#include "homework-mount.h"
10#include "mount-util.h"
11#include "process-util.h"
1845ba36 12#include "stat-util.h"
70a5db58
LP
13#include "strv.h"
14#include "tmpfile-util.h"
15
aa0a6214 16int home_setup_cifs(
70a5db58 17 UserRecord *h,
e1df968b 18 HomeSetupFlags flags,
70a5db58
LP
19 HomeSetup *setup) {
20
70a5db58
LP
21 assert(h);
22 assert(setup);
23 assert(user_record_storage(h) == USER_CIFS);
24
e1df968b 25 if (FLAGS_SET(flags, HOME_SETUP_ALREADY_ACTIVATED))
70a5db58
LP
26 setup->root_fd = open(user_record_home_directory(h), O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW);
27 else {
28 bool mounted = false;
00c7b071
YW
29 char **pw;
30 int r;
70a5db58 31
7cb791bc 32 r = home_unshare_and_mkdir();
70a5db58
LP
33 if (r < 0)
34 return r;
35
36 STRV_FOREACH(pw, h->password) {
37 _cleanup_(unlink_and_freep) char *p = NULL;
38 _cleanup_free_ char *options = NULL;
39 _cleanup_(fclosep) FILE *f = NULL;
40 pid_t mount_pid;
41 int exit_status;
42
43 r = fopen_temporary(NULL, &f, &p);
44 if (r < 0)
45 return log_error_errno(r, "Failed to create temporary credentials file: %m");
46
47 fprintf(f,
48 "username=%s\n"
49 "password=%s\n",
50 user_record_cifs_user_name(h),
51 *pw);
52
53 if (h->cifs_domain)
54 fprintf(f, "domain=%s\n", h->cifs_domain);
55
56 r = fflush_and_check(f);
57 if (r < 0)
58 return log_error_errno(r, "Failed to write temporary credentials file: %m");
59
60 f = safe_fclose(f);
61
279e060e
LP
62 if (asprintf(&options, "credentials=%s,uid=" UID_FMT ",forceuid,gid=" GID_FMT ",forcegid,file_mode=0%3o,dir_mode=0%3o",
63 p, h->uid, user_record_gid(h), user_record_access_mode(h), user_record_access_mode(h)) < 0)
70a5db58
LP
64 return log_oom();
65
66 r = safe_fork("(mount)", FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG|FORK_LOG|FORK_STDOUT_TO_STDERR, &mount_pid);
67 if (r < 0)
68 return r;
69 if (r == 0) {
70 /* Child */
71 execl("/bin/mount", "/bin/mount", "-n", "-t", "cifs",
498abadb 72 h->cifs_service, HOME_RUNTIME_WORK_DIR,
70a5db58
LP
73 "-o", options, NULL);
74
e070b9ea 75 log_error_errno(errno, "Failed to execute mount: %m");
70a5db58
LP
76 _exit(EXIT_FAILURE);
77 }
78
79 exit_status = wait_for_terminate_and_check("mount", mount_pid, WAIT_LOG_ABNORMAL|WAIT_LOG_NON_ZERO_EXIT_STATUS);
80 if (exit_status < 0)
81 return exit_status;
82 if (exit_status != EXIT_SUCCESS)
83 return -EPROTO;
84
85 mounted = true;
86 break;
87 }
88
89 if (!mounted)
9191142d
LP
90 return log_error_errno(SYNTHETIC_ERRNO(ENOKEY),
91 "Failed to mount home directory with supplied password.");
70a5db58 92
498abadb 93 setup->root_fd = open(HOME_RUNTIME_WORK_DIR, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW);
70a5db58
LP
94 }
95 if (setup->root_fd < 0)
00c7b071 96 return log_error_errno(errno, "Failed to open home directory: %m");
70a5db58
LP
97
98 return 0;
99}
100
101int home_activate_cifs(
102 UserRecord *h,
a74e2e44 103 HomeSetup *setup,
7b78db28 104 PasswordCache *cache,
70a5db58
LP
105 UserRecord **ret_home) {
106
de7df6c3 107 _cleanup_(user_record_unrefp) UserRecord *new_home = NULL, *header_home = NULL;
70a5db58
LP
108 const char *hdo, *hd;
109 int r;
110
111 assert(h);
112 assert(user_record_storage(h) == USER_CIFS);
a74e2e44 113 assert(setup);
70a5db58
LP
114 assert(ret_home);
115
116 if (!h->cifs_service)
117 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "User record lacks CIFS service, refusing.");
118
119 assert_se(hdo = user_record_home_directory(h));
2f82562b 120 hd = strdupa_safe(hdo); /* copy the string out, since it might change later in the home record object */
70a5db58 121
de7df6c3 122 r = home_setup(h, 0, cache, setup, &header_home);
70a5db58
LP
123 if (r < 0)
124 return r;
125
de7df6c3 126 r = home_refresh(h, setup, header_home, cache, NULL, &new_home);
70a5db58
LP
127 if (r < 0)
128 return r;
129
a74e2e44 130 setup->root_fd = safe_close(setup->root_fd);
70a5db58
LP
131
132 r = home_move_mount(NULL, hd);
133 if (r < 0)
134 return r;
135
a74e2e44 136 setup->undo_mount = false;
aa0379f1 137 setup->do_drop_caches = false;
70a5db58
LP
138
139 log_info("Everything completed.");
140
141 *ret_home = TAKE_PTR(new_home);
142 return 1;
143}
144
a74e2e44 145int home_create_cifs(UserRecord *h, HomeSetup *setup, UserRecord **ret_home) {
70a5db58 146 _cleanup_(user_record_unrefp) UserRecord *new_home = NULL;
8e06af80 147 int r;
70a5db58
LP
148
149 assert(h);
150 assert(user_record_storage(h) == USER_CIFS);
a74e2e44 151 assert(setup);
70a5db58
LP
152 assert(ret_home);
153
154 if (!h->cifs_service)
155 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "User record lacks CIFS service, refusing.");
156
157 if (access("/sbin/mount.cifs", F_OK) < 0) {
158 if (errno == ENOENT)
159 return log_error_errno(SYNTHETIC_ERRNO(ENOLINK), "/sbin/mount.cifs is missing.");
160
161 return log_error_errno(errno, "Unable to detect whether /sbin/mount.cifs exists: %m");
162 }
163
a74e2e44 164 r = home_setup_cifs(h, 0, setup);
70a5db58
LP
165 if (r < 0)
166 return r;
167
1845ba36
LP
168 r = dir_is_empty_at(setup->root_fd, NULL);
169 if (r < 0)
170 return log_error_errno(r, "Failed to detect if CIFS directory is empty: %m");
171 if (r == 0)
70a5db58 172 return log_error_errno(SYNTHETIC_ERRNO(ENOTEMPTY), "Selected CIFS directory not empty, refusing.");
70a5db58 173
a74e2e44 174 r = home_populate(h, setup->root_fd);
70a5db58
LP
175 if (r < 0)
176 return r;
177
a74e2e44 178 r = home_sync_and_statfs(setup->root_fd, NULL);
70a5db58
LP
179 if (r < 0)
180 return r;
181
bfc0cc1a 182 r = user_record_clone(h, USER_RECORD_LOAD_MASK_SECRET|USER_RECORD_PERMISSIVE, &new_home);
70a5db58
LP
183 if (r < 0)
184 return log_error_errno(r, "Failed to clone record: %m");
185
186 r = user_record_add_binding(
187 new_home,
188 USER_CIFS,
189 NULL,
190 SD_ID128_NULL,
191 SD_ID128_NULL,
192 SD_ID128_NULL,
193 NULL,
194 NULL,
195 UINT64_MAX,
196 NULL,
197 NULL,
198 h->uid,
199 (gid_t) h->uid);
200 if (r < 0)
201 return log_error_errno(r, "Failed to add binding to record: %m");
202
203 log_info("Everything completed.");
204
205 *ret_home = TAKE_PTR(new_home);
206 return 0;
207}