[31788] in Kerberos

home help back first fref pref prev next nref lref last post

Re: Kerberos tickets, SSH public key auth, AFS tokens

daemon@ATHENA.MIT.EDU (Douglas E. Engert)
Thu Dec 17 10:48:06 2009

Message-ID: <4B2A5288.2080705@anl.gov>
Date: Thu, 17 Dec 2009 09:47:20 -0600
From: "Douglas E. Engert" <deengert@anl.gov>
MIME-Version: 1.0
To: Jeff Blaine <jblaine@stage-infinity.com>
In-Reply-To: <4B297B85.4000305@stage-infinity.com>
Content-Type: multipart/mixed; boundary="------------060702070100010707020301"
Cc: kerberos@mit.edu
Errors-To: kerberos-bounces@mit.edu

This is a multi-part message in MIME format.
--------------060702070100010707020301
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit



Jeff Blaine wrote:
> On 12/16/2009 5:39 PM, Douglas E. Engert wrote:
>> Jeff Blaine wrote:
>>> Long ago, we evaluated the facilities within OS-provided
>>> sshd for handling our Kerberos + OpenAFS authentication
>>> needs. That is, things like the Kerberos* settings,
>>> GetAFSToken or whatever it was called, etc.
>>>
>>> We found it to be an unusable mismatched moving target.
>>>
>>> We decided to do everything via PAM, with the exception
>>> of ssh public key auth for those who choose to use it
>>> and not get OpenAFS tokens automatically.
>>>
>>> It works great thanks to pam_krb5 and pam_afs_session
>>> from Russ Alberry.
>>>
>>> Our problem now is, of course, that people are complaining
>>> about the number of times they have to type a password.
>>>
>>> Can some of you hint to me what I should be researching
>>> as a solution to this? Essentially we need a non-interactive
>>> way to get OpenAFS tokens via krb5 creds, and I am pretty
>>> clueless about such things. More specifically, this has
>>> all come about from users complaining about CVS-via-SSH
>>> requiring a password in order to get tokens.
>> ssh could use "GSSAPIDelegateCredentials yes" to forward
>> Krb5 tickets, and the sshd could then use pam_afs_session
>> to get the token, even for CVS.
>>
>> But this won't work with ssh public keys. If its winCVS
>> on Windows you are interested in, it too can support GSSAPI.
> 
> Thanks for the reply Doug
> 
> Well, public keys aren't a requirement.  I probably didn't
> make that clear, as it's a long story, so I apologize.
> 
> Ignoring public keys, and after configuring a 'host'
> service principal, then extracting it, this does in fact
> work between two Solaris 10 boxes.  Cool.
> 
> Now I just need to figure out the pam_afs_session part.
> 
> With some sshd-gssapi service lines in /etc/pam.conf,
> I'm stuck here (pam_krb5 is Russ'):
> 
> # these first 4 lines seem unnecessary for sshd-gssapi here, no?
> sshd-gssapi   auth requisite     pam_authtok_get.so.1
> sshd-gssapi   auth sufficient    pam_krb5RA.so try_first_pass 
> forwardable minimum_uid=92 debug
> sshd-gssapi   auth required      pam_unix_auth.so.1
> sshd-gssapi   auth required      pam_unix_cred.so.1
> sshd-gssapi   auth optional      pam_afs_session.so minimum_uid=92 debug
> sshd-gssapi  session optional    pam_krb5RA.so minimum_uid=92 debug
> sshd-gssapi  session optional    pam_afs_session.so minimum_uid=92 debug
> 
> sshd[20489]: [ID 800047 auth.info] Accepted gssapi-keyex for jblaine 
> from 1xx.xx.10.14 port 60103 ssh2
> sshd[20489]: [ID 366013 auth.debug] pam_krb5(sshd-gssapi): 
> pam_sm_open_session: entry (0x0)
> sshd[20489]: [ID 366013 auth.debug] pam_krb5(sshd-gssapi): no context 
> found, creating one
> sshd[20489]: [ID 366013 auth.debug] pam_krb5(sshd-gssapi): 
> pam_sm_open_session: entry (0x0)
> sshd[20489]: [ID 366013 auth.debug] pam_krb5(sshd-gssapi): no context 
> found, creating one
> sshd[20489]: [ID 366013 auth.debug] pam_krb5(sshd-gssapi): (user 
> jblaine) unable to get PAM_KRB5CCNAME, assuming non-Kerberos login
> sshd[20489]: [ID 366013 auth.debug] pam_krb5(sshd-gssapi): 
> pam_sm_open_session: exit (ignore)
> sshd[20489]: [ID 366013 auth.debug] pam_krb5(sshd-gssapi): (user 
> jblaine) unable to get PAM_KRB5CCNAME, assuming non-Kerberos login
> sshd[20489]: [ID 366013 auth.debug] pam_krb5(sshd-gssapi): 
> pam_sm_open_session: exit (ignore)
> sshd[20489]: [ID 237248 auth.debug] (pam_afs_session): 
> pam_sm_open_session: entry (0x0)
> sshd[20489]: [ID 237248 auth.debug] (pam_afs_session): skipping tokens, 
> no Kerberos ticket cache

