예제 #1
2
파일: pam.c 프로젝트: 2014-class/freerouter
static void
set_tkt_string(uid_t uid)
{
  char buf[128];

  snprintf(buf, sizeof(buf), "%s%u", TKT_ROOT, (unsigned)uid);
  krb_set_tkt_string(buf);

#if 0
  /* pam_set_data+pam_get_data are not guaranteed to work, grr. */
  pam_set_data(pamh, "KRBTKFILE", strdup(t), cleanup);
  if (pam_get_data(pamh, "KRBTKFILE", (const void**)&tkt) == PAM_SUCCESS)
    {
      pam_putenv(pamh, var);
    }
#endif

  /* We don't want to inherit this variable.
   * If we still do, it must have a sane value. */
  if (getenv("KRBTKFILE") != 0)
    {
      char *var = malloc(sizeof(buf));
      snprintf(var, sizeof(buf), "KRBTKFILE=%s", tkt_string());
      putenv(var);
      /* free(var); XXX */
    }
}
예제 #2
0
static void test_pam_env_functions(void **state)
{
	int rv;
	const char *v;
	char **vlist;
	struct pwrap_test_ctx *test_ctx;

	test_ctx = (struct pwrap_test_ctx *) *state;

	rv = pam_putenv(test_ctx->ph, "KEY=value");
	assert_int_equal(rv, PAM_SUCCESS);
	rv = pam_putenv(test_ctx->ph, "KEY2=value2");
	assert_int_equal(rv, PAM_SUCCESS);

	v = pam_getenv(test_ctx->ph, "KEY");
	assert_non_null(v);
	assert_string_equal(v, "value");

	v = pam_getenv(test_ctx->ph, "KEY2");
	assert_non_null(v);
	assert_string_equal(v, "value2");

	vlist = pam_getenvlist(test_ctx->ph);
	assert_non_null(vlist);
	assert_non_null(vlist[0]);
	assert_string_equal(vlist[0], "KEY=value");
	assert_non_null(vlist[1]);
	assert_string_equal(vlist[1], "KEY2=value2");
	assert_null(vlist[2]);
	free_vlist(vlist);

	rv = pam_putenv(test_ctx->ph, "KEY2=");
	assert_int_equal(rv, PAM_SUCCESS);

	vlist = pam_getenvlist(test_ctx->ph);
	assert_non_null(vlist);
	assert_non_null(vlist[0]);
	assert_string_equal(vlist[0], "KEY=value");
	assert_non_null(vlist[1]);
	assert_string_equal(vlist[1], "KEY2=");
	assert_null(vlist[2]);
	free_vlist(vlist);

#ifndef HAVE_OPENPAM
	/* OpenPAM does not support this feature */
	rv = pam_putenv(test_ctx->ph, "KEY2");
	assert_int_equal(rv, PAM_SUCCESS);

	vlist = pam_getenvlist(test_ctx->ph);
	assert_non_null(vlist);
	assert_non_null(vlist[0]);
	assert_string_equal(vlist[0], "KEY=value");
	assert_null(vlist[1]);
	free_vlist(vlist);
#endif
}
예제 #3
0
// This method is the method that execute the authentication procedure
int authenticate() {
	pam_handle_t *pamh = NULL;
	int retval = 0;
	int ritorno = 1;
	char path_script[1024];

	// The service to be authenticated against is defined by *service
	retval = pam_start(service, username, &conv, &pamh);
	if (retval != PAM_SUCCESS) {
		return 1;
	}

	// Call the addmessage.pl script that adds a message to the spool of the sms daemon
	sprintf(path_script, "PATH_ADD_MSG=%s/addmessage.pl", PATH_SCRIPT);
	retval = pam_putenv(pamh, path_script);
	if (retval != PAM_SUCCESS) {
		return 1;
	}

	// Execute the real authentication
	retval = pam_authenticate(pamh, 0);
	if (retval == PAM_SUCCESS) {
		ritorno = 0;
	}

	if (pam_end(pamh, retval) != PAM_SUCCESS)
		pamh = NULL;

	return ritorno;
}
예제 #4
0
int
pam_setenv(pam_handle_t *pamh,
           const char *name,
           const char *value,
           int overwrite)
{
    char *env;
    int r;

    ENTER();
    if (pamh == NULL)
        RETURNC(PAM_SYSTEM_ERR);

    /* sanity checks */
    if (name == NULL || value == NULL || strchr(name, '=') != NULL)
        RETURNC(PAM_SYSTEM_ERR);

    /* is it already there? */
    if (!overwrite && openpam_findenv(pamh, name, strlen(name)) >= 0)
        RETURNC(PAM_SUCCESS);

    /* set it... */
    if (asprintf(&env, "%s=%s", name, value) < 0)
        RETURNC(PAM_BUF_ERR);
    r = pam_putenv(pamh, env);
    FREE(env);
    RETURNC(r);
}
예제 #5
0
static void
transfer_pam_env (pam_handle_t *pamh,
                  ...)
{
  const char *name;
  const char *value;
  char *nameval;
  va_list va;

  va_start (va, pamh);
  for (;;)
    {
      name = va_arg (va, const char *);
      if (!name)
        break;
      value = getenv (name);
      if (value)
        {
          if (asprintf (&nameval, "%s=%s", name, value) < 0)
            errx (42, "couldn't allocate environment");
          pam_putenv (pamh, nameval);
        }
    }
  va_end (va);
}
예제 #6
0
static void
modify_environment_putenv (pam_handle_t *pam_handle, poldi_ctx_t ctx,
			   const char *name, const char *value)
{
  char *str;
  int ret;

  str = NULL;
  ret = asprintf (&str, "%s=%s", name, value);
  if (ret < 0)
    {
      log_msg_error (ctx->loghandle,
		     _("asprintf() failed in modify_environment_putenv(): %s"),
		     errno);
      return;
    }

  ret = pam_putenv (pam_handle, str);
  if (ret != PAM_SUCCESS)
    {
      log_msg_error (ctx->loghandle,
		     _("pam_putenv() failed in modify_environment_putenv(): %s"),
		     pam_strerror (pam_handle, ret));
    }
  free (str);
}
예제 #7
0
static int
setup_environment (char *line, void *arg)
{
	pam_handle_t *ph = (pam_handle_t*)arg;
	char *x;
	int ret;
	
	/* 
	 * Called for each stdout output line from the daemon
	 * presumably environment variables.
	 */
	
	assert (line);
	assert (arg);
	
	/* Make sure it is in fact an environment variable */
	if (!strchr (line, '='))
		return PAM_SUCCESS;
			
	line = strbtrim (line);
	ret = pam_putenv (ph, line);
	
	/* If it's the PID line then we're interested in it */
	if (strncmp (line, ENV_PID, strlen (ENV_PID)) == 0) { 
		x = line + strlen (ENV_PID);
		if (x[0] == '=')
			pam_set_data (ph, "gkr-pam-pid", strdup (x + 1), cleanup_free);
	}
	
	return ret;
}
예제 #8
0
/**
 * create a key value pair from the given key and value string
 */
