1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
8 #include "data-fd-util.h"
9 #include "dirent-util.h"
12 #include "format-util.h"
14 #include "homework-cifs.h"
15 #include "homework-mount.h"
17 #include "mount-util.h"
18 #include "process-util.h"
19 #include "stat-util.h"
21 #include "tmpfile-util.h"
28 _cleanup_free_
char *chost
= NULL
, *cservice
= NULL
, *cdir
= NULL
, *chost_and_service
= NULL
, *j
= NULL
, *options
= NULL
;
32 assert(user_record_storage(h
) == USER_CIFS
);
34 assert(!setup
->undo_mount
);
35 assert(setup
->root_fd
< 0);
37 if (FLAGS_SET(flags
, HOME_SETUP_ALREADY_ACTIVATED
)) {
38 setup
->root_fd
= open(user_record_home_directory(h
), O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
39 if (setup
->root_fd
< 0)
40 return log_error_errno(errno
, "Failed to open home directory: %m");
46 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "User record lacks CIFS service, refusing.");
48 r
= parse_cifs_service(h
->cifs_service
, &chost
, &cservice
, &cdir
);
50 return log_error_errno(r
, "Failed parse CIFS service specification: %m");
52 /* Just the host and service part, without the directory */
53 chost_and_service
= strjoin("//", chost
, "/", cservice
);
54 if (!chost_and_service
)
57 if (asprintf(&options
, "user=%s,uid=" UID_FMT
",forceuid,gid=" GID_FMT
",forcegid,file_mode=0%3o,dir_mode=0%3o",
58 user_record_cifs_user_name(h
), h
->uid
, user_record_gid(h
), user_record_access_mode(h
),
59 user_record_access_mode(h
)) < 0)
63 if (strextendf_with_separator(&options
, ",", "domain=%s", h
->cifs_domain
) < 0)
66 if (h
->cifs_extra_mount_options
)
67 if (!strextend_with_separator(&options
, ",", h
->cifs_extra_mount_options
))
70 r
= home_unshare_and_mkdir();
74 STRV_FOREACH(pw
, h
->password
) {
75 _cleanup_close_
int passwd_fd
= -EBADF
;
79 passwd_fd
= acquire_data_fd(*pw
);
81 return log_error_errno(passwd_fd
, "Failed to create data FD for password: %m");
83 r
= safe_fork("(mount)", FORK_RESET_SIGNALS
|FORK_RLIMIT_NOFILE_SAFE
|FORK_DEATHSIG_SIGTERM
|FORK_LOG
|FORK_STDOUT_TO_STDERR
, &mount_pid
);
89 r
= fd_cloexec(passwd_fd
, false);
91 log_error_errno(r
, "Failed to disable CLOEXEC on password FD: %m");
95 r
= setenvf("PASSWD_FD", /* overwrite= */ true, "%d", passwd_fd
);
97 log_error_errno(r
, "Failed to set $PASSWD_FD: %m");
101 execl("/bin/mount", "/bin/mount", "-n", "-t", "cifs",
102 chost_and_service
, HOME_RUNTIME_WORK_DIR
,
103 "-o", options
, NULL
);
105 log_error_errno(errno
, "Failed to execute mount: %m");
109 exit_status
= wait_for_terminate_and_check("mount", mount_pid
, WAIT_LOG_ABNORMAL
|WAIT_LOG_NON_ZERO_EXIT_STATUS
);
112 if (exit_status
== EXIT_SUCCESS
) {
113 setup
->undo_mount
= true;
118 log_info("CIFS mount failed with password #%zu, trying next password.", (size_t) (pw
- h
->password
) + 1);
121 if (!setup
->undo_mount
)
122 return log_error_errno(SYNTHETIC_ERRNO(ENOKEY
),
123 "Failed to mount home directory, supplied password(s) possibly wrong.");
125 /* Adjust MS_SUID and similar flags */
126 r
= mount_nofollow_verbose(LOG_ERR
, NULL
, HOME_RUNTIME_WORK_DIR
, NULL
, MS_BIND
|MS_REMOUNT
|user_record_mount_flags(h
), NULL
);
131 j
= path_join(HOME_RUNTIME_WORK_DIR
, cdir
);
135 if (FLAGS_SET(flags
, HOME_SETUP_CIFS_MKDIR
)) {
136 setup
->root_fd
= open_mkdir_at(AT_FDCWD
, j
, O_CLOEXEC
, 0700);
137 if (setup
->root_fd
< 0)
138 return log_error_errno(setup
->root_fd
, "Failed to create CIFS subdirectory: %m");
142 if (setup
->root_fd
< 0) {
143 setup
->root_fd
= open(j
?: HOME_RUNTIME_WORK_DIR
, O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
144 if (setup
->root_fd
< 0)
145 return log_error_errno(errno
, "Failed to open home directory: %m");
148 setup
->mount_suffix
= TAKE_PTR(cdir
);
152 int home_activate_cifs(
154 HomeSetupFlags flags
,
156 PasswordCache
*cache
,
157 UserRecord
**ret_home
) {
159 _cleanup_(user_record_unrefp
) UserRecord
*new_home
= NULL
, *header_home
= NULL
;
160 const char *hdo
, *hd
;
164 assert(user_record_storage(h
) == USER_CIFS
);
168 assert_se(hdo
= user_record_home_directory(h
));
169 hd
= strdupa_safe(hdo
); /* copy the string out, since it might change later in the home record object */
171 r
= home_setup(h
, 0, setup
, cache
, &header_home
);
175 r
= home_refresh(h
, flags
, setup
, header_home
, cache
, NULL
, &new_home
);
179 setup
->root_fd
= safe_close(setup
->root_fd
);
181 r
= home_move_mount(setup
->mount_suffix
, hd
);
185 setup
->undo_mount
= false;
186 setup
->do_drop_caches
= false;
188 log_info("Everything completed.");
190 *ret_home
= TAKE_PTR(new_home
);
194 int home_create_cifs(UserRecord
*h
, HomeSetup
*setup
, UserRecord
**ret_home
) {
195 _cleanup_(user_record_unrefp
) UserRecord
*new_home
= NULL
;
199 assert(user_record_storage(h
) == USER_CIFS
);
203 if (!h
->cifs_service
)
204 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "User record lacks CIFS service, refusing.");
206 if (access("/sbin/mount.cifs", F_OK
) < 0) {
208 return log_error_errno(SYNTHETIC_ERRNO(ENOLINK
), "/sbin/mount.cifs is missing.");
210 return log_error_errno(errno
, "Unable to detect whether /sbin/mount.cifs exists: %m");
213 r
= home_setup_cifs(h
, HOME_SETUP_CIFS_MKDIR
, setup
);
217 r
= dir_is_empty_at(setup
->root_fd
, NULL
, /* ignore_hidden_or_backup= */ false);
219 return log_error_errno(r
, "Failed to detect if CIFS directory is empty: %m");
221 return log_error_errno(SYNTHETIC_ERRNO(ENOTEMPTY
), "Selected CIFS directory not empty, refusing.");
223 r
= home_populate(h
, setup
->root_fd
);
227 r
= home_sync_and_statfs(setup
->root_fd
, NULL
);
231 r
= user_record_clone(h
, USER_RECORD_LOAD_MASK_SECRET
|USER_RECORD_PERMISSIVE
, &new_home
);
233 return log_error_errno(r
, "Failed to clone record: %m");
235 r
= user_record_add_binding(
250 return log_error_errno(r
, "Failed to add binding to record: %m");
252 log_info("Everything completed.");
254 *ret_home
= TAKE_PTR(new_home
);