Пример #1
0
PAM_EXTERN int
pam_sm_authenticate(pam_handle_t *pamh, int flags,
    int argc, const char *argv[])
{
	int ret;
	int faked = 0;
	const char *dir = NULL;
	const char *fake_suite = NULL;
	char *questions;
	const char *user;
	char *response = NULL;
	char fmt[512];

	(void)flags;
	(void)argc;
	(void)argv;

	pam_get_item(pamh, PAM_USER, (const void **)&user);

	openlog("pam_ocra", 0, LOG_AUTHPRIV);

	fake_suite = openpam_get_option(pamh, "fake_prompt");
	dir = openpam_get_option(pamh, "dir");
	if (PAM_SUCCESS != (ret = challenge(dir, user, &questions))) {
		if (PAM_NO_MODULE_DATA == ret && NULL != fake_suite) {
			if (PAM_SUCCESS !=
			    (ret = fake_challenge(fake_suite, &questions)))
				goto end;
			faked = 1;
		} else
			goto end;
	}
	snprintf(fmt, 512, "OCRA Challenge: %s\nOCRA  Response: ", questions);
	if (PAM_SUCCESS != (ret = get_response(pamh, fmt, &response)))
		goto end;
	if (1 == faked)
		ret = PAM_AUTH_ERR;
	else
		ret = verify(dir, user, questions, response);

	free(response);
end:
	closelog();
	return ret;
}
Пример #2
0
int
pam_get_user(pam_handle_t *pamh,
	const char **user,
	const char *prompt)
{
	char prompt_buf[1024];
	size_t prompt_size;
	const void *promptp;
	char *resp;
	int r;

	ENTER();
	if (pamh == NULL || user == NULL)
		RETURNC(PAM_SYSTEM_ERR);
	r = pam_get_item(pamh, PAM_USER, (const void **)user);
	if (r == PAM_SUCCESS && *user != NULL)
		RETURNC(PAM_SUCCESS);
	/* pam policy overrides the module's choice */
	if ((promptp = openpam_get_option(pamh, "user_prompt")) != NULL)
		prompt = promptp;
	/* no prompt provided, see if there is one tucked away somewhere */
	if (prompt == NULL)
		if (pam_get_item(pamh, PAM_USER_PROMPT, &promptp) &&
		    promptp != NULL)
			prompt = promptp;
	/* fall back to hardcoded default */
	if (prompt == NULL)
		prompt = user_prompt;
	/* expand */
	prompt_size = sizeof prompt_buf;
	r = openpam_subst(pamh, prompt_buf, &prompt_size, prompt);
	if (r == PAM_SUCCESS && prompt_size <= sizeof prompt_buf)
		prompt = prompt_buf;
	r = pam_prompt(pamh, PAM_PROMPT_ECHO_ON, &resp, "%s", prompt);
	if (r != PAM_SUCCESS)
		RETURNC(r);
	r = pam_set_item(pamh, PAM_USER, resp);
	FREE(resp);
	if (r != PAM_SUCCESS)
		RETURNC(r);
	r = pam_get_item(pamh, PAM_USER, (const void **)user);
	RETURNC(r);
}
Пример #3
0
/* Print a verbose error, including the function name and a
 * cleaned up filename.
 */
