QPopper and C2

From: Arn <arn_at_oracle.dsuper.net>
Date: Mon, 02 Feb 1998 20:36:41 -0500 (EST)

Hello ppl,

I have been working with qpopper 2.4 and Dec Unix 4.0b, running on an
Alpha. Here is the situation. I dont know if it has been already released
before but, there is a security bug involving qpopper and C2 security.
Much like the wu-ftpd bug, it does not keep track of the ammount of
unsuccessful logins. There are programs out on the net that can brute
force this exploit.

With this in mind, I have been trying to apply a patch to this bug,
following the code released sometime ago by Dave Diehl, for qpopper 2.4.
However my programming C skills are somewhat new and I cannot seem to get
proper authetication with the patch. I have attached qpopper's code for
OSF and my version ( including the patch ). Any help would be much
appreciated.

Thanks

._._._._._._._._._._._._._._._._._._._._._._._._.
| | |
| Douglas Meldrum | A tiny lil bit in a |
| Network Coordinator | stream of bytes being |
| Delphi Supernet | bridge, routed, |
| .o0o. | filtered and dumped |
| | into someone's bit |
| "Eschew obfuscation" | bucket. |
| | |
.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.



/*
 * Copyright (c) 1989 Regents of the University of California.
 * All rights reserved. The Berkeley software License Agreement
 * specifies the terms and conditions for redistribution.
 */

/*
 * Copyright (c) 1997 by Qualcomm Incorporated.
 */

#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#include <string.h>
#if HAVE_STRINGS_H
# include <strings.h>
#endif

#include <pwd.h>
#include "popper.h"

#define SLEEP_SECONDS 10


/* This error message is vague on purpose to help reduce help improve
   security at the inconvience of administrators and users */

char *pwerrmsg = "Password supplied for \"%s\" is incorrect.";


#ifdef NONAUTHFILE
checknonauthfile(user)
     char *user;
{
    char buf[MAXUSERNAMELEN+1];
    FILE *fp;
    char cool = 0;

    if ((fp = fopen(NONAUTHFILE, "r")) != NULL) {
        while (fgets(buf, MAXUSERNAMELEN+1, fp)) {
            buf[strlen(buf) -1] = '\0';
            if (!strcmp(buf, user)) {
                fclose(fp);
                return(-1);
            }
        }

        fclose(fp);
    }
    return(0);
}
#endif

#ifdef AUTHFILE
checkauthfile(user)
     char *user;
{
    char buf[MAXUSERNAMELEN+1];
    FILE *fp;
    char cool = 0;

    if ((fp = fopen(AUTHFILE, "r")) != NULL) {
        while (fgets(buf, MAXUSERNAMELEN+1, fp)) {
            buf[strlen(buf) -1] = '\0';
            if (!strcmp(buf, user)) {
                fclose(fp);
                return(0);
            }
        }

        fclose(fp);
    }
    return(-1);
}
#endif

int auth_user_kerberos (p, pw)
POP * p;
struct passwd *pw;
{
#ifdef KERBEROS
    char lrealm[REALM_SZ];
    int status;
    struct passwd *pwp;
 
    if ((status = krb_get_lrealm(lrealm,1)) == KFAILURE) {
        pop_log(p, LOG_WARNING, "%s: (%s.%s@%s) %s", p->client, kdata.pname,
                kdata.pinst, kdata.prealm, krb_err_txt[status]);
        return(pop_msg(p,POP_FAILURE,
            "Kerberos error: \"%s\".", krb_err_txt[status]));
    }

# ifdef KUSEROK
    if (kuserok(&kdata, p->user)) {
        pop_log(p, LOG_WARNING, "%s: (%s.%s@%s): not in %s's ACL.",
            p->client, kdata.pname, kdata.pinst, kdata.prealm, p->user);
        return(pop_msg(p,POP_FAILURE, "Not in %s's ACL.", p->user));
    }
# else
    if (strcmp(kdata.prealm,lrealm)) {
         pop_log(p, LOG_WARNING, "%s: (%s.%s@%s) realm not accepted.",
                 p->client, kdata.pname, kdata.pinst, kdata.prealm);
         return(pop_msg(p,POP_FAILURE,
                     "Kerberos realm \"%s\" not accepted.", kdata.prealm));
    }

    if (strcmp(kdata.pinst,"")) {
        pop_log(p, LOG_WARNING, "%s: (%s.%s@%s) instance not accepted.",
                 p->client, kdata.pname, kdata.pinst, kdata.prealm);
        return(pop_msg(p,POP_FAILURE,
              "Must use null Kerberos(tm) instance - \"%s.%s\" not accepted.",
              kdata.pname, kdata.pinst));
    }
# endif /* KUSEROK */
    return(POP_SUCCESS);
#else /* Kerberos not defined */
    return(pop_log(p, LOG_WARNING,
        "Kerberos failure: The popper has not been compiled with -DKERBEROS"));
#endif /* KERBEROS */
}


#ifdef AUTH
    char *crypt();

#if defined(SUNOS4) && !defined(ISC)

#include <sys/label.h>
#include <sys/audit.h>
#include <pwdadj.h>

static int
auth_user(p, pw)
POP * p;
struct passwd *pw;
{
    struct passwd_adjunct *pwadj;

