示例#1
0
PAM_EXTERN
int pam_sm_authenticate(pam_handle_t *pamh, int flags,
			int argc, const char **argv)
{
     const char *username;
     const char *password;
     int retval = PAM_AUTH_ERR;
    
     /* parse arguments */
     ctrl = _pam_parse(argc, argv);

     /* Get the username */
     retval = pam_get_user(pamh, &username, NULL);
     if ((retval != PAM_SUCCESS) || (!username)) {
        if (ctrl & PAM_DEBUG_ARG)
            _pam_log(LOG_DEBUG,"can not get the username");
        return PAM_SERVICE_ERR;
     }
     
     /* Converse just to be sure we have the password */
     retval = conversation(pamh);
     if (retval != PAM_SUCCESS) {
	 _pam_log(LOG_ERR, "could not obtain password for `%s'",
		  username);
	 return -2;
     }
     
     /* Get the password */
     retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&password);
     if (retval != PAM_SUCCESS) {
	 _pam_log(LOG_ERR, "Could not retrive user's password");
	 return -2;
     }
     
     if (ctrl & PAM_DEBUG_ARG)
	 _pam_log(LOG_INFO, "Verify user `%s' with password `%s'",
		  username, password);
     
     /* Now use the username to look up password in the database file */
     retval = user_lookup(username, password);
     switch (retval) {
	 case -2:
	     /* some sort of system error. The log was already printed */
	     return PAM_SERVICE_ERR;    
	 case -1:
	     /* incorrect password */
	     _pam_log(LOG_WARNING,
		      "user `%s' denied access (incorrect password)",
		      username);
	     return PAM_AUTH_ERR;
	 case 1:
	     /* the user does not exist in the database */
	     if (ctrl & PAM_DEBUG_ARG)
		 _pam_log(LOG_NOTICE, "user `%s' not found in the database",
			  username);
	     return PAM_USER_UNKNOWN;
	 case 0:
	     /* Otherwise, the authentication looked good */
	     _pam_log(LOG_NOTICE, "user '%s' granted acces", username);
	     return PAM_SUCCESS;
	 default:
	     /* we don't know anything about this return value */
	     _pam_log(LOG_ERR,
		      "internal module error (retval = %d, user = `%s'",
		      retval, username);
	     return PAM_SERVICE_ERR;
     }

     /* should not be reached */
     return PAM_IGNORE;
}
示例#2
0
/*
 * Send an accounting record to the TACACS+ server.
 * We send the start/stop accounting records even if the user is not known
 * to the TACACS+ server.   This seems non-intuitive, but it's the way
 * this code is written to work.
 */
int _pam_account(pam_handle_t *pamh, int argc, const char **argv,
    int type, char *cmd) {

    int retval;
    int ctrl;
    char *user = NULL;
    char *tty = NULL;
    char *r_addr = NULL;
    char *typemsg;
    int status = PAM_SESSION_ERR;
    int srv_i, tac_fd;

    typemsg = tac_acct_flag2str(type);
    ctrl = _pam_parse (argc, argv);

    if (ctrl & PAM_TAC_DEBUG)
        syslog (LOG_DEBUG, "%s: [%s] called (pam_tacplus v%u.%u.%u)",
            __func__, typemsg, PAM_TAC_VMAJ, PAM_TAC_VMIN, PAM_TAC_VPAT);

    _pam_get_user(pamh, &user);
    if (user == NULL)
        return PAM_USER_UNKNOWN;

    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: username [%s] obtained", __func__, user);

    if (!task_id)
#if defined(HAVE_OPENSSL_RAND_H) && defined(HAVE_LIBCRYPTO)
        RAND_pseudo_bytes((unsigned char *) &task_id, sizeof(task_id));
#else
        task_id = (short unsigned int) tac_magic();
#endif

    _pam_get_terminal(pamh, &tty);
    if(!strncmp(tty, "/dev/", 5))
        tty += 5;
    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: tty [%s] obtained", __func__, tty);

    _pam_get_rhost(pamh, &r_addr);
    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: rhost [%s] obtained", __func__, r_addr);

    /* checks for specific data required by TACACS+, which should
       be supplied in command line  */
    if(tac_protocol[0] == '\0') {
        _pam_log (LOG_ERR, "ACC: TACACS+ protocol type not configured");
        return PAM_AUTH_ERR;
    }

    /* when this module is called from within pppd or other
       application dealing with serial lines, it is likely
       that we will get hit with signal caused by modem hangup;
       this is important only for STOP packets, it's relatively
       rare that modem hangs up on accounting start */
    if(type == TAC_PLUS_ACCT_FLAG_STOP) {
        signal(SIGALRM, SIG_IGN);
        signal(SIGCHLD, SIG_IGN);
        signal(SIGHUP, SIG_IGN);
    }

    /*
     * If PAM_SESSION_ERR is used, then the pam config can't
     * ignore server failures, so use PAM_AUTHINFO_UNAVAIL.
     *
     * We have to make a new connection each time, because libtac is single
     * threaded (doesn't support multiple connects at the same time due to
     * use of globals)), and doesn't have support for persistent connections.
     * That's fixable, but not worth the effort at this point.
     *
     * TODO: this should be converted to use do_tac_connect eventually.
     */
    status = PAM_AUTHINFO_UNAVAIL;
    for(srv_i = 0; srv_i < tac_srv_no; srv_i++) {
        tac_fd = tac_connect_single(tac_srv[srv_i].addr, tac_srv[srv_i].key,
            NULL, __vrfname);
        if (tac_fd < 0) {
            _pam_log(LOG_WARNING, "%s: error sending %s (fd)", __func__,
                typemsg);
            continue;
        }
        if (ctrl & PAM_TAC_DEBUG)
            syslog(LOG_DEBUG, "%s: connected with fd=%d to srv[%d] %s", __func__,
                tac_fd, srv_i, tac_srv[srv_i].addr ?
                tac_ntop(tac_srv[srv_i].addr->ai_addr) : "not set");

        retval = _pam_send_account(tac_fd, type, user, tty, r_addr, cmd);
        if (retval < 0) {
            _pam_log(LOG_WARNING, "%s: error sending %s (acct)",
                __func__, typemsg);
        } else {
            status = PAM_SUCCESS;
            if (ctrl & PAM_TAC_DEBUG)
                syslog(LOG_DEBUG, "%s: [%s] for [%s] sent", __func__, typemsg, user);
        }

        if ((status == PAM_SUCCESS) && !(ctrl & PAM_TAC_ACCT)) {
            /* do not send acct start/stop packets to _all_ servers */
            break;
        }
    }

    if (type == TAC_PLUS_ACCT_FLAG_STOP) {
        signal(SIGALRM, SIG_DFL);
        signal(SIGCHLD, SIG_DFL);
        signal(SIGHUP, SIG_DFL);
    }
    return status;
}
示例#3
0
/* no-op function for future use */
PAM_EXTERN
int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
    int argc, const char **argv) {

    int ctrl, retval;
    char *user;
    char *pass;
    char *tty;
    char *r_addr;
    const void *pam_pass = NULL;
    int srv_i;
    int tac_fd, status, msg, communicating;

    user = pass = tty = r_addr = NULL;

    ctrl = _pam_parse(argc, argv);

    if (ctrl & PAM_TAC_DEBUG)
        syslog (LOG_DEBUG, "%s: called (pam_tacplus v%u.%u.%u)"
            , __FUNCTION__, PAM_TAC_VMAJ, PAM_TAC_VMIN, PAM_TAC_VPAT);

    syslog(LOG_DEBUG, "%s(flags=%d, argc=%d)", __func__, flags, argc);

    if (   (pam_get_item(pamh, PAM_OLDAUTHTOK, &pam_pass) == PAM_SUCCESS)
        && (pam_pass != NULL) ) {
         if ((pass = strdup(pam_pass)) == NULL)
              return PAM_BUF_ERR;
    } else {
        pass = strdup("");
    }
    
    if ((user = _pam_get_user(pamh)) == NULL)
        return PAM_USER_UNKNOWN;
    
    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: user [%s] obtained", __FUNCTION__, user);

    tty = _pam_get_terminal(pamh);
    if (!strncmp(tty, "/dev/", 5))
        tty += 5;
    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: tty [%s] obtained", __FUNCTION__, tty);

    r_addr = _pam_get_rhost(pamh);
    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: rhost [%s] obtained", __FUNCTION__, r_addr);

    if (PAM_SILENT == (flags & PAM_SILENT)) {
        status = PAM_AUTHTOK_ERR;
        goto finish;
    }

    status = PAM_TRY_AGAIN;
    for (srv_i = 0; srv_i < tac_srv_no; srv_i++) {
        if (ctrl & PAM_TAC_DEBUG)
            syslog(LOG_DEBUG, "%s: trying srv %d", __FUNCTION__, srv_i );

        tac_fd = tac_connect_single(tac_srv[srv_i].addr, tac_srv[srv_i].key, NULL, tac_timeout);
        if (tac_fd < 0) {
            _pam_log(LOG_ERR, "connection failed srv %d: %m", srv_i);
            continue;
        }
        if (PAM_PRELIM_CHECK == (flags & PAM_PRELIM_CHECK)) {
            if (PAM_TAC_DEBUG == (ctrl & PAM_TAC_DEBUG))
                syslog(LOG_DEBUG, "%s: finishing PAM_PRELIM_CHECK with srv %d",
                       __FUNCTION__, srv_i);

            close(tac_fd);
            status = PAM_SUCCESS;
            goto finish;
        }

        if (tac_authen_send(tac_fd, user, "", tty, r_addr, TAC_PLUS_AUTHEN_CHPASS) < 0) {
            close(tac_fd);
            _pam_log(LOG_ERR, "error sending auth req to TACACS+ server");
            continue;
        }
        communicating = 1;
        while (communicating) {
            struct areply re = { .attr = NULL, .msg = NULL, status = 0, flags = 0 };
            struct pam_message conv_msg = { .msg_style = 0, .msg = NULL };
            struct pam_response *resp = NULL;

            msg = tac_authen_read(tac_fd, &re);

            if (NULL != re.msg) {
                conv_msg.msg = re.msg;
            }

            /* talk the protocol */
            switch (msg) {
                case TAC_PLUS_AUTHEN_STATUS_PASS:
                    /* success */
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_PASS");

                    if (NULL != conv_msg.msg) {
                        int retval = -1;

                        conv_msg.msg_style = PAM_TEXT_INFO;
                        retval = converse(pamh, 1, &conv_msg, &resp);
                        if (PAM_SUCCESS == retval) {
                            if (PAM_TAC_DEBUG == (ctrl & PAM_TAC_DEBUG))
                                syslog(LOG_DEBUG, "send msg=\"%s\"", conv_msg.msg);
                        }
                        else {
                            _pam_log(LOG_WARNING, "%s: error sending msg=\"%s\", retval=%d",
                                     __FUNCTION__, conv_msg.msg, retval);
                        }

                    }
                    status = PAM_SUCCESS;
                    communicating = 0;

                    active_server.addr = tac_srv[srv_i].addr;
                    active_server.key = tac_srv[srv_i].key;

                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "%s: active srv %d", __FUNCTION__, srv_i);

                    break;

                case TAC_PLUS_AUTHEN_STATUS_FAIL:
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_FAIL");

                    if (NULL != conv_msg.msg) {
                        int retval = -1;

                        conv_msg.msg_style = PAM_ERROR_MSG;
                        retval = converse(pamh, 1, &conv_msg, &resp);
                        if (PAM_SUCCESS == retval) {
                            if (PAM_TAC_DEBUG == (ctrl & PAM_TAC_DEBUG))
                                syslog(LOG_DEBUG, "send msg=\"%s\"", conv_msg.msg);
                        }
                        else {
                            _pam_log(LOG_WARNING, "%s: error sending msg=\"%s\", retval=%d",
                                     __FUNCTION__, conv_msg.msg, retval);
                        }

                    }
                    status = PAM_AUTHTOK_ERR;
                    communicating = 0;

                    _pam_log(LOG_ERR, "chauthtok failed: %d", msg);

                    break;

                case TAC_PLUS_AUTHEN_STATUS_GETDATA:
                    if (PAM_TAC_DEBUG == (ctrl & PAM_TAC_DEBUG))
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_GETDATA");

                    if (NULL != conv_msg.msg) {
                        int retval = -1;
                        int echo_off = (0x1 == (re.flags & 0x1));
                        
                        conv_msg.msg_style = echo_off ? PAM_PROMPT_ECHO_OFF : PAM_PROMPT_ECHO_ON;
                        retval = converse(pamh, 1, &conv_msg, &resp);
                        if (PAM_SUCCESS == retval) {
                            if (PAM_TAC_DEBUG == (ctrl & PAM_TAC_DEBUG)) 
                                syslog(LOG_DEBUG, "sent msg=\"%s\", resp=\"%s\"",
                                       conv_msg.msg, resp->resp);

                            if (PAM_TAC_DEBUG == (ctrl & PAM_TAC_DEBUG))
                                syslog(LOG_DEBUG, "%s: calling tac_cont_send", __FUNCTION__);

                            if (0 > tac_cont_send_seq(tac_fd, resp->resp, re.seq_no + 1)) {
                                _pam_log(LOG_ERR, "error sending continue req to TACACS+ server");
                                communicating = 0;
                            }
                        }
                        else {
                            _pam_log(LOG_WARNING, "%s: error sending msg=\"%s\", retval=%d",
                                     __FUNCTION__, conv_msg.msg, retval);
                            communicating = 0;
                        }
                    }
                    else { 
                        syslog(LOG_ERR, "GETDATA response with no message, returning PAM_TRY_AGAIN");
                        communicating = 0;
                    }

                    break;

                case TAC_PLUS_AUTHEN_STATUS_GETUSER:
                    /* not implemented */
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_GETUSER");

                    communicating = 0;
                    break;

                case TAC_PLUS_AUTHEN_STATUS_GETPASS:
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_GETPASS");

                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "%s: calling tac_cont_send", __FUNCTION__);

                    if (tac_cont_send(tac_fd, pass) < 0) {
                        _pam_log (LOG_ERR, "error sending continue req to TACACS+ server");
                        communicating = 0;
                        break;
                    }
                    /* continue the while loop; go read tac response */
                    break;

                case TAC_PLUS_AUTHEN_STATUS_RESTART:
                    /* try it again */
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_RESTART");

                    /*
                     * not implemented
                     * WdJ: I *think* you can just do tac_authen_send(user, pass) again
                     *      but I'm not sure
                     */
                    communicating = 0;
                    break;

                case TAC_PLUS_AUTHEN_STATUS_ERROR:
                    /* server has problems */
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_ERROR");

                    communicating = 0;
                    break;

                case TAC_PLUS_AUTHEN_STATUS_FOLLOW:
                    /* server tells to try a different server address */
                    /* not implemented */
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_FOLLOW");

                    communicating = 0;
                    break;

                default:
                    if (msg < 0) {
                        /* connection error */
                        communicating = 0;
                        if (ctrl & PAM_TAC_DEBUG)
                            syslog(LOG_DEBUG, "error communicating with tacacs server");
                        break;
                    }

                    /* unknown response code */
                    communicating = 0;
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: unknown response 0x%02x", msg);
            }

            if (NULL != resp) {
                free(resp->resp);
                free(resp);
            }

            free(re.msg);

        }    /* end while(communicating) */
        close(tac_fd);

        if (status == PAM_SUCCESS || status == PAM_AUTHTOK_ERR)
            break;
    }