void
_pam_verbose_error(pam_handle_t *pamh, int flags,
    const char *file, const char *function, const char *format, ...)
{
	va_list ap;
	char *fmtbuf, *modname, *period;

	if (!(flags & PAM_SILENT) && !openpam_get_option(pamh, "no_warn")) {
		modname = basename(file);
		period = strchr(modname, '.');
		if (period == NULL)
			period = strchr(modname, '\0');
		va_start(ap, format);
		asprintf(&fmtbuf, "%.*s: %s: %s\n", (int)(period - modname),
		    modname, function, format);
		pam_verror(pamh, fmtbuf, ap);
		free(fmtbuf);
		va_end(ap);
	}
}
Пример #4
0
int
openpam_dispatch(pam_handle_t *pamh,
	int primitive,
	int flags)
{
	pam_chain_t *chain;
	int err, fail, nsuccess, r;
	int debug;

	ENTER();

	/* prevent recursion */
	if (pamh->current != NULL) {
		openpam_log(PAM_LOG_ERROR,
		    "%s() called while %s::%s() is in progress",
		    pam_func_name[primitive],
		    pamh->current->module->path,
		    pam_sm_func_name[pamh->primitive]);
		RETURNC(PAM_ABORT);
	}

	/* pick a chain */
	switch (primitive) {
	case PAM_SM_AUTHENTICATE:
	case PAM_SM_SETCRED:
		chain = pamh->chains[PAM_AUTH];
		break;
	case PAM_SM_ACCT_MGMT:
		chain = pamh->chains[PAM_ACCOUNT];
		break;
	case PAM_SM_OPEN_SESSION:
	case PAM_SM_CLOSE_SESSION:
		chain = pamh->chains[PAM_SESSION];
		break;
	case PAM_SM_CHAUTHTOK:
		chain = pamh->chains[PAM_PASSWORD];
		break;
	default:
		RETURNC(PAM_SYSTEM_ERR);
	}

	/* execute */
	err = PAM_SUCCESS;
	fail = nsuccess = 0;
	for (; chain != NULL; chain = chain->next) {
		if (chain->module->func[primitive] == NULL) {
			openpam_log(PAM_LOG_ERROR, "%s: no %s()",
			    chain->module->path, pam_sm_func_name[primitive]);
			r = PAM_SYMBOL_ERR;
		} else {
			pamh->primitive = primitive;
			pamh->current = chain;
			debug = (openpam_get_option(pamh, "debug") != NULL);
			if (debug)
				++openpam_debug;
			openpam_log(PAM_LOG_LIBDEBUG, "calling %s() in %s",
			    pam_sm_func_name[primitive], chain->module->path);
			r = (chain->module->func[primitive])(pamh, flags,
			    chain->optc, (const char **)(intptr_t)chain->optv);
			pamh->current = NULL;
			openpam_log(PAM_LOG_LIBDEBUG, "%s: %s(): %s",
			    chain->module->path, pam_sm_func_name[primitive],
			    pam_strerror(pamh, r));
			if (debug)
				--openpam_debug;
		}

		if (r == PAM_IGNORE)
			continue;
		if (r == PAM_SUCCESS) {
			++nsuccess;
			/*
			 * For pam_setcred() and pam_chauthtok() with the
			 * PAM_PRELIM_CHECK flag, treat "sufficient" as
			 * "optional".
			 */
			if ((chain->flag == PAM_SUFFICIENT ||
			    chain->flag == PAM_BINDING) && !fail &&
			    primitive != PAM_SM_SETCRED &&
			    !(primitive == PAM_SM_CHAUTHTOK &&
				(flags & PAM_PRELIM_CHECK)))
				break;
			continue;
		}

		openpam_check_error_code(primitive, r);

		/*
		 * Record the return code from the first module to
		 * fail.  If a required module fails, record the
		 * return code from the first required module to fail.
		 */
		if (err == PAM_SUCCESS)
			err = r;
		if ((chain->flag == PAM_REQUIRED ||
		    chain->flag == PAM_BINDING) && !fail) {
			openpam_log(PAM_LOG_LIBDEBUG, "required module failed");
			fail = 1;
			err = r;
		}

		/*
		 * If a requisite module fails, terminate the chain
		 * immediately.
		 */
		if (chain->flag == PAM_REQUISITE) {
			openpam_log(PAM_LOG_LIBDEBUG, "requisite module failed");
			fail = 1;
			break;
		}
	}

	if (!fail && err != PAM_NEW_AUTHTOK_REQD)
		err = PAM_SUCCESS;

	/*
	 * Require the chain to be non-empty, and at least one module
	 * in the chain to be successful, so that we don't fail open.
	 */
	if (err == PAM_SUCCESS && nsuccess < 1) {
		openpam_log(PAM_LOG_ERROR,
		    "all modules were unsuccessful for %s()",
		    pam_sm_func_name[primitive]);
		err = PAM_SYSTEM_ERR;
	}

	RETURNC(err);
}
Пример #5
0
static int
pam_group(pam_handle_t *pamh)
{
	int local, remote;
	const char *group, *user;
	const void *ruser;
	char *const *list;
	struct passwd *pwd;
	struct group *grp;

	/* get target account */
	if (pam_get_user(pamh, &user, NULL) != PAM_SUCCESS ||
	    user == NULL || (pwd = getpwnam(user)) == NULL)
		return (PAM_AUTH_ERR);
	if (pwd->pw_uid != 0 && openpam_get_option(pamh, "root_only"))
		return (PAM_IGNORE);

	/* check local / remote */
	local = openpam_get_option(pamh, "luser") ? 1 : 0;
	remote = openpam_get_option(pamh, "ruser") ? 1 : 0;
	if (local && remote) {
		openpam_log(PAM_LOG_ERROR, "(pam_group) "
		    "the luser and ruser options are mutually exclusive");
		return (PAM_SERVICE_ERR);
	} else if (local) {
		/* we already have the correct struct passwd */
	} else {
		if (!remote)
			openpam_log(PAM_LOG_NOTICE, "(pam_group) "
			    "neither luser nor ruser specified, assuming ruser");
		/* default / historical behavior */
		if (pam_get_item(pamh, PAM_RUSER, &ruser) != PAM_SUCCESS ||
		    ruser == NULL || (pwd = getpwnam(ruser)) == NULL)
			return (PAM_AUTH_ERR);
	}

	/* get regulating group */
	if ((group = openpam_get_option(pamh, "group")) == NULL)
		group = "wheel";
	if ((grp = getgrnam(group)) == NULL || grp->gr_mem == NULL)
		goto failed;

	/* check if user's own primary group */
	if (pwd->pw_gid == grp->gr_gid)
		goto found;

	/* iterate over members */
	for (list = grp->gr_mem; list != NULL && *list != NULL; ++list)
		if (strcmp(*list, pwd->pw_name) == 0)
			goto found;

 not_found:
	if (openpam_get_option(pamh, "deny"))
		return (PAM_SUCCESS);
	return (PAM_AUTH_ERR);
 found:
	if (openpam_get_option(pamh, "deny"))
		return (PAM_AUTH_ERR);
	return (PAM_SUCCESS);
 failed:
	if (openpam_get_option(pamh, "fail_safe"))
		goto found;
	else
		goto not_found;
}
Пример #6
0
int
pam_get_authtok(pam_handle_t *pamh,
	int item,
	const char **authtok,
	const char *prompt)
{
	char prompt_buf[1024];
	size_t prompt_size;
	const void *oldauthtok, *prevauthtok, *promptp;
	const char *prompt_option, *default_prompt;
	const void *lhost, *rhost;
	char *resp, *resp2;
	int pitem, r, style, twice;

	ENTER();
	if (pamh == NULL || authtok == NULL)
		RETURNC(PAM_SYSTEM_ERR);
	*authtok = NULL;
	twice = 0;
	switch (item) {
	case PAM_AUTHTOK:
		pitem = PAM_AUTHTOK_PROMPT;
		prompt_option = "authtok_prompt";
		default_prompt = authtok_prompt;
		r = pam_get_item(pamh, PAM_RHOST, &rhost);
		if (r == PAM_SUCCESS && rhost != NULL) {
			r = pam_get_item(pamh, PAM_HOST, &lhost);
			if (r == PAM_SUCCESS && lhost != NULL) {
				if (strcmp(rhost, lhost) != 0)
					default_prompt = authtok_prompt_remote;
			}
		}
		r = pam_get_item(pamh, PAM_OLDAUTHTOK, &oldauthtok);
		if (r == PAM_SUCCESS && oldauthtok != NULL) {
			default_prompt = newauthtok_prompt;
			twice = 1;
		}
		break;
	case PAM_OLDAUTHTOK:
		pitem = PAM_OLDAUTHTOK_PROMPT;
		prompt_option = "oldauthtok_prompt";
		default_prompt = oldauthtok_prompt;
		twice = 0;
		break;
	default:
		RETURNC(PAM_SYMBOL_ERR);
	}
	if (openpam_get_option(pamh, "try_first_pass") ||
	    openpam_get_option(pamh, "use_first_pass")) {
		r = pam_get_item(pamh, item, &prevauthtok);
		if (r == PAM_SUCCESS && prevauthtok != NULL) {
			*authtok = prevauthtok;
			RETURNC(PAM_SUCCESS);
		} else if (openpam_get_option(pamh, "use_first_pass")) {
			RETURNC(r == PAM_SUCCESS ? PAM_AUTH_ERR : r);
		}
	}
	/* pam policy overrides the module's choice */
	if ((promptp = openpam_get_option(pamh, prompt_option)) != NULL)
		prompt = promptp;
	/* no prompt provided, see if there is one tucked away somewhere */
	if (prompt == NULL)
		if (pam_get_item(pamh, pitem, &promptp) && promptp != NULL)
			prompt = promptp;
	/* fall back to hardcoded default */
	if (prompt == NULL)
		prompt = default_prompt;
	/* expand */
	prompt_size = sizeof prompt_buf;
	r = openpam_subst(pamh, prompt_buf, &prompt_size, prompt);
	if (r == PAM_SUCCESS && prompt_size <= sizeof prompt_buf)
		prompt = prompt_buf;
	style = openpam_get_option(pamh, "echo_pass") ?
	    PAM_PROMPT_ECHO_ON : PAM_PROMPT_ECHO_OFF;
	r = pam_prompt(pamh, style, &resp, "%s", prompt);
	if (r != PAM_SUCCESS)
		RETURNC(r);
	if (twice) {
		r = pam_prompt(pamh, style, &resp2, "Retype %s", prompt);
		if (r != PAM_SUCCESS) {
			strlset(resp, 0, PAM_MAX_RESP_SIZE);
			FREE(resp);
			RETURNC(r);
		}
		if (strcmp(resp, resp2) != 0) {
			strlset(resp, 0, PAM_MAX_RESP_SIZE);
			FREE(resp);
		}
		strlset(resp2, 0, PAM_MAX_RESP_SIZE);
		FREE(resp2);
	}
	if (resp == NULL)
		RETURNC(PAM_TRY_AGAIN);
	r = pam_set_item(pamh, item, resp);
	strlset(resp, 0, PAM_MAX_RESP_SIZE);
	FREE(resp);
	if (r != PAM_SUCCESS)
		RETURNC(r);
	r = pam_get_item(pamh, item, (const void **)authtok);
	RETURNC(r);
}
Пример #7
0
		syslog(LOG_CRIT, "tac_set_msg: %s", tac_strerror(tach));
		tac_close(tach);
		return -1;
	}
	return 0;
}