static void set_to_pam_env(pam_handle_t *pamh, ngx_http_request_t *r,
                           char *key, char *value)
{
        if (key != NULL && value != NULL) {
                size_t size = strlen(key) + strlen(value) + 1 * sizeof(char);
                char *key_value_pair = ngx_palloc(r->pool, size);
                sprintf(key_value_pair, "%s=%s", key, value);

                pam_putenv(pamh, key_value_pair);
        }
}
예제 #9
0
/* Import regular and PAM environment from subprocess */
static void
import_environments(struct sshbuf *b)
{
	char *env;
	u_int n, i, num_env;
	int r;

	debug3("PAM: %s entering", __func__);

#ifndef UNSUPPORTED_POSIX_THREADS_HACK
	/* Import variables set by do_pam_account */
	if ((r = sshbuf_get_u32(b, &n)) != 0)
		fatal("%s: buffer error: %s", __func__, ssh_err(r));
	if (n > INT_MAX)
		fatal("%s: invalid PAM account status %u", __func__, n);
	sshpam_account_status = (int)n;
	if ((r = sshbuf_get_u32(b, &n)) != 0)
		fatal("%s: buffer error: %s", __func__, ssh_err(r));
	sshpam_password_change_required(n != 0);

	/* Import environment from subprocess */
	if ((r = sshbuf_get_u32(b, &num_env)) != 0)
		fatal("%s: buffer error: %s", __func__, ssh_err(r));
	if (num_env > 1024)
		fatal("%s: received %u environment variables, expected <= 1024",
		    __func__, num_env);
	sshpam_env = xcalloc(num_env + 1, sizeof(*sshpam_env));
	debug3("PAM: num env strings %d", num_env);
	for(i = 0; i < num_env; i++) {
		if ((r = sshbuf_get_cstring(b, &(sshpam_env[i]), NULL)) != 0)
			fatal("%s: buffer error: %s", __func__, ssh_err(r));
	}
	sshpam_env[num_env] = NULL;

	/* Import PAM environment from subprocess */
	if ((r = sshbuf_get_u32(b, &num_env)) != 0)
		fatal("%s: buffer error: %s", __func__, ssh_err(r));
	debug("PAM: num PAM env strings %d", num_env);
	for (i = 0; i < num_env; i++) {
		if ((r = sshbuf_get_cstring(b, &env, NULL)) != 0)
			fatal("%s: buffer error: %s", __func__, ssh_err(r));
#ifdef HAVE_PAM_PUTENV
		/* Errors are not fatal here */
		if ((r = pam_putenv(sshpam_handle, env)) != PAM_SUCCESS) {
			error("PAM: pam_putenv: %s",
			    pam_strerror(sshpam_handle, r));
		}
#endif
		/* XXX leak env? */
	}
#endif
}
예제 #10
0
static _printf_(2, 3) int pam_setenv(pam_handle_t *ph, const char *fmt, ...)
{
    va_list ap;
    int nbytes;
    _cleanup_free_ char *line = NULL;

    va_start(ap, fmt);
    nbytes = vasprintf(&line, fmt, ap);
    va_end(ap);

    if (nbytes < 0)
        return -1;

    pam_putenv(ph, line);
    return 0;
}
예제 #11
0
파일: pam_envoy.c 프로젝트: Apsu/envoy
static int __attribute__((format (printf, 2, 3))) pam_setenv(pam_handle_t *ph, const char *fmt, ...)
{
    va_list ap;
    int nbytes;
    char *line = NULL;

    va_start(ap, fmt);
    nbytes = vasprintf(&line, fmt, ap);
    va_end(ap);

    if (nbytes < 0)
        return -1;

    pam_putenv(ph, line);
    free(line);
    return 0;
}
예제 #12
0
void Authenticator::delenv(const std::string& key) {
    switch((last_result=pam_putenv(pam_handle, key.c_str()))) {
    default:
    case PAM_PERM_DENIED:
    case PAM_ABORT:
    case PAM_BUF_ERR:
#ifdef __LIBPAM_VERSION
    case PAM_BAD_ITEM:
#endif
        _end();
        throw Exception(pam_handle, "pam_putenv()", last_result);

    case PAM_SUCCESS:
        break;
    };
    return;
}
예제 #13
0
void
ssh_gssapi_rekey_creds() {
	int ok;
	int ret;
#ifdef USE_PAM
	pam_handle_t *pamh = NULL;
	struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL};
	char *envstr;
#endif

	if (gssapi_client.store.filename == NULL && 
	    gssapi_client.store.envval == NULL &&
	    gssapi_client.store.envvar == NULL)
		return;
 
	ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store));

	if (!ok)
		return;

	debug("Rekeyed credentials stored successfully");

	/* Actually managing to play with the ssh pam stack from here will
	 * be next to impossible. In any case, we may want different options
	 * for rekeying. So, use our own :)
	 */
#ifdef USE_PAM	
	if (!use_privsep) {
		debug("Not even going to try and do PAM with privsep disabled");
		return;
	}

	ret = pam_start("sshd-rekey", gssapi_client.store.owner->pw_name,
 	    &pamconv, &pamh);
	if (ret)
		return;

	xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar, 
	    gssapi_client.store.envval);

	ret = pam_putenv(pamh, envstr);
	if (!ret)
		pam_setcred(pamh, PAM_REINITIALIZE_CRED);
	pam_end(pamh, PAM_SUCCESS);
#endif
}
예제 #14
0
파일: auth-pam.c 프로젝트: Alkzndr/freebsd
/*
 * Set a PAM environment string. We need to do this so that the session
 * modules can handle things like Kerberos/GSI credentials that appear
 * during the ssh authentication process.
 */
int
do_pam_putenv(char *name, char *value)
{
	int ret = 1;
#ifdef HAVE_PAM_PUTENV
	char *compound;
	size_t len;

	len = strlen(name) + strlen(value) + 2;
	compound = xmalloc(len);

	snprintf(compound, len, "%s=%s", name, value);
	ret = pam_putenv(sshpam_handle, compound);
	free(compound);
#endif

	return (ret);
}
예제 #15
0
static int set_env(pam_handle_t *pamh, const char *name, const char *value)
{
    if (setenv(name, value, 1) < 0) {
        pam_syslog(pamh, LOG_WARNING, "pam_kwallet: Couldn't setenv %s = %s", name, value);
        //We do not return because pam_putenv might work
    }

    char *pamEnv = malloc(strlen(name) + strlen(value) + 2); //2 is for = and \0
    if (!pamEnv) {
        pam_syslog(pamh, LOG_WARNING, "pam_kwallet: Impossible to allocate memory for pamEnv");
        return -1;
    }

    sprintf (pamEnv, "%s=%s", name, value);
    int ret = pam_putenv(pamh, pamEnv);
    free(pamEnv);

    return ret;
}
예제 #16
0
/**
 * EscalateUtilPamEnvFromVariant:
 * @pamh: PAM handle where environment variables should be written.
 * @iter: Iterator over environment key/value pairs to write.
 * @error: (out)(allow-none): Error return location or #NULL.
 *
 * Returns: #TRUE if all variables from @iter were written to @pamh.
 */
gboolean EscalateUtilPamEnvFromVariant(pam_handle_t *pamh, GVariantIter *iter,
                                       GError **error) {
  const gchar *key = NULL;
  const gchar *value = NULL;
  gboolean result = TRUE;

  while (result && g_variant_iter_next(iter, "{&s&s}", &key, &value)) {
    gchar *key_and_value = g_strjoin("=", key, value, NULL);
    int pam_result = pam_putenv(pamh, key_and_value);
    if (pam_result != PAM_SUCCESS) {
      g_set_error(error, ESCALATE_UTIL_ERROR, ESCALATE_UTIL_ERROR_ENVIRONMENT,
                  "Failed to set environment variable '%s'", key_and_value);
      result = FALSE;
    }
    g_free(key_and_value);
  }

  return result;
}
예제 #17
0
/*
 * set_ccname()
 *
 * set KRB5CCNAME shell var
 */