finish:
    if (status != PAM_SUCCESS && status != PAM_AUTHTOK_ERR)
        _pam_log(LOG_ERR, "no more servers to connect");

    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: exit with pam status: %d", __FUNCTION__, status);

    if (NULL != pass) {
        bzero(pass, strlen(pass));
        free(pass);
        pass = NULL;
    }

    return status;
}    /* pam_sm_chauthtok */
#endif


#ifdef PAM_STATIC
struct pam_module _pam_tacplus_modstruct {
    "pam_tacplus",
    pam_sm_authenticate,
    pam_sm_setcred,
    pam_sm_acct_mgmt,
    pam_sm_open_session,
    pam_sm_close_session,
#ifdef PAM_SM_PASSWORD
    pam_sm_chauthtok
#else
    NULL
#endif
};
示例#4
0
PAM_EXTERN
int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc
			,const char **argv)
{
     int ctrl;
     const char *username;
     char *fromsu;
     struct passwd *pwd, *tpwd;
     struct group *grp;
     int retval = PAM_AUTH_ERR;
     char use_group[BUFSIZ];
    
     /* Init the optional group */
     bzero(use_group,BUFSIZ);
     
     ctrl = _pam_parse(argc, argv, use_group);
     retval = pam_get_user(pamh,&username,NULL);
     if ((retval != PAM_SUCCESS) || (!username)) {
        if (ctrl & PAM_DEBUG_ARG)
            _pam_log(LOG_DEBUG,"can not get the username");
        return PAM_SERVICE_ERR;
     }

     /* su to a uid 0 account ? */
     pwd = getpwnam(username);
     if (!pwd) {
        if (ctrl & PAM_DEBUG_ARG)
            _pam_log(LOG_NOTICE,"unknown user %s",username);
        return PAM_USER_UNKNOWN;
     }
     
     /* Now we know that the username exists, pass on to other modules...
      * the call to pam_get_user made this obsolete, so is commented out
      *
      * pam_set_item(pamh,PAM_USER,(const void *)username);
      */

     /* is this user an UID 0 account ? */
     if(pwd->pw_uid) {
        /* no need to check for wheel */
        return PAM_IGNORE;
     }
     
     if (ctrl & PAM_USE_UID_ARG) {
         tpwd = getpwuid(getuid());
         if (!tpwd) {
            if (ctrl & PAM_DEBUG_ARG)
                _pam_log(LOG_NOTICE,"who is running me ?!");
            return PAM_SERVICE_ERR;
         }
         fromsu = tpwd->pw_name;
     } else {
         fromsu = getlogin();
         if (!fromsu) {
             if (ctrl & PAM_DEBUG_ARG)
                _pam_log(LOG_NOTICE,"who is running me ?!");
             return PAM_SERVICE_ERR;
         }
     }
     
     if (!use_group[0]) {
	 if ((grp = getgrnam("wheel")) == NULL) {
	     grp = getgrgid(0);
	 }
     } else
	 grp = getgrnam(use_group);
        
     if (!grp || !grp->gr_mem) {
        if (ctrl & PAM_DEBUG_ARG) {
            if (!use_group[0])
                _pam_log(LOG_NOTICE,"no members in a GID 0 group");
            else
                _pam_log(LOG_NOTICE,"no members in '%s' group",use_group);
        }
        if (ctrl & PAM_DENY_ARG)
            /* if this was meant to deny access to the members
             * of this group and the group does not exist, allow
             * access
             */
            return PAM_IGNORE;
        else
            return PAM_AUTH_ERR;
     }
        
     if (is_on_list(grp->gr_mem, fromsu)) {
        if (ctrl & PAM_DEBUG_ARG)
            _pam_log(LOG_NOTICE,"Access %s to '%s' for '%s'",
                     (ctrl & PAM_DENY_ARG)?"denied":"granted",
                     fromsu,username);
        if (ctrl & PAM_DENY_ARG)
            return PAM_PERM_DENIED;
        else
            if (ctrl & PAM_TRUST_ARG)
                return PAM_SUCCESS;
            else
                return PAM_IGNORE;
     }

     if (ctrl & PAM_DEBUG_ARG)
        _pam_log(LOG_NOTICE,"Access %s for '%s' to '%s'",
        (ctrl & PAM_DENY_ARG)?"granted":"denied",fromsu,username);
     if (ctrl & PAM_DENY_ARG)
        return PAM_SUCCESS;
     else
        return PAM_PERM_DENIED;
}
示例#5
0
/* now the session stuff */
PAM_EXTERN int
pam_sm_open_session (pam_handle_t *pamh, int flags UNUSED,
		     int argc, const char **argv)
{
    int retval;
    int i;
    int glob_rc;
    char *user_name;
    struct passwd *pwd;
    int ctrl;
    struct pam_limit_s plstruct;
    struct pam_limit_s *pl = &plstruct;
    glob_t globbuf;
    const char *oldlocale;

    D(("called."));

    memset(pl, 0, sizeof(*pl));
    memset(&globbuf, 0, sizeof(globbuf));

    ctrl = _pam_parse(pamh, argc, argv, pl);
    retval = pam_get_item( pamh, PAM_USER, (void*) &user_name );
    if ( user_name == NULL || retval != PAM_SUCCESS ) {
        pam_syslog(pamh, LOG_CRIT, "open_session - error recovering username");
        return PAM_SESSION_ERR;
     }

    pwd = pam_modutil_getpwnam(pamh, user_name);
    if (!pwd) {
        if (ctrl & PAM_DEBUG_ARG)
            pam_syslog(pamh, LOG_WARNING,
		       "open_session username '%s' does not exist", user_name);
        return PAM_USER_UNKNOWN;
    }

    retval = init_limits(pamh, pl, ctrl);
    if (retval != PAM_SUCCESS) {
        pam_syslog(pamh, LOG_WARNING, "cannot initialize");
        return PAM_ABORT;
    }

    retval = parse_config_file(pamh, pwd->pw_name, pwd->pw_uid, pwd->pw_gid, ctrl, pl);
    if (retval == PAM_IGNORE) {
	D(("the configuration file ('%s') has an applicable '<domain> -' entry", CONF_FILE));
	return PAM_SUCCESS;
    }
    if (retval != PAM_SUCCESS || pl->conf_file != NULL)
	/* skip reading limits.d if config file explicitely specified */
	goto out;

    /* Read subsequent *.conf files, if they exist. */

    /* set the LC_COLLATE so the sorting order doesn't depend
	on system locale */

    oldlocale = setlocale(LC_COLLATE, "C");
    glob_rc = glob(LIMITS_CONF_GLOB, GLOB_ERR, NULL, &globbuf);

    if (oldlocale != NULL)
	setlocale (LC_COLLATE, oldlocale);

    if (!glob_rc) {
	/* Parse the *.conf files. */
	for (i = 0; globbuf.gl_pathv[i] != NULL; i++) {
	    pl->conf_file = globbuf.gl_pathv[i];
    	    retval = parse_config_file(pamh, pwd->pw_name, pwd->pw_uid, pwd->pw_gid, ctrl, pl);
    	    if (retval == PAM_IGNORE) {
		D(("the configuration file ('%s') has an applicable '<domain> -' entry", pl->conf_file));
		globfree(&globbuf);
		return PAM_SUCCESS;
      	    }
	    if (retval != PAM_SUCCESS)
		goto out;
        }
    }

out:
    globfree(&globbuf);
    if (retval != PAM_SUCCESS)
    {
       	pam_syslog(pamh, LOG_WARNING, "error parsing the configuration file: '%s' ",CONF_FILE);
	return retval;
    }

    retval = setup_limits(pamh, pwd->pw_name, pwd->pw_uid, ctrl, pl);
    if (retval & LOGIN_ERR)
	pam_error(pamh, _("Too many logins for '%s'."), pwd->pw_name);
    if (retval != LIMITED_OK) {
        return PAM_PERM_DENIED;
    }

    return PAM_SUCCESS;
}
示例#6
0
文件: pam_mail.c 项目: aosm/pam
static int _do_mail(pam_handle_t *pamh, int flags, int argc,
    const char **argv, int est)
{
    int retval, ctrl, hashcount;
    char *path_mail=NULL, *folder;
    const char *type;

    /*
     * this module (un)sets the MAIL environment variable, and checks if
     * the user has any new mail.
     */

    ctrl = _pam_parse(flags, argc, argv, &path_mail, &hashcount);

    /* Do we have anything to do? */

    if (flags & PAM_SILENT)
	return PAM_SUCCESS;

    /* which folder? */

    retval = get_folder(pamh, ctrl, &path_mail, &folder, hashcount);
    if (retval != PAM_SUCCESS) {
	D(("failed to find folder"));
	return retval;
    }

    /* set the MAIL variable? */

    if (!(ctrl & PAM_NO_ENV) && est) {
	char *tmp;

	tmp = malloc(strlen(folder)+sizeof(MAIL_ENV_FORMAT));
	if (tmp != NULL) {
	    sprintf(tmp, MAIL_ENV_FORMAT, folder);
	    D(("setting env: %s", tmp));
	    retval = pam_putenv(pamh, tmp);
	    _pam_overwrite(tmp);
	    _pam_drop(tmp);
	    if (retval != PAM_SUCCESS) {
		_pam_overwrite(folder);
		_pam_drop(folder);
		_log_err(LOG_CRIT, "unable to set " MAIL_ENV_NAME " variable");
		return retval;
	    }
	} else {
	    _log_err(LOG_CRIT, "no memory for " MAIL_ENV_NAME " variable");
	    _pam_overwrite(folder);
	    _pam_drop(folder);
	    return retval;
	}
    } else {
	D(("not setting " MAIL_ENV_NAME " variable"));
    }

    /*
     * OK. we've got the mail folder... what about its status?
     */

    if ((est && !(ctrl & PAM_NO_LOGIN))
	|| (!est && (ctrl & PAM_LOGOUT_TOO))) {
	type = get_mail_status(ctrl, folder);
	if (type != NULL) {
	    retval = report_mail(pamh, ctrl, type, folder);
	    type = NULL;
	}
    }
    
    /* Delete environment variable? */  
    if (!est)
	(void) pam_putenv(pamh, MAIL_ENV_NAME);

    _pam_overwrite(folder); /* clean up */
    _pam_drop(folder);

    /* indicate success or failure */

    return retval;
}
示例#7
0
/* authorizes user on remote TACACS+ server, i.e. checks
 * his permission to access requested service
 * returns PAM_SUCCESS if the service is allowed
 */