    /* Look for the user in the shadow password file */
    if ((pwadj = getpwanam(p->user)) == NULL) {
        sleep(SLEEP_SECONDS);
        return (pop_msg(p,POP_FAILURE,
                "(shadow) Password supplied for \"%s\" is empty.",p->user));
    } else {
        pw->pw_passwd = (char *)strdup(pwadj->pwa_passwd);
    }

    /* We don't accept connections from users with null passwords */
    /* Compare the supplied password with the password file entry */
    if ((pw->pw_passwd == NULL) || (*pw->pw_passwd == '\0') ||
                strcmp(crypt(p->pop_parm[1], pw->pw_passwd), pw->pw_passwd)) {
        sleep(SLEEP_SECONDS);
        return (pop_msg(p,POP_FAILURE,pwerrmsg, p->user));
    }

    return(POP_SUCCESS);
}

#endif /* SUNOS4 */

#if defined(SOLARIS2) || defined(AUX)

#include <shadow.h>

static int
auth_user(p, pw)
POP * p;
struct passwd *pw;
{
    register struct spwd * pwd;
    long today;

    /* Look for the user in the shadow password file */
    if ((pwd = getspnam(p->user)) == NULL) {
        if (!strcmp(pw->pw_passwd, "x")) { /* This my be a YP entry */
            sleep(SLEEP_SECONDS);
            return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
        }
    } else {
        today = (long)time((time_t *)NULL)/24/60/60;

        /* Check for expiration date */
        if (pwd->sp_expire > 0 && today > pwd->sp_expire) {
            sleep(SLEEP_SECONDS);
            return (pop_msg(p,POP_FAILURE,"\"%s\": account expired.",p->user));
        }

        /* Check if password is valid */
        if (pwd->sp_max > 0 && today > pwd->sp_lstchg+pwd->sp_max) {
            sleep(SLEEP_SECONDS);
            return (pop_msg(p,POP_FAILURE,"\"%s\": account expired.",p->user));
        }

        pw->pw_passwd = (char *)strdup(pwd->sp_pwdp);
        endspent();
    }

    /* We don't accept connections from users with null passwords */
    /* Compare the supplied password with the password file entry */
    if ((pw->pw_passwd == NULL) || (*pw->pw_passwd == '\0') ||
                strcmp(crypt(p->pop_parm[1], pw->pw_passwd), pw->pw_passwd)) {
        sleep(SLEEP_SECONDS);
        return (pop_msg(p, POP_FAILURE, pwerrmsg, p->user));
    }

    return(POP_SUCCESS);
}

#endif /* SOLARIS2 || AUX */

#if defined(PTX) || defined(ISC)

#include <shadow.h>

static int
auth_user(p, pw)
POP * p;
struct passwd *pw;
{
    register struct spwd * pwd;
    long today;

    /* Look for the user in the shadow password file */
    if ((pwd = getspnam(p->user)) == NULL) {
        if (!strcmp(pw->pw_passwd, "x")) { /* This my be a YP entry */
            sleep(SLEEP_SECONDS);
            return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
        }
    } else {
        pw->pw_passwd = (char *)strdup(pwd->sp_pwdp);
    }

    /* We don't accept connections from users with null passwords */
    /* Compare the supplied password with the password file entry */
    if ((pw->pw_passwd == NULL) || (*pw->pw_passwd == '\0') ||
                strcmp(crypt(p->pop_parm[1], pw->pw_passwd), pw->pw_passwd)) {
        sleep(SLEEP_SECONDS);
        return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
    }

    return(POP_SUCCESS);
}

#endif /* PTX */

#if defined(POPSCO) || defined(HPUX10)

#ifdef POPSCO
# include <sys/security.h>
# include <sys/audit.h>
#else
# include <hpsecurity.h>
#endif

#include <prot.h>
#define PASSWD(p) p->ufld.fd_encrypt

static int
auth_user(p, pw)
POP * p;
struct passwd *pw;
{
    register struct pr_passwd *pr;

