예제 #1
0
파일: util.c 프로젝트: jsbillings/duo_unix
int
duo_check_groups(struct passwd *pw, char **groups, int groups_cnt)
{
    int i;

    if (groups_cnt > 0) {
        int matched = 0;

        if (ga_init(pw->pw_name, pw->pw_gid) < 0) {
            duo_log(LOG_ERR, "Couldn't get groups",
                pw->pw_name, NULL, strerror(errno));
            return (-1);
        }
        for (i = 0; i < groups_cnt; i++) {
            if (ga_match_pattern_list(groups[i])) {
                matched = 1;
                break;
            }
        }
        ga_free();

        /* User in configured groups for Duo auth? */
        return matched;
    } else {
        return 1;
    }
}
예제 #2
0
static int
match_cfg_line_group(const char *grps, int line, const char *user)
{
	int result = 0;
	struct passwd *pw;

	if (user == NULL)
		goto out;

	if ((pw = getpwnam(user)) == NULL) {
		debug("Can't match group at line %d because user %.100s does "
		    "not exist", line, user);
	} else if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
		debug("Can't Match group because user %.100s not in any group "
		    "at line %d", user, line);
	} else if (ga_match_pattern_list(grps) != 1) {
		debug("user %.100s does not match group list %.100s at line %d",
		    user, grps, line);
	} else {
		debug("user %.100s matched group list %.100s at line %d", user,
		    grps, line);
		result = 1;
	}
