|
|
Index: Makefile.in |
|
|
--- Makefile.in.orig 2019-10-09 02:31:03.000000000 +0200 |
|
|
+++ Makefile.in 2019-10-09 23:03:45.281692000 +0200 |
|
|
@@ -119,7 +119,7 @@ |
|
|
sftp-server.o sftp-common.o sftp-realpath.o \ |
|
|
sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \ |
|
|
sandbox-seccomp-filter.o sandbox-capsicum.o sandbox-pledge.o \ |
|
|
- sandbox-solaris.o uidswap.o |
|
|
+ sandbox-solaris.o uidswap.o ldapauth.o |
|
|
|
|
|
MANPAGES = moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-keysign.8.out ssh-pkcs11-helper.8.out sshd_config.5.out ssh_config.5.out |
|
|
MANPAGES_IN = moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-keysign.8 ssh-pkcs11-helper.8 sshd_config.5 ssh_config.5 |
|
|
Index: README.lpk |
|
|
--- README.lpk.orig 2019-10-09 23:03:45.282233000 +0200 |
|
|
+++ README.lpk 2019-10-09 23:03:45.282108000 +0200 |
|
|
@@ -0,0 +1,267 @@ |
|
|
+OpenSSH LDAP PUBLIC KEY PATCH |
|
|
+Copyright (c) 2003 Eric AUGE (eau@phear.org) |
|
|
+All rights reserved. |
|
|
+ |
|
|
+Redistribution and use in source and binary forms, with or without |
|
|
+modification, are permitted provided that the following conditions |
|
|
+are met: |
|
|
+1. Redistributions of source code must retain the above copyright |
|
|
+ notice, this list of conditions and the following disclaimer. |
|
|
+2. Redistributions in binary form must reproduce the above copyright |
|
|
+ notice, this list of conditions and the following disclaimer in the |
|
|
+ documentation and/or other materials provided with the distribution. |
|
|
+3. The name of the author may not be used to endorse or promote products |
|
|
+ derived from this software without specific prior written permission. |
|
|
+ |
|
|
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
|
|
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
|
|
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
|
|
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
|
|
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
|
|
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
|
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
|
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
|
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
|
|
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
|
+ |
|
|
+purposes of this patch: |
|
|
+ |
|
|
+This patch would help to have authentication centralization policy |
|
|
+using ssh public key authentication. |
|
|
+This patch could be an alternative to other "secure" authentication system |
|
|
+working in a similar way (Kerberos, SecurID, etc...), except the fact |
|
|
+that it's based on OpenSSH and its public key abilities. |
|
|
+ |
|
|
+>> FYI: << |
|
|
+'uid': means unix accounts existing on the current server |
|
|
+'lpkServerGroup:' mean server group configured on the current server ('lpkServerGroup' in sshd_config) |
|
|
+ |
|
|
+example schema: |
|
|
+ |
|
|
+ |
|
|
+ server1 (uid: eau,rival,toto) (lpkServerGroup: unix) |
|
|
+ ___________ / |
|
|
+ / \ --- - server3 (uid: eau, titi) (lpkServerGroup: unix) |
|
|
+ | LDAP Server | \ |
|
|
+ | eau ,rival | server2 (uid: rival, eau) (lpkServerGroup: unix) |
|
|
+ | titi ,toto | |
|
|
+ | userx,.... | server5 (uid: eau) (lpkServerGroup: mail) |
|
|
+ \___________/ \ / |
|
|
+ ----- - server4 (uid: eau, rival) (no group configured) |
|
|
+ \ |
|
|
+ etc... |
|
|
+ |
|
|
+- WHAT WE NEED : |
|
|
+ |
|
|
+ * configured LDAP server somewhere on the network (i.e. OpenLDAP) |
|
|
+ * patched sshd (with this patch ;) |
|
|
+ * LDAP user(/group) entry (look at users.ldif (& groups.ldif)): |
|
|
+ User entry: |
|
|
+ - attached to the 'ldapPublicKey' objectclass |
|
|
+ - attached to the 'posixAccount' objectclass |
|
|
+ - with a filled 'sshPublicKey' attribute |
|
|
+ Example: |
|
|
+ dn: uid=eau,ou=users,dc=cuckoos,dc=net |
|
|
+ objectclass: top |
|
|
+ objectclass: person |
|
|
+ objectclass: organizationalPerson |
|
|
+ objectclass: posixAccount |
|
|
+ objectclass: ldapPublicKey |
|
|
+ description: Eric AUGE Account |
|
|
+ userPassword: blah |
|
|
+ cn: Eric AUGE |
|
|
+ sn: Eric AUGE |
|
|
+ uid: eau |
|
|
+ uidNumber: 1034 |
|
|
+ gidNumber: 1 |
|
|
+ homeDirectory: /export/home/eau |
|
|
+ sshPublicKey: ssh-dss AAAAB3... |
|
|
+ sshPublicKey: ssh-dss AAAAM5... |
|
|
+ |
|
|
+ Group entry: |
|
|
+ - attached to the 'posixGroup' objectclass |
|
|
+ - with a 'cn' groupname attribute |
|
|
+ - with multiple 'memberUid' attributes filled with usernames allowed in this group |
|
|
+ Example: |
|
|
+ # few members |
|
|
+ dn: cn=unix,ou=groups,dc=cuckoos,dc=net |
|
|
+ objectclass: top |
|
|
+ objectclass: posixGroup |
|
|
+ description: Unix based servers group |
|
|
+ cn: unix |
|
|
+ gidNumber: 1002 |
|
|
+ memberUid: eau |
|
|
+ memberUid: user1 |
|
|
+ memberUid: user2 |
|
|
+ |
|
|
+ |
|
|
+- HOW IT WORKS : |
|
|
+ |
|
|
+ * without patch |
|
|
+ If a user wants to authenticate to log in a server the sshd, will first look for authentication method allowed (RSAauth,kerberos,etc..) |
|
|
+ and if RSAauth and tickets based auth fails, it will fallback to standard password authentication (if enabled). |
|
|
+ |
|
|
+ * with the patch |
|
|
+ If a user want to authenticate to log in a server, the sshd will first look for auth method including LDAP pubkey, if the ldappubkey options is enabled. |
|
|
+ It will do an ldapsearch to get the public key directly from the LDAP instead of reading it from the server filesystem. |
|
|
+ (usually in $HOME/.ssh/authorized_keys) |
|
|
+ |
|
|
+ If groups are enabled, it will also check if the user that wants to login is in the group of the server he is trying to log into. |
|
|
+ If it fails, it falls back on RSA auth files ($HOME/.ssh/authorized_keys), etc.. and finally to standard password authentication (if enabled). |
|
|
+ |
|
|
+ 7 tokens are added to sshd_config : |
|
|
+ # here is the new patched ldap related tokens |
|
|
+ # entries in your LDAP must be posixAccount & strongAuthenticationUser & posixGroup |
|
|
+ UseLPK yes # look the pub key into LDAP |
|
|
+ LpkServers ldap://10.31.32.5/ ldap://10.31.32.4 ldap://10.31.32.3 # which LDAP server for users ? (URL format) |
|
|
+ LpkUserDN ou=users,dc=foobar,dc=net # which base DN for users ? |
|
|
+ LpkGroupDN ou=groups,dc=foobar,dc=net # which base DN for groups ? |
|
|
+ LpkBindDN cn=manager,dc=foobar,dc=net # which bind DN ? |
|
|
+ LpkBindPw asecret # bind DN credidentials |
|
|
+ LpkServerGroup agroupname # the group the server is part of |
|
|
+ |
|
|
+ Right now i'm using anonymous binding to get public keys, because getting public keys of someone doesn't impersonate him<EFBFBD> but there is some |
|
|
+ flaws you have to take care of. |
|
|
+ |
|
|
+- HOW TO INSERT A USER/KEY INTO AN LDAP ENTRY |
|
|
+ |
|
|
+ * my way (there is plenty :) |
|
|
+ - create ldif file (i.e. users.ldif) |
|
|
+ - cat ~/.ssh/id_dsa.pub OR cat ~/.ssh/id_rsa.pub OR cat ~/.ssh/identity.pub |
|
|
+ - my way in 4 steps : |
|
|
+ Example: |
|
|
+ |
|
|
+ # you add this to the user entry in the LDIF file : |
|
|
+ [...] |
|
|
+ objectclass: posixAccount |
|
|
+ objectclass: ldapPublicKey |
|
|
+ [...] |
|
|
+ sshPubliKey: ssh-dss AAAABDh12DDUR2... |
|
|
+ [...] |
|
|
+ |
|
|
+ # insert your entry and you're done :) |
|
|
+ ldapadd -D balblabla -w bleh < file.ldif |
|
|
+ |
|
|
+ all standard options can be present in the 'sshPublicKey' attribute. |
|
|
+ |
|
|
+- WHY : |
|
|
+ |
|
|
+ Simply because, i was looking for a way to centralize all sysadmins authentication, easily, without completely using LDAP |
|
|
+ as authentication method (like pam_ldap etc..). |
|
|
+ |
|
|
+ After looking into Kerberos, SecurID, and other centralized secure authentications systems, the use of RSA and LDAP to get |
|
|
+ public key for authentication allows us to control who has access to which server (the user needs an account and to be in 'strongAuthenticationUser' |
|
|
+ objectclass within LDAP and part of the group the SSH server is in). |
|
|
+ |
|
|
+ Passwords update are no longer a nightmare for a server farm (key pair passphrase is stored on each user's box and private key is locally encrypted using his passphrase |
|
|
+ so each user can change it as much as he wants). |
|
|
+ |
|
|
+ Blocking a user account can be done directly from the LDAP (if sshd is using RSAAuth + ldap only). |
|
|
+ |
|
|
+- RULES : |
|
|
+ Entry in the LDAP server must respect 'posixAccount' and 'ldapPublicKey' which are defined in core.schema. |
|
|
+ and the additionnal lpk.schema. |
|
|
+ |
|
|
+ This patch could allow a smooth transition between standard auth (/etc/passwd) and complete LDAP based authentication |
|
|
+ (pamldap, nss_ldap, etc..). |
|
|
+ |
|
|
+ This can be an alternative to other (old?/expensive?) authentication methods (Kerberos/SecurID/..). |
|
|
+ |
|
|
+ Referring to schema at the beginning of this file if user 'eau' is only in group 'unix' |
|
|
+ 'eau' would ONLY access 'server1', 'server2', 'server3' AND 'server4' BUT NOT 'server5'. |
|
|
+ If you then modify the LDAP 'mail' group entry to add 'memberUid: eau' THEN user 'eau' would be able |
|
|
+ to log in 'server5' (i hope you got the idea, my english is bad :). |
|
|
+ |
|
|
+ Each server's sshd is patched and configured to ask the public key and the group infos in the LDAP |
|
|
+ server. |
|
|
+ When you want to allow a new user to have access to the server parc, you just add him an account on |
|
|
+ your servers, you add his public key into his entry on the LDAP server, it's done. |
|
|
+ |
|
|
+ Because sshds are looking public keys into the LDAP directly instead of a file ($HOME/.ssh/authorized_keys). |
|
|
+ |
|
|
+ When the user needs to change his passphrase he can do it directly from his workstation by changing |
|
|
+ his own key set lock passphrase, and all servers are automatically aware. |
|
|
+ |
|
|
+ With a CAREFUL LDAP server configuration you could allow a user to add/delete/modify his own entry himself |
|
|
+ so he can add/modify/delete himself his public key when needed. |
|
|
+ |
|
|
+<EFBFBD> FLAWS : |
|
|
+ LDAP must be well configured, getting the public key of some user is not a problem, but if anonymous LDAP |
|
|
+ allow write to users dn, somebody could replace someuser's public key by its own and impersonate some |
|
|
+ of your users in all your server farm be VERY CAREFUL. |
|
|
+ |
|
|
+ MITM attack when sshd is requesting the public key, could lead to a compromise of your servers allowing login |
|
|
+ as the impersonnated user. |
|
|
+ |
|
|
+ If LDAP server is down then, fallback on passwd auth. |
|
|
+ |
|
|
+ the ldap code part has not been well audited yet. |
|
|
+ |
|
|
+- LDAP USER ENTRY EXAMPLES (LDIF Format, look in users.ldif) |
|
|
+ --- CUT HERE --- |
|
|
+ dn: uid=jdoe,ou=users,dc=foobar,dc=net |
|
|
+ objectclass: top |
|
|
+ objectclass: person |
|
|
+ objectclass: organizationalPerson |
|
|
+ objectclass: posixAccount |
|
|
+ objectclass: ldapPublicKey |
|
|
+ description: My account |
|
|
+ cn: John Doe |
|
|
+ sn: John Doe |
|
|
+ uid: jdoe |
|
|
+ uidNumber: 100 |
|
|
+ gidNumber: 100 |
|
|
+ homeDirectory: /home/jdoe |
|
|
+ sshPublicKey: ssh-dss AAAAB3NzaC1kc3MAAAEBAOvL8pREUg9wSy/8+hQJ54YF3AXkB0OZrXB.... |
|
|
+ [...] |
|
|
+ --- CUT HERE --- |
|
|
+ |
|
|
+- LDAP GROUP ENTRY EXAMPLES (LDIF Format, look in groups.ldif) |
|
|
+ --- CUT HERE --- |
|
|
+ dn: cn=unix,ou=groups,dc=cuckoos,dc=net |
|
|
+ objectclass: top |
|
|
+ objectclass: posixGroup |
|
|
+ description: Unix based servers group |
|
|
+ cn: unix |
|
|
+ gidNumber: 1002 |
|
|
+ memberUid: jdoe |
|
|
+ memberUid: user1 |
|
|
+ memberUid: user2 |
|
|
+ [...] |
|
|
+ --- CUT HERE --- |
|
|
+ |
|
|
+>> FYI: << |
|
|
+Multiple 'sshPublicKey' in a user entry are allowed, as well as multiple 'memberUid' attributes in a group entry |
|
|
+ |
|
|
+- COMPILING: |
|
|
+ 1. Apply the patch |
|
|
+ 2. ./configure --with-your-options --with-ldap=/prefix/to/ldap_libs_and_includes |
|
|
+ 3. make |
|
|
+ 4. it's done. |
|
|
+ |
|
|
+- BLA : |
|
|
+ I hope this could help, and i hope to be clear enough,, or give ideas. questions/comments/improvements are welcome. |
|
|
+ |
|
|
+- TODO : |
|
|
+ Redesign differently. |
|
|
+ |
|
|
+- DOCS/LINK : |
|
|
+ http://pacsec.jp/core05/psj05-barisani-en.pdf |
|
|
+ http://fritz.potsdam.edu/projects/openssh-lpk/ |
|
|
+ http://fritz.potsdam.edu/projects/sshgate/ |
|
|
+ http://dev.inversepath.com/trac/openssh-lpk |
|
|
+ http://lam.sf.net/ ( http://lam.sourceforge.net/documentation/supportedSchemas.htm ) |
|
|
+ |
|
|
+- CONTRIBUTORS/IDEAS/GREETS : |
|
|
+ - Falk Siemonsmeier. |
|
|
+ - Jacob Rief. |
|
|
+ - Michael Durchgraf. |
|
|
+ - frederic peters. |
|
|
+ - Finlay dobbie. |
|
|
+ - Stefan Fisher. |
|
|
+ - Robin H. Johnson. |
|
|
+ - Adrian Bridgett. |
|
|
+ |
|
|
+- CONTACT : |
|
|
+ - Eric AUGE <eau@phear.org> |
|
|
+ - Andrea Barisani <andrea@inversepath.com> |
|
|
Index: auth2-pubkey.c |
|
|
--- auth2-pubkey.c.orig 2019-10-09 02:31:03.000000000 +0200 |
|
|
+++ auth2-pubkey.c 2019-10-09 23:03:45.282647000 +0200 |
|
|
@@ -69,6 +69,10 @@ |
|
|
#include "channels.h" /* XXX for session.h */ |
|
|
#include "session.h" /* XXX for child_set_env(); refactor? */ |
|
|
|
|
|
+#ifdef WITH_LDAP_PUBKEY |
|
|
+#include "ldapauth.h" |
|
|
+#endif |
|
|
+ |
|
|
/* import */ |
|
|
extern ServerOptions options; |
|
|
extern u_char *session_id2; |
|
|
@@ -691,10 +695,76 @@ |
|
|
size_t linesize = 0; |
|
|
int found_key = 0; |
|
|
u_long linenum = 0; |
|
|
+#ifdef WITH_LDAP_PUBKEY |
|
|
+ ldap_key_t * k; |
|
|
+ unsigned int i = 0; |
|
|
+#endif |
|
|
|
|
|
if (authoptsp != NULL) |
|
|
*authoptsp = NULL; |
|
|
|
|
|
+#ifdef WITH_LDAP_PUBKEY |
|
|
+ /* first check if the options is enabled, then try.. */ |
|
|
+ if (options.lpk.on) { |
|
|
+ debug("[LDAP] trying LDAP first uid=%s",pw->pw_name); |
|
|
+ if (ldap_ismember(&options.lpk, pw->pw_name) > 0) { |
|
|
+ if ((k = ldap_getuserkey(&options.lpk, pw->pw_name)) != NULL) { |
|
|
+ /* Skip leading whitespace, empty and comment lines. */ |
|
|
+ for (i = 0 ; i < k->num ; i++) { |
|
|
+ /* dont forget if multiple keys to reset options */ |
|
|
+ char *cp, *options = NULL; |
|
|
+ |
|
|
+ for (cp = (char *)k->keys[i]->bv_val; *cp == ' ' || *cp == '\t'; cp++) |
|
|
+ ; |
|
|
+ if (!*cp || *cp == '\n' || *cp == '#') |
|
|
+ continue; |
|
|
+ |
|
|
+ if (key_read(found, &cp) != 1) { |
|
|
+ /* no key? check if there are options for this key */ |
|
|
+ int quoted = 0; |
|
|
+ debug2("[LDAP] user_key_allowed: check options: '%s'", cp); |
|
|
+ options = cp; |
|
|
+ for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { |
|
|
+ if (*cp == '\\' && cp[1] == '"') |
|
|
+ cp++; /* Skip both */ |
|
|
+ else if (*cp == '"') |
|
|
+ quoted = !quoted; |
|
|
+ } |
|
|
+ /* Skip remaining whitespace. */ |
|
|
+ for (; *cp == ' ' || *cp == '\t'; cp++) |
|
|
+ ; |
|
|
+ if (key_read(found, &cp) != 1) { |
|
|
+ debug2("[LDAP] user_key_allowed: advance: '%s'", cp); |
|
|
+ /* still no key? advance to next line*/ |
|
|
+ continue; |
|
|
+ } |
|
|
+ } |
|
|
+ |
|
|
+ if (key_equal(found, key) && |
|
|
+ auth_parse_options(pw, options, file, linenum) == 1) { |
|
|
+ found_key = 1; |
|
|
+ debug("[LDAP] matching key found"); |
|
|
+ fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); |
|
|
+ verbose("[LDAP] Found matching %s key: %s", key_type(found), fp); |
|
|
+ |
|
|
+ /* restoring memory */ |
|
|
+ ldap_keys_free(k); |
|
|
+ free(fp); |
|
|
+ restore_uid(); |
|
|
+ key_free(found); |
|
|
+ return found_key; |
|
|
+ break; |
|
|
+ } |
|
|
+ }/* end of LDAP for() */ |
|
|
+ } else { |
|
|
+ logit("[LDAP] no keys found for '%s'!", pw->pw_name); |
|
|
+ } |
|
|
+ } else { |
|
|
+ logit("[LDAP] '%s' is not in '%s'", pw->pw_name, options.lpk.sgroup); |
|
|
+ } |
|
|
+ } |
|
|
+#endif |
|
|
+ |
|
|
while (getline(&line, &linesize, f) != -1) { |
|
|
linenum++; |
|
|
/* Always consume entire file */ |
|
|
Index: config.h.in |
|
|
--- config.h.in.orig 2019-10-09 02:39:34.000000000 +0200 |
|
|
+++ config.h.in 2019-10-09 23:03:45.283261000 +0200 |
|
|
@@ -852,6 +852,9 @@ |
|
|
/* Define to 1 if you have the <locale.h> header file. */ |
|
|
#undef HAVE_LOCALE_H |
|
|
|
|
|
+/* Define if you want LDAP support */ |
|
|
+#undef WITH_LDAP_PUBKEY |
|
|
+ |
|
|
/* Define to 1 if you have the `login' function. */ |
|
|
#undef HAVE_LOGIN |
|
|
|
|
|
Index: configure.ac |
|
|
--- configure.ac.orig 2019-10-09 02:31:03.000000000 +0200 |
|
|
+++ configure.ac 2019-10-09 23:03:45.284543000 +0200 |
|
|
@@ -1698,6 +1698,37 @@ |
|
|
fi |
|
|
fi |
|
|
|
|
|
+# Check whether user wants LDAP support |
|
|
+LDAP_MSG="no" |
|
|
+AC_ARG_WITH(ldap, |
|
|
+ [ --with-ldap[[=PATH]] Enable LDAP pubkey support (optionally in PATH)], |
|
|
+ [ |
|
|
+ if test "x$withval" != "xno" ; then |
|
|
+ |
|
|
+ if test "x$withval" != "xyes" ; then |
|
|
+ CPPFLAGS="$CPPFLAGS -I${withval}/include" |
|
|
+ LDFLAGS="$LDFLAGS -L${withval}/lib" |
|
|
+ fi |
|
|
+ |
|
|
+ AC_DEFINE([WITH_LDAP_PUBKEY], 1, [Enable LDAP pubkey support]) |
|
|
+ LIBS="-lldap $LIBS" |
|
|
+ LDAP_MSG="yes" |
|
|
+ |
|
|
+ AC_MSG_CHECKING([for LDAP support]) |
|
|
+ AC_TRY_COMPILE( |
|
|
+ [#include <sys/types.h> |
|
|
+ #include <ldap.h>], |
|
|
+ [(void)ldap_init(0, 0);], |
|
|
+ [AC_MSG_RESULT(yes)], |
|
|
+ [ |
|
|
+ AC_MSG_RESULT(no) |
|
|
+ AC_MSG_ERROR([** Incomplete or missing ldap libraries **]) |
|
|
+ ] |
|
|
+ ) |
|
|
+ fi |
|
|
+ ] |
|
|
+) |
|
|
+ |
|
|
dnl Checks for library functions. Please keep in alphabetical order |
|
|
AC_CHECK_FUNCS([ \ |
|
|
Blowfish_initstate \ |
|
|
@@ -5218,6 +5249,7 @@ |
|
|
echo " OSF SIA support: $SIA_MSG" |
|
|
echo " KerberosV support: $KRB5_MSG" |
|
|
echo " SELinux support: $SELINUX_MSG" |
|
|
+echo " LDAP support: $LDAP_MSG" |
|
|
echo " MD5 password support: $MD5_MSG" |
|
|
echo " libedit support: $LIBEDIT_MSG" |
|
|
echo " libldns support: $LDNS_MSG" |
|
|
Index: configure |
|
|
--- configure.orig 2019-10-09 02:39:30.000000000 +0200 |
|
|
+++ configure 2019-10-09 23:03:45.287311000 +0200 |
|
|
@@ -1449,6 +1449,7 @@ |
|
|
--with-ldns[=PATH] Use ldns for DNSSEC support (optionally in PATH) |
|
|
--with-libedit[=PATH] Enable libedit support for sftp |
|
|
--with-audit=module Enable audit support (modules=debug,bsm,linux) |
|
|
+ --with-ldap[=PATH] Enable LDAP pubkey support (optionally in PATH) |
|
|
--with-pie Build Position Independent Executables if possible |
|
|
--with-ssl-dir=PATH Specify path to OpenSSL installation |
|
|
--without-openssl-header-check Disable OpenSSL version consistency check |
|
|
@@ -13664,6 +13665,57 @@ |
|
|
|
|
|
fi |
|
|
|
|
|
+# Check whether user wants LDAP support |
|
|
+LDAP_MSG="no" |
|
|
+ |
|
|
+# Check whether --with-ldap was given. |
|
|
+if test "${with_ldap+set}" = set; then : |
|
|
+ withval=$with_ldap; |
|
|
+ if test "x$withval" != "xno" ; then |
|
|
+ |
|
|
+ if test "x$withval" != "xyes" ; then |
|
|
+ CPPFLAGS="$CPPFLAGS -I${withval}/include" |
|
|
+ LDFLAGS="$LDFLAGS -L${withval}/lib" |
|
|
+ fi |
|
|
+ |
|
|
+ |
|
|
+$as_echo "#define WITH_LDAP_PUBKEY 1" >>confdefs.h |
|
|
+ |
|
|
+ LIBS="-lldap $LIBS" |
|
|
+ LDAP_MSG="yes" |
|
|
+ |
|
|
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for LDAP support" >&5 |
|
|
+$as_echo_n "checking for LDAP support... " >&6; } |
|
|
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext |
|
|
+/* end confdefs.h. */ |
|
|
+#include <sys/types.h> |
|
|
+ #include <ldap.h> |
|
|
+int |
|
|
+main () |
|
|
+{ |
|
|
+(void)ldap_init(0, 0); |
|
|
+ ; |
|
|
+ return 0; |
|
|
+} |
|
|
+_ACEOF |
|
|
+if ac_fn_c_try_compile "$LINENO"; then : |
|
|
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 |
|
|
+$as_echo "yes" >&6; } |
|
|
+else |
|
|
+ |
|
|
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 |
|
|
+$as_echo "no" >&6; } |
|
|
+ as_fn_error $? "** Incomplete or missing ldap libraries **" "$LINENO" 5 |
|
|
+ |
|
|
+ |
|
|
+fi |
|
|
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext |
|
|
+ fi |
|
|
+ |
|
|
+ |
|
|
+fi |
|
|
+ |
|
|
+ |
|
|
for ac_func in \ |
|
|
arc4random \ |
|
|
arc4random_buf \ |
|
|
@@ -20766,6 +20818,7 @@ |
|
|
echo " OSF SIA support: $SIA_MSG" |
|
|
echo " KerberosV support: $KRB5_MSG" |
|
|
echo " SELinux support: $SELINUX_MSG" |
|
|
+echo " LDAP support: $LDAP_MSG" |
|
|
echo " MD5 password support: $MD5_MSG" |
|
|
echo " libedit support: $LIBEDIT_MSG" |
|
|
echo " libldns support: $LDNS_MSG" |
|
|
Index: ldapauth.c |
|
|
--- ldapauth.c.orig 2019-10-09 23:03:45.287898000 +0200 |
|
|
+++ ldapauth.c 2019-10-09 23:03:45.287771000 +0200 |
|
|
@@ -0,0 +1,579 @@ |
|
|
+/* |
|
|
+ * $Id: openssh-lpk-4.3p1-0.3.7.patch,v 1.3 2006/04/18 15:29:09 eau Exp $ |
|
|
+ */ |
|
|
+ |
|
|
+/* |
|
|
+ * |
|
|
+ * Copyright (c) 2005, Eric AUGE <eau@phear.org> |
|
|
+ * All rights reserved. |
|
|
+ * |
|
|
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: |
|
|
+ * |
|
|
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. |
|
|
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. |
|
|
+ * Neither the name of the phear.org nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. |
|
|
+ * |
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, |
|
|
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
|
|
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, |
|
|
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
|
|
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
|
|
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
|
+ * |
|
|
+ * |
|
|
+ */ |
|
|
+ |
|
|
+#include "includes.h" |
|
|
+ |
|
|
+#ifdef WITH_LDAP_PUBKEY |
|
|
+ |
|
|
+#include <stdio.h> |
|
|
+#include <stdlib.h> |
|
|
+#include <unistd.h> |
|
|
+#include <string.h> |
|
|
+#include <stdarg.h> |
|
|
+ |
|
|
+#include "ldapauth.h" |
|
|
+#include "log.h" |
|
|
+ |
|
|
+/* filter building infos */ |
|
|
+#define FILTER_GROUP_PREFIX "(&(objectclass=posixGroup)" |
|
|
+#define FILTER_OR_PREFIX "(|" |
|
|
+#define FILTER_OR_SUFFIX ")" |
|
|
+#define FILTER_CN_PREFIX "(cn=" |
|
|
+#define FILTER_CN_SUFFIX ")" |
|
|
+#define FILTER_UID_FORMAT "(memberUid=%s)" |
|
|
+#define FILTER_GROUP_SUFFIX ")" |
|
|
+#define FILTER_GROUP_SIZE(group) (size_t) (strlen(group)+(ldap_count_group(group)*5)+52) |
|
|
+ |
|
|
+/* just filter building stuff */ |
|
|
+#define REQUEST_GROUP_SIZE(filter, uid) (size_t) (strlen(filter)+strlen(uid)+1) |
|
|
+#define REQUEST_GROUP(buffer, prefilter, pwname) \ |
|
|
+ buffer = (char *) calloc(REQUEST_GROUP_SIZE(prefilter, pwname), sizeof(char)); \ |
|
|
+ if (!buffer) { \ |
|
|
+ perror("calloc()"); \ |
|
|
+ return FAILURE; \ |
|
|
+ } \ |
|
|
+ snprintf(buffer, REQUEST_GROUP_SIZE(prefilter,pwname), prefilter, pwname) |
|
|
+/* |
|
|
+XXX OLD group building macros |
|
|
+#define REQUEST_GROUP_SIZE(grp, uid) (size_t) (strlen(grp)+strlen(uid)+46) |
|
|
+#define REQUEST_GROUP(buffer,pwname,grp) \ |
|
|
+ buffer = (char *) calloc(REQUEST_GROUP_SIZE(grp, pwname), sizeof(char)); \ |
|
|
+ if (!buffer) { \ |
|
|
+ perror("calloc()"); \ |
|
|
+ return FAILURE; \ |
|
|
+ } \ |
|
|
+ snprintf(buffer,REQUEST_GROUP_SIZE(grp,pwname),"(&(objectclass=posixGroup)(cn=%s)(memberUid=%s))",grp,pwname) |
|
|
+ */ |
|
|
+ |
|
|
+/* |
|
|
+XXX stock upstream version without extra filter support |
|
|
+#define REQUEST_USER_SIZE(uid) (size_t) (strlen(uid)+64) |
|
|
+#define REQUEST_USER(buffer, pwname) \ |
|
|
+ buffer = (char *) calloc(REQUEST_USER_SIZE(pwname), sizeof(char)); \ |
|
|
+ if (!buffer) { \ |
|
|
+ perror("calloc()"); \ |
|
|
+ return NULL; \ |
|
|
+ } \ |
|
|
+ snprintf(buffer,REQUEST_USER_SIZE(pwname),"(&(objectclass=posixAccount)(objectclass=ldapPublicKey)(uid=%s))",pwname) |
|
|
+ */ |
|
|
+ |
|
|
+#define REQUEST_USER_SIZE(uid, filter, uid_attr) (size_t) (strlen(uid)+strlen(uid_attr)+61+(filter != NULL ? strlen(filter) : 0)) |
|
|
+#define REQUEST_USER(buffer, pwname, customfilter, uid_attr) \ |
|
|
+ buffer = (char *) calloc(REQUEST_USER_SIZE(pwname, customfilter, uid_attr), sizeof(char)); \ |
|
|
+ if (!buffer) { \ |
|
|
+ perror("calloc()"); \ |
|
|
+ return NULL; \ |
|
|
+ } \ |
|
|
+ snprintf(buffer, REQUEST_USER_SIZE(pwname, customfilter, uid_attr), \ |
|
|
+ "(&(objectclass=posixAccount)(objectclass=ldapPublicKey)(%s=%s)%s)", \ |
|
|
+ uid_attr, pwname, (customfilter != NULL ? customfilter : "")) |
|
|
+ |
|
|
+/* some portable and working tokenizer, lame though */ |
|
|
+static int tokenize(char ** o, size_t size, char * input) { |
|
|
+ unsigned int i = 0, num; |
|
|
+ const char * charset = " \t"; |
|
|
+ char * ptr = input; |
|
|
+ |
|
|
+ /* leading white spaces are ignored */ |
|
|
+ num = strspn(ptr, charset); |
|
|
+ ptr += num; |
|
|
+ |
|
|
+ while ((num = strcspn(ptr, charset))) { |
|
|
+ if (i < size-1) { |
|
|
+ o[i++] = ptr; |
|
|
+ ptr += num; |
|
|
+ if (*ptr) |
|
|
+ *ptr++ = '\0'; |
|
|
+ } |
|
|
+ } |
|
|
+ o[i] = NULL; |
|
|
+ return SUCCESS; |
|
|
+} |
|
|
+ |
|
|
+void ldap_close(ldap_opt_t * ldap) { |
|
|
+ |
|
|
+ if (!ldap) |
|
|
+ return; |
|
|
+ |
|
|
+ if ( ldap_unbind_ext(ldap->ld, NULL, NULL) < 0) |
|
|
+ ldap_perror(ldap->ld, "ldap_unbind()"); |
|
|
+ |
|
|
+ ldap->ld = NULL; |
|
|
+ FLAG_SET_DISCONNECTED(ldap->flags); |
|
|
+ |
|
|
+ return; |
|
|
+} |
|
|
+ |
|
|
+/* init && bind */ |
|
|
+int ldap_connect(ldap_opt_t * ldap) { |
|
|
+ int version = LDAP_VERSION3; |
|
|
+ |
|
|
+ if (!ldap->servers) |
|
|
+ return FAILURE; |
|
|
+ |
|
|
+ /* Connection Init and setup */ |
|
|
+ ldap->ld = ldap_init(ldap->servers, LDAP_PORT); |
|
|
+ if (!ldap->ld) { |
|
|
+ ldap_perror(ldap->ld, "ldap_init()"); |
|
|
+ return FAILURE; |
|
|
+ } |
|
|
+ |
|
|
+ if ( ldap_set_option(ldap->ld, LDAP_OPT_PROTOCOL_VERSION, &version) != LDAP_OPT_SUCCESS) { |
|
|
+ ldap_perror(ldap->ld, "ldap_set_option(LDAP_OPT_PROTOCOL_VERSION)"); |
|
|
+ return FAILURE; |
|
|
+ } |
|
|
+ |
|
|
+ /* Timeouts setup */ |
|
|
+ if (ldap_set_option(ldap->ld, LDAP_OPT_NETWORK_TIMEOUT, &ldap->b_timeout) != LDAP_SUCCESS) { |
|
|
+ ldap_perror(ldap->ld, "ldap_set_option(LDAP_OPT_NETWORK_TIMEOUT)"); |
|
|
+ } |
|
|
+ if (ldap_set_option(ldap->ld, LDAP_OPT_TIMEOUT, &ldap->s_timeout) != LDAP_SUCCESS) { |
|
|
+ ldap_perror(ldap->ld, "ldap_set_option(LDAP_OPT_TIMEOUT)"); |
|
|
+ } |
|
|
+ |
|
|
+ /* TLS support */ |
|
|
+ if ( (ldap->tls == -1) || (ldap->tls == 1) ) { |
|
|
+ if (ldap_start_tls_s(ldap->ld, NULL, NULL ) != LDAP_SUCCESS) { |
|
|
+ /* failed then reinit the initial connect */ |
|
|
+ ldap_perror(ldap->ld, "ldap_connect: (TLS) ldap_start_tls()"); |
|
|
+ if (ldap->tls == 1) |
|
|
+ return FAILURE; |
|
|
+ |
|
|
+ ldap->ld = ldap_init(ldap->servers, LDAP_PORT); |
|
|
+ if (!ldap->ld) { |
|
|
+ ldap_perror(ldap->ld, "ldap_init()"); |
|
|
+ return FAILURE; |
|
|
+ } |
|
|
+ |
|
|
+ if ( ldap_set_option(ldap->ld, LDAP_OPT_PROTOCOL_VERSION, &version) != LDAP_OPT_SUCCESS) { |
|
|
+ ldap_perror(ldap->ld, "ldap_set_option()"); |
|
|
+ return FAILURE; |
|
|
+ } |
|
|
+ } |
|
|
+ } |
|
|
+ |
|
|
+ |
|
|
+ if ( ldap_simple_bind_s(ldap->ld, ldap->binddn, ldap->bindpw) != LDAP_SUCCESS) { |
|
|
+ ldap_perror(ldap->ld, "ldap_simple_bind_s()"); |
|
|
+ return FAILURE; |
|
|
+ } |
|
|
+ |
|
|
+ /* says it is connected */ |
|
|
+ FLAG_SET_CONNECTED(ldap->flags); |
|
|
+ |
|
|
+ return SUCCESS; |
|
|
+} |
|
|
+ |
|
|
+/* must free allocated ressource */ |
|
|
+static char * ldap_build_host(char *host, int port) { |
|
|
+ unsigned int size = strlen(host)+11; |
|
|
+ char * h = (char *) calloc (size, sizeof(char)); |
|
|
+ int rc; |
|
|
+ if (!h) |
|
|
+ return NULL; |
|
|
+ |
|
|
+ rc = snprintf(h, size, "%s:%d ", host, port); |
|
|
+ if (rc == -1) |
|
|
+ return NULL; |
|
|
+ return h; |
|
|
+} |
|
|
+ |
|
|
+static int ldap_count_group(const char * input) { |
|
|
+ const char * charset = " \t"; |
|
|
+ const char * ptr = input; |
|
|
+ unsigned int count = 0; |
|
|
+ unsigned int num; |
|
|
+ |
|
|
+ num = strspn(ptr, charset); |
|
|
+ ptr += num; |
|
|
+ |
|
|
+ while ((num = strcspn(ptr, charset))) { |
|
|
+ count++; |
|
|
+ ptr += num; |
|
|
+ ptr++; |
|
|
+ } |
|
|
+ |
|
|
+ return count; |
|
|
+} |
|
|
+ |
|
|
+/* format filter */ |
|
|
+char * ldap_parse_groups(const char * groups) { |
|
|
+ unsigned int buffer_size = FILTER_GROUP_SIZE(groups); |
|
|
+ char * buffer = (char *) calloc(buffer_size, sizeof(char)); |
|
|
+ char * g = NULL; |
|
|
+ char * garray[32]; |
|
|
+ unsigned int i = 0; |
|
|
+ |
|
|
+ if ((!groups)||(!buffer)) |
|
|
+ return NULL; |
|
|
+ |
|
|
+ g = strdup(groups); |
|
|
+ if (!g) { |
|
|
+ free(buffer); |
|
|
+ return NULL; |
|
|
+ } |
|
|
+ |
|
|
+ /* first separate into n tokens */ |
|
|
+ if ( tokenize(garray, sizeof(garray)/sizeof(*garray), g) < 0) { |
|
|
+ free(g); |
|
|
+ free(buffer); |
|
|
+ return NULL; |
|
|
+ } |
|
|
+ |
|
|
+ /* build the final filter format */ |
|
|
+ strlcat(buffer, FILTER_GROUP_PREFIX, buffer_size); |
|
|
+ strlcat(buffer, FILTER_OR_PREFIX, buffer_size); |
|
|
+ i = 0; |
|
|
+ while (garray[i]) { |
|
|
+ strlcat(buffer, FILTER_CN_PREFIX, buffer_size); |
|
|
+ strlcat(buffer, garray[i], buffer_size); |
|
|
+ strlcat(buffer, FILTER_CN_SUFFIX, buffer_size); |
|
|
+ i++; |
|
|
+ } |
|
|
+ strlcat(buffer, FILTER_OR_SUFFIX, buffer_size); |
|
|
+ strlcat(buffer, FILTER_UID_FORMAT, buffer_size); |
|
|
+ strlcat(buffer, FILTER_GROUP_SUFFIX, buffer_size); |
|
|
+ |
|
|
+ free(g); |
|
|
+ return buffer; |
|
|
+} |
|
|
+ |
|
|
+/* a bit dirty but leak free */ |
|
|
+char * ldap_parse_servers(const char * servers) { |
|
|
+ char * s = NULL; |
|
|
+ char * tmp = NULL, *urls[32]; |
|
|
+ unsigned int num = 0 , i = 0 , asize = 0; |
|
|
+ LDAPURLDesc *urld[32]; |
|
|
+ |
|
|
+ if (!servers) |
|
|
+ return NULL; |
|
|
+ |
|
|
+ /* local copy of the arg */ |
|
|
+ s = strdup(servers); |
|
|
+ if (!s) |
|
|
+ return NULL; |
|
|
+ |
|
|
+ /* first separate into URL tokens */ |
|
|
+ if ( tokenize(urls, sizeof(urls)/sizeof(*urls), s) < 0) |
|
|
+ return NULL; |
|
|
+ |
|
|
+ i = 0; |
|
|
+ while (urls[i]) { |
|
|
+ if (! ldap_is_ldap_url(urls[i]) || |
|
|
+ (ldap_url_parse(urls[i], &urld[i]) != 0)) { |
|
|
+ return NULL; |
|
|
+ } |
|
|
+ i++; |
|
|
+ } |
|
|
+ |
|
|
+ /* now free(s) */ |
|
|
+ free (s); |
|
|
+ |
|
|
+ /* how much memory do we need */ |
|
|
+ num = i; |
|
|
+ for (i = 0 ; i < num ; i++) |
|
|
+ asize += strlen(urld[i]->lud_host)+11; |
|
|
+ |
|
|
+ /* alloc */ |
|
|
+ s = (char *) calloc( asize+1 , sizeof(char)); |
|
|
+ if (!s) { |
|
|
+ for (i = 0 ; i < num ; i++) |
|
|
+ ldap_free_urldesc(urld[i]); |
|
|
+ return NULL; |
|
|
+ } |
|
|
+ |
|
|
+ /* then build the final host string */ |
|
|
+ for (i = 0 ; i < num ; i++) { |
|
|
+ /* built host part */ |
|
|
+ tmp = ldap_build_host(urld[i]->lud_host, urld[i]->lud_port); |
|
|
+ strncat(s, tmp, strlen(tmp)); |
|
|
+ ldap_free_urldesc(urld[i]); |
|
|
+ free(tmp); |
|
|
+ } |
|
|
+ |
|
|
+ return s; |
|
|
+} |
|
|
+ |
|
|
+void ldap_options_print(ldap_opt_t * ldap) { |
|
|
+ debug("ldap options:"); |
|
|
+ debug("servers: %s", ldap->servers); |
|
|
+ if (ldap->u_basedn) |
|
|
+ debug("user basedn: %s", ldap->u_basedn); |
|
|
+ if (ldap->g_basedn) |
|
|
+ debug("group basedn: %s", ldap->g_basedn); |
|
|
+ if (ldap->binddn) |
|
|
+ debug("binddn: %s", ldap->binddn); |
|
|
+ if (ldap->bindpw) |
|
|
+ debug("bindpw: %s", ldap->bindpw); |
|
|
+ if (ldap->sgroup) |
|
|
+ debug("group: %s", ldap->sgroup); |
|
|
+ if (ldap->filter) |
|
|
+ debug("filter: %s", ldap->filter); |
|
|
+ if (ldap->uid_attr) |
|
|
+ debug("uid_attr: %s", ldap->uid_attr); |
|
|
+} |
|
|
+ |
|
|
+void ldap_options_free(ldap_opt_t * l) { |
|
|
+ if (!l) |
|
|
+ return; |
|
|
+ if (l->servers) |
|
|
+ free(l->servers); |
|
|
+ if (l->u_basedn) |
|
|
+ free(l->u_basedn); |
|
|
+ if (l->g_basedn) |
|
|
+ free(l->g_basedn); |
|
|
+ if (l->binddn) |
|
|
+ free(l->binddn); |
|
|
+ if (l->bindpw) |
|
|
+ free(l->bindpw); |
|
|
+ if (l->sgroup) |
|
|
+ free(l->sgroup); |
|
|
+ if (l->fgroup) |
|
|
+ free(l->fgroup); |
|
|
+ if (l->filter) |
|
|
+ free(l->filter); |
|
|
+ if (l->l_conf) |
|
|
+ free(l->l_conf); |
|
|
+ if (l->uid_attr) |
|
|
+ free(l->uid_attr); |
|
|
+ free(l); |
|
|
+} |
|
|
+ |
|
|
+/* free keys */ |
|
|
+void ldap_keys_free(ldap_key_t * k) { |
|
|
+ ldap_value_free_len(k->keys); |
|
|
+ free(k); |
|
|
+ return; |
|
|
+} |
|
|
+ |
|
|
+ldap_key_t * ldap_getuserkey(ldap_opt_t *l, const char * user) { |
|
|
+ ldap_key_t * k = (ldap_key_t *) calloc (1, sizeof(ldap_key_t)); |
|
|
+ LDAPMessage *res, *e; |
|
|
+ char * filter; |
|
|
+ int i; |
|
|
+ char *attrs[] = { |
|
|
+ l->pub_key_attr, |
|
|
+ NULL |
|
|
+ }; |
|
|
+ |
|
|
+ if ((!k) || (!l)) |
|
|
+ return NULL; |
|
|
+ |
|
|
+ /* Am i still connected ? RETRY n times */ |
|
|
+ /* XXX TODO: setup some conf value for retrying */ |
|
|
+ if (!(l->flags & FLAG_CONNECTED)) |
|
|
+ for (i = 0 ; i < 2 ; i++) |
|
|
+ if (ldap_connect(l) == 0) |
|
|
+ break; |
|
|
+ |
|
|
+ /* quick check for attempts to be evil */ |
|
|
+ if ((strchr(user, '(') != NULL) || (strchr(user, ')') != NULL) || |
|
|
+ (strchr(user, '*') != NULL) || (strchr(user, '\\') != NULL)) |
|
|
+ return NULL; |
|
|
+ |
|
|
+ /* build filter for LDAP request */ |
|
|
+ REQUEST_USER(filter, user, l->filter, l->uid_attr); |
|
|
+ |
|
|
+ if ( ldap_search_st( l->ld, |
|
|
+ l->u_basedn, |
|
|
+ LDAP_SCOPE_SUBTREE, |
|
|
+ filter, |
|
|
+ attrs, 0, &l->s_timeout, &res ) != LDAP_SUCCESS) { |
|
|
+ |
|
|
+ ldap_perror(l->ld, "ldap_search_st()"); |
|
|
+ |
|
|
+ free(filter); |
|
|
+ free(k); |
|
|
+ |
|
|
+ /* XXX error on search, timeout etc.. close ask for reconnect */ |
|
|
+ ldap_close(l); |
|
|
+ |
|
|
+ return NULL; |
|
|
+ } |
|
|
+ |
|
|
+ /* free */ |
|
|
+ free(filter); |
|
|
+ |
|
|
+ /* check if any results */ |
|
|
+ i = ldap_count_entries(l->ld,res); |
|
|
+ if (i <= 0) { |
|
|
+ ldap_msgfree(res); |
|
|
+ free(k); |
|
|
+ return NULL; |
|
|
+ } |
|
|
+ |
|
|
+ if (i > 1) |
|
|
+ debug("[LDAP] duplicate entries, using the FIRST entry returned"); |
|
|
+ |
|
|
+ e = ldap_first_entry(l->ld, res); |
|
|
+ k->keys = ldap_get_values_len(l->ld, e, l->pub_key_attr); |
|
|
+ k->num = ldap_count_values_len(k->keys); |
|
|
+ |
|
|
+ ldap_msgfree(res); |
|
|
+ return k; |
|
|
+} |
|
|
+ |
|
|
+ |
|
|
+/* -1 if trouble |
|
|
+ 0 if user is NOT member of current server group |
|
|
+ 1 if user IS MEMBER of current server group |
|
|
+ */ |
|
|
+int ldap_ismember(ldap_opt_t * l, const char * user) { |
|
|
+ LDAPMessage *res; |
|
|
+ char * filter; |
|
|
+ int i; |
|
|
+ |
|
|
+ if ((!l->sgroup) || !(l->g_basedn)) |
|
|
+ return 1; |
|
|
+ |
|
|
+ /* Am i still connected ? RETRY n times */ |
|
|
+ /* XXX TODO: setup some conf value for retrying */ |
|
|
+ if (!(l->flags & FLAG_CONNECTED)) |
|
|
+ for (i = 0 ; i < 2 ; i++) |
|
|
+ if (ldap_connect(l) == 0) |
|
|
+ break; |
|
|
+ |
|
|
+ /* quick check for attempts to be evil */ |
|
|
+ if ((strchr(user, '(') != NULL) || (strchr(user, ')') != NULL) || |
|
|
+ (strchr(user, '*') != NULL) || (strchr(user, '\\') != NULL)) |
|
|
+ return FAILURE; |
|
|
+ |
|
|
+ /* build filter for LDAP request */ |
|
|
+ REQUEST_GROUP(filter, l->fgroup, user); |
|
|
+ |
|
|
+ if (ldap_search_st( l->ld, |
|
|
+ l->g_basedn, |
|
|
+ LDAP_SCOPE_SUBTREE, |
|
|
+ filter, |
|
|
+ NULL, 0, &l->s_timeout, &res) != LDAP_SUCCESS) { |
|
|
+ |
|
|
+ ldap_perror(l->ld, "ldap_search_st()"); |
|
|
+ |
|
|
+ free(filter); |
|
|
+ |
|
|
+ /* XXX error on search, timeout etc.. close ask for reconnect */ |
|
|
+ ldap_close(l); |
|
|
+ |
|
|
+ return FAILURE; |
|
|
+ } |
|
|
+ |
|
|
+ free(filter); |
|
|
+ |
|
|
+ /* check if any results */ |
|
|
+ if (ldap_count_entries(l->ld, res) > 0) { |
|
|
+ ldap_msgfree(res); |
|
|
+ return 1; |
|
|
+ } |
|
|
+ |
|
|
+ ldap_msgfree(res); |
|
|
+ return 0; |
|
|
+} |
|
|
+ |
|
|
+/* |
|
|
+ * ldap.conf simple parser |
|
|
+ * XXX TODO: sanity checks |
|
|
+ * must either |
|
|
+ * - free the previous ldap_opt_before replacing entries |
|
|
+ * - free each necessary previously parsed elements |
|
|
+ * ret: |
|
|
+ * -1 on FAILURE, 0 on SUCCESS |
|
|
+ */ |
|
|
+int ldap_parse_lconf(ldap_opt_t * l) { |
|
|
+ FILE * lcd; /* ldap.conf descriptor */ |
|
|
+ char buf[BUFSIZ]; |
|
|
+ char * s = NULL, * k = NULL, * v = NULL; |
|
|
+ int li, len; |
|
|
+ |
|
|
+ lcd = fopen (l->l_conf, "r"); |
|
|
+ if (lcd == NULL) { |
|
|
+ /* debug("Cannot open %s", l->l_conf); */ |
|
|
+ perror("ldap_parse_lconf()"); |
|
|
+ return FAILURE; |
|
|
+ } |
|
|
+ |
|
|
+ while (fgets (buf, sizeof (buf), lcd) != NULL) { |
|
|
+ |
|
|
+ if (*buf == '\n' || *buf == '#') |
|
|
+ continue; |
|
|
+ |
|
|
+ k = buf; |
|
|
+ v = k; |
|
|
+ while (*v != '\0' && *v != ' ' && *v != '\t') |
|
|
+ v++; |
|
|
+ |
|
|
+ if (*v == '\0') |
|
|
+ continue; |
|
|
+ |
|
|
+ *(v++) = '\0'; |
|
|
+ |
|
|
+ while (*v == ' ' || *v == '\t') |
|
|
+ v++; |
|
|
+ |
|
|
+ li = strlen (v) - 1; |
|
|
+ while (v[li] == ' ' || v[li] == '\t' || v[li] == '\n') |
|
|
+ --li; |
|
|
+ v[li + 1] = '\0'; |
|
|
+ |
|
|
+ if (!strcasecmp (k, "uri")) { |
|
|
+ if ((l->servers = ldap_parse_servers(v)) == NULL) { |
|
|
+ fatal("error in ldap servers"); |
|
|
+ return FAILURE; |
|
|
+ } |
|
|
+ |
|
|
+ } |
|
|
+ else if (!strcasecmp (k, "base")) { |
|
|
+ s = strchr (v, '?'); |
|
|
+ if (s != NULL) { |
|
|
+ len = s - v; |
|
|
+ l->u_basedn = malloc (len + 1); |
|
|
+ strncpy (l->u_basedn, v, len); |
|
|
+ l->u_basedn[len] = '\0'; |
|
|
+ } else { |
|
|
+ l->u_basedn = strdup (v); |
|
|
+ } |
|
|
+ } |
|
|
+ else if (!strcasecmp (k, "binddn")) { |
|
|
+ l->binddn = strdup (v); |
|
|
+ } |
|
|
+ else if (!strcasecmp (k, "bindpw")) { |
|
|
+ l->bindpw = strdup (v); |
|
|
+ } |
|
|
+ else if (!strcasecmp (k, "timelimit")) { |
|
|
+ l->s_timeout.tv_sec = atoi (v); |
|
|
+ } |
|
|
+ else if (!strcasecmp (k, "bind_timelimit")) { |
|
|
+ l->b_timeout.tv_sec = atoi (v); |
|
|
+ } |
|
|
+ else if (!strcasecmp (k, "ssl")) { |
|
|
+ if (!strcasecmp (v, "start_tls")) |
|
|
+ l->tls = 1; |
|
|
+ } |
|
|
+ } |
|
|
+ |
|
|
+ fclose (lcd); |
|
|
+ return SUCCESS; |
|
|
+} |
|
|
+ |
|
|
+#endif /* WITH_LDAP_PUBKEY */ |
|
|
Index: ldapauth.h |
|
|
--- ldapauth.h.orig 2019-10-09 23:03:45.288189000 +0200 |
|
|
+++ ldapauth.h 2019-10-09 23:03:45.288063000 +0200 |
|
|
@@ -0,0 +1,130 @@ |
|
|
+/* |
|
|
+ * $Id: openssh-lpk-4.3p1-0.3.7.patch,v 1.3 2006/04/18 15:29:09 eau Exp $ |
|
|
+ */ |
|
|
+ |
|
|
+/* |
|
|
+ * |
|
|
+ * Copyright (c) 2005, Eric AUGE <eau@phear.org> |
|
|
+ * All rights reserved. |
|
|
+ * |
|
|
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: |
|
|
+ * |
|
|
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. |
|
|
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. |
|
|
+ * Neither the name of the phear.org nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. |
|
|
+ * |
|
|
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, |
|
|
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
|
|
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, |
|
|
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
|
|
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
|
|
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
|
+ * |
|
|
+ * |
|
|
+ */ |
|
|
+ |
|
|
+#ifndef LDAPAUTH_H |
|
|
+#define LDAPAUTH_H |
|
|
+ |
|
|
+#define LDAP_DEPRECATED 1 |
|
|
+ |
|
|
+#include <string.h> |
|
|
+#include <time.h> |
|
|
+#include <ldap.h> |
|
|
+#include <lber.h> |
|
|
+ |
|
|
+/* tokens in use for config */ |
|
|
+#define _DEFAULT_LPK_TOKEN "UseLPK" |
|
|
+#define _DEFAULT_SRV_TOKEN "LpkServers" |
|
|
+#define _DEFAULT_USR_TOKEN "LpkUserDN" |
|
|
+#define _DEFAULT_GRP_TOKEN "LpkGroupDN" |
|
|
+#define _DEFAULT_BDN_TOKEN "LpkBindDN" |
|
|
+#define _DEFAULT_BPW_TOKEN "LpkBindPw" |
|
|
+#define _DEFAULT_MYG_TOKEN "LpkServerGroup" |
|
|
+#define _DEFAULT_FIL_TOKEN "LpkFilter" |
|
|
+#define _DEFAULT_TLS_TOKEN "LpkForceTLS" |
|
|
+#define _DEFAULT_BTI_TOKEN "LpkBindTimelimit" |
|
|
+#define _DEFAULT_STI_TOKEN "LpkSearchTimelimit" |
|
|
+#define _DEFAULT_LDP_TOKEN "LpkLdapConf" |
|
|
+#define _DEFAULT_UID_TOKEN "LpkUIDAttribute" |
|
|
+ |
|
|
+#define _DEFAULT_PUB_TOKEN "LpkPubKeyAttr" |
|
|
+ |
|
|
+/* default options */ |
|
|
+#define _DEFAULT_LPK_ON 0 |
|
|
+#define _DEFAULT_LPK_SERVERS NULL |
|
|
+#define _DEFAULT_LPK_UDN NULL |
|
|
+#define _DEFAULT_LPK_GDN NULL |
|
|
+#define _DEFAULT_LPK_BINDDN NULL |
|
|
+#define _DEFAULT_LPK_BINDPW NULL |
|
|
+#define _DEFAULT_LPK_SGROUP NULL |
|
|
+#define _DEFAULT_LPK_FILTER NULL |
|
|
+#define _DEFAULT_LPK_TLS -1 |
|
|
+#define _DEFAULT_LPK_BTIMEOUT 10 |
|
|
+#define _DEFAULT_LPK_STIMEOUT 10 |
|
|
+#define _DEFAULT_LPK_LDP NULL |
|
|
+#define _DEFAULT_LPK_PUB "sshPublicKey" |
|
|
+#define _DEFAULT_LPK_UID "uid" |
|
|
+ |
|
|
+/* flags */ |
|
|
+#define FLAG_EMPTY 0x00000000 |
|
|
+#define FLAG_CONNECTED 0x00000001 |
|
|
+ |
|
|
+/* flag macros */ |
|
|
+#define FLAG_SET_EMPTY(x) x&=(FLAG_EMPTY) |
|
|
+#define FLAG_SET_CONNECTED(x) x|=(FLAG_CONNECTED) |
|
|
+#define FLAG_SET_DISCONNECTED(x) x&=~(FLAG_CONNECTED) |
|
|
+ |
|
|
+/* defines */ |
|
|
+#define FAILURE -1 |
|
|
+#define SUCCESS 0 |
|
|
+ |
|
|
+/* |
|
|
+ * |
|
|
+ * defined files path |
|
|
+ * (should be relocated to pathnames.h, |
|
|
+ * if one day it's included within the tree) |
|
|
+ * |
|
|
+ */ |
|
|
+#define _PATH_LDAP_CONFIG_FILE "/etc/ldap.conf" |
|
|
+ |
|
|
+/* structures */ |
|
|
+typedef struct ldap_options { |
|
|
+ int on; /* Use it or NOT */ |
|
|
+ LDAP * ld; /* LDAP file desc */ |
|
|
+ char * servers; /* parsed servers for ldaplib failover handling */ |
|
|
+ char * u_basedn; /* user basedn */ |
|
|
+ char * g_basedn; /* group basedn */ |
|
|
+ char * uid_attr; /* LDAP attribute that represents uid, defaults to uid*/ |
|
|
+ char * binddn; /* binddn */ |
|
|
+ char * bindpw; /* bind password */ |
|
|
+ char * sgroup; /* server group */ |
|
|
+ char * fgroup; /* group filter */ |
|
|
+ char * filter; /* additional filter */ |
|
|
+ char * l_conf; /* use ldap.conf */ |
|
|
+ int tls; /* TLS only */ |
|
|
+ struct timeval b_timeout; /* bind timeout */ |
|
|
+ struct timeval s_timeout; /* search timeout */ |
|
|
+ unsigned int flags; /* misc flags (reconnection, future use?) */ |
|
|
+ char * pub_key_attr; /* Pubkey-Attribute */ |
|
|
+} ldap_opt_t; |
|
|
+ |
|
|
+typedef struct ldap_keys { |
|
|
+ struct berval ** keys; /* the public keys retrieved */ |
|
|
+ unsigned int num; /* number of keys */ |
|
|
+} ldap_key_t; |
|
|
+ |
|
|
+ |
|
|
+/* function headers */ |
|
|
+void ldap_close(ldap_opt_t *); |
|
|
+int ldap_connect(ldap_opt_t *); |
|
|
+char * ldap_parse_groups(const char *); |
|
|
+char * ldap_parse_servers(const char *); |
|
|
+void ldap_options_print(ldap_opt_t *); |
|
|
+void ldap_options_free(ldap_opt_t *); |
|
|
+void ldap_keys_free(ldap_key_t *); |
|
|
+int ldap_parse_lconf(ldap_opt_t *); |
|
|
+ldap_key_t * ldap_getuserkey(ldap_opt_t *, const char *); |
|
|
+int ldap_ismember(ldap_opt_t *, const char *); |
|
|
+ |
|
|
+#endif |
|
|
Index: lpk-user-example.txt |
|
|
--- lpk-user-example.txt.orig 2019-10-09 23:03:45.288452000 +0200 |
|
|
+++ lpk-user-example.txt 2019-10-09 23:03:45.288336000 +0200 |
|
|
@@ -0,0 +1,117 @@ |
|
|
+ |
|
|
+Post to ML -> User Made Quick Install Doc. |
|
|
+Contribution from John Lane <john@lane.uk.net> |
|
|
+ |
|
|
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
|
|
+ |
|
|
+OpenSSH LDAP keystore Patch |
|
|
+=========================== |
|
|
+ |
|
|
+NOTE: these notes are a transcript of a specific installation |
|
|
+ they work for me, your specifics may be different! |
|
|
+ from John Lane March 17th 2005 john@lane.uk.net |
|
|
+ |
|
|
+This is a patch to OpenSSH 4.0p1 to allow it to obtain users' public keys |
|
|
+from their LDAP record as an alternative to ~/.ssh/authorized_keys. |
|
|
+ |
|
|
+(Assuming here that necessary build stuff is in $BUILD) |
|
|
+ |
|
|
+cd $BUILD/openssh-4.0p1 |
|
|
+patch -Np1 -i $BUILD/openssh-lpk-4.0p1-0.3.patch |
|
|
+mkdir -p /var/empty && |
|
|
+./configure --prefix=/usr --sysconfdir=/etc/ssh \ |
|
|
+ --libexecdir=/usr/sbin --with-md5-passwords --with-pam \ |
|
|
+ --with-libs="-lldap" --with-cppflags="-DWITH_LDAP_PUBKEY" |
|
|
+Now do. |
|
|
+make && |
|
|
+make install |
|
|
+ |
|
|
+Add the following config to /etc/ssh/ssh_config |
|
|
+UseLPK yes |
|
|
+LpkServers ldap://myhost.mydomain.com |
|
|
+LpkUserDN ou=People,dc=mydomain,dc=com |
|
|
+ |
|
|
+We need to tell sshd about the SSL keys during boot, as root's |
|
|
+environment does not exist at that time. Edit /etc/rc.d/init.d/sshd. |
|
|
+Change the startup code from this: |
|
|
+ echo "Starting SSH Server..." |
|
|
+ loadproc /usr/sbin/sshd |
|
|
+ ;; |
|
|
+to this: |
|
|
+ echo "Starting SSH Server..." |
|
|
+ LDAPRC="/root/.ldaprc" loadproc /usr/sbin/sshd |
|
|
+ ;; |
|
|
+ |
|
|
+Re-start the sshd daemon: |
|
|
+/etc/rc.d/init.d/sshd restart |
|
|
+ |
|
|
+Install the additional LDAP schema |
|
|
+cp $BUILD/openssh-lpk-0.2.schema /etc/openldap/schema/openssh.schema |
|
|
+ |
|
|
+Now add the openSSH LDAP schema to /etc/openldap/slapd.conf: |
|
|
+Add the following to the end of the existing block of schema includes |
|
|
+include /etc/openldap/schema/openssh.schema |
|
|
+ |
|
|
+Re-start the LDAP server: |
|
|
+/etc/rc.d/init.d/slapd restart |
|
|
+ |
|
|
+To add one or more public keys to a user, eg "testuser" : |
|
|
+ldapsearch -x -W -Z -LLL -b "uid=testuser,ou=People,dc=mydomain,dc=com" -D |
|
|
+"uid=testuser,ou=People,dc=mydomain,dc=com" > /tmp/testuser |
|
|
+ |
|
|
+append the following to this /tmp/testuser file |
|
|
+objectclass: ldapPublicKey |
|
|
+sshPublicKey: ssh-rsa |
|
|
+AAAAB3NzaC1yc2EAAAABJQAAAIB3dsrwqXqD7E4zYYrxwdDKBUQxKMioXy9pxFVai64kAPxjU9KS |
|
|
+qIo7QfkjslfsjflksjfldfkjsldfjLX/5zkzRmT28I5piGzunPv17S89z8XwSsuAoR1t86t+5dlI |
|
|
+7eZE/gVbn2UQkQq7+kdDTS2yXV6VnC52N/kKLG3ciBkBAw== General Purpose RSA Key |
|
|
+ |
|
|
+Then do a modify: |
|
|
+ldapmodify -x -D "uid=testuser,ou=People,dc=mydomain,dc=com" -W -f |
|
|
+/tmp/testuser -Z |
|
|
+Enter LDAP Password: |
|
|
+modifying entry "uid=testuser,ou=People,dc=mydomain,dc=com" |
|
|
+And check the modify is ok: |
|
|
+ldapsearch -x -W -Z -b "uid=testuser,ou=People,dc=mydomain,dc=com" -D |
|
|
+"uid=testuser,ou=People,dc=mydomain,dc=com" |
|
|
+Enter LDAP Password: |
|
|
+# extended LDIF |
|
|
+# |
|
|
+# LDAPv3 |
|
|
+# base <uid=testuser,ou=People,dc=mydomain,dc=com> with scope sub |
|
|
+# filter: (objectclass=*) |
|
|
+# requesting: ALL |
|
|
+# |
|
|
+ |
|
|
+# testuser, People, mydomain.com |
|
|
+dn: uid=testuser,ou=People,dc=mydomain,dc=com |
|
|
+uid: testuser |
|
|
+cn: testuser |
|
|
+objectClass: account |
|
|
+objectClass: posixAccount |
|
|
+objectClass: top |
|
|
+objectClass: shadowAccount |
|
|
+objectClass: ldapPublicKey |
|
|
+shadowLastChange: 12757 |
|
|
+shadowMax: 99999 |
|
|
+shadowWarning: 7 |
|
|
+loginShell: /bin/bash |
|
|
+uidNumber: 9999 |
|
|
+gidNumber: 501 |
|
|
+homeDirectory: /home/testuser |
|
|
+userPassword:: e1NTSEF9UDgwV1hnM1VjUDRJK0k1YnFiL1d4ZUJObXlZZ3Z3UTU= |
|
|
+sshPublicKey: ssh-rsa |
|
|
+AAAAB3NzaC1yc2EAAAABJQAAAIB3dsrwqXqD7E4zYYrxwdDKBUQxKMioXy9pxFVai64kAPxjU9KSqIo7QfkjslfsjflksjfldfkjsldfjLX/5zkzRmT28I5piGzunPv17S89z |
|
|
+8XwSsuAoR1t86t+5dlI7eZE/gVbn2UQkQq7+kdDTS2yXV6VnC52N/kKLG3ciBkBAw== General Purpose RSA Key |
|
|
+ |
|
|
+# search result |
|
|
+search: 3 |
|
|
+result: 0 Success |
|
|
+ |
|
|
+# numResponses: 2 |
|
|
+# numEntries: 1 |
|
|
+ |
|
|
+Now start a ssh session to user "testuser" from usual ssh client (e.g. |
|
|
+puTTY). Login should succeed. |
|
|
+ |
|
|
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
|
|
Index: openssh-lpk_openldap.schema |
|
|
--- openssh-lpk_openldap.schema.orig 2019-10-09 23:03:45.288692000 +0200 |
|
|
+++ openssh-lpk_openldap.schema 2019-10-09 23:03:45.288574000 +0200 |
|
|
@@ -0,0 +1,19 @@ |
|
|
+# |
|
|
+# LDAP Public Key Patch schema for use with openssh-ldappubkey |
|
|
+# Author: Eric AUGE <eau@phear.org> |
|
|
+# |
|
|
+# Based on the proposal of : Mark Ruijter |
|
|
+# |
|
|
+ |
|
|
+ |
|
|
+# octetString SYNTAX |
|
|
+attributetype ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey' |
|
|
+ DESC 'MANDATORY: OpenSSH Public key' |
|
|
+ EQUALITY octetStringMatch |
|
|
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) |
|
|
+ |
|
|
+# printableString SYNTAX yes|no |
|
|
+objectclass ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY |
|
|
+ DESC 'MANDATORY: OpenSSH LPK objectclass' |
|
|
+ MUST ( sshPublicKey $ uid ) |
|
|
+ ) |
|
|
Index: openssh-lpk_sun.schema |
|
|
--- openssh-lpk_sun.schema.orig 2019-10-09 23:03:45.288920000 +0200 |
|
|
+++ openssh-lpk_sun.schema 2019-10-09 23:03:45.288804000 +0200 |
|
|
@@ -0,0 +1,21 @@ |
|
|
+# |
|
|
+# LDAP Public Key Patch schema for use with openssh-ldappubkey |
|
|
+# Author: Eric AUGE <eau@phear.org> |
|
|
+# |
|
|
+# Schema for Sun Directory Server. |
|
|
+# Based on the original schema, modified by Stefan Fischer. |
|
|
+# |
|
|
+ |
|
|
+dn: cn=schema |
|
|
+ |
|
|
+# octetString SYNTAX |
|
|
+attributeTypes: ( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey' |
|
|
+ DESC 'MANDATORY: OpenSSH Public key' |
|
|
+ EQUALITY octetStringMatch |
|
|
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 ) |
|
|
+ |
|
|
+# printableString SYNTAX yes|no |
|
|
+objectClasses: ( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' SUP top AUXILIARY |
|
|
+ DESC 'MANDATORY: OpenSSH LPK objectclass' |
|
|
+ MUST ( sshPublicKey $ uid ) |
|
|
+ ) |
|
|
Index: servconf.c |
|
|
--- servconf.c.orig 2019-10-09 02:31:03.000000000 +0200 |
|
|
+++ servconf.c 2019-10-09 23:03:45.289748000 +0200 |
|
|
@@ -65,6 +65,10 @@ |
|
|
#include "myproposal.h" |
|
|
#include "digest.h" |
|
|
|
|
|
+#ifdef WITH_LDAP_PUBKEY |
|
|
+#include "ldapauth.h" |
|
|
+#endif |
|
|
+ |
|
|
static void add_listen_addr(ServerOptions *, const char *, |
|
|
const char *, int); |
|
|
static void add_one_listen_addr(ServerOptions *, const char *, |
|
|
@@ -143,6 +147,26 @@ |
|
|
options->num_allow_groups = 0; |
|
|
options->num_deny_groups = 0; |
|
|
options->ciphers = NULL; |
|
|
+#ifdef WITH_LDAP_PUBKEY |
|
|
+ /* XXX dirty */ |
|
|
+ options->lpk.ld = NULL; |
|
|
+ options->lpk.on = -1; |
|
|
+ options->lpk.servers = NULL; |
|
|
+ options->lpk.u_basedn = NULL; |
|
|
+ options->lpk.g_basedn = NULL; |
|
|
+ options->lpk.binddn = NULL; |
|
|
+ options->lpk.bindpw = NULL; |
|
|
+ options->lpk.sgroup = NULL; |
|
|
+ options->lpk.filter = NULL; |
|
|
+ options->lpk.fgroup = NULL; |
|
|
+ options->lpk.l_conf = NULL; |
|
|
+ options->lpk.tls = -1; |
|
|
+ options->lpk.b_timeout.tv_sec = -1; |
|
|
+ options->lpk.s_timeout.tv_sec = -1; |
|
|
+ options->lpk.flags = FLAG_EMPTY; |
|
|
+ options->lpk.pub_key_attr = NULL; |
|
|
+ options->lpk.uid_attr = NULL; |
|
|
+#endif |
|
|
options->macs = NULL; |
|
|
options->kex_algorithms = NULL; |
|
|
options->ca_sign_algorithms = NULL; |
|
|
@@ -425,6 +449,36 @@ |
|
|
options->disable_forwarding = 0; |
|
|
if (options->expose_userauth_info == -1) |
|
|
options->expose_userauth_info = 0; |
|
|
+#ifdef WITH_LDAP_PUBKEY |
|
|
+ if (options->lpk.on == -1) |
|
|
+ options->lpk.on = _DEFAULT_LPK_ON; |
|
|
+ if (options->lpk.servers == NULL) |
|
|
+ options->lpk.servers = _DEFAULT_LPK_SERVERS; |
|
|
+ if (options->lpk.u_basedn == NULL) |
|
|
+ options->lpk.u_basedn = _DEFAULT_LPK_UDN; |
|
|
+ if (options->lpk.g_basedn == NULL) |
|
|
+ options->lpk.g_basedn = _DEFAULT_LPK_GDN; |
|
|
+ if (options->lpk.uid_attr == NULL) |
|
|
+ options->lpk.uid_attr = _DEFAULT_LPK_UID; |
|
|
+ if (options->lpk.binddn == NULL) |
|
|
+ options->lpk.binddn = _DEFAULT_LPK_BINDDN; |
|
|
+ if (options->lpk.bindpw == NULL) |
|
|
+ options->lpk.bindpw = _DEFAULT_LPK_BINDPW; |
|
|
+ if (options->lpk.sgroup == NULL) |
|
|
+ options->lpk.sgroup = _DEFAULT_LPK_SGROUP; |
|
|
+ if (options->lpk.filter == NULL) |
|
|
+ options->lpk.filter = _DEFAULT_LPK_FILTER; |
|
|
+ if (options->lpk.tls == -1) |
|
|
+ options->lpk.tls = _DEFAULT_LPK_TLS; |
|
|
+ if (options->lpk.b_timeout.tv_sec == -1) |
|
|
+ options->lpk.b_timeout.tv_sec = _DEFAULT_LPK_BTIMEOUT; |
|
|
+ if (options->lpk.s_timeout.tv_sec == -1) |
|
|
+ options->lpk.s_timeout.tv_sec = _DEFAULT_LPK_STIMEOUT; |
|
|
+ if (options->lpk.l_conf == NULL) |
|
|
+ options->lpk.l_conf = _DEFAULT_LPK_LDP; |
|
|
+ if (options->lpk.pub_key_attr == NULL) |
|
|
+ options->lpk.pub_key_attr = _DEFAULT_LPK_PUB; |
|
|
+#endif |
|
|
|
|
|
assemble_algorithms(options); |
|
|
|
|
|
@@ -511,6 +565,12 @@ |
|
|
sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding, |
|
|
sExposeAuthInfo, sRDomain, |
|
|
sDeprecated, sIgnore, sUnsupported |
|
|
+#ifdef WITH_LDAP_PUBKEY |
|
|
+ ,sLdapPublickey, sLdapServers, sLdapUserDN |
|
|
+ ,sLdapGroupDN, sBindDN, sBindPw, sUIDAttribute, sMyGroup |
|
|
+ ,sLdapFilter, sForceTLS, sBindTimeout |
|
|
+ ,sSearchTimeout, sLdapConf ,sLpkPubKeyAttr |
|
|
+#endif |
|
|
} ServerOpCodes; |
|
|
|
|
|
#define SSHCFG_GLOBAL 0x01 /* allowed in main section of sshd_config */ |
|
|
@@ -627,6 +687,22 @@ |
|
|
{ "clientalivecountmax", sClientAliveCountMax, SSHCFG_ALL }, |
|
|
{ "authorizedkeysfile", sAuthorizedKeysFile, SSHCFG_ALL }, |
|
|
{ "authorizedkeysfile2", sDeprecated, SSHCFG_ALL }, |
|
|
+#ifdef WITH_LDAP_PUBKEY |
|
|
+ { _DEFAULT_LPK_TOKEN, sLdapPublickey, SSHCFG_GLOBAL }, |
|
|
+ { _DEFAULT_SRV_TOKEN, sLdapServers, SSHCFG_GLOBAL }, |
|
|
+ { _DEFAULT_USR_TOKEN, sLdapUserDN, SSHCFG_GLOBAL }, |
|
|
+ { _DEFAULT_GRP_TOKEN, sLdapGroupDN, SSHCFG_GLOBAL }, |
|
|
+ { _DEFAULT_UID_TOKEN, sUIDAttribute, SSHCFG_GLOBAL }, |
|
|
+ { _DEFAULT_BDN_TOKEN, sBindDN, SSHCFG_GLOBAL }, |
|
|
+ { _DEFAULT_BPW_TOKEN, sBindPw, SSHCFG_GLOBAL }, |
|
|
+ { _DEFAULT_MYG_TOKEN, sMyGroup, SSHCFG_GLOBAL }, |
|
|
+ { _DEFAULT_FIL_TOKEN, sLdapFilter, SSHCFG_GLOBAL }, |
|
|
+ { _DEFAULT_TLS_TOKEN, sForceTLS, SSHCFG_GLOBAL }, |
|
|
+ { _DEFAULT_BTI_TOKEN, sBindTimeout, SSHCFG_GLOBAL }, |
|
|
+ { _DEFAULT_STI_TOKEN, sSearchTimeout, SSHCFG_GLOBAL }, |
|
|
+ { _DEFAULT_LDP_TOKEN, sLdapConf, SSHCFG_GLOBAL }, |
|
|
+ { "LpkPubKeyAttr", sLpkPubKeyAttr, SSHCFG_GLOBAL }, |
|
|
+#endif |
|
|
{ "useprivilegeseparation", sDeprecated, SSHCFG_GLOBAL}, |
|
|
{ "acceptenv", sAcceptEnv, SSHCFG_ALL }, |
|
|
{ "setenv", sSetEnv, SSHCFG_ALL }, |
|
|
@@ -1220,6 +1296,7 @@ |
|
|
int cmdline = 0, *intptr, value, value2, n, port; |
|
|
SyslogFacility *log_facility_ptr; |
|
|
LogLevel *log_level_ptr; |
|
|
+ unsigned long lvalue, *longptr; |
|
|
ServerOpCodes opcode; |
|
|
u_int i, *uintptr, uvalue, flags = 0; |
|
|
size_t len; |
|
|
@@ -1245,6 +1322,7 @@ |
|
|
if (!arg || !*arg || *arg == '#') |
|
|
return 0; |
|
|
intptr = NULL; |
|
|
+ longptr = NULL; |
|
|
charptr = NULL; |
|
|
opcode = parse_token(arg, filename, linenum, &flags); |
|
|
|
|
|
@@ -2183,6 +2261,133 @@ |
|
|
while (arg) |
|
|
arg = strdelim(&cp); |
|
|
break; |
|
|
+#ifdef WITH_LDAP_PUBKEY |
|
|
+ case sLdapPublickey: |
|
|
+ intptr = &options->lpk.on; |
|
|
+ goto parse_flag; |
|
|
+ case sLdapServers: |
|
|
+ /* arg = strdelim(&cp); */ |
|
|
+ p = line; |
|
|
+ while(*p++); |
|
|
+ arg = p; |
|
|
+ if (!arg || *arg == '\0') |
|
|
+ fatal("%s line %d: missing ldap server",filename,linenum); |
|
|
+ arg[strlen(arg)] = '\0'; |
|
|
+ if ((options->lpk.servers = ldap_parse_servers(arg)) == NULL) |
|
|
+ fatal("%s line %d: error in ldap servers", filename, linenum); |
|
|
+ memset(arg,0,strlen(arg)); |
|
|
+ break; |
|
|
+ case sLdapUserDN: |
|
|
+ arg = cp; |
|
|
+ if (!arg || *arg == '\0') |
|
|
+ fatal("%s line %d: missing ldap server",filename,linenum); |
|
|
+ arg[strlen(arg)] = '\0'; |
|
|
+ options->lpk.u_basedn = xstrdup(arg); |
|
|
+ memset(arg,0,strlen(arg)); |
|
|
+ break; |
|
|
+ case sLdapGroupDN: |
|
|
+ arg = cp; |
|
|
+ if (!arg || *arg == '\0') |
|
|
+ fatal("%s line %d: missing ldap server",filename,linenum); |
|
|
+ arg[strlen(arg)] = '\0'; |
|
|
+ options->lpk.g_basedn = xstrdup(arg); |
|
|
+ memset(arg,0,strlen(arg)); |
|
|
+ break; |
|
|
+ case sUIDAttribute: |
|
|
+ arg = cp; |
|
|
+ if (!arg || *arg == '\0') |
|
|
+ fatal("%s line %d: missing uid_attr",filename,linenum); |
|
|
+ arg[strlen(arg)] = '\0'; |
|
|
+ options->lpk.uid_attr = xstrdup(arg); |
|
|
+ memset(arg,0,strlen(arg)); |
|
|
+ break; |
|
|
+ case sBindDN: |
|
|
+ arg = cp; |
|
|
+ if (!arg || *arg == '\0') |
|
|
+ fatal("%s line %d: missing binddn",filename,linenum); |
|
|
+ arg[strlen(arg)] = '\0'; |
|
|
+ options->lpk.binddn = xstrdup(arg); |
|
|
+ memset(arg,0,strlen(arg)); |
|
|
+ break; |
|
|
+ case sBindPw: |
|
|
+ arg = cp; |
|
|
+ if (!arg || *arg == '\0') |
|
|
+ fatal("%s line %d: missing bindpw",filename,linenum); |
|
|
+ arg[strlen(arg)] = '\0'; |
|
|
+ options->lpk.bindpw = xstrdup(arg); |
|
|
+ memset(arg,0,strlen(arg)); |
|
|
+ break; |
|
|
+ case sMyGroup: |
|
|
+ arg = cp; |
|
|
+ if (!arg || *arg == '\0') |
|
|
+ fatal("%s line %d: missing groupname",filename, linenum); |
|
|
+ arg[strlen(arg)] = '\0'; |
|
|
+ options->lpk.sgroup = xstrdup(arg); |
|
|
+ if (options->lpk.sgroup) |
|
|
+ options->lpk.fgroup = ldap_parse_groups(options->lpk.sgroup); |
|
|
+ memset(arg,0,strlen(arg)); |
|
|
+ break; |
|
|
+ case sLdapFilter: |
|
|
+ arg = cp; |
|
|
+ if (!arg || *arg == '\0') |
|
|
+ fatal("%s line %d: missing filter",filename, linenum); |
|
|
+ arg[strlen(arg)] = '\0'; |
|
|
+ options->lpk.filter = xstrdup(arg); |
|
|
+ memset(arg,0,strlen(arg)); |
|
|
+ break; |
|
|
+ case sForceTLS: |
|
|
+ intptr = &options->lpk.tls; |
|
|
+ arg = strdelim(&cp); |
|
|
+ if (!arg || *arg == '\0') |
|
|
+ fatal("%s line %d: missing yes/no argument.", |
|
|
+ filename, linenum); |
|
|
+ value = 0; /* silence compiler */ |
|
|
+ if (strcmp(arg, "yes") == 0) |
|
|
+ value = 1; |
|
|
+ else if (strcmp(arg, "no") == 0) |
|
|
+ value = 0; |
|
|
+ else if (strcmp(arg, "try") == 0) |
|
|
+ value = -1; |
|
|
+ else |
|
|
+ fatal("%s line %d: Bad yes/no argument: %s", |
|
|
+ filename, linenum, arg); |
|
|
+ if (*intptr == -1) |
|
|
+ *intptr = value; |
|
|
+ break; |
|
|
+ case sBindTimeout: |
|
|
+ longptr = (unsigned long *) &options->lpk.b_timeout.tv_sec; |
|
|
+parse_ulong: |
|
|
+ arg = strdelim(&cp); |
|
|
+ if (!arg || *arg == '\0') |
|
|
+ fatal("%s line %d: missing integer value.", |
|
|
+ filename, linenum); |
|
|
+ lvalue = atol(arg); |
|
|
+ if (*activep && *longptr == -1) |
|
|
+ *longptr = lvalue; |
|
|
+ break; |
|
|
+ |
|
|
+ case sSearchTimeout: |
|
|
+ longptr = (unsigned long *) &options->lpk.s_timeout.tv_sec; |
|
|
+ goto parse_ulong; |
|
|
+ break; |
|
|
+ case sLdapConf: |
|
|
+ arg = cp; |
|
|
+ if (!arg || *arg == '\0') |
|
|
+ fatal("%s line %d: missing LpkLdapConf", filename, linenum); |
|
|
+ arg[strlen(arg)] = '\0'; |
|
|
+ options->lpk.l_conf = xstrdup(arg); |
|
|
+ memset(arg, 0, strlen(arg)); |
|
|
+ break; |
|
|
+ case sLpkPubKeyAttr: |
|
|
+ arg = cp; |
|
|
+ if (!arg || *arg == '\0') |
|
|
+ fatal("%s line %d: missing pubkeyattr",filename,linenum); |
|
|
+ arg[strlen(arg)] = '\0'; |
|
|
+ options->lpk.pub_key_attr = xstrdup(arg); |
|
|
+ memset(arg,0,strlen(arg)); |
|
|
+ break; |
|
|
+ |
|
|
+#endif |
|
|
|
|
|
default: |
|
|
fatal("%s line %d: Missing handler for opcode %s (%d)", |
|
|
Index: servconf.h |
|
|
--- servconf.h.orig 2019-10-09 02:31:03.000000000 +0200 |
|
|
+++ servconf.h 2019-10-09 23:03:45.290191000 +0200 |
|
|
@@ -16,6 +16,10 @@ |
|
|
#ifndef SERVCONF_H |
|
|
#define SERVCONF_H |
|
|
|
|
|
+#ifdef WITH_LDAP_PUBKEY |
|
|
+#include "ldapauth.h" |
|
|
+#endif |
|
|
+ |
|
|
#define MAX_PORTS 256 /* Max # ports. */ |
|
|
|
|
|
#define MAX_SUBSYSTEMS 256 /* Max # subsystems. */ |
|
|
@@ -185,6 +189,9 @@ |
|
|
int use_pam; /* Enable auth via PAM */ |
|
|
|
|
|
int permit_tun; |
|
|
+#ifdef WITH_LDAP_PUBKEY |
|
|
+ ldap_opt_t lpk; |
|
|
+#endif |
|
|
|
|
|
char **permitted_opens; /* May also be one of PERMITOPEN_* */ |
|
|
u_int num_permitted_opens; |
|
|
Index: sshd.c |
|
|
--- sshd.c.orig 2019-10-09 02:31:03.000000000 +0200 |
|
|
+++ sshd.c 2019-10-09 23:03:45.290791000 +0200 |
|
|
@@ -129,6 +129,10 @@ |
|
|
#define REEXEC_CONFIG_PASS_FD (STDERR_FILENO + 3) |
|
|
#define REEXEC_MIN_FREE_FD (STDERR_FILENO + 4) |
|
|
|
|
|
+#ifdef WITH_LDAP_PUBKEY |
|
|
+#include "ldapauth.h" |
|
|
+#endif |
|
|
+ |
|
|
extern char *__progname; |
|
|
|
|
|
/* Server configuration options. */ |
|
|
@@ -1675,6 +1679,17 @@ |
|
|
exit(1); |
|
|
} |
|
|
|
|
|
+#ifdef WITH_LDAP_PUBKEY |
|
|
+ /* ldap_options_print(&options.lpk); */ |
|
|
+ /* XXX initialize/check ldap connection and set *LD */ |
|
|
+ if (options.lpk.on) { |
|
|
+ if (options.lpk.l_conf && (ldap_parse_lconf(&options.lpk) < 0) ) |
|
|
+ error("[LDAP] could not parse %s", options.lpk.l_conf); |
|
|
+ if (ldap_connect(&options.lpk) < 0) |
|
|
+ error("[LDAP] could not initialize ldap connection"); |
|
|
+ } |
|
|
+#endif |
|
|
+ |
|
|
debug("sshd version %s, %s", SSH_VERSION, |
|
|
#ifdef WITH_OPENSSL |
|
|
OpenSSL_version(OPENSSL_VERSION) |
|
|
Index: sshd_config.5 |
|
|
--- sshd_config.5.orig 2019-10-09 02:31:03.000000000 +0200 |
|
|
+++ sshd_config.5 2019-10-09 23:03:45.291330000 +0200 |
|
|
@@ -1717,6 +1717,62 @@ |
|
|
to not use one. |
|
|
The default is |
|
|
.Pa /usr/X11R6/bin/xauth . |
|
|
+.It Cm UseLPK |
|
|
+Specifies whether LDAP public key retrieval must be used or not. It allow |
|
|
+an easy centralisation of public keys within an LDAP directory. The argument must be |
|
|
+.Dq yes |
|
|
+or |
|
|
+.Dq no . |
|
|
+.It Cm LpkLdapConf |
|
|
+Specifies whether LDAP Public keys should parse the specified ldap.conf file |
|
|
+instead of sshd_config Tokens. The argument must be a valid path to an ldap.conf |
|
|
+file like |
|
|
+.Pa /etc/ldap.conf |
|
|
+.It Cm LpkServers |
|
|
+Specifies LDAP one or more [:space:] separated server's url the following form may be used: |
|
|
+.Pp |
|
|
+LpkServers ldaps://127.0.0.1 ldap://127.0.0.2 ldap://127.0.0.3 |
|
|
+.It Cm LpkUserDN |
|
|
+Specifies the LDAP user DN. |
|
|
+.Pp |
|
|
+LpkUserDN ou=users,dc=phear,dc=org |
|
|
+.It Cm LpkGroupDN |
|
|
+Specifies the LDAP groups DN. |
|
|
+.Pp |
|
|
+LpkGroupDN ou=groups,dc=phear,dc=org |
|
|
+.It Cm LpkBindDN |
|
|
+Specifies the LDAP bind DN to use if necessary. |
|
|
+.Pp |
|
|
+LpkBindDN cn=Manager,dc=phear,dc=org |
|
|
+.It Cm LpkBindPw |
|
|
+Specifies the LDAP bind credential. |
|
|
+.Pp |
|
|
+LpkBindPw secret |
|
|
+.It Cm LpkServerGroup |
|
|
+Specifies one or more [:space:] separated group the server is part of. |
|
|
+.Pp |
|
|
+LpkServerGroup unix mail prod |
|
|
+.It Cm LpkFilter |
|
|
+Specifies an additional LDAP filter to use for finding SSH keys |
|
|
+.Pp |
|
|
+LpkFilter (hostAccess=master.phear.org) |
|
|
+.It Cm LpkForceTLS |
|
|
+Specifies if the LDAP server connection must be tried, forced or not used. The argument must be |
|
|
+.Dq yes |
|
|
+or |
|
|
+.Dq no |
|
|
+or |
|
|
+.Dq try . |
|
|
+.It Cm LpkSearchTimelimit |
|
|
+Sepcifies the search time limit before the search is considered over. value is |
|
|
+in seconds. |
|
|
+.Pp |
|
|
+LpkSearchTimelimit 3 |
|
|
+.It Cm LpkBindTimelimit |
|
|
+Sepcifies the bind time limit before the connection is considered dead. value is |
|
|
+in seconds. |
|
|
+.Pp |
|
|
+LpkBindTimelimit 3 |
|
|
.El |
|
|
.Sh TIME FORMATS |
|
|
.Xr sshd 8 |
|
|
Index: sshd_config |
|
|
--- sshd_config.orig 2019-10-09 02:31:03.000000000 +0200 |
|
|
+++ sshd_config 2019-10-09 23:03:45.291639000 +0200 |
|
|
@@ -105,6 +105,22 @@ |
|
|
# no default banner path |
|
|
#Banner none |
|
|
|
|
|
+# here are the new patched ldap related tokens |
|
|
+# entries in your LDAP must have posixAccount & ldapPublicKey objectclass |
|
|
+#UseLPK yes |
|
|
+#LpkLdapConf /etc/ldap.conf |
|
|
+#LpkServers ldap://10.1.7.1/ ldap://10.1.7.2/ |
|
|
+#LpkUserDN ou=users,dc=phear,dc=org |
|
|
+#LpkGroupDN ou=groups,dc=phear,dc=org |
|
|
+#LpkBindDN cn=Manager,dc=phear,dc=org |
|
|
+#LpkBindPw secret |
|
|
+#LpkServerGroup mail |
|
|
+#LpkFilter (hostAccess=master.phear.org) |
|
|
+#LpkForceTLS no |
|
|
+#LpkSearchTimelimit 3 |
|
|
+#LpkBindTimelimit 3 |
|
|
+#LpkPubKeyAttr sshPublicKey |
|
|
+ |
|
|
# override default of no subsystems |
|
|
Subsystem sftp /usr/libexec/sftp-server |
|
|
|
|
|
|