PAM_EXTERN 
int pam_sm_acct_mgmt (pam_handle_t * pamh, int flags,
    int argc, const char **argv) {

    int retval, ctrl, status=PAM_AUTH_ERR;
    char *user;
    char *tty;
    char *r_addr;
    struct areply arep;
    struct tac_attrib *attr = NULL;
    int tac_fd;

    user = tty = r_addr = NULL;
  
    /* this also obtains service name for authorization
       this should be normally performed by pam_get_item(PAM_SERVICE)
       but since PAM service names are incompatible TACACS+
       we have to pass it via command line argument until a better
       solution is found ;) */
    ctrl = _pam_parse (argc, argv);

    if (ctrl & PAM_TAC_DEBUG)
        _pam_log (LOG_DEBUG, "%s: called (pam_tacplus v%u.%u.%u)"
            , __FUNCTION__, PAM_TAC_VMAJ, PAM_TAC_VMIN, PAM_TAC_VPAT);
  
    if ((user = _pam_get_user(pamh)) == NULL)
        return PAM_USER_UNKNOWN;

    if (ctrl & PAM_TAC_DEBUG)
        _pam_log(LOG_DEBUG, "%s: username obtained [%s]", __FUNCTION__, user);
  
    tty = _pam_get_terminal(pamh);
    if(!strncmp(tty, "/dev/", 5)) 
        tty += 5;
    if (ctrl & PAM_TAC_DEBUG)
        _pam_log(LOG_DEBUG, "%s: tty obtained [%s]", __FUNCTION__, tty);

    r_addr = _pam_get_rhost(pamh);
    if (ctrl & PAM_TAC_DEBUG)
        _pam_log(LOG_DEBUG, "%s: rhost obtained [%s]", __FUNCTION__, r_addr);
  
    /* checks if user has been successfully authenticated
       by TACACS+; we cannot solely authorize user if it hasn't
       been authenticated or has been authenticated by method other
       than TACACS+ */
    if(!active_server) {
        _pam_log (LOG_ERR, "user not authenticated by TACACS+");
        return PAM_AUTH_ERR;
    }
    if (ctrl & PAM_TAC_DEBUG)
        _pam_log (LOG_DEBUG, "%s: active server is [%s]", __FUNCTION__,
            tac_ntop(active_server->ai_addr, active_server->ai_addrlen));

    /* checks for specific data required by TACACS+, which should
       be supplied in command line  */
    if(tac_service == NULL || *tac_service == '\0') {
        _pam_log (LOG_ERR, "TACACS+ service type not configured");
        return PAM_AUTH_ERR;
    }
    if(tac_protocol == NULL || *tac_protocol == '\0') {
        _pam_log (LOG_ERR, "TACACS+ protocol type not configured");
        return PAM_AUTH_ERR;
    }

    tac_add_attrib(&attr, "service", tac_service);
    tac_add_attrib(&attr, "protocol", tac_protocol);

    tac_fd = tac_connect_single(active_server, active_key);
    if(tac_fd < 0) {
        _pam_log (LOG_ERR, "TACACS+ server unavailable");
        if(arep.msg != NULL) free (arep.msg);
        close(tac_fd);
        return PAM_AUTH_ERR;
    }

    retval = tac_author_send(tac_fd, user, tty, r_addr, attr);

    tac_free_attrib(&attr);
  
    if(retval < 0) {
        _pam_log (LOG_ERR, "error getting authorization");
        if(arep.msg != NULL) free (arep.msg);
        close(tac_fd);
        return PAM_AUTH_ERR;
    }

    if (ctrl & PAM_TAC_DEBUG)
        _pam_log(LOG_DEBUG, "%s: sent authorization request", __FUNCTION__);
  
    tac_author_read(tac_fd, &arep);

    if(arep.status != AUTHOR_STATUS_PASS_ADD &&
        arep.status != AUTHOR_STATUS_PASS_REPL) {

        _pam_log (LOG_ERR, "TACACS+ authorisation failed for [%s]", user);
        if(arep.msg != NULL) free (arep.msg);
        close(tac_fd);
        return PAM_PERM_DENIED;
    }

    if (ctrl & PAM_TAC_DEBUG)
        _pam_log(LOG_DEBUG, "%s: user [%s] successfully authorized", __FUNCTION__, user);
  
    status = PAM_SUCCESS;
  
    attr = arep.attr;
    while (attr != NULL)  {
        char attribute[attr->attr_len];
        char value[attr->attr_len];
        char *sep;

        sep = index(attr->attr, '=');
        if(sep == NULL)
            sep = index(attr->attr, '*');
        if(sep != NULL) {
            bcopy(attr->attr, attribute, attr->attr_len-strlen(sep));
            attribute[attr->attr_len-strlen(sep)] = '\0';
            bcopy(sep, value, strlen(sep));
            value[strlen(sep)] = '\0';

            size_t i;
            for (i = 0; attribute[i] != '\0'; i++) {
                attribute[i] = toupper(attribute[i]);
                if (attribute[i] == '-')
                    attribute[i] = '_';
            }

            if (ctrl & PAM_TAC_DEBUG)
                _pam_log(LOG_DEBUG, "%s: returned attribute `%s%s' from server", __FUNCTION__, attribute, value);

            /* make returned attributes available for other PAM modules via PAM environment */
            if (pam_putenv(pamh, strncat(attribute, value, strlen(value))) != PAM_SUCCESS)
                _pam_log(LOG_WARNING, "%s: unable to set PAM environment", __FUNCTION__);

        } else {
            _pam_log(LOG_WARNING, "%s: invalid attribute `%s', no separator", __FUNCTION__, attr->attr);
        }
        attr = attr->next;
    }

    /* free returned attributes */
    if(arep.attr != NULL) tac_free_attrib(&arep.attr);
    if(arep.msg != NULL) free (arep.msg);
    close(tac_fd);

    return status;
}    /* pam_sm_acct_mgmt */
示例#8
0
/* Tested for servers that require password change during challenge/response */
PAM_EXTERN
int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
    int argc, const char **argv) {

    int ctrl;
    char *user;
    char *pass;
    char *tty;
    char *r_addr;
    const void *pam_pass = NULL;
    int srv_i;
    int status;

    user = pass = tty = r_addr = NULL;

    ctrl = _pam_parse(argc, argv);

    if (ctrl & PAM_TAC_DEBUG)
        syslog (LOG_DEBUG, "%s: called (pam_tacplus v%u.%u.%u) (flags=%d, argc=%d)",
            __func__, PAM_TAC_VMAJ, PAM_TAC_VMIN, PAM_TAC_VPAT, flags, argc);

    if (   (pam_get_item(pamh, PAM_OLDAUTHTOK, &pam_pass) == PAM_SUCCESS)
        && (pam_pass != NULL) ) {
         if ((pass = strdup(pam_pass)) == NULL)
              return PAM_BUF_ERR;
    } else {
        pass = strdup("");
    }

    _pam_get_user(pamh, &user);
    if (user == NULL) {
        if(pass) {
                free(pass);
        }
        return PAM_USER_UNKNOWN;
    }

    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: user [%s] obtained", __func__, user);

    _pam_get_terminal(pamh, &tty);
    if (tty && !strncmp(tty, "/dev/", 5))
        tty += 5;
    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: tty [%s] obtained", __func__, tty?tty:"UNKNOWN");

    _pam_get_rhost(pamh, &r_addr);
    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: rhost [%s] obtained", __func__, r_addr?r_addr:"UNKNOWN");

    if (PAM_SILENT != (flags & PAM_SILENT))
        status = do_tac_connect(ctrl, NULL, user, pass, tty, r_addr, NULL, NULL, pamh);
    else
        status = PAM_AUTHTOK_ERR;

    if (status != PAM_SUCCESS && status != PAM_AUTHTOK_ERR)
        _pam_log(LOG_ERR, "no more servers to connect");

    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: exit with pam status: %d", __func__, status);

    if (NULL != pass) {
        bzero(pass, strlen(pass));
        free(pass);
        pass = NULL;
    }

    return status;

}    /* pam_sm_chauthtok */
示例#9
0
int _pam_account(pam_handle_t *pamh, int argc, const char **argv,
    int type, char *cmd) {

    int retval;
    static int ctrl;
    char *user = NULL;
    char *tty = NULL;
    char *r_addr = NULL;
    char *typemsg;
    int status = PAM_SESSION_ERR;
  
    typemsg = tac_acct_flag2str(type);
    ctrl = _pam_parse (argc, argv);

    if (ctrl & PAM_TAC_DEBUG)
        _pam_log (LOG_DEBUG, "%s: [%s] called (pam_tacplus v%u.%u.%u)"
            , __FUNCTION__, typemsg, PAM_TAC_VMAJ, PAM_TAC_VMIN, PAM_TAC_VPAT);
    if (ctrl & PAM_TAC_DEBUG)
        _pam_log(LOG_DEBUG, "%s: tac_srv_no=%d", __FUNCTION__, tac_srv_no);
  
    if ((user = _pam_get_user(pamh)) == NULL)
        return PAM_USER_UNKNOWN;

    if (ctrl & PAM_TAC_DEBUG)
        _pam_log(LOG_DEBUG, "%s: username [%s] obtained", __FUNCTION__, user);
  
    tty = _pam_get_terminal(pamh);
    if(!strncmp(tty, "/dev/", 5)) 
        tty += 5;
    if (ctrl & PAM_TAC_DEBUG)
        _pam_log(LOG_DEBUG, "%s: tty [%s] obtained", __FUNCTION__, tty);

    r_addr = _pam_get_rhost(pamh);
    if (ctrl & PAM_TAC_DEBUG)
        _pam_log(LOG_DEBUG, "%s: rhost [%s] obtained", __FUNCTION__, r_addr);

    /* checks for specific data required by TACACS+, which should
       be supplied in command line  */
    if(tac_service == NULL || *tac_service == '\0') {
        _pam_log (LOG_ERR, "TACACS+ service type not configured");
        return PAM_AUTH_ERR;
    }
    if(tac_protocol == NULL || *tac_protocol == '\0') {
        _pam_log (LOG_ERR, "TACACS+ protocol type not configured");
        return PAM_AUTH_ERR;
    }

    /* when this module is called from within pppd or other
       application dealing with serial lines, it is likely
       that we will get hit with signal caused by modem hangup;
       this is important only for STOP packets, it's relatively
       rare that modem hangs up on accounting start */
    if(type == TAC_PLUS_ACCT_FLAG_STOP) {
        signal(SIGALRM, SIG_IGN);
        signal(SIGCHLD, SIG_IGN);
        signal(SIGHUP, SIG_IGN);
    }

    if(!(ctrl & PAM_TAC_ACCT)) {
    /* normal mode, send packet to the first available server */
        int srv_i = 0;
                  
        status = PAM_SESSION_ERR;
        while ((status == PAM_SESSION_ERR) && (srv_i < tac_srv_no)) {
            int tac_fd;
                                  
            tac_fd = tac_connect_single(tac_srv[srv_i], tac_srv_key[srv_i]);
            if(tac_fd < 0) {
                _pam_log(LOG_WARNING, "%s: error sending %s (fd)",
                    __FUNCTION__, typemsg);
                srv_i++;
                continue;
            }

            if (ctrl & PAM_TAC_DEBUG)
                _pam_log(LOG_DEBUG, "%s: connected with fd=%d (srv %d)", __FUNCTION__, tac_fd, srv_i);

            retval = _pam_send_account(tac_fd, type, user, tty, r_addr, cmd);
            /* return code from function in this mode is
               status of the last server we tried to send
               packet to */
            if(retval < 0) {
                _pam_log(LOG_WARNING, "%s: error sending %s (acct)",
                    __FUNCTION__, typemsg);
            } else {
                status = PAM_SUCCESS;
                if (ctrl & PAM_TAC_DEBUG) 
                    _pam_log(LOG_DEBUG, "%s: [%s] for [%s] sent",
                        __FUNCTION__, typemsg,user);
            }
            close(tac_fd);
            srv_i++;
        }
    } else {
        /* send packet to all servers specified */
        int srv_i;
                  
        status = PAM_SESSION_ERR;
        for(srv_i = 0; srv_i < tac_srv_no; srv_i++) {
            int tac_fd;
                                  
            tac_fd = tac_connect_single(tac_srv[srv_i], tac_srv_key[srv_i]);
            if(tac_fd < 0) {
                _pam_log(LOG_WARNING, "%s: error sending %s (fd)",
                    __FUNCTION__, typemsg);
                continue;
            }

            if (ctrl & PAM_TAC_DEBUG)
                _pam_log(LOG_DEBUG, "%s: connected with fd=%d (srv %d)", __FUNCTION__, tac_fd, srv_i);

            retval = _pam_send_account(tac_fd, type, user, tty, r_addr, cmd);
            /* return code from function in this mode is
               status of the last server we tried to send
               packet to */
            if(retval < 0) {
                _pam_log(LOG_WARNING, "%s: error sending %s (acct)",
                    __FUNCTION__, typemsg);
            } else {
                status = PAM_SUCCESS;
                if (ctrl & PAM_TAC_DEBUG) 
                    _pam_log(LOG_DEBUG, "%s: [%s] for [%s] sent",
                        __FUNCTION__, typemsg,user);
            }
            close(tac_fd);
        }
    }  /* acct mode */

    if(type == TAC_PLUS_ACCT_FLAG_STOP) {
        signal(SIGALRM, SIG_DFL);
        signal(SIGCHLD, SIG_DFL);
        signal(SIGHUP, SIG_DFL);
    }
    return status;
}                               
示例#10
0
/* authenticates user on remote TACACS+ server
 * returns PAM_SUCCESS if the supplied username and password
 * pair is valid 
 */