out:
	ga_free();
	return result;
}
예제 #3
0
PAM_EXTERN int
pam_sm_authenticate(pam_handle_t *pamh, int pam_flags,
    int argc, const char *argv[])
{
	struct duo_config cfg;
	struct passwd *pw;
	duo_t *duo;
	duo_code_t code;
	duopam_const char *config, *cmd, *ip, *p, *service, *user;
	int i, flags, pam_err;

	memset(&cfg, 0, sizeof(cfg));
        cfg.failmode = DUO_FAIL_SAFE;

	/* Parse configuration */
	config = DUO_CONF;
	for (i = 0; i < argc; i++) {
		if (strncmp("conf=", argv[i], 5) == 0) {
			config = argv[i] + 5;
		} else if (strcmp("debug", argv[i]) == 0) {
			options |= PAM_OPT_DEBUG;
		} else if (strcmp("try_first_pass", argv[i]) == 0) {
			options |= PAM_OPT_TRY_FIRST_PASS;
		} else if (strcmp("use_first_pass", argv[i]) == 0) {
			options |= PAM_OPT_USE_FIRST_PASS|PAM_OPT_TRY_FIRST_PASS;
		} else if (strcmp("use_uid", argv[i]) == 0) {
			options |= PAM_OPT_USE_UID;
		} else if (strcmp("push", argv[i]) == 0) {
			options |= PAM_OPT_PUSH;
		} else {
			_syslog(LOG_ERR, "Invalid pam_duo option: '%s'",
			    argv[i]);
			return (PAM_SERVICE_ERR);
		}
	}
	i = duo_parse_config(config, __ini_handler, &cfg);
	if (i == -2) {
		_syslog(LOG_ERR, "%s must be readable only by user 'root'",
		    config);
		return (PAM_SERVICE_ERR);
	} else if (i == -1) {
		_syslog(LOG_ERR, "Couldn't open %s: %s",
		    config, strerror(errno));
		return (PAM_SERVICE_ERR);
	} else if (i > 0) {
		_syslog(LOG_ERR, "Parse error in %s, line %d", config, i);
		return (PAM_SERVICE_ERR);
	} else if (!cfg.host || !cfg.host[0] ||
            !cfg.skey || !cfg.skey[0] || !cfg.ikey || !cfg.ikey[0]) {
		_syslog(LOG_ERR, "Missing host, ikey, or skey in %s", config);
		return (PAM_SERVICE_ERR);
	}
        
        /* Check user */
        if (pam_get_user(pamh, &user, NULL) != PAM_SUCCESS ||
            (pw = getpwnam(user)) == NULL) {
                return (PAM_USER_UNKNOWN);
        }
        /* XXX - Service-specific behavior */
	flags = 0;
        cmd = NULL;
	if (pam_get_item(pamh, PAM_SERVICE, (duopam_const void **)
		(duopam_const void *)&service) != PAM_SUCCESS) {
                return (PAM_SERVICE_ERR);
        }
	if (options & PAM_OPT_USE_UID) {
                /* Check calling user for Duo auth, just like sudo */
                if ((pw = getpwuid(getuid())) == NULL) {
                        return (PAM_USER_UNKNOWN);
                }
                user = pw->pw_name;
	}

        if (strcmp(service, "sshd") == 0) {
                /*
                 * Disable incremental status reporting for sshd :-(
                 * OpenSSH accumulates PAM_TEXT_INFO from modules to send in
                 * an SSH_MSG_USERAUTH_BANNER post-auth, not real-time!
                 */
                flags |= DUO_FLAG_SYNC;
        } else if (strcmp(service, "sudo") == 0) {
                cmd = getenv("SUDO_COMMAND");
        }
	/* Check group membership */
	if (cfg.groups_cnt > 0) {
		int matched = 0;

		if (ga_init(pw->pw_name, pw->pw_gid) < 0) {
			_log(LOG_ERR, "Couldn't get groups",
			    pw->pw_name, NULL, strerror(errno));
			return (PAM_SERVICE_ERR);
		}
		for (i = 0; i < cfg.groups_cnt; i++) {
			if (ga_match_pattern_list(cfg.groups[i])) {
				matched = 1;
				break;
			}
		}
		ga_free();

		/* User in configured groups for Duo auth? */
		if (!matched)
			return (PAM_SUCCESS);
	}

	ip = NULL;
	pam_get_item(pamh, PAM_RHOST,
	    (duopam_const void **)(duopam_const void *)&ip);

	/* Honor configured http_proxy */
	if (cfg.http_proxy != NULL) {
		setenv("http_proxy", cfg.http_proxy, 1);
	}

	/* Try Duo auth */
	if ((duo = duo_open(cfg.host, cfg.ikey, cfg.skey,
                    "pam_duo/" PACKAGE_VERSION,
                    cfg.noverify ? "" : cfg.cafile)) == NULL) {
		_log(LOG_ERR, "Couldn't open Duo API handle", user, ip, NULL);
		return (PAM_SERVICE_ERR);
	}
	duo_set_conv_funcs(duo, __duo_prompt, __duo_status, pamh);

	pam_err = PAM_SERVICE_ERR;
	
	for (i = 0; i < MAX_RETRIES; i++) {
		code = duo_login(duo, user, ip, flags,
                    cfg.pushinfo ? cmd : NULL);
		if (code == DUO_FAIL) {
			_log(LOG_WARNING, "Failed Duo login",
			    user, ip, duo_geterr(duo));
			if ((flags & DUO_FLAG_SYNC) == 0) {
				pam_info(pamh, "%s", "");
                        }
			/* Keep going */
			continue;
		}
		/* Terminal conditions */
		if (code == DUO_OK) {
			if ((p = duo_geterr(duo)) != NULL) {
				_log(LOG_WARNING, "Skipped Duo login",
				    user, ip, p);
			} else {
				_log(LOG_INFO, "Successful Duo login",
				    user, ip, NULL);
			}
			pam_err = PAM_SUCCESS;
		} else if (code == DUO_ABORT) {
			_log(LOG_WARNING, "Aborted Duo login",
			    user, ip, duo_geterr(duo));
			pam_err = PAM_ABORT;
		} else if (cfg.failmode == DUO_FAIL_SAFE &&
                    (code == DUO_CONN_ERROR ||
                     code == DUO_CLIENT_ERROR || code == DUO_SERVER_ERROR)) {
			_log(LOG_WARNING, "Failsafe Duo login",
			    user, ip, duo_geterr(duo));
			pam_err = PAM_SUCCESS;
		} else {
			_log(LOG_ERR, "Error in Duo login",
			    user, ip, duo_geterr(duo));
			pam_err = PAM_SERVICE_ERR;
		}
		break;
	}
	if (i == MAX_RETRIES) {
		pam_err = PAM_MAXTRIES;
	}
	duo_close(duo);
	
	return (pam_err);
}