    if ((pr = getprpwnam(p->user)) == NULL) {
        if (!strcmp(pw->pw_passwd, "x")) {
            sleep(SLEEP_SECONDS);
            return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
        }

        /* We don't accept connections from users with null passwords */
        if ((pw->pw_passwd == NULL) || (*pw->pw_passwd == '\0') ||
             (strcmp(bigcrypt(p->pop_parm[1], pw->pw_passwd), pw->pw_passwd) &&
              strcmp(crypt (p->pop_parm[1], pw->pw_passwd), pw->pw_passwd))) {
            sleep(SLEEP_SECONDS);
            return(pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
        }
    } else {
        /* We don't accept connections from users with null passwords */
        /* Compare the supplied password with the password file entry */
        if ((PASSWD(pr) == NULL) || (*PASSWD(pr) == '\0')) {
            sleep(SLEEP_SECONDS);
            return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
        }
        
        if (strcmp(bigcrypt(p->pop_parm[1], PASSWD(pr)), PASSWD(pr)) &&
                    strcmp(crypt(p->pop_parm[1], PASSWD(pr)), PASSWD(pr))) {
            sleep(SLEEP_SECONDS);
            return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
        }
    }

    return(POP_SUCCESS);
}

#endif /* POPSCO || HPUX10 */

#ifdef ULTRIX

#include <auth.h>

static int
auth_user(p, pw)
struct passwd * pw;
POP * p;
{
    AUTHORIZATION *auth, *getauthuid();

    if ((auth = getauthuid(pw->pw_uid)) == NULL) {
        if (!strcmp(pw->pw_passwd, "x")) { /* This my be a YP entry */
            sleep(SLEEP_SECONDS);
            return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
        }
    } else {
        pw->pw_passwd = (char *)strdup(auth->a_password);
    }

    /* We don't accept connections from users with null passwords */
    /* Compare the supplied password with the password file entry */
    if ((pw->pw_passwd == NULL) || (*pw->pw_passwd == '\0')) {
        sleep(SLEEP_SECONDS);
        return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
    }

    if (strcmp(crypt16(p->pop_parm[1], pw->pw_passwd), pw->pw_passwd) &&
                strcmp(crypt(p->pop_parm[1], pw->pw_passwd), pw->pw_passwd)) {
        sleep(SLEEP_SECONDS);
        return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
    }

    return(POP_SUCCESS);
}

#endif /* ULTRIX */

#ifdef OSF1
#include <sia.h>
#include <siad.h>
#include <sys/types.h>
#include <sys/security.h>
#include <prot.h>
/* #define PASSWD(p) (p->ufld.fd_encrypt) */
static int
auth_user(p, pw)
POP * p;
struct passwd *pw;
int osf_check_pass(char user[32], char *passwd)
{
    register struct pr_passwd *pr;

    if ((pr = getprpwnam(p->user)) == NULL) {
        if (!strcmp(pw->pw_passwd, "x")) { /* This my be a YP entry */
            sleep(SLEEP_SECONDS);
            return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
        }
    } else { */
        pw->pw_passwd = (char *)strdup(PASSWD(pr));
    }

    /* Enhanced C2 security code */
    if (osf_check_pass(user, pw->pw_passwd) <0) {
               return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
    }

    /* We don't accept connections from users with null passwords
        Compare the supplied password with the password file entry
    if ((pw->pw_passwd == NULL) || (*pw->pw_passwd == '\0')) {
        sleep(SLEEP_SECONDS);
        return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
    }

    if (strcmp(bigcrypt(p->pop_parm[1], pw->pw_passwd), pw->pw_passwd) &&
                strcmp(crypt(p->pop_parm[1], pw->pw_passwd), pw->pw_passwd)) {
        sleep(SLEEP_SECONDS);
        return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
    }
    */

    return(POP_SUCCESS);
}

/*
 Enhanced C2 security code for keeping track of the number of login attempts
*/

in sia_collect_null(int timeout, int rendition, unsigned char *title, int num_pr
ompts, prompt_t *prompt)
{
    return SIACOLSUCCESS;
}

static int
osf_check_passs(char user[32], char *passwd)
{
    SIAENTITY *entity = NULL;
    /* char uname[32]; */
    int auth_status;
    int argc = 1;
    char *argv[2];
    
    argv[0] = "popper";
    argv[1] = (char *) 0;
    set_auth_parameters(argc, argv);

    /* (void) strcpy(uname, pw->pw_name); */

    aut_status = sia_ses_init(&entity, argc, argv, NULL, user, NULL, FALSE, NUL
L);
    if (auth_status != SIASUCCESS)
    {
        syslof(LOG_ERR, "sia_ses_init() failed in osf_check_pass");
        return -1;
    }

    if (pw == (struct passwd *) NULL) {
        return -1;
    }

    auth_status = sia_ses_authent(sia_collect_null, passwd, enntity);
    if (auth_status != SIASUCCESS) {
        return -1;
    }

    auth_status = sia_ses_estab(sia_collect_null, entity);
    if (auth_status != SIASUCCESS)
    {
        syslog(LOG_WARNING, "sia_ses_estab() failed in osf_check_pass");
        return -1;
    }

    auth_status = sia_ses_release(&entity);
    if (auth_status != SIASUCCESS)
    {
        syslog(LOG_ERR, "sia_ses_release() failed ion osf_check_pass");
        return -1;
    }

    return 0;
}




#endif /* OSF1 */

#ifdef UNIXWARE

#include <shadow.h>

static int
auth_user(p, pw)
struct passwd * pw;
POP * p;
{
    register struct spwd * pwd;
    long today;

    /* Look for the user in the shadow password file */
    if ((pwd = getspnam(p->user)) == NULL) {
        if (!strcmp(pw->pw_passwd, "x")) { /* This my be a YP entry */
            sleep(SLEEP_SECONDS);
            return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
        }
    } else {
        today = (long)time((time_t *)NULL)/24/60/60;

        /* Check for expiration date */
        if (pwd->sp_expire > 0 && today > pwd->sp_expire) {
            sleep(SLEEP_SECONDS);
            return (pop_msg(p,POP_FAILURE,"\"%s\": account expired.",p->user));
        }

        /* Check if password is valid */
        if (pwd->sp_max > 0 && today > pwd->sp_lstchg+pwd->sp_max) {
            sleep(SLEEP_SECONDS);
            return (pop_msg(p,POP_FAILURE,"\"%s\": account expired.",p->user));
        }

        pw->pw_passwd = (char *)strdup(pwd->sp_pwdp);
        endspent();
    }

    /* We don't accept connections from users with null passwords */
    /* Compare the supplied password with the password file entry */
    if ((pw->pw_passwd == NULL) || (*pw->pw_passwd == '\0') ||
                strcmp(crypt(p->pop_parm[1], pw->pw_passwd), pw->pw_passwd)) {
        sleep(SLEEP_SECONDS);
        return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
    }

    return(POP_SUCCESS);
}

#endif /* UNIXWARE */

#ifdef LINUX
#include <shadow.h>
 
static int
auth_user(p, pw)
POP * p;
struct passwd *pw;
{
    register struct spwd * pwd;
    long today;

