pam_ldaphome: read /etc/ldap.conf file.

* lib/env.c (gray_env_read_tr): New function.
(gray_env_read): Rewrite using gray_env_read_tr.
(gray_env_merge): New function.
* lib/escape.c (gray_escape_string): Remove useless typecasts.
* lib/graypam.h (gray_env_read_tr)
(gray_env_merge): New protos.
* pam_ldaphome/pam_ldaphome.c (ldap_config_name): New variable.
(ldap_connect): Use 'ssl' keyword, if 'tls' is not defined.
(ldaphome_main): New keyword ldap-config

* doc/pam-modules.texi: Document reading system-wide ldap.conf
* doc/pam_ldaphome.8in: Likewise.
This commit is contained in:
Sergey Poznyakoff 2014-07-25 15:09:33 +03:00
parent c1059e0398
commit b4a27a9c7a
6 changed files with 250 additions and 102 deletions

View file

@ -1179,36 +1179,45 @@ Read configuration from @var{file}. Default is
@file{pam_ldaphome.conf} in @var{sysconfdir}.
@end table
Actual module configuration is read from the configuration file, which
has the same syntax as described in @ref{config, SQL configuration
file}. The following keywords are defined:
Actual module configuration is read from the configuration file.
@deffn {pam_ldaphome config} allow-home-dir @var{path}
If present, this option controls where @command{pam_ldaphome} should
try to create home directories. Its value is a list of directories
separated by colons. The user's home directory will be created only
if the directory part of its name is listed in @var{path}.
@end deffn
@menu
* ldaphome config::
* ldaphome example::
* ldappubkey::
* usergitconfig::
@end menu
@deffn {pam_ldaphome config} skel @var{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 preserved.
@end deffn
@node ldaphome config
@section Configuration file for @command{pam_ldaphome}
@deffn {pam_ldaphome config} uri @var{arg}
Sets the URI of the LDAP server to consult for the user profile.
Example:
@command{Pam_ldaphome} reads its configuration from two files: the
configuration file supplied with the @command{config} command line
option and the system-wide LDAP configuration file
@file{/etc/ldap.conf}.
@example
uri ldap://127.0.0.1/
@end example
@end deffn
The syntax of the former is described in @ref{config, SQL configuration
file}. Allowed keywords are discussed below.
@deffn {pam_ldaphome config} ldap-version @var{v}
Sets the LDAP version to use. Valid values for @var{v} are @samp{2}
and @samp{3} (the default).
@end deffn
The syntax of the @file{/etc/ldap.conf} configuration file is
described in @ref{ldap.conf,,LDAP configuration file,ldap.conf(5),
ldap.conf(5) manpage}. Its parsing can be suppressed using the
@command{ldap-config} statement (see below).
From @file{/etc/ldap.conf}, the following statements are used:
@samp{base}, @samp{binddn}, @samp{bindpw}, @samp{tls_cacert},
@samp{uri}. The @samp{ssl} statement is understood if its value is
@samp{start_tls} or @samp{off}. Other values are silently ignored.
In general, all statements defined below can appear in both files.
However, since @file{/etc/ldap.conf} is read by other system utilities
as well, we do not recomment using @command{pam_ldaphome}-specific
keywords in it.
The values read from @command{pam_ldaphome} configuration file
override those obtained from the standard LDAP configuration file.
@subheading LDAP configuration
@deffn {pam_ldaphome config} base @var{searchbase}
Use @var{searchbase} as the starting point for the search instead of
@ -1237,6 +1246,27 @@ password for simple authentication.
Read password for simple authentication from @var{file}.
@end deffn
@deffn {pam_ldaphome config} filter @var{expr}
Sets the LDAP filter expression to return a user profile. The
@var{expr} should conform to the string representation for search
filters as defined in RFC 4515.
@end deffn
@deffn {pam_ldaphome config} ldap-config @var{file}
Read LDAP configuration from @var{file} (default --
@file{/etc/ldap.conf}). Special value @samp{none} disables this
feature.
@end deffn
@deffn {pam_ldaphome config} ldap-version @var{v}
Sets the LDAP version to use. Valid values for @var{v} are @samp{2}
and @samp{3} (the default).
@end deffn
@deffn {pam_ldaphome config} pubkey-attr @var{text}
Defines the name of the attribute which holds the user public key.
@end deffn
@deffn {pam_ldaphome config} tls @var{val}
Controls whether TLS is desired or required. If @var{val} is
@samp{no} (the default), TLS will not be used. If it is @samp{yes},
@ -1247,41 +1277,27 @@ mandatory, and the module will not establish LDAP connection unless
@end deffn
@deffn {pam_ldaphome config} tls-cacert @var{val}
@deffnx {pam_ldaphome config} tls_cacert @var{val}
Full pathname to the CA certificate file. Used if TLS is enabled.
The second form (@samp{tls_cacert}) is for use in
@file{/etc/ldap.conf} file.
@end deffn
@deffn {pam_ldaphome config} min-uid @var{n}
Sets the minimal UID. For users with UIDs less than @var{n},
@command{pam_ldaphome} returns PAM_SUCCESS immediately. This allows
you to have a set of basic users whose credentials are kept in the
system database and who will not be disturbed by
@command{pam_ldaphome}. See also @samp{min-gid} and
@samp{allow-groups}.
@deffn {pam_ldaphome config} uri @var{arg}
Sets the URI of the LDAP server to consult for the user profile.
Example:
@example
uri ldap://127.0.0.1/
@end example
@end deffn
@deffn {pam_ldaphome config} min-gid @var{n}
Sets the minimal GID. For users with GIDs less than @var{n},
@command{pam_ldaphome} returns PAM_SUCCESS immediately.
@end deffn
@deffn {pam_ldaphome config} allow-groups @var{group} [@var{group}...]
Only handle members of the listed groups.
@end deffn
@deffn {pam_ldaphome config} filter @var{expr}
Sets the LDAP filter expression to return a user profile. The
@var{expr} should conform to the string representation for search
filters as defined in RFC 4515.
@end deffn
@deffn {pam_ldaphome config} import-public-keys @var{bool}
When set to @samp{no}, disables importing public keys from LDAP. You
may wish to use this option if you are using @command{openssh} 6.1 or
later with @command{ldappubkey} as @samp{AuthorizedKeysCommand}.
@end deffn
@deffn {pam_ldaphome config} pubkey-attr @var{text}
Defines the name of the attribute which holds the user public key.
@subheading Home directory creation
@deffn {pam_ldaphome config} allow-home-dir @var{path}
If present, this option controls where @command{pam_ldaphome} should
try to create home directories. Its value is a list of directories
separated by colons. The user's home directory will be created only
if the directory part of its name is listed in @var{path}.
@end deffn
@deffn {pam_ldaphome config} copy-buf-size @var{n}
@ -1293,10 +1309,13 @@ directory to the newly created home. The default size is 16384 bytes.
Sets the mode (octal) for the created user directories.
@end deffn
@deffn {pam_ldaphome config} keyfile-mode @var{mode}
Sets the mode (octal) for the created authorized keys file.
@deffn {pam_ldaphome config} skel @var{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 preserved.
@end deffn
@subheading Authorized keys file
@deffn {pam_ldaphome config} authorized_keys @var{name}
Sets the pathname (relative to the home directory) for the authorized
keys file. The default is @samp{.ssh/authorized_keys}. For normal
@ -1305,11 +1324,47 @@ operation, this value must be the same as the value of
change the latter, there's no need to edit it.
@end deffn
@deffn {pam_ldaphome config} import-public-keys @var{bool}
When set to @samp{no}, disables importing public keys from LDAP. You
may wish to use this option if you are using @command{openssh} 6.1 or
later with @command{ldappubkey} as @samp{AuthorizedKeysCommand}.
@end deffn
@deffn {pam_ldaphome config} keyfile-mode @var{mode}
Sets the mode (octal) for the created authorized keys file.
@end deffn
@subheading Access control
@deffn {pam_ldaphome config} allow-groups @var{group} [@var{group}...]
Only handle members of the listed groups.
@end deffn
@deffn {pam_ldaphome config} min-gid @var{n}
Sets the minimal GID. For users with GIDs less than @var{n},
@command{pam_ldaphome} returns PAM_SUCCESS immediately.
@end deffn
@deffn {pam_ldaphome config} min-uid @var{n}
Sets the minimal UID. For users with UIDs less than @var{n},
@command{pam_ldaphome} returns PAM_SUCCESS immediately. This allows
you to have a set of basic users whose credentials are kept in the
system database and who will not be disturbed by
@command{pam_ldaphome}. See also @samp{min-gid} and
@samp{allow-groups}.
@end deffn
@subheading Initialization script
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} exec-timeout @var{seconds}
Sets maximum time the @command{initrc-command} is allowed to run. If
it runs longer than @var{seconds}, it will be terminated with a
@samp{SIGKILL}, and the module will return PAM_SYSTEM_ERR.
@end deffn
@deffn {pam_ldaphome config} initrc-command @var{command}
Run @command{command} after populating the user home directory with
files from the skeleton directory.
@ -1324,12 +1379,6 @@ non-zero code, @command{pam_ldaphome} will report
@samp{PAM_SYSTEM_ERR}.
@end deffn
@deffn {pam_ldaphome config} exec-timeout @var{seconds}
Sets maximum time the @command{initrc-command} is allowed to run. If
it runs longer than @var{seconds}, it will be terminated with a
@samp{SIGKILL}, and the module will return PAM_SYSTEM_ERR.
@end deffn
@deffn {pam_ldaphome config} initrc-log @var{file}
This statement redirects the standard output and error from the
@command{initrc-command} to @var{file}.
@ -1386,12 +1435,6 @@ 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::
* ldappubkey::
* usergitconfig::
@end menu
@node ldaphome example
@section Example of pam_ldaphome configuration
This example assumes you are using GNU/Linux. The aim of this

View file

@ -14,7 +14,7 @@
.\" You should have received a copy of the GNU General Public License
.\" along with PAM-Modules. If not, see <http://www.gnu.org/licenses/>.
.so config.so
.TH PAM_LDAPHOME 8 "July 24, 2014" "PAM-MODULES" "Pam-Modules User Reference"
.TH PAM_LDAPHOME 8 "July 25, 2014" "PAM-MODULES" "Pam-Modules User Reference"
.SH NAME
pam_ldaphome \- create and populate user home directories
.SH SYNOPSIS
@ -43,7 +43,21 @@ The configuration is kept in the file
The file is a usual UNIX-style configuration file with
comments introduced by the \fB#\fR character. Long statements can be
split across several physical lines of text by ending each line but
the last with a backslash character.
the last with a backslash character.
.PP
The system-wide configuration file
.B /etc/ldap.conf
is parsed after processing the main configuration file. In general,
all statements defined below can appear in both files. However, since
.B /etc/ldap.conf
is read by other system utilities as well, we do not recomment using
.BR pam_ldaphome -specific
keywords in it.
.PP
The values from
.B \*(ET/pam_ldaphome.conf
override those obtained from
.BR /etc/ldap.conf .
.PP
Available configuration directives are:
.SS LDAP Settings
@ -66,6 +80,11 @@ Defines a LDAP filter expression which returns the user profile. The
\fIEXPR\fR should conform to the string representation for search
filters as defined in RFC 4515.
.TP
.BI ldap\-config " FILE"
Read LDAP configuration from \fIFILE\fR (default --
\fB/etc/ldap.conf\fR). Special value \fBnone\fR disables reading
this file.
.TP
.BI ldap\-version " NUM"
Sets the LDAP version to use. Valid arguments are
.B 2
@ -86,6 +105,11 @@ connection unless \fIStartTLS\fR succeeds.
.TP
.BI tls-cacert " VAL"
Full pathname to the CA certificate file. Used if TLS is enabled.
The form
.B tls_cacert
is also understood (for use in
.B /etc/ldap.conf
file).
.TP
.BI uri " ARG"
Sets the URI of the LDAP server to consult for the user profile.

View file

@ -45,8 +45,39 @@ gray_env_free(struct gray_env *env)
}
}
static void
tr(char *input, char **map)
{
unsigned char *s = (unsigned char*) input;
for (; *s; s++) {
unsigned char *f = (unsigned char *)map[0];
unsigned char *t = (unsigned char *)map[1];
for (; *f && *t; f++, t++) {
if (f > (unsigned char *)map[0]
&& *f == '-' && *t == '-'
&& f[1] && t[1]) {
int a = f[-1];
int d = f[1] - a;
if ((d > 0
&& a < *s && *s <= a + d)
|| (d < 0
&& (a + d <= *s && *s < a))) {
*s = t[-1] + *s - a;
break;
}
++f; ++t;
} else if (*f == *s) {
*s = *t;
break;
}
}
}
}
int
gray_env_read(const char *file_name, struct gray_env **penv)
gray_env_read_tr(const char *file_name, struct gray_env **penv, char **trmap)
{
FILE *fp;
char *p;
@ -63,7 +94,6 @@ gray_env_read(const char *file_name, struct gray_env **penv)
return 1;
}
config_env = NULL;
while (p = fgets(buf, sizeof buf, fp)) {
int len;
struct gray_env *env;
@ -147,6 +177,8 @@ gray_env_read(const char *file_name, struct gray_env **penv)
;
if (*p)
*p++ = 0;
if (trmap)
tr(env->name, trmap);
for (; *p && isspace(*p); p++)
;
if (!*p) {
@ -167,6 +199,28 @@ gray_env_read(const char *file_name, struct gray_env **penv)
return rc;
}
int
gray_env_read(const char *file_name, struct gray_env **penv)
{
return gray_env_read_tr(file_name, penv, NULL);
}
void
gray_env_merge(struct gray_env **pa, struct gray_env **pb)
{
if (!*pa)
*pa = *pb;
else if (!*pb)
return;
else {
struct gray_env *a;
for (a = *pa; a->next; a = a->next)
;
a->next = *pb;
}
*pb = NULL;
}
int
gray_boolean_true_p(const char *value)
{

View file

@ -17,15 +17,15 @@
#include <graypam.h>
void
gray_escape_string (gray_slist_t slist, const char *str, size_t len)
gray_escape_string(gray_slist_t slist, const char *str, size_t len)
{
const unsigned char *p;
const char *p;
#define ESCAPABLE_CHAR "\\'\""
#define FLUSH() \
gray_slist_append(slist, str, p - (const unsigned char *)str); \
gray_slist_append(slist, str, p - str); \
str = p;
for (p = (const unsigned char *) str; p < str + len; p++) {
for (p = str; p < str + len; p++) {
if (strchr(ESCAPABLE_CHAR, *p)) {
FLUSH();
str++;

View file

@ -212,6 +212,8 @@ char *gray_env_get(struct gray_env *env, const char *name);
int gray_env_get_bool(struct gray_env *env, const char *name, int dfl);
void gray_env_free(struct gray_env *env);
int gray_env_read(const char *file_name, struct gray_env **penv);
int gray_env_read_tr(const char *file_name, struct gray_env **penv, char **tr);
void gray_env_merge(struct gray_env **pa, struct gray_env **pb);
int gray_boolean_true_p(const char *value);

View file

@ -48,7 +48,8 @@ static char *config_file_name;
static int ldap_debug_level;
/* FIXME: This should be read from sshd_config */
static char *authorized_keys_file=".ssh/authorized_keys";
static char *ldap_config_name = "/etc/ldap.conf";
struct pam_opt pam_opt[] = {
{ PAM_OPTSTR(debug), pam_opt_long, &debug_level },
{ PAM_OPTSTR(debug), pam_opt_const, &debug_level, { 1 } },
@ -313,6 +314,7 @@ ldap_connect(struct gray_env *env)
int protocol = LDAP_VERSION3;
char *val;
unsigned long lval;
enum { tls_no, tls_yes, tls_only } tls = tls_no;
if (ldap_debug_level) {
if (ber_set_option(NULL, LBER_OPT_DEBUG_LEVEL,
@ -371,8 +373,6 @@ ldap_connect(struct gray_env *env)
val = gray_env_get(env, "tls");
if (val) {
enum { tls_no, tls_yes, tls_only } tls;
if (strcmp(val, "yes") == 0)
tls = tls_yes;
else if (strcmp(val, "no") == 0)
@ -385,28 +385,39 @@ ldap_connect(struct gray_env *env)
"assuming \"no\"");
tls = tls_no;
}
if (tls != tls_no) {
rc = ldap_start_tls_s(ld, NULL, NULL);
if (rc != LDAP_SUCCESS) {
char *msg = NULL;
ldap_get_option(ld,
LDAP_OPT_DIAGNOSTIC_MESSAGE,
(void*)&msg);
_pam_log(LOG_ERR,
"ldap_start_tls failed: %s",
ldap_err2string(rc));
_pam_log(LOG_ERR,
"TLS diagnostics: %s", msg);
ldap_memfree(msg);
if (tls == tls_only) {
ldap_unbind(ld);
return NULL;
}
/* try to continue anyway */
} else {
val = gray_env_get(env, "ssl");
if (!val)
tls = tls_no;
else if (strcmp(val, "on") == 0)
tls = tls_only;
else if (strcmp(val, "start_tls") == 0)
tls = tls_only;
else
tls = tls_no;
/* FIXME: "tls-reqcert" */
}
if (tls != tls_no) {
rc = ldap_start_tls_s(ld, NULL, NULL);
if (rc != LDAP_SUCCESS) {
char *msg = NULL;
ldap_get_option(ld,
LDAP_OPT_DIAGNOSTIC_MESSAGE,
(void*)&msg);
_pam_log(LOG_ERR,
"ldap_start_tls failed: %s",
ldap_err2string(rc));
_pam_log(LOG_ERR,
"TLS diagnostics: %s", msg);
ldap_memfree(msg);
if (tls == tls_only) {
ldap_unbind(ld);
return NULL;
}
/* try to continue anyway */
} else {
val = gray_env_get(env, "tls-cacert");
if (val) {
rc = ldap_set_option(ld,
@ -552,7 +563,7 @@ ldap_bind(LDAP *ld, struct gray_env *env)
|| (matched && matched[0])
|| (info && info[0])
|| refs) {
/* FIXME: Use debug output for that */
DEBUG(2,("ldap_bind: %s (%d)%s",
ldap_err2string(err), err, msgbuf));
@ -1890,6 +1901,20 @@ ldaphome_main(pam_handle_t *pamh, int flags, int argc, const char **argv,
char *val;
struct passwd *pw;
if (val = gray_env_get(env, "ldap-config")) {
if (strcmp(val, "none") == 0)
ldap_config_name = NULL;
else
ldap_config_name = val;
}
if (ldap_config_name) {
static char *map[] = { "A-Z_", "a-z-" };
struct gray_env *tmp;
gray_env_read_tr(ldap_config_name, &tmp, map);
gray_env_merge(&env, &tmp);
}
if (val = gray_env_get(env, "authorized_keys"))
authorized_keys_file = val;