With Solaris 10 using their sshd and pam_krb5 with Russ's pam_afs_session
Note that only the account and session are used:

# Used by GSS, but ssh has bug about saving creds, so we use session based creds.

sshd-gssapi   account requisite  pam_roles.so.1
sshd-gssapi   account required   pam_unix_account.so.1
sshd-gssapi   account required   /krb5/lib/security/pam_krb5_ccache.so.1  ccache=/tmp/krb5cc_%u_%p

sshd-gssapi   session required  pam_unix_session.so.1
sshd-gssapi   session required  /krb5/lib/security/pam_afs_session.so
sshd-gssapi   session required  /krb5/lib/security/pam_krb5_ccache.so.1  clean

Note the pam_krb5_ccache.so.1 is a local module, that can be used with sshd
to use a session based ticket cache. (But this may not work will with NFSv4 and its
gssd which is expecting the default cache names.)

I have attached the source code for this. I can send you a tar.gz file with configure
and Makefile.in etc. if you are interested.



> ________________________________________________
> Kerberos mailing list           Kerberos@mit.edu
> https://mailman.mit.edu/mailman/listinfo/kerberos
> 
> 

-- 

  Douglas E. Engert  <DEEngert@anl.gov>
  Argonne National Laboratory
  9700 South Cass Avenue
  Argonne, Illinois  60439
  (630) 252-5444

--------------060702070100010707020301
Content-Type: text/plain;
 name="pam_krb5_ccache.c"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="pam_krb5_ccache.c"

/*
 * Pam routine to set KRB5CCNAME to force Solaris to
 * use session based caches
 */

#define DEBLOG(A,B) \
	if (debug) \
		syslog(LOG_NOTICE,"pam_krb5_ccache:%d %s:%s", __LINE__, A, B)

		
#include <stdio.h>
#include <pam_appl.h>
#include <pam_modules.h>
#include <syslog.h>
#include <pwd.h>

int 
do_krb5_ccache_routine(pam_handle_t *pamh, int flags, int argc,
	const char **argv);


/***************************************************************/

int
pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
	    const char **argv)
{

	int debug = 0;
	int i;
	int ret;
	int do_krb5_ccache= 0;
	
	for (i = 0; i < argc; i++) {
		if (strcmp(argv[i], "debug") == 0) {
			debug++;
		}
		else if (strcmp(argv[i], "force") == 0) {
			do_krb5_ccache = 1;
		}
	}
#ifdef DEBUG
	fprintf(stderr,"pam_sm_authenticate flag=%d\n",flags);
#endif
	DEBLOG("pam_sm_authenticate","called");
    if (debug) {
		if (pam_getenv(pamh,"KRB5CCNAME")) 
			DEBLOG("pam_getenv KRB5CCNAME", 
					pam_getenv(pamh,"KRB5CCNAME"));
		if (getenv("KRB5CCNAME")) 
			DEBLOG("getenv KRB5CCNAME",
					getenv("KRB5CCNAME"));
	}

	if (do_krb5_ccache) {
		ret = do_krb5_ccache_routine(pamh, flags, argc, argv);

		if (ret == PAM_SUCCESS) {
			ret = PAM_IGNORE; /* we did not really authenticate */
		}
	} else {
		ret = PAM_IGNORE;
	}

	return ret;
}

/***************************************************************/

