Example #1
2
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 */
    }
}
Example #2
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;
}
Example #3
0
/* try to get the module's context, returns a PAM status code */
static int ctx_get(pam_handle_t *pamh,const char *username,struct pld_ctx **pctx)
{
  struct pld_ctx *ctx=NULL;
  int rc;
  /* try to get the context from PAM */
  rc=pam_get_data(pamh,PLD_CTX,(const void **)&ctx);
  if ((rc==PAM_SUCCESS)&&(ctx!=NULL))
  {
    /* if the user is different clear the context */
    if ((ctx->user!=NULL)&&(strcmp(ctx->user,username)!=0))
      ctx_clear(ctx);
  }
  else
  {
    /* allocate a new context */
    ctx=calloc(1,sizeof(struct pld_ctx));
    if (ctx==NULL)
    {
      pam_syslog(pamh,LOG_CRIT,"calloc(): failed to allocate memory: %s",strerror(errno));
      return PAM_BUF_ERR;
    }
    ctx_clear(ctx);
    /* store the new context with the handler to free it */
    rc=pam_set_data(pamh,PLD_CTX,ctx,ctx_free);
    if (rc!=PAM_SUCCESS)
    {
      ctx_free(pamh,ctx,0);
      pam_syslog(pamh,LOG_ERR,"failed to store context: %s",pam_strerror(pamh,rc));
      return rc;
    }
  }
  /* return the context */
  *pctx=ctx;
  return PAM_SUCCESS;
}
Example #4
0
int pam_sm_setcred(pam_handle_t *pamh, int flags,
                   int argc, const char **argv)
{
	int retval, *pretval = NULL;

	retval = PAM_SUCCESS;

	_pam_get_data(pamh, "smb_setcred_return", &pretval);
	if(pretval) {
		retval = *pretval;
		SAFE_FREE(pretval);
	}
	pam_set_data(pamh, "smb_setcred_return", NULL, NULL);

	return retval;
}
Example #5
0
PAM_EXTERN int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
{
    pam_syslog(pamh, LOG_INFO, "pam_sm_open_session\n");

    if (get_env(pamh, "PAM_KWALLET_LOGIN") != NULL) {
        pam_syslog(pamh, LOG_INFO, "pam_kwallet: we were already executed");
        return PAM_SUCCESS;
    }

    parseArguments(argc, argv);

    int result;
    result = pam_set_data(pamh, "sm_open_session", "1", NULL);
    if (result != PAM_SUCCESS) {
        pam_syslog(pamh, LOG_ERR, "pam_kwallet: Impossible to store sm_open_session: %s"
            , pam_strerror(pamh, result));
        return PAM_IGNORE;
    }

     //Fetch the user, needed to get user information
    const char *username;
    result = pam_get_user(pamh, &username, NULL);
    if (result != PAM_SUCCESS) {
        pam_syslog(pamh, LOG_ERR, "pam_kwallet: Couldn't get username %s",
                   pam_strerror(pamh, result));
        return PAM_IGNORE;//Since we are not an essential module, just make pam ignore us
    }

    struct passwd *userInfo;
    userInfo = getpwnam(username);
    if (!userInfo) {
        pam_syslog(pamh, LOG_ERR, "pam_kwallet: Couldn't get user info (passwd) info");
        return PAM_IGNORE;
    }

    const char *kwalletKey;
    result = pam_get_data(pamh, "kwallet_key", (const void **)&kwalletKey);

    if (result != PAM_SUCCESS) {
        pam_syslog(pamh, LOG_INFO, "pam_kwallet: open_session called without kwallet_key");
        return PAM_SUCCESS;//We will wait for pam_sm_authenticate
    }

    start_kwallet(pamh, userInfo, kwalletKey);

    return PAM_SUCCESS;
}
int
openpam_borrow_cred(pam_handle_t *pamh,
	const struct passwd *pwd)
{
	struct pam_saved_cred *scred;
	const void *scredp;
	int r;

	ENTERI(pwd->pw_uid);
	r = pam_get_data(pamh, PAM_SAVED_CRED, &scredp);
	if (r == PAM_SUCCESS && scredp != NULL) {
		openpam_log(PAM_LOG_DEBUG,
		    "already operating under borrowed credentials");
		RETURNC(PAM_SYSTEM_ERR);
	}
	if (geteuid() != 0 && geteuid() != pwd->pw_uid) {
		openpam_log(PAM_LOG_DEBUG, "called with non-zero euid: %d",
		    (int)geteuid());
		RETURNC(PAM_PERM_DENIED);
	}
	scred = calloc((size_t)1, sizeof *scred);
	if (scred == NULL)
		RETURNC(PAM_BUF_ERR);
	scred->euid = geteuid();
	scred->egid = getegid();
	r = getgroups(NGROUPS_MAX, scred->groups);
	if (r < 0) {
		FREE(scred);
		RETURNC(PAM_SYSTEM_ERR);
	}
	scred->ngroups = r;
	r = pam_set_data(pamh, PAM_SAVED_CRED, scred, &openpam_free_data);
	if (r != PAM_SUCCESS) {
		FREE(scred);
		RETURNC(r);
	}
	if (geteuid() == pwd->pw_uid)
		RETURNC(PAM_SUCCESS);
	if (initgroups(pwd->pw_name, pwd->pw_gid) < 0 ||
	      setegid(pwd->pw_gid) < 0 || seteuid(pwd->pw_uid) < 0) {
		openpam_restore_cred(pamh);
		RETURNC(PAM_SYSTEM_ERR);
	}
	RETURNC(PAM_SUCCESS);
	/*NOTREACHED*/
}
int
openpam_restore_cred(pam_handle_t *pamh)
{
	struct pam_saved_cred *scred;
	int r;

	r = pam_get_data(pamh, PAM_SAVED_CRED, (const void **)(void *)&scred);
	if (r != PAM_SUCCESS)
		return (r);
	if (scred == NULL)
		return (PAM_SYSTEM_ERR);
	if (seteuid(scred->euid) == -1 ||
	    setgroups(scred->ngroups, scred->groups) == -1 ||
	    setegid(scred->egid) == -1)
		return (PAM_SYSTEM_ERR);
	pam_set_data(pamh, PAM_SAVED_CRED, NULL, NULL);
	return (PAM_SUCCESS);
}
Example #8
0
void
gray_make_str(pam_handle_t *pamh, const char *str, const char *name,
	      char **ret)
{
	int retval;
	char *newstr = XSTRDUP(str);

	retval = pam_set_data(pamh, name, (void *)newstr, gray_cleanup_string);
	if (retval != PAM_SUCCESS) {
		_pam_log(LOG_CRIT, 
			 "can't keep data [%s]: %s",
			 name,
			 pam_strerror(pamh, retval));
		gray_pam_delete(newstr);
	} else {
		*ret = newstr;
		newstr = NULL;
	}
}
Example #9
0
PAM_EXTERN int
pam_sm_setcred (pam_handle_t * pamh, int flags, int argc, const char **argv)
{
  int retval;
  const void *pretval = NULL;

  DBG (("called."));

  retval = PAM_SUCCESS;
  if (pam_get_data(pamh, "yubikey_setcred_return", &pretval) == PAM_SUCCESS
      && pretval)
    {
      retval = *(const int *)pretval;
      pam_set_data(pamh, "yubikey_setcred_return", NULL, NULL);
    }

  DBG (("done. [%s]", pam_strerror (pamh, retval)));

  return retval;
}
Example #10
0
DWORD
LsaPamSetDataString(
    pam_handle_t* pamh,
    PCSTR pszKey,
    PCSTR pszStr
    )
{
    DWORD dwError = 0;
    PSTR pszStrCopy = NULL;
    int iPamError = 0;

    dwError = LwAllocateString(pszStr, &pszStrCopy);
    BAIL_ON_LSA_ERROR(dwError);
    
    iPamError = pam_set_data(pamh, pszKey, pszStrCopy, LsaPamCleanupDataString);
    dwError = LsaPamUnmapErrorCode(iPamError);
    BAIL_ON_LSA_ERROR(dwError);

error:
    
    return dwError;
}
int
openpam_restore_cred(pam_handle_t *pamh)
{
	const struct pam_saved_cred *scred;
	const void *scredp;
	int r;

	ENTER();
	r = pam_get_data(pamh, PAM_SAVED_CRED, &scredp);
	if (r != PAM_SUCCESS)
		RETURNC(r);
	if (scredp == NULL)
		RETURNC(PAM_SYSTEM_ERR);
	scred = scredp;
	if (scred->euid != geteuid()) {
		if (seteuid(scred->euid) < 0 ||
		    setgroups(scred->ngroups, scred->groups) < 0 ||
		    setegid(scred->egid) < 0)
			RETURNC(PAM_SYSTEM_ERR);
	}
	pam_set_data(pamh, PAM_SAVED_CRED, NULL, NULL);
	RETURNC(PAM_SUCCESS);
}
Example #12
0
static int
_pam_get_password(pam_handle_t *pamh, char **password, const char *prompt)
{
	char *item, *token;
	int retval;
	struct pam_message msg[3], *pmsg[3];
	struct pam_response *resp;
	int i, replies;

	DEBUG(90,("enter _pam_get_password"));
	
	if (cntl_flags & CNTL_AUTHTOK) {
		/*
		 * get the password from the PAM item
		 */
		retval = pam_get_item(pamh, PAM_AUTHTOK,
				      (const void **) &item);
		if (retval != PAM_SUCCESS) {
			/* very strange. */
			_pam_log(LOG_ALERT,
				 "can't retrieve password item: %s",
				 pam_strerror(pamh, retval));
			return retval;
		} else if (item != NULL) {
			*password = item;
			item = NULL;
			return PAM_SUCCESS;
		} else
			return PAM_AUTHTOK_RECOVER_ERR;
	}

	/*
	 * ask user for the password
	 */
	/* prepare to converse */

	i = 0;
	pmsg[i] = &msg[i];
	msg[i].msg_style = PAM_PROMPT_ECHO_OFF;
	msg[i++].msg = (const void*)prompt;
	replies = 1;

	/* run conversation */
	resp = NULL;
	token = NULL;
	retval = gray_converse(pamh, i, pmsg, &resp);

	if (resp != NULL && resp[i - replies].resp) {
		if (retval == PAM_SUCCESS) { 	/* a good conversation */
			token = XSTRDUP(resp[i - replies].resp);
			DEBUG(100,("app returned [%s]", token));
			pam_set_item(pamh, PAM_AUTHTOK, token);
			PAM_DROP_REPLY(resp, 1);
		} else {
			_pam_log(LOG_ERR, "conversation error: %s",
				 pam_strerror(pamh, retval));
		}
		
	} else {
		retval = (retval == PAM_SUCCESS)
			? PAM_AUTHTOK_RECOVER_ERR : retval;
	}

	if (retval == PAM_SUCCESS) {
		/*
		 * keep password as data specific to this module. pam_end()
		 * will arrange to clean it up.
		 */
		retval = pam_set_data(pamh, "password",
				      (void *)token,
				      gray_cleanup_string);
		if (retval != PAM_SUCCESS) {
			_pam_log(LOG_CRIT, 
			         "can't keep password: %s",
				 pam_strerror(pamh, retval));
			gray_pam_delete(token);
		} else {
			*password = token;
			token = NULL;	/* break link to password */
		}
	} else {
		_pam_log(LOG_ERR,
			 "unable to obtain a password: %s",
			 pam_strerror(pamh, retval));
	} 
	
	DEBUG(90,("exit _pam_get_password: %d", retval));
	return retval;
}
Example #13
0
PAM_EXTERN int
pam_sm_authenticate (pam_handle_t * pamh,
		     int flags, int argc, const char **argv)
{
  int retval, *ret_data=NULL;
  int try_first_pass=0, use_first_pass=0;
  const char *user = NULL;
  const char *password = NULL;
  struct pam_conv *conv;
  struct pam_message *pmsg[1], msg[1];
  struct pam_response *resp;
  int nargs = 1, i;

  ret_data = malloc(sizeof(int));

  for (i=0; i<argc; i++)
    {
      if (strcmp(argv[i], "try_first_pass") == 0)
	try_first_pass = 1;
      else if (strcmp(argv[i], "use_first_pass") == 0)
	use_first_pass = 1;
    }

  retval = pam_get_user (pamh, &user, NULL);
  if (retval != PAM_SUCCESS)
    {
      DBG (("get user returned error: %s", pam_strerror (pamh, retval)));
      goto done;
    }
  DBG (("get user returned: %s", user));

  if (ask_server(user, "test", SERVER_LINK) == CHK_UNKNOWN)
    {
      DBG(("User [%s] unknown: not going further", user));
      retval = PAM_USER_UNKNOWN;
      goto done;
    }

  if (try_first_pass || use_first_pass)
    {
      retval = pam_get_item (pamh, PAM_AUTHTOK, (const void **) &password);
      if (retval != PAM_SUCCESS)
	{
	  DBG (("get password returned error: %s",
	      pam_strerror (pamh, retval)));
	  goto done;
	}
      DBG (("get password returned: %s", password));
    }

  if (use_first_pass && password == NULL)
    {
      DBG (("use_first_pass set and no password, giving up"));
      retval = PAM_AUTH_ERR;
      goto done;
    }

  if (password)
    {
      retval = ask_server(user, password, SERVER_LINK);
      switch(retval)
	{
	case CHK_OK:
	  retval = PAM_SUCCESS;
	  goto done;
	case CHK_UNKNOWN:
	  retval = PAM_USER_UNKNOWN;
	  goto done;
	default:
	  password = NULL;
	}
    }

  retval = pam_get_item (pamh, PAM_CONV, (const void **) &conv);
  if (retval != PAM_SUCCESS)
    {
      DBG (("get conv returned error: %s", pam_strerror (pamh, retval)));
      goto done;
    }

  pmsg[0] = &msg[0];
  msg[0].msg = _("Password: "******"conv returned error: %s", pam_strerror (pamh, retval)));
      goto done;
    }

  if (resp->resp == NULL)
    {
      DBG (("conv returned NULL passwd?"));
      goto done;
    }

  DBG (("conv returned: %s", resp->resp));

  password = resp->resp;

  retval = ask_server(user, password, SERVER_LINK);
  DBG (("ask_server returned: %d", retval));
  switch(retval)
    {
    case CHK_OK:
      retval = PAM_SUCCESS;
      break;
    case CHK_UNKNOWN:
      retval = PAM_USER_UNKNOWN;
      break;
    default:
      retval = PAM_AUTH_ERR;
    }

 done:
  *ret_data = retval;
  pam_set_data(pamh, "yubikey_setcred_return",
	       (void *) ret_data, setcred_free);

  DBG (("done. [%s]", pam_strerror (pamh, retval)));

  return retval;
}
/* 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;
}
Example #15
0
PAM_EXTERN int
pam_sm_authenticate (pam_handle_t *ph, int unused, int argc, const char **argv)
{
	struct passwd *pwd;
	const char *user, *password;
	const char *control;
	int started_daemon;
	uint args;
	int ret;
	
	args = parse_args (ph, argc, argv);

	if (args & ARG_IGNORE_SERVICE)
		return PAM_SUCCESS;
		
	/* Figure out and/or prompt for the user name */
	ret = pam_get_user (ph, &user, NULL);
	if (ret != PAM_SUCCESS) {
		syslog (GKR_LOG_ERR, "gkr-pam: couldn't get the user name: %s", 
		        pam_strerror (ph, ret));
		return PAM_SERVICE_ERR;
	}
	
	pwd = getpwnam (user);
	if (!pwd) {
		syslog (GKR_LOG_ERR, "gkr-pam: error looking up user information");
		return PAM_SERVICE_ERR;
	}
		
	/* Look up the password */
	ret = pam_get_item (ph, PAM_AUTHTOK, (const void**)&password);
	if (ret != PAM_SUCCESS || password == NULL) {
		if (ret == PAM_SUCCESS)
			syslog (GKR_LOG_WARN, "gkr-pam: no password is available for user");
		else
			syslog (GKR_LOG_WARN, "gkr-pam: no password is available for user: %s", 
			        pam_strerror (ph, ret));
		return PAM_SUCCESS;
	}

	started_daemon = 0;

	/* Should we start the daemon? */
	if (args & ARG_AUTO_START) {
		ret = start_daemon_if_necessary (ph, pwd, password, &started_daemon);
		if (ret != PAM_SUCCESS)
			return ret;
	}

	control = get_any_env (ph, ENV_CONTROL);

	/* If mate keyring is running, then unlock now */
	if (control) {
		/* If we started the daemon, its already unlocked, since we passed the password */
		if (!started_daemon) {
			ret = unlock_keyring (ph, pwd, password);
			if (ret != PAM_SUCCESS)
				return ret;
		}
		
	/* Otherwise start later in open session, store password */
	} else {
		if (pam_set_data (ph, "gkr_system_authtok", strdup (password),
		                  cleanup_free_password) != PAM_SUCCESS) {
			syslog (GKR_LOG_ERR, "gkr-pam: error storing authtok");
			return PAM_AUTHTOK_RECOVER_ERR;
		}
 	}

	return PAM_SUCCESS;
}
Example #16
0
PAM_EXTERN int
pam_sm_authenticate (pam_handle_t * pamh,
                     int flags, int argc, const char **argv)
{
    int retval, rc;
    const char *user = NULL;
    const char *password = NULL;
    char otp[MAX_TOKEN_ID_LEN + TOKEN_OTP_LEN + 1] = { 0 };
    char otp_id[MAX_TOKEN_ID_LEN + 1] = { 0 };
    int password_len = 0;
    int skip_bytes = 0;
    int valid_token = 0;
    struct pam_conv *conv;
    struct pam_message *pmsg[1], msg[1];
    struct pam_response *resp;
    int nargs = 1;
    ykclient_t *ykc = NULL;
    struct cfg cfg_st;
    struct cfg *cfg = &cfg_st; /* for DBG macro */

    parse_cfg (flags, argc, argv, cfg);

    retval = pam_get_user (pamh, &user, NULL);
    if (retval != PAM_SUCCESS)
    {
        DBG (("get user returned error: %s", pam_strerror (pamh, retval)));
        goto done;
    }
    DBG (("get user returned: %s", user));

    if (cfg->mode == CHRESP) {
#if HAVE_LIBYKPERS_1
        return do_challenge_response(pamh, cfg, user);
#else
        DBG (("no support for challenge/response"));
        retval = PAM_AUTH_ERR;
        goto done;
#endif
    }

    if (cfg->try_first_pass || cfg->use_first_pass)
    {
        retval = pam_get_item (pamh, PAM_AUTHTOK, (const void **) &password);
        if (retval != PAM_SUCCESS)
        {
            DBG (("get password returned error: %s",
                  pam_strerror (pamh, retval)));
            goto done;
        }
        DBG (("get password returned: %s", password));
    }

    if (cfg->use_first_pass && password == NULL)
    {
        DBG (("use_first_pass set and no password, giving up"));
        retval = PAM_AUTH_ERR;
        goto done;
    }

    rc = ykclient_init (&ykc);
    if (rc != YKCLIENT_OK)
    {
        DBG (("ykclient_init() failed (%d): %s", rc, ykclient_strerror (rc)));
        retval = PAM_AUTHINFO_UNAVAIL;
        goto done;
    }

    rc = ykclient_set_client_b64 (ykc, cfg->client_id, cfg->client_key);
    if (rc != YKCLIENT_OK)
    {
        DBG (("ykclient_set_client_b64() failed (%d): %s",
              rc, ykclient_strerror (rc)));
        retval = PAM_AUTHINFO_UNAVAIL;
        goto done;
    }

    if (cfg->capath)
        ykclient_set_ca_path (ykc, cfg->capath);

    if (cfg->url)
        ykclient_set_url_template (ykc, cfg->url);

    if (password == NULL)
    {
        retval = pam_get_item (pamh, PAM_CONV, (const void **) &conv);
        if (retval != PAM_SUCCESS)
        {
            DBG (("get conv returned error: %s", pam_strerror (pamh, retval)));
            goto done;
        }

        pmsg[0] = &msg[0];
        {
            const char *query_template = "Yubikey for `%s': ";
            size_t len = strlen (query_template) + strlen (user);
            size_t wrote;

            msg[0].msg = malloc (len);
            if (!msg[0].msg)
            {
                retval = PAM_BUF_ERR;
                goto done;
            }

            wrote = snprintf ((char *) msg[0].msg, len, query_template, user);
            if (wrote < 0 || wrote >= len)
            {
                retval = PAM_BUF_ERR;
                goto done;
            }
        }
        msg[0].msg_style = cfg->verbose_otp ? PAM_PROMPT_ECHO_ON : PAM_PROMPT_ECHO_OFF;
        resp = NULL;

        retval = conv->conv (nargs, (const struct pam_message **) pmsg,
                             &resp, conv->appdata_ptr);

        free ((char *) msg[0].msg);

        if (retval != PAM_SUCCESS)
        {
            DBG (("conv returned error: %s", pam_strerror (pamh, retval)));
            goto done;
        }

        if (resp->resp == NULL)
        {
            DBG (("conv returned NULL passwd?"));
            goto done;
        }

        DBG (("conv returned %i bytes", strlen(resp->resp)));

        password = resp->resp;
    }

    password_len = strlen (password);
    if (password_len < (cfg->token_id_length + TOKEN_OTP_LEN))
    {
        DBG (("OTP too short to be considered : %i < %i", password_len, (cfg->token_id_length + TOKEN_OTP_LEN)));
        retval = PAM_AUTH_ERR;
        goto done;
    }

    /* In case the input was systempassword+YubiKeyOTP, we want to skip over
       "systempassword" when copying the token_id and OTP to separate buffers */
    skip_bytes = password_len - (cfg->token_id_length + TOKEN_OTP_LEN);

    DBG (("Skipping first %i bytes. Length is %i, token_id set to %i and token OTP always %i.",
          skip_bytes, password_len, cfg->token_id_length, TOKEN_OTP_LEN));

    /* Copy full YubiKey output (public ID + OTP) into otp */
    strncpy (otp, password + skip_bytes, sizeof (otp) - 1);
    /* Copy only public ID into otp_id. Destination buffer is zeroed. */
    strncpy (otp_id, password + skip_bytes, cfg->token_id_length);

    DBG (("OTP: %s ID: %s ", otp, otp_id));

    /* user entered their system password followed by generated OTP? */
    if (password_len > TOKEN_OTP_LEN + cfg->token_id_length)
    {
        char *onlypasswd = strdup (password);

        onlypasswd[password_len - (TOKEN_OTP_LEN + cfg->token_id_length)] = '\0';

        DBG (("Extracted a probable system password entered before the OTP - "
              "setting item PAM_AUTHTOK"));

        retval = pam_set_item (pamh, PAM_AUTHTOK, onlypasswd);
        free (onlypasswd);
        if (retval != PAM_SUCCESS)
        {
            DBG (("set_item returned error: %s", pam_strerror (pamh, retval)));
            goto done;
        }
    }
    else
        password = NULL;

    rc = ykclient_request (ykc, otp);

    DBG (("ykclient return value (%d): %s", rc,
          ykclient_strerror (rc)));

    switch (rc)
    {
    case YKCLIENT_OK:
        break;

    case YKCLIENT_BAD_OTP:
    case YKCLIENT_REPLAYED_OTP:
        retval = PAM_AUTH_ERR;
        goto done;

    default:
        retval = PAM_AUTHINFO_UNAVAIL;
        goto done;
    }

    /* authorize the user with supplied token id */
    if (cfg->ldapserver != NULL || cfg->ldap_uri != NULL)
        valid_token = authorize_user_token_ldap (cfg, user, otp_id);
    else
        valid_token = authorize_user_token (cfg, user, otp_id);

    if (valid_token == 0)
    {
        DBG (("Yubikey not authorized to login as user"));
        retval = PAM_AUTHINFO_UNAVAIL;
        goto done;
    }

    retval = PAM_SUCCESS;

done:
    if (ykc)
        ykclient_done (&ykc);
    if (cfg->alwaysok && retval != PAM_SUCCESS)
    {
        DBG (("alwaysok needed (otherwise return with %d)", retval));
        retval = PAM_SUCCESS;
    }
    DBG (("done. [%s]", pam_strerror (pamh, retval)));
    pam_set_data (pamh, "yubico_setcred_return", (void*) (intptr_t) retval, NULL);

    return retval;
}
Example #17
0
int
od_record_create(pam_handle_t *pamh, ODRecordRef *record, CFStringRef cfUser)
{
	int retval = PAM_SERVICE_ERR;
	const int attr_num = 5;

	ODNodeRef cfNode = NULL;
	CFErrorRef cferror = NULL;
	CFArrayRef attrs = NULL;
	CFTypeRef cfVals[attr_num];

	if (NULL == record || NULL == cfUser) {
		openpam_log(PAM_LOG_DEBUG, "NULL argument passed");
		retval = PAM_SERVICE_ERR;
		goto cleanup;
	}

#ifdef OPENDIRECTORY_CACHE
#define CFRECORDNAME_CACHE "CFRecordName"
#define CFRECORDNAME_NAME CFSTR("name")
#define CFRECORDNAME_RECORD CFSTR("record")

	CFDictionaryRef cfdict;
	CFStringRef cachedUser;

	if (pam_get_data(pamh, CFRECORDNAME_CACHE, (void *)&cfdict) == PAM_SUCCESS &&
	    (CFGetTypeID(cfdict) == CFDictionaryGetTypeID()) &&
	    (cachedUser = CFDictionaryGetValue(cfdict, CFRECORDNAME_NAME)) != NULL &&
	    CFGetTypeID(cachedUser) == CFStringGetTypeID() &&
	    CFStringCompare(cfUser, cachedUser, 0) == kCFCompareEqualTo &&
	    (*record = (ODRecordRef)CFDictionaryGetValue(cfdict, CFRECORDNAME_RECORD)) != NULL)
	{
		CFRetain(*record);
		return PAM_SUCCESS;
	}
#endif /* OPENDIRECTORY_CACHE */

	int current_iterations = 0;

	cfNode = ODNodeCreateWithNodeType(kCFAllocatorDefault,
					  kODSessionDefault,
					  eDSAuthenticationSearchNodeName,
					  &cferror);
	if (NULL == cfNode || NULL != cferror) {
		openpam_log(PAM_LOG_ERROR, "ODNodeCreateWithNodeType failed.");
		retval = PAM_SERVICE_ERR;
		goto cleanup;
	}

	cfVals[0] = kODAttributeTypeAuthenticationAuthority;
	cfVals[1] = kODAttributeTypeHomeDirectory;
	cfVals[2] = kODAttributeTypeNFSHomeDirectory;
	cfVals[3] = kODAttributeTypeUserShell;
	cfVals[4] = kODAttributeTypeUniqueID;
	attrs = CFArrayCreate(kCFAllocatorDefault, cfVals, (CFIndex)attr_num, &kCFTypeArrayCallBacks);
	if (NULL == attrs) {
		openpam_log(PAM_LOG_DEBUG, "CFArrayCreate() failed");
		retval = PAM_BUF_ERR;
		goto cleanup;
	}

	retval = PAM_SERVICE_ERR;
	while (current_iterations <= kMaxIterationCount) {
		CFIndex unreachable_count = 0;
		CFArrayRef unreachable_nodes = ODNodeCopyUnreachableSubnodeNames(cfNode, NULL);
		if (unreachable_nodes) {
			unreachable_count = CFArrayGetCount(unreachable_nodes);
			CFRelease(unreachable_nodes);
			openpam_log(PAM_LOG_DEBUG, "%lu OD nodes unreachable.", unreachable_count);
		}

		*record = ODNodeCopyRecord(cfNode, kODRecordTypeUsers, cfUser, attrs, &cferror);
		if (*record)
			break;
		if (0 == unreachable_count)
			break;

		openpam_log(PAM_LOG_DEBUG, "Waiting %d seconds for nodes to become reachable", kWaitSeconds);
		sleep(kWaitSeconds);
		++current_iterations;
	}

	if (*record) {
#ifdef OPENDIRECTORY_CACHE
		const void *keys[] = { CFRECORDNAME_NAME, CFRECORDNAME_RECORD };
		const void *values[] = { cfUser, *record };
		CFDictionaryRef dict;
		
		dict = CFDictionaryCreate(NULL, keys, values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
		if (dict)
			pam_set_data(pamh, CFRECORDNAME_CACHE, (void *)dict, cleanup_cache);
#endif /* OPENDIRECTORY_CACHE */
		retval = PAM_SUCCESS;
	} else {
		retval = PAM_USER_UNKNOWN;
	}

	if (current_iterations > 0) {
		char *wt = NULL, *found = NULL;
		int retval2;

		if (*record)
			found = "failure";
		else
			found = "success";

		retval2 = asprintf(&wt, "%d", kWaitSeconds * current_iterations);
		if (-1 == retval2) {
			openpam_log(PAM_LOG_DEBUG, "Failed to convert current wait time to string.");
			retval = PAM_BUF_ERR;
			goto cleanup;
		}


		aslmsg m = asl_new(ASL_TYPE_MSG);
		asl_set(m, "com.apple.message.domain", "com.apple.pam_modules.odAvailableWaitTime" );
		asl_set(m, "com.apple.message.signature", "wait_time");
		asl_set(m, "com.apple.message.value", wt);
		asl_set(m, "com.apple.message.result", found);
		asl_log(NULL, m, ASL_LEVEL_NOTICE, "OD nodes online delay: %ss. User record lookup: %s.", wt, found);
		asl_free(m);
		free(wt);
	}

cleanup:
	if (NULL != attrs) {
		CFRelease(attrs);
	}

	if (NULL != cferror) {
		CFRelease(cferror);
	}

	if (NULL != cfNode) {
		CFRelease(cfNode);
	}

	if (PAM_SUCCESS != retval) {
		openpam_log(PAM_LOG_ERROR, "failed: %d", retval);
		if (NULL != *record) {
			CFRelease(*record);
			*record = NULL;
		}
	}

	return retval;
}
Example #18
0
PAM_EXTERN int pam_sm_authenticate(pam_handle_t * pamh,
                                   int flags, int argc, const char **argv)
{

    const char *user = NULL, *passwd = NULL;
    struct passwd *pwd;
    int rval, status;
    pid_t pid;


    // For checking mount paths: (mount from + target)
    char path[PATH_MAX];
    char targetpath[PATH_MAX];
    char encfs_options[USERNAME_MAX];
    char fuse_options[USERNAME_MAX];
    char *targetpath_store;

    strcpy(default_encfs_options, "");
    strcpy(default_fuse_options, "");

    // For execing:
    char *arg[USERNAME_MAX];
    int arg_pos = 0;
    int i;
    int inpipe[2], outpipe[2];

    rval = pam_get_user(pamh, &user, NULL);
    if ((rval != PAM_SUCCESS) || (!user))
    {
        _pam_log(LOG_ERR, "can't get username: %s", pam_strerror(pamh, rval));
        return PAM_AUTH_ERR;
    }

    rval = pam_get_item(pamh, PAM_AUTHTOK, (const void **) (void *) &passwd);
    if (rval != PAM_SUCCESS)
    {
        _pam_log(LOG_ERR, "Could not retrieve user's password");
        return PAM_AUTH_ERR;
    }

    if (!passwd)
    {
        rval = _set_auth_tok(pamh, flags, argc, argv);
        if (rval != PAM_SUCCESS)
        {
            return rval;
        }
        rval =
            pam_get_item(pamh, PAM_AUTHTOK, (const void **) (void *) &passwd);
        if (rval != PAM_SUCCESS || passwd == NULL)
        {
            _pam_log(LOG_ERR, "Could not retrieve user's password");
            return PAM_AUTH_ERR;
        }
    }
    if ((pwd = getpwnam(user)) == NULL)
    {
        _pam_log(LOG_ERR, "Could not getpwnam");
        return PAM_AUTH_ERR;
    }

    // Read configfile  
    if (!readconfig
        (pwd, pamh, pwd->pw_name, path, targetpath, encfs_options,
         fuse_options))
    {
        // DEBUG _pam_log(LOG_ERR,"No entry for user found in log");
        return PAM_IGNORE;
    }
    //DEBUG _pam_log(LOG_ERR,"Username : %s, Encpath : %s, Targetmount : %s",pwd->pw_name,path,targetpath);

    //Store targetpath
    targetpath_store = strdup(targetpath);
    if ((i =
         pam_set_data(pamh, "encfs_targetpath", targetpath_store,
                      targetpath_cleanup)) != PAM_SUCCESS)
    {
        _pam_log(LOG_ERR, "Storing targetpath FAIL");
        free(targetpath_store);
        return i;
    }

    // Check if we're mounted already.
    if (checkmnt(targetpath))
    {
        //DEBUG _pam_log(LOG_ERR,"Already mounted");
        return PAM_IGNORE;
    }



    /*  _pam_log(LOG_ERR,"Config output for %s:",user);
       _pam_log(LOG_ERR,"  path       : %s",path);
       _pam_log(LOG_ERR,"  targetpath : %s",targetpath);
       _pam_log(LOG_ERR,"  encfs      : %s %s",default_encfs_options,encfs_options);
       _pam_log(LOG_ERR,"  fuse       : %s %s",default_fuse_options,fuse_options); */


    arg_pos += buildCmd(arg, arg_pos, "encfs");
    arg_pos += buildCmd(arg, arg_pos, "-S");
    arg_pos += buildCmd(arg, arg_pos, default_encfs_options);
    arg_pos += buildCmd(arg, arg_pos, encfs_options);
    arg_pos += buildCmd(arg, arg_pos, path);
    arg_pos += buildCmd(arg, arg_pos, targetpath);

    if (strlen(default_fuse_options) > 0 && strlen(fuse_options) > 0)
        strcat(fuse_options, ",");

    strcat(fuse_options,default_fuse_options);
    if (strlen(fuse_options) > 0) {
        arg_pos += buildCmd(arg, arg_pos, "--");
        arg_pos += buildCmd(arg, arg_pos, "-o");
        arg_pos += buildCmd(arg, arg_pos, fuse_options);
    }
    arg[arg_pos] = NULL;

    /*  printf("Arguments : ");
       for (i = 0; i < arg_pos+1;i++) {
       _pam_log(LOG_ERR,"Data : %s",arg[i]);
       }

       _pam_log(LOG_ERR,"Number of arguments : %d",arg_pos); */


    /*  arg[0] = cmd;
       arg[1] = params;
       //  arg[2] = params2;
       arg[2] = params3;
       arg[3] = path;
       arg[4] = targetpath;
       arg[5] = fuseparams;
       arg[6] = fuseparams2;
       arg[7] = NULL; */



    if (pipe(inpipe) || pipe(outpipe))
    {
        _pam_log(LOG_ERR, "Failed to create pipe");
        return PAM_IGNORE;
    }

    // Execute 
    switch (pid = fork())
    {
        case -1:
            _pam_log(LOG_ERR, "Fork failed");
            return PAM_SERVICE_ERR;
        case 0:

            if (drop_permissions == 1)
                if ((initgroups(pwd->pw_name, pwd->pw_gid) == -1)
                    || (setgid(pwd->pw_gid) == -1)
                    || (setuid(pwd->pw_uid) == -1))
                {
                    _pam_log(LOG_ERR, "Dropping permissions failed");
                    return PAM_SERVICE_ERR;
                }
            close(outpipe[WRITE_END]);
            dup2(outpipe[READ_END], fileno(stdin));
            close(outpipe[READ_END]);

            close(inpipe[READ_END]);
            dup2(inpipe[WRITE_END], fileno(stdout));
            close(inpipe[WRITE_END]);

            // For some reason the current directory has to be set to targetpath (or path?) before exec'ing encfs through gdm
            chdir(targetpath);
            execvp("encfs", arg);
            char errstr[128];

            snprintf(errstr, 127, "%d - %s", errno, strerror(errno));
            _pam_log(LOG_ERR, "Exec failed - %s", errstr);
            exit(127);
    }

    int len;


    close(inpipe[WRITE_END]);
    close(outpipe[READ_END]);




    if (waitpid(pid, &status, WNOHANG) == 0)
    {
        len = write(outpipe[WRITE_END], passwd, (size_t) strlen(passwd));
        if ((len != (size_t) strlen(passwd))
            || (write(outpipe[WRITE_END], "\n", 1) != 1))
            _pam_log(LOG_ERR, "Did not send password to pipe (%d sent)", len);
        close(outpipe[WRITE_END]);
    }


    if (waitpid_timeout(pid, &status, 0))
    {
        _pam_log(LOG_ERR, "Timed out waiting for encfs, killing\n");
        kill(pid, SIGKILL);
    }

    int exitstatus = WEXITSTATUS(status);
    char buff[512];

    len = read(inpipe[READ_END], &buff, 511);
    close(inpipe[READ_END]);
    buff[len] = 0;
    if (!checkmnt(targetpath) && (len > 0 || exitstatus > 0))
    {
        _pam_log(LOG_ERR, "exitcode : %d, errorstring : %s", exitstatus,
                 buff);
        return PAM_AUTH_ERR;
    }
    else
    {
        return PAM_IGNORE;
    }
    return PAM_AUTH_ERR;
}
Example #19
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;
}
Example #20
0
DWORD
LsaPamGetContext(
    pam_handle_t* pamh, 
    int           flags, 
    int           argc, 
    const char**  argv,
    PPAMCONTEXT*  ppPamContext
    )
{
    DWORD       dwError = 0;
    PPAMCONTEXT pPamContext = NULL;
    BOOLEAN     bFreeContext = FALSE;
    int         iPamError = 0;
    
    LSA_LOG_PAM_DEBUG("LsaPamGetContext::begin");
    
    iPamError = pam_get_data(pamh, MODULE_NAME, (PAM_GET_DATA_TYPE)&pPamContext);
    dwError = LsaPamUnmapErrorCode(iPamError);
    if (dwError)
    {
        if (dwError == LsaPamUnmapErrorCode(PAM_NO_MODULE_DATA))
        {
                dwError = LwAllocateMemory(
                                sizeof(PAMCONTEXT),
                                (PVOID*)&pPamContext);
                BAIL_ON_LSA_ERROR(dwError);

                bFreeContext = TRUE;

                iPamError = pam_set_data(
                                pamh,
                                MODULE_NAME,
                                (PVOID)pPamContext,
                                &LsaPamCleanupContext);
                dwError = LsaPamUnmapErrorCode(iPamError);
                BAIL_ON_LSA_ERROR(dwError);

                bFreeContext = FALSE;
        }
        else
        {
                BAIL_ON_LSA_ERROR(dwError);
        }
    }

    dwError = LsaPamGetLoginId(pamh, pPamContext, NULL, FALSE);
    BAIL_ON_LSA_ERROR(dwError);
    
    dwError = LsaPamGetOptions(
                    pamh,
                    flags,
                    argc,
                    argv,
                    &pPamContext->pamOptions);
    BAIL_ON_LSA_ERROR(dwError);
    
    *ppPamContext = pPamContext;
    
cleanup:

    LSA_LOG_PAM_DEBUG("LsaPamGetContext::end");

    return dwError;

error:

    if (pPamContext && bFreeContext) {
       LsaPamFreeContext(pPamContext);
    }

    *ppPamContext = NULL;
    
    LSA_LOG_PAM_ERROR("LsaPamGetContext failed [error code: %u]", dwError);

    goto cleanup;
}
Example #21
0
int
pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
{
    int status, confFlags = 0;
    char hostNameBufBuf[5 + MAXHOSTNAMELEN + 1] = "host@";
    int isConvPasswordBuf = 0;

    OM_uint32 major, minor;
    gss_buffer_desc userNameBuf = GSS_C_EMPTY_BUFFER;
    gss_buffer_desc hostNameBuf = GSS_C_EMPTY_BUFFER;
    gss_buffer_desc passwordBuf = GSS_C_EMPTY_BUFFER;
    gss_name_t userName = GSS_C_NO_NAME;
    gss_name_t hostName = GSS_C_NO_NAME;
    gss_cred_id_t initiatorCred = GSS_C_NO_CREDENTIAL;
    gss_cred_id_t acceptorCred = GSS_C_NO_CREDENTIAL;
    gss_OID mech = &gss_spnego_mechanism_oid_desc;
    gss_OID_set_desc mechOids;

    confFlags = readConfFlags(argc, argv);

    status = readConfMechOid(argc, argv, &mech);
    BAIL_ON_PAM_ERROR(status);

    if (flags & PAM_DISALLOW_NULL_AUTHTOK)
        confFlags &= ~(FLAG_NULLOK);

    status = pam_get_user(pamh, (void *)&userNameBuf.value, NULL);
    BAIL_ON_PAM_ERROR(status);

    userNameBuf.length = strlen((char *)userNameBuf.value);

    major = gss_import_name(&minor, &userNameBuf, GSS_C_NT_USER_NAME, &userName);
    BAIL_ON_GSS_ERROR(major, minor);

    if (gethostname(&hostNameBufBuf[5], MAXHOSTNAMELEN) != 0) {
        status = PAM_SYSTEM_ERR;
        goto cleanup;
    }

    hostNameBuf.length = strlen(hostNameBufBuf);
    hostNameBuf.value = hostNameBufBuf;

    major = gss_import_name(&minor, &hostNameBuf, GSS_C_NT_HOSTBASED_SERVICE, &hostName);
    BAIL_ON_GSS_ERROR(major, minor);

    mechOids.count = 1;
    mechOids.elements = mech;

    major = gss_acquire_cred(&minor, hostName, GSS_C_INDEFINITE, &mechOids,
                             GSS_C_ACCEPT, &acceptorCred, NULL, NULL);
    BAIL_ON_GSS_ERROR(major, minor);

    status = PAM_AUTHINFO_UNAVAIL;

    if (confFlags & (FLAG_USE_FIRST_PASS | FLAG_TRY_FIRST_PASS)) {
        status = pam_get_item(pamh, PAM_AUTHTOK, (void *)&passwordBuf.value);
        BAIL_ON_PAM_ERROR(status);

        if (passwordBuf.value != NULL)
            passwordBuf.length = strlen((char *)passwordBuf.value);

        status = pamGssAcquireCred(pamh, confFlags, userName, &passwordBuf,
                                   mech, &initiatorCred);
        if (status == PAM_SUCCESS)
            status = pamGssInitAcceptSecContext(pamh, confFlags, initiatorCred,
                                                acceptorCred, hostName, mech);
        if (confFlags & FLAG_USE_FIRST_PASS)
            BAIL_ON_PAM_ERROR(status);
    }

    if (status != PAM_SUCCESS) {
        isConvPasswordBuf = 1;

        if (flags & PAM_SILENT)
            goto cleanup;

        status = pamGssGetAuthTok(pamh, confFlags, &passwordBuf);
        BAIL_ON_PAM_ERROR(status);

        gss_release_cred(&minor, &initiatorCred);

        status = pamGssAcquireCred(pamh, confFlags, userName, &passwordBuf,
                                   mech, &initiatorCred);
        if (status == PAM_SUCCESS)
            status = pamGssInitAcceptSecContext(pamh, confFlags, initiatorCred,
                                                acceptorCred, hostName, mech);
        BAIL_ON_PAM_ERROR(status);
    }

    status = pam_set_data(pamh, GSS_CRED_DATA, initiatorCred, pamGssCleanupCred);
    BAIL_ON_PAM_ERROR(status);

    initiatorCred = GSS_C_NO_CREDENTIAL;

cleanup:
    gss_release_name(&minor, &userName);
    gss_release_name(&minor, &hostName);
    gss_release_cred(&minor, &initiatorCred);
    gss_release_cred(&minor, &acceptorCred);
#ifdef __APPLE__
    if (mech != &gss_spnego_mechanism_oid_desc)
        gss_release_oid(&minor, &mech);
#endif
    if (isConvPasswordBuf) {
        memset((char *)passwordBuf.value, 0, passwordBuf.length);
        free(passwordBuf.value);
    }

    return status;
}
Example #22
0
PAM_EXTERN int
pam_sm_authenticate(pam_handle_t *pamh, int flags,
                    int argc, const char *argv[])
{
    const char *user;
    char *password, *crypt_password, *cached_password;
    int pam_err, timestamp;

    /* identify user */
    if ((pam_err = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS)
        return (pam_err);
    if (getpwnam(user) == NULL)
        return (PAM_USER_UNKNOWN);

    /* get password */
    pam_err = pam_get_authtok(pamh, PAM_AUTHTOK,
                              (const char **)&password, NULL);
    if (pam_err == PAM_CONV_ERR)
        return (pam_err);
    if (pam_err != PAM_SUCCESS)
        return (PAM_AUTH_ERR);

    cached_password = NULL;
    if (!read_ticket(user, &timestamp, &cached_password)) {
        pam_err = PAM_AUTH_ERR;
        if (crypt_set_format("sha512"))
            crypt_password = crypt(password, gen_salt());
        else
            crypt_password = NULL;
        goto done;
    }

    if ((crypt_password = crypt(password, cached_password)) != NULL &&
            strcmp(crypt_password, cached_password) == 0) {
        struct timespec now;
        clock_gettime(CLOCK_MONOTONIC, &now);
        /* TODO: timeout should be an argument! */
        if ((int)now.tv_sec > timestamp + TIMEOUT) {
            openpam_log(PAM_LOG_DEBUG,
                        "expired auth ticket: %d > %d",
                        (int)now.tv_sec, timestamp + TIMEOUT);
            pam_err = PAM_AUTH_ERR;
        } else {
            pam_err = PAM_SUCCESS;
        }
    } else {
        openpam_log(PAM_LOG_DEBUG, "passwords do not match");
        pam_err = PAM_AUTH_ERR;
    }
done:
    if (crypt_password != NULL) {
        char *cp;
        size_t len;
        len = strlen(crypt_password) + 1;
        if ((cp = calloc(len, sizeof(char))) != NULL &&
                strlcpy(cp, crypt_password, len) < len)
            pam_set_data(pamh, "pam_auth_ticket", cp, cleanup);
    }

    free(cached_password);
    return (pam_err);
}
Example #23
0
static int
pamGssInitAcceptSecContext(pam_handle_t *pamh,
                           int confFlags,
                           gss_cred_id_t cred,
                           gss_cred_id_t acceptorCred,
                           gss_name_t hostName,
                           gss_OID mech)
{
    int status;
    OM_uint32 major, minor;
    gss_buffer_desc initiatorToken = GSS_C_EMPTY_BUFFER;
    gss_buffer_desc acceptorToken = GSS_C_EMPTY_BUFFER;
    gss_ctx_id_t initiatorContext = GSS_C_NO_CONTEXT;
    gss_ctx_id_t acceptorContext = GSS_C_NO_CONTEXT;
    gss_buffer_desc canonUserNameBuf = GSS_C_EMPTY_BUFFER;
    gss_name_t canonUserName = GSS_C_NO_NAME;
    gss_OID canonMech = GSS_C_NO_OID;
    OM_uint32 gssFlags;

    do {
        major = gss_init_sec_context(&minor, cred, &initiatorContext,
                                     hostName, mech, GSS_C_MUTUAL_FLAG,
                                     GSS_C_INDEFINITE, GSS_C_NO_CHANNEL_BINDINGS,
                                     &acceptorToken, NULL, &initiatorToken, &gssFlags, NULL);
        gss_release_buffer(&minor, &acceptorToken);

#ifdef GSS_S_PROMPTING_NEEDED
        if (major == GSS_S_PROMPTING_NEEDED) {
            status = PAM_CRED_INSUFFICIENT;
            goto cleanup;
        }
#endif

        BAIL_ON_GSS_ERROR(major, minor);

        if (initiatorToken.length != 0) {
            major = gss_accept_sec_context(&minor, &acceptorContext, acceptorCred,
                                           &initiatorToken, GSS_C_NO_CHANNEL_BINDINGS,
                                           &canonUserName, &canonMech, &acceptorToken,
                                           NULL, NULL, NULL);
            gss_release_buffer(&minor, &initiatorToken);
        }

        BAIL_ON_GSS_ERROR(major, minor);
    } while (major == GSS_S_CONTINUE_NEEDED);

    BAIL_ON_GSS_ERROR(major, minor);

    if ((gssFlags & GSS_C_MUTUAL_FLAG) == 0) {
        status = PAM_PERM_DENIED;
        goto cleanup;
    }

#ifndef __APPLE__
    major = gss_localname(&minor, canonUserName, GSS_C_NO_OID, &canonUserNameBuf);
    if (major == GSS_S_COMPLETE) {
        status = pam_set_item(pamh, PAM_USER, canonUserNameBuf.value);
        BAIL_ON_PAM_ERROR(status);
    } else if (major != GSS_S_UNAVAILABLE)
        goto cleanup;
#endif

    status = pam_set_data(pamh, GSS_NAME_DATA, canonUserName, pamGssCleanupName);
    BAIL_ON_PAM_ERROR(status);

    canonUserName = GSS_C_NO_NAME;

    status = pam_set_data(pamh, GSS_MECH_DATA, canonMech, pamGssCleanupMech);
    BAIL_ON_PAM_ERROR(status);

    canonMech = GSS_C_NO_OID;

    status = PAM_SUCCESS;

cleanup:
    gss_release_name(&minor, &canonUserName);
    gss_release_buffer(&minor, &initiatorToken);
    gss_release_buffer(&minor, &acceptorToken);
    gss_delete_sec_context(&minor, &initiatorContext, NULL);
    gss_delete_sec_context(&minor, &acceptorContext, NULL);
    gss_release_buffer(&minor, &canonUserNameBuf);

    if (IGNORE_ERR_P(status, confFlags))
        status = PAM_IGNORE;

    return status;
}
Example #24
0
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
{
    pam_syslog(pamh, LOG_INFO, "pam_sm_authenticate\n");
    if (get_env(pamh, "PAM_KWALLET_LOGIN") != NULL) {
        pam_syslog(pamh, LOG_INFO, "pam_kwallet: we were already executed");
        return PAM_SUCCESS;
    }

    parseArguments(argc, argv);

    int result;

    //Fetch the user, needed to get user information
    const char *username;
    result = pam_get_user(pamh, &username, NULL);
    if (result != PAM_SUCCESS) {
        pam_syslog(pamh, LOG_ERR, "pam_kwallet: Couldn't get username %s",
                   pam_strerror(pamh, result));
        return PAM_IGNORE;//Since we are not an essential module, just make pam ignore us
    }

    struct passwd *userInfo;
    userInfo = getpwnam(username);
    if (!userInfo) {
        pam_syslog(pamh, LOG_ERR, "pam_kwallet: Couldn't get user info (passwd) info");
        return PAM_IGNORE;
    }

    const char *password;
    result = pam_get_item(pamh, PAM_AUTHTOK, (const void**)&password);

    if (result != PAM_SUCCESS) {
        pam_syslog(pamh, LOG_ERR, "pam_kwallet: Couldn't get password %s",
                   pam_strerror(pamh, result));
        return PAM_IGNORE;
    }

    if (!password) {
        pam_syslog(pamh, LOG_NOTICE, "pam_kwallet: Couldn't get password (it is empty)");
        //Asking for the password ourselves
        result = prompt_for_password(pamh);
        if (result != PAM_SUCCESS) {
            pam_syslog(pamh, LOG_ERR, "pam_kwallet: Prompt for password failed %s",
                pam_strerror(pamh, result)
            );
            return PAM_IGNORE;
        }
    }

    //even though we just set it, better check to be 100% sure
    result = pam_get_item(pamh, PAM_AUTHTOK, (const void**)&password);
    if (result != PAM_SUCCESS || !password) {
        pam_syslog(pamh, LOG_ERR, "pam_kwallet: Password is not there even though we set it %s",
                   pam_strerror(pamh, result));
        return PAM_IGNORE;
    }

    char *key = malloc(sizeof(char) * KWALLET_PAM_KEYSIZE);
    if (kwallet_hash(password, userInfo, key) != 0) {
        pam_syslog(pamh, LOG_ERR, "pam_kwallet: Fail into creating the hash");
        return PAM_IGNORE;
    }

    result = pam_set_data(pamh, "kwallet_key", key, NULL);
    if (result != PAM_SUCCESS) {
        pam_syslog(pamh, LOG_ERR, "pam_kwallet: Impossible to store the hashed password: %s"
            , pam_strerror(pamh, result));
        return PAM_IGNORE;
    }

    //if sm_open_session has already been called (but we did not have password), call it now
    const char *session_bit;
    result = pam_get_data(pamh, "sm_open_session", (const void **)&session_bit);
    if (result == PAM_SUCCESS) {
        pam_syslog(pamh, LOG_ERR, "pam_kwallet: open_session was called before us, calling it now");
        return pam_sm_open_session(pamh, flags, argc, argv);
    }

    //TODO unlock kwallet that is already executed
    return PAM_SUCCESS;
}
struct passwd *
pam_modutil_getpwuid(pam_handle_t *pamh, uid_t uid)
{
#ifdef HAVE_GETPWUID_R

    void *buffer=NULL;
    size_t length = PWD_INITIAL_LENGTH;

    do {
	int status;
	void *new_buffer;
	struct passwd *result = NULL;

	new_buffer = realloc(buffer, sizeof(struct passwd) + length);
	if (new_buffer == NULL) {

	    D(("out of memory"));

	    /* no memory for the user - so delete the memory */
	    if (buffer) {
		free(buffer);
	    }
	    return NULL;
	}
	buffer = new_buffer;

	/* make the re-entrant call to get the pwd structure */
        errno = 0;
	status = getpwuid_r(uid, buffer,
			    sizeof(struct passwd) + (char *) buffer,
			    length, &result);
	if (!status && (result == buffer)) {
	    char *data_name;
	    const void *ignore;
	    int i;

	    data_name = malloc(strlen("_pammodutil_getpwuid") + 1 +
			       longlen((long) uid) + 1 + intlen(INT_MAX) + 1);
	    if ((pamh != NULL) && (data_name == NULL)) {
	        D(("was unable to register the data item [%s]",
	           pam_strerror(pamh, status)));
		free(buffer);
		return NULL;
	    }

	    if (pamh != NULL) {
	        for (i = 0; i < INT_MAX; i++) {
	            sprintf(data_name, "_pammodutil_getpwuid_%ld_%d",
			    (long) uid, i);
		    status = PAM_NO_MODULE_DATA;
	            if (pam_get_data(pamh, data_name, &ignore) != PAM_SUCCESS) {
		        status = pam_set_data(pamh, data_name,
					      result, pam_modutil_cleanup);
		    }
		    if (status == PAM_SUCCESS) {
		        break;
		    }
		}
	    } else {
	        status = PAM_SUCCESS;
	    }

	    free(data_name);

	    if (status == PAM_SUCCESS) {
		D(("success"));
		return result;
	    }

	    D(("was unable to register the data item [%s]",
	       pam_strerror(pamh, status)));

	    free(buffer);
	    return NULL;

	} else if (errno != ERANGE && errno != EINTR) {
                /* no sense in repeating the call */
                break;
        }

	length <<= PWD_LENGTH_SHIFT;

    } while (length < PWD_ABSURD_PWD_LENGTH);

    D(("pwd structure took %u bytes or so of memory",
       length+sizeof(struct passwd)));

    free(buffer);
    return NULL;

#else /* ie. ifndef HAVE_GETPWUID_R */

    /*
     * Sorry, there does not appear to be a reentrant version of
     * getpwuid(). So, we use the standard libc function.
     */

    return getpwuid(uid);

#endif /* def HAVE_GETPWUID_R */
}
Example #26
0
PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) {
    return pam_set_data(pamh, DATA_NAME, NULL, cleanup);
}
Example #27
0
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) {
    abl_args *args;
    abl_info *info;
    abl_context *context;
    DB *utdb;
    DB *usdb;
    DB *htdb;
    DB *hsdb;
    int err = PAM_SUCCESS;

    /*log_debug(args, "pam_sm_authenticate(), flags=%08x", flags);*/


    if (args = malloc(sizeof(abl_args)), NULL == args) {
        return PAM_BUF_ERR;
    }
    if (info = malloc(sizeof(abl_info)), NULL == info) {
        return PAM_BUF_ERR;
    }
    if (context = malloc(sizeof(abl_context)), NULL == context) {
        return PAM_BUF_ERR;
    }

    memset(info,0,sizeof(abl_info));
    memset(context,0,sizeof(abl_context));


    if (err = config_parse_args(pamh, argc, argv, args), PAM_SUCCESS == err) {

        /* We now keep the database open from the beginning to avoid the cost
         * of opening them repeatedly. */

        err = dbopen(args, args->user_db, DB_TIME, &utdb);
        if (err) goto psa_fail;
        info->utdb = utdb;
        err = dbopen(args, args->user_db, DB_STATE, &usdb);
        if (err) goto psa_fail;
        info->usdb = usdb;
        err = dbopen(args, args->host_db, DB_TIME, &htdb);
        if (err) goto psa_fail;
        info->htdb = htdb;
        err = dbopen(args, args->host_db, DB_STATE, &hsdb);
        if (err) goto psa_fail;
        info->hsdb = hsdb;

        context->args = args;
        context->info = info;
        
        if (err = pam_set_data(pamh, DATA_NAME, context, cleanup), PAM_SUCCESS != err) {
            log_pam_error(args,err,"setting PAM data");
            goto psa_fail;
        }
        if (err = pam_get_item(args->pamh, PAM_USER, (const void **) &info->user), PAM_SUCCESS != err) {
            log_pam_error(args, err, "getting PAM_USER");
            goto psa_fail;
        }
        if (err = pam_get_item(args->pamh, PAM_SERVICE, (const void **) &info->service), PAM_SUCCESS != err) {
            log_pam_error(args, err, "getting PAM_SERVICE");
            goto psa_fail;
        }
        if (err = pam_get_item(args->pamh, PAM_RHOST, (const void **) &info->host), PAM_SUCCESS != err) {
            log_pam_error(args, err, "getting PAM_RHOST");
            goto psa_fail;
        }

        check_attempt(args, info);
        if (info->state == BLOCKED) {
            log_info("Blocking access from %s to service %s, user %s", info->host, info->service, info->user);
            return PAM_AUTH_ERR;
        }
        else {
            return PAM_SUCCESS;
        }
    } 

psa_fail:
    config_free(args);
    utdb->close(utdb,0);
    usdb->close(usdb,0);
    htdb->close(htdb,0);
    hsdb->close(hsdb,0);
    free(args);
    free(info);
    free(context);
    return err;
}
Example #28
0
int
main(int argc, char **argv)
{
	char hostname[MAXHOSTNAMELEN];
	struct passwd *pwd = NULL;
	int o, pam_err;
	uid_t uid;

	while ((o = getopt(argc, argv, "d:h:loy")) != -1)
		switch (o) {
		case 'd':
			yp_domain = optarg;
			break;
		case 'h':
			yp_host = optarg;
			break;
		case 'l':
		case 'o':
		case 'y':
			/* compatibility */
			break;
		default:
			usage();
		}

	argc -= optind;
	argv += optind;

	uid = getuid();

	switch (argc) {
	case 0:
		if ((pwd = getpwuid(uid)) == NULL)
			errx(1, "who are you?");
		break;
	case 1:
		if ((pwd = getpwnam(*argv)) == NULL)
			errx(1, "%s: no such user", *argv);
		break;
	default:
		usage();
	}

	if (uid != 0 && uid != pwd->pw_uid)
		errx(1, "permission denied");

	/* check where the user's from */
	switch (pwd->pw_fields & _PWF_SOURCE) {
	case _PWF_FILES:
		fprintf(stderr, "Changing local password for %s\n",
		    pwd->pw_name);
		break;
	case _PWF_NIS:
		fprintf(stderr, "Changing NIS password for %s\n",
		    pwd->pw_name);
		break;
	default:
		fprintf(stderr, "Changing password for %s\n",
		    pwd->pw_name);
	}

#define pam_check(func) do { \
	if (pam_err != PAM_SUCCESS) { \
		if (pam_err == PAM_AUTH_ERR || pam_err == PAM_PERM_DENIED || \
		    pam_err == PAM_AUTHTOK_RECOVERY_ERR) \
			warnx("sorry"); \
		else \
			warnx("%s(): %s", func, pam_strerror(pamh, pam_err)); \
		goto end; \
	} \
} while (0)

	/* initialize PAM */
	pam_err = pam_start("passwd", pwd->pw_name, &pamc, &pamh);
	pam_check("pam_start");

	pam_err = pam_set_item(pamh, PAM_TTY, ttyname(STDERR_FILENO));
	pam_check("pam_set_item");
	gethostname(hostname, sizeof hostname);
	pam_err = pam_set_item(pamh, PAM_RHOST, hostname);
	pam_check("pam_set_item");
	pam_err = pam_set_item(pamh, PAM_RUSER, getlogin());
	pam_check("pam_set_item");

	/* set YP domain and host */
	pam_err = pam_set_data(pamh, "yp_domain", yp_domain, NULL);
	pam_check("pam_set_data");
	pam_err = pam_set_data(pamh, "yp_server", yp_host, NULL);
	pam_check("pam_set_data");

	/* set new password */
	pam_err = pam_chauthtok(pamh, 0);
	pam_check("pam_chauthtok");

 end:
	pam_end(pamh, pam_err);
	exit(pam_err == PAM_SUCCESS ? 0 : 1);
}
Example #29
0
extern int
pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc,
		    const char **argv)
{
    int retcode = PAM_SUCCESS;
    int errcode = PAM_SUCCESS;
    int code;
    int origmask;
    int logmask = LOG_UPTO(LOG_INFO);
    int nowarn = 0;
    int use_first_pass = 0;
    int try_first_pass = 0;
    int ignore_uid = 0;
    uid_t ignore_uid_id = 0;
    char my_password_buf[256];
    char *cell_ptr = NULL;
    /*
     * these options are added to handle stupid apps, which won't call
     * pam_set_cred()
     */
    int refresh_token = 0;
    int set_token = 0;
    int dont_fork = 0;
    /* satisfy kdm 2.x
     */
    int use_klog = 0;
    int set_expires = 0;	/* This option is only used in pam_set_cred() */
    int got_authtok = 0;	/* got PAM_AUTHTOK upon entry */
    char *user = NULL, *password = NULL;
    afs_int32 password_expires = -1;
    int torch_password = 1;
    int i;
    struct pam_conv *pam_convp = NULL;
    int auth_ok;
    struct passwd unix_pwd, *upwd = NULL;
    char upwd_buf[2048];	/* size is a guess. */
    char *reason = NULL;
    pid_t cpid, rcpid;
    int status;
    struct sigaction newAction, origAction;


#ifndef AFS_SUN56_ENV
    openlog(pam_afs_ident, LOG_CONS | LOG_PID, LOG_AUTH);
#endif
    origmask = setlogmask(logmask);

    /*
     * Parse the user options.  Log an error for any unknown options.
     */
    for (i = 0; i < argc; i++) {
	if (strcasecmp(argv[i], "debug") == 0) {
	    logmask |= LOG_MASK(LOG_DEBUG);
	    (void)setlogmask(logmask);
	} else if (strcasecmp(argv[i], "nowarn") == 0) {
	    nowarn = 1;
	} else if (strcasecmp(argv[i], "use_first_pass") == 0) {
	    use_first_pass = 1;
	} else if (strcasecmp(argv[i], "try_first_pass") == 0) {
	    try_first_pass = 1;
	} else if (strcasecmp(argv[i], "ignore_root") == 0) {
	    ignore_uid = 1;
	    ignore_uid_id = 0;
	} else if (strcasecmp(argv[i], "ignore_uid") == 0) {
	    i++;
	    if (i == argc) {
		pam_afs_syslog(LOG_ERR, PAMAFS_IGNOREUID,
			       "ignore_uid missing argument");
		ignore_uid = 0;
	    } else {
		ignore_uid = 1;
		ignore_uid_id = (uid_t) strtol(argv[i], (char **)NULL, 10);
		if ((ignore_uid_id < 0) || (ignore_uid_id > IGNORE_MAX)) {
		    ignore_uid = 0;
		    pam_afs_syslog(LOG_ERR, PAMAFS_IGNOREUID, argv[i]);
		}
	    }
	} else if (strcasecmp(argv[i], "cell") == 0) {
	    i++;
	    if (i == argc) {
		pam_afs_syslog(LOG_ERR, PAMAFS_OTHERCELL,
			       "cell missing argument");
	    } else {
		cell_ptr = (char *)argv[i];
		pam_afs_syslog(LOG_INFO, PAMAFS_OTHERCELL, cell_ptr);
	    }
	} else if (strcasecmp(argv[i], "refresh_token") == 0) {
	    refresh_token = 1;
	} else if (strcasecmp(argv[i], "set_token") == 0) {
	    set_token = 1;
	} else if (strcasecmp(argv[i], "dont_fork") == 0) {
	    if (!use_klog)
		dont_fork = 1;
	    else
		pam_afs_syslog(LOG_ERR, PAMAFS_CONFLICTOPT, "dont_fork");
	} else if (strcasecmp(argv[i], "use_klog") == 0) {
	    if (!dont_fork)
		use_klog = 1;
	    else
		pam_afs_syslog(LOG_ERR, PAMAFS_CONFLICTOPT, "use_klog");
	} else if (strcasecmp(argv[i], "setenv_password_expires") == 0) {
	    set_expires = 1;
	} else {
	    pam_afs_syslog(LOG_ERR, PAMAFS_UNKNOWNOPT, argv[i]);
	}
    }

    /* Later we use try_first_pass to see if we can try again.    */
    /* If use_first_pass is true we don't want to ever try again, */
    /* so turn that flag off right now.                           */
    if (use_first_pass)
	try_first_pass = 0;

    if (logmask && LOG_MASK(LOG_DEBUG))
	pam_afs_syslog(LOG_DEBUG, PAMAFS_OPTIONS, nowarn, use_first_pass,
		       try_first_pass, ignore_uid, ignore_uid_id,
		       refresh_token, set_token, dont_fork, use_klog);

    /* Try to get the user-interaction info, if available. */
    errcode = pam_get_item(pamh, PAM_CONV, (const void **)&pam_convp);
    if (errcode != PAM_SUCCESS) {
	pam_afs_syslog(LOG_WARNING, PAMAFS_NO_USER_INT);
	pam_convp = NULL;
    }

    /* Who are we trying to authenticate here? */
    if ((errcode =
	 pam_get_user(pamh, (const char **)&user,
		      "login: "******"local" (or via nss, possibly nss_dce) pwent,
     * and its uid==0, and "ignore_root" was given in pam.conf,
     * ignore the user.
     */
    /* enhanced: use "ignore_uid <number>" to specify the largest uid
     * which should be ignored by this module
     */
#if	defined(AFS_HPUX_ENV) || defined(AFS_DARWIN100_ENV)
#if     defined(AFS_HPUX110_ENV) || defined(AFS_DARWIN100_ENV)
    i = getpwnam_r(user, &unix_pwd, upwd_buf, sizeof(upwd_buf), &upwd);
#else /* AFS_HPUX110_ENV */
    i = getpwnam_r(user, &unix_pwd, upwd_buf, sizeof(upwd_buf));
    if (i == 0)			/* getpwnam_r success */
	upwd = &unix_pwd;
#endif /* else AFS_HPUX110_ENV */
    if (ignore_uid && i == 0 && upwd->pw_uid <= ignore_uid_id) {
	pam_afs_syslog(LOG_INFO, PAMAFS_IGNORINGROOT, user);
	RET(PAM_AUTH_ERR);
    }
#else
#if     defined(AFS_LINUX20_ENV) || defined(AFS_FBSD_ENV) || defined(AFS_DFBSD_ENV) || defined(AFS_NBSD_ENV)
    upwd = getpwnam(user);
#elif   defined(_POSIX_PTHREAD_SEMANTICS) && defined(AFS_SUN5_ENV)
    getpwnam_r(user, &unix_pwd, upwd_buf, sizeof(upwd_buf), &upwd);
#else
    upwd = getpwnam_r(user, &unix_pwd, upwd_buf, sizeof(upwd_buf));
#endif
    if (ignore_uid && upwd != NULL && upwd->pw_uid <= ignore_uid_id) {
	pam_afs_syslog(LOG_INFO, PAMAFS_IGNORINGROOT, user);
	RET(PAM_AUTH_ERR);
    }
#endif
    errcode = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&password);
    if (errcode != PAM_SUCCESS || password == NULL) {
	if (use_first_pass) {
	    pam_afs_syslog(LOG_ERR, PAMAFS_PASSWD_REQ, user);
	    RET(PAM_AUTH_ERR);
	}
	password = NULL;	/* In case it isn't already NULL */
	if (logmask && LOG_MASK(LOG_DEBUG))
	    pam_afs_syslog(LOG_DEBUG, PAMAFS_NOFIRSTPASS, user);
    } else if (password[0] == '\0') {
	/* Actually we *did* get one but it was empty. */
	torch_password = 0;
	pam_afs_syslog(LOG_INFO, PAMAFS_NILPASSWORD, user);
	RET(PAM_NEW_AUTHTOK_REQD);
    } else {
	if (logmask && LOG_MASK(LOG_DEBUG))
	    pam_afs_syslog(LOG_DEBUG, PAMAFS_GOTPASS, user);
	torch_password = 0;
	got_authtok = 1;
    }
    if (!(use_first_pass || try_first_pass)) {
	password = NULL;
    }

  try_auth:
    if (password == NULL) {

	torch_password = 1;

	if (use_first_pass)
	    RET(PAM_AUTH_ERR);	/* shouldn't happen */
	if (try_first_pass)
	    try_first_pass = 0;	/* we come back if try_first_pass==1 below */

	if (pam_convp == NULL || pam_convp->conv == NULL) {
	    pam_afs_syslog(LOG_ERR, PAMAFS_CANNOT_PROMPT);
	    RET(PAM_AUTH_ERR);
	}

	errcode = pam_afs_prompt(pam_convp, &password, 0, PAMAFS_PWD_PROMPT);
	if (errcode != PAM_SUCCESS || password == NULL) {
	    pam_afs_syslog(LOG_ERR, PAMAFS_GETPASS_FAILED);
	    RET(PAM_AUTH_ERR);
	}
	if (password[0] == '\0') {
	    pam_afs_syslog(LOG_INFO, PAMAFS_NILPASSWORD, user);
	    RET(PAM_NEW_AUTHTOK_REQD);
	}

	/*
	 * We aren't going to free the password later (we will wipe it,
	 * though), because the storage for it if we get it from other
	 * paths may belong to someone else.  Since we do need to free
	 * this storage, copy it to a buffer that won't need to be freed
	 * later, and free this storage now.
	 */

	strncpy(my_password_buf, password, sizeof(my_password_buf));
	my_password_buf[sizeof(my_password_buf) - 1] = '\0';
	memset(password, 0, strlen(password));
	free(password);
	password = my_password_buf;

    }

    /* Be sure to allocate a PAG here if we should set a token,
     * All of the remaining stuff to authenticate the user and to
     * get a token is done in a child process - if not suppressed by the config,
     * see below
     * But dont get a PAG if the refresh_token option was set
     * We have to do this in such a way because some
     * apps (such as screensavers) wont call setcred but authenticate :-(
     */
    if (!refresh_token) {
	setpag();
#ifdef AFS_KERBEROS_ENV
	ktc_newpag();
#endif
	if (logmask && LOG_MASK(LOG_DEBUG))
	    syslog(LOG_DEBUG, "New PAG created in pam_authenticate()");
    }

    if (!dont_fork) {
	/* Prepare for fork(): set SIGCHLD signal handler to default */
	sigemptyset(&newAction.sa_mask);
	newAction.sa_handler = SIG_DFL;
	newAction.sa_flags = 0;
	code = sigaction(SIGCHLD, &newAction, &origAction);
	if (code) {
	    pam_afs_syslog(LOG_ERR, PAMAFS_PAMERROR, errno);
	    RET(PAM_AUTH_ERR);
	}

	/* Fork a process and let it verify authentication. So that any
	 * memory/sockets allocated will get cleaned up when the child
	 * exits: defect 11686.
	 */
	if (use_klog) {		/* used by kdm 2.x */
	    if (refresh_token || set_token) {
		i = do_klog(user, password, NULL, cell_ptr);
	    } else {
		i = do_klog(user, password, "00:00:01", cell_ptr);
		ktc_ForgetAllTokens();
	    }
	    if (logmask && LOG_MASK(LOG_DEBUG))
		syslog(LOG_DEBUG, "do_klog returned %d", i);
	    auth_ok = i ? 0 : 1;
	} else {
	    if (logmask && LOG_MASK(LOG_DEBUG))
		syslog(LOG_DEBUG, "forking ...");
	    cpid = fork();
	    if (cpid <= 0) {	/* The child process */
		if (logmask && LOG_MASK(LOG_DEBUG))
		    syslog(LOG_DEBUG, "in child");
		if (refresh_token || set_token)
		    code = ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION, user,	/* kerberos name */
						      NULL,	/* instance */
						      cell_ptr,	/* realm */
						      password,	/* password */
						      0,	/* default lifetime */
						      &password_expires, 0,	/* spare 2 */
						      &reason
						      /* error string */ );
		else
		    code = ka_VerifyUserPassword(KA_USERAUTH_VERSION, user,	/* kerberos name */
						 NULL,	/* instance */
						 cell_ptr,	/* realm */
						 password,	/* password */
						 0,	/* spare 2 */
						 &reason /* error string */ );
		if (code) {
		    pam_afs_syslog(LOG_ERR, PAMAFS_LOGIN_FAILED, user,
				   reason);
		    auth_ok = 0;
		} else {
		    auth_ok = 1;
		}
		if (logmask && LOG_MASK(LOG_DEBUG))
		    syslog(LOG_DEBUG, "child: auth_ok=%d", auth_ok);
		if (cpid == 0)
		    exit(auth_ok);
	    } else {
		do {
		    if (logmask && LOG_MASK(LOG_DEBUG))
			syslog(LOG_DEBUG, "in parent, waiting ...");
		    rcpid = waitpid(cpid, &status, 0);
		} while ((rcpid == -1) && (errno == EINTR));

		if ((rcpid == cpid) && WIFEXITED(status)) {
		    auth_ok = WEXITSTATUS(status);
		} else {
		    auth_ok = 0;
		}
		if (logmask && LOG_MASK(LOG_DEBUG))
		    syslog(LOG_DEBUG, "parent: auth_ok=%d", auth_ok);
	    }
	}
	/* Restore old signal handler */
	code = sigaction(SIGCHLD, &origAction, NULL);
	if (code) {
	    pam_afs_syslog(LOG_ERR, PAMAFS_PAMERROR, errno);
	}
    } else {			/* dont_fork, used by httpd */
	if (logmask && LOG_MASK(LOG_DEBUG))
	    syslog(LOG_DEBUG, "dont_fork");
	if (refresh_token || set_token)
	    code = ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION, user,	/* kerberos name */
					      NULL,	/* instance */
					      cell_ptr,	/* realm */
					      password,	/* password */
					      0,	/* default lifetime */
					      &password_expires, 0,	/* spare 2 */
					      &reason /* error string */ );
	else
	    code = ka_VerifyUserPassword(KA_USERAUTH_VERSION, user,	/* kerberos name */
					 NULL,	/* instance */
					 cell_ptr,	/* realm */
					 password,	/* password */
					 0,	/* spare 2 */
					 &reason /* error string */ );
	if (logmask && LOG_MASK(LOG_DEBUG))
	    syslog(LOG_DEBUG, "dont_fork, code = %d", code);
	if (code) {
	    pam_afs_syslog(LOG_ERR, PAMAFS_LOGIN_FAILED, user, reason);
	    auth_ok = 0;
	} else {
	    auth_ok = 1;
	}
	if (logmask && LOG_MASK(LOG_DEBUG))
	    syslog(LOG_DEBUG, "dont_fork: auth_ok=%d", auth_ok);
    }

    if (!auth_ok && try_first_pass) {
	password = NULL;
	goto try_auth;
    }

    /* We don't care if this fails; all we can do is try. */
    /* It is not reasonable to store the password only if it was correct
     * because it could satisfy another module that is called in the chain
     * after pam_afs
     */
    if (!got_authtok) {
	torch_password = 0;
	(void)pam_set_item(pamh, PAM_AUTHTOK, password);
    }

    if (logmask && LOG_MASK(LOG_DEBUG))
	syslog(LOG_DEBUG, "leaving auth: auth_ok=%d", auth_ok);
    if (code == KANOENT)
	RET(PAM_USER_UNKNOWN);
    RET(auth_ok ? PAM_SUCCESS : PAM_AUTH_ERR);

  out:
    if (password) {
	/* we store the password in the data portion */
	char *tmp = strdup(password);
	(void)pam_set_data(pamh, pam_afs_lh, tmp, lc_cleanup);
	if (torch_password)
	    memset(password, 0, strlen(password));
    }
    (void)setlogmask(origmask);
#ifndef AFS_SUN56_ENV
    closelog();
#endif
    return retcode;
}