    /* Look for the user in the shadow password file */
    if ((pwd = getspnam(p->user)) == NULL) {
        if (!strcmp(pw->pw_passwd, "x")) { /* This my be a YP entry */
            sleep(SLEEP_SECONDS);
            return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
        }
    } else {
        today = (long)time((time_t *)NULL)/24/60/60;

        /* Check for expiration date */
        if (pwd->sp_expire > 0 && today > pwd->sp_expire) {
            sleep(SLEEP_SECONDS);
            return (pop_msg(p,POP_FAILURE,"\"%s\": account expired.",p->user));
        }

        /* Check if password is valid */
        if (pwd->sp_max > 0 && today > pwd->sp_lstchg+pwd->sp_max) {
            sleep(SLEEP_SECONDS);
            return (pop_msg(p,POP_FAILURE,"\"%s\": account expired.",p->user));
        }

        pw->pw_passwd = (char *)strdup(pwd->sp_pwdp);
        endspent();
    }

    /* We don't accept connections from users with null passwords */
    /* Compare the supplied password with the password file entry */
        /* pw_encrypt() ?? */
    if ((pw->pw_passwd == NULL) || (*pw->pw_passwd == '\0') ||
            (strcmp(crypt(p->pop_parm[1], pw->pw_passwd), pw->pw_passwd) &&
             strcmp(pw_encrypt(p->pop_parm[1], pw->pw_passwd), pw->pw_passwd))){
        sleep(SLEEP_SECONDS);
        return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
    }

    return(POP_SUCCESS);
}

#endif /* LINUX */

#else /* NOT AUTH */

char *crypt();

static int
auth_user(p, pw)
POP * p;
struct passwd * pw;
{
    /* We don't accept connections from users with null passwords */
    /* Compare the supplied password with the password file entry */

    if ((pw->pw_passwd == NULL) || (*pw->pw_passwd == '\0') ||
                strcmp(crypt(p->pop_parm[1], pw->pw_passwd), pw->pw_passwd)) {
        sleep(SLEEP_SECONDS);
        return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
    }