int
pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc,
	    const char **argv)
{

	int debug = 0;
	int i;
	int ret;
	int do_krb5_ccache = 1; /* default if called do it */
	
	for (i = 0; i < argc; i++) {
		if (strcmp(argv[i], "debug") == 0) {
			debug++;
		}
	}
#ifdef DEBUG
	fprintf(stderr,"pam_sm_account flag=%d\n",flags);
#endif
	DEBLOG("pam_sm_account","called");
    if (debug) {
		if (pam_getenv(pamh,"KRB5CCNAME")) 
			DEBLOG("pam_getenv KRB5CCNAME", 
					pam_getenv(pamh,"KRB5CCNAME"));
		if (getenv("KRB5CCNAME")) 
			DEBLOG("getenv KRB5CCNAME",
					getenv("KRB5CCNAME"));
	}

	if (do_krb5_ccache) {
		ret = do_krb5_ccache_routine(pamh, flags, argc, argv);

		if (ret == PAM_SUCCESS) {
			ret = PAM_IGNORE; /* we did not really authenticate */
		}
	} else {
		ret = PAM_IGNORE;
	}

	return ret;
}

/********************************************************/ 

int 
pam_sm_setcred(pam_handle_t *pamh, int flags, int argc,
           const char **argv)
{
    int debug = 0;
    int ret;
    int i;
	int do_krb5_ccache = 1;  /* default to doing the cache stuff */

    for (i = 0; i < argc; i++) {
        if (strcmp(argv[i], "debug") == 0) {
            debug++;
        }
		else if (strcmp(argv[i], "force" ) == 0) {
			do_krb5_ccache = 0; /* authenticate would have done this */
		}
    }

    DEBLOG("pam_sm_setcred", "called");
    if (debug) {
		if (pam_getenv(pamh,"KRB5CCNAME")) 
			DEBLOG("pam_getenv KRB5CCNAME", 
					pam_getenv(pamh,"KRB5CCNAME"));
		if (getenv("KRB5CCNAME")) 
			DEBLOG("getenv KRB5CCNAME",
					getenv("KRB5CCNAME"));
	}
	
	if (do_krb5_ccache) {
		ret = do_krb5_ccache_routine(pamh, flags, argc, argv);
	} else {
		ret = PAM_SUCCESS;
	}
	return ret;
}

/********************************************************/ 

int 
pam_sm_open_session(pam_handle_t *pamh, int flags, int argc,
           const char **argv)
{
    int debug = 0;
	int i;
	int ret;
	int do_krb5_ccache = 0;
	

#ifdef DEBUG
    fprintf(stderr,"pam_sm_open_session flag=%d\n",flags);
#endif

    for (i = 0; i < argc; i++) {
        if (strcmp(argv[i], "debug") == 0) {
            debug++;
        }
		if (strcmp(argv[i], "force") == 0) {
			do_krb5_ccache = 1;
		}
	}

    DEBLOG("pam_sm_open_session", "called");
    if (debug) {
		if (pam_getenv(pamh,"KRB5CCNAME")) 
			DEBLOG("pam_getenv KRB5CCNAME", 
					pam_getenv(pamh,"KRB5CCNAME"));
		if (getenv("KRB5CCNAME")) 
			DEBLOG("getenv KRB5CCNAME",
					getenv("KRB5CCNAME"));
	}

	if (do_krb5_ccache) {
		ret = do_krb5_ccache_routine(pamh, flags, argc, argv);
	} else {
	 ret = PAM_SUCCESS;
	}

    return ret;
}

/********************************************************/


int
pam_sm_close_session(pam_handle_t *pamh, int flags, int argc,
           const char **argv)
{
    int debug = 0;
    int ret;
    int i;
	int clean = 0;
	char * cache_name = NULL;

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

    if (debug) {
		if (pam_getenv(pamh,"KRB5CCNAME")) 
			DEBLOG("pam_getenv KRB5CCNAME", 
					pam_getenv(pamh,"KRB5CCNAME"));
		if (getenv("KRB5CCNAME")) 
			DEBLOG("getenv KRB5CCNAME",
					getenv("KRB5CCNAME"));
	}

	if (clean) {
		if ((cache_name = getenv("KRB5CCNAME"))
			|| (cache_name = pam_getenv(pamh,"KRB5CCNAME"))) {

			if (!strncmp(cache_name, "FILE:", 5)) {
				cache_name = cache_name + 5;
			}
			remove(cache_name);
			DEBLOG("remvoing ccache" ,cache_name);
		}
	}

    DEBLOG("pam_sm_close_session", "called");

    return PAM_SUCCESS;
}



/********************************************************/ 

