Exemplo n.º 1
0
/* Called at exit to cleanly shutdown PAM */
static void
do_pam_cleanup_proc(void *context)
{
	int pam_retval;
	pam_stuff *pam = (pam_stuff *) context;

	if (pam == NULL)
		return;

	if (pam->authctxt != NULL && pam->authctxt->pam == pam) {
		pam->authctxt->pam_retval = pam->last_pam_retval;
		pam->authctxt->pam = NULL;
		pam->authctxt = NULL;
	}

	if (pam->h == NULL)
		return;

	/*
	 * We're in fatal_cleanup() or not in userauth or without a
	 * channel -- can't converse now, too bad.
	 */
	pam_retval = pam_set_item(pam->h, PAM_CONV, NULL);
	if (pam_retval != PAM_SUCCESS) {
		log("Cannot remove PAM conv, close session or delete creds[%d]: %.200s",
			pam_retval, PAM_STRERROR(pam->h, pam_retval));
		goto cleanup;
	}

	if (pam->state & PAM_S_DONE_OPEN_SESSION) {
		pam_retval = pam_close_session(pam->h, 0);
		if (pam_retval != PAM_SUCCESS)
			log("Cannot close PAM session[%d]: %.200s",
			    pam_retval, PAM_STRERROR(pam->h, pam_retval));
	}

	if (pam->state & PAM_S_DONE_SETCRED) {
		pam_retval = pam_setcred(pam->h, PAM_DELETE_CRED);
		if (pam_retval != PAM_SUCCESS)
			debug("Cannot delete credentials[%d]: %.200s", 
			    pam_retval, PAM_STRERROR(pam->h, pam_retval));
	}

cleanup:

	/* Use the previous PAM result, if not PAM_SUCCESS for pam_end() */
	if (pam->last_pam_retval != PAM_SUCCESS)
		pam_retval = pam_end(pam->h, pam->last_pam_retval);
	else if (pam_retval != PAM_SUCCESS)
		pam_retval = pam_end(pam->h, pam_retval);
	else
		pam_retval = pam_end(pam->h, PAM_ABORT);

	if (pam_retval != PAM_SUCCESS)
		log("Cannot release PAM authentication[%d]: %.200s",
		    pam_retval, PAM_STRERROR(pam->h, pam_retval));

	xfree(pam);
}
Exemplo n.º 2
0
void
do_pam_passwd(const char *user, int silent, int change_expired)
{
	pam_handle_t *pamh = NULL;
	int flags = 0, ret;

	if (silent)
		flags |= PAM_SILENT;
	if (change_expired)
		flags |= PAM_CHANGE_EXPIRED_AUTHTOK;

	ret = pam_start("passwd", user, &conv, &pamh);
	if (ret != PAM_SUCCESS) {
		fprintf(stderr, _("passwd: pam_start() failed, error %d\n"),
			ret);
		exit(10);  /* XXX */
	}

	ret = pam_chauthtok(pamh, flags);
	if (ret != PAM_SUCCESS) {
		fprintf(stderr, _("passwd: %s\n"), PAM_STRERROR(pamh, ret));
		pam_end(pamh, ret);
		exit(10);  /* XXX */
	}

	pam_end(pamh, PAM_SUCCESS);
}
Exemplo n.º 3
0
jboolean
shaj_chkpasswd_pam(const char* service, const char *user, const char *password, loginfo_t* logger){
  
  pam_handle_t *pamh = 0;
  int status = -1;
  struct pam_conv pc;
  struct ourpam_authdata c;
  
  c.user = user;
  c.password = password;
  c.logger = logger;
  
  pc.conv = &ourpam_conversation;
  pc.appdata_ptr = (void *) &c;
  
  
  status = mypam_start(service, c.user, &pc, &pamh);
  shaj_log_debug(logger, "pam_start (\"%s\", \"%s\", ...) ==> %d (%s)",
                    service, c.user,
                    status, PAM_STRERROR (pamh, status));
  
  if (status != PAM_SUCCESS) goto DONE;
  
  status = mypam_authenticate(pamh, 0);
  
  shaj_log_debug(logger, " pam_authenticate (...) ==> %d (%s)",
                    status, PAM_STRERROR(pamh, status));
  
  if (status == PAM_SUCCESS) {
    /* be nice to Kerberos and refresh credentials */
    int status2 = mypam_setcred(pamh, PAM_REINITIALIZE_CRED);
    shaj_log_debug(logger, " pam_setcred (...) ==> %d (%s)",
                      status2, PAM_STRERROR(pamh, status2));
    goto DONE;
  }

 DONE:
  if (pamh) {
    int status2 = mypam_end(pamh, status);
    pamh = 0;
    shaj_log_debug(logger, "pam_end (...) ==> %d (%s)",
                      status2,
                      (status2 == PAM_SUCCESS ? "Success" : "Failure"));
  }
  return (status == PAM_SUCCESS ? JNI_TRUE : JNI_FALSE);
}
Exemplo n.º 4
0
/**
 * This function is the PAM conversation driver. It conducts a full
 * authentication round by invoking the GUI with various prompts.
 */