    return(POP_SUCCESS);
}

#endif /* AUTH */

/*
 * pass: Obtain the user password from a POP client
 */

#ifdef SECURENISPLUS
/* AUTH gets defined in rpc/... */
# ifdef AUTH
# undef AUTH
# endif
# include <rpc/rpc.h>
# include <rpc/key_prot.h>
#endif

int pop_pass (p)
POP * p;
{
    struct passwd pw, *pwp;
#ifdef CHECK_SHELL
    char *getusershell();
    void endusershell();
    char *shell;
    char *cp;
    int shellvalid;
#endif

#ifdef SECURENISPLUS
    UID_T uid_save;
    char net_name[MAXNETNAMELEN],
         secretkey[HEXKEYBYTES + 1];

    *secretkey = '\0';
#endif

#ifdef NONAUTHFILE
    /* Is the user not authorized to use POP? */
    if (checknonauthfile(p->user) != 0) {
        sleep(SLEEP_SECONDS);
        return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
    }
#endif

#ifdef AUTHFILE
    /* Is the user authorized to use POP? */
    if (checkauthfile(p->user) != 0) {
        sleep(SLEEP_SECONDS);
        return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
    }
#endif

    /* Look for the user in the password file */
    if ((pwp = getpwnam(p->user)) == NULL) {
        sleep(SLEEP_SECONDS);
        return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
    }

    pw = *pwp;

#ifdef SECURENISPLUS
    /* we must do this keyserv stuff (as well as auth_user()!) as the user */
    uid_save = geteuid();
    seteuid(pw.pw_uid);

    /* see if DES keys are already known to the keyserv(1m) */
    if (! key_secretkey_is_set()) {
        /* keys are not known, so we must get the DES keys
            and register with the keyserv(1m) */

        getnetname(net_name);

        if (getpublickey(net_name, secretkey)) {
            if (strlen(p->pop_parm[1]) > 8) (p->pop_parm[1])[8] = '\0';

            if (! getsecretkey(net_name, secretkey, p->pop_parm[1]) ||
                                                        *secretkey == '\0') {
                sleep(SLEEP_SECONDS);
                return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
            }

            key_setsecret(secretkey);
            memset(secretkey, '\0', sizeof(secretkey));
        } else {
            /* if there are no keys defined, we assume that password entry
               either resides in /etc/shadow or "root" has access to the
               corresponding NIS+ entry */
            seteuid(0);
        }
    }
#endif

#ifdef BLOCK_UID
    if (pw.pw_uid <= BLOCK_UID)
        return (pop_msg(p,POP_FAILURE,
                            "Access is blocked for UIDs below %d", BLOCK_UID));
#endif

#ifdef CHECK_SHELL
    /* Disallow anyone who does not have a standard shell as returned by
     * getusershell(), unless the sys admin has included the wildcard
     * shell in /etc/shells. (default wildcard - /POPPER/ANY/SHELL)
     */
    if ((shell = pw.pw_shell) == NULL || *shell == 0)
/* You can default the shell, but I don't think it's a good idea */
/* shell = "/usr/bin/sh"; */
        return(pop_msg(p, POP_FAILURE, "No user shell defined"));
    
    for (shellvalid = 0; !shellvalid && ((cp = getusershell()) != NULL);)
        if (!strcmp(cp, WILDCARD_SHELL) || !strcmp(cp, shell))
             shellvalid = 1;
    endusershell();

    if (!shellvalid)
        return(pop_msg(p, POP_FAILURE, "\"%s\": shell not found.", p->user));
#endif

    if ((p->kerberos ? auth_user_kerberos(p, pw) : auth_user(p, pwp))
                                                        != POP_SUCCESS) {
            pop_log(p,POP_PRIORITY,"Failed attempted login to %s from host %s",
                                                            p->user, p->client);
        return(POP_FAILURE);
    }

#ifdef SECURENISPLUS
    seteuid(uid_save);
#endif

    /* Make a temporary copy of the user's maildrop */
    /* and set the group and user id */
    /* and get information about the maildrop */
    if (pop_dropcopy(p, &pw) != POP_SUCCESS) return (POP_FAILURE);

    /* Initialize the last-message-accessed number */
    p->last_msg = 0;

    /* Authorization completed successfully */
    return (pop_msg (p,POP_SUCCESS,
        "%s has %d message%s (%d octets).",
            p->user,p->msg_count, p->msg_count == 1 ? "" : "s", p->drop_size));
}


/*
 * Copyright (c) 1989 Regents of the University of California.
 * All rights reserved. The Berkeley software License Agreement
 * specifies the terms and conditions for redistribution.
 */

/*
 * Copyright (c) 1997 by Qualcomm Incorporated.
 */

#include <config.h>
#include <stdio.h>
#include <sys/types.h>
#include <string.h>
#if HAVE_STRINGS_H
# include <strings.h>
#endif

#include <pwd.h>
#include "popper.h"

#define SLEEP_SECONDS 10


/* This error message is vague on purpose to help reduce help improve
   security at the inconvience of administrators and users */

char *pwerrmsg = "Password supplied for \"%s\" is incorrect.";


#ifdef NONAUTHFILE
checknonauthfile(user)
     char *user;
{
    char buf[MAXUSERNAMELEN+1];
    FILE *fp;
    char cool = 0;

    if ((fp = fopen(NONAUTHFILE, "r")) != NULL) {
        while (fgets(buf, MAXUSERNAMELEN+1, fp)) {
            buf[strlen(buf) -1] = '\0';
            if (!strcmp(buf, user)) {
                fclose(fp);
                return(-1);
            }
        }

        fclose(fp);
    }
    return(0);
}
#endif

#ifdef AUTHFILE
checkauthfile(user)
     char *user;
{
    char buf[MAXUSERNAMELEN+1];
    FILE *fp;
    char cool = 0;

    if ((fp = fopen(AUTHFILE, "r")) != NULL) {
        while (fgets(buf, MAXUSERNAMELEN+1, fp)) {
            buf[strlen(buf) -1] = '\0';
            if (!strcmp(buf, user)) {
                fclose(fp);
                return(0);
            }
        }

        fclose(fp);
    }
    return(-1);
}
#endif

int auth_user_kerberos (p, pw)
POP * p;
struct passwd *pw;
{
#ifdef KERBEROS
    char lrealm[REALM_SZ];
    int status;
    struct passwd *pwp;
 
    if ((status = krb_get_lrealm(lrealm,1)) == KFAILURE) {
        pop_log(p, LOG_WARNING, "%s: (%s.%s@%s) %s", p->client, kdata.pname,
                kdata.pinst, kdata.prealm, krb_err_txt[status]);
        return(pop_msg(p,POP_FAILURE,
            "Kerberos error: \"%s\".", krb_err_txt[status]));
    }

# ifdef KUSEROK
    if (kuserok(&kdata, p->user)) {
        pop_log(p, LOG_WARNING, "%s: (%s.%s@%s): not in %s's ACL.",
            p->client, kdata.pname, kdata.pinst, kdata.prealm, p->user);
        return(pop_msg(p,POP_FAILURE, "Not in %s's ACL.", p->user));
    }
# else
    if (strcmp(kdata.prealm,lrealm)) {
         pop_log(p, LOG_WARNING, "%s: (%s.%s@%s) realm not accepted.",
                 p->client, kdata.pname, kdata.pinst, kdata.prealm);
         return(pop_msg(p,POP_FAILURE,
                     "Kerberos realm \"%s\" not accepted.", kdata.prealm));
    }

    if (strcmp(kdata.pinst,"")) {
        pop_log(p, LOG_WARNING, "%s: (%s.%s@%s) instance not accepted.",
                 p->client, kdata.pname, kdata.pinst, kdata.prealm);
        return(pop_msg(p,POP_FAILURE,
              "Must use null Kerberos(tm) instance - \"%s.%s\" not accepted.",
              kdata.pname, kdata.pinst));
    }
# endif /* KUSEROK */
    return(POP_SUCCESS);
#else /* Kerberos not defined */
    return(pop_log(p, LOG_WARNING,
        "Kerberos failure: The popper has not been compiled with -DKERBEROS"));
#endif /* KERBEROS */
}


#ifdef AUTH
    char *crypt();

#if defined(SUNOS4) && !defined(ISC)

#include <sys/label.h>
#include <sys/audit.h>
#include <pwdadj.h>

static int
auth_user(p, pw)
POP * p;
struct passwd *pw;
{
    struct passwd_adjunct *pwadj;

