On Mon, Nov 17, 2003 at 10:23:32AM -0800, Keith wrote:
> 
> Hello,
>    After many unsuccessful hours, I have resorted to
> this list in the hope of finding an answer to this
> question:
> 
>    How to change the courier-imap MAILDIR env variable
> from the default $HOME/Maildir to
> '/var/spool/mail/$USERNAME/Maildir' (for example),
> when courier-imap is using the authpam authentication
> module?

I had to do this since my department uses nfs home directories extensively. I
didn't want someone's email deferred because there was a power failure or
their machine goes down. Anyway here's the code to do it. It's from
courier-0.37.3 source, so you may have to make a modification to it. It works
great, but I'm not entirely sure that the code is all done "properly." Just
two files you have to change. base/authlib/authpam.c and
base/authlib/preauthpam.c

I'll just include the source code as attachments. The prefix I made is
/var/spool/mail/courier/juser/Maildir and I have soft links in
/var/spool/mail/juser -> /var/spool/mail/courier/juser/Maildir so that
any user can use pine and mutt with maildir support and /var/spool/mail
is distributed on nfs.

> 
> The manual [1] hints that a MAILDIR environment
> variable can be set: "3. Some additional environment
> variables may also be initialized: AUTHFULLNAME - the
> login ID's full name; MAILDIR - the login ID's default
> maildir mailbox; MAILDIRQUOTA - the requested maildir
> quota." However it is unclear (to me) how this can be
> accomplished when authenticating using authpam.
> Documentation examples I could find seem to centre on
> other authentication modules.
> 
>    The discussion here [2] suggests editing the imapd
> startup script, while here [3] the suggestions point
> to trying to set the MAILDIR environment variable
> using pam_env. As with the people in these posts, I
> have also not had much success using these
> suggestions.
> 
>    Symbolic linking $HOME/Maildir is not an option,
> and I cannot switch to use a different authentication
> module.
> 
>    Any suggestions or ideas on setting this MAILDIR
> environment variable for authpam authentication are
> very welcome!
> 
> Cheers,
> 
> Keith Nelson.
> 
> [1] http://www.courier-mta.org/authlib.html
> [2]
> http://www.mail-archive.com/[EMAIL PROTECTED]/msg09986.html
> [3]
> http://www.mail-archive.com/[EMAIL PROTECTED]/msg14029.html
> 
> 
> __________________________________
> Do you Yahoo!?
> Protect your identity with Yahoo! Mail AddressGuard
> http://antispam.yahoo.com/whatsnewfree
> 
> 
> -------------------------------------------------------
> This SF. Net email is sponsored by: GoToMyPC
> GoToMyPC is the fast, easy and secure way to access your computer from
> any Web browser or wireless device. Click here to Try it Free!
> https://www.gotomypc.com/tr/OSDN/AW/Q4_2003/t/g22lp?Target=mm/g22lp.tmpl
> _______________________________________________
> courier-users mailing list
> [EMAIL PROTECTED]
> Unsubscribe: https://lists.sourceforge.net/lists/listinfo/courier-users

-- 

EECS Systems Staff
-Michael Woods
/*
** Copyright 1998 - 2001 Double Precision, Inc.  See COPYING for
** distribution information.
*/

#if     HAVE_CONFIG_H
#include        "config.h"
#endif
#include        <stdio.h>
#include        <stdlib.h>
#include        <string.h>
#include        <signal.h>
#include        <errno.h>
#if     HAVE_UNISTD_H
#include        <unistd.h>
#endif
#include        "auth.h"
#include        "authmod.h"
#include        "authwait.h"
#include        "authstaticlist.h"

#if     HAVE_SECURITY_PAM_APPL_H
#include        <security/pam_appl.h>
#endif

#if     HAVE_PAM_PAM_APPL_H
#include        <Pam/pam_appl.h>
#endif

static const char rcsid[]="$Id: authpam.c,v 1.13 2001/06/16 22:16:25 mrsam Exp $";

static const char *pam_username, *pam_password, *pam_service;

static int pam_conv(int num_msg, const struct pam_message **msg,
                    struct pam_response **resp, void *appdata_ptr)
{
int i = 0;
struct pam_response *repl = NULL;

        repl = malloc(sizeof(struct pam_response) * num_msg);
        if (!repl) return PAM_CONV_ERR;