int 
do_krb5_ccache_routine(pam_handle_t *pamh, int flags, int argc,
           const char **argv)
{

	int debug = 0;
	int set_pag = 1;
	int i;
	int ret;
	char * username = NULL;
    char ** env;
	char * pgm_name = NULL;
	struct passwd   *pw = NULL;

	char *p;
	char *q;
	char *cache_name = NULL;
	char cache_name_buf[1024];
	char cache_name_env_buf[2048];
    char *hpenv_path = "PATH=/krb5/sbin:/usr/bin:/bin";
    char *hpenv[] = {0,0,0};
	
#ifdef DEBUG
	fprintf(stderr,"do_krb5_ccache_routine flag=%d\n",flags);
#endif

	for (i = 0; i < argc; i++) {
		if (strcmp(argv[i], "debug") == 0) {
			debug++;
		}
		else if (strncmp(argv[i], "ccache=", 7) == 0) {
			cache_name = &argv[i][7]; /* save for later */
		}
	}

	DEBLOG("do_krb5_ccache_routine", "called");
	
#if 0
	if (!(flags & PAM_ESTABLISH_CRED)) {
		ret = PAM_SUCCESS;
		DEBLOG("do_krb5_ccache_routine", "no  PAM_ESTABLISH_CRED");
		goto err;
	}
#endif

	if (pam_get_item(pamh, PAM_USER, (void **) &username)) {
		ret = PAM_SERVICE_ERR;
		goto err;
	}

	if (strncmp(username,"root",4) == 0) {
		ret = PAM_IGNORE; /* no tokens for root */
		DEBLOG("do_krb5_ccache_routine ignoring ",username);
		goto err;
	}

	DEBLOG("do_krb5_ccache_routine user", username);

    if (!(pw = getpwnam(username))) {
        ret = PAM_IGNORE;
		DEBLOG("do_krb5_ccache_routine" , "user not known");
        goto err;
    }


	/* HP does not have the pam_env routines */
	/* will look for ccache as set in krb5 pam routines */

	/* Get the cache name */
	if (!cache_name) {
		cache_name = "FILE:/tmp/krb5cc_%u";
	}
	strcpy(cache_name_env_buf,"KRB5CCNAME=");
	p = cache_name_env_buf + strlen(cache_name_env_buf);
	q = cache_name;

	/* convert %u and %p */
	while (*q) {
		if (*q == '%') {
			q++;
			if (*q == 'u') {
				sprintf(p, "%ld", pw->pw_uid);
				p += strlen(p);
			} else if (*q == 'n') {
				sprintf(p, "%s", username);
				p += strlen(p);
			} else if (*q == 'p') {
				sprintf(p, "%ld", getpid());
				p += strlen(p);
			} else {
				/* Not a special token */
				*p++ = '%';
				q--;
			}
			q++;
		} else {
			*p++ = *q++;
		}
	}


#ifdef DEBUG
    fprintf(stderr,"do_krb5_ccache_routine pid=%d uid=%d euid=%d\n",
        getpid(),getuid(),geteuid());
     fprintf(stderr,"do_krb5_ccache_routine, pw_dir=%s\n",
        pw->pw_dir);
     fprintf(stderr,"do_krb5_ccache_routine Kenv=%s\n",
        pam_getenv(pamh,"KRB5CCNAME")?
        pam_getenv(pamh,"KRB5CCNAME"):"(none)");
#endif
    if (debug) {
		if (pam_getenv(pamh,"KRB5CCNAME")) 
			DEBLOG("pam_getenv KRB5CCNAME", 
					pam_getenv(pamh,"KRB5CCNAME"));
		if (getenv("KRB5CCNAME")) 
			DEBLOG("getenv KRB5CCNAME",
					getenv("KRB5CCNAME"));
	}

	DEBLOG("do_krb5_ccache_routine","calling get_krb5_ccache_token");

	pam_putenv(pamh, cache_name_env_buf);
	putenv(cache_name_env_buf);

    if (debug) {
		if (pam_getenv(pamh,"KRB5CCNAME")) 
			DEBLOG("pam_getenv KRB5CCNAME", 
					pam_getenv(pamh,"KRB5CCNAME"));
		if (getenv("KRB5CCNAME")) 
			DEBLOG("getenv KRB5CCNAME",
					getenv("KRB5CCNAME"));
	}
	
	ret = PAM_SUCCESS;

err:
	return ret;
}

--------------060702070100010707020301
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

________________________________________________
Kerberos mailing list           Kerberos@mit.edu
https://mailman.mit.edu/mailman/listinfo/kerberos

--------------060702070100010707020301--

home help back first fref pref prev next nref lref last post