1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include "dirent-util.h"
6 #include "format-util.h"
8 #include "homework-cifs.h"
9 #include "homework-mount.h"
11 #include "mount-util.h"
12 #include "process-util.h"
13 #include "stat-util.h"
15 #include "tmpfile-util.h"
22 _cleanup_free_
char *chost
= NULL
, *cservice
= NULL
, *cdir
= NULL
, *chost_and_service
= NULL
, *j
= NULL
;
27 assert(user_record_storage(h
) == USER_CIFS
);
29 assert(!setup
->undo_mount
);
30 assert(setup
->root_fd
< 0);
32 if (FLAGS_SET(flags
, HOME_SETUP_ALREADY_ACTIVATED
)) {
33 setup
->root_fd
= open(user_record_home_directory(h
), O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
34 if (setup
->root_fd
< 0)
35 return log_error_errno(errno
, "Failed to open home directory: %m");
41 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "User record lacks CIFS service, refusing.");
43 r
= parse_cifs_service(h
->cifs_service
, &chost
, &cservice
, &cdir
);
45 return log_error_errno(r
, "Failed parse CIFS service specification: %m");
47 /* Just the host and service part, without the directory */
48 chost_and_service
= strjoin("//", chost
, "/", cservice
);
49 if (!chost_and_service
)
52 r
= home_unshare_and_mkdir();
56 STRV_FOREACH(pw
, h
->password
) {
57 _cleanup_(unlink_and_freep
) char *p
= NULL
;
58 _cleanup_free_
char *options
= NULL
;
59 _cleanup_(fclosep
) FILE *f
= NULL
;
63 r
= fopen_temporary(NULL
, &f
, &p
);
65 return log_error_errno(r
, "Failed to create temporary credentials file: %m");
70 user_record_cifs_user_name(h
),
74 fprintf(f
, "domain=%s\n", h
->cifs_domain
);
76 r
= fflush_and_check(f
);
78 return log_error_errno(r
, "Failed to write temporary credentials file: %m");
82 if (asprintf(&options
, "credentials=%s,uid=" UID_FMT
",forceuid,gid=" GID_FMT
",forcegid,file_mode=0%3o,dir_mode=0%3o",
83 p
, h
->uid
, user_record_gid(h
), user_record_access_mode(h
), user_record_access_mode(h
)) < 0)
86 r
= safe_fork("(mount)", FORK_RESET_SIGNALS
|FORK_RLIMIT_NOFILE_SAFE
|FORK_DEATHSIG
|FORK_LOG
|FORK_STDOUT_TO_STDERR
, &mount_pid
);
91 execl("/bin/mount", "/bin/mount", "-n", "-t", "cifs",
92 chost_and_service
, HOME_RUNTIME_WORK_DIR
,
95 log_error_errno(errno
, "Failed to execute mount: %m");
99 exit_status
= wait_for_terminate_and_check("mount", mount_pid
, WAIT_LOG_ABNORMAL
|WAIT_LOG_NON_ZERO_EXIT_STATUS
);
102 if (exit_status
!= EXIT_SUCCESS
)
105 setup
->undo_mount
= true;
109 if (!setup
->undo_mount
)
110 return log_error_errno(SYNTHETIC_ERRNO(ENOKEY
),
111 "Failed to mount home directory with supplied password.");
113 /* Adjust MS_SUID and similar flags */
114 r
= mount_nofollow_verbose(LOG_ERR
, NULL
, HOME_RUNTIME_WORK_DIR
, NULL
, MS_BIND
|MS_REMOUNT
|user_record_mount_flags(h
), NULL
);
119 j
= path_join(HOME_RUNTIME_WORK_DIR
, cdir
);
123 if (FLAGS_SET(flags
, HOME_SETUP_CIFS_MKDIR
)) {
124 r
= mkdir_p(j
, 0700);
126 return log_error_errno(r
, "Failed to create CIFS subdirectory: %m");
130 setup
->root_fd
= open(j
?: HOME_RUNTIME_WORK_DIR
, O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
|O_NOFOLLOW
);
131 if (setup
->root_fd
< 0)
132 return log_error_errno(errno
, "Failed to open home directory: %m");
134 setup
->mount_suffix
= TAKE_PTR(cdir
);
138 int home_activate_cifs(
141 PasswordCache
*cache
,
142 UserRecord
**ret_home
) {
144 _cleanup_(user_record_unrefp
) UserRecord
*new_home
= NULL
, *header_home
= NULL
;
145 const char *hdo
, *hd
;
149 assert(user_record_storage(h
) == USER_CIFS
);
153 assert_se(hdo
= user_record_home_directory(h
));
154 hd
= strdupa_safe(hdo
); /* copy the string out, since it might change later in the home record object */
156 r
= home_setup(h
, 0, cache
, setup
, &header_home
);
160 r
= home_refresh(h
, setup
, header_home
, cache
, NULL
, &new_home
);
164 setup
->root_fd
= safe_close(setup
->root_fd
);
166 r
= home_move_mount(setup
->mount_suffix
, hd
);
170 setup
->undo_mount
= false;
171 setup
->do_drop_caches
= false;
173 log_info("Everything completed.");
175 *ret_home
= TAKE_PTR(new_home
);
179 int home_create_cifs(UserRecord
*h
, HomeSetup
*setup
, UserRecord
**ret_home
) {
180 _cleanup_(user_record_unrefp
) UserRecord
*new_home
= NULL
;
184 assert(user_record_storage(h
) == USER_CIFS
);
188 if (!h
->cifs_service
)
189 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "User record lacks CIFS service, refusing.");
191 if (access("/sbin/mount.cifs", F_OK
) < 0) {
193 return log_error_errno(SYNTHETIC_ERRNO(ENOLINK
), "/sbin/mount.cifs is missing.");
195 return log_error_errno(errno
, "Unable to detect whether /sbin/mount.cifs exists: %m");
198 r
= home_setup_cifs(h
, HOME_SETUP_CIFS_MKDIR
, setup
);
202 r
= dir_is_empty_at(setup
->root_fd
, NULL
);
204 return log_error_errno(r
, "Failed to detect if CIFS directory is empty: %m");
206 return log_error_errno(SYNTHETIC_ERRNO(ENOTEMPTY
), "Selected CIFS directory not empty, refusing.");
208 r
= home_populate(h
, setup
->root_fd
);
212 r
= home_sync_and_statfs(setup
->root_fd
, NULL
);
216 r
= user_record_clone(h
, USER_RECORD_LOAD_MASK_SECRET
|USER_RECORD_PERMISSIVE
, &new_home
);
218 return log_error_errno(r
, "Failed to clone record: %m");
220 r
= user_record_add_binding(
235 return log_error_errno(r
, "Failed to add binding to record: %m");
237 log_info("Everything completed.");
239 *ret_home
= TAKE_PTR(new_home
);