    /* Look for the user in the shadow password file */
    if ((pwadj = getpwanam(p->user)) == NULL) {
        sleep(SLEEP_SECONDS);
        return (pop_msg(p,POP_FAILURE,
                "(shadow) Password supplied for \"%s\" is empty.",p->user));
    } else {
        pw->pw_passwd = (char *)strdup(pwadj->pwa_passwd);
    }

    /* We don't accept connections from users with null passwords */
    /* Compare the supplied password with the password file entry */
    if ((pw->pw_passwd == NULL) || (*pw->pw_passwd == '\0') ||
                strcmp(crypt(p->pop_parm[1], pw->pw_passwd), pw->pw_passwd)) {
        sleep(SLEEP_SECONDS);
        return (pop_msg(p,POP_FAILURE,pwerrmsg, p->user));
    }

    return(POP_SUCCESS);
}

#endif /* SUNOS4 */

#if defined(SOLARIS2) || defined(AUX)

#include <shadow.h>

static int
auth_user(p, pw)
POP * p;
struct passwd *pw;
{
    register struct spwd * pwd;
    long today;

    /* Look for the user in the shadow password file */
    if ((pwd = getspnam(p->user)) == NULL) {
        if (!strcmp(pw->pw_passwd, "x")) { /* This my be a YP entry */
            sleep(SLEEP_SECONDS);
            return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
        }
    } else {
        today = (long)time((time_t *)NULL)/24/60/60;

        /* Check for expiration date */
        if (pwd->sp_expire > 0 && today > pwd->sp_expire) {
            sleep(SLEEP_SECONDS);
            return (pop_msg(p,POP_FAILURE,"\"%s\": account expired.",p->user));
        }

        /* Check if password is valid */
        if (pwd->sp_max > 0 && today > pwd->sp_lstchg+pwd->sp_max) {
            sleep(SLEEP_SECONDS);
            return (pop_msg(p,POP_FAILURE,"\"%s\": account expired.",p->user));
        }

        pw->pw_passwd = (char *)strdup(pwd->sp_pwdp);
        endspent();
    }

    /* We don't accept connections from users with null passwords */
    /* Compare the supplied password with the password file entry */
    if ((pw->pw_passwd == NULL) || (*pw->pw_passwd == '\0') ||
                strcmp(crypt(p->pop_parm[1], pw->pw_passwd), pw->pw_passwd)) {
        sleep(SLEEP_SECONDS);
        return (pop_msg(p, POP_FAILURE, pwerrmsg, p->user));
    }

    return(POP_SUCCESS);
}

#endif /* SOLARIS2 || AUX */

#if defined(PTX) || defined(ISC)

#include <shadow.h>

static int
auth_user(p, pw)
POP * p;
struct passwd *pw;
{
    register struct spwd * pwd;
    long today;

    /* Look for the user in the shadow password file */
    if ((pwd = getspnam(p->user)) == NULL) {
        if (!strcmp(pw->pw_passwd, "x")) { /* This my be a YP entry */
            sleep(SLEEP_SECONDS);
            return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
        }
    } else {
        pw->pw_passwd = (char *)strdup(pwd->sp_pwdp);
    }

    /* We don't accept connections from users with null passwords */
    /* Compare the supplied password with the password file entry */
    if ((pw->pw_passwd == NULL) || (*pw->pw_passwd == '\0') ||
                strcmp(crypt(p->pop_parm[1], pw->pw_passwd), pw->pw_passwd)) {
        sleep(SLEEP_SECONDS);
        return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
    }

    return(POP_SUCCESS);
}

#endif /* PTX */

#if defined(POPSCO) || defined(HPUX10)

#ifdef POPSCO
# include <sys/security.h>
# include <sys/audit.h>
#else
# include <hpsecurity.h>
#endif

#include <prot.h>
#define PASSWD(p) p->ufld.fd_encrypt

static int
auth_user(p, pw)
POP * p;
struct passwd *pw;
{
    register struct pr_passwd *pr;