        for (i=0; i<num_msg; i++)
                switch (msg[i]->msg_style) {
                case PAM_PROMPT_ECHO_ON:
                        repl[i].resp_retcode = PAM_SUCCESS;
                        repl[i].resp = strdup(pam_username);
                        if (!repl[i].resp)
                        {
                                perror("strdup");
                                authexit(1);
                        }
                        break;
                case PAM_PROMPT_ECHO_OFF:
                        repl[i].resp_retcode = PAM_SUCCESS;
                        repl[i].resp = strdup(pam_password);
                        if (!repl[i].resp)
                        {
                                perror("strdup");
                                authexit(1);
                        }
                        break;
                case PAM_TEXT_INFO:
                case PAM_ERROR_MSG:
                        write(2, msg[i]->msg, strlen(msg[i]->msg));
                        write(2, "\n", 1);
                        repl[i].resp_retcode = PAM_SUCCESS;
                        repl[i].resp = NULL;
                        break;
                default:
                        free (repl);
                        return PAM_CONV_ERR;
                }

        *resp=repl;
        return PAM_SUCCESS;
}

static struct pam_conv conv = {
          pam_conv,
          NULL
      };

static int dopam(pam_handle_t **pamh)
{
int     retval;

        retval=pam_start(pam_service, pam_username, &conv, pamh);

#if 0
        if (retval == PAM_SUCCESS)
                retval=pam_set_item(*pamh, PAM_AUTHTOK, pam_password);
#endif

        if (retval == PAM_SUCCESS)
                retval=pam_authenticate(*pamh, 0);

#if 0

#if     HAVE_PAM_SETCRED
        if (retval == PAM_SUCCESS)
                retval=pam_setcred(*pamh, PAM_ESTABLISH_CRED);
#endif

        if (retval == PAM_SUCCESS)
                retval=pam_acct_mgmt(*pamh, 0);
#endif
        return (retval);
}

struct callback_info {
        char *username;
        int issession;
        void (*callback_func)(struct authinfo *, void *);
        void *callback_arg;
        } ;

static int callback_pam(struct authinfo *a, void *argptr)
{
struct callback_info *ci=(struct callback_info *)argptr;
pam_handle_t    *pamh=NULL;
int     pipefd[2];
int     retval;
pid_t   p;
int     waitstat;
char    *s;

// add these

char    *alloc_buf;
char    prepend[25];

        s=strdup(a->sysusername);
        if (!s)
        {
                perror("malloc");
                return (1);
        }

        if (!ci->issession &&   /* Thankfully, no session voodoo needed this time */
                ci->callback_func == 0)
        {
                retval=dopam(&pamh);

                if (retval == PAM_SUCCESS)
                {
                        if (pam_end(pamh, retval) != PAM_SUCCESS)
                                perror("Unable to release PAM tokens");
                        if (ci->callback_func == 0){

// changes made here

                                strcpy( prepend, "/var/spool/mail/courier/" );
                                
alloc_buf=malloc(strlen(a->sysusername)+strlen(prepend)+2);
                                strcat(strcpy(alloc_buf, prepend), a->sysusername);
                                authsuccess(alloc_buf,
//

                                        a->sysusername,
                                        0,
                                        &a->sysgroupid,
                                        a->address,
                                        a->fullname);
                        }

                        ci->username=s;
                        putenv("MAILDIR=");
                        return (0);
                }
                free(s);
                free(alloc_buf);
                if (pam_end(pamh, retval) != PAM_SUCCESS)
                        perror("Unable to release PAM tokens");
                return (-1);
        }

/*
**      OK, in order to transparently support PAM sessions inside this
**      authentication module, what we need to do is to fork(), and let
**      the child run in its parent place.  Once the child process exits,
**      the parent calls pam_end_session, and clears the PAM library.
**
**      This means that upon return from auth_pam(), your process ID
**      might've changed!!!
**
**      However, if the authentication fails, we can simply exit, without
**      running as a child process.
**
**      Additionally, the PAM library might allocate some resources that
**      authenticated clients should not access.  Therefore, we fork
**      *before* we try to authenticate.  If the authentication succeeds,
**      the child process will run in the parent's place.  The child
**      process waits until the parent tells it whether the authentication
**      worked.  If it worked, the child keeps running.  If not, the child
**      exits, which the parent waits for.
**
**      The authentication status is communicated to the child process via
**      a pipe.
*/
        if (pipe(pipefd) < 0)
        {
                perror("pipe");
                free(s);
                return (1);
        }

        if ((p=fork()) == -1)
        {
                perror("fork");
                free(s);
                return (1);
        }

        if (p == 0)
        {
        char    dummy;

                if (ci->callback_func)  /* PAM memory leak */
                {
                        close(pipefd[0]);
                        retval=dopam(&pamh);
                        if (retval == PAM_SUCCESS)
                                write(pipefd[1], "", 1);
                        close(pipefd[1]);
                        _exit(0);
                }

                close(pipefd[1]);

                if (read(pipefd[0], &dummy, 1) != 1 || dummy)
                        authexit(1);    /* Authentication failed by parent */
                close(pipefd[0]);

                putenv("MAILDIR=");

// here again

                strcpy( prepend, "/var/spool/mail/courier/" );
                alloc_buf=malloc(strlen(a->sysusername)+strlen(prepend)+2);
                strcat(strcpy(alloc_buf, prepend), a->sysusername);

                authsuccess(alloc_buf,

//

                        a->sysusername,
                        0,
                        &a->sysgroupid,
                        a->address,
                        a->fullname);
                ci->username=s;
                if (ci->callback_func)
                {
                        a->address=s;
                        (*ci->callback_func)(a, ci->callback_arg);
                }
                return (0);
        }

        if (ci->callback_func)
        {
        char    buf[1];

                close(pipefd[1]);
                while (wait(&waitstat) != p)
                        ;
                if (read(pipefd[0], buf, 1) > 0)
                {
                        close(pipefd[0]);
                        a->address=s;
                        ci->username=s;
                        (*ci->callback_func)(a, ci->callback_arg);
                        return (0);
                }
                close(pipefd[0]);
                free(s);
                return (-1);
        }

        free(alloc_buf);
        free(s);
        close(pipefd[0]);

        retval=dopam(&pamh);

        if (retval == PAM_SUCCESS)
                retval=pam_open_session(pamh, 0);

        if (retval != PAM_SUCCESS)
        {
                if (pam_end(pamh, retval) != PAM_SUCCESS)
                        perror("Unable to release PAM tokens");

                /* Wait for child to terminate */

                close(pipefd[1]); /* Tell the child to shut down */
                while (wait(&waitstat) != p)
                        ;
                return (-1);
        }

        /* Tell child process to run in authenticated state */

        write(pipefd[1], "", 1);
        close(pipefd[1]);

        /* Wait for child process to finish */

        while (wait(&waitstat) != p)
                ;

        retval=pam_close_session(pamh, 0);
        if (retval != PAM_SUCCESS)
                perror("pam_close_session");

        if (pam_end(pamh, retval) != PAM_SUCCESS)
                perror("Unable to release PAM tokens");

        if (WIFEXITED(waitstat))
                authexit(WEXITSTATUS(waitstat));
        authexit(255);
        return (1);
}