static void
set_ccname(
	pam_handle_t *pamh,
	krb5_module_data_t *kmd,
	int login_result,
	int debug)
{
	int result;

	if (debug)
		syslog(LOG_DEBUG,
		    "PAM-KRB5 (password): password: finalize"
		    " ccname env, login_result =%d, env ='%s'",
		    login_result, kmd->env ? kmd->env : "<null>");

	if (kmd->env) {

		if (login_result == PAM_SUCCESS) {
				/*
				 * Put ccname into the pamh so that login
				 * apps can pick this up when they run
				 * pam_getenvlist().
				 */
			if ((result = pam_putenv(pamh, kmd->env))
			    != PAM_SUCCESS) {
				/* should not happen but... */
				syslog(LOG_ERR,
				    dgettext(TEXT_DOMAIN,
					    "PAM-KRB5 (password):"
					    " pam_putenv failed: result: %d"),
				    result);
				goto cleanupccname;
			}
		} else {
		cleanupccname:
				/* for lack of a Solaris unputenv() */
			krb5_unsetenv(KRB5_ENV_CCNAME);
			free(kmd->env);
			kmd->env = NULL;
		}
	}
}
예제 #18
0
파일: auth-pam.c 프로젝트: Alkzndr/freebsd
/* Import regular and PAM environment from subprocess */
static void
import_environments(Buffer *b)
{
	char *env;
	u_int i, num_env;
	int err;

	debug3("PAM: %s entering", __func__);

#ifndef UNSUPPORTED_POSIX_THREADS_HACK
	/* Import variables set by do_pam_account */
	sshpam_account_status = buffer_get_int(b);
	sshpam_password_change_required(buffer_get_int(b));

	/* Import environment from subprocess */
	num_env = buffer_get_int(b);
	if (num_env > 1024)
		fatal("%s: received %u environment variables, expected <= 1024",
		    __func__, num_env);
	sshpam_env = xcalloc(num_env + 1, sizeof(*sshpam_env));
	debug3("PAM: num env strings %d", num_env);
	for(i = 0; i < num_env; i++)
		sshpam_env[i] = buffer_get_string(b, NULL);

	sshpam_env[num_env] = NULL;

	/* Import PAM environment from subprocess */
	num_env = buffer_get_int(b);
	debug("PAM: num PAM env strings %d", num_env);
	for(i = 0; i < num_env; i++) {
		env = buffer_get_string(b, NULL);

#ifdef HAVE_PAM_PUTENV
		/* Errors are not fatal here */
		if ((err = pam_putenv(sshpam_handle, env)) != PAM_SUCCESS) {
			error("PAM: pam_putenv: %s",
			    pam_strerror(sshpam_handle, sshpam_err));
		}
#endif
	}
#endif
}
예제 #19
0
static int
setup_pam_env (pam_handle_t *ph, const char *name, const char *val)
{
	int ret;
	char *var;
	
	assert (name);
	assert (val);
	
	var = malloc (strlen (name) + strlen (val) + 2);
	if (!var) {
		syslog (GKR_LOG_ERR, "gkr-pam: out of memory");
		return PAM_SYSTEM_ERR;
	} 
	
	sprintf (var, "%s=%s", name, val);
	ret = pam_putenv (ph, var);
	free (var);
	
	return ret;
}
예제 #20
0
파일: pam.c 프로젝트: carlodoro88/lxdm
int lxdm_auth_session_begin(LXDM_AUTH *a,const char *name,int tty,int display,char mcookie[16])
{
	int err;
	char x[256];
	
	if(!a->handle)
	{
		return -1;
	}
	sprintf(x, "tty%d", tty);
	pam_set_item(a->handle, PAM_TTY, x);
#ifdef PAM_XDISPLAY
	sprintf(x,":%d",display);
	pam_set_item(a->handle, PAM_XDISPLAY, x);
#endif
#if !defined(DISABLE_XAUTH) && defined(PAM_XAUTHDATA)
	struct pam_xauth_data value;
	value.name="MIT-MAGIC-COOKIE-1";
	value.namelen=18;
	value.data=mcookie;
	value.datalen=16;
	pam_set_item (a->handle, PAM_XAUTHDATA, &value);
#endif
	if(name && name[0])
	{
		char *env;
		env = g_strdup_printf ("DESKTOP_SESSION=%s", name);
		pam_putenv (a->handle, env);
		g_free (env);
	}
	err = pam_open_session(a->handle, 0); /* FIXME pam session failed */
	if( err != PAM_SUCCESS )
		g_warning( "pam open session error \"%s\"\n", pam_strerror(a->handle, err));
	else
		a->in_session=1;
	return 0;
}
예제 #21
0
파일: cache.c 프로젝트: irush-cs/pam-krb5
/*
 * Put the ticket cache information into the environment.  Takes the path and
 * the environment variable to set, since this is used both for the permanent
 * cache (KRB5CCNAME) and the temporary cache (PAM_KRB5CCNAME).  Returns a PAM
 * status code.
 */