    if ((pr = getprpwnam(p->user)) == NULL) {
        if (!strcmp(pw->pw_passwd, "x")) {
            sleep(SLEEP_SECONDS);
            return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
        }

        /* We don't accept connections from users with null passwords */
        if ((pw->pw_passwd == NULL) || (*pw->pw_passwd == '\0') ||
             (strcmp(bigcrypt(p->pop_parm[1], pw->pw_passwd), pw->pw_passwd) &&
              strcmp(crypt (p->pop_parm[1], pw->pw_passwd), pw->pw_passwd))) {
            sleep(SLEEP_SECONDS);
            return(pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
        }
    } else {
        /* We don't accept connections from users with null passwords */
        /* Compare the supplied password with the password file entry */
        if ((PASSWD(pr) == NULL) || (*PASSWD(pr) == '\0')) {
            sleep(SLEEP_SECONDS);
            return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
        }
        
        if (strcmp(bigcrypt(p->pop_parm[1], PASSWD(pr)), PASSWD(pr)) &&
                    strcmp(crypt(p->pop_parm[1], PASSWD(pr)), PASSWD(pr))) {
            sleep(SLEEP_SECONDS);
            return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
        }
    }

    return(POP_SUCCESS);
}

#endif /* POPSCO || HPUX10 */

#ifdef ULTRIX

#include <auth.h>

static int
auth_user(p, pw)
struct passwd * pw;
POP * p;
{
    AUTHORIZATION *auth, *getauthuid();

    if ((auth = getauthuid(pw->pw_uid)) == NULL) {
        if (!strcmp(pw->pw_passwd, "x")) { /* This my be a YP entry */
            sleep(SLEEP_SECONDS);
            return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
        }
    } else {
        pw->pw_passwd = (char *)strdup(auth->a_password);
    }

    /* We don't accept connections from users with null passwords */
    /* Compare the supplied password with the password file entry */
    if ((pw->pw_passwd == NULL) || (*pw->pw_passwd == '\0')) {
        sleep(SLEEP_SECONDS);
        return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
    }

    if (strcmp(crypt16(p->pop_parm[1], pw->pw_passwd), pw->pw_passwd) &&
                strcmp(crypt(p->pop_parm[1], pw->pw_passwd), pw->pw_passwd)) {
        sleep(SLEEP_SECONDS);
        return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
    }

    return(POP_SUCCESS);
}

#endif /* ULTRIX */

#ifdef OSF1
#include <sys/types.h>
#include <sys/security.h>
#include <prot.h>
#define PASSWD(p) (p->ufld.fd_encrypt)
static int
auth_user(p, pw)
POP * p;
struct passwd *pw;
{
    register struct pr_passwd *pr;

    if ((pr = getprpwnam(p->user)) == NULL) {
        if (!strcmp(pw->pw_passwd, "x")) { /* This my be a YP entry */
            sleep(SLEEP_SECONDS);
            return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
        }
    } else {
        pw->pw_passwd = (char *)strdup(PASSWD(pr));
    }

    /* We don't accept connections from users with null passwords */
    /* Compare the supplied password with the password file entry */
    if ((pw->pw_passwd == NULL) || (*pw->pw_passwd == '\0')) {
        sleep(SLEEP_SECONDS);
        return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
    }

    if (strcmp(bigcrypt(p->pop_parm[1], pw->pw_passwd), pw->pw_passwd) &&
                strcmp(crypt(p->pop_parm[1], pw->pw_passwd), pw->pw_passwd)) {
        sleep(SLEEP_SECONDS);
        return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
    }

    return(POP_SUCCESS);
}

#endif /* OSF1 */

#ifdef UNIXWARE

#include <shadow.h>

static int
auth_user(p, pw)
struct passwd * pw;
POP * p;
{
    register struct spwd * pwd;
    long today;

    /* Look for the user in the shadow password file */
    if ((pwd = getspnam(p->user)) == NULL) {
        if (!strcmp(pw->pw_passwd, "x")) { /* This my be a YP entry */
            sleep(SLEEP_SECONDS);
            return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
        }
    } else {
        today = (long)time((time_t *)NULL)/24/60/60;

        /* Check for expiration date */
        if (pwd->sp_expire > 0 && today > pwd->sp_expire) {
            sleep(SLEEP_SECONDS);
            return (pop_msg(p,POP_FAILURE,"\"%s\": account expired.",p->user));
        }

        /* Check if password is valid */
        if (pwd->sp_max > 0 && today > pwd->sp_lstchg+pwd->sp_max) {
            sleep(SLEEP_SECONDS);
            return (pop_msg(p,POP_FAILURE,"\"%s\": account expired.",p->user));
        }

        pw->pw_passwd = (char *)strdup(pwd->sp_pwdp);
        endspent();
    }

    /* We don't accept connections from users with null passwords */
    /* Compare the supplied password with the password file entry */
    if ((pw->pw_passwd == NULL) || (*pw->pw_passwd == '\0') ||
                strcmp(crypt(p->pop_parm[1], pw->pw_passwd), pw->pw_passwd)) {
        sleep(SLEEP_SECONDS);
        return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
    }

    return(POP_SUCCESS);
}

#endif /* UNIXWARE */

#ifdef LINUX
#include <shadow.h>
 
static int
auth_user(p, pw)
POP * p;
struct passwd *pw;
{
    register struct spwd * pwd;
    long today;

    /* Look for the user in the shadow password file */
    if ((pwd = getspnam(p->user)) == NULL) {
        if (!strcmp(pw->pw_passwd, "x")) { /* This my be a YP entry */
            sleep(SLEEP_SECONDS);
            return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
        }
    } else {
        today = (long)time((time_t *)NULL)/24/60/60;

        /* Check for expiration date */
        if (pwd->sp_expire > 0 && today > pwd->sp_expire) {
            sleep(SLEEP_SECONDS);
            return (pop_msg(p,POP_FAILURE,"\"%s\": account expired.",p->user));
        }

        /* Check if password is valid */
        if (pwd->sp_max > 0 && today > pwd->sp_lstchg+pwd->sp_max) {
            sleep(SLEEP_SECONDS);
            return (pop_msg(p,POP_FAILURE,"\"%s\": account expired.",p->user));
        }

        pw->pw_passwd = (char *)strdup(pwd->sp_pwdp);
        endspent();
    }

    /* We don't accept connections from users with null passwords */
    /* Compare the supplied password with the password file entry */
        /* pw_encrypt() ?? */
    if ((pw->pw_passwd == NULL) || (*pw->pw_passwd == '\0') ||
            (strcmp(crypt(p->pop_parm[1], pw->pw_passwd), pw->pw_passwd) &&
             strcmp(pw_encrypt(p->pop_parm[1], pw->pw_passwd), pw->pw_passwd))){
        sleep(SLEEP_SECONDS);
        return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
    }