void
pam_try_unlock(saver_info *si, Bool verbose_p,
	       Bool (*valid_p)(const char *typed_passwd, Bool verbose_p))
{
  const char *service = PAM_SERVICE_NAME;
  pam_handle_t *pamh = 0;
  int status = -1;
  struct pam_conv pc;
  sigset_t set;
  struct timespec timeout;

  pc.conv = &pam_conversation;
  pc.appdata_ptr = (void *) si;

  /* On SunOS 5.6, the `appdata_ptr' slot seems to be ignored, and the
     `closure' argument to pc.conv always comes in as random garbage. */
  suns_pam_implementation_blows = (void *) si;


  /* Initialize PAM.
   */
  status = pam_start (service, si->user, &pc, &pamh);
  if (verbose_p)
    fprintf (stderr, "%s: pam_start (\"%s\", \"%s\", ...) ==> %d (%s)\n",
             blurb(), service, si->user,
             status, PAM_STRERROR (pamh, status));
  if (status != PAM_SUCCESS) goto DONE;

  /* #### We should set PAM_TTY to the display we're using, but we
     don't have that handy from here.  So set it to :0.0, which is a
     good guess (and has the bonus of counting as a "secure tty" as
     far as PAM is concerned...)
   */
  {
    char *tty = strdup (":0.0");
    status = pam_set_item (pamh, PAM_TTY, tty);
    if (verbose_p)
      fprintf (stderr, "%s:   pam_set_item (p, PAM_TTY, \"%s\") ==> %d (%s)\n",
               blurb(), tty, status, PAM_STRERROR(pamh, status));
    free (tty);
  }

  /* Try to authenticate as the current user.
     We must turn off our SIGCHLD handler for the duration of the call to
     pam_authenticate(), because in some cases, the underlying PAM code
     will do this:

        1: fork a setuid subprocess to do some dirty work;
        2: read a response from that subprocess;
        3: waitpid(pid, ...) on that subprocess.

    If we (the ignorant parent process) have a SIGCHLD handler, then there's
    a race condition between steps 2 and 3: if the subprocess exits before
    waitpid() was called, then our SIGCHLD handler fires, and gets notified
    of the subprocess death; then PAM's call to waitpid() fails, because the
    process has already been reaped.

    I consider this a bug in PAM, since the caller should be able to have
    whatever signal handlers it wants -- the PAM documentation doesn't say
    "oh by the way, if you use PAM, you can't use SIGCHLD."
   */

  PAM_NO_DELAY(pamh);

  if (verbose_p)
    fprintf (stderr, "%s:   pam_authenticate (...) ...\n", blurb());

  timeout.tv_sec = 0;
  timeout.tv_nsec = 1;
  set = block_sigchld();
  status = pam_authenticate (pamh, 0);
# ifdef HAVE_SIGTIMEDWAIT
  sigtimedwait (&set, NULL, &timeout);
  /* #### What is the portable thing to do if we don't have it? */
# endif /* HAVE_SIGTIMEDWAIT */
  unblock_sigchld();

  if (verbose_p)
    fprintf (stderr, "%s:   pam_authenticate (...) ==> %d (%s)\n",
             blurb(), status, PAM_STRERROR(pamh, status));

  if (status == PAM_SUCCESS)  /* Win! */
    {
      int status2;

      /* On most systems, it doesn't matter whether the account modules
         are run, or whether they fail or succeed.

         On some systems, the account modules fail, because they were
         never configured properly, but it's necessary to run them anyway
         because certain PAM modules depend on side effects of the account
         modules having been run.

         And on still other systems, the account modules are actually
         used, and failures in them should be considered to be true!

         So:
         - We run the account modules on all systems.
         - Whether we ignore them is a configure option.

         It's all kind of a mess.
       */
      status2 = pam_acct_mgmt (pamh, 0);

      if (verbose_p)
        fprintf (stderr, "%s:   pam_acct_mgmt (...) ==> %d (%s)\n",
                 blurb(), status2, PAM_STRERROR(pamh, status2));

      /* HPUX for some reason likes to make PAM defines different from
       * everyone else's. */
#ifdef PAM_AUTHTOKEN_REQD
      if (status2 == PAM_AUTHTOKEN_REQD)
#else
      if (status2 == PAM_NEW_AUTHTOK_REQD)
#endif
        {
          status2 = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
          if (verbose_p)
            fprintf (stderr, "%s: pam_chauthtok (...) ==> %d (%s)\n",
                     blurb(), status2, PAM_STRERROR(pamh, status2));
        }

      /* If 'configure' requested that we believe the results of PAM
         account module failures, then obey that status code.
         Otherwise ignore it.
       */
#ifdef PAM_CHECK_ACCOUNT_TYPE
       status = status2;
#endif

      /* Each time we successfully authenticate, refresh credentials,
         for Kerberos/AFS/DCE/etc.  If this fails, just ignore that
         failure and blunder along; it shouldn't matter.
       */

#if defined(__linux__)
      /* Apparently the Linux PAM library ignores PAM_REFRESH_CRED and only
         refreshes credentials when using PAM_REINITIALIZE_CRED. */
      status2 = pam_setcred (pamh, PAM_REINITIALIZE_CRED);
#else
      /* But Solaris requires PAM_REFRESH_CRED or extra prompts appear. */
      status2 = pam_setcred (pamh, PAM_REFRESH_CRED);
#endif

      if (verbose_p)
        fprintf (stderr, "%s:   pam_setcred (...) ==> %d (%s)\n",
                 blurb(), status2, PAM_STRERROR(pamh, status2));
    }

 DONE:
  if (pamh)
    {
      int status2 = pam_end (pamh, status);
      pamh = 0;
      if (verbose_p)
        fprintf (stderr, "%s: pam_end (...) ==> %d (%s)\n",
                 blurb(), status2,
                 (status2 == PAM_SUCCESS ? "Success" : "Failure"));
    }

  if (status == PAM_SUCCESS)
    si->unlock_state = ul_success;	     /* yay */
  else if (si->unlock_state == ul_cancel ||
           si->unlock_state == ul_time)
    ;					     /* more specific failures ok */
  else
    si->unlock_state = ul_fail;		     /* generic failure */
}
Exemplo n.º 5
0
/*
 * To be called from userauth methods, directly (as in keyboard-interactive) or
 * indirectly (from auth_pam_password() or from do_pam_non_initial_userauth().
 *
 * The caller is responsible for calling new_start_pam() first.
 *
 * PAM state is not cleaned up here on error.  This is left to subsequent calls
 * to new_start_pam() or to the cleanup function upon authentication error.
 */