PAM_EXTERN 
int pam_sm_authenticate (pam_handle_t * pamh, int flags,
    int argc, const char **argv) {

    int ctrl, retval;
    char *user;
    char *pass;
    char *tty;
    char *r_addr;
    int srv_i;
    int tac_fd;
    int status = PAM_AUTH_ERR;
    int seq = 0;

    user = pass = tty = r_addr = NULL;

    ctrl = _pam_parse (argc, argv);

    if (ctrl & PAM_TAC_DEBUG)
        _pam_log (LOG_DEBUG, "%s: called (pam_tacplus v%u.%u.%u)"
            , __FUNCTION__, PAM_TAC_VMAJ, PAM_TAC_VMIN, PAM_TAC_VPAT);

    if ((user = _pam_get_user(pamh)) == NULL)
        return PAM_USER_UNKNOWN;

    if (ctrl & PAM_TAC_DEBUG)
        _pam_log (LOG_DEBUG, "%s: user [%s] obtained", __FUNCTION__, user);
  
    /* uwzgledniac PAM_DISALLOW_NULL_AUTHTOK */

    retval = tacacs_get_password (pamh, flags, ctrl, &pass);

    if (retval != PAM_SUCCESS || pass == NULL || *pass == '\0') {
        _pam_log (LOG_ERR, "unable to obtain password");
        return PAM_CRED_INSUFFICIENT;
    }

    retval = pam_set_item (pamh, PAM_AUTHTOK, pass);
    if (retval != PAM_SUCCESS) {
        _pam_log (LOG_ERR, "unable to set password");
        return PAM_CRED_INSUFFICIENT;
    }

    if (ctrl & PAM_TAC_DEBUG)
        _pam_log (LOG_DEBUG, "%s: password obtained", __FUNCTION__);

    tty = _pam_get_terminal(pamh);
    if (!strncmp (tty, "/dev/", 5))
        tty += 5;
    if (ctrl & PAM_TAC_DEBUG)
        _pam_log (LOG_DEBUG, "%s: tty [%s] obtained", __FUNCTION__, tty);

    r_addr = _pam_get_rhost(pamh);
    if (ctrl & PAM_TAC_DEBUG)
        _pam_log (LOG_DEBUG, "%s: rhost [%s] obtained", __FUNCTION__, r_addr);

    /* Attempt server connect */
    for (srv_i = 0; srv_i < tac_srv_no; srv_i++) {
        status = TAC_PLUS_AUTHEN_STATUS_FAIL;
        if (ctrl & PAM_TAC_DEBUG)
            _pam_log (LOG_DEBUG, "%s: trying srv %d", __FUNCTION__, srv_i );

        tac_fd = tac_connect_single(tac_srv[srv_i], tac_srv_key[srv_i]);
        if (tac_fd < 0) {
            _pam_log (LOG_ERR, "connection failed srv %d: %m", srv_i);
            if (srv_i == tac_srv_no-1) {
                _pam_log (LOG_ERR, "no more servers to connect");
                return PAM_AUTHINFO_UNAVAIL;
            }
            continue;
        }

        /* Send AUTHEN/START */
        if (tac_authen_send(tac_fd, user, pass, tty, r_addr, TAC_PLUS_AUTHEN_LOGIN, ctrl) < 0) {
            _pam_log (LOG_ERR, "error sending auth req to TACACS+ server");
            status = PAM_AUTHINFO_UNAVAIL;
        } else {
        	/* Read AUTHEN/REPLY and act on status */
        	struct msg_status *msgstatus = malloc(sizeof(msg_status));

            do
			{
            	tac_authen_read(msgstatus, tac_fd, ctrl, &seq);
        		status = msgstatus->status;

            	switch (status) {
            		case TAC_PLUS_AUTHEN_STATUS_GETPASS:
            			/* AUTHEN/CONT with password */
						if (ctrl & PAM_TAC_DEBUG)
							_pam_log (LOG_DEBUG, "%s: tac_cont_send called", __FUNCTION__);

						if (tac_cont_send(tac_fd, pass, ctrl, seq+1) < 0) {
							_pam_log (LOG_ERR, "error sending continue req to TACACS+ server");
							status = PAM_MAXTRIES;
						}
            		break;

            		case TAC_PLUS_AUTHEN_STATUS_GETDATA: {
            			/* The only GETDATA request should be if the user's password
            			 * has expired and ACS is requesting a new password
            			 *
            			 * Check if a conversation function has been set and either
            			 * return a PAM_AUTHTOK_EXPIRED or start a conversation
            			 * with the user for to change the password
            			 */
            			if (!strcmp(tty,"http")) {
            				status = PAM_NEW_AUTHTOK_REQD;
            				if (ctrl & PAM_TAC_DEBUG)
            					_pam_log (LOG_DEBUG, "%s: expired", __FUNCTION__);
            			} else {

							/* Get data from user with pam conversation */
							struct pam_message msg;
							struct pam_response *resp = NULL;
							int retval;
							char *user_data = NULL;

							/* set up conversation call */
							msg.msg_style = PAM_PROMPT_ECHO_OFF;
							msg.msg = malloc(100);
							strcpy((char *)msg.msg,msgstatus->server_msg);

							if ((retval = converse (pamh, 1, &msg, &resp)) != PAM_SUCCESS) {
								status = PAM_AUTHINFO_UNAVAIL;
							} else {
								if (resp != NULL) {
									if (resp->resp == NULL && (ctrl & PAM_TAC_DEBUG))
										_pam_log (LOG_DEBUG, "pam_sm_authenticate: NULL given by user for GETDATA request");

									user_data = resp->resp;
									resp->resp = NULL;
								} else {
									if (ctrl & PAM_TAC_DEBUG) {
										_pam_log (LOG_DEBUG, "pam_sm_authenticate: no error reported");
										_pam_log (LOG_DEBUG, "getting data from user - NULL returned!?");
									}
									return PAM_CONV_ERR;
								}

								/* AUTHEN/CONT with data */
								if (ctrl & PAM_TAC_DEBUG)
									_pam_log (LOG_DEBUG, "%s: tac_cont_send called", __FUNCTION__);

								if (tac_cont_send(tac_fd, user_data, ctrl, seq+1) < 0) {
									_pam_log (LOG_ERR, "error sending continue req to TACACS+ server");
									status = PAM_AUTHINFO_UNAVAIL;
								}
							}
							free(msg.msg);
            			}
            		}
            		break;

            		case TAC_PLUS_AUTHEN_STATUS_GETUSER:
            			/* AUTHEN/CONT with username */
            			if (ctrl & PAM_TAC_DEBUG)
							_pam_log (LOG_DEBUG, "%s: tac_cont_send called", __FUNCTION__);

						if (tac_cont_send(tac_fd, user, ctrl, seq+1) < 0) {
							_pam_log (LOG_ERR, "error sending continue req to TACACS+ server");
							status = PAM_AUTHINFO_UNAVAIL;
						}
            		break;
            	}
            } while ( 	(status == TAC_PLUS_AUTHEN_STATUS_GETDATA) ||
            			(status == TAC_PLUS_AUTHEN_STATUS_GETPASS) ||
            			(status == TAC_PLUS_AUTHEN_STATUS_GETUSER)		);

            if (ctrl & PAM_TAC_DEBUG)
            	_pam_log (LOG_DEBUG, "%s: out of while loop status=%d", __FUNCTION__,status);

            if (status == TAC_PLUS_AUTHEN_STATUS_PASS) {
            	/* OK, we got authenticated; save the server that
				   accepted us for pam_sm_acct_mgmt and exit the loop */
				status = PAM_SUCCESS;
				active_server = tac_srv[srv_i];
				active_key = tac_srv_key[srv_i];
            } else if (status != PAM_NEW_AUTHTOK_REQD) {
                _pam_log (LOG_ERR, "auth failed: %d", status);
                status = PAM_AUTH_ERR;
            }
        }
        close(tac_fd);

        /* TODO: Allow time for tac server to reply
         * TODO: Check if reply received before connecting to next server
         */
    }

    if (ctrl & PAM_TAC_DEBUG)
        _pam_log (LOG_DEBUG, "%s: exit with pam status: %i", __FUNCTION__, status);

    bzero (pass, strlen (pass));
    free(pass);
    pass = NULL;

    return status;
}    /* pam_sm_authenticate */
示例#11
0
/* authenticates user on remote TACACS+ server
 * returns PAM_SUCCESS if the supplied username and password
 * pair is valid
 */
PAM_EXTERN
int pam_sm_authenticate (pam_handle_t * pamh, int flags,
    int argc, const char **argv) {

    int ctrl, retval;
    char *user;
    char *pass;
    char *tty;
    char *r_addr;
    int srv_i;
    int tac_fd, status, msg, communicating;

    user = pass = tty = r_addr = NULL;

    ctrl = _pam_parse(argc, argv);

    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: called (pam_tacplus v%u.%u.%u)",
            __FUNCTION__, PAM_TAC_VMAJ, PAM_TAC_VMIN, PAM_TAC_VPAT);

    if ((user = _pam_get_user(pamh)) == NULL)
        return PAM_USER_UNKNOWN;

    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: user [%s] obtained", __FUNCTION__, user);

    /* uwzgledniac PAM_DISALLOW_NULL_AUTHTOK */

    retval = tacacs_get_password (pamh, flags, ctrl, &pass);
    if (retval != PAM_SUCCESS || pass == NULL || *pass == '\0') {
        _pam_log(LOG_ERR, "unable to obtain password");
        return PAM_CRED_INSUFFICIENT;
    }

    retval = pam_set_item (pamh, PAM_AUTHTOK, pass);
    if (retval != PAM_SUCCESS) {
        _pam_log(LOG_ERR, "unable to set password");
        return PAM_CRED_INSUFFICIENT;
    }

    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: password obtained", __FUNCTION__);

    tty = _pam_get_terminal(pamh);
    if (!strncmp(tty, "/dev/", 5))
        tty += 5;
    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: tty [%s] obtained", __FUNCTION__, tty);

    r_addr = _pam_get_rhost(pamh);
    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: rhost [%s] obtained", __FUNCTION__, r_addr);

    status = PAM_AUTHINFO_UNAVAIL;
    for (srv_i = 0; srv_i < tac_srv_no; srv_i++) {
        if (ctrl & PAM_TAC_DEBUG)
            syslog(LOG_DEBUG, "%s: trying srv %d", __FUNCTION__, srv_i );

        tac_fd = tac_connect_single(tac_srv[srv_i].addr, tac_srv[srv_i].key);
        if (tac_fd < 0) {
            _pam_log(LOG_ERR, "connection failed srv %d: %m", srv_i);
            continue;
        }
        if (tac_authen_send(tac_fd, user, pass, tty, r_addr) < 0) {
            close(tac_fd);
            _pam_log(LOG_ERR, "error sending auth req to TACACS+ server");
            continue;
        }
        communicating = 1;
        while (communicating) {
            msg = tac_authen_read(tac_fd);

            /* talk the protocol */
            switch (msg) {
                case TAC_PLUS_AUTHEN_STATUS_PASS:
                    /* success */
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_PASS");

                    status = PAM_SUCCESS;
                    communicating = 0;
                    active_server.addr = tac_srv[srv_i].addr;
                    active_server.key = tac_srv[srv_i].key;

                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "%s: active srv %d", __FUNCTION__, srv_i);
                    break;

                case TAC_PLUS_AUTHEN_STATUS_FAIL:
                    /* forget it */
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_FAIL");

                    status = PAM_AUTH_ERR;
                    communicating = 0;
                    _pam_log(LOG_ERR, "auth failed: %d", msg);
                    break;

                case TAC_PLUS_AUTHEN_STATUS_GETDATA:
                    /* not implemented */
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_GETDATA");

                    communicating = 0;
                    break;

                case TAC_PLUS_AUTHEN_STATUS_GETUSER:
                    /* not implemented */
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_GETUSER");

                    communicating = 0;
                    break;

                case TAC_PLUS_AUTHEN_STATUS_GETPASS:
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_GETPASS");

                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "%s: tac_cont_send called", __FUNCTION__);

                    if (tac_cont_send(tac_fd, pass) < 0) {
                        _pam_log (LOG_ERR, "error sending continue req to TACACS+ server");
                        communicating = 0;
                        break;
                    }
                    /* continue the while loop; go read tac response */
                    break;

                case TAC_PLUS_AUTHEN_STATUS_RESTART:
                    /* try it again */
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_RESTART");

                    /*
                     * not implemented
                     * WdJ: I *think* you can just do tac_authen_send(user, pass) again
                     *      but I'm not sure
                     */
                    communicating = 0;
                    break;

                case TAC_PLUS_AUTHEN_STATUS_ERROR:
                    /* server has problems */
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_ERROR");

                    communicating = 0;
                    break;

                case TAC_PLUS_AUTHEN_STATUS_FOLLOW:
                    /* server tells to try a different server address */
                    /* not implemented */
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_FOLLOW");

                    communicating = 0;
                    break;

                default:
                    if (msg < 0) {
                        /* connection error */
                        communicating = 0;
                        if (ctrl & PAM_TAC_DEBUG)
                            syslog(LOG_DEBUG, "error communicating with tacacs server");
                        break;
                    }

                    /* unknown response code */
                    communicating = 0;
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: unknown response 0x%02x", msg);
            }
        }    /* end while(communicating) */
        close(tac_fd);

        if (status == PAM_SUCCESS || status == PAM_AUTH_ERR)
            break;
    }
    if (status != PAM_SUCCESS && status != PAM_AUTH_ERR)
        _pam_log(LOG_ERR, "no more servers to connect");

    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: exit with pam status: %d", __FUNCTION__, status);

    bzero(pass, strlen (pass));
    free(pass);
    pass = NULL;

    return status;
}    /* pam_sm_authenticate */
示例#12
0
文件: pam_ftp.c 项目: bigon/linux-pam
int
pam_sm_authenticate (pam_handle_t *pamh, int flags UNUSED,
		     int argc, const char **argv)
{
    int retval, anon=0, ctrl;
    const char *user;
    const char *users = NULL;

    /*
     * this module checks if the user name is ftp or annonymous. If
     * this is the case, it can set the PAM_RUSER to the entered email
     * address and SUCCEEDS, otherwise it FAILS.
     */

    ctrl = _pam_parse(pamh, argc, argv, &users);

    retval = pam_get_user(pamh, &user, NULL);
    if (retval != PAM_SUCCESS || user == NULL) {
	pam_syslog(pamh, LOG_ERR, "no user specified");
	return PAM_USER_UNKNOWN;
    }

    if (!(ctrl & PAM_NO_ANON)) {
	anon = lookup(user, users, &user);
    }

    if (anon) {
	retval = pam_set_item(pamh, PAM_USER, (const void *)user);
	if (retval != PAM_SUCCESS || user == NULL) {
	    pam_syslog(pamh, LOG_ERR, "user resetting failed");
	    return PAM_USER_UNKNOWN;
	}
    }

    /*
     * OK. we require an email address for user or the user's password.
     * - build conversation and get their input.
     */

    {
	char *resp = NULL;
	const char *token;

	if (!anon)
	  retval = pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp,
			       PLEASE_ENTER_PASSWORD, user);
	else
	  retval = pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp,
			       GUEST_LOGIN_PROMPT);

	if (retval != PAM_SUCCESS) {
	    _pam_overwrite (resp);
	    _pam_drop (resp);
	    return ((retval == PAM_CONV_AGAIN)
		    ? PAM_INCOMPLETE:PAM_AUTHINFO_UNAVAIL);
	}

	if (anon) {
	  /* XXX: Some effort should be made to verify this email address! */

	    if (!(ctrl & PAM_IGNORE_EMAIL)) {
		char *sptr = NULL;
		token = strtok_r(resp, "@", &sptr);
		retval = pam_set_item(pamh, PAM_RUSER, token);

		if ((token) && (retval == PAM_SUCCESS)) {
		    token = strtok_r(NULL, "@", &sptr);
		    retval = pam_set_item(pamh, PAM_RHOST, token);
		}
	    }

	    /* we are happy to grant annonymous access to the user */
	    retval = PAM_SUCCESS;

	} else {
	    /*
	     * we have a password so set AUTHTOK
	     */

	    pam_set_item(pamh, PAM_AUTHTOK, resp);

	    /*
	     * this module failed, but the next one might succeed with
	     * this password.
	     */

	    retval = PAM_AUTH_ERR;
	}

	/* clean up */
	_pam_overwrite(resp);
	_pam_drop(resp);

	/* success or failure */

	return retval;
    }
}
示例#13
0
/* authenticates user on remote TACACS+ server
 * returns PAM_SUCCESS if the supplied username and password
 * pair is valid 
 */
