[tpop3d-discuss] ldap virtual auth plugin : near release

Prune prune at lecentre.net
Mon, 18 Feb 2002 17:08:52 +0100


This is a multi-part message in MIME format.
--------------020907050004070400050402
Content-Type: multipart/alternative;
 boundary="------------080202040107010308000707"


--------------080202040107010308000707
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit

re,

Chris Lightfoot wrote:

>On Mon, Feb 18, 2002 at 03:44:11PM +0100, Prune wrote:
>
>>So.....
>>the plugins is finaly finished. I just need to clear things like logs 
>>and be sure no memory leaks stays around.
>>I added many things in the configuration file, so everything is 
>>customisable :
>>
>> "auth-ldap-username" : manager username to bind ldap
>> "auth-ldap-password" : manager's password
>> "auth-ldap-mail-user" : predefined username to chown when fork
>> "auth-ldap-mail-group" : predefined group to chgrp to when fork
>> "auth-ldap-filter-attr" : attribut to compare to the mail account
>> "auth-ldap-filter-addon" : some more attributes a user would like to 
>>                            add to the filter
>> "auth-ldap-url" : ldap url formated string giving host, port and base 
>>                   ldap server
>> "auth-ldap-use-TLS" : on/off, activate TLS (encryption of data 
>>                       between the pop and the ldap server
>> "auth-ldap-mailbox-attr" : ldap attribut to return as mailbox path 
>>                            (default to "maildrop", but must be changed to
>>                            "mailbox" according to RFC's)
>> "auth-ldap-uid-attr" : ldap attribut to return as uid when pop3d 
>>                        forks (if not define in "auth-ldap-mail-user")
>> "auth-ldap-gid-attr" : ldap attribut to return as gid when pop3d 
>>                        forks (if not define in "auth-ldap-mail-group" )
>>
>>
>>What it does :
>>
>>-do auth agains an ldap server
>>-get the location of the mailbox (or maildir) from LDAP
>>-get the uid/gid of the mailbox from LDAP
>>
>
>OK, this all looks sensible. I take it that the way that
>authentication is done is defined by LDAP, so that you
>don't have to retrieve a password from the directory
>explicitly?
>
right. That's why it's a good thing to use TLS, so data from the client 
to LDAP are encrypted overt the network.
Ldap has a special way to authenticate users with a methode called 'bind'.
First you connect to the server.
Then you 'bind' as manager (privilegied read user).
you search for the user and his attributes
once you have all this, you can 'bind' again as the user.
the bind operation give you success or fail.
You never get the password and you never have to challenge it.

>
>
>>what does it needs : openldap 2.x (not tested with any other ldap SDK). 
>>Your openldap must support TLS if you want to be able to use this function.
>>
>>how it works :
>>-the way tpop3d deals with mailbox types is not the same postfix does. 
>>This plugin have been developped for using tpop3d with postfix :
>>   postifx virtual delivery agent gets the mailbox path from ldap like 
>>:  "/var/mail/virtuals/user1/"
>>   the / at the end means it is a maildir format.
>>   tpop3d wanted it like "maildir:/var/mail/virtuals/user1"
>>  
>>   As the mysql plugin force to "bsd" mailbox, I chosed to force my 
>>ldap plugin to check the last char of the mailbox path.
>>   The plugin so work in postfix's way.
>>
>
>Hmm. Better, I think, to stat the path given and choose a
>mailbox type based upon whether it's a file or a
>directory. Is the model used by postfix typical of how
>other MTAs work?
>
... no clue. I think only qmail and postfix are maildir aware... of 
course, courier, but I don't know how maildrop do to determine if it's 
maildir or mailbox.

I would personaly do it the postfix way, as I want to run it with 
postfix. The only problem is when others mailbox format will show up. 
using name:path is the best thing, but would require me to have 2 entry 
in ldap, one for postfix and one for the popper...
We could add a check :
    -see if the mailbox name begin with "something:/"   
    -then see if there are / at the end.
    -else use default...

doing a stat is not good either, if some new mailbox format shoes up....
Doing the postfix way is good now. let's go with it, and search around...

>>-the apop function is not (yet) integrated. In fact it seems to be the 
>>same as the normal pop. Am I right ?
>>
>
>Not quite. For APOP you need to be able to retrieve a
>plaintext password which is used in a challenge-response
>dialogue. If you can't get a plaintext password out of the
>directory, then you can't do APOP, but this is not a very
>serious problem as APOP is not widely used and there are
>better ways to secure the POP3 protocol.
>
storing a plaintext password is not a good idea. As LDAP help us not to 
do this kind of things, I just propose to not include apop compatibility 
with the ldap plugin.
ideas ?

>
>
>>-the server connects only once. If the connection ends up, it will be 
>>re-opened next time someone try to authenticate.
>>
>
>OK.
>
>>   -I'll check to see how to do asynchronous searches, so multiple 
>>requests could be done at a time.
>>
>
>tpop3d is not organised in such a way as to make this
>easy, so it's probably not worth doing.
>
ok. maybe for tpop3D-2.0 !! :)

>>-the server can only use one server. I would like to add support for 
>>multi server and failover.
>>
>
>That's sensible.
>
 ?
that's just easy. in the init step, we check the conf for multiple 
server defined, and we put data to connect to then in a struct.
When the plugins connect (and fail) it test the next one...
In fact, I was speaking of pop server connecting to many LDAP servers ;)