int
finish_userauth_do_pam(Authctxt *authctxt)
{
	int retval;
	char *user, *method;

	/* Various checks; fail gracefully */
	if (authctxt == NULL || authctxt->pam == NULL)
		return PAM_SYSTEM_ERR;	/* shouldn't happen */

	if (compat20) {
		if (authctxt->method == NULL || authctxt->method->name == NULL)
			return PAM_SYSTEM_ERR;	/* shouldn't happen */
		method = authctxt->method->name;
	} else if ((method = authctxt->v1_auth_name) == NULL)
		return PAM_SYSTEM_ERR;	/* shouldn't happen */

	if (AUTHPAM_DONE(authctxt))
		return PAM_SYSTEM_ERR;	/* shouldn't happen */

	if (!(authctxt->pam->state & PAM_S_DONE_ACCT_MGMT)) {
		retval = pam_acct_mgmt(authctxt->pam->h, 0);
		authctxt->pam->last_pam_retval = retval;
		if (retval == PAM_NEW_AUTHTOK_REQD) {
			userauth_force_kbdint();
			return retval;
		}
		if (retval != PAM_SUCCESS)
			return retval;
		authctxt->pam->state |= PAM_S_DONE_ACCT_MGMT;
	}

	/*
	 * Handle PAM_USER change, if any.
	 *
	 * We do this before pam_open_session() because we need the PAM_USER's
	 * UID for:
	 *
	 * a) PermitRootLogin checking
	 * b) to get at the lastlog entry before pam_open_session() updates it.
	 */
	retval = pam_get_item(authctxt->pam->h, PAM_USER, (void **) &user);
	if (retval != PAM_SUCCESS) {
		fatal("PAM failure: pam_get_item(PAM_USER) "
		      "returned %d: %.200s", retval,
		      PAM_STRERROR(authctxt->pam->h, retval));
	}

	if (user == NULL || *user == '\0') {
		debug("PAM set NULL PAM_USER");
		return PAM_PERM_DENIED;
	}

	if (strcmp(user, authctxt->user) != 0) {
		log("PAM changed the SSH username");
		pwfree(&authctxt->pw);
		authctxt->pw = PRIVSEP(getpwnamallow(user));
		authctxt->valid = (authctxt->pw != NULL);
		xfree(authctxt->user);
		authctxt->user = xstrdup(user);
	}

	if (!authctxt->valid) {
		debug2("PAM set PAM_USER to unknown user");
		/*
		 * Return success, userauth_finish() will catch
		 * this and send back a failure message.
		 */
		return PAM_SUCCESS;
	}

	/* Check PermitRootLogin semantics */
	if (authctxt->pw->pw_uid == 0 && !auth_root_allowed(method))
		return PAM_PERM_DENIED;

	if (!(authctxt->pam->state & PAM_S_DONE_SETCRED)) {
		retval = pam_setcred(authctxt->pam->h,
				     PAM_ESTABLISH_CRED);
		authctxt->pam->last_pam_retval = retval;
		if (retval != PAM_SUCCESS)
			return retval;
		authctxt->pam->state |= PAM_S_DONE_SETCRED;

#ifdef GSSAPI
		/*
		 * Store GSS-API delegated creds after pam_setcred(), which may
		 * have set the current credential store.
		 */
		ssh_gssapi_storecreds(NULL, authctxt);
#endif /* GSSAPI */
	}

	/*
	 * On Solaris pam_unix_session.so updates the lastlog, but does
	 * not converse a PAM_TEXT_INFO message about it.  So we need to
	 * fetch the lastlog entry here and save it for use later.
	 */
	authctxt->last_login_time =
		get_last_login_time(authctxt->pw->pw_uid,
			authctxt->pw->pw_name,
			authctxt->last_login_host,
			sizeof(authctxt->last_login_host));

	if (!(authctxt->pam->state & PAM_S_DONE_OPEN_SESSION)) {
		retval = pam_open_session(authctxt->pam->h, 0);
		authctxt->pam->last_pam_retval = retval;
		if (retval != PAM_SUCCESS)
			return retval;
		authctxt->pam->state |= PAM_S_DONE_OPEN_SESSION;
	}

	/*
	 * All PAM work done successfully.
	 *
	 * PAM handle stays around so we can call pam_close_session() on
	 * it later.
	 */
	return PAM_SUCCESS;
}
static int
gs_auth_thread_func (int auth_operation_fd)
{
        static const int flags = 0;
        int              status;
        int              status2;
        struct timespec  timeout;
        sigset_t         set;
        const void      *p;

        timeout.tv_sec = 0;
        timeout.tv_nsec = 1;

        set = block_sigchld ();

        status = pam_authenticate (pam_handle, flags);

        sigtimedwait (&set, NULL, &timeout);
        unblock_sigchld ();

        if (gs_auth_get_verbose ()) {
                g_message ("   pam_authenticate (...) ==> %d (%s)",
                           status,
                           PAM_STRERROR (pam_handle, status));
        }

        if (status != PAM_SUCCESS) {
                goto done;
        }

        if ((status = pam_get_item (pam_handle, PAM_USER, &p)) != PAM_SUCCESS) {
                /* is not really an auth problem, but it will
                   pretty much look as such, it shouldn't really
                   happen */
                goto done;
        }

        /* We don't actually care if the account modules fail or succeed,
         * but we need to run them anyway because certain pam modules
         * depend on side effects of the account modules getting run.
         */
        status2 = pam_acct_mgmt (pam_handle, 0);

        if (gs_auth_get_verbose ()) {
                g_message ("pam_acct_mgmt (...) ==> %d (%s)\n",
                           status2,
                           PAM_STRERROR (pam_handle, status2));
        }

        /* FIXME: should we handle these? */
        switch (status2) {
        case PAM_SUCCESS:
                break;
        case PAM_NEW_AUTHTOK_REQD:
                status2 = pam_chauthtok (pam_handle, PAM_CHANGE_EXPIRED_AUTHTOK);

                if (status2 != PAM_SUCCESS) {
                    g_message ("pam_acct_mgmt (...) ==> %d (%s)\n",
                           status2,
                           PAM_STRERROR (pam_handle, status2));
		    status = status2;
                }
                break;
        case PAM_AUTHINFO_UNAVAIL:
                break;
        case PAM_ACCT_EXPIRED:
                break;
        case PAM_PERM_DENIED:
                break;
        default :
                break;
        }

        /* Each time we successfully authenticate, refresh credentials,
           for Kerberos/AFS/DCE/etc.  If this fails, just ignore that
           failure and blunder along; it shouldn't matter.

           Note: this used to be PAM_REFRESH_CRED instead of
           PAM_REINITIALIZE_CRED, but Jason Heiss <*****@*****.**>
           says that the Linux PAM library ignores that one, and only refreshes
           credentials when using PAM_REINITIALIZE_CRED.
        */
        status2 = pam_setcred (pam_handle, PAM_REINITIALIZE_CRED);
        if (gs_auth_get_verbose ()) {
                g_message ("   pam_setcred (...) ==> %d (%s)",
                           status2,
                           PAM_STRERROR (pam_handle, status2));
        }

 done:
        /* we're done, close the fd and wake up the main
         * loop
         */
        close (auth_operation_fd);

        return status;
}
static gboolean
create_pam_handle (const char      *username,
                   const char      *display,
                   struct pam_conv *conv,
                   int             *status_code)
{
        int         status;
        const char *service = PAM_SERVICE_NAME;
        char       *disp;
        gboolean    ret;

	if (pam_handle != NULL) {
		g_warning ("create_pam_handle: Stale pam handle around, cleaning up");
                close_pam_handle (PAM_SUCCESS);
	}

	/* init things */
	pam_handle = NULL;
        status = -1;
        disp = NULL;
        ret = TRUE;

	/* Initialize a PAM session for the user */
	if ((status = pam_start (service, username, conv, &pam_handle)) != PAM_SUCCESS) {
		pam_handle = NULL;
                g_warning (_("Unable to establish service %s: %s\n"),
                           service,
                           PAM_STRERROR (NULL, status));

                if (status_code != NULL) {
                        *status_code = status;
                }

                ret = FALSE;
                goto out;
	}

        if (gs_auth_get_verbose ()) {
                g_message ("pam_start (\"%s\", \"%s\", ...) ==> %d (%s)",
                           service,
                           username,
                           status,
                           PAM_STRERROR (pam_handle, status));
        }

        disp = g_strdup (display);
        if (disp == NULL) {
                disp = g_strdup (":0.0");
        }

	if ((status = pam_set_item (pam_handle, PAM_TTY, disp)) != PAM_SUCCESS) {
                g_warning (_("Can't set PAM_TTY=%s"), display);

                if (status_code != NULL) {
                        *status_code = status;
                }

                ret = FALSE;
                goto out;
	}

        ret = TRUE;
	message_handled_condition = g_cond_new ();
	message_handler_mutex = g_mutex_new ();

 out:
        if (status_code != NULL) {
                *status_code = status;
        }

        g_free (disp);

        return ret;
}