int
pamk5_set_krb5ccname(struct pam_args *args, const char *name, const char *key)
{
    char *env_name = NULL;
    int pamret;

    if (asprintf(&env_name, "%s=%s", key, name) < 0) {
        putil_crit(args, "asprintf failed: %s", strerror(errno));
        pamret = PAM_BUF_ERR;
        goto done;
    }
    pamret = pam_putenv(args->pamh, env_name);
    if (pamret != PAM_SUCCESS) {
        putil_err_pam(args, pamret, "pam_putenv failed");
        pamret = PAM_SERVICE_ERR;
        goto done;
    }
    pamret = PAM_SUCCESS;

done:
    if (env_name != NULL)
        free(env_name);
    return pamret;
}
예제 #22
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);

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

    retval = pam_set_item (pamh, PAM_AUTHTOK, pass);
    if (retval != PAM_SUCCESS) {
        _pam_log(LOG_ERR, "unable to set password");
        xfree(pass);
        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;
                    if (active_server.addr != NULL)
                    {
                        xfree(active_server.addr);
                    }
                    active_server.addr = (struct addrinfo*)xcalloc(1, sizeof(struct addrinfo));
                    bcopy(tac_srv[srv_i].addr, active_server.addr, sizeof(struct addrinfo));
                    if (active_server.key != NULL)
                    {
                        xfree(active_server.key);
                    }
                    active_server.key = xstrdup(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)
            {
                if (resp->resp != NULL)
                {
                    xfree(resp->resp);
                }
                xfree(resp);
            }
                
            if (re.msg != NULL)
            {
                xfree(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));
        xfree(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;
    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)"
            , __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);

    // read config file
    _read_config(ctrl);

    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) {
        _pam_log (LOG_ERR, "SM: TACACS+ protocol type not configured (IGNORED)");
    }

    tac_add_attrib(&attr, "service", tac_service);
    if(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)
            xfree (arep.msg);
        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)
            xfree (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)
            xfree (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)
        xfree (arep.msg);

    close(tac_fd);

    return status;
}    /* pam_sm_acct_mgmt */
예제 #23
0
파일: blank.c 프로젝트: aosm/pam
int main(int argc, char **argv)
{
     pam_handle_t *pamh=NULL;
     char *username=NULL;
     int retcode;

     /* did the user call with a username as an argument ? */

     if (argc > 2) {
	  fprintf(stderr,"usage: %s [username]\n",argv[0]);
     } else if (argc == 2) {
	  username = argv[1];
     } 

     /* initialize the Linux-PAM library */
     retcode = pam_start("blank", username, &conv, &pamh);
     bail_out(pamh,1,retcode,"pam_start");

     /* test the environment stuff */
     {
#define MAXENV 15
	 const char *greek[MAXENV] = {
	     "a=alpha", "b=beta", "c=gamma", "d=delta", "e=epsilon",
	     "f=phi", "g=psi", "h=eta", "i=iota", "j=mu", "k=nu",
	     "l=zeta", "h=", "d", "k=xi"
	 };
	 char **env;
	 int i;

	 for (i=0; i<MAXENV; ++i) {
	     retcode = pam_putenv(pamh,greek[i]);
	     bail_out(pamh,0,retcode,"pam_putenv");
	 }
	 env = pam_getenvlist(pamh);
	 if (env)
	     env = pam_misc_drop_env(env);
	 else
	     fprintf(stderr,"???\n");
	 fprintf(stderr,"a test: c=[%s], j=[%s]\n"
		 , pam_getenv(pamh, "c"), pam_getenv(pamh, "j"));
     }

     /* to avoid using goto we abuse a loop here */
     for (;;) {
	  /* authenticate the user --- `0' here, could have been PAM_SILENT
	   *	| PAM_DISALLOW_NULL_AUTHTOK */

	  retcode = pam_authenticate(pamh, 0);
	  bail_out(pamh,0,retcode,"pam_authenticate");

	  /* has the user proved themself valid? */
	  if (retcode != PAM_SUCCESS) {
	       fprintf(stderr,"%s: invalid request\n",argv[0]);
	       break;
	  }

	  /* the user is valid, but should they have access at this
	     time? */

	  retcode = pam_acct_mgmt(pamh, 0); /* `0' could be as above */
	  bail_out(pamh,0,retcode,"pam_acct_mgmt");

	  if (retcode == PAM_NEW_AUTHTOK_REQD) {
	       fprintf(stderr,"Application must request new password...\n");
	       retcode = pam_chauthtok(pamh,PAM_CHANGE_EXPIRED_AUTHTOK);
	       bail_out(pamh,0,retcode,"pam_chauthtok");
	  }

	  if (retcode != PAM_SUCCESS) {
	       fprintf(stderr,"%s: invalid request\n",argv[0]);
	       break;
	  }

	  /* `0' could be as above */
	  retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED);
	  bail_out(pamh,0,retcode,"pam_setcred1");

	  if (retcode != PAM_SUCCESS) {
	       fprintf(stderr,"%s: problem setting user credentials\n"
		       ,argv[0]);
	       break;
	  }

	  /* open a session for the user --- `0' could be PAM_SILENT */
	  retcode = pam_open_session(pamh,0);
	  bail_out(pamh,0,retcode,"pam_open_session");
	  if (retcode != PAM_SUCCESS) {
	       fprintf(stderr,"%s: problem opening a session\n",argv[0]);
	       break;
	  }

	  fprintf(stderr,"The user has been authenticated and `logged in'\n");

	  /* close a session for the user --- `0' could be PAM_SILENT
	   * it is possible that this pam_close_call is in another program..
	   */

	  retcode = pam_close_session(pamh,0);
	  bail_out(pamh,0,retcode,"pam_close_session");
	  if (retcode != PAM_SUCCESS) {
	       fprintf(stderr,"%s: problem closing a session\n",argv[0]);
	       break;
	  }
	  
	  retcode = pam_setcred(pamh, PAM_DELETE_CRED);
	  bail_out(pamh,0,retcode,"pam_setcred2");

	  break;                      /* don't go on for ever! */
     }

     /* close the Linux-PAM library */
     retcode = pam_end(pamh, PAM_SUCCESS);
     pamh = NULL;

     bail_out(pamh,1,retcode,"pam_end");

     exit(0);
}
예제 #24
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;
}
예제 #25
0
/* Initiate session management by creating temporary file. */
int
pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
{
    int i;
    int debug = 0;
    int pamret;
    int n;
    const char *user;
    struct passwd *pw;
    char mktemp_buf[MAXBUF];
    char envput[MAXBUF];
    const char *prefix = "/tmp/tempfile";
    const char *var = NULL;
    int fd;
    int dir = 0;

    for (i = 0; i < argc; i++) {
	if (strcmp(argv[i], "debug") == 0)
	    debug = 1;
	else if (strncmp(argv[i], "prefix=", 7) == 0)
	    prefix = argv[i] + 7;
	else if (strncmp(argv[i], "var=", 4) == 0)
	    var = argv[i] + 4;
	else if (strcmp(argv[i], "dir") == 0)
	    dir = 1;
    }

    if (var == NULL) {
	syslog(LOG_ERR, "pam_mktemp: No variable to set");
	return PAM_SESSION_ERR;
    }
    if ((pamret = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS) {
	syslog(LOG_ERR, "pam_mktemp: pam_get_user: %s", pam_strerror(pamh, pamret));
	return PAM_SESSION_ERR;
    }
    errno = 0;
    pw = getpwnam(user);
    if (pw == NULL) {
	if (errno != 0)
	    syslog(LOG_ERR, "pam_mktemp: getpwnam: %m");
	else
	    syslog(LOG_ERR, "pam_mktemp: no such user: %s", user);
	return PAM_SESSION_ERR;
    }

    n = snprintf(mktemp_buf, MAXBUF, "%s-%d-XXXXXX", prefix, pw->pw_uid);
    if (n < 0 || n >= MAXBUF) {
	syslog(LOG_ERR, "pam_mktemp: snprintf failed");
	return PAM_SESSION_ERR;
    }
    if (dir) {
	if (mkdtemp(mktemp_buf) == NULL) {
	    syslog(LOG_ERR, "pam_mktemp: mkdtemp: %m");
	    return PAM_SESSION_ERR;
	}
    }
    else {
	fd = mkstemp(mktemp_buf);
	if (fd == -1) {
	    syslog(LOG_ERR, "pam_mktemp: mkstemp: %m");
	    return PAM_SESSION_ERR;
	}
	if (close(fd) != 0) {
	    syslog(LOG_ERR, "pam_mktemp: close: %m");
	    return PAM_SESSION_ERR;
	}
    }
    if (chown(mktemp_buf, pw->pw_uid, -1) != 0) {
	syslog(LOG_ERR, "pam_mktemp: chown: %m");
	return PAM_SESSION_ERR;
    }
    if (debug)
	syslog(LOG_DEBUG, "pam_mktemp: using temporary file %s", mktemp_buf);

    n = snprintf(envput, MAXBUF, "%s=%s", var, mktemp_buf);
    if (n < 0 || n >= MAXBUF) {
	syslog(LOG_ERR, "pam_mktemp: snprintf failed");
	return PAM_SESSION_ERR;
    }
    pamret = pam_putenv(pamh, envput);
    if (pamret != PAM_SUCCESS) {
	syslog(LOG_ERR, "pam_mktemp: pam_putenv: %s",
	       pam_strerror(pamh, pamret));
	return PAM_SESSION_ERR;
    }
    pamret = pam_set_data(pamh, var, mktemp_buf, mktemp_cleanup);
    if (pamret != PAM_SUCCESS) {
	syslog(LOG_ERR, "pam_mktemp: pam_set_data: %s",
	       pam_strerror(pamh, pamret));
	return PAM_SESSION_ERR;
    }
    return PAM_SUCCESS;
}
예제 #26
0
/* Initiate session management by creating Xauthority file. */
int
pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
{
    int i;
    int debug = 0;
    int pamret;
    int n;
    const char *user;
    struct passwd *pw;
    char xauth[MAXBUF];
    char envput[MAXBUF];
    const char *dir = "/tmp";
    int xauth_fd;

    for (i = 0; i < argc; i++) {
	if (strcmp(argv[i], "debug") == 0)
	    debug = 1;
	else if (strncmp(argv[i], "dir=", 4) == 0)
	    dir = argv[i] + 4;
    }

    if ((pamret = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS) {
	syslog(LOG_ERR, "pam_athena-locker: pam_get_user: %s", pam_strerror(pamh, pamret));
	return PAM_SESSION_ERR;
    }
    errno = 0;
    pw = getpwnam(user);
    if (pw == NULL) {
	if (errno != 0)
	    syslog(LOG_ERR, "pam_xauthority: getpwnam: %s", strerror(errno));
	else
	    syslog(LOG_ERR, "pam_xauthority: no such user: %s", user);
	return PAM_SESSION_ERR;
    }

    n = snprintf(xauth, MAXBUF, "%s/xauth-%d-XXXXXX", dir, pw->pw_uid);
    if (n < 0 || n >= MAXBUF) {
	syslog(LOG_ERR, "pam_xauthority: snprintf failed");
	return PAM_SESSION_ERR;
    }
    xauth_fd = mkstemp(xauth);
    if (xauth_fd == -1) {
	syslog(LOG_ERR, "pam_xauthority: mkstemp: %s", strerror(errno));
	return PAM_SESSION_ERR;
    }
    if (fchown(xauth_fd, pw->pw_uid, -1) != 0) {
	syslog(LOG_ERR, "pam_xauthority: fchown: %s", strerror(errno));
	return PAM_SESSION_ERR;
    }
    if (close(xauth_fd) != 0) {
	syslog(LOG_ERR, "pam_xauthority: close: %s", strerror(errno));
	return PAM_SESSION_ERR;
    }
    if (debug)
	syslog(LOG_DEBUG, "pam_xauthority: using Xauthority file %s", xauth);

    n = snprintf(envput, MAXBUF, "%s=%s", XAUTH, xauth);
    if (n < 0 || n >= MAXBUF) {
	syslog(LOG_ERR, "pam_xauthority: snprintf failed");
	return PAM_SESSION_ERR;
    }
    pamret = pam_putenv(pamh, envput);
    if (pamret != PAM_SUCCESS) {
	syslog(LOG_ERR, "pam_xauthority: pam_putenv: %s",
	       pam_strerror(pamh, pamret));
	return PAM_SESSION_ERR;
    }
    pamret = pam_set_data(pamh, XAUTH, xauth, xauth_cleanup);
    if (pamret != PAM_SUCCESS) {
	syslog(LOG_ERR, "pam_xauthority: pam_set_data: %s",
	       pam_strerror(pamh, pamret));
	return PAM_SESSION_ERR;
    }
    return PAM_SUCCESS;
}
예제 #27
0
int
main (int argc, char *argv[])
{
        int             retcode;
        int             ret;
        pam_handle_t   *pamh;
        char           *username;
        char           *hostname;
        char           *tty_name;
        char           *ttyn;
        struct pam_conv conv = { misc_conv, NULL };
        int             failcount;

        ret = 1;
        username = NULL;
        hostname = NULL;
        tty_name = NULL;

        retcode = pam_start ("login", username, &conv, &pamh);
        if (retcode != PAM_SUCCESS) {
                fprintf (stderr, "login: PAM Failure, aborting: %s\n",
                         pam_strerror (pamh, retcode));
                exit (99);
        }

        ttyn = ttyname (0);

        if (strncmp (ttyn, _PATH_DEV, 5) == 0) {
                tty_name = ttyn + 5;
        } else {
                tty_name = ttyn;
        }

        retcode = pam_set_item (pamh, PAM_RHOST, hostname);
        PAM_FAIL_CHECK;
        retcode = pam_set_item (pamh, PAM_TTY, tty_name);
        PAM_FAIL_CHECK;
        pam_set_item (pamh, PAM_USER, NULL);

        retcode = pam_set_item (pamh, PAM_USER_PROMPT, "Username: "******"Login incorrect\n\n");
                pam_set_item (pamh, PAM_USER, NULL);
                retcode = pam_authenticate (pamh, 0);
        }

        if (retcode != PAM_SUCCESS) {
                fprintf (stderr, "\nLogin incorrect\n");
                pam_end (pamh, retcode);
                exit (0);
        }

        retcode = pam_acct_mgmt (pamh, 0);
        if (retcode == PAM_NEW_AUTHTOK_REQD) {
                retcode = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
        }

        PAM_FAIL_CHECK;

        pam_putenv (pamh, "CKCON_TTY=/dev/tty55");
        pam_putenv (pamh, "CKCON_X11_DISPLAY=:50");

        retcode = pam_open_session (pamh, 0);
        PAM_FAIL_CHECK;

        retcode = pam_setcred (pamh, PAM_ESTABLISH_CRED);
        PAM_FAIL_CHECK;

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

        printf ("Session opened for %s\n", username);

        printf ("sleeping for 20 seconds...");
        sleep (20);

        PAM_END;

        printf ("\nSession closed\n");

        return ret;
}
예제 #28
0
int
main(void)
{
    pam_handle_t *pamh;
    struct pam_conv conv = { NULL, NULL };
    char **env;
    size_t i;

    /*
     * Skip this test if the native PAM library doesn't support a PAM
     * environment, since we "break" pam_putenv to mirror the native behavior
     * in that case.
     */
#ifndef HAVE_PAM_GETENV
    skip_all("system doesn't support PAM environment");
#endif

    plan(33);

    /* Basic environment manipulation. */
    if (pam_start("test", NULL, &conv, &pamh) != PAM_SUCCESS)
        sysbail("Fake PAM initialization failed");
    is_int(PAM_BAD_ITEM, pam_putenv(pamh, "TEST"), "delete when NULL");
    ok(pam_getenv(pamh, "TEST") == NULL, "getenv when NULL");
    env = pam_getenvlist(pamh);
    ok(env != NULL, "getenvlist when NULL returns non-NULL");
    is_string(NULL, env[0], "...but first element is NULL");
    for (i = 0; env[i] != NULL; i++)
        free(env[i]);
    free(env);

    /* putenv and getenv. */
    is_int(PAM_SUCCESS, pam_putenv(pamh, "TEST=foo"), "putenv TEST");
    is_string("foo", pam_getenv(pamh, "TEST"), "getenv TEST");
    is_int(PAM_SUCCESS, pam_putenv(pamh, "FOO=bar"), "putenv FOO");
    is_int(PAM_SUCCESS, pam_putenv(pamh, "BAR=baz"), "putenv BAR");
    is_string("foo", pam_getenv(pamh, "TEST"), "getenv TEST");
    is_string("bar", pam_getenv(pamh, "FOO"), "getenv FOO");
    is_string("baz", pam_getenv(pamh, "BAR"), "getenv BAR");
    ok(pam_getenv(pamh, "BAZ") == NULL, "getenv BAZ is NULL");

    /* Replacing and deleting environment variables. */
    is_int(PAM_BAD_ITEM, pam_putenv(pamh, "BAZ"), "putenv nonexistent delete");
    is_int(PAM_SUCCESS, pam_putenv(pamh, "FOO=foo"), "putenv replace");
    is_int(PAM_SUCCESS, pam_putenv(pamh, "FOON=bar=n"), "putenv prefix");
    is_string("foo", pam_getenv(pamh, "FOO"), "getenv FOO");
    is_string("bar=n", pam_getenv(pamh, "FOON"), "getenv FOON");
    is_int(PAM_BAD_ITEM, pam_putenv(pamh, "FO"), "putenv delete FO");
    is_int(PAM_SUCCESS, pam_putenv(pamh, "FOO"), "putenv delete FOO");
    ok(pam_getenv(pamh, "FOO") == NULL, "getenv FOO is NULL");
    is_string("bar=n", pam_getenv(pamh, "FOON"), "getenv FOON");
    is_string("baz", pam_getenv(pamh, "BAR"), "getenv BAR");

    /* pam_getenvlist. */
    env = pam_getenvlist(pamh);
    ok(env != NULL, "getenvlist not NULL");
    is_string("TEST=foo", env[0], "getenvlist TEST");
    is_string("BAR=baz", env[1], "getenvlist BAR");
    is_string("FOON=bar=n", env[2], "getenvlist FOON");
    ok(env[3] == NULL, "getenvlist length");
    for (i = 0; env[i] != NULL; i++)
        free(env[i]);
    free(env);
    is_int(PAM_SUCCESS, pam_putenv(pamh, "FOO=foo"), "putenv FOO");
    is_string("TEST=foo", pamh->environ[0], "pamh environ TEST");
    is_string("BAR=baz", pamh->environ[1], "pamh environ BAR");
    is_string("FOON=bar=n", pamh->environ[2], "pamh environ FOON");
    is_string("FOO=foo", pamh->environ[3], "pamh environ FOO");
    ok(pamh->environ[4] == NULL, "pamh environ length");

    pam_end(pamh, 0);

    return 0;
}
예제 #29
0
int
pam_sm_open_session(
    pam_handle_t* pamh,
    int           flags,
    int           argc,
    const char**  argv
    )
{
    DWORD dwError = 0;
    PPAMCONTEXT pPamContext = NULL;
    HANDLE hLsaConnection = (HANDLE)NULL;
    PSTR pszLoginId = NULL;
    PLSA_PAM_CONFIG pConfig = NULL;

#ifdef HAVE_PAM_PUTENV
    PSTR pszSmartCardReader = NULL;
    PSTR pszSmartCardReaderEnv = NULL;
#endif /* HAVE_PAM_PUTENV */

    LSA_LOG_PAM_DEBUG("pam_sm_open_session::begin");

    dwError = LsaPamGetConfig(&pConfig);
    BAIL_ON_LSA_ERROR(dwError);

    LsaPamSetLogLevel(pConfig->dwLogLevel);

    dwError = LsaPamGetContext(
                    pamh,
                    flags,
                    argc,
                    argv,
                    &pPamContext);
    BAIL_ON_LSA_ERROR(dwError);

    dwError = LsaPamGetLoginId(
                    pamh,
                    pPamContext,
                    &pszLoginId,
                    TRUE);
    BAIL_ON_LSA_ERROR(dwError);

#ifdef HAVE_PAM_PUTENV
    dwError = pam_get_data(
        pamh,
        PAM_LSASS_SMART_CARD_READER,
        (PAM_GET_DATA_TYPE)&pszSmartCardReader);
    /* pszSmartCardReader will be freed when the module is closed. */
    if (dwError == PAM_SUCCESS && pszSmartCardReader != NULL)
    {
        dwError = LwAllocateStringPrintf(
            &pszSmartCardReaderEnv,
            "LW_SMART_CARD_READER=%s",
            pszSmartCardReader);
        BAIL_ON_LSA_ERROR(dwError);

        dwError = pam_putenv(
            pamh,
            pszSmartCardReaderEnv);
        BAIL_ON_LSA_ERROR(dwError);
    }
#endif /* HAVE_PAM_PUTENV */

    if (LsaShouldIgnoreUser(pszLoginId))
    {
        LSA_LOG_PAM_DEBUG("By passing lsassd for local account");
        dwError = LW_ERROR_NOT_HANDLED;
        BAIL_ON_LSA_ERROR(dwError);
    }

    dwError = LsaOpenServer(&hLsaConnection);
    BAIL_ON_LSA_ERROR(dwError);

    dwError = LsaOpenSession(
                    hLsaConnection,
                    pszLoginId);
    BAIL_ON_LSA_ERROR(dwError);


    if (pPamContext &&
        pConfig->bLsaPamDisplayMOTD)
    {
        dwError = LsaPamDisplayMOTD(
                        pamh,
                        pPamContext);
        BAIL_ON_LSA_ERROR(dwError);
    }

    if (pPamContext &&
        pPamContext->bOnlineLogon)
    {
        dwError = LsaPamNotifyUserLogon(
                        pszLoginId);
        if (dwError == LW_ERROR_LOAD_LIBRARY_FAILED ||
            dwError == LW_ERROR_LOOKUP_SYMBOL_FAILED )
        {
            dwError = 0;
        }
        BAIL_ON_LSA_ERROR(dwError);
    }

cleanup:

    if (hLsaConnection != (HANDLE)NULL) {
        LsaCloseServer(hLsaConnection);
    }

    if (pConfig)
    {
        LsaPamFreeConfig(pConfig);
    }

    LW_SAFE_FREE_STRING(pszLoginId);

#ifdef HAVE_PAM_PUTENV
    LW_SAFE_FREE_STRING(pszSmartCardReaderEnv);
#endif /* HAVE_PAM_PUTENV */

    LSA_LOG_PAM_DEBUG("pam_sm_open_session::end");

    return LsaPamOpenPamFilterOpenSession(
                            LsaPamMapErrorCode(dwError, pPamContext));

error:

    if ((dwError == LW_ERROR_NO_SUCH_USER) || (dwError == LW_ERROR_NOT_HANDLED))
    {
        LSA_LOG_PAM_WARNING("pam_sm_open_session failed [login:%s][error code: %u]", 
                            LSA_SAFE_LOG_STRING(pszLoginId),
                            dwError);
    }
    else
    {
        LSA_LOG_PAM_ERROR("pam_sm_open_session failed [login:%s][error code: %u]", 
                          LSA_SAFE_LOG_STRING(pszLoginId),
                          dwError);
    }

    goto cleanup;
}
예제 #30
0
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
{
  int i, rv;
  const char *user = NULL;
  char *password;
  unsigned int slot_num = 0;
  int is_a_screen_saver = 0;
  struct configuration_st *configuration;
  int pkcs11_pam_fail = PAM_AUTHINFO_UNAVAIL;

  pkcs11_handle_t *ph;
  cert_object_t *chosen_cert = NULL;
  cert_object_t **cert_list;
  int ncert;
  unsigned char random_value[128];
  unsigned char *signature;
  unsigned long signature_length;
  /* enough space to hold an issuer DN */
  char env_temp[256] = "";
  char **issuer, **serial;
  const char *login_token_name = NULL;

  pam_prompt(pamh, PAM_TEXT_INFO , NULL, _("Smartcard authentication starts"));

  /* first of all check whether debugging should be enabled */
  for (i = 0; i < argc; i++)
    if (strcmp("debug", argv[i]) == 0) {
      set_debug_level(1);
    }

  /* call configure routines */
  configuration = pk_configure(argc,argv);
  if (!configuration ) {
	ERR("Error setting configuration parameters");
	return PAM_AUTHINFO_UNAVAIL;
  }

  /* Either slot_description or slot_num, but not both, needs to be used */
  if ((configuration->slot_description != NULL && configuration->slot_num != -1) || (configuration->slot_description == NULL && configuration->slot_num == -1)) {
	ERR("Error setting configuration parameters");
	return PAM_AUTHINFO_UNAVAIL;
  }

  /* fail if we are using a remote server
   * local login: DISPLAY=:0
   * XDMCP login: DISPLAY=host:0 */
  {
	  char *display = getenv("DISPLAY");

	  if (display)
	  {
		  if (strncmp(display, "localhost:", 10) != 0 && (display[0] != ':')
			  && (display[0] != '\0')) {
			  ERR1("Remote login (from %s) is not (yet) supported", display);
			  pam_syslog(pamh, LOG_ERR,
				  "Remote login (from %s) is not (yet) supported", display);
			  return PAM_AUTHINFO_UNAVAIL;
		  }
	  }
  }

#ifdef ENABLE_NLS
  setlocale(LC_ALL, "");
  bindtextdomain(PACKAGE, "/usr/share/locale");
  textdomain(PACKAGE);
#endif

  /* init openssl */
  rv = crypto_init(&configuration->policy);
  if (rv != 0) {
    ERR("Failed to initialize crypto");
    if (!configuration->quiet)
      pam_syslog(pamh,LOG_ERR, "Failed to initialize crypto");
    return PAM_AUTHINFO_UNAVAIL;
  }


  /*
   * card_only means:
   *  1) always get the userid from the certificate.
   *  2) don't prompt for the user name if the card is present.
   *  3) if the token is present, then we must use the cardAuth mechanism.
   *
   * wait_for_card means:
   *  1) nothing if card_only isn't set
   *  2) if logged in, block in pam conversation until the token used for login
   *     is inserted
   *  3) if not logged in, block until a token that could be used for logging in
   *     is inserted
   * right now, logged in means PKC11_LOGIN_TOKEN_NAME is set,
   * but we could something else later (like set some per-user state in
   * a pam session module keyed off uid)
   */
  if (configuration->card_only) {
	char *service;
	if (configuration->screen_savers) {
	    DBG("Is it a screen saver?");
		pam_get_item(pamh, PAM_SERVICE, &service);
	    for (i=0; configuration->screen_savers[i]; i++) {
		if (strcmp(configuration->screen_savers[i], service) == 0) {
		    is_a_screen_saver = 1;
		    break;
		}
	    }
	}

	pkcs11_pam_fail = PAM_CRED_INSUFFICIENT;

	/* look to see if username is already set */
	pam_get_item(pamh, PAM_USER, &user);
	if (user) {
	    DBG1("explicit username = [%s]", user);
	}
  } else {
	rv = pam_get_item(pamh, PAM_USER, &user);
	if (rv != PAM_SUCCESS || user == NULL || user[0] == '\0') {
	  pam_prompt(pamh, PAM_TEXT_INFO, NULL,
		  _("Please insert your %s or enter your username."),
		  _(configuration->token_type));
	  /* get user name */
	  rv = pam_get_user(pamh, &user, NULL);

	  if (rv != PAM_SUCCESS) {
		pam_syslog(pamh, LOG_ERR,
			"pam_get_user() failed %s", pam_strerror(pamh, rv));
		return PAM_USER_UNKNOWN;
	  }
	}
	DBG1("username = [%s]", user);
  }
  login_token_name = getenv("PKCS11_LOGIN_TOKEN_NAME");

  /* if we are using a screen saver, and we didn't log in using the smart card
   * drop to the next pam module.  */
  if (is_a_screen_saver && !login_token_name) {
    return PAM_IGNORE;
  }

  /* load pkcs #11 module */
  DBG("loading pkcs #11 module...");
  rv = load_pkcs11_module(configuration->pkcs11_modulepath, &ph);
  if (rv != 0) {
    ERR2("load_pkcs11_module() failed loading %s: %s",
		configuration->pkcs11_modulepath, get_error());
    if (!configuration->quiet) {
		pam_syslog(pamh, LOG_ERR, "load_pkcs11_module() failed loading %s: %s",
			configuration->pkcs11_modulepath, get_error());
		pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2302: PKCS#11 module failed loading"));
		sleep(configuration->err_display_time);
	}
    return PAM_AUTHINFO_UNAVAIL;
  }

  /* initialise pkcs #11 module */
  DBG("initialising pkcs #11 module...");
  rv = init_pkcs11_module(ph,configuration->support_threads);
  if (rv != 0) {
    release_pkcs11_module(ph);
    ERR1("init_pkcs11_module() failed: %s", get_error());
    if (!configuration->quiet) {
		pam_syslog(pamh, LOG_ERR, "init_pkcs11_module() failed: %s", get_error());
		pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2304: PKCS#11 module could not be initialized"));
		sleep(configuration->err_display_time);
	}
    return PAM_AUTHINFO_UNAVAIL;
  }

  /* open pkcs #11 session */
  if (configuration->slot_description != NULL) {
    rv = find_slot_by_slotlabel_and_tokenlabel(ph,
      configuration->slot_description, login_token_name, &slot_num);
  } else if (configuration->slot_num != -1) {
    rv = find_slot_by_number_and_label(ph, configuration->slot_num,
                                     login_token_name, &slot_num);
  }

  if (rv != 0) {
    ERR("no suitable token available");
    if (!configuration->quiet) {
		pam_syslog(pamh, LOG_ERR, "no suitable token available");
		pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2306: No suitable token available"));
		sleep(configuration->err_display_time);
	}

    if (!configuration->card_only) {
      release_pkcs11_module(ph);
      return PAM_AUTHINFO_UNAVAIL;
    }

    /* we must have a smart card, either because we've configured it as such,
     * or because we used one to log in */
    if (login_token_name || configuration->wait_for_card) {
      if (login_token_name) {
        pam_prompt(pamh, PAM_TEXT_INFO, NULL,
			_("Please insert your smart card called \"%.32s\"."),
			login_token_name);
      } else {
        pam_prompt(pamh, PAM_TEXT_INFO, NULL,
                 _("Please insert your smart card."));
      }

      if (configuration->slot_description != NULL) {
	rv = wait_for_token_by_slotlabel(ph, configuration->slot_description,
          login_token_name, &slot_num);
      } else if (configuration->slot_num != -1) {
        rv = wait_for_token(ph, configuration->slot_num,
                          login_token_name, &slot_num);
      }

      if (rv != 0) {
        release_pkcs11_module(ph);
        return pkcs11_pam_fail;
      }
    } else if (user) {
		if (!configuration->quiet) {
			pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2308: No smartcard found"));
			sleep(configuration->err_display_time);
		}

      /* we have a user and no smart card, go to the next pam module */
      release_pkcs11_module(ph);
      return PAM_AUTHINFO_UNAVAIL;
    } else {
      /* we haven't prompted for the user yet, get the user and see if
       * the smart card has been inserted in the mean time */
      pam_prompt(pamh, PAM_TEXT_INFO, NULL,
	    _("Please insert your %s or enter your username."),
		_(configuration->token_type));
      rv = pam_get_user(pamh, &user, NULL);

      /* check one last time for the smart card before bouncing to the next
       * module */
      if (configuration->slot_description != NULL) {
	rv = find_slot_by_slotlabel(ph, configuration->slot_description,
	  &slot_num);
      } else if (configuration->slot_num != -1) {
        rv = find_slot_by_number(ph, configuration->slot_num, &slot_num);
      }

      if (rv != 0) {
        /* user gave us a user id and no smart card go to next module */
		if (!configuration->quiet) {
			pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2310: No smartcard found"));
			sleep(configuration->err_display_time);
		}

        release_pkcs11_module(ph);
        return PAM_AUTHINFO_UNAVAIL;
      }
    }
  } else {
      pam_prompt(pamh, PAM_TEXT_INFO, NULL,
		  _("%s found."), _(configuration->token_type));
  }
  rv = open_pkcs11_session(ph, slot_num);
  if (rv != 0) {
    ERR1("open_pkcs11_session() failed: %s", get_error());
    if (!configuration->quiet) {
		pam_syslog(pamh, LOG_ERR, "open_pkcs11_session() failed: %s", get_error());
		pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2312: open PKCS#11 session failed"));
		sleep(configuration->err_display_time);
	}
    release_pkcs11_module(ph);
    return pkcs11_pam_fail;
  }

  rv = get_slot_login_required(ph);
  if (rv == -1) {
    ERR1("get_slot_login_required() failed: %s", get_error());
    if (!configuration->quiet) {
		pam_syslog(pamh, LOG_ERR, "get_slot_login_required() failed: %s", get_error());
		pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2314: Slot login failed"));
		sleep(configuration->err_display_time);
	}
    release_pkcs11_module(ph);
    return pkcs11_pam_fail;
  } else if (rv) {
    /* get password */
	pam_prompt(pamh, PAM_TEXT_INFO, NULL,
		_("Welcome %.32s!"), get_slot_tokenlabel(ph));

	/* no CKF_PROTECTED_AUTHENTICATION_PATH */
	rv = get_slot_protected_authentication_path(ph);
	if ((-1 == rv) || (0 == rv))
	{
		char password_prompt[128];

		snprintf(password_prompt,  sizeof(password_prompt), _("%s PIN: "), _(configuration->token_type));
		if (configuration->use_first_pass) {
			rv = pam_get_pwd(pamh, &password, NULL, PAM_AUTHTOK, 0);
		} else if (configuration->try_first_pass) {
			rv = pam_get_pwd(pamh, &password, password_prompt, PAM_AUTHTOK,
					PAM_AUTHTOK);
		} else {
			rv = pam_get_pwd(pamh, &password, password_prompt, 0, PAM_AUTHTOK);
		}
		if (rv != PAM_SUCCESS) {
			if (!configuration->quiet) {
				pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2316: password could not be read"));
				sleep(configuration->err_display_time);
			}
			release_pkcs11_module(ph);
			pam_syslog(pamh, LOG_ERR,
					"pam_get_pwd() failed: %s", pam_strerror(pamh, rv));
			return pkcs11_pam_fail;
		}
#ifdef DEBUG_SHOW_PASSWORD
		DBG1("password = [%s]", password);
#endif

		/* check password length */
		if (!configuration->nullok && strlen(password) == 0) {
			release_pkcs11_module(ph);
			memset(password, 0, strlen(password));
			free(password);
			pam_syslog(pamh, LOG_ERR,
					"password length is zero but the 'nullok' argument was not defined.");
			if (!configuration->quiet) {
				pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2318: Empty smartcard PIN not allowed."));
				sleep(configuration->err_display_time);
			}
			return PAM_AUTH_ERR;
		}
	}
	else
	{
		pam_prompt(pamh, PAM_TEXT_INFO, NULL,
			_("Enter your %s PIN on the pinpad"), _(configuration->token_type));
		/* use pin pad */
		password = NULL;
	}

    /* call pkcs#11 login to ensure that the user is the real owner of the card
     * we need to do thise before get_certificate_list because some tokens
     * can not read their certificates until the token is authenticated */
    rv = pkcs11_login(ph, password);
    /* erase and free in-memory password data asap */
	if (password)
	{
		memset(password, 0, strlen(password));
		free(password);
	}
    if (rv != 0) {
      ERR1("open_pkcs11_login() failed: %s", get_error());
		if (!configuration->quiet) {
			pam_syslog(pamh, LOG_ERR, "open_pkcs11_login() failed: %s", get_error());
			pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2320: Wrong smartcard PIN"));
			sleep(configuration->err_display_time);
		}
      goto auth_failed_nopw;
    }
  }

  cert_list = get_certificate_list(ph, &ncert);
  if (rv<0) {
    ERR1("get_certificate_list() failed: %s", get_error());
    if (!configuration->quiet) {
		pam_syslog(pamh, LOG_ERR, "get_certificate_list() failed: %s", get_error());
		pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2322: No certificate found"));
		sleep(configuration->err_display_time);
	}
    goto auth_failed_nopw;
  }

  /* load mapper modules */
  load_mappers(configuration->ctx);

  /* find a valid and matching certificates */
  for (i = 0; i < ncert; i++) {
    X509 *x509 = (X509 *)get_X509_certificate(cert_list[i]);
    if (!x509 ) continue; /* sanity check */
    DBG1("verifying the certificate #%d", i + 1);
	if (!configuration->quiet) {
		pam_prompt(pamh, PAM_TEXT_INFO, NULL, _("verifying certificate"));
	}

      /* verify certificate (date, signature, CRL, ...) */
      rv = verify_certificate(x509,&configuration->policy);
      if (rv < 0) {
        ERR1("verify_certificate() failed: %s", get_error());
        if (!configuration->quiet) {
          pam_syslog(pamh, LOG_ERR,
                   "verify_certificate() failed: %s", get_error());
			switch (rv) {
				case -2: // X509_V_ERR_CERT_HAS_EXPIRED:
					pam_prompt(pamh, PAM_ERROR_MSG , NULL,
						_("Error 2324: Certificate has expired"));
					break;
				case -3: // X509_V_ERR_CERT_NOT_YET_VALID:
					pam_prompt(pamh, PAM_ERROR_MSG , NULL,
						_("Error 2326: Certificate not yet valid"));
					break;
				case -4: // X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
					pam_prompt(pamh, PAM_ERROR_MSG , NULL,
						_("Error 2328: Certificate signature invalid"));
					break;
				default:
					pam_prompt(pamh, PAM_ERROR_MSG , NULL,
						_("Error 2330: Certificate invalid"));
					break;
			}
			sleep(configuration->err_display_time);
		}
        continue; /* try next certificate */
      } else if (rv != 1) {
        ERR1("verify_certificate() failed: %s", get_error());
        continue; /* try next certificate */
      }

    /* CA and CRL verified, now check/find user */

    if ( is_spaced_str(user) ) {
      /*
	if provided user is null or empty extract and set user
	name from certificate
      */
	DBG("Empty login: try to deduce from certificate");
	user=find_user(x509);
	if (!user) {
          ERR2("find_user() failed: %s on cert #%d", get_error(),i+1);
          if (!configuration->quiet)
            pam_syslog(pamh, LOG_ERR,
                     "find_user() failed: %s on cert #%d",get_error(),i+1);
	  continue; /* try on next certificate */
	} else {
          DBG1("certificate is valid and matches user %s",user);
	  /* try to set up PAM user entry with evaluated value */
	  rv = pam_set_item(pamh, PAM_USER,(const void *)user);
	  if (rv != PAM_SUCCESS) {
	    ERR1("pam_set_item() failed %s", pam_strerror(pamh, rv));
            if (!configuration->quiet) {
				pam_syslog(pamh, LOG_ERR,
                       "pam_set_item() failed %s", pam_strerror(pamh, rv));
				pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2332: setting PAM userentry failed"));
				sleep(configuration->err_display_time);
			}
	    goto auth_failed_nopw;
	}
          chosen_cert = cert_list[i];
          break; /* end loop, as find user success */
      }
    } else {
      /* User provided:
         check whether the certificate matches the user */
        rv = match_user(x509, user);
        if (rv < 0) { /* match error; abort and return */
          ERR1("match_user() failed: %s", get_error());
			if (!configuration->quiet) {
				pam_syslog(pamh, LOG_ERR, "match_user() failed: %s", get_error());
				pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2334: No matching user"));
				sleep(configuration->err_display_time);
			}
	  goto auth_failed_nopw;
        } else if (rv == 0) { /* match didn't success */
          DBG("certificate is valid but does not match the user");
	  continue; /* try next certificate */
        } else { /* match success */
          DBG("certificate is valid and matches the user");
          chosen_cert = cert_list[i];
          break;
      }
    } /* if is_spaced string */
  } /* for (i=0; i<ncerts; i++) */

  /* now myCert points to our found certificate or null if no user found */
  if (!chosen_cert) {
    ERR("no valid certificate which meets all requirements found");
		if (!configuration->quiet) {
			pam_syslog(pamh, LOG_ERR,
				"no valid certificate which meets all requirements found");
		pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2336: No matching certificate found"));
		sleep(configuration->err_display_time);
	}
    goto auth_failed_nopw;
  }


  /* if signature check is enforced, generate random data, sign and verify */
  if (configuration->policy.signature_policy) {
		pam_prompt(pamh, PAM_TEXT_INFO, NULL, _("Checking signature"));


#ifdef notdef
    rv = get_private_key(ph);
    if (rv != 0) {
      ERR1("get_private_key() failed: %s", get_error());
      if (!configuration->quiet)
        pam_syslog(pamh, LOG_ERR,
                 "get_private_key() failed: %s", get_error());
      goto auth_failed_nopw;
    }
#endif

    /* read random value */
    rv = get_random_value(random_value, sizeof(random_value));
    if (rv != 0) {
      ERR1("get_random_value() failed: %s", get_error());
		if (!configuration->quiet){
			pam_syslog(pamh, LOG_ERR, "get_random_value() failed: %s", get_error());
			pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2338: Getting random value failed"));
			sleep(configuration->err_display_time);
		}
      goto auth_failed_nopw;
    }

    /* sign random value */
    signature = NULL;
    rv = sign_value(ph, chosen_cert, random_value, sizeof(random_value),
		    &signature, &signature_length);
    if (rv != 0) {
      ERR1("sign_value() failed: %s", get_error());
		if (!configuration->quiet) {
			pam_syslog(pamh, LOG_ERR, "sign_value() failed: %s", get_error());
			pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2340: Signing failed"));
			sleep(configuration->err_display_time);
		}
      goto auth_failed_nopw;
    }

    /* verify the signature */
    DBG("verifying signature...");
    rv = verify_signature((X509 *)get_X509_certificate(chosen_cert),
             random_value, sizeof(random_value), signature, signature_length);
    if (signature != NULL) {
      free(signature);
    }
    if (rv != 0) {
      close_pkcs11_session(ph);
      release_pkcs11_module(ph);
      ERR1("verify_signature() failed: %s", get_error());
		if (!configuration->quiet) {
			pam_syslog(pamh, LOG_ERR, "verify_signature() failed: %s", get_error());
			pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2342: Verifying signature failed"));
			sleep(configuration->err_display_time);
		}
      return PAM_AUTH_ERR;
    }

  } else {
      DBG("Skipping signature check");
  }

  /*
   * fill in the environment variables.
   */
  snprintf(env_temp, sizeof(env_temp) - 1,
	   "PKCS11_LOGIN_TOKEN_NAME=%.*s",
	   (int)((sizeof(env_temp) - 1) - strlen("PKCS11_LOGIN_TOKEN_NAME=")),
	   get_slot_tokenlabel(ph));
  rv = pam_putenv(pamh, env_temp);

  if (rv != PAM_SUCCESS) {
    ERR1("could not put token name in environment: %s",
         pam_strerror(pamh, rv));
    if (!configuration->quiet)
      pam_syslog(pamh, LOG_ERR, "could not put token name in environment: %s",
           pam_strerror(pamh, rv));
  }

  issuer = cert_info((X509 *)get_X509_certificate(chosen_cert), CERT_ISSUER,
                     ALGORITHM_NULL);
  if (issuer) {
    snprintf(env_temp, sizeof(env_temp) - 1,
	   "PKCS11_LOGIN_CERT_ISSUER=%.*s",
	   (int)((sizeof(env_temp) - 1) - strlen("PKCS11_LOGIN_CERT_ISSUER=")),
	   issuer[0]);
    rv = pam_putenv(pamh, env_temp);
  } else {
    ERR("couldn't get certificate issuer.");
    if (!configuration->quiet)
      pam_syslog(pamh, LOG_ERR, "couldn't get certificate issuer.");
  }

  if (rv != PAM_SUCCESS) {
    ERR1("could not put cert issuer in environment: %s",
         pam_strerror(pamh, rv));
    if (!configuration->quiet)
      pam_syslog(pamh, LOG_ERR, "could not put cert issuer in environment: %s",
           pam_strerror(pamh, rv));
  }

  serial = cert_info((X509 *)get_X509_certificate(chosen_cert), CERT_SERIAL,
                     ALGORITHM_NULL);
  if (serial) {
    snprintf(env_temp, sizeof(env_temp) - 1,
	   "PKCS11_LOGIN_CERT_SERIAL=%.*s",
	   (int)((sizeof(env_temp) - 1) - strlen("PKCS11_LOGIN_CERT_SERIAL=")),
	   serial[0]);
    rv = pam_putenv(pamh, env_temp);
  } else {
    ERR("couldn't get certificate serial number.");
    if (!configuration->quiet)
      pam_syslog(pamh, LOG_ERR, "couldn't get certificate serial number.");
  }

  if (rv != PAM_SUCCESS) {
    ERR1("could not put cert serial in environment: %s",
         pam_strerror(pamh, rv));
    if (!configuration->quiet)
      pam_syslog(pamh, LOG_ERR, "could not put cert serial in environment: %s",
           pam_strerror(pamh, rv));
  }

  /* unload mapper modules */
  unload_mappers();

  /* close pkcs #11 session */
  rv = close_pkcs11_session(ph);
  if (rv != 0) {
    release_pkcs11_module(ph);
    ERR1("close_pkcs11_session() failed: %s", get_error());
		if (!configuration->quiet) {
			pam_syslog(pamh, LOG_ERR, "close_pkcs11_module() failed: %s", get_error());
			pam_prompt(pamh, PAM_ERROR_MSG , NULL, ("Error 2344: Closing PKCS#11 session failed"));
			sleep(configuration->err_display_time);
		}
    return pkcs11_pam_fail;
  }

  /* release pkcs #11 module */
  DBG("releasing pkcs #11 module...");
  release_pkcs11_module(ph);

  DBG("authentication succeeded");
  return PAM_SUCCESS;

    /* quick and dirty fail exit point */
    memset(password, 0, strlen(password));
    free(password); /* erase and free in-memory password data */

auth_failed_nopw:
    unload_mappers();
    close_pkcs11_session(ph);
    release_pkcs11_module(ph);
    return pkcs11_pam_fail;
}