    return(POP_SUCCESS);
}

#endif /* LINUX */

#else /* NOT AUTH */

char *crypt();

static int
auth_user(p, pw)
POP * p;
struct passwd * pw;
{
    /* We don't accept connections from users with null passwords */
    /* Compare the supplied password with the password file entry */

    if ((pw->pw_passwd == NULL) || (*pw->pw_passwd == '\0') ||
                strcmp(crypt(p->pop_parm[1], pw->pw_passwd), pw->pw_passwd)) {
        sleep(SLEEP_SECONDS);
        return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
    }

    return(POP_SUCCESS);
}

#endif /* AUTH */

/*
 * pass: Obtain the user password from a POP client
 */

#ifdef SECURENISPLUS
/* AUTH gets defined in rpc/... */
# ifdef AUTH
# undef AUTH
# endif
# include <rpc/rpc.h>
# include <rpc/key_prot.h>
#endif

int pop_pass (p)
POP * p;
{
    struct passwd pw, *pwp;
#ifdef CHECK_SHELL
    char *getusershell();
    void endusershell();
    char *shell;
    char *cp;
    int shellvalid;
#endif

#ifdef SECURENISPLUS
    UID_T uid_save;
    char net_name[MAXNETNAMELEN],
         secretkey[HEXKEYBYTES + 1];

    *secretkey = '\0';
#endif

#ifdef NONAUTHFILE
    /* Is the user not authorized to use POP? */
    if (checknonauthfile(p->user) != 0) {
        sleep(SLEEP_SECONDS);
        return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
    }
#endif

#ifdef AUTHFILE
    /* Is the user authorized to use POP? */
    if (checkauthfile(p->user) != 0) {
        sleep(SLEEP_SECONDS);
        return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
    }
#endif

    /* Look for the user in the password file */
    if ((pwp = getpwnam(p->user)) == NULL) {
        sleep(SLEEP_SECONDS);
        return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
    }

    pw = *pwp;

#ifdef SECURENISPLUS
    /* we must do this keyserv stuff (as well as auth_user()!) as the user */
    uid_save = geteuid();
    seteuid(pw.pw_uid);

    /* see if DES keys are already known to the keyserv(1m) */
    if (! key_secretkey_is_set()) {
        /* keys are not known, so we must get the DES keys
            and register with the keyserv(1m) */

        getnetname(net_name);

        if (getpublickey(net_name, secretkey)) {
            if (strlen(p->pop_parm[1]) > 8) (p->pop_parm[1])[8] = '\0';

            if (! getsecretkey(net_name, secretkey, p->pop_parm[1]) ||
                                                        *secretkey == '\0') {
                sleep(SLEEP_SECONDS);
                return (pop_msg(p,POP_FAILURE, pwerrmsg, p->user));
            }

            key_setsecret(secretkey);
            memset(secretkey, '\0', sizeof(secretkey));
        } else {
            /* if there are no keys defined, we assume that password entry
               either resides in /etc/shadow or "root" has access to the
               corresponding NIS+ entry */
            seteuid(0);
        }
    }
#endif

#ifdef BLOCK_UID
    if (pw.pw_uid <= BLOCK_UID)
        return (pop_msg(p,POP_FAILURE,
                            "Access is blocked for UIDs below %d", BLOCK_UID));
#endif

#ifdef CHECK_SHELL
    /* Disallow anyone who does not have a standard shell as returned by
     * getusershell(), unless the sys admin has included the wildcard
     * shell in /etc/shells. (default wildcard - /POPPER/ANY/SHELL)
     */
    if ((shell = pw.pw_shell) == NULL || *shell == 0)
/* You can default the shell, but I don't think it's a good idea */
/* shell = "/usr/bin/sh"; */
        return(pop_msg(p, POP_FAILURE, "No user shell defined"));
    
    for (shellvalid = 0; !shellvalid && ((cp = getusershell()) != NULL);)
        if (!strcmp(cp, WILDCARD_SHELL) || !strcmp(cp, shell))
             shellvalid = 1;
    endusershell();

    if (!shellvalid)
        return(pop_msg(p, POP_FAILURE, "\"%s\": shell not found.", p->user));
#endif

    if ((p->kerberos ? auth_user_kerberos(p, pw) : auth_user(p, pwp))
                                                        != POP_SUCCESS) {
            pop_log(p,POP_PRIORITY,"Failed attempted login to %s from host %s",
                                                            p->user, p->client);
        return(POP_FAILURE);
    }

#ifdef SECURENISPLUS
    seteuid(uid_save);
#endif

    /* Make a temporary copy of the user's maildrop */
    /* and set the group and user id */
    /* and get information about the maildrop */
    if (pop_dropcopy(p, &pw) != POP_SUCCESS) return (POP_FAILURE);

    /* Initialize the last-message-accessed number */
    p->last_msg = 0;

    /* Authorization completed successfully */
    return (pop_msg (p,POP_SUCCESS,
        "%s has %d message%s (%d octets).",
            p->user,p->msg_count, p->msg_count == 1 ? "" : "s", p->drop_size));
}

Received on Tue Feb 03 1998 - 02:36:00 NZDT

This archive was generated by hypermail 2.4.0 : Wed Nov 08 2023 - 11:53:37 NZDT