]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/home/homework-cifs.c
896b1bf78be18df001c4183dbe3d551851ce42ca
[thirdparty/systemd.git] / src / home / homework-cifs.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
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"
12 #include "stat-util.h"
13 #include "strv.h"
14 #include "tmpfile-util.h"
15
16 int home_setup_cifs(
17 UserRecord *h,
18 HomeSetupFlags flags,
19 HomeSetup *setup) {
20
21 assert(h);
22 assert(setup);
23 assert(user_record_storage(h) == USER_CIFS);
24
25 if (FLAGS_SET(flags, HOME_SETUP_ALREADY_ACTIVATED))
26 setup->root_fd = open(user_record_home_directory(h), O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW);
27 else {
28 bool mounted = false;
29 char **pw;
30 int r;
31
32 r = home_unshare_and_mkdir();
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
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)
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",
72 h->cifs_service, HOME_RUNTIME_WORK_DIR,
73 "-o", options, NULL);
74
75 log_error_errno(errno, "Failed to execute mount: %m");
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)
90 return log_error_errno(SYNTHETIC_ERRNO(ENOKEY),
91 "Failed to mount home directory with supplied password.");
92
93 setup->root_fd = open(HOME_RUNTIME_WORK_DIR, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW);
94 }
95 if (setup->root_fd < 0)
96 return log_error_errno(errno, "Failed to open home directory: %m");
97
98 return 0;
99 }
100
101 int home_activate_cifs(
102 UserRecord *h,
103 HomeSetup *setup,
104 PasswordCache *cache,
105 UserRecord **ret_home) {
106
107 _cleanup_(user_record_unrefp) UserRecord *new_home = NULL;
108 const char *hdo, *hd;
109 int r;
110
111 assert(h);
112 assert(user_record_storage(h) == USER_CIFS);
113 assert(setup);
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));
120 hd = strdupa_safe(hdo); /* copy the string out, since it might change later in the home record object */
121
122 r = home_setup_cifs(h, 0, setup);
123 if (r < 0)
124 return r;
125
126 r = home_refresh(h, setup, NULL, cache, NULL, &new_home);
127 if (r < 0)
128 return r;
129
130 setup->root_fd = safe_close(setup->root_fd);
131
132 r = home_move_mount(NULL, hd);
133 if (r < 0)
134 return r;
135
136 setup->undo_mount = false;
137 setup->do_drop_caches = false;
138
139 log_info("Everything completed.");
140
141 *ret_home = TAKE_PTR(new_home);
142 return 1;
143 }
144
145 int home_create_cifs(UserRecord *h, HomeSetup *setup, UserRecord **ret_home) {
146 _cleanup_(user_record_unrefp) UserRecord *new_home = NULL;
147 int r;
148
149 assert(h);
150 assert(user_record_storage(h) == USER_CIFS);
151 assert(setup);
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
164 r = home_setup_cifs(h, 0, setup);
165 if (r < 0)
166 return r;
167
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)
172 return log_error_errno(SYNTHETIC_ERRNO(ENOTEMPTY), "Selected CIFS directory not empty, refusing.");
173
174 r = home_populate(h, setup->root_fd);
175 if (r < 0)
176 return r;
177
178 r = home_sync_and_statfs(setup->root_fd, NULL);
179 if (r < 0)
180 return r;
181
182 r = user_record_clone(h, USER_RECORD_LOAD_MASK_SECRET|USER_RECORD_PERMISSIVE, &new_home);
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 }