summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org.ua>2014-05-11 08:17:31 (GMT)
committer Sergey Poznyakoff <gray@gnu.org.ua>2014-05-11 08:20:58 (GMT)
commit867eaccec7a1324f958d0d86c1a148187212bf6f (patch) (side-by-side diff)
treefd615a0c3de58a7c5ab6cc8cf20b613a5d58901f
parente1aa833138248238ceb23def33b3bfbfcc9f4b97 (diff)
downloadpam-modules-867eaccec7a1324f958d0d86c1a148187212bf6f.tar.gz
pam-modules-867eaccec7a1324f958d0d86c1a148187212bf6f.tar.bz2
Allow to modify environment of initrc-command
* pam_ldaphome/pam_ldaphome.c (find_env,locate_unset) (env_concat,parsenv,env_setup): New statics. (run_prog): Use execve and env_setup to set up the environment. * doc/pam-modules.texi: Document new statements. * doc/pam_ldaphome.8in: Likewise.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--doc/pam-modules.texi79
-rw-r--r--doc/pam_ldaphome.8in52
-rw-r--r--pam_ldaphome/pam_ldaphome.c273
3 files changed, 400 insertions, 4 deletions
diff --git a/doc/pam-modules.texi b/doc/pam-modules.texi
index a0578da..87c4d6c 100644
--- a/doc/pam-modules.texi
+++ b/doc/pam-modules.texi
@@ -1172,7 +1172,7 @@ if the directory part of its name is listed in @var{path}.
@deffn {pam_ldaphome config} skel dir
Supplies the name of a @dfn{skeleton directory}. The contents of this
directory is copied to the newly created user home directory. The
-file modes and permissions are retained.
+file modes and permissions are preserved.
@end deffn
@deffn {pam_ldaphome config} uri arg
@@ -1250,7 +1250,7 @@ filters as defined in RFC 4515.
@end deffn
@deffn {pam_ldaphome config} pubkey-attr text
-Defines the name of the attribute keeping user public key.
+Defines the name of the attribute which holds the user public key.
@end deffn
@deffn {pam_ldaphome config} copy-buf-size n
@@ -1274,6 +1274,81 @@ operation, this value must be the same as the value of
change the latter, there's no need to edit it.
@end deffn
+The following statements instruct @command{pam_ldaphome} to invoke an
+external command after initializing the user home directory. This can
+be used to customize the files copied from the skeleton directory
+according to the user.
+
+@deffn {pam_ldaphome config} initrc-command command
+Run @command{command} after populating the user home directory with
+files from the skeleton directory.
+
+The user login name is passed to the command as its argument. Before
+invoking, the current working directory is changed to the user home,
+standard input is closed, and standard output is redirected to
+standard errror.
+
+The command should exit with code 0 on success. If it exits with a
+non-zero code, @command{pam_ldaphome} will report
+@samp{PAM_SYSTEM_ERR}.
+@end deffn
+
+@deffn {pam_ldaphome config} initrc-log file
+This statement redirects the standard output and error from the
+@command{initrc-command} to @var{file}.
+@end deffn
+
+@deffn {pam_ldaphome config} initrc-environ env ...
+Modifies the environment of @command{initrc-command}.
+
+This statement takes one or more arguments. Each argument can be one
+of:
+
+@table @asis
+@item - (a dash)
+Clear the environment. This is understood only when used as the first
+argument.
+
+@item -@var{name}
+Unset the environment variable @var{name}.
+
+@item -@var{name}=@var{val}
+Unset the environment variable @var{name} only if its value is @var{val}.
+
+@item @var{name}
+Retain the environment variable @var{name}.
+
+@item @var{name}=@var{value}
+Define environment variable @var{name} to have given @var{value}.
+
+@item @var{name}+=@var{value}
+Retain variable @var{name} and append @var{value} to its existing
+value. If no such variable is present in the environment, it is
+created and @var{value} is assigned to it. However, if @var{value}
+begins with a punctuation character, this character is removed from it
+before the assignment. This is convenient for using this construct with
+environment variables like @env{PATH}, e.g.:
+
+@smallexample
+PATH+=:/sbin
+@end smallexample
+
+In this example, if @env{PATH} exists, @samp{:/sbin} will be appended
+to it. Otherwise, it will be created and @samp{/sbin} will be
+assigned to it.
+
+@item @var{name}=+@var{value}
+Retain variable @var{name} and prepend @var{value} to its existing
+value. If no such variable is present in the environment, it is
+created and @var{value} is assigned to it. However, if @var{value}
+ends with a punctuation character, this character is removed from it
+before assignment.
+@end table
+
+The @var{value} part can be enclosed in single or double quotes, in
+which case the usual shell dequoting rules apply.
+@end deffn
+
@menu
* ldaphome example::
@end menu
diff --git a/doc/pam_ldaphome.8in b/doc/pam_ldaphome.8in
index 20c7810..6d74e4e 100644
--- a/doc/pam_ldaphome.8in
+++ b/doc/pam_ldaphome.8in
@@ -128,6 +128,58 @@ operation, this value must be the same as the value of
\fBAuthorizedKeysFile\fR variable in
.BR sshd_config (5).
Unless you change the latter, there's no need to edit it.
+.TP
+.BI initrc\-command " COMMAND"
+Run \fICOMMAND\fR after populating the user home directory with
+files from the skeleton directory. The user login name is passed to
+\fICOMMAND\fR as its argument. Before invoking, the current working
+directory is changed to the user home, standard input is closed, and
+standard output is redirected to standard errror.
+
+The command should exit with code 0 on success. If it exits with a
+non-zero code, PAM_SYSTEM_ERR will be reported.
+.TP
+.BI initrc-log " FILE"
+Redirects standard output and error from the
+\fBinitrc\-command\fR to \fIFILE\fR.
+.TP
+\fBinitrc\-environ\fR \fIENV\fR ...
+Modifies the environment of \fBinitrc\-command\fR.
+
+This statement takes one or more arguments. Each argument can be one
+of:
+.RS +4
+.TP
+.BR \- " (a dash)"
+Clear the environment. This is understood only when used as the first
+argument.
+.TP
+\fB\-\fINAME\fR
+Unset the environment variable \fINAME\fR.
+.TP
+\fB\-\fINAME\fB=\fIVALUE\fR
+Unset the environment variable \fINAME\fR only if it has the given \fIVALUE\fR.
+.TP
+.I NAME
+Retain the environment variable \fINAME\fR.
+.TP
+\fINAME\fB=\fIVALUE\fR
+Define environment variable \fINAME\fR to have given \fIVALUE\fR.
+.TP
+\fINAME\fB+=\fIVALUE\fR
+Retain the variable \fINAME\fR and append \fIVALUE\fR to its existing
+value. If no such variable is present in the environment, it is
+created. If \fIVALUE\fR begins with a punctuation character, this character
+is removed from it before the assignment.
+.TP
+\fINAME\fB=+\fIVALUE\fR
+Retain variable \fINAME\fR and prepend \fIVALUE\fR to its existing
+value. If no such variable is present in the environment, it is
+created. If \fIVALUE\fR ends with a punctuation character, this character
+is removed from it before assignment.
+.RE
+The \fIVALUE\fR part can be enclosed in single or double quotes, in
+which case the usual shell dequoting rules apply.
.SH OPTIONS
.TP
.BI config= FILE
diff --git a/pam_ldaphome/pam_ldaphome.c b/pam_ldaphome/pam_ldaphome.c
index f3191b9..1df9de0 100644
--- a/pam_ldaphome/pam_ldaphome.c
+++ b/pam_ldaphome/pam_ldaphome.c
@@ -1432,6 +1432,274 @@ create_home_dir(pam_handle_t *pamh, struct passwd *pw, struct gray_env *env)
return create_ok;
}
+extern char **environ;
+
+static char *
+find_env(char *name, int val)
+{
+ int nlen = strcspn(name, "?+=");
+ int i;
+
+ for (i = 0; environ[i]; i++) {
+ size_t elen = strcspn(environ[i], "=");
+ if (elen == nlen && memcmp(name, environ[i], nlen) == 0)
+ return val ? environ[i] + elen + 1 : environ[i];
+ }
+ return NULL;
+}
+
+static int
+locate_unset(char **env, const char *name)
+{
+ volatile int i;
+ int nlen = strcspn(name, "=");
+
+ for (i = 0; env[i]; i++) {
+ if (env[i][0] == '-') {
+ size_t elen = strcspn(env[i] + 1, "=");
+ if (elen == nlen
+ && memcmp(name, env[i] + 1, nlen) == 0) {
+ if (env[i][nlen + 1])
+ return strcmp(name + nlen,
+ env[i] + 1 + nlen) == 0;
+ else
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+static char *
+env_concat(char *name, size_t namelen, char *a, char *b)
+{
+ char *res;
+ size_t len;
+
+ if (a && b) {
+ res = gray_malloc(namelen + 1 + strlen(a) + strlen(b) + 1);
+ strcpy(res + namelen + 1, a);
+ strcat(res, b);
+ } else if (a) {
+ len = strlen(a);
+ if (ispunct(a[len-1]))
+ len--;
+ res = gray_malloc(namelen + 1 + len + 1);
+ memcpy(res + namelen + 1, a, len);
+ res[namelen + 1 + len] = 0;
+ } else /* if (a == NULL) */ {
+ if (ispunct(b[0]))
+ b++;
+ len = strlen(b);
+ res = gray_malloc(namelen + 1 + len + 1);
+ strcpy(res + namelen + 1, b);
+ }
+ memcpy(res, name, namelen);
+ res[namelen] = '=';
+ return res;
+}
+
+static char **
+parsenv(char *str)
+{
+ enum {
+ st_init,
+ st_kwd,
+ st_val,
+ st_eq,
+ st_dquote,
+ st_squote,
+ st_end
+ } state = st_init, prev_state;
+# define setstate(s) do { prev_state = state; state = s; } while (0)
+ char *p, *kw;
+ char **wv = NULL;
+ size_t wi = 0, wc = 0;
+
+ if (!str)
+ return NULL;
+
+ for (p = str; *p; ++p) {
+ switch (state) {
+ case st_init:
+ if (*p == ' ' || *p == '\t')
+ continue;
+ setstate(st_kwd);
+ kw = p;
+ break;
+ case st_kwd:
+ if (*p == ' ' || *p == '\t') {
+ setstate(st_end);
+ } else if (*p == '=') {
+ setstate(st_eq);
+ }
+ break;
+ case st_eq:
+ if (*p == '"') {
+ setstate(st_dquote);
+ } else if (*p == '\'') {
+ setstate(st_squote);
+ } else {
+ setstate(st_val);
+ }
+ /* fall through */
+ case st_val:
+ if (*p == ' ' || *p == '\t')
+ setstate(st_end);
+ break;
+ case st_dquote:
+ if (*p == '\\')
+ ++p;
+ else if (*p == '"')
+ setstate(st_end);
+ break;
+ case st_squote:
+ if (*p == '\'')
+ setstate(st_end);
+ break;
+ case st_end:
+ /* can't happen */
+ break;
+ }
+
+ if (state == st_end) {
+ size_t len = p - kw;
+ char *q;
+
+ if (wi == wc) {
+ if (wc == 0)
+ wc = 4;
+ else
+ wc *= 2;
+ wv = gray_realloc(wv, wc * sizeof(wv[0]));
+ }
+
+ switch (prev_state) {
+ case st_squote:
+ len -= 2;
+ wv[wi] = gray_malloc(len + 1);
+ for (q = wv[wi]; *kw; ) {
+ if (*kw == '\'')
+ ++kw;
+ else
+ *q++ = *kw++;
+ }
+ *q = 0;
+ break;
+ case st_dquote:
+ len -= 2;
+ wv[wi] = gray_malloc(len + 1);
+ q = wv[wi];
+ while ((*q++ = *kw++) != '=')
+ ;
+ while (*kw != '"')
+ *q++ = *kw++;
+ ++kw;
+ while (*kw != '"') {
+ if (*kw == '\\')
+ ++kw;
+ *q++ = *kw++;
+ }
+ *q = 0;
+ break;
+ default:
+ wv[wi] = gray_malloc(len + 1);
+ memcpy(wv[wi], kw, len);
+ wv[wi][len] = 0;
+ }
+ ++wi;
+ setstate(st_init);
+ }
+ }
+
+ if (state != st_init) {
+ if (wc == wi) {
+ ++wc;
+ wv = gray_realloc(wv, (wc + 1) * sizeof(wv[0]));
+ }
+ wv[wi++] = gray_strdup(kw);
+ }
+
+ if (wc == wi)
+ wv = gray_realloc(wv, (wc + 1) * sizeof(wv[0]));
+ wv[wi] = NULL;
+
+ return wv;
+}
+
+static char **
+env_setup(char *envstr)
+{
+ char **env;
+ char **old_env = environ;
+ char **new_env;
+ int count, i, n;
+
+ env = parsenv(envstr);
+
+ if (!env)
+ return old_env;
+
+ if (strcmp(env[0], "-") == 0) {
+ old_env = NULL;
+ env++;
+ }
+
+ /* Count new environment size */
+ count = 0;
+ if (old_env)
+ for (i = 0; old_env[i]; i++)
+ count++;
+
+ for (i = 0; env[i]; i++)
+ count++;
+
+ /* Allocate the new environment. */
+ new_env = gray_calloc(count + 1, sizeof new_env[0]);
+
+ /* Populate the environment. */
+ n = 0;
+
+ if (old_env)
+ for (i = 0; old_env[i]; i++) {
+ if (!locate_unset(env, old_env[i]))
+ new_env[n++] = old_env[i];
+ }
+
+ for (i = 0; env[i]; i++) {
+ char *p;
+
+ if (env[i][0] == '-') {
+ /* Skip unset directives. */
+ continue;
+ } if ((p = strchr(env[i], '='))) {
+ if (p == env[i])
+ continue; /* Ignore erroneous entry */
+ if (p[-1] == '+')
+ new_env[n++] = env_concat(env[i],
+ p - env[i] - 1,
+ find_env(env[i], 1),
+ p + 1);
+ else if (p[1] == '+')
+ new_env[n++] = env_concat(env[i],
+ p - env[i],
+ p + 2,
+ find_env(env[i], 1));
+ else if (p[-1] == '?') {
+ if (!find_env(env[i], 0))
+ new_env[n++] = p + 1;
+ } else
+ new_env[n++] = env[i];
+ } else {
+ p = find_env(env[i], 0);
+ if (p)
+ new_env[n++] = p;
+ }
+ }
+ new_env[n] = NULL;
+ return new_env;
+}
+
static int
run_prog(pam_handle_t *pamh, struct passwd *pw, struct gray_env *env,
const char *command, const char *logfile)
@@ -1490,7 +1758,8 @@ run_prog(pam_handle_t *pamh, struct passwd *pw, struct gray_env *env,
argv[0] = (char*) command;
argv[1] = pw->pw_name;
argv[2] = NULL;
- execv(command, argv);
+ execve(command, argv,
+ env_setup(gray_env_get(env, "initrc-environ")));
_exit(127);
}
@@ -1552,7 +1821,7 @@ run_prog(pam_handle_t *pamh, struct passwd *pw, struct gray_env *env,
return PAM_SUCCESS;
}
-void
+static void
sigchld(int sig)
{
/* nothing */;

Return to:

Send suggestions and report system problems to the System administrator.