PAM_EXTERN 
int pam_sm_authenticate (pam_handle_t * pamh, int flags,
    int argc, const char **argv) {

    int ctrl, retval;
    char *user;
    char *pass;
    char *tty;
    char *r_addr;
    int srv_i;
    int tac_fd;
    int status = PAM_AUTH_ERR;

    user = pass = tty = r_addr = NULL;

    ctrl = _pam_parse (argc, argv);

    if (ctrl & PAM_TAC_DEBUG)
        syslog (LOG_DEBUG, "%s: called (pam_tacplus v%u.%u.%u)"
            , __FUNCTION__, PAM_TAC_VMAJ, PAM_TAC_VMIN, PAM_TAC_VPAT);

    if ((user = _pam_get_user(pamh)) == NULL)
        return PAM_USER_UNKNOWN;

    if (ctrl & PAM_TAC_DEBUG)
        syslog (LOG_DEBUG, "%s: user [%s] obtained", __FUNCTION__, user);
  
    /* uwzgledniac PAM_DISALLOW_NULL_AUTHTOK */

    retval = tacacs_get_password (pamh, flags, ctrl, &pass);
    if (retval != PAM_SUCCESS || pass == NULL || *pass == '\0') {
        _pam_log (LOG_ERR, "unable to obtain password");
        return PAM_CRED_INSUFFICIENT;
    }

    retval = pam_set_item (pamh, PAM_AUTHTOK, pass);
    if (retval != PAM_SUCCESS) {
        _pam_log (LOG_ERR, "unable to set password");
        return PAM_CRED_INSUFFICIENT;
    }

    if (ctrl & PAM_TAC_DEBUG)
        syslog (LOG_DEBUG, "%s: password obtained", __FUNCTION__);

    tty = _pam_get_terminal(pamh);
    if (!strncmp (tty, "/dev/", 5))
        tty += 5;
    if (ctrl & PAM_TAC_DEBUG)
        syslog (LOG_DEBUG, "%s: tty [%s] obtained", __FUNCTION__, tty);

    r_addr = _pam_get_rhost(pamh);
    if (ctrl & PAM_TAC_DEBUG)
        syslog (LOG_DEBUG, "%s: rhost [%s] obtained", __FUNCTION__, r_addr);

    for (srv_i = 0; srv_i < tac_srv_no; srv_i++) {
        int msg = TAC_PLUS_AUTHEN_STATUS_FAIL;
        if (ctrl & PAM_TAC_DEBUG)
            syslog (LOG_DEBUG, "%s: trying srv %d", __FUNCTION__, srv_i );

        tac_fd = tac_connect_single(tac_srv[srv_i], tac_srv_key[srv_i]);
        if (tac_fd < 0) {
            _pam_log (LOG_ERR, "connection failed srv %d: %m", srv_i);
            if (srv_i == tac_srv_no-1) {
                _pam_log (LOG_ERR, "no more servers to connect");
                return PAM_AUTHINFO_UNAVAIL;
            }
            continue;
        }

        if (tac_authen_send(tac_fd, user, pass, tty, r_addr) < 0) {
            _pam_log (LOG_ERR, "error sending auth req to TACACS+ server");
            status = PAM_AUTHINFO_UNAVAIL;
        } else {
            msg = tac_authen_read(tac_fd);
            if (msg == TAC_PLUS_AUTHEN_STATUS_GETPASS) {
                if (ctrl & PAM_TAC_DEBUG)
                    syslog (LOG_DEBUG, "%s: tac_cont_send called", __FUNCTION__);
                if (tac_cont_send(tac_fd, pass) < 0) {
                    _pam_log (LOG_ERR, "error sending continue req to TACACS+ server");
                    status = PAM_AUTHINFO_UNAVAIL;
                } else {
                    msg = tac_authen_read(tac_fd);
                    if (msg != TAC_PLUS_AUTHEN_STATUS_PASS) {
                        _pam_log (LOG_ERR, "auth failed: %d", msg);
                        status = PAM_AUTH_ERR;
                    } else {
                        /* OK, we got authenticated; save the server that
                           accepted us for pam_sm_acct_mgmt and exit the loop */
                        status = PAM_SUCCESS;
                        active_server = tac_srv[srv_i];
                        active_key = tac_srv_key[srv_i];
                        close(tac_fd);
                        break;
                    }
                }
            } else if (msg != TAC_PLUS_AUTHEN_STATUS_PASS) {
                _pam_log (LOG_ERR, "auth failed: %d", msg);
                status = PAM_AUTH_ERR;
            } else {
                /* OK, we got authenticated; save the server that
                   accepted us for pam_sm_acct_mgmt and exit the loop */
                status = PAM_SUCCESS;
                active_server = tac_srv[srv_i];
                active_key = tac_srv_key[srv_i];
                close(tac_fd);
                break;
            }
        }
        close(tac_fd);
    }

    if (ctrl & PAM_TAC_DEBUG)
        syslog (LOG_DEBUG, "%s: exit with pam status: %i", __FUNCTION__, status);

    bzero (pass, strlen (pass));
    free(pass);
    pass = NULL;

    return status;
}    /* pam_sm_authenticate */
示例#14
0
/* authenticates user on remote TACACS+ server
 * returns PAM_SUCCESS if the supplied username and password
 * pair is valid
 */
PAM_EXTERN
int pam_sm_authenticate (pam_handle_t * pamh, int flags,
    int argc, const char **argv) {
    int ctrl, retval;
    char *user, *puser;
    char *pass;
    char *tty;
    char *r_addr;
    int status;

    priv_level = 0;
    user = pass = tty = r_addr = NULL;

    ctrl = _pam_parse(argc, argv);

    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: called (pam_tacplus v%u.%u.%u)",
            __func__, PAM_TAC_VMAJ, PAM_TAC_VMIN, PAM_TAC_VPAT);

    /* reset static state in case we are re-entered */
    _reset_saved_user(ctrl & PAM_TAC_DEBUG);

    /*
     * If a mapped user entry already exists, we are probably being
     * used for su or sudo, so we need to get the original user password,
     * rather than the mapped user.
     * Decided based on auid != uid and then do the lookup, similar to
     * find_pw_user() in nss_tacplusc
     */
    _pam_get_user(pamh, &puser);
    user = get_user_to_auth(puser);

    if (user == NULL)
        return PAM_USER_UNKNOWN;

    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: user [%s] obtained", __func__, user);

    retval = tacacs_get_password (pamh, flags, ctrl, &pass);
    if (retval != PAM_SUCCESS || pass == NULL || *pass == '\0') {
        _pam_log(LOG_ERR, "unable to obtain password");
        status = PAM_CRED_INSUFFICIENT;
        goto err;
    }

    retval = pam_set_item (pamh, PAM_AUTHTOK, pass);
    if (retval != PAM_SUCCESS) {
        _pam_log(LOG_ERR, "unable to set password");
        status = PAM_CRED_INSUFFICIENT;
        goto err;
    }

    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: password obtained", __func__);

    _pam_get_terminal(pamh, &tty);
    if (!strncmp(tty, "/dev/", 5))
        tty += 5;
    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: tty [%s] obtained", __func__, tty);

    _pam_get_rhost(pamh, &r_addr);
    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: rhost [%s] obtained", __func__, r_addr);

    status = do_tac_connect(ctrl, NULL, user, pass, tty, r_addr, NULL, NULL, pamh);

    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: exit with pam status: %d", __func__, status);

err:
    if (user && user != puser)
        free(user); /* it was stdrup'ed */
    if (NULL != pass) {
        bzero(pass, strlen (pass));
        free(pass);
    }

    return status;
}    /* pam_sm_authenticate */
示例#15
0
PAM_EXTERN 
int pam_sm_chauthtok (pam_handle_t * pamh, int flags,
    int argc, const char **argv) {

    int ctrl, retval;
    char *user;
    char *pass;
    char *tty;
    char *r_addr;
    int srv_i;
    int tac_fd;
    int status = PAM_TRY_AGAIN;
    int seq = 0;

    user = pass = tty = r_addr = NULL;

    ctrl = _pam_parse (argc, argv);

    if (ctrl & PAM_TAC_DEBUG)
        _pam_log (LOG_DEBUG, "%s: called (pam_tacplus v%u.%u.%u)"
            , __FUNCTION__, PAM_TAC_VMAJ, PAM_TAC_VMIN, PAM_TAC_VPAT);

    /* Preliminary call to check readiness of our module */
    if (flags & PAM_PRELIM_CHECK) {
    	/* Can we connect to TACACS? */
    	for (srv_i = 0; srv_i < tac_srv_no; srv_i++) {
    		if (ctrl & PAM_TAC_DEBUG)
    			_pam_log (LOG_DEBUG, "%s: trying srv %d", __FUNCTION__, srv_i );
    		tac_fd = tac_connect_single(tac_srv[srv_i], tac_srv_key[srv_i]);
			if (tac_fd < 0) {
				_pam_log (LOG_ERR, "connection failed srv %d: %m", srv_i);
				if (srv_i == tac_srv_no-1) {
					_pam_log (LOG_ERR, "no more servers to connect");
					return PAM_TRY_AGAIN;
				}
				continue;
			}
    	}
    	close(tac_fd);
    	return PAM_SUCCESS;
    }

    if ((user = _pam_get_user(pamh)) == NULL)
        return PAM_USER_UNKNOWN;

    if (ctrl & PAM_TAC_DEBUG)
        _pam_log (LOG_DEBUG, "%s: user [%s] obtained", __FUNCTION__, user);

    /* CHPASS does not send a password in data field,
     * user is prompted by a GETDATA reply packet
     */
    pass = malloc(5);
    strcpy(pass,"null");

    tty = _pam_get_terminal(pamh);
    if (!strncmp (tty, "/dev/", 5))
        tty += 5;
    if (ctrl & PAM_TAC_DEBUG)
        _pam_log (LOG_DEBUG, "%s: tty [%s] obtained", __FUNCTION__, tty);

    r_addr = _pam_get_rhost(pamh);
    if (ctrl & PAM_TAC_DEBUG)
        _pam_log (LOG_DEBUG, "%s: rhost [%s] obtained", __FUNCTION__, r_addr);

    /* Attempt server connect */
    for (srv_i = 0; srv_i < tac_srv_no; srv_i++) {
        status = TAC_PLUS_AUTHEN_STATUS_FAIL;
        if (ctrl & PAM_TAC_DEBUG)
            _pam_log (LOG_DEBUG, "%s: trying srv %d", __FUNCTION__, srv_i );

        tac_fd = tac_connect_single(tac_srv[srv_i], tac_srv_key[srv_i]);
        if (tac_fd < 0) {
            _pam_log (LOG_ERR, "connection failed srv %d: %m", srv_i);
            if (srv_i == tac_srv_no-1) {
                _pam_log (LOG_ERR, "no more servers to connect");
                return PAM_AUTHINFO_UNAVAIL;
            }
            continue;
        }

        /* Send AUTHEN/START */
        if (tac_authen_send(tac_fd, user, pass, tty, r_addr, TAC_PLUS_AUTHEN_CHPASS, ctrl) < 0) {
            _pam_log (LOG_ERR, "error sending auth req to TACACS+ server");
            status = PAM_AUTHINFO_UNAVAIL;
        } else {
        	/* Read AUTHEN/REPLY and act on status */
			struct msg_status *msgstatus = malloc(sizeof(msg_status));

			do
			{
				tac_authen_read(msgstatus, tac_fd, ctrl, &seq);
				status = msgstatus->status;

				switch (status) {
					case TAC_PLUS_AUTHEN_STATUS_GETPASS:
						/* AUTHEN/CONT with password */
						if (ctrl & PAM_TAC_DEBUG)
							_pam_log (LOG_DEBUG, "%s: tac_cont_send called", __FUNCTION__);

						if (tac_cont_send(tac_fd, pass, ctrl, seq+1) < 0) {
							_pam_log (LOG_ERR, "error sending continue req to TACACS+ server");
							status = PAM_AUTHINFO_UNAVAIL;
						}
					break;

					case TAC_PLUS_AUTHEN_STATUS_GETDATA: {
						/* Get data from user with pam conversation */
						struct pam_message msg;
						struct pam_response *resp = NULL;
						int retval;
						char *user_data = NULL;

						/* set up conversation call */
						msg.msg_style = PAM_PROMPT_ECHO_OFF;
						msg.msg = malloc(100);
						strcpy((char *)msg.msg,msgstatus->server_msg);

						if ((retval = converse (pamh, 1, &msg, &resp)) != PAM_SUCCESS) {
							status = PAM_AUTHINFO_UNAVAIL;
						} else {
							if (resp != NULL) {
								if (resp->resp == NULL && (ctrl & PAM_TAC_DEBUG))
									_pam_log (LOG_DEBUG, "pam_sm_authenticate: NULL given by user for GETDATA request");

								user_data = resp->resp;
								resp->resp = NULL;
							} else {
								if (ctrl & PAM_TAC_DEBUG) {
									_pam_log (LOG_DEBUG, "pam_sm_authenticate: no error reported");
									_pam_log (LOG_DEBUG, "getting data from user - NULL returned!?");
								}
								return PAM_CONV_ERR;
							}

							/* AUTHEN/CONT with data */
							if (ctrl & PAM_TAC_DEBUG)
								_pam_log (LOG_DEBUG, "%s: tac_cont_send called", __FUNCTION__);

							if (tac_cont_send(tac_fd, user_data, ctrl, seq+1) < 0) {
								_pam_log (LOG_ERR, "error sending continue req to TACACS+ server");
								status = PAM_AUTHINFO_UNAVAIL;
							}
						}
						free(msg.msg);
					}
					break;

					case TAC_PLUS_AUTHEN_STATUS_GETUSER:
						/* AUTHEN/CONT with username */
						if (ctrl & PAM_TAC_DEBUG)
							_pam_log (LOG_DEBUG, "%s: tac_cont_send called", __FUNCTION__);

						if (tac_cont_send(tac_fd, user, ctrl, seq+1) < 0) {
							_pam_log (LOG_ERR, "error sending continue req to TACACS+ server");
							status = PAM_AUTHINFO_UNAVAIL;
						}
					break;
				}
			} while ( 	(status == TAC_PLUS_AUTHEN_STATUS_GETDATA) ||
						(status == TAC_PLUS_AUTHEN_STATUS_GETPASS) ||
						(status == TAC_PLUS_AUTHEN_STATUS_GETUSER)		);

            if (status != TAC_PLUS_AUTHEN_STATUS_PASS) {
                _pam_log (LOG_ERR, "auth failed: %d", status);
                status = PAM_AUTHTOK_ERR;
            } else {
                /* OK, we got authenticated; save the server that
                   accepted us for pam_sm_acct_mgmt and exit the loop */
                status = PAM_SUCCESS;
                active_server = tac_srv[srv_i];
                active_key = tac_srv_key[srv_i];
                close(tac_fd);
                break;
            }
        }
        close(tac_fd);
    }

    if (ctrl & PAM_TAC_DEBUG)
        _pam_log (LOG_DEBUG, "%s: exit with pam status: %i", __FUNCTION__, status);

    bzero (pass, strlen (pass));
    free(pass);
    pass = NULL;

    return status;
}    /* pam_sm_chauthtok */
示例#16
0
/* authorizes user on remote TACACS+ server, i.e. checks
 * his permission to access requested service
 * returns PAM_SUCCESS if the service is allowed
 */
