Hi all,

This issue is happening on both :
* debian etch   openvpn 2.0.9-4etch1  libpam-ldap 180-1.7
* debian lenny openvpn 2.1~rc11-1  libpam-ldap 184-4.2

Issue is only happening when LDAP is used with TLS support. On every
authentication, a file handle to /dev/urandom is created but never
released even after the dynamic library was closed with dlclose .

>From
http://openvpn.net/index.php/open-source/documentation/change-log/71-21-change-log.html
 :

        * auth-pam change:  link with -lpam rather than dlopen (Roy
        Marples).

so it seems that some changes were done to the auth backend, but still
the same issue is happeing. 




Because the handle to /dev/urandom is never released, after some times
the service had been running, users will fail to authentication because
the backend is not able to open new file handles on /dev/urandom.
In [4] or [5] you can see how the number of opened /dev/urandom files
increase while running a script that fails to authenticate as a wrong
username/password were given.

So, basically, an authorized user could kindda DoS the service by
providing fake user/password .


the openvpn logs will output when the issue happens:


        Apr 15 08:45:40 myhost openvpnconf[6581]: src.ip:srcport CRL
        CHECK
        OK: 
/C=county/ST=state/L=location/O=organisation/CN=commun.name/emailAddress=em...@example.com
        Apr 15 08:45:40 myhost openvpnconf[6581]: src.ip:srcport VERIFY
        OK:
        depth=1, 
/C=county/ST=state/L=location/O=organisation/CN=commun.name/emailAddress=em...@example.com
        Apr 15 08:45:40 myhost openvpnconf[6581]: src.ip:srcport CRL
        CHECK
        OK: 
/C=country/ST=state/O=organisation/CN=commun_name/emailAddress=em...@example.com
        Apr 15 08:45:40 myhost openvpnconf[6581]: src.ip:srcport VERIFY
        OK:
        depth=0, 
/C=country/ST=state/O=organisation/CN=commun_name/emailAddress=em...@example.com
        Apr 15 08:45:41 myhost openvpn[6574]: PAM unable to
        dlopen(/lib/security/pam_ldap.so)
        Apr 15 08:45:41 myhost openvpn[6574]: PAM
        [dlerror: /lib/security/pam_ldap.so: cannot open shared object
        file: Too many open files]
        Apr 15 08:45:41 myhost openvpn[6574]: PAM adding faulty
        module: /lib/security/pam_ldap.so
        Apr 15 08:45:41 myhost openvpnconf[6581]: src.ip:srcport
        PLUGIN_CALL:
        POST /usr/lib/openvpn/openvpn-auth-pam.so/PLUGIN_AUTH_USER_PASS_VERIFY 
status=1
        Apr 15 08:45:41 myhost openvpnconf[6581]: src.ip:srcport
        PLUGIN_CALL: plugin function PLUGIN_AUTH_USER_PASS_VERIFY failed
        with status 1: /usr/lib/openvpn/openvpn-auth-pam.so
        Apr 15 08:45:41 myhost openvpnconf[6581]: src.ip:srcport TLS
        Auth Error: Auth Username/Password verification failed for peer
        Apr 15 08:45:44 myhost openvpnconf[6581]: src.ip:srcport Control
        Channel: TLSv1, cipher TLSv1/SSLv3 DHE-RSA-AES256-SHA, 1024 bit
        RSA
        Apr 15 08:45:44 myhost openvpnconf[6581]: src.ip:srcport
        [common_name] Peer Connection Initiated with src.ip:srcport
        Apr 15 08:45:44 myhost openvpnconf[6581]: src.ip:srcport PUSH:
        Received control message: 'PUSH_REQUEST'
        Apr 15 08:45:44 myhost openvpnconf[6581]: src.ip:srcport SENT
        CONTROL [common_name]: 'AUTH_FAILED' (status=1)



How to Reproduce:
==========
Here is my openvpn auth set up:

        $ cat /etc/pam.d/openvpn 
        account required pam_ldap.so config=/etc/openvpn/pam_ldap.conf
        auth  required pam_ldap.so config=/etc/openvpn/pam_ldap.conf
        password required pam_ldap.so config=/etc/openvpn/pam_ldap.conf
        session required pam_ldap.so config=/etc/openvpn/pam_ldap.conf

        $ grep -v '^#' /etc/openvpn/pam_ldap.conf  | grep -v '^$'
        base ou=Users,dc=somain,dc=com
        uri ldap://ldap.domain.com
        ldap_version 3
        pam_login_attribute uid
        pam_groupdn cn=vpn,ou=Groups,dc=domain,dc=com
        pam_member_attribute member
        pam_password crypt
        ssl start_tls
        tls_checkpeer no


* check number of urandom file handle opened:

        $ sudo lsof -p `ps -u root | grep openvpn | cut -f1 -d' '` |
        grep urandom | wc -l

* connect to the service and confirm that there is one more handle
opened.
* disconnect from service. file handle is still there.