PAM_EXTERN int
pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
    int argc __unused, const char *argv[] __unused)
{
	int retval;
	struct tac_handle *tach;
	const char *conf_file, *template_user;

	conf_file = openpam_get_option(pamh, PAM_OPT_CONF);
	template_user = openpam_get_option(pamh, PAM_OPT_TEMPLATE_USER);

	tach = tac_open();
	if (tach == NULL) {
		syslog(LOG_CRIT, "tac_open failed");
		return (PAM_SERVICE_ERR);
	}
	if (tac_config(tach, conf_file) == -1) {
		syslog(LOG_ALERT, "tac_config: %s", tac_strerror(tach));
		tac_close(tach);
		return (PAM_SERVICE_ERR);
	}
	if (tac_create_authen(tach, TAC_AUTHEN_LOGIN, TAC_AUTHEN_TYPE_ASCII,
	    TAC_AUTHEN_SVC_LOGIN) == -1) {
		syslog(LOG_CRIT, "tac_create_authen: %s", tac_strerror(tach));
Пример #8
0
		free(msgs[--num_msgs].msg);
	return (PAM_SUCCESS);
}

PAM_EXTERN int
pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
    int argc __unused, const char *argv[] __unused)
{
	struct rad_handle *radh;
	const char *user, *pass;
	const void *tmpuser;
	const char *conf_file, *template_user, *nas_id, *nas_ipaddr;
	int retval;
	int e;

	conf_file = openpam_get_option(pamh, PAM_OPT_CONF);
	template_user = openpam_get_option(pamh, PAM_OPT_TEMPLATE_USER);
	nas_id = openpam_get_option(pamh, PAM_OPT_NAS_ID);
	nas_ipaddr = openpam_get_option(pamh, PAM_OPT_NAS_IPADDR);

	retval = pam_get_user(pamh, &user, NULL);
	if (retval != PAM_SUCCESS)
		return (retval);

	PAM_LOG("Got user: %s", user);

	retval = pam_get_authtok(pamh, PAM_AUTHTOK, &pass, PASSWORD_PROMPT);
	if (retval != PAM_SUCCESS)
		return (retval);

	PAM_LOG("Got password");
Пример #9
0
PAM_EXTERN int pam_sm_acct_mgmt(pam_handle_t * pamh, int flags,
			int argc, const char ** argv)
{
	const char *	service = NULL;
	const char *	username = NULL;
	const char *	debug = NULL;
	bool		allow_trustacct = false;

	struct passwd *pwd = NULL;
	struct passwd pwdbuf;
	char pwbuffer[2 * PATH_MAX];

	uuid_t	user_uuid;
	int	err;
	int	ismember;

	service = openpam_get_option(pamh, "sacl_service");
	allow_trustacct = openpam_get_option(pamh, "allow_trustacct");
	debug = openpam_get_option(pamh, "debug");

	if (!service) {
		DEBUG_MESSAGE("%s: missing service option", MODULE_NAME);
		return PAM_IGNORE;
	}

	if (pam_get_user(pamh, &username, NULL) != PAM_SUCCESS ||
	    username == NULL || *username == '\0') {
		DEBUG_MESSAGE("%s: missing username", MODULE_NAME);
		return PAM_SYSTEM_ERR;
	}
 
	DEBUG_MESSAGE("%s: checking if account '%s' can access service '%s'",
		    MODULE_NAME, username, service);

	/* Since computer trust accounts in OD are not user accounts, you can't
	 * add them to a SACL, so we always let them through (if the option is
	 * set). A computer trust account has a username ending in '$' and no
	 * corresponding user account (ie. no passwd entry).
	 */
	if (allow_trustacct) {
		const char * c;

		c = strrchr(username, '$');
		if (c && *(c + 1) == '\0' && getpwnam_r(username, &pwdbuf, pwbuffer, sizeof(pwbuffer), &pwd) == 0) {
			DEBUG_MESSAGE("%s: allowing '%s' because it is a "
				"computer trust account",
				MODULE_NAME, username);
			return PAM_SUCCESS;
		}
	}

	/* Get the UUID. This will fail if the user is is logging in over
	 * SMB, is specifed as DOMAIN\user or user@REALM and the directory
	 * does not have the aliases we need.
	 */
	if (mbr_user_name_to_uuid(username, user_uuid)) {
		char * sacl_group;

		/* We couldn't map the user to a UID, but we only care about
		 * this if the relevant SACL groups exist.
		 */

		if (asprintf(&sacl_group, "com.apple.access_%s\n",
							service) == -1) {
			return PAM_SYSTEM_ERR;
		}

		if (getgrnam(sacl_group) == NULL &&
		    getgrnam("com.apple.access_all_services") == NULL) {

			DEBUG_MESSAGE("%s: allowing '%s' "
				    "due to absence of service ACL",
				    MODULE_NAME, username);

			free(sacl_group);
			return PAM_SUCCESS;
		}

		DEBUG_MESSAGE("%s: denying '%s' due to missing UUID",
			MODULE_NAME, username);

		free(sacl_group);
		return PAM_PERM_DENIED;
	}

	err = mbr_check_service_membership(user_uuid, service, &ismember);
	if (err) {
	        if (err == ENOENT) {
	                /* Service ACLs not configured. */
			DEBUG_MESSAGE("%s: allowing '%s' "
				"due to unconfigured service ACLs",
				MODULE_NAME, username);
	                return PAM_SUCCESS;
	        }
	
		DEBUG_MESSAGE("%s: denying '%s' "
			"due to failed service ACL check (errno=%d)",
			MODULE_NAME, username, err);

	        return PAM_PERM_DENIED;
	}
	
        if (ismember) {
		DEBUG_MESSAGE("%s: allowing '%s'", MODULE_NAME, username);
		return PAM_SUCCESS;
	} else {
		DEBUG_MESSAGE("%s: denying '%s' "
			"due to failed service ACL check",
			MODULE_NAME, username);
		return PAM_PERM_DENIED;
	}
}
Пример #10
0
/**
 * Called when someone logs in.
 */
int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv){ 
    int ret;
    int pam_err;
    const char *pam_user = NULL;
    char *pam_service = NULL;
    char *pam_tty = NULL;
    char *pam_rhost = NULL;
    const char *notifo_user = NULL;
    const char *notifo_api_key = NULL;
    char hostname[MAXHOSTNAMELEN];
    char notifoMessage[NOTIFO_MESSAGE_LENGTH];
    
    openlog("pam_notifo", 0, LOG_AUTHPRIV);
    
    // This system
    gethostname(hostname, sizeof(hostname));
    
    // Get username who is logging in
    pam_err = pam_get_user(pamh, &pam_user, NULL);
    if (pam_err != PAM_SUCCESS) {
        pam_user = "******";
        syslog(LOG_WARNING, "Could not determine incoming username", pam_user);
    }
    
    // Get service type
    pam_err = pam_get_item(pamh, PAM_SERVICE, (const void **)&pam_service);
    if (pam_err != PAM_SUCCESS || pam_service == NULL) {
        pam_service = "Unknown Service";
        syslog(LOG_WARNING, "Could not determine incoming service type for user %s", pam_user);
    }
    
    // Get TTY
    // This is an alternative to rhost
    pam_err = pam_get_item(pamh, PAM_TTY, (const void **)&pam_tty);
    if (pam_err != PAM_SUCCESS ){
        pam_tty = "Unknown TTY";
        syslog(LOG_WARNING, "Could not determine incoming TTY for user %s", pam_user);
    }
    
    // Get remote host
    // This is an alternative to tty
    pam_err = pam_get_item(pamh, PAM_RHOST, (const void **)&pam_rhost);
    if (pam_err != PAM_SUCCESS ){
        pam_rhost = "Unknown RHOST";
        syslog(LOG_WARNING, "Could not determine incoming remote host for user %s", pam_user);
    }
    
    
    // Get Notifo user info
    notifo_user = openpam_get_option(pamh, PAM_NOTIFO_USER_KEY);
    if( notifo_user == NULL ) {
        syslog(LOG_WARNING, "Notifo username not provided in '%s' pam config file.", pam_service);
        return PAM_SESSION_ERR;
    }
    
    // Get Notifo API key
    notifo_api_key = openpam_get_option(pamh, PAM_NOTIFO_API_KEY);
    if( notifo_api_key == NULL ) {
        syslog(LOG_WARNING, "Notifo API key not provided in '%s' pam config file.", pam_service);
        return PAM_SESSION_ERR;
    }
    
        
    // Build message
    ret = snprintf( notifoMessage, NOTIFO_MESSAGE_LENGTH, "User: %s, Source: %s, Service: %s", 
                   pam_user, 
                   (pam_tty != NULL ? pam_tty : (pam_rhost != NULL ? pam_rhost : "unknown") ),
                   pam_service );
    
    // Send Notifo notification
    curl_notifo(notifo_user, notifo_api_key, hostname, "User Logged In", notifoMessage, NULL);
    
    // Log
    syslog(LOG_NOTICE, "User Logged In: %s\n", notifoMessage);
    
    return PAM_SUCCESS; 

}
Пример #11
0
PAM_EXTERN int
pam_sm_authenticate(pam_handle_t * pamh, int flags,
		int argc, const char * argv[]) 
{
	struct passwd *opwd,*tpwd;
	struct group *group;
	const char *orig_user, *target_user;
	char **user_list;
	int pam_err, member;

	/* Get info for target user. Who do you want to su to ? */

	if ( ( (pam_err = pam_get_user(pamh, &target_user, NULL)) != PAM_SUCCESS )
			|| ( orig_user == NULL ) )  {
		PAM_ERROR("Error recovering username.");	
		return (pam_err);
	}

	if ( (tpwd = getpwnam(target_user)) == NULL ) {
		PAM_ERROR("Could not get passwd entry for user [%s]",target_user);
		return (PAM_SERVICE_ERR);
	}
	
	if ( openpam_get_option(pamh, PAM_OPT_ROOT_ONLY) ) {
		/* if su to non-root -> ignore */
		if (tpwd->pw_uid != 0) 
			return (PAM_AUTH_ERR);
	}
	
	/* Get info for originating user. Who called su? */

	if ( ( (pam_err = pam_get_user(pamh, &orig_user, NULL)) != PAM_SUCCESS )
                        || ( orig_user == NULL ) )  {                                        
	        PAM_ERROR("Error recovering username.");
		return (pam_err);
	}

	if ( (opwd = getpwnam(orig_user)) == NULL ) {
		PAM_ERROR("Could not get passwd entry for user [%s]",orig_user);
		return (PAM_SERVICE_ERR);
	}
	
	/* We now have all user info we need */

	if ( (group = getgrnam("wheel")) == NULL ) { 
		group = getgrgid(0); 
	}
	
	/* Check wheel or group with GID 0 have any members */

	if (!group || (!group->gr_mem && (opwd->pw_gid != group->gr_gid))) {
		PAM_LOG("Group wheel or with GID 0 has no members");
		return (PAM_AUTH_ERR);
	}
	/* Check user's membership to the interested groups */
	member=0;
	user_list = group->gr_mem; 
	while ( !member && user_list && *(user_list) ) {
		if (strncmp(*user_list, orig_user, strlen(orig_user)-1 ) == 0) 
		            member=1;
		
		user_list++;
	}
	
	if ( member || ( opwd->pw_gid == group->gr_gid ) ) { 
		PAM_LOG("Access granted for user '%s' to user '%s'", orig_user, target_user);
		return (PAM_SUCCESS);
	} else { 
		PAM_ERROR("Access denied for user '%s' to user '%s'", orig_user, target_user);
		return (PAM_PERM_DENIED);
	}
}