extern int auth_pam_pre(const char *userid, const char *service,
        int (*callback)(struct authinfo *, void *),
                        void *arg);

char *auth_pam(const char *service, const char *type, char *authdata,
        int issession,
        void (*callback_func)(struct authinfo *, void *), void *callback_arg)
{
struct  callback_info   ci;
int     rc;

        if (strcmp(type, AUTHTYPE_LOGIN) ||
                (pam_username=strtok(authdata, "\n")) == 0 ||
                (pam_password=strtok(0, "\n")) == 0)
        {
                errno=EPERM;
                return (0);
        }

        pam_service=service;

        ci.issession=issession;
        ci.callback_func=callback_func;
        ci.callback_arg=callback_arg;
        rc=auth_pam_pre(pam_username, service, &callback_pam, &ci);
        if (rc) return (0);
        return (ci.username);
}

static void auth_pam_cleanup()
{
}

struct authstaticinfo authpam_info={
        "authpam",
        auth_pam,
        auth_pam_pre,
        auth_pam_cleanup,
        auth_syspasswd};
/*
** Copyright 1998 - 1999 Double Precision, Inc.  See COPYING for
** distribution information.
*/

#if     HAVE_CONFIG_H
#include        "config.h"
#endif
#include        <stdio.h>
#include        <stdlib.h>
#include        <string.h>
#include        <errno.h>
#include        <pwd.h>
#include        "auth.h"

#if     HAVE_SHADOW_H
#include        <shadow.h>
#endif

static const char rcsid[]="$Id: preauthpam.c,v 1.8 2001/12/22 21:25:13 mrsam Exp $";

int auth_pam_pre(const char *userid, const char *service,
        int (*callback)(struct authinfo *, void *),
                        void *arg)
{
struct authinfo auth;
struct passwd *pw;

// added these

char    *alloc_buf;
char    prepend[25];
#if     HAVE_GETSPENT
struct spwd *spw;
#endif

        memset(&auth, 0, sizeof(auth));

        if ((pw=getpwnam(userid)) == 0)
        {
                if (errno == ENOMEM)    return (1);
                errno=EPERM;
                return (-1);
        }


// changes made here

        strcpy( prepend, "/var/spool/mail/courier/" );
        alloc_buf=malloc(strlen(userid)+strlen(prepend)+2);
        strcat(strcpy(alloc_buf, prepend), userid);

        auth.sysusername=userid;
        auth.sysgroupid=pw->pw_gid;
        auth.homedir=alloc_buf;

//

        auth.address=userid;
        auth.fullname=pw->pw_gecos;
        auth.passwd=pw->pw_passwd;

#if     HAVE_GETSPENT
        if ((spw=getspnam(userid)) != 0)
                auth.passwd=spw->sp_pwdp;
#endif

        free(alloc_buf);
        return ((*callback)(&auth, arg));
}

Reply via email to