>
>
>>Finaly :
>>
>>
>>-who would like to test ?
>>-who (chris ?) will plainly add my module to the distrib ?
>>   as for now I can give auth_ldap.c and auth_ldap.h. we need to modify 
>>the makefile to add -I/-L  and -lldap for openldap libs.
>>
>>For testing, at the moment, files still name "auth_mysql.c", Makefile is 
>>changed by hand, but everything works fine.
>>
>>who want to integrate it to the actual pre-release ?
>>
>
>If you send me the code, I will integrate it into a new
>pre-release.
>

here are the files. I'll have to change things for logging to be 
more.... hummm.... better.
some obvious and nasty debug is laying around....
and maybe the code is not exactly formated as you expect (tabs, spaces...)


2 files :

-auth_ldap.h
-auth_ldap.c

here is what you need for cfgdirectives.c :

#ifdef AUTH_MYSQL
    /* auth-mysql options */
   "auth-mysql-enable",
   "auth-ldap-username",
   "auth-ldap-password",
   "auth-ldap-mail-user",
   "auth-ldap-mail-group",
   "auth-ldap-filter-attr",
   "auth-ldap-filter-addon",
   "auth-ldap-url",
   "auth-ldap-use-TLS",
   "auth-ldap-mailbox-attr",
   "auth-ldap-uid-attr",
   "auth-ldap-gid-attr",
#endif /* AUTH_MYSQL */

What you'll see : everything is named as auth_mysql's plugin.
I've developped everything based on this plugin.

The first thing to do is... change every MYSQL things to LDAP...
and add LDAP everywhere needed.

code is not really clear yet, but I'm working on this. I maybe also have 
to free some memory some time. just let me know if you find strange things.

>>chris : I would like to know what is the difference between the "home" 
>>and the "mailbox" in a authcontext ? my plugin return the same, as user 
>>are only present in the LDAP, and not in the system's password file....
>>
>
>In this case you probably don't care about the value of
>a->home. This value is used to allow path-specs for
>mailboxes to be relative to user home directories.
>
oki



I also realised that there was a new function for pop-before-smtp
As it's not recommended to write into ldap... it's not really a good 
idea to have a flag there. Any suggestion on how to do it ?

Cheers,

Prune

--------------080202040107010308000707
Content-Type: text/html; charset=us-ascii
Content-Transfer-Encoding: 7bit