PAM_EXTERN
int pam_sm_acct_mgmt (pam_handle_t * pamh, int flags,
    int argc, const char **argv) {

    int ctrl, status=PAM_AUTH_ERR;
    char *user;
    char *tty;
    char *r_addr;
    struct areply arep;
    struct tac_attrib *attr_s = NULL, *attr;
    int tac_fd = -1;

    user = tty = r_addr = NULL;
    memset(&arep, 0, sizeof(arep));

    /* this also obtains service name for authorization
       this should be normally performed by pam_get_item(PAM_SERVICE)
       but since PAM service names are incompatible TACACS+
       we have to pass it via command line argument until a better
       solution is found ;) */
    ctrl = _pam_parse (argc, argv);

    if (ctrl & PAM_TAC_DEBUG)
        syslog (LOG_DEBUG, "%s: called (pam_tacplus v%u.%u.%u)",
            __func__, PAM_TAC_VMAJ, PAM_TAC_VMIN, PAM_TAC_VPAT);

    _pam_get_user(pamh, &user);
    if (user == NULL)
        return PAM_USER_UNKNOWN;


    _pam_get_terminal(pamh, &tty);
    if(!strncmp(tty, "/dev/", 5))
        tty += 5;

    _pam_get_rhost(pamh, &r_addr);

    /* checks for specific data required by TACACS+, which should
       be supplied in pam module command line  */
    if(!*tac_service) {
        _pam_log (LOG_ERR, "TACACS+ service type not configured");
        return PAM_AUTH_ERR;
    }
    tac_add_attrib(&attr_s, "service", tac_service);

    if(tac_protocol != NULL && tac_protocol[0] != '\0')
          tac_add_attrib(&attr_s, "protocol", tac_protocol);
    else
          _pam_log (LOG_ERR, "TACACS+ protocol type not configured (IGNORED)");

    tac_add_attrib(&attr_s, "cmd", "");

    memset(&arep, 0, sizeof arep);

    /*
     * Check if user is authorized, independently of authentication.
     * Authentication may have happened via ssh public key, rather than
     * via TACACS+.  PAM should not normally get to this entry point if
     * user is not yet authenticated.
     * We only write the mapping entry (if needed) when authorization
     * is succesful.
     * attr is not used here, but having a non-NULL value is how
     * talk_tac_server() distinguishes that it is an acct call, vs auth
     * TODO: use a different mechanism
    */
    status = do_tac_connect(ctrl, &tac_fd, user, NULL, tty, r_addr, &attr_s,
        &arep, pamh);
    tac_free_attrib(&attr_s);
    if(active_server.addr == NULL || tac_fd < 0) {
        /* we need to return PAM_AUTHINFO_UNAVAIL here, rather than
         * PAM_AUTH_ERR, or we can't use "ignore" in the pam configuration
         */
        status = PAM_AUTHINFO_UNAVAIL;
        goto cleanup;
    }

    if(status) {
        if (ctrl & PAM_TAC_DEBUG)
            _pam_log(LOG_NOTICE, "No TACACS mapping for %s after auth failure",
                user);
        goto cleanup;
    }

    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: user [%s] successfully authorized", __func__,
            user);

    attr = arep.attr;
    while (attr != NULL)  {
        char attribute[attr->attr_len];
        char value[attr->attr_len];
        char attrenv[attr->attr_len];
        char *sep;

        sep = index(attr->attr, '=');
        if(sep == NULL)
            sep = index(attr->attr, '*');
        if(sep != NULL) {
            bcopy(attr->attr, attribute, attr->attr_len-strlen(sep));
            attribute[attr->attr_len-strlen(sep)] = '\0';
            bcopy(sep, value, strlen(sep));
            value[strlen(sep)] = '\0';

            size_t i;
            for (i = 0; attribute[i] != '\0'; i++) {
                attribute[i] = toupper(attribute[i]);
                if (attribute[i] == '-')
                    attribute[i] = '_';
            }

            if (ctrl & PAM_TAC_DEBUG)
                syslog(LOG_DEBUG, "%s: returned attribute `%s(%s)' from server",
                    __func__, attribute, value);

            if(strncmp(attribute, "PRIV", 4) == 0) {
                char *ok;

                /* because of the separation above, value will start with
                 * the separator, which we don't want.  */
                priv_level = (unsigned)strtoul(value+1, &ok, 0);
                /* if this fails, we leave priv_level at 0, which is
                 * least privileged, so that's OK, but at least report it
                 */
                if (ok == value)
                    _pam_log (LOG_WARNING,
                        "%s: non-numeric privilege for %s, got (%s)",
                        __func__, attribute, value+1);
            }

            /*
             * make returned attributes available for other PAM modules via PAM
             * environment. Since separator can be = or *, ensure it's = for
             * the env.
             */
            snprintf(attrenv, sizeof attribute, "%s=%s", attribute, value+1);
            if (pam_putenv(pamh, attrenv) != PAM_SUCCESS)
                _pam_log(LOG_WARNING, "%s: unable to set PAM environment (%s)",
                    __func__, attribute);

        } else {
            syslog(LOG_WARNING, "%s: invalid attribute `%s', no separator",
                __func__, attr->attr);
        }
        attr = attr->next;
    }

    update_mapped(pamh, user, priv_level, r_addr);


