mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-02-19 21:57:27 +03:00
Merge pull request #21162 from poettering/homed-cifs-improvements
homed: various cifs backend improvements
This commit is contained in:
commit
93a5fe3e65
@ -411,7 +411,12 @@ useful when `cifs` is used as storage mechanism for the user's home directory,
|
||||
see above.
|
||||
|
||||
`cifsService` → A string indicating the Windows File Share service (CIFS) to
|
||||
mount as home directory of the user on login.
|
||||
mount as home directory of the user on login. Should be in format
|
||||
`//<host>/<service>/<directory/…>`. The directory part is optional. If missing
|
||||
the top-level directory of the CIFS share is used.
|
||||
|
||||
`cifsExtraMountOptions` → A string with additional mount options to pass to
|
||||
`mount.cifs` when mounting the home directory CIFS share.
|
||||
|
||||
`imagePath` → A string with an absolute file system path to the file, directory
|
||||
or block device to use for storage backing the home directory. If the `luks`
|
||||
@ -705,15 +710,16 @@ that may be used in this section are identical to the equally named ones in the
|
||||
`notAfterUSec`, `storage`, `diskSize`, `diskSizeRelative`, `skeletonDirectory`,
|
||||
`accessMode`, `tasksMax`, `memoryHigh`, `memoryMax`, `cpuWeight`, `ioWeight`,
|
||||
`mountNoDevices`, `mountNoSuid`, `mountNoExecute`, `cifsDomain`,
|
||||
`cifsUserName`, `cifsService`, `imagePath`, `uid`, `gid`, `memberOf`,
|
||||
`fileSystemType`, `partitionUuid`, `luksUuid`, `fileSystemUuid`, `luksDiscard`,
|
||||
`luksOfflineDiscard`, `luksCipher`, `luksCipherMode`, `luksVolumeKeySize`,
|
||||
`luksPbkdfHashAlgorithm`, `luksPbkdfType`, `luksPbkdfTimeCostUSec`,
|
||||
`luksPbkdfMemoryCost`, `luksPbkdfParallelThreads`, `rateLimitIntervalUSec`,
|
||||
`rateLimitBurst`, `enforcePasswordPolicy`, `autoLogin`, `stopDelayUSec`,
|
||||
`killProcesses`, `passwordChangeMinUSec`, `passwordChangeMaxUSec`,
|
||||
`passwordChangeWarnUSec`, `passwordChangeInactiveUSec`, `passwordChangeNow`,
|
||||
`pkcs11TokenUri`, `fido2HmacCredential`.
|
||||
`cifsUserName`, `cifsService`, `cifsExtraMountOptions`, `imagePath`, `uid`,
|
||||
`gid`, `memberOf`, `fileSystemType`, `partitionUuid`, `luksUuid`,
|
||||
`fileSystemUuid`, `luksDiscard`, `luksOfflineDiscard`, `luksCipher`,
|
||||
`luksCipherMode`, `luksVolumeKeySize`, `luksPbkdfHashAlgorithm`,
|
||||
`luksPbkdfType`, `luksPbkdfTimeCostUSec`, `luksPbkdfMemoryCost`,
|
||||
`luksPbkdfParallelThreads`, `rateLimitIntervalUSec`, `rateLimitBurst`,
|
||||
`enforcePasswordPolicy`, `autoLogin`, `stopDelayUSec`, `killProcesses`,
|
||||
`passwordChangeMinUSec`, `passwordChangeMaxUSec`, `passwordChangeWarnUSec`,
|
||||
`passwordChangeInactiveUSec`, `passwordChangeNow`, `pkcs11TokenUri`,
|
||||
`fido2HmacCredential`.
|
||||
|
||||
## Fields in the `binding` section
|
||||
|
||||
|
@ -688,10 +688,17 @@
|
||||
<term><option>--cifs-domain=</option><replaceable>DOMAIN</replaceable></term>
|
||||
<term><option>--cifs-user-name=</option><replaceable>USER</replaceable></term>
|
||||
<term><option>--cifs-service=</option><replaceable>SERVICE</replaceable></term>
|
||||
<term><option>--cifs-extra-mount-options=</option><replaceable>OPTIONS</replaceable></term>
|
||||
|
||||
<listitem><para>Configures the Windows File Sharing (CIFS) domain and user to associate with the home
|
||||
directory/user account, as well as the file share ("service") to mount as directory. The latter is used when
|
||||
<literal>cifs</literal> storage is selected.</para></listitem>
|
||||
directory/user account, as well as the file share ("service") to mount as directory. The latter is
|
||||
used when <literal>cifs</literal> storage is selected. The file share should be specified in format
|
||||
<literal>//<replaceable>host</replaceable>/<replaceable>share</replaceable>/<replaceable>directory/…</replaceable></literal>. The
|
||||
directory part is optional — if not specified the home directory will be placed in the top-level
|
||||
directory of the share. The <option>--cifs-extra-mount-options=</option> setting allows specifying
|
||||
additional mount options when mounting the share, see <citerefentry
|
||||
project='man-pages'><refentrytitle>mount.cifs</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
for details.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "fs-util.h"
|
||||
#include "hostname-util.h"
|
||||
#include "log.h"
|
||||
#include "macro.h"
|
||||
#include "missing_fcntl.h"
|
||||
@ -952,3 +953,78 @@ int posix_fallocate_loop(int fd, uint64_t offset, uint64_t size) {
|
||||
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
int parse_cifs_service(
|
||||
const char *s,
|
||||
char **ret_host,
|
||||
char **ret_service,
|
||||
char **ret_path) {
|
||||
|
||||
_cleanup_free_ char *h = NULL, *ss = NULL, *x = NULL;
|
||||
const char *p, *e, *d;
|
||||
char delimiter;
|
||||
|
||||
/* Parses a CIFS service in form of //host/service/path… and splitting it in three parts. The last
|
||||
* part is optional, in which case NULL is returned there. To maximize compatibility syntax with
|
||||
* backslashes instead of slashes is accepted too. */
|
||||
|
||||
if (!s)
|
||||
return -EINVAL;
|
||||
|
||||
p = startswith(s, "//");
|
||||
if (!p) {
|
||||
p = startswith(s, "\\\\");
|
||||
if (!p)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
delimiter = s[0];
|
||||
e = strchr(p, delimiter);
|
||||
if (!e)
|
||||
return -EINVAL;
|
||||
|
||||
h = strndup(p, e - p);
|
||||
if (!h)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!hostname_is_valid(h, 0))
|
||||
return -EINVAL;
|
||||
|
||||
e++;
|
||||
|
||||
d = strchrnul(e, delimiter);
|
||||
|
||||
ss = strndup(e, d - e);
|
||||
if (!ss)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!filename_is_valid(ss))
|
||||
return -EINVAL;
|
||||
|
||||
if (!isempty(d)) {
|
||||
x = strdup(skip_leading_chars(d, CHAR_TO_STR(delimiter)));
|
||||
if (!x)
|
||||
return -EINVAL;
|
||||
|
||||
/* Make sure to convert Windows-style "\" → Unix-style / */
|
||||
for (char *i = x; *i; i++)
|
||||
if (*i == delimiter)
|
||||
*i = '/';
|
||||
|
||||
if (!path_is_valid(x))
|
||||
return -EINVAL;
|
||||
|
||||
path_simplify(x);
|
||||
if (!path_is_normalized(x))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ret_host)
|
||||
*ret_host = TAKE_PTR(h);
|
||||
if (ret_service)
|
||||
*ret_service = TAKE_PTR(ss);
|
||||
if (ret_path)
|
||||
*ret_path = TAKE_PTR(x);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -106,3 +106,5 @@ static inline int conservative_rename(const char *oldpath, const char *newpath)
|
||||
}
|
||||
|
||||
int posix_fallocate_loop(int fd, uint64_t offset, uint64_t size);
|
||||
|
||||
int parse_cifs_service(const char *s, char **ret_host, char **ret_service, char **ret_path);
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "format-table.h"
|
||||
#include "fs-util.h"
|
||||
#include "glyph-util.h"
|
||||
#include "home-util.h"
|
||||
#include "homectl-fido2.h"
|
||||
@ -2160,6 +2161,8 @@ static int help(int argc, char *argv[], void *userdata) {
|
||||
" --cifs-domain=DOMAIN CIFS (Windows) domain\n"
|
||||
" --cifs-user-name=USER CIFS (Windows) user name\n"
|
||||
" --cifs-service=SERVICE CIFS (Windows) service to mount as home area\n"
|
||||
" --cifs-extra-mount-options=OPTIONS\n"
|
||||
" CIFS (Windows) extra mount options\n"
|
||||
"\n%4$sLogin Behaviour User Record Properties:%5$s\n"
|
||||
" --stop-delay=SECS How long to leave user services running after\n"
|
||||
" logout\n"
|
||||
@ -2216,6 +2219,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
ARG_CIFS_DOMAIN,
|
||||
ARG_CIFS_USER_NAME,
|
||||
ARG_CIFS_SERVICE,
|
||||
ARG_CIFS_EXTRA_MOUNT_OPTIONS,
|
||||
ARG_TASKS_MAX,
|
||||
ARG_MEMORY_HIGH,
|
||||
ARG_MEMORY_MAX,
|
||||
@ -2308,6 +2312,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
{ "cifs-user-name", required_argument, NULL, ARG_CIFS_USER_NAME },
|
||||
{ "cifs-domain", required_argument, NULL, ARG_CIFS_DOMAIN },
|
||||
{ "cifs-service", required_argument, NULL, ARG_CIFS_SERVICE },
|
||||
{ "cifs-extra-mount-options", required_argument, NULL, ARG_CIFS_EXTRA_MOUNT_OPTIONS },
|
||||
{ "rate-limit-interval", required_argument, NULL, ARG_RATE_LIMIT_INTERVAL },
|
||||
{ "rate-limit-burst", required_argument, NULL, ARG_RATE_LIMIT_BURST },
|
||||
{ "stop-delay", required_argument, NULL, ARG_STOP_DELAY },
|
||||
@ -2447,16 +2452,16 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
case ARG_ICON_NAME:
|
||||
case ARG_CIFS_USER_NAME:
|
||||
case ARG_CIFS_DOMAIN:
|
||||
case ARG_CIFS_SERVICE: {
|
||||
case ARG_CIFS_EXTRA_MOUNT_OPTIONS: {
|
||||
|
||||
const char *field =
|
||||
c == ARG_EMAIL_ADDRESS ? "emailAddress" :
|
||||
c == ARG_LOCATION ? "location" :
|
||||
c == ARG_ICON_NAME ? "iconName" :
|
||||
c == ARG_CIFS_USER_NAME ? "cifsUserName" :
|
||||
c == ARG_CIFS_DOMAIN ? "cifsDomain" :
|
||||
c == ARG_CIFS_SERVICE ? "cifsService" :
|
||||
NULL;
|
||||
c == ARG_EMAIL_ADDRESS ? "emailAddress" :
|
||||
c == ARG_LOCATION ? "location" :
|
||||
c == ARG_ICON_NAME ? "iconName" :
|
||||
c == ARG_CIFS_USER_NAME ? "cifsUserName" :
|
||||
c == ARG_CIFS_DOMAIN ? "cifsDomain" :
|
||||
c == ARG_CIFS_EXTRA_MOUNT_OPTIONS ? "cifsExtraMountOptions" :
|
||||
NULL;
|
||||
|
||||
assert(field);
|
||||
|
||||
@ -2475,6 +2480,25 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
break;
|
||||
}
|
||||
|
||||
case ARG_CIFS_SERVICE:
|
||||
if (isempty(optarg)) {
|
||||
r = drop_from_identity("cifsService");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
r = parse_cifs_service(optarg, NULL, NULL, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to validate CIFS service name: %s", optarg);
|
||||
|
||||
r = json_variant_set_field_string(&arg_identity_extra, "cifsService", optarg);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set cifsService field: %m");
|
||||
|
||||
break;
|
||||
|
||||
case ARG_PASSWORD_HINT:
|
||||
if (isempty(optarg)) {
|
||||
r = drop_from_identity("passwordHint");
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "fs-util.h"
|
||||
#include "homework-cifs.h"
|
||||
#include "homework-mount.h"
|
||||
#include "mkdir.h"
|
||||
#include "mount-util.h"
|
||||
#include "process-util.h"
|
||||
#include "stat-util.h"
|
||||
@ -18,83 +19,125 @@ int home_setup_cifs(
|
||||
HomeSetupFlags flags,
|
||||
HomeSetup *setup) {
|
||||
|
||||
_cleanup_free_ char *chost = NULL, *cservice = NULL, *cdir = NULL, *chost_and_service = NULL, *j = NULL;
|
||||
char **pw;
|
||||
int r;
|
||||
|
||||
assert(h);
|
||||
assert(setup);
|
||||
assert(user_record_storage(h) == USER_CIFS);
|
||||
assert(setup);
|
||||
assert(!setup->undo_mount);
|
||||
assert(setup->root_fd < 0);
|
||||
|
||||
if (FLAGS_SET(flags, HOME_SETUP_ALREADY_ACTIVATED))
|
||||
if (FLAGS_SET(flags, HOME_SETUP_ALREADY_ACTIVATED)) {
|
||||
setup->root_fd = open(user_record_home_directory(h), O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW);
|
||||
else {
|
||||
bool mounted = false;
|
||||
char **pw;
|
||||
int r;
|
||||
if (setup->root_fd < 0)
|
||||
return log_error_errno(errno, "Failed to open home directory: %m");
|
||||
|
||||
r = home_unshare_and_mkdir();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!h->cifs_service)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "User record lacks CIFS service, refusing.");
|
||||
|
||||
r = parse_cifs_service(h->cifs_service, &chost, &cservice, &cdir);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed parse CIFS service specification: %m");
|
||||
|
||||
/* Just the host and service part, without the directory */
|
||||
chost_and_service = strjoin("//", chost, "/", cservice);
|
||||
if (!chost_and_service)
|
||||
return log_oom();
|
||||
|
||||
r = home_unshare_and_mkdir();
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
STRV_FOREACH(pw, h->password) {
|
||||
_cleanup_(unlink_and_freep) char *p = NULL;
|
||||
_cleanup_free_ char *options = NULL;
|
||||
_cleanup_(fclosep) FILE *f = NULL;
|
||||
pid_t mount_pid;
|
||||
int exit_status;
|
||||
|
||||
r = fopen_temporary(NULL, &f, &p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return log_error_errno(r, "Failed to create temporary credentials file: %m");
|
||||
|
||||
STRV_FOREACH(pw, h->password) {
|
||||
_cleanup_(unlink_and_freep) char *p = NULL;
|
||||
_cleanup_free_ char *options = NULL;
|
||||
_cleanup_(fclosep) FILE *f = NULL;
|
||||
pid_t mount_pid;
|
||||
int exit_status;
|
||||
fprintf(f,
|
||||
"username=%s\n"
|
||||
"password=%s\n",
|
||||
user_record_cifs_user_name(h),
|
||||
*pw);
|
||||
|
||||
r = fopen_temporary(NULL, &f, &p);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to create temporary credentials file: %m");
|
||||
if (h->cifs_domain)
|
||||
fprintf(f, "domain=%s\n", h->cifs_domain);
|
||||
|
||||
fprintf(f,
|
||||
"username=%s\n"
|
||||
"password=%s\n",
|
||||
user_record_cifs_user_name(h),
|
||||
*pw);
|
||||
r = fflush_and_check(f);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to write temporary credentials file: %m");
|
||||
|
||||
if (h->cifs_domain)
|
||||
fprintf(f, "domain=%s\n", h->cifs_domain);
|
||||
f = safe_fclose(f);
|
||||
|
||||
r = fflush_and_check(f);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to write temporary credentials file: %m");
|
||||
if (asprintf(&options, "credentials=%s,uid=" UID_FMT ",forceuid,gid=" GID_FMT ",forcegid,file_mode=0%3o,dir_mode=0%3o",
|
||||
p, h->uid, user_record_gid(h), user_record_access_mode(h), user_record_access_mode(h)) < 0)
|
||||
return log_oom();
|
||||
|
||||
f = safe_fclose(f);
|
||||
|
||||
if (asprintf(&options, "credentials=%s,uid=" UID_FMT ",forceuid,gid=" GID_FMT ",forcegid,file_mode=0%3o,dir_mode=0%3o",
|
||||
p, h->uid, user_record_gid(h), user_record_access_mode(h), user_record_access_mode(h)) < 0)
|
||||
if (h->cifs_extra_mount_options)
|
||||
if (!strextend_with_separator(&options, ",", h->cifs_extra_mount_options))
|
||||
return log_oom();
|
||||
|
||||
r = safe_fork("(mount)", FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG|FORK_LOG|FORK_STDOUT_TO_STDERR, &mount_pid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
/* Child */
|
||||
execl("/bin/mount", "/bin/mount", "-n", "-t", "cifs",
|
||||
h->cifs_service, HOME_RUNTIME_WORK_DIR,
|
||||
"-o", options, NULL);
|
||||
r = safe_fork("(mount)", FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG|FORK_LOG|FORK_STDOUT_TO_STDERR, &mount_pid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) {
|
||||
/* Child */
|
||||
execl("/bin/mount", "/bin/mount", "-n", "-t", "cifs",
|
||||
chost_and_service, HOME_RUNTIME_WORK_DIR,
|
||||
"-o", options, NULL);
|
||||
|
||||
log_error_errno(errno, "Failed to execute mount: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
log_error_errno(errno, "Failed to execute mount: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
exit_status = wait_for_terminate_and_check("mount", mount_pid, WAIT_LOG_ABNORMAL|WAIT_LOG_NON_ZERO_EXIT_STATUS);
|
||||
if (exit_status < 0)
|
||||
return exit_status;
|
||||
if (exit_status != EXIT_SUCCESS)
|
||||
return -EPROTO;
|
||||
|
||||
mounted = true;
|
||||
exit_status = wait_for_terminate_and_check("mount", mount_pid, WAIT_LOG_ABNORMAL|WAIT_LOG_NON_ZERO_EXIT_STATUS);
|
||||
if (exit_status < 0)
|
||||
return exit_status;
|
||||
if (exit_status == EXIT_SUCCESS) {
|
||||
setup->undo_mount = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!mounted)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOKEY),
|
||||
"Failed to mount home directory with supplied password.");
|
||||
|
||||
setup->root_fd = open(HOME_RUNTIME_WORK_DIR, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW);
|
||||
if (pw[1])
|
||||
log_info("CIFS mount failed with password #%zu, trying next password.", (size_t) (pw - h->password) + 1);
|
||||
}
|
||||
|
||||
if (!setup->undo_mount)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENOKEY),
|
||||
"Failed to mount home directory, supplied password(s) possibly wrong.");
|
||||
|
||||
/* Adjust MS_SUID and similar flags */
|
||||
r = mount_nofollow_verbose(LOG_ERR, NULL, HOME_RUNTIME_WORK_DIR, NULL, MS_BIND|MS_REMOUNT|user_record_mount_flags(h), NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (cdir) {
|
||||
j = path_join(HOME_RUNTIME_WORK_DIR, cdir);
|
||||
if (!j)
|
||||
return log_oom();
|
||||
|
||||
if (FLAGS_SET(flags, HOME_SETUP_CIFS_MKDIR)) {
|
||||
r = mkdir_p(j, 0700);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to create CIFS subdirectory: %m");
|
||||
}
|
||||
}
|
||||
|
||||
setup->root_fd = open(j ?: HOME_RUNTIME_WORK_DIR, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOFOLLOW);
|
||||
if (setup->root_fd < 0)
|
||||
return log_error_errno(errno, "Failed to open home directory: %m");
|
||||
|
||||
setup->mount_suffix = TAKE_PTR(cdir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -104,7 +147,7 @@ int home_activate_cifs(
|
||||
PasswordCache *cache,
|
||||
UserRecord **ret_home) {
|
||||
|
||||
_cleanup_(user_record_unrefp) UserRecord *new_home = NULL;
|
||||
_cleanup_(user_record_unrefp) UserRecord *new_home = NULL, *header_home = NULL;
|
||||
const char *hdo, *hd;
|
||||
int r;
|
||||
|
||||
@ -113,23 +156,20 @@ int home_activate_cifs(
|
||||
assert(setup);
|
||||
assert(ret_home);
|
||||
|
||||
if (!h->cifs_service)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "User record lacks CIFS service, refusing.");
|
||||
|
||||
assert_se(hdo = user_record_home_directory(h));
|
||||
hd = strdupa_safe(hdo); /* copy the string out, since it might change later in the home record object */
|
||||
|
||||
r = home_setup_cifs(h, 0, setup);
|
||||
r = home_setup(h, 0, cache, setup, &header_home);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = home_refresh(h, setup, NULL, cache, NULL, &new_home);
|
||||
r = home_refresh(h, setup, header_home, cache, NULL, &new_home);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
setup->root_fd = safe_close(setup->root_fd);
|
||||
|
||||
r = home_move_mount(NULL, hd);
|
||||
r = home_move_mount(setup->mount_suffix, hd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -161,7 +201,7 @@ int home_create_cifs(UserRecord *h, HomeSetup *setup, UserRecord **ret_home) {
|
||||
return log_error_errno(errno, "Unable to detect whether /sbin/mount.cifs exists: %m");
|
||||
}
|
||||
|
||||
r = home_setup_cifs(h, 0, setup);
|
||||
r = home_setup_cifs(h, HOME_SETUP_CIFS_MKDIR, setup);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -87,17 +87,17 @@ int home_unshare_and_mount(const char *node, const char *fstype, bool discard, u
|
||||
return home_mount_node(node, fstype, discard, flags);
|
||||
}
|
||||
|
||||
int home_move_mount(const char *user_name_and_realm, const char *target) {
|
||||
int home_move_mount(const char *mount_suffix, const char *target) {
|
||||
_cleanup_free_ char *subdir = NULL;
|
||||
const char *d;
|
||||
int r;
|
||||
|
||||
assert(target);
|
||||
|
||||
/* If user_name_and_realm is set, then we'll mount a subdir of the source mount into the host. If
|
||||
* it's NULL we'll move the mount itself */
|
||||
if (user_name_and_realm) {
|
||||
subdir = path_join(HOME_RUNTIME_WORK_DIR, user_name_and_realm);
|
||||
/* If 'mount_suffix' is set, then we'll mount a subdir of the source mount into the host. If it's
|
||||
* NULL we'll move the mount itself */
|
||||
if (mount_suffix) {
|
||||
subdir = path_join(HOME_RUNTIME_WORK_DIR, mount_suffix);
|
||||
if (!subdir)
|
||||
return log_oom();
|
||||
|
||||
|
@ -379,6 +379,8 @@ int home_setup_done(HomeSetup *setup) {
|
||||
if (setup->do_drop_caches)
|
||||
drop_caches_now();
|
||||
|
||||
setup->mount_suffix = mfree(setup->mount_suffix);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -37,6 +37,8 @@ typedef struct HomeSetup {
|
||||
|
||||
uint64_t partition_offset;
|
||||
uint64_t partition_size;
|
||||
|
||||
char *mount_suffix; /* The directory to use as home dir is this path below /run/systemd/user-home-mount */
|
||||
} HomeSetup;
|
||||
|
||||
typedef struct PasswordCache {
|
||||
@ -66,6 +68,9 @@ static inline bool password_cache_contains(const PasswordCache *cache, const cha
|
||||
/* Various flags for the operation of setting up a home directory */
|
||||
typedef enum HomeSetupFlags {
|
||||
HOME_SETUP_ALREADY_ACTIVATED = 1 << 0, /* Open an already activated home, rather than activate it afresh */
|
||||
|
||||
/* CIFS backend: */
|
||||
HOME_SETUP_CIFS_MKDIR = 1 << 1, /* Create CIFS subdir when missing */
|
||||
} HomeSetupFlags;
|
||||
|
||||
int home_setup_done(HomeSetup *setup);
|
||||
|
@ -271,6 +271,7 @@ static UserRecord* user_record_free(UserRecord *h) {
|
||||
free(h->cifs_service);
|
||||
free(h->cifs_user_name);
|
||||
free(h->cifs_domain);
|
||||
free(h->cifs_extra_mount_options);
|
||||
|
||||
free(h->image_path);
|
||||
free(h->image_path_auto);
|
||||
@ -1267,6 +1268,7 @@ static int dispatch_per_machine(const char *name, JsonVariant *variant, JsonDisp
|
||||
{ "cifsDomain", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, cifs_domain), JSON_SAFE },
|
||||
{ "cifsUserName", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, cifs_user_name), JSON_SAFE },
|
||||
{ "cifsService", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, cifs_service), JSON_SAFE },
|
||||
{ "cifsExtraMountOptions", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, cifs_extra_mount_options), 0 },
|
||||
{ "imagePath", JSON_VARIANT_STRING, json_dispatch_path, offsetof(UserRecord, image_path), 0 },
|
||||
{ "uid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(UserRecord, uid), 0 },
|
||||
{ "gid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(UserRecord, gid), 0 },
|
||||
@ -1612,6 +1614,7 @@ int user_record_load(UserRecord *h, JsonVariant *v, UserRecordLoadFlags load_fla
|
||||
{ "cifsDomain", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, cifs_domain), JSON_SAFE },
|
||||
{ "cifsUserName", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, cifs_user_name), JSON_SAFE },
|
||||
{ "cifsService", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, cifs_service), JSON_SAFE },
|
||||
{ "cifsExtraMountOptions", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, cifs_extra_mount_options), 0 },
|
||||
{ "imagePath", JSON_VARIANT_STRING, json_dispatch_path, offsetof(UserRecord, image_path), 0 },
|
||||
{ "homeDirectory", JSON_VARIANT_STRING, json_dispatch_home_directory, offsetof(UserRecord, home_directory), 0 },
|
||||
{ "uid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(UserRecord, uid), 0 },
|
||||
|
@ -304,6 +304,7 @@ typedef struct UserRecord {
|
||||
char *cifs_domain;
|
||||
char *cifs_user_name;
|
||||
char *cifs_service;
|
||||
char *cifs_extra_mount_options;
|
||||
|
||||
char *image_path;
|
||||
char *image_path_auto; /* when none is configured explicitly, this is where we place the implicit image */
|
||||
|
@ -921,6 +921,36 @@ static void test_rmdir_parents(void) {
|
||||
assert_se(rm_rf(temp, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
|
||||
}
|
||||
|
||||
static void test_parse_cifs_service_one(const char *f, const char *h, const char *s, const char *d, int ret) {
|
||||
_cleanup_free_ char *a = NULL, *b = NULL, *c = NULL;
|
||||
|
||||
assert_se(parse_cifs_service(f, &a, &b, &c) == ret);
|
||||
assert_se(streq_ptr(a, h));
|
||||
assert_se(streq_ptr(b, s));
|
||||
assert_se(streq_ptr(c, d));
|
||||
}
|
||||
|
||||
static void test_parse_cifs_service(void) {
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
test_parse_cifs_service_one("//foo/bar/baz", "foo", "bar", "baz", 0);
|
||||
test_parse_cifs_service_one("\\\\foo\\bar\\baz", "foo", "bar", "baz", 0);
|
||||
test_parse_cifs_service_one("//foo/bar", "foo", "bar", NULL, 0);
|
||||
test_parse_cifs_service_one("\\\\foo\\bar", "foo", "bar", NULL, 0);
|
||||
test_parse_cifs_service_one("//foo/bar/baz/uuu", "foo", "bar", "baz/uuu", 0);
|
||||
test_parse_cifs_service_one("\\\\foo\\bar\\baz\\uuu", "foo", "bar", "baz/uuu", 0);
|
||||
|
||||
test_parse_cifs_service_one(NULL, NULL, NULL, NULL, -EINVAL);
|
||||
test_parse_cifs_service_one("", NULL, NULL, NULL, -EINVAL);
|
||||
test_parse_cifs_service_one("abc", NULL, NULL, NULL, -EINVAL);
|
||||
test_parse_cifs_service_one("abc/cde/efg", NULL, NULL, NULL, -EINVAL);
|
||||
test_parse_cifs_service_one("//foo/bar/baz/..", NULL, NULL, NULL, -EINVAL);
|
||||
test_parse_cifs_service_one("//foo///", NULL, NULL, NULL, -EINVAL);
|
||||
test_parse_cifs_service_one("//foo/.", NULL, NULL, NULL, -EINVAL);
|
||||
test_parse_cifs_service_one("//foo/a/.", NULL, NULL, NULL, -EINVAL);
|
||||
test_parse_cifs_service_one("//./a", NULL, NULL, NULL, -EINVAL);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
test_setup_logging(LOG_INFO);
|
||||
|
||||
@ -940,6 +970,7 @@ int main(int argc, char *argv[]) {
|
||||
test_chmod_and_chown();
|
||||
test_conservative_rename();
|
||||
test_rmdir_parents();
|
||||
test_parse_cifs_service();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user