<html>
<head>
</head>
<body>
re,<br>
<br>
Chris Lightfoot wrote:<br>
<blockquote type="cite" cite="mid:20020218151300.GA4405@aquila.esc.cam.ac.uk">
  <pre wrap="">On Mon, Feb 18, 2002 at 03:44:11PM +0100, Prune wrote:<br></pre>
  <blockquote type="cite">
    <pre wrap="">So.....<br>the plugins is finaly finished. I just need to clear things like logs <br>and be sure no memory leaks stays around.<br>I added many things in the configuration file, so everything is <br>customisable :<br><br> "auth-ldap-username" : manager username to bind ldap<br> "auth-ldap-password" : manager's password<br> "auth-ldap-mail-user" : predefined username to chown when fork<br> "auth-ldap-mail-group" : predefined group to chgrp to when fork<br> "auth-ldap-filter-attr" : attribut to compare to the mail account<br> "auth-ldap-filter-addon" : some more attributes a user would like to <br>                            add to the filter<br> "auth-ldap-url" : ldap url formated string giving host, port and base <br>                   ldap server<br> "auth-ldap-use-TLS" : on/off, activate TLS (encryption of data <br>                       between the pop and the ldap server<br> "auth-ldap-mailbox-attr" : ldap attribut to return as mailbox path <br>           
                 (default to "maildrop", but must be changed to<br>                            "mailbox" according to RFC's)<br> "auth-ldap-uid-attr" : ldap attribut to return as uid when pop3d <br>                        forks (if not define in "auth-ldap-mail-user")<br> "auth-ldap-gid-attr" : ldap attribut to return as gid when pop3d <br>                        forks (if not define in "auth-ldap-mail-group" )<br><br><br>What it does :<br><br>-do auth agains an ldap server<br>-get the location of the mailbox (or maildir) from LDAP<br>-get the uid/gid of the mailbox from LDAP<br></pre>
    </blockquote>
    <pre wrap=""><!----><br>OK, this all looks sensible. I take it that the way that<br>authentication is done is defined by LDAP, so that you<br>don't have to retrieve a password from the directory<br>explicitly?</pre>
    </blockquote>
right. That's why it's a good thing to use TLS, so data from the client to
LDAP are encrypted overt the network.<br>
Ldap has a special way to authenticate users with a methode called 'bind'.<br>
First you connect to the server.<br>
Then you 'bind' as manager (privilegied read user).<br>
you search for the user and his attributes<br>
once you have all this, you can 'bind' again as the user.<br>
the bind operation give you success or fail.<br>
You never get the password and you never have to challenge it.<br>
    <blockquote type="cite" cite="mid:20020218151300.GA4405@aquila.esc.cam.ac.uk">
      <pre wrap=""><br><br></pre>
      <blockquote type="cite">
        <pre wrap="">what does it needs : openldap 2.x (not tested with any other ldap SDK). <br>Your openldap must support TLS if you want to be able to use this function.<br><br>how it works :<br>-the way tpop3d deals with mailbox types is not the same postfix does. <br>This plugin have been developped for using tpop3d with postfix :<br>   postifx virtual delivery agent gets the mailbox path from ldap like <br>:  "/var/mail/virtuals/user1/"<br>   the / at the end means it is a maildir format.<br>   tpop3d wanted it like "maildir:/var/mail/virtuals/user1"<br>  <br>   As the mysql plugin force to "bsd" mailbox, I chosed to force my <br>ldap plugin to check the last char of the mailbox path.<br>   The plugin so work in postfix's way.<br></pre>
        </blockquote>
        <pre wrap=""><!----><br>Hmm. Better, I think, to stat the path given and choose a<br>mailbox type based upon whether it's a file or a<br>directory. Is the model used by postfix typical of how<br>other MTAs work?</pre>
        </blockquote>
... no clue. I think only qmail and postfix are maildir aware... of course,
courier, but I don't know how maildrop do to determine if it's maildir or
mailbox.<br>
        <br>
I would personaly do it the postfix way, as I want to run it with postfix.
The only problem is when others mailbox format will show up. using name:path
is the best thing, but would require me to have 2 entry in ldap, one for
postfix and one for the popper...<br>
We could add a check :<br>
&nbsp;&nbsp;&nbsp; -see if the mailbox name begin with "something:/" &nbsp;&nbsp; <br>
&nbsp;&nbsp;&nbsp; -then see if there are / at the end.<br>
&nbsp;&nbsp;&nbsp; -else use default...<br>
        <br>
doing a stat is not good either, if some new mailbox format shoes up....<br>
Doing the postfix way is good now. let's go with it, and search around...
        <blockquote type="cite" cite="mid:20020218151300.GA4405@aquila.esc.cam.ac.uk">
          <blockquote type="cite">
            <pre wrap="">-the apop function is not (yet) integrated. In fact it seems to be the <br>same as the normal pop. Am I right ?<br></pre>
            </blockquote>
            <pre wrap=""><!----><br>Not quite. For APOP you need to be able to retrieve a<br>plaintext password which is used in a challenge-response<br>dialogue. If you can't get a plaintext password out of the<br>directory, then you can't do APOP, but this is not a very<br>serious problem as APOP is not widely used and there are<br>better ways to secure the POP3 protocol.</pre>
            </blockquote>
storing a plaintext password is not a good idea. As LDAP help us not to do
this kind of things, I just propose to not include apop compatibility with
the ldap plugin.<br>
ideas ?<br>
            <blockquote type="cite" cite="mid:20020218151300.GA4405@aquila.esc.cam.ac.uk">
              <pre wrap=""><br><br></pre>
              <blockquote type="cite">
                <pre wrap="">-the server connects only once. If the connection ends up, it will be <br>re-opened next time someone try to authenticate.<br></pre>
                </blockquote>
                <pre wrap=""><!----><br>OK.<br><br></pre>
                <blockquote type="cite">
                  <pre wrap="">   -I'll check to see how to do asynchronous searches, so multiple <br>requests could be done at a time.<br></pre>
                  </blockquote>
                  <pre wrap=""><!----><br>tpop3d is not organised in such a way as to make this<br>easy, so it's probably not worth doing.</pre>
                  </blockquote>
ok. maybe for tpop3D-2.0 !! :)
                  <blockquote type="cite" cite="mid:20020218151300.GA4405@aquila.esc.cam.ac.uk">
                    <blockquote type="cite">
                      <pre wrap="">-the server can only use one server. I would like to add support for <br>multi server and failover.<br></pre>
                      </blockquote>
                      <pre wrap=""><!----><br>That's sensible.</pre>
                      </blockquote>