cleanup:
    /* free returned attributes */
    if(arep.attr != NULL)
        tac_free_attrib(&arep.attr);

    if(arep.msg != NULL)
        free (arep.msg);

    if(tac_fd >= 0) {
        active_server.addr = NULL;
        close(tac_fd);
        tac_fd = -1;
    }

    return status;
}    /* pam_sm_acct_mgmt */
示例#17
0
PAM_EXTERN
int pam_sm_authenticate(pam_handle_t *pamh, int flags,
			int argc, const char **argv)
{
     const char *username;
     const char *password;
     const char *member = NULL;
     int retval = PAM_AUTH_ERR;
     int i;
    
     /* parse arguments */
     int ctrl = _pam_parse(argc, argv);

     /* Get the username */
     retval = pam_get_user(pamh, &username, NULL);
     if ((retval != PAM_SUCCESS) || (!username)) {
        if (ctrl & WINBIND_DEBUG_ARG)
            _pam_log(LOG_DEBUG,"can not get the username");
        return PAM_SERVICE_ERR;
     }
     
     retval = _winbind_read_password(pamh, ctrl, NULL, 
				     "Password: "******"Could not retrieve user's password");
	 return PAM_AUTHTOK_ERR;
     }
     
     if (ctrl & WINBIND_DEBUG_ARG) {

	     /* Let's not give too much away in the log file */

#ifdef DEBUG_PASSWORD
	 _pam_log(LOG_INFO, "Verify user `%s' with password `%s'",
		  username, password);
#else
	 _pam_log(LOG_INFO, "Verify user `%s'", username);
#endif
     }

     /* Retrieve membership-string here */
     for ( i=0; i<argc; i++ ) {

	 if ((strncmp(argv[i], "require_membership_of", strlen("require_membership_of")) == 0) 
	     || (strncmp(argv[i], "require-membership-of", strlen("require-membership-of")) == 0)) {

	     char *p;
	     char *parm = strdup(argv[i]);

	     if ( (p = strchr( parm, '=' )) == NULL) {
	     	_pam_log(LOG_INFO, "no \"=\" delimiter for \"require_membership_of\" found\n");
		break;
	     }

	     member = strdup(p+1);
	 }
     }

     /* Now use the username to look up password */
     return winbind_auth_request(username, password, member, ctrl);
}
示例#18
0
文件: pam_ftp.c 项目: ysleu/RTL8685
PAM_EXTERN
int pam_sm_authenticate(pam_handle_t *pamh,int flags,int argc
			,const char **argv)
{
    int retval, anon=0, ctrl;
    const char *user;
    char *users=NULL;

    /*
     * this module checks if the user name is ftp or annonymous. If
     * this is the case, it can set the PAM_RUSER to the entered email
     * address and SUCCEEDS, otherwise it FAILS.
     */

    ctrl = _pam_parse(argc, argv, &users);

    retval = pam_get_user(pamh, &user, NULL);
    if (retval != PAM_SUCCESS || user == NULL) {
	_pam_log(LOG_ERR, "no user specified");
	return PAM_USER_UNKNOWN;
    }

    if (!(ctrl & PAM_NO_ANON)) {
	anon = lookup(user, users, &user);
    }

    if (anon) {
	retval = pam_set_item(pamh, PAM_USER, (const void *)user);
	if (retval != PAM_SUCCESS || user == NULL) {
	    _pam_log(LOG_ERR, "user resetting failed");
	    return PAM_USER_UNKNOWN;
	}
    }

    /*
     * OK. we require an email address for user or the user's password.
     * - build conversation and get their input.
     */

    {
	struct pam_message msg[1], *mesg[1];
	struct pam_response *resp=NULL;
	const char *token;
	char *prompt=NULL;
	int i=0;

	if (!anon) {
	    prompt = malloc(strlen(PLEASE_ENTER_PASSWORD) + strlen(user));
	    if (prompt == NULL) {
		D(("out of memory!?"));
		return PAM_BUF_ERR;
	    } else {
		sprintf(prompt, PLEASE_ENTER_PASSWORD, user);
		msg[i].msg = prompt;
	    }
	} else {
	    msg[i].msg = GUEST_LOGIN_PROMPT;
	}

	msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
	mesg[i] = &msg[i];

	retval = converse(pamh, ++i, mesg, &resp);
	if (prompt) {
	    _pam_overwrite(prompt);
	    _pam_drop(prompt);
	}

	if (retval != PAM_SUCCESS) {
	    if (resp != NULL)
		_pam_drop_reply(resp,i);
	    return ((retval == PAM_CONV_AGAIN)
		    ? PAM_INCOMPLETE:PAM_AUTHINFO_UNAVAIL);
	}

	if (anon) {
	    /* XXX: Some effort should be made to verify this email address! */

	    if (!(ctrl & PAM_IGNORE_EMAIL)) {
		token = strtok(resp->resp, "@");
		retval = pam_set_item(pamh, PAM_RUSER, token);

		if ((token) && (retval == PAM_SUCCESS)) {
		    token = strtok(NULL, "@");
		    retval = pam_set_item(pamh, PAM_RHOST, token);
		}
	    }

	    /* we are happy to grant annonymous access to the user */
	    retval = PAM_SUCCESS;

	} else {
	    /*
	     * we have a password so set AUTHTOK
	     */

	    (void) pam_set_item(pamh, PAM_AUTHTOK, resp->resp);

	    /*
	     * this module failed, but the next one might succeed with
	     * this password.
	     */

	    retval = PAM_AUTH_ERR;
	}

	if (resp) {                                      /* clean up */
	    _pam_drop_reply(resp, i);
	}

	/* success or failure */

	return retval;
    }
}
示例#19
0
PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
				int argc, const char **argv)
{
	unsigned int lctrl;
	int retval;
	unsigned int ctrl = _pam_parse(argc, argv);

	/* <DO NOT free() THESE> */
	const char *user;
	const char *member = NULL;
	char *pass_old, *pass_new;
	/* </DO NOT free() THESE> */

	char *Announce;
	
	int retry = 0;

	/*
	 * First get the name of a user
	 */
	retval = pam_get_user(pamh, &user, "Username: "******"username was NULL!");
			return PAM_USER_UNKNOWN;
		}
		if (retval == PAM_SUCCESS && on(WINBIND_DEBUG_ARG, ctrl))
			_pam_log(LOG_DEBUG, "username [%s] obtained",
				 user);
	} else {
		if (on(WINBIND_DEBUG_ARG, ctrl))
			_pam_log(LOG_DEBUG,
				 "password - could not identify user");
		return retval;
	}

	/*
	 * obtain and verify the current password (OLDAUTHTOK) for
	 * the user.
	 */

	if (flags & PAM_PRELIM_CHECK) {
		
		/* instruct user what is happening */
#define greeting "Changing password for "
		Announce = (char *) malloc(sizeof(greeting) + strlen(user));
		if (Announce == NULL) {
		_pam_log(LOG_CRIT, 
			 "password - out of memory");
		return PAM_BUF_ERR;
		}
		(void) strcpy(Announce, greeting);
		(void) strcpy(Announce + sizeof(greeting) - 1, user);
#undef greeting
		
		lctrl = ctrl | WINBIND__OLD_PASSWORD;
		retval = _winbind_read_password(pamh, lctrl
						,Announce
						,"(current) NT password: "******"password - (old) token not obtained");
			return retval;
		}
		/* verify that this is the password for this user */
		
		retval = winbind_auth_request(user, pass_old, member, ctrl);
		
		if (retval != PAM_ACCT_EXPIRED 
		    && retval != PAM_AUTHTOK_EXPIRED
		    && retval != PAM_NEW_AUTHTOK_REQD 
		    && retval != PAM_SUCCESS) {
			pass_old = NULL;
			return retval;
		}
		
		retval = pam_set_item(pamh, PAM_OLDAUTHTOK, (const void *) pass_old);
		pass_old = NULL;
		if (retval != PAM_SUCCESS) {
			_pam_log(LOG_CRIT, 
				 "failed to set PAM_OLDAUTHTOK");
		}
	} else if (flags & PAM_UPDATE_AUTHTOK) {
	
		/*
		 * obtain the proposed password
		 */
		
		/*
		 * get the old token back. 
		 */
		
		retval = pam_get_item(pamh, PAM_OLDAUTHTOK
				      ,(const void **) &pass_old);
		
		if (retval != PAM_SUCCESS) {
			_pam_log(LOG_NOTICE, "user not authenticated");
			return retval;
		}
		
		lctrl = ctrl;
		
		if (on(WINBIND_USE_AUTHTOK_ARG, lctrl)) {
			lctrl |= WINBIND_USE_FIRST_PASS_ARG;
		}
		retry = 0;
		retval = PAM_AUTHTOK_ERR;
		while ((retval != PAM_SUCCESS) && (retry++ < MAX_PASSWD_TRIES)) {
			/*
			 * use_authtok is to force the use of a previously entered
			 * password -- needed for pluggable password strength checking
			 */
			
			retval = _winbind_read_password(pamh, lctrl
							,NULL
							,"Enter new NT password: "******"Retype new NT password: "******"password - new password not obtained");
				}
				pass_old = NULL;/* tidy up */
				return retval;
			}

			/*
			 * At this point we know who the user is and what they
			 * propose as their new password. Verify that the new
			 * password is acceptable.
			 */
			
			if (pass_new[0] == '\0') {/* "\0" password = NULL */
				pass_new = NULL;
			}
		}
		
		/*
		 * By reaching here we have approved the passwords and must now
		 * rebuild the password database file.
		 */

		retval = winbind_chauthtok_request(user, pass_old, pass_new, ctrl);
		_pam_overwrite(pass_new);
		_pam_overwrite(pass_old);
		pass_old = pass_new = NULL;
	} else {
		retval = PAM_SERVICE_ERR;
	}
	
	return retval;
}
示例#20
0
/* now the session stuff */
PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags,
                                   int argc, const char **argv)
{
    int retval;
    char *user_name;
    struct passwd *pwd;
    int ctrl;
    struct pam_limit_s pl;

    D(("called."));

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

    ctrl = _pam_parse(argc, argv, &pl);
    retval = pam_get_item( pamh, PAM_USER, (void*) &user_name );
    if ( user_name == NULL || retval != PAM_SUCCESS ) {
        _pam_log(LOG_CRIT, "open_session - error recovering username");
        return PAM_SESSION_ERR;
     }
	
    setpwent();
    pwd = getpwnam(user_name);
    endpwent();
    if (!pwd) {
        if (ctrl & PAM_DEBUG_ARG)
            _pam_log(LOG_WARNING, "open_session username '%s' does not exist",
                                   user_name);
        return PAM_SESSION_ERR;
    }
                     
    /* do not impose limits on UID 0 accounts */
    if (!pwd->pw_uid) {
        if (ctrl & PAM_DEBUG_ARG)
            _pam_log(LOG_DEBUG, "user '%s' have UID 0 - no limits imposed",
                                user_name);
        return PAM_SUCCESS;
    }
        
    retval = init_limits(&pl);
    if (retval != PAM_SUCCESS) {
        _pam_log(LOG_WARNING, "cannot initialize");
        return PAM_IGNORE;
    }

    retval = parse_config_file(pwd->pw_name, ctrl, &pl);
    if (retval == PAM_IGNORE) {
	D(("the configuration file has an applicable '<domain> -' entry"));
	return PAM_SUCCESS;
    }
    if (retval != PAM_SUCCESS) {
        _pam_log(LOG_WARNING, "error parsing the configuration file");
        return PAM_IGNORE;
    }

    if (ctrl & PAM_DO_SETREUID)
	setreuid(pwd->pw_uid, -1);
    retval = setup_limits(pwd->pw_name, ctrl, &pl);
    if (retval & LOGIN_ERR) {
        printf("\nToo many logins for '%s'\n",pwd->pw_name);
        sleep(2);
        return PAM_PERM_DENIED;
    }

    return PAM_SUCCESS;
}
示例#21
0
PAM_EXTERN int
pam_sm_chauthtok(pam_handle_t *pamh, int flags,
                 int argc, const char **argv)
{
        int ctrl;
        struct module_options options;

        memset(&options, 0, sizeof(options));
        options.retry_times = CO_RETRY_TIMES;

        ctrl = _pam_parse(pamh, &options, argc, argv);
        if (ctrl < 0)
                return PAM_BUF_ERR;

        if (flags & PAM_PRELIM_CHECK) {
                /* Check for passwd dictionary
                 * We cannot do that, since the original path is compiled
                 * into the cracklib library and we don't know it.
                 */
                return PAM_SUCCESS;
        } else if (flags & PAM_UPDATE_AUTHTOK) {
                int retval;
                const void *oldtoken;
                const char *user;
                int tries;

                retval = pam_get_user(pamh, &user, NULL);
                if (retval != PAM_SUCCESS || user == NULL) {
                        if (ctrl & PAM_DEBUG_ARG)
                                pam_syslog(pamh, LOG_ERR, "Can not get username");
                        return PAM_AUTHTOK_ERR;
                }

                retval = pam_get_item(pamh, PAM_OLDAUTHTOK, &oldtoken);
                if (retval != PAM_SUCCESS) {
                        if (ctrl & PAM_DEBUG_ARG)
                                pam_syslog(pamh, LOG_ERR, "Can not get old passwd");
                        oldtoken = NULL;
                }

                tries = 0;
                while (tries < options.retry_times) {
                        void *auxerror;
                        const char *newtoken = NULL;

                        tries++;

                        /* Planned modus operandi:
                         * Get a passwd.
                         * Verify it against libpwquality.
                         * If okay get it a second time.
                         * Check to be the same with the first one.
                         * set PAM_AUTHTOK and return
                         */

                        retval = pam_get_authtok_noverify(pamh, &newtoken, NULL);
                        if (retval != PAM_SUCCESS) {
                                pam_syslog(pamh, LOG_ERR, "pam_get_authtok_noverify returned error: %s",
                                        pam_strerror(pamh, retval));
                                continue;
                        } else if (newtoken == NULL) { /* user aborted password change, quit */
                                return PAM_AUTHTOK_ERR;
                        }

                        /* now test this passwd against libpwquality */
                        retval = pwquality_check(options.pwq, newtoken, oldtoken, user, &auxerror);

                        if (retval < 0) {
                                const char *msg;
                                char buf[PWQ_MAX_ERROR_MESSAGE_LEN];
                                msg = pwquality_strerror(buf, sizeof(buf), retval, auxerror);
                                if (ctrl & PAM_DEBUG_ARG)
                                        pam_syslog(pamh, LOG_DEBUG, "bad password: %s", msg);
                                pam_error(pamh, _("BAD PASSWORD: %s"), msg);

                                if (getuid() || options.enforce_for_root ||
                                    (flags & PAM_CHANGE_EXPIRED_AUTHTOK)) {
                                        pam_set_item(pamh, PAM_AUTHTOK, NULL);
                                        retval = PAM_AUTHTOK_ERR;
                                        continue;
                                }
                        } else {
                                if (ctrl & PAM_DEBUG_ARG)
                                        pam_syslog(pamh, LOG_DEBUG, "password score: %d", retval);
                        }

                        retval = pam_get_authtok_verify(pamh, &newtoken, NULL);
                        if (retval != PAM_SUCCESS) {
                                pam_syslog(pamh, LOG_ERR, "pam_get_authtok_verify returned error: %s",
                                pam_strerror(pamh, retval));
                                pam_set_item(pamh, PAM_AUTHTOK, NULL);
                                continue;
                        } else if (newtoken == NULL) {      /* user aborted password change, quit */
                                return PAM_AUTHTOK_ERR;
                        }

                        return PAM_SUCCESS;
                }

                pam_set_item (pamh, PAM_AUTHTOK, NULL);

                /* if we have only one try, we can use the real reason,
                 * else say that there were too many tries. */
                if (options.retry_times > 1)
                        return PAM_MAXTRIES;
                else
                        return retval;
        } else {
                if (ctrl & PAM_DEBUG_ARG)
                        pam_syslog(pamh, LOG_NOTICE, "UNKNOWN flags setting %02X",flags);
        }

        return PAM_SERVICE_ERR;
}
示例#22
0
文件: pam_userdb.c 项目: ssem/rat
PAM_EXTERN int
pam_sm_authenticate(pam_handle_t *pamh, int flags UNUSED,
		    int argc, const char **argv)
{
     const char *username;
     const void *password;
     const char *database = NULL;
     const char *cryptmode = NULL;
     int retval = PAM_AUTH_ERR, ctrl;

     /* parse arguments */
     ctrl = _pam_parse(pamh, argc, argv, &database, &cryptmode);
     if (database == NULL) {
        pam_syslog(pamh, LOG_ERR, "can not get the database name");
        return PAM_SERVICE_ERR;
     }

     /* Get the username */
     retval = pam_get_user(pamh, &username, NULL);
     if ((retval != PAM_SUCCESS) || (!username)) {
        pam_syslog(pamh, LOG_ERR, "can not get the username");
        return PAM_SERVICE_ERR;
     }

     if ((ctrl & PAM_USE_FPASS_ARG) == 0 && (ctrl & PAM_TRY_FPASS_ARG) == 0) {
        /* Converse to obtain a password */
        retval = obtain_authtok(pamh);
        if (retval != PAM_SUCCESS) {
	    pam_syslog(pamh, LOG_ERR, "can not obtain password from user");
	    return retval;
        }
     }

     /* Check if we got a password */
     retval = pam_get_item(pamh, PAM_AUTHTOK, &password);
     if (retval != PAM_SUCCESS || password == NULL) {
        if ((ctrl & PAM_TRY_FPASS_ARG) != 0) {
	    /* Converse to obtain a password */
	    retval = obtain_authtok(pamh);
	    if (retval != PAM_SUCCESS) {
	        pam_syslog(pamh, LOG_ERR, "can not obtain password from user");
		return retval;
	    }
	    retval = pam_get_item(pamh, PAM_AUTHTOK, &password);
	}
	if (retval != PAM_SUCCESS || password == NULL) {
	    pam_syslog(pamh, LOG_ERR, "can not recover user password");
	    return PAM_AUTHTOK_RECOVERY_ERR;
	}
     }

     if (ctrl & PAM_DEBUG_ARG)
	 pam_syslog(pamh, LOG_INFO, "Verify user `%s' with a password",
		    username);

     /* Now use the username to look up password in the database file */
     retval = user_lookup(pamh, database, cryptmode, username, password, ctrl);
     switch (retval) {
	 case -2:
	     /* some sort of system error. The log was already printed */
	     return PAM_SERVICE_ERR;
	 case -1:
	     /* incorrect password */
	     pam_syslog(pamh, LOG_WARNING,
			"user `%s' denied access (incorrect password)",
			username);
	     return PAM_AUTH_ERR;
	 case 1:
	     /* the user does not exist in the database */
	     if (ctrl & PAM_DEBUG_ARG)
		 pam_syslog(pamh, LOG_NOTICE,
			    "user `%s' not found in the database", username);
	     return PAM_USER_UNKNOWN;
	 case 0:
	     /* Otherwise, the authentication looked good */
	     pam_syslog(pamh, LOG_NOTICE, "user '%s' granted access", username);
	     return PAM_SUCCESS;
	 default:
	     /* we don't know anything about this return value */
	     pam_syslog(pamh, LOG_ERR,
		      "internal module error (retval = %d, user = `%s'",
		      retval, username);
	     return PAM_SERVICE_ERR;
     }

     /* should not be reached */
     return PAM_IGNORE;
}
示例#23
0
/* authenticates user on remote TACACS+ server
 * returns PAM_SUCCESS if the supplied username and password
 * pair is valid
 */
