File pam_mkhomedir-Use-vendordir-when-defined.patch of Package pam
From c4a53492e1b7aebcf7a65a778d9e3a78f196d117 Mon Sep 17 00:00:00 2001
From: vlefebvre <valentin.lefebvre@suse.com>
Date: Tue, 15 Jul 2025 15:42:50 +0200
Subject: [PATCH] pam_mkhomedir: Use vendordir when defined
* When the configuration is split between /etc and vendordir,
pam_mkhomedir now takes care of the distribution-provided
skeleton directory.
* mkhomedir_helper gets a new optional argument: vendordir.
If specified, the home directory will be populated by contents of
the directory specified by skeldir argument, followed by contents
of the directory specified by vendordir argument.
Signed-off-by: vlefebvre <valentin.lefebvre@suse.com>
---
modules/pam_mkhomedir/mkhomedir_helper.8.xml | 12 ++-
modules/pam_mkhomedir/mkhomedir_helper.c | 91 +++++++++++++-------
modules/pam_mkhomedir/pam_mkhomedir.8.xml | 8 +-
modules/pam_mkhomedir/pam_mkhomedir.c | 14 ++-
4 files changed, 88 insertions(+), 37 deletions(-)
diff --git a/modules/pam_mkhomedir/mkhomedir_helper.8.xml b/modules/pam_mkhomedir/mkhomedir_helper.8.xml
index 0f4c4b40..87b83a40 100644
--- a/modules/pam_mkhomedir/mkhomedir_helper.8.xml
+++ b/modules/pam_mkhomedir/mkhomedir_helper.8.xml
@@ -24,6 +24,9 @@
<replaceable>path-to-skel</replaceable>
<arg choice="opt" rep="norepeat">
<replaceable>home_mode</replaceable>
+ <arg choice="opt" rep="norepeat">
+ <replaceable>path-to-vendor-skel</replaceable>
+ </arg>
</arg>
</arg>
</arg>
@@ -48,6 +51,13 @@
<replaceable>umask</replaceable>.
</para>
+ <para>
+ <replaceable>path-to-vendor-skel</replaceable> doesn't have default
+ value. When set to a <emphasis>path</emphasis>, home directory will be
+ populated by contents of <replaceable>path-to-skel</replaceable> first,
+ and then by contents of <emphasis>path</emphasis>.
+ </para>
+
<para>
The helper is separated from the module to not require direct access from
login SELinux domains to the contents of user home directories. The
@@ -77,4 +87,4 @@
</para>
</refsect1>
-</refentry>
\ No newline at end of file
+</refentry>
diff --git a/modules/pam_mkhomedir/mkhomedir_helper.c b/modules/pam_mkhomedir/mkhomedir_helper.c
index 0c05ee9c..1d741c5d 100644
--- a/modules/pam_mkhomedir/mkhomedir_helper.c
+++ b/modules/pam_mkhomedir/mkhomedir_helper.c
@@ -36,7 +36,7 @@ static unsigned long u_mask = 0022;
static const char *skeldir = "/etc/skel";
static int create_homedir(struct dir_spec *, const struct passwd *, mode_t,
- const char *, const char *);
+ const char *, const char *, const char *);
static int
dir_spec_open(struct dir_spec *spec, const char *path)
@@ -88,7 +88,7 @@ dir_spec_close(struct dir_spec *spec)
static int
copy_entry(struct dir_spec *parent, const struct passwd *pwd, mode_t dir_mode,
- const char *source, struct dirent *dent)
+ const char *source, struct dirent *dent, const char *vendordir)
{
char remark[BUFSIZ];
int srcfd = -1, destfd = -1;
@@ -96,6 +96,7 @@ copy_entry(struct dir_spec *parent, const struct passwd *pwd, mode_t dir_mode,
int retval = PAM_SESSION_ERR;
struct stat st;
char *newsource;
+ char *newvendordir = NULL;
/* Determine what kind of file it is. */
if ((newsource = pam_asprintf("%s/%s", source, dent->d_name)) == NULL)
@@ -114,8 +115,23 @@ copy_entry(struct dir_spec *parent, const struct passwd *pwd, mode_t dir_mode,
/* If it's a directory, recurse. */
if (S_ISDIR(st.st_mode))
{
+ if (vendordir != NULL)
+ {
+ if ((newvendordir = pam_asprintf("%s/%s", vendordir, dent->d_name)) == NULL)
+ {
+ pam_syslog(NULL, LOG_CRIT, "asprintf failed for 'newvendordir'");
+ retval = PAM_BUF_ERR;
+ goto go_out;
+ }
+ if (lstat(newvendordir, &st) != 0)
+ {
+ free(newvendordir);
+ newvendordir = NULL;
+ }
+ }
+
retval = create_homedir(parent, pwd, dir_mode & (~u_mask), newsource,
- dent->d_name);
+ dent->d_name, newvendordir);
goto go_out;
}
@@ -259,19 +275,22 @@ copy_entry(struct dir_spec *parent, const struct passwd *pwd, mode_t dir_mode,
close(destfd);
free(newsource);
-
+ free(newvendordir);
return retval;
}
/* Do the actual work of creating a home dir */
static int
create_homedir(struct dir_spec *parent, const struct passwd *pwd,
- mode_t dir_mode, const char *source, const char *dest)
+ mode_t dir_mode, const char *source, const char *dest,
+ const char *vendordir)
{
DIR *d = NULL;
struct dirent *dent;
struct dir_spec base;
int retval = PAM_SESSION_ERR;
+ const char *sourcedirs[] = {source, vendordir};
+ unsigned int idx = 0;
/* Create the new directory */
if (mkdirat(parent->fd, dest, 0700))
@@ -289,32 +308,35 @@ create_homedir(struct dir_spec *parent, const struct passwd *pwd,
goto go_out;
}
- /* See if we need to copy the skel dir over. */
- if ((source == NULL) || (strlen(source) == 0))
- {
- retval = PAM_SUCCESS;
- goto go_out;
- }
-
- /* Scan the directory */
- d = opendir(source);
- if (d == NULL)
- {
- pam_syslog(NULL, LOG_DEBUG, "unable to read directory %s: %m", source);
- retval = PAM_PERM_DENIED;
- goto go_out;
- }
-
- for (dent = readdir(d); dent != NULL; dent = readdir(d))
+ /* Scan source directories */
+ for (idx = 0; idx < PAM_ARRAY_SIZE(sourcedirs); idx++)
{
- /* Skip some files.. */
- if (strcmp(dent->d_name,".") == 0 ||
- strcmp(dent->d_name,"..") == 0)
- continue;
+ /* See if we need to copy the source skel dir over. */
+ if ((sourcedirs[idx] == NULL) || strlen(sourcedirs[idx]) == 0)
+ continue;
+ d = opendir(sourcedirs[idx]);
+ if (d == NULL)
+ {
+ pam_syslog(NULL, LOG_DEBUG, "unable to read directory %s: %m",
+ sourcedirs[idx]);
+ retval = PAM_PERM_DENIED;
+ goto go_out;
+ }
- retval = copy_entry(&base, pwd, dir_mode, source, dent);
- if (retval != PAM_SUCCESS)
- goto go_out;
+ for (dent = readdir(d); dent != NULL; dent = readdir(d))
+ {
+ /* Skip some files.. */
+ if (strcmp(dent->d_name,".") == 0 ||
+ strcmp(dent->d_name,"..") == 0)
+ continue;
+
+ retval = copy_entry(&base, pwd, dir_mode, sourcedirs[idx], dent,
+ sourcedirs[idx] == vendordir ? NULL : vendordir);
+ if (retval != PAM_SUCCESS)
+ goto go_out;
+ }
+ closedir(d);
+ d = NULL;
}
retval = PAM_SUCCESS;
@@ -340,7 +362,8 @@ create_homedir(struct dir_spec *parent, const struct passwd *pwd,
static int
create_homedir_helper(const struct passwd *_pwd, mode_t home_mode,
- const char *_skeldir, const char *_homedir)
+ const char *_skeldir, const char *_homedir,
+ const char *_vendordir)
{
int retval = PAM_SESSION_ERR;
struct dir_spec base;
@@ -357,7 +380,7 @@ create_homedir_helper(const struct passwd *_pwd, mode_t home_mode,
}
*cp = '/';
- retval = create_homedir(&base, _pwd, home_mode, _skeldir, cp + 1);
+ retval = create_homedir(&base, _pwd, home_mode, _skeldir, cp + 1, _vendordir);
go_out:
dir_spec_close(&base);
@@ -399,6 +422,7 @@ main(int argc, char *argv[])
struct stat st;
char *eptr;
unsigned long home_mode = 0;
+ const char *vendordir = NULL;
if (argc < 2) {
fprintf(stderr, "Usage: %s <username> [<umask> [<skeldir> [<home_mode>]]]\n", argv[0]);
@@ -433,6 +457,9 @@ main(int argc, char *argv[])
}
}
+ if (argc >= 6)
+ vendordir = argv[5];
+
if (home_mode == 0)
home_mode = 0777 & ~u_mask;
@@ -449,5 +476,5 @@ main(int argc, char *argv[])
if (make_parent_dirs(pwd->pw_dir, 0) != PAM_SUCCESS)
return PAM_PERM_DENIED;
- return create_homedir_helper(pwd, home_mode, skeldir, pwd->pw_dir);
+ return create_homedir_helper(pwd, home_mode, skeldir, pwd->pw_dir, vendordir);
}
diff --git a/modules/pam_mkhomedir/pam_mkhomedir.8.xml b/modules/pam_mkhomedir/pam_mkhomedir.8.xml
index ad957248..42f42c58 100644
--- a/modules/pam_mkhomedir/pam_mkhomedir.8.xml
+++ b/modules/pam_mkhomedir/pam_mkhomedir.8.xml
@@ -46,6 +46,12 @@
<filename>/etc/skel/</filename>) is used to copy default files
and also sets a umask for the creation.
</para>
+
+ <para condition="with_vendordir">
+ <emphasis>%vendordir%/skel</emphasis> will also be used unless
+ <replaceable>skel</replaceable> option is specified.
+ </para>
+
<para>
The new users home directory will not be removed after logout
of the user.
@@ -213,4 +219,4 @@
pam_mkhomedir was written by Jason Gunthorpe <jgg@debian.org>.
</para>
</refsect1>
-</refentry>
\ No newline at end of file
+</refentry>
diff --git a/modules/pam_mkhomedir/pam_mkhomedir.c b/modules/pam_mkhomedir/pam_mkhomedir.c
index f090deee..5b08b6fd 100644
--- a/modules/pam_mkhomedir/pam_mkhomedir.c
+++ b/modules/pam_mkhomedir/pam_mkhomedir.c
@@ -60,6 +60,11 @@
#define LOGIN_DEFS "/etc/login.defs"
#define UMASK_DEFAULT "0022"
+#define SKELDIR "/etc/skel"
+#ifdef VENDORDIR
+#define VENDOR_SKELDIR (VENDORDIR "/skel")
+#endif
+
struct options_t {
int ctrl;
const char *umask;
@@ -73,7 +78,7 @@ _pam_parse (const pam_handle_t *pamh, int flags, int argc, const char **argv,
{
opt->ctrl = 0;
opt->umask = NULL;
- opt->skeldir = "/etc/skel";
+ opt->skeldir = NULL;
/* does the application require quiet? */
if ((flags & PAM_SILENT) == PAM_SILENT)
@@ -154,7 +159,7 @@ create_homedir (pam_handle_t *pamh, options_t *opt,
child = fork();
if (child == 0) {
static char *envp[] = { NULL };
- const char *args[] = { NULL, NULL, NULL, NULL, NULL, NULL };
+ const char *args[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
if (pam_modutil_sanitize_helper_fds(pamh, PAM_MODUTIL_PIPE_FD,
PAM_MODUTIL_PIPE_FD,
@@ -165,8 +170,11 @@ create_homedir (pam_handle_t *pamh, options_t *opt,
args[0] = MKHOMEDIR_HELPER;
args[1] = user;
args[2] = opt->umask ? opt->umask : UMASK_DEFAULT;
- args[3] = opt->skeldir;
+ args[3] = opt->skeldir ? opt->skeldir : SKELDIR;
args[4] = login_homemode;
+#ifdef VENDORDIR
+ args[5] = opt->skeldir ? NULL : VENDOR_SKELDIR;
+#endif
DIAG_PUSH_IGNORE_CAST_QUAL;
execve(MKHOMEDIR_HELPER, (char **)args, envp);
--
2.51.0