&nbsp;?<br>
that's just easy. in the init step, we check the conf for multiple server
defined, and we put data to connect to then in a struct.<br>
When the plugins connect (and fail) it test the next one...<br>
In fact, I was speaking of pop server connecting to many LDAP servers ;)<br>
                      <blockquote type="cite" cite="mid:20020218151300.GA4405@aquila.esc.cam.ac.uk">
                        <pre wrap=""><br><br></pre>
                        <blockquote type="cite">
                          <pre wrap="">Finaly :<br><br><br>-who would like to test ?<br>-who (chris ?) will plainly add my module to the distrib ?<br>   as for now I can give auth_ldap.c and auth_ldap.h. we need to modify <br>the makefile to add -I/-L  and -lldap for openldap libs.<br><br>For testing, at the moment, files still name "auth_mysql.c", Makefile is <br>changed by hand, but everything works fine.<br><br>who want to integrate it to the actual pre-release ?<br></pre>
                          </blockquote>
                          <pre wrap=""><!----><br>If you send me the code, I will integrate it into a new<br>pre-release.</pre>
                          </blockquote>
                          <br>
here are the files. I'll have to change things for logging to be more....
hummm.... better.<br>
some obvious and nasty debug is laying around....<br>
and maybe the code is not exactly formated as you expect (tabs, spaces...)<br>
                          <br>
                          <br>
2&nbsp;files : <br>
                          <br>
-auth_ldap.h<br>
-auth_ldap.c<br>
                          <br>
here is what you need for cfgdirectives.c : <br>
                          <br>
#ifdef AUTH_MYSQL<br>
&nbsp;&nbsp;&nbsp; /* auth-mysql options */<br>
&nbsp;&nbsp; "auth-mysql-enable",<br>
&nbsp;&nbsp; "auth-ldap-username",<br>
&nbsp;&nbsp; "auth-ldap-password",<br>
&nbsp;&nbsp; "auth-ldap-mail-user",<br>
&nbsp;&nbsp; "auth-ldap-mail-group",<br>
&nbsp;&nbsp; "auth-ldap-filter-attr",<br>
&nbsp;&nbsp; "auth-ldap-filter-addon",<br>
&nbsp;&nbsp; "auth-ldap-url",<br>
&nbsp;&nbsp; "auth-ldap-use-TLS",<br>
&nbsp;&nbsp; "auth-ldap-mailbox-attr",<br>
&nbsp;&nbsp; "auth-ldap-uid-attr",<br>
&nbsp;&nbsp; "auth-ldap-gid-attr",<br>
#endif /* AUTH_MYSQL */<br>
                          <br>
What you'll see : everything is named as auth_mysql's plugin.<br>
I've developped everything based on this plugin.<br>
                          <br>
The first thing to do is... change every MYSQL things to LDAP...<br>
and add LDAP everywhere needed.<br>
                          <br>
code is not really clear yet, but I'm working on this. I maybe also have
to free some memory some time. just let me know if you find strange things.<br>
                          <blockquote type="cite" cite="mid:20020218151300.GA4405@aquila.esc.cam.ac.uk">
                            <blockquote type="cite">
                              <pre wrap="">chris : I would like to know what is the difference between the "home" <br>and the "mailbox" in a authcontext ? my plugin return the same, as user <br>are only present in the LDAP, and not in the system's password file....<br></pre>
                              </blockquote>
                              <pre wrap=""><!----><br>In this case you probably don't care about the value of<br>a-&gt;home. This value is used to allow path-specs for<br>mailboxes to be relative to user home directories.<br><br></pre>
                              </blockquote>
oki<br>
                              <br>
                              <br>
                              <br>
I also realised that there was a new function for pop-before-smtp<br>
As it's not recommended to write into ldap... it's not really a good idea
to have a flag there. Any suggestion on how to do it ?<br>
                              <br>
Cheers,<br>
                              <br>
Prune<br>
                              </body>
                              </html>

--------------080202040107010308000707--

--------------020907050004070400050402
Content-Type: text/plain;
 name="auth_ldap.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="auth_ldap.c"

/*
 * auth_ldap.c:
 * Authenticate users against a LDAP server.
 *
 * designed for tpop3D by Sebastien THOMAS (prune@lecentre.net) - Mad Cow tribe
 * Copyright (c) 2001 Chris Lightfoot. All rights reserved.
 * 
 */

#ifdef HAVE_CONFIG_H
#include "configuration.h"
#endif /* HAVE_CONFIG_H */

#ifdef AUTH_MYSQL
static const char rcsid[] = "$Id: auth_ldap.c,v 1.0 2002/02/18 14:41:10 Prune Exp $";

#include <sys/types.h> /* BSD needs this here, apparently. */


#include <grp.h>
#include <pwd.h>
#include <ldap.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <sys/types.h>

#include "auth_mysql.h"
#include "authswitch.h"
#include "stringmap.h"
#include "util.h"


/* auth_ldap_init:
 * Initialise the database connection driver. Clears the config directives
 * associated with the database so that a user cannot recover them with a
 * debugger.
 */
extern stringmap config; /* in main.c */

/* This is the main LDAP connection structure */
ldap_handler ldap_connection;

/* password strcture storing uid and gid */
struct passwd fork_as_user;