PAM_EXTERN
int pam_sm_authenticate (pam_handle_t * pamh, int flags,
    int argc, const char **argv) {

    int ctrl, retval;
    char *user;
    char *pass;
    char *tty;
    char *r_addr;
    int srv_i;
    int tac_fd, status, msg, communicating;

    user = pass = tty = r_addr = NULL;

    ctrl = _pam_parse(argc, argv);

    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: called (pam_tacplus v%u.%u.%u)",
            __FUNCTION__, PAM_TAC_VMAJ, PAM_TAC_VMIN, PAM_TAC_VPAT);

    if ((user = _pam_get_user(pamh)) == NULL)
        return PAM_USER_UNKNOWN;

    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: user [%s] obtained", __FUNCTION__, user);

    retval = tacacs_get_password (pamh, flags, ctrl, &pass);
    if (retval != PAM_SUCCESS || pass == NULL || *pass == '\0') {
        _pam_log(LOG_ERR, "unable to obtain password");
        return PAM_CRED_INSUFFICIENT;
    }

    retval = pam_set_item (pamh, PAM_AUTHTOK, pass);
    if (retval != PAM_SUCCESS) {
        _pam_log(LOG_ERR, "unable to set password");
        return PAM_CRED_INSUFFICIENT;
    }

    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: password obtained", __FUNCTION__);

    tty = _pam_get_terminal(pamh);
    if (!strncmp(tty, "/dev/", 5))
        tty += 5;
    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: tty [%s] obtained", __FUNCTION__, tty);

    r_addr = _pam_get_rhost(pamh);
    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: rhost [%s] obtained", __FUNCTION__, r_addr);

    status = PAM_AUTHINFO_UNAVAIL;
    for (srv_i = 0; srv_i < tac_srv_no; srv_i++) {
        if (ctrl & PAM_TAC_DEBUG)
            syslog(LOG_DEBUG, "%s: trying srv %d", __FUNCTION__, srv_i );

        tac_fd = tac_connect_single(tac_srv[srv_i].addr, tac_srv[srv_i].key, NULL, tac_timeout);
        if (tac_fd < 0) {
            _pam_log(LOG_ERR, "connection failed srv %d: %m", srv_i);
            continue;
        }
        if (tac_authen_send(tac_fd, user, pass, tty, r_addr, TAC_PLUS_AUTHEN_LOGIN) < 0) {
            close(tac_fd);
            _pam_log(LOG_ERR, "error sending auth req to TACACS+ server");
            continue;
        }
        communicating = 1;
        while (communicating) {
            struct areply re = { .attr = NULL, .msg = NULL, status = 0, flags = 0 };
            struct pam_message conv_msg = { .msg_style = 0, .msg = NULL };
            struct pam_response *resp = NULL;

            msg = tac_authen_read(tac_fd, &re);

            if (NULL != re.msg) {
                conv_msg.msg = re.msg;
            }

            /* talk the protocol */
            switch (msg) {
                case TAC_PLUS_AUTHEN_STATUS_PASS:
                    /* success */
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_PASS");
  
                    if (NULL != conv_msg.msg) {
                        int retval = -1;

                        conv_msg.msg_style = PAM_TEXT_INFO;
                        retval = converse(pamh, 1, &conv_msg, &resp);
                        if (PAM_SUCCESS == retval) {
                            if (PAM_TAC_DEBUG == (ctrl & PAM_TAC_DEBUG))
                                syslog(LOG_DEBUG, "send msg=\"%s\"", conv_msg.msg);
                        }
                        else {
                            _pam_log(LOG_WARNING, "%s: error sending msg=\"%s\", retval=%d",
                                     __FUNCTION__, conv_msg.msg, retval);
                        }

                    }
                    status = PAM_SUCCESS;
                    communicating = 0;
                    active_server.addr = tac_srv[srv_i].addr;
                    active_server.key = tac_srv[srv_i].key;

                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "%s: active srv %d", __FUNCTION__, srv_i);

                    break;

                case TAC_PLUS_AUTHEN_STATUS_FAIL:
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_FAIL");

                    if (NULL != conv_msg.msg) {
                        int retval = -1;

                        conv_msg.msg_style = PAM_ERROR_MSG;
                        retval = converse(pamh, 1, &conv_msg, &resp);
                        if (PAM_SUCCESS == retval) {
                            if (PAM_TAC_DEBUG == (ctrl & PAM_TAC_DEBUG))
                                syslog(LOG_DEBUG, "send msg=\"%s\"", conv_msg.msg);
                        }
                        else {
                            _pam_log(LOG_WARNING, "%s: error sending msg=\"%s\", retval=%d",
                                     __FUNCTION__, conv_msg.msg, retval);
                        }

                    }
                    status = PAM_AUTH_ERR;
                    communicating = 0;

                    _pam_log(LOG_ERR, "auth failed: %d", msg);

                    break;

                case TAC_PLUS_AUTHEN_STATUS_GETDATA:
                    if (PAM_TAC_DEBUG == (ctrl & PAM_TAC_DEBUG))
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_GETDATA");

                    if (NULL != conv_msg.msg) {
                        int retval = -1;
                        int echo_off = (0x1 == (re.flags & 0x1));
                        
                        conv_msg.msg_style = echo_off ? PAM_PROMPT_ECHO_OFF : PAM_PROMPT_ECHO_ON;
                        retval = converse(pamh, 1, &conv_msg, &resp);
                        if (PAM_SUCCESS == retval) {
                            if (PAM_TAC_DEBUG == (ctrl & PAM_TAC_DEBUG)) 
                                syslog(LOG_DEBUG, "sent msg=\"%s\", resp=\"%s\"",
                                       conv_msg.msg, resp->resp);

                            if (PAM_TAC_DEBUG == (ctrl & PAM_TAC_DEBUG))
                                syslog(LOG_DEBUG, "%s: calling tac_cont_send", __FUNCTION__);

                            if (0 > tac_cont_send_seq(tac_fd, resp->resp, re.seq_no + 1)) {
                                _pam_log(LOG_ERR, "error sending continue req to TACACS+ server");
                                status = PAM_AUTH_ERR;
                                communicating = 0;
                            }
                        }
                        else {
                            _pam_log(LOG_WARNING, "%s: error sending msg=\"%s\", retval=%d (%s)",
                                     __FUNCTION__, conv_msg.msg, retval, pam_strerror(pamh, retval));
                            status = PAM_AUTH_ERR;
                            communicating = 0;
                        }
                    }
                    else { 
                        syslog(LOG_ERR, "GETDATA response with no message, returning PAM_AUTH_ERR");

                        status = PAM_AUTH_ERR;
                        communicating = 0;
                    }

                    break;

                case TAC_PLUS_AUTHEN_STATUS_GETUSER:
                    /* not implemented */
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_GETUSER");

                    communicating = 0;
                    break;

                case TAC_PLUS_AUTHEN_STATUS_GETPASS:
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_GETPASS");

                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "%s: tac_cont_send called", __FUNCTION__);

                    if (tac_cont_send(tac_fd, pass) < 0) {
                        _pam_log (LOG_ERR, "error sending continue req to TACACS+ server");
                        communicating = 0;
                    }
                    /* continue the while loop; go read tac response */
                    break;

                case TAC_PLUS_AUTHEN_STATUS_RESTART:
                    /* try it again */
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_RESTART");

                    /*
                     * not implemented
                     * WdJ: I *think* you can just do tac_authen_send(user, pass) again
                     *      but I'm not sure
                     */
                    communicating = 0;
                    break;

                case TAC_PLUS_AUTHEN_STATUS_ERROR:
                    /* server has problems */
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_ERROR");

                    communicating = 0;
                    break;

                case TAC_PLUS_AUTHEN_STATUS_FOLLOW:
                    /* server tells to try a different server address */
                    /* not implemented */
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_FOLLOW");

                    communicating = 0;
                    break;

                default:
                    if (msg < 0) {
                        /* connection error */
                        communicating = 0;
                        if (ctrl & PAM_TAC_DEBUG)
                            syslog(LOG_DEBUG, "error communicating with tacacs server");
                        break;
                    }

                    /* unknown response code */
                    communicating = 0;
                    if (ctrl & PAM_TAC_DEBUG)
                        syslog(LOG_DEBUG, "tacacs status: unknown response 0x%02x", msg);
            }

            if (NULL != resp) {
                free(resp->resp);
                free(resp);
            }
                
            free(re.msg);

        }    /* end while(communicating) */
        close(tac_fd);

        if (status == PAM_SUCCESS || status == PAM_AUTH_ERR)
            break;
    }
    if (status != PAM_SUCCESS && status != PAM_AUTH_ERR)
        _pam_log(LOG_ERR, "no more servers to connect");

    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: exit with pam status: %d", __FUNCTION__, status);

    if (NULL != pass) {
        bzero(pass, strlen (pass));
        free(pass);
        pass = NULL;
    }

    return status;
}    /* pam_sm_authenticate */


/* no-op function to satisfy PAM authentication module */
PAM_EXTERN
int pam_sm_setcred (pam_handle_t * pamh, int flags,
    int argc, const char **argv) {

    int ctrl = _pam_parse (argc, argv);

    if (ctrl & PAM_TAC_DEBUG)
        syslog (LOG_DEBUG, "%s: called (pam_tacplus v%u.%u.%u)"
            , __FUNCTION__, PAM_TAC_VMAJ, PAM_TAC_VMIN, PAM_TAC_VPAT);

    return PAM_SUCCESS;
}    /* pam_sm_setcred */


/* authorizes user on remote TACACS+ server, i.e. checks
 * his permission to access requested service
 * returns PAM_SUCCESS if the service is allowed
 */
PAM_EXTERN
int pam_sm_acct_mgmt (pam_handle_t * pamh, int flags,
    int argc, const char **argv) {

    int retval, ctrl, status=PAM_AUTH_ERR;
    char *user;
    char *tty;
    char *r_addr;
    struct areply arep;
    struct tac_attrib *attr = NULL;
    int tac_fd;

    user = tty = r_addr = NULL;

    /* this also obtains service name for authorization
       this should be normally performed by pam_get_item(PAM_SERVICE)
       but since PAM service names are incompatible TACACS+
       we have to pass it via command line argument until a better
       solution is found ;) */
    ctrl = _pam_parse (argc, argv);

    if (ctrl & PAM_TAC_DEBUG)
        syslog (LOG_DEBUG, "%s: called (pam_tacplus v%u.%u.%u)"
            , __FUNCTION__, PAM_TAC_VMAJ, PAM_TAC_VMIN, PAM_TAC_VPAT);

    if ((user = _pam_get_user(pamh)) == NULL)
        return PAM_USER_UNKNOWN;

    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: username obtained [%s]", __FUNCTION__, user);

    tty = _pam_get_terminal(pamh);
    if(!strncmp(tty, "/dev/", 5))
        tty += 5;
    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: tty obtained [%s]", __FUNCTION__, tty);

    r_addr = _pam_get_rhost(pamh);
    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: rhost obtained [%s]", __FUNCTION__, r_addr);

    /* checks if user has been successfully authenticated
       by TACACS+; we cannot solely authorize user if it hasn't
       been authenticated or has been authenticated by method other
       than TACACS+ */
    if(active_server.addr == NULL) {
        _pam_log (LOG_ERR, "user not authenticated by TACACS+");
        return PAM_AUTH_ERR;
    }
    if (ctrl & PAM_TAC_DEBUG)
        syslog (LOG_DEBUG, "%s: active server is [%s]", __FUNCTION__,
            tac_ntop(active_server.addr->ai_addr));

    /* checks for specific data required by TACACS+, which should
       be supplied in command line  */
    if(!*tac_service) {
        _pam_log (LOG_ERR, "SM: TACACS+ service type not configured");
        return PAM_AUTH_ERR;
    }
    if(tac_protocol == NULL || !*tac_protocol) {
        _pam_log (LOG_ERR, "SM: TACACS+ protocol type not configured (IGNORED)");
    }

    tac_add_attrib(&attr, "service", tac_service);
    if(tac_protocol != NULL && tac_protocol[0] != '\0')
      tac_add_attrib(&attr, "protocol", tac_protocol);

    tac_fd = tac_connect_single(active_server.addr, active_server.key, NULL, tac_timeout);
    if(tac_fd < 0) {
        _pam_log (LOG_ERR, "TACACS+ server unavailable");
        if(arep.msg != NULL)
            free (arep.msg);

        close(tac_fd);
        return PAM_AUTH_ERR;
    }

    retval = tac_author_send(tac_fd, user, tty, r_addr, attr);

    tac_free_attrib(&attr);

    if(retval < 0) {
        _pam_log (LOG_ERR, "error getting authorization");
        if(arep.msg != NULL)
            free (arep.msg);

        close(tac_fd);
        return PAM_AUTH_ERR;
    }

    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: sent authorization request", __FUNCTION__);

    tac_author_read(tac_fd, &arep);

    if(arep.status != AUTHOR_STATUS_PASS_ADD &&
        arep.status != AUTHOR_STATUS_PASS_REPL) {

        _pam_log (LOG_ERR, "TACACS+ authorisation failed for [%s]", user);
        if(arep.msg != NULL)
            free (arep.msg);

        close(tac_fd);
        return PAM_PERM_DENIED;
    }

    if (ctrl & PAM_TAC_DEBUG)
        syslog(LOG_DEBUG, "%s: user [%s] successfully authorized", __FUNCTION__, user);

    status = PAM_SUCCESS;

    attr = arep.attr;
    while (attr != NULL)  {
        char attribute[attr->attr_len];
        char value[attr->attr_len];
        char *sep;

        sep = index(attr->attr, '=');
        if(sep == NULL)
            sep = index(attr->attr, '*');
        if(sep != NULL) {
            bcopy(attr->attr, attribute, attr->attr_len-strlen(sep));
            attribute[attr->attr_len-strlen(sep)] = '\0';
            bcopy(sep, value, strlen(sep));
            value[strlen(sep)] = '\0';

            size_t i;
            for (i = 0; attribute[i] != '\0'; i++) {
                attribute[i] = toupper(attribute[i]);
                if (attribute[i] == '-')
                    attribute[i] = '_';
            }

            if (ctrl & PAM_TAC_DEBUG)
                syslog(LOG_DEBUG, "%s: returned attribute `%s%s' from server", __FUNCTION__, attribute, value);

            /* make returned attributes available for other PAM modules via PAM environment */
            if (pam_putenv(pamh, strncat(attribute, value, strlen(value))) != PAM_SUCCESS)
                syslog(LOG_WARNING, "%s: unable to set PAM environment", __FUNCTION__);

        } else {
            syslog(LOG_WARNING, "%s: invalid attribute `%s', no separator", __FUNCTION__, attr->attr);
        }
        attr = attr->next;
    }

    /* free returned attributes */
    if(arep.attr != NULL)
        tac_free_attrib(&arep.attr);

    if(arep.msg != NULL)
        free (arep.msg);

    close(tac_fd);

    return status;
}    /* pam_sm_acct_mgmt */