diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2014-05-11 11:17:31 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2014-05-11 11:20:58 +0300 |
commit | 867eaccec7a1324f958d0d86c1a148187212bf6f (patch) | |
tree | fd615a0c3de58a7c5ab6cc8cf20b613a5d58901f | |
parent | e1aa833138248238ceb23def33b3bfbfcc9f4b97 (diff) | |
download | pam-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.
-rw-r--r-- | doc/pam-modules.texi | 79 | ||||
-rw-r--r-- | doc/pam_ldaphome.8in | 52 | ||||
-rw-r--r-- | pam_ldaphome/pam_ldaphome.c | 273 |
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 */; |