Workaround:
=======
A quick workaround is to restart openvpn service once everyday ( might
depend on the service usage though).


Some attempt to understand the issue:
=======================
In the attached program, it seems that the LDAP ressource is not fully
released after calling ldap_unbind .

Looping over the connection/disconnection proves that the ldp pointer is
allocated at the same location, so I wonder if in that case, the LDAP
resource is re-used over and over (thus reusing the same /dev/urandom
file handle) while in the dlopen/dlclose case a fully new allocated TLS
env is created.

A while back, I logged [1] and [2] against openldap and pam_ldap as I
thought issue could have been in the underlying libs. But lately, I have
set up VsFTPd with pam-ldap+TLS auth and the issue is not happening in
that implementation although the settings are pretty similar.
[3] seems to contain the auth part in vsf_sysdep_check_auth() 'round
line 323 .

Could that be of any use? Would that solve this issue?

Cheers,

chantra

[1] http://www.openldap.org/lists/openldap-software/200904/msg00072.html
[2] http://bugzilla.padl.com/show_bug.cgi?id=395
[3]
ftp://vsftpd.beasts.org/users/cevans/untar/vsftpd-2.2.0/sysdeputil.c 
[4] http://www.megaupload.com/?d=94M1OYL0 (.ogg )
[5] http://www.megaupload.com/?d=E2NMD2I6   (.avi )


!DSPAM:4a9514d890406079588618!
/*
* compile with
* gcc -o start_tls start_tls.c -lldap
* ./start_tls ldap://myldaphost 10
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <ldap.h>
#include <unistd.h>
#include <sys/types.h>




void
ldap_pvt_tls_destroy( void );

void usage(const char *name){
  fprintf(stderr, "USAGE: %s ldap://host [N]\n\tN:\tNumber of connection to create (default: 1)\n", name);
}

int main(int argc, char **argv){
  char uri[BUFSIZ];
  char cmdline[BUFSIZ];
  LDAP *ldp;
  int rc;
  int ldap_version = 3;
  LDAPControl *serverctrls;
  LDAPControl *clientctrls;
  int nbconn = 1;
  int i;

  if(argc < 2){
    usage(argv[0]);
    exit(1);
  }
  if( argc == 3 ){
    nbconn = atoi(argv[2]);
  }

  strcpy(uri, argv[1]);
  sprintf(cmdline, "sudo lsof -p %d | grep random", getpid() );

  for(i = 0; i < nbconn; i++){
    ldp = NULL;
    serverctrls = clientctrls = NULL;
    fprintf(stdout, "\n\n<<<<<<<<<<<< Connection attempt #%d   >>>>>>>>>\n\n", i );
    rc = ldap_initialize(&ldp, uri);
    if(rc != LDAP_SUCCESS){
      fprintf(stderr, "ERROR: ldap_initialize returned (%d) \"%s\" : %s\n", rc, ldap_err2string(rc), strerror(errno));
      exit(1);
    }
    rc = ldap_set_option(ldp, LDAP_OPT_PROTOCOL_VERSION, &ldap_version);
    if(rc != LDAP_OPT_SUCCESS){
      fprintf(stderr, "ERROR: ldap_set_option returned (%d) \"%s\"\n", rc, ldap_err2string(rc));
      exit(1);
    }


    fprintf(stdout, "\t\t******\n");
    fprintf(stdout, "opened urandom files before ldap_start_tls_s:\n");
    system(cmdline);
    fprintf(stdout, "\t\t******\n");
    rc = ldap_start_tls_s(ldp, NULL, NULL);//&serverctrls, &clientctrls);
    if(rc != LDAP_SUCCESS){
      fprintf(stderr, "ERROR: ldap_start_tls_s returned (%d) \"%s\"\n", rc, ldap_err2string(rc));
      exit(1);
    }
    fprintf(stdout, "Successfully started ldap_start_tls_s\n");

    fprintf(stdout, "\tLDAP pointer\t%p\n", ldp);

    fprintf(stdout, "\t\t******\n");
    fprintf(stdout, "opened urandom files after ldap_start_tls_s:\n");
    system(cmdline);
    fprintf(stdout, "\t\t******\n");

    //rc = ldap_unbind_ext_s(ldp, &serverctrls, &clientctrls);
    rc = ldap_unbind_s(ldp);
    if( rc != LDAP_SUCCESS ){
      fprintf(stderr, "ERROR: ldap_unbind_ext_s returned (%d) \"%s\"\n", rc, ldap_err2string(rc));
      exit(1);
    }
    fprintf( stdout, "Successfully unbound\n" );
    fprintf(stdout, "\t\t******\n");
    fprintf(stdout, "opened urandom files after ldap_unbind_ext_s:\n");
    system(cmdline);
    fprintf(stdout, "\t\t******\n");
  }
/*
  no effect
  ldap_pvt_tls_destroy();
*/
  fprintf(stdout, "%s\n", cmdline);
  sleep(100);
  exit(0);
}

Reply via email to