/* attr needed for auth */
//char *database = NULL, *filter_attr = NULL, *DEFAULT_FILTER_ATTR="mail";
char *DEFAULT_FILTER_ATTR="mail";
char *DEFAULT_MAILBOX_ATTR="maildrop";
char *DEFAULT_UID_ATTR="uidnumber";
char *DEFAULT_GID_ATTR="gidnumber";

int auth_mysql_init() {
    char *ldap_url = NULL;
    item *I;
    int ret = 0, ldap_ret=0;
    LDAPURLDesc    **ludpp;
    int ldapversion;

    /* get the data from an ldap_url string */
    if ((I = stringmap_find(config, "auth-ldap-url"))) ldap_url = (char*)I->v;
    else {
        log_print(LOG_ERR, _("auth_ldap_init: no auth-ldap-url directive in config"));
        goto fail;
    }

    /* find hostname and port from ldap url */
    if (!ldap_is_ldap_url( ldap_url )) {
      log_print(LOG_ERR, _("auth_ldap_init: auth-ldap-url directive is not valid : %s"),ldap_url);
      goto fail;
    }
    if ( (ldap_ret = ldap_url_parse( ldap_url, ludpp )) != LDAP_SUCCESS ) {
      log_print(LOG_ERR, _("auth_ldap_init: can't parse URL : %d"),ldap_ret);
      goto fail;
    }
    strncpy(ldap_connection.hostname, (*ludpp)->lud_host, HOSTNAME_MAXLENGTH);
    /* if port is not defines, we usr "389" as default */
    if (!(ldap_connection.port = (*ludpp)->lud_port))
      ldap_connection.port = LDAP_PORT;
    strncpy(ldap_connection.dn, (*ludpp)->lud_dn,DN_MAXLENGTH) ;
    ldap_free_urldesc(*ludpp);

    log_print(LOG_ERR, _("auth_ldap_init: url_parse complete : dn=%s on %s:%d "),ldap_connection.dn,ldap_connection.hostname,ldap_connection.port  );

    /* find the manager user to open ldap connection to server */
    if ((I = stringmap_find(config, "auth-ldap-username")))
      strncpy(ldap_connection.login,(char*)I->v, LOGIN_MAXLENGTH);
    else {
        log_print(LOG_ERR, _("auth_ldap_init: no auth-ldap-username directive in config"));
        goto fail;
    }

    /* we get the password of the ldap manager account */
    if ((I = stringmap_find(config, "auth-ldap-password")))
      strncpy(ldap_connection.password, (char*)I->v,PASSWORD_MAXLENGTH) ;
    else {
        log_print(LOG_WARNING, _("auth_ldap_init: no auth-ldap-password directive in config; we do not allow anonymous bind for security reasons"));
        goto fail;
    }
    
    /* we get the attribut used for the login match */
    if ((I = stringmap_find(config, "auth-ldap-filter-attr")))
      strncpy(ldap_connection.filter_attr, (char*)I->v, FILTER_MAXLENGTH) ;
    else {
      strcpy(ldap_connection.filter_attr,DEFAULT_FILTER_ATTR);
      log_print(LOG_WARNING, _("auth_ldap_init: no auth-ldap-filter-attr directive in config; using default 'mail' attribut"));
    }

    /* Obtain gid to use from conf*/
    if ((I = stringmap_find(config, "auth-ldap-mail-group"))) {
      if (!parse_gid((char*)I->v, &(fork_as_user.pw_gid))) {
	log_print(LOG_ERR, _("auth_ldap_init: auth-ldap-mail-group directive `%s' does not make sense"), (char*)I->v);
	goto fail;
      }
    }

    /* Obtain uid to use from conf, else get it from ldap... */
    if ((I = stringmap_find(config, "auth-ldap-mail-user"))) {
      if (!parse_uid((char*)I->v, &(fork_as_user.pw_uid))) {
	log_print(LOG_ERR, _("auth_ldap_init: auth-ldap-mail-userid directive `%s' does not make sense"), (char*)I->v);
	goto fail;
      }
    }

    /* get attributes to use when getting data from ldap */
    if ((I = stringmap_find(config, "auth-ldap-mailbox-attr")))
      strncpy(ldap_connection.mailbox_attr, (char*)I->v, MAILBOX_MAXLENGTH) ;
    else {
      strcpy(ldap_connection.mailbox_attr,DEFAULT_MAILBOX_ATTR);
      log_print(LOG_WARNING, _("auth_ldap_init: no auth-ldap-mailbox-attr directive in config; using default '%s' attribut"),DEFAULT_MAILBOX_ATTR);
    }

    if ((I = stringmap_find(config, "auth-ldap-uid-attr")))
      strncpy(ldap_connection.uid_attr, (char*)I->v, UID_MAXLENGTH) ;
    else {
      strcpy(ldap_connection.uid_attr,DEFAULT_UID_ATTR);
      log_print(LOG_WARNING, _("auth_ldap_init: no auth-ldap-uid-attr directive in config; using default '%s' attribut"),DEFAULT_UID_ATTR);
    }

    if ((I = stringmap_find(config, "auth-ldap-gid-attr")))
      strncpy(ldap_connection.gid_attr, (char*)I->v, GID_MAXLENGTH) ;
    else {
      strcpy(ldap_connection.gid_attr,DEFAULT_GID_ATTR);
      log_print(LOG_WARNING, _("auth_ldap_init: no auth-ldap-gid-attr directive in config; using default '%s' attribut"),DEFAULT_GID_ATTR);
    }


    /* check if we must use TLS */
    if ((I = stringmap_find(config, "auth-ldap-use-TLS")))
      ldap_connection.useTLS = 1;
    else
      ldap_connection.useTLS = 0;

    /* we ask for search filter added by user */
    /* like : ("objectclass=mailAccount") */
    if ( (I = stringmap_find(config, "auth-ldap-filter-addon")) ) 
      strncpy(ldap_connection.filter_addon, (char*)I->v, FILTER_MAXLENGTH);
    else  ldap_connection.filter_addon[0] = '\0';

    /* Make a connection to the LDAP server, notice we can use */
    /* the default ldap port by specifying LDAP_PORT */
   ldap_connection.ldap_server_connection = ldap_open(ldap_connection.hostname, ldap_connection.port);


   /* Start TLS if required */
   if (ldap_connection.useTLS == 1) {
     log_print(LOG_ERR, _("Setup TLS"));
     ldapversion = LDAP_VERSION3;
     if (ldap_set_option(ldap_connection.ldap_server_connection, LDAP_OPT_PROTOCOL_VERSION, &ldapversion) != LDAP_OPT_SUCCESS) {
       log_print(LOG_ERR, _("Cannot set LDAP_VERSION3"));
       goto fail;
     }
     
     if (ldap_start_tls_s (ldap_connection.ldap_server_connection, NULL, NULL) != LDAP_SUCCESS) {
       log_print(LOG_ERR, _("Cannot start TLS"));
       goto fail;
     }
   }

 log_print(LOG_ERR, "auth_ldap_init: connection fini" );
    if (ldap_connection.ldap_server_connection==NULL) {
        log_print(LOG_ERR, _("auth_ldap_init: ldap_init: failed to connect to server %s:%d"),ldap_connection.hostname,&ldap_connection.port);
        goto fail;
    }
    log_print(LOG_ERR, _("auth_ldap_init: connection to ldap server ok"));

    ret = 1;
fail:
    return ret;
}

extern int verbose; /* in main.c */

/* auth_mysql_new_apop:
 * Attempt to authenticate a user via APOP, using the template SELECT query in
 * the config file or the default defined above otherwise.
 */
authcontext auth_mysql_new_apop(const char *name, const char *timestamp, const unsigned char *digest, const char *host /* unused */) {
  /* no apop for the moment... */
    return NULL;
}

/* auth_mysql_new_user_pass */

authcontext auth_mysql_new_user_pass(const char *user, const char *pass, const char *host /* unused */) {
  authcontext a = NULL;
  char *local_part = NULL;
  const char *domain;
  char *filter = NULL;


  /* This message will hold my search result */
  LDAPMessage    *ldap_search_result;
    
  /* This message will hold the current message in the search*/
  /* result list as I walk through that list */
  LDAPMessage    *user_attr;

  /* This is the ber element used for printing attributes */
  BerElement     *ber;
  
  /* This will hold the dn string when it is extracted from the returned ldap entry */
  char         *user_dn, *attr, maildrop[255];
  char        **vals;
  int		nentries, ret, i;
  char *v;
  long l;

  int ldapversion;

  /* mailbox type returned. the default is "bsd". it changes to "maildir" if the maildrop ends with a "/" */
  char mailbox_type[255] = "bsd";


  /* if no connexion available, ends */ 
    if (!ldap_connection.ldap_server_connection) return NULL;

    /* we split the login and the domain from the email style login given by the user */
    domain = user + strcspn(user, "@%!");
    if (domain == user || !*domain) return NULL;
    ++domain;
    local_part = xmalloc(domain - user);
    if (!local_part) return NULL;
    memset(local_part, 0, domain - user);
    strncpy(local_part, user, domain - user - 1);
    
    /* build the filter for the search */
    /* default to 5 (sizeof "mail=") for now */
    if (strlen(ldap_connection.filter_addon)) {
      filter = xmalloc((1+strlen(user)+1+strlen(ldap_connection.filter_attr)+strlen(ldap_connection.filter_addon)+5));
      strcpy(filter,"(&(");
      strcat(filter,ldap_connection.filter_attr);
      strcat(filter,"=");
      strcat(filter,user);
      strcat(filter,")");
      strcat(filter,ldap_connection.filter_addon);
      strcat(filter,")");
	
    }
    else {
      filter = xmalloc((1+strlen(user)+1+strlen(ldap_connection.filter_attr)+2));
      strcpy(filter,"(");
      strcat(filter,ldap_connection.filter_attr);
      strcat(filter,"=");
      strcat(filter,user);
      strcat(filter,")");
	}

    if (!filter) return NULL;

log_print(LOG_DEBUG, _("auth_mysql_new_user_pass: LDAP search filter: %s"), filter);

/* bind as manager for the search */

/* we try to bind 3 times, reconnect if needed */
 for ( i=0 ; i<3; i++) {
   if ( (ret = ldap_simple_bind_s(ldap_connection.ldap_server_connection, ldap_connection.login, ldap_connection.password)) != LDAP_SUCCESS) {
     if (ret == LDAP_SERVER_DOWN ) {
       log_print(LOG_ERR, _("auth_ldap_new_user: ldap_simple_bind_s cans't bind as manager, server disconnect; trying to reconnect...") );
       ldap_connection.ldap_server_connection = ldap_open(ldap_connection.hostname, ldap_connection.port);
       if (ldap_connection.ldap_server_connection==NULL) {
	 log_print(LOG_ERR, _("auth_ldap_init: ldap_init: failed to connect to server %s:%d"),ldap_connection.hostname,&ldap_connection.port);
	 goto fail;
       }

       /* start TLS if required */
       if (ldap_connection.useTLS == 1) {
	 log_print(LOG_ERR, _("Setup TLS"));
	 ldapversion = LDAP_VERSION3;
	 if (ldap_set_option(ldap_connection.ldap_server_connection, LDAP_OPT_PROTOCOL_VERSION, &ldapversion) != LDAP_OPT_SUCCESS) {
	   log_print(LOG_ERR, _("Cannot set LDAP_VERSION3"));
	   goto fail;
	 }
	 
	 if (ldap_start_tls_s (ldap_connection.ldap_server_connection, NULL, NULL) != LDAP_SUCCESS) {
	   log_print(LOG_ERR, _("Cannot start TLS"));
	   goto fail;
	 }
       }

     }
     else {
       log_print(LOG_ERR, _("auth_ldap_new_user: ldap_simple_bind_s cans't bind as manager, check configuration") );
       ldap_unbind( ldap_connection.ldap_server_connection );
       goto fail;
     }
   }
 }
 
 /* Search through the directory synchronously for the DN of the user */
 ldap_search_s(ldap_connection.ldap_server_connection,    /* Our earlier connection */\
	       ldap_connection.dn, /* database,     base dn of directory */  \
	       LDAP_SCOPE_SUBTREE,    /* search the subtree  */   \
	       filter,    /* get me all the entries*/
	       NULL, /* I want all attributes */ \
	       0 /* Give both attributes and their values */, \
	       &ldap_search_result /* a pointer for the result*/);
 
  if (verbose)
    log_print(LOG_DEBUG, _("auth_mysql_new_user_pass: LDAP search filter: %s"), filter);
 
  /* check if entry is unique (check ldap inconcistancy) */
  if ( (nentries =ldap_count_entries (ldap_connection.ldap_server_connection, ldap_search_result)) != 1) {
    log_print(LOG_DEBUG, _("auth_ldap: LDAP search returned too many entries : %i"),nentries);
    goto fail;
  }
	
  /* we get the attributes of the first entry and store them for succes return */
  user_attr = ldap_first_entry(ldap_connection.ldap_server_connection, ldap_search_result);
        
  /* Get the dn string from the current entry */
  user_dn = ldap_get_dn(ldap_connection.ldap_server_connection, user_attr);
  
  if (user_dn != NULL) {
    /* user_dn existe, first we try to bind to validate password*/
    if ( ldap_simple_bind_s(ldap_connection.ldap_server_connection, user_dn, pass) != LDAP_SUCCESS ){
      ldap_perror (ldap_connection.ldap_server_connection,"ldap_simple_bind");
      log_print(LOG_ERR, _("auth_ldap_new_user_pass: wrong password supplied for user %s"), user);
      goto fail;
    }
        	
    /* the bind was successfull, we can get attributes */
    for ( attr = ldap_first_attribute( ldap_connection.ldap_server_connection, user_attr , &ber ); attr != NULL ; attr = ldap_next_attribute( ldap_connection.ldap_server_connection, user_attr, ber )) {

      if (verbose)
	log_print(LOG_ERR, _("auth_ldap_new_user_pass: attribut tested = %s"),attr);
      
      if ( strcasecmp(attr,ldap_connection.mailbox_attr) == 0) {
	vals = ldap_get_values (ldap_connection.ldap_server_connection, user_attr, attr);
	strcpy(maildrop,vals[0]);
	if (maildrop[strlen(maildrop)-1] == '/' )
	  strncpy(mailbox_type,"maildir", 7);
      }
	
      /* if uid was not found in conf, we get it from LDAP */
      if ( !fork_as_user.pw_uid && strcasecmp(attr,ldap_connection.uid_attr) == 0) {
	vals = ldap_get_values (ldap_connection.ldap_server_connection, user_attr, attr);
	l = strtol(vals[0], &v, 10);
	if (v && !*v) 
	  fork_as_user.pw_uid=(uid_t)l;
      }

      /* if gid was not found in conf, we get it from LDAP */
      if ( !fork_as_user.pw_gid && strcasecmp(attr,ldap_connection.gid_attr) == 0) {
	vals = ldap_get_values (ldap_connection.ldap_server_connection, user_attr, attr);
	l = strtol(vals[0], &v, 10);
	if (v && !*v) 
	  fork_as_user.pw_gid = (gid_t)l;
      }
    }
    
    /* if no maildrop found in ldap, we use a default */
    if (!maildrop) {
      strcpy(maildrop,"/var/mail/");
      strcat (maildrop,local_part);
      log_print(LOG_ERR, _("auth_ldap_new_user_pass: maildrop not set, using standard /var/mail/user : %s "),maildrop);
    }


    /* we free memory */
    ldap_memfree(attr);
  }
  if (ber != NULL) {
    ber_free( ber,0);
  }

  log_print(LOG_ERR, _("auth_ldap_new_user_pass:  end : %s of %s, %s=%s, uid : %d, gid : %d"),user,domain,mailbox_type,maildrop,fork_as_user.pw_uid,fork_as_user.pw_gid);
  a = authcontext_new(fork_as_user.pw_uid,fork_as_user.pw_gid,mailbox_type, maildrop, maildrop, domain);
  ldap_memfree( user_dn );
          

 fail:
  if (local_part) xfree(local_part);
  if (filter) xfree(filter);
  
  return a;
}

/* auth_mysql_close:
 * Close the ldap connection.
 */
void auth_mysql_close() {
  ldap_unbind( ldap_connection.ldap_server_connection );
}

/* auth_mysql_onlogin:
 *  * If specified, perform a query (action) after a successful login. The
 *   * variables substituted in the template are $(local_part), $(domain) and
 *    * $(clienthost), the username, domain, and connecting client host. */
void auth_mysql_onlogin(const authcontext A, const char *host) {
}

/* auth_mysql_postfork:
 *  * Post-fork cleanup. */
void auth_mysql_postfork() {
}

#endif /* AUTH_MYSQL */

--------------020907050004070400050402
Content-Type: text/plain;
 name="auth_ldap.h"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="auth_ldap.h"

/*
 * auth_ldap.h: authenticate users against a LDAP server
 *
 * designed for tpop3D by Sebastien THOMAS (prune@lecentre.net) - Mad Cow tribe
 * Copyright (c) 2001 Chris Lightfoot. All rights reserved.
 *
 * $Id: auth_ldap.h,v 1.0 2002/02/18 18:47:30 Prune Exp $
 *
 */

#ifndef LDAP
#include <ldap.h>
#endif

#ifndef __AUTH_MYSQL_H_ /* include guard */
#define __AUTH_MYSQL_H_

#ifdef HAVE_CONFIG_H
#include "configuration.h"
#endif /* HAVE_CONFIG_H */

#ifdef AUTH_MYSQL

#include "authswitch.h"

/* The username, password, database and host for the database must be
 * specified in the config file, using the directives
 *
 * auth-mysql-username
 * auth-mysql-password
 * auth-mysql-database
 * auth-mysql-hostname      (assumed to be "localhost" if unspecified)
 */

#define HOSTNAME_MAXLENGTH 256
#define DN_MAXLENGTH 256
#define LOGIN_MAXLENGTH 256
#define PASSWORD_MAXLENGTH 256
#define FILTER_MAXLENGTH 256
#define MAILBOX_MAXLENGTH 256
#define UID_MAXLENGTH 256
#define GID_MAXLENGTH 256

/* define global LDAP structure */
typedef struct _ldap_handler {
  LDAP        *ldap_server_connection;
  char hostname[HOSTNAME_MAXLENGTH];
  int  port;
  char dn[DN_MAXLENGTH];
  char login[LOGIN_MAXLENGTH];
  char password[PASSWORD_MAXLENGTH];
  char filter_attr[FILTER_MAXLENGTH];
  char filter_addon[FILTER_MAXLENGTH];
  char mailbox_attr[MAILBOX_MAXLENGTH];
  char uid_attr[UID_MAXLENGTH];
  char gid_attr[GID_MAXLENGTH];
  int useTLS;
} ldap_handler;

/* Config directive: auth-mysql-mail-group */
#undef AUTH_MYSQL_MAIL_GID

int  auth_mysql_init();

/* These use SELECT statements defined in auth_mysql.c */
authcontext auth_mysql_new_apop(const char *name, const char *timestamp, const unsigned char *digest, const char *host);
authcontext auth_mysql_new_user_pass(const char *user, const char *pass, const char *host);
void auth_mysql_close();
void auth_mysql_onlogin(const authcontext A, const char *host);
void auth_mysql_postfork();

#endif /* AUTH_MYSQL */

#endif /* __AUTH_MYSQL_H_ */

--------------020907050004070400050402--