X-Git-Url: http://git.openafs.org/?p=openafs.git;a=blobdiff_plain;f=src%2Fauth%2Fauthcon.c;h=aa29f79f90de6efe5dd2c6b30523dc8968b3d18d;hp=029464730e459ff4540bf1467b0ad432c6735069;hb=d0a2889098526aa148d99e042aa8c3f7855565f7;hpb=872bc94f8ce5d38f0a12e7cec455a2cb368b7427 diff --git a/src/auth/authcon.c b/src/auth/authcon.c index 0294647..aa29f79 100644 --- a/src/auth/authcon.c +++ b/src/auth/authcon.c @@ -1,138 +1,175 @@ /* * Copyright 2000, International Business Machines Corporation and others. * All Rights Reserved. - * + * * This software has been released under the terms of the IBM Public * License. For details, see the LICENSE file in the top-level source * directory or online at http://www.openafs.org/dl/license10.html */ #include -#if defined(UKERNEL) -#include "afs/param.h" -#else #include -#endif - -RCSID - ("$Header$"); - -#if defined(UKERNEL) -#include "afs/sysincludes.h" -#include "afsincludes.h" -#include "afs/stds.h" -#include "afs/pthread_glock.h" -#include "des/des.h" -#include "rx/rxkad.h" -#include "rx/rx.h" -#include "afs/cellconfig.h" -#include "afs/keys.h" -#include "afs/auth.h" -#include "afs/pthread_glock.h" -#else /* defined(UKERNEL) */ #include -#include -#include -#ifdef AFS_NT40_ENV -#include -#else -#include -#include -#include -#include + +#include + +#ifdef IGNORE_SOME_GCC_WARNINGS +# pragma GCC diagnostic warning "-Wdeprecated-declarations" #endif -#include + +#define HC_DEPRECATED +#include +#include + #include #include + +#include + #include "cellconfig.h" #include "keys.h" +#include "ktc.h" #include "auth.h" -#endif /* defined(UKERNEL) */ /* return a null security object if nothing else can be done */ static afs_int32 -QuickAuth(astr, aindex) - struct rx_securityClass **astr; - afs_int32 *aindex; +QuickAuth(struct rx_securityClass **astr, afs_int32 *aindex) { - register struct rx_securityClass *tc; + struct rx_securityClass *tc; tc = rxnull_NewClientSecurityObject(); *astr = tc; - *aindex = 0; + *aindex = RX_SECIDX_NULL; + return 0; +} + +static int _afsconf_GetRxkadKrb5Key(void *arock, int kvno, int enctype, void *outkey, + size_t *keylen) +{ + struct afsconf_dir *adir = arock; + struct afsconf_typedKey *kobj; + struct rx_opaque *keymat; + afsconf_keyType tktype; + int tkvno, tenctype; + int code; + + code = afsconf_GetKeyByTypes(adir, afsconf_rxkad_krb5, kvno, enctype, &kobj); + if (code != 0) + return code; + afsconf_typedKey_values(kobj, &tktype, &tkvno, &tenctype, &keymat); + if (*keylen < keymat->len) { + afsconf_typedKey_put(&kobj); + return AFSCONF_BADKEY; + } + memcpy(outkey, keymat->val, keymat->len); + *keylen = keymat->len; + afsconf_typedKey_put(&kobj); return 0; } -#if !defined(UKERNEL) + /* Return an appropriate security class and index */ afs_int32 -afsconf_ServerAuth(adir, astr, aindex) - register struct afsconf_dir *adir; - struct rx_securityClass **astr; - afs_int32 *aindex; +afsconf_ServerAuth(void *arock, + struct rx_securityClass **astr, + afs_int32 *aindex) { - register struct rx_securityClass *tclass; + struct afsconf_dir *adir = (struct afsconf_dir *) arock; + struct rx_securityClass *tclass; - LOCK_GLOBAL_MUTEX tclass = (struct rx_securityClass *) - rxkad_NewServerSecurityObject(0, adir, afsconf_GetKey, NULL); + LOCK_GLOBAL_MUTEX; + tclass = (struct rx_securityClass *) + rxkad_NewKrb5ServerSecurityObject(0, adir, afsconf_GetKey, + _afsconf_GetRxkadKrb5Key, NULL); if (tclass) { *astr = tclass; - *aindex = 2; /* kerberos security index */ - UNLOCK_GLOBAL_MUTEX return 0; + *aindex = RX_SECIDX_KAD; + UNLOCK_GLOBAL_MUTEX; + return 0; } else { - UNLOCK_GLOBAL_MUTEX return 2; + UNLOCK_GLOBAL_MUTEX; + return 2; } } -#endif /* !defined(UKERNEL) */ static afs_int32 -GenericAuth(adir, astr, aindex, enclevel) - struct afsconf_dir *adir; - struct rx_securityClass **astr; - afs_int32 *aindex; - rxkad_level enclevel; +GenericAuth(struct afsconf_dir *adir, + struct rx_securityClass **astr, + afs_int32 *aindex, + rxkad_level enclevel) { - char tbuffer[256]; + int enctype_preflist[]={18, 17, 23, 16, 0}; + char tbuffer[512]; struct ktc_encryptionKey key, session; struct rx_securityClass *tclass; afs_int32 kvno; afs_int32 ticketLen; - register afs_int32 code; + afs_int32 code; + int use_krb5=0; + struct afsconf_typedKey *kobj; + struct rx_opaque *keymat; + int *et; /* first, find the right key and kvno to use */ - code = afsconf_GetLatestKey(adir, &kvno, &key); - if (code) { - return QuickAuth(astr, aindex); + + et = enctype_preflist; + while(*et != 0) { + code = afsconf_GetLatestKeyByTypes(adir, afsconf_rxkad_krb5, *et, + &kobj); + if (code == 0) { + afsconf_keyType tktype; + int tenctype; + afsconf_typedKey_values(kobj, &tktype, &kvno, &tenctype, &keymat); + RAND_add(keymat->val, keymat->len, 0.0); + use_krb5 = 1; + break; + } + et++; } - /* next create random session key, using key for seed to good random */ - des_init_random_number_generator(&key); - code = des_random_key(&session); + if (use_krb5 == 0) { + code = afsconf_GetLatestKey(adir, &kvno, &key); + if (code) { + return QuickAuth(astr, aindex); + } + /* next create random session key, using key for seed to good random */ + DES_init_random_number_generator((DES_cblock *) &key); + } + code = DES_new_random_key((DES_cblock *) &session); if (code) { + if (use_krb5) + afsconf_typedKey_put(&kobj); return QuickAuth(astr, aindex); } - /* now create the actual ticket */ - ticketLen = sizeof(tbuffer); - memset(tbuffer, '\0', sizeof(tbuffer)); - code = - tkt_MakeTicket(tbuffer, &ticketLen, &key, AUTH_SUPERUSER, "", "", 0, - 0xffffffff, &session, 0, "afs", ""); - /* parms were buffer, ticketlen, key to seal ticket with, principal - * name, instance and cell, start time, end time, session key to seal - * in ticket, inet host, server name and server instance */ + if (use_krb5) { + ticketLen = sizeof(tbuffer); + memset(tbuffer, '\0', sizeof(tbuffer)); + code = + tkt_MakeTicket5(tbuffer, &ticketLen, *et, &kvno, keymat->val, + keymat->len, AUTH_SUPERUSER, "", "", 0, 0x7fffffff, + &session, "afs", ""); + afsconf_typedKey_put(&kobj); + } else { + /* now create the actual ticket */ + ticketLen = sizeof(tbuffer); + memset(tbuffer, '\0', sizeof(tbuffer)); + code = + tkt_MakeTicket(tbuffer, &ticketLen, &key, AUTH_SUPERUSER, "", "", 0, + 0xffffffff, &session, 0, "afs", ""); + /* parms were buffer, ticketlen, key to seal ticket with, principal + * name, instance and cell, start time, end time, session key to seal + * in ticket, inet host, server name and server instance */ + } if (code) { return QuickAuth(astr, aindex); } - /* Next, we have ticket, kvno and session key, authenticate the connection. - * We use a magic # instead of a constant because of basic compilation - * order when compiling the system from scratch (rx/rxkad.h isn't installed - * yet). */ + /* Next, we have ticket, kvno and session key, authenticate the connection.*/ tclass = (struct rx_securityClass *) rxkad_NewClientSecurityObject(enclevel, &session, kvno, ticketLen, tbuffer); *astr = tclass; - *aindex = 2; /* kerberos security index */ + *aindex = RX_SECIDX_KAD; return 0; } @@ -140,13 +177,16 @@ GenericAuth(adir, astr, aindex, enclevel) * appropriate security class and index */ afs_int32 -afsconf_ClientAuth(struct afsconf_dir * adir, struct rx_securityClass ** astr, +afsconf_ClientAuth(void *arock, struct rx_securityClass ** astr, afs_int32 * aindex) { + struct afsconf_dir * adir = (struct afsconf_dir *) arock; afs_int32 rc; - LOCK_GLOBAL_MUTEX rc = GenericAuth(adir, astr, aindex, rxkad_clear); - UNLOCK_GLOBAL_MUTEX return rc; + LOCK_GLOBAL_MUTEX; + rc = GenericAuth(adir, astr, aindex, rxkad_clear); + UNLOCK_GLOBAL_MUTEX; + return rc; } /* build a fake ticket for 'afs' using keys from adir, returning an @@ -154,13 +194,231 @@ afsconf_ClientAuth(struct afsconf_dir * adir, struct rx_securityClass ** astr, * tells rxkad to encrypt the data, too. */ afs_int32 -afsconf_ClientAuthSecure(adir, astr, aindex) - struct afsconf_dir *adir; - struct rx_securityClass **astr; - afs_int32 *aindex; +afsconf_ClientAuthSecure(void *arock, + struct rx_securityClass **astr, + afs_int32 *aindex) { + struct afsconf_dir *adir = (struct afsconf_dir *) arock; afs_int32 rc; - LOCK_GLOBAL_MUTEX rc = GenericAuth(adir, astr, aindex, rxkad_crypt); - UNLOCK_GLOBAL_MUTEX return rc; + LOCK_GLOBAL_MUTEX; + rc = GenericAuth(adir, astr, aindex, rxkad_crypt); + UNLOCK_GLOBAL_MUTEX; + return rc; +} + +/*! + * Build a security class from the user's current tokens + * + * This function constructs an RX security class from a user's current + * tokens. + * + * @param[in] info The cell information structure + * @param[in] flags Security flags describing the desired mechanism + * @param[out] sc The selected security class + * @param[out] scIndex The index of the selected class + * @parma[out] expires The expiry time of the tokens used to build the class + * + * Only the AFSCONF_SECOPTS_ALWAYSENCRYPT flag will modify the behaviour of + * this function - it determines whether a cleartext, or encrypting, security + * class is provided. + * + * @return + * 0 on success, non-zero on failure. An error code of + * AFSCONF_NO_SECURITY_CLASS indicates that were were unable to build a + * security class using the selected tokens. + */ + +afs_int32 +afsconf_ClientAuthToken(struct afsconf_cell *info, + afsconf_secflags flags, + struct rx_securityClass **sc, + afs_int32 *scIndex, + time_t *expires) +{ + struct ktc_setTokenData *tokenSet = NULL; + struct ktc_token ttoken; + int encryptLevel; + afs_int32 code; + + *sc = NULL; + *scIndex = RX_SECIDX_NULL; + + code = ktc_GetTokenEx(info->name, &tokenSet); + if (code) + goto out; + + code = token_extractRxkad(tokenSet, &ttoken, NULL, NULL); + if (code == 0) { + /* XXX - We should think about how to handle this */ + if (ttoken.kvno < 0 || ttoken.kvno > 256) { + fprintf(stderr, + "funny kvno (%d) in ticket, proceeding\n", + ttoken.kvno); + } + if (flags & AFSCONF_SECOPTS_ALWAYSENCRYPT) + encryptLevel = rxkad_crypt; + else + encryptLevel = rxkad_clear; + *sc = rxkad_NewClientSecurityObject(encryptLevel, + &ttoken.sessionKey, + ttoken.kvno, + ttoken.ticketLen, + ttoken.ticket); + *scIndex = RX_SECIDX_KAD; + if (expires) + *expires = ttoken.endTime; + } + +out: + token_FreeSet(&tokenSet); + + if (*sc == NULL) + return AFSCONF_NO_SECURITY_CLASS; + + return code; +} + +/*! + * Set the security flags to be used for a particular configuration + */ +void +afsconf_SetSecurityFlags(struct afsconf_dir *dir, + afsconf_secflags flags) +{ + dir->securityFlags = flags; +} + +/*! + * Build a set of security classes suitable for a server accepting + * incoming connections + */ +void +afsconf_BuildServerSecurityObjects(void *rock, + struct rx_securityClass ***classes, + afs_int32 *numClasses) +{ + struct afsconf_dir *dir = rock; + + if (dir->securityFlags & AFSCONF_SECOPTS_ALWAYSENCRYPT) + *numClasses = 4; + else + *numClasses = 3; + + *classes = calloc(*numClasses, sizeof(**classes)); + + (*classes)[RX_SECIDX_NULL] = rxnull_NewServerSecurityObject(); + (*classes)[RX_SECIDX_VAB] = NULL; + (*classes)[RX_SECIDX_KAD] = + rxkad_NewKrb5ServerSecurityObject(0, dir, afsconf_GetKey, + _afsconf_GetRxkadKrb5Key, NULL); + + if (dir->securityFlags & AFSCONF_SECOPTS_ALWAYSENCRYPT) + (*classes)[RX_SECIDX_KAE] = + rxkad_NewKrb5ServerSecurityObject(rxkad_crypt, dir, afsconf_GetKey, + _afsconf_GetRxkadKrb5Key, NULL); +} + +/*! + * Pick a security class to use for an outgoing connection + * + * This function selects an RX security class to use for an outgoing + * connection, based on the set of security flags provided. + * + * @param[in] dir + * The configuration directory structure for this cell. If NULL, + * no classes requiring local configuration will be returned. + * @param[in] flags + * A set of flags to determine the properties of the security class which + * is selected + * - AFSCONF_SECOPTS_NOAUTH - return an anonymous secirty class + * - AFSCONF_SECOPTS_LOCALAUTH - use classes which have local key + * material available. + * - AFSCONF_SECOPTS_ALWAYSENCRYPT - use classes in encrypting, rather + * than authentication or integrity modes. + * - AFSCONF_SECOPTS_FALLBACK_NULL - if no suitable class can be found, + * then fallback to the rxnull security class. + * @param[in] info + * The cell information structure for the current cell. If this is NULL, + * then use a version locally obtained using the cellName. + * @param[in] cellName + * The cellName to use when obtaining cell information (may be NULL if + * info is specified) + * @param[out] sc + * The selected security class + * @param[out] scIndex + * The index of the selected security class + * @param[out] expires + * The expiry time of the tokens used to construct the class. Will be + * NEVER_DATE if the class has an unlimited lifetime. If NULL, the + * function won't store the expiry date. + * + * @return + * Returns 0 on success, or a com_err error code on failure. + */ +afs_int32 +afsconf_PickClientSecObj(struct afsconf_dir *dir, afsconf_secflags flags, + struct afsconf_cell *info, + char *cellName, struct rx_securityClass **sc, + afs_int32 *scIndex, time_t *expires) { + struct afsconf_cell localInfo; + afs_int32 code = 0; + + *sc = NULL; + *scIndex = RX_SECIDX_NULL; + if (expires) + *expires = 0; + + if ( !(flags & AFSCONF_SECOPTS_NOAUTH) ) { + if (!dir) + return AFSCONF_NOCELLDB; + + if (flags & AFSCONF_SECOPTS_LOCALAUTH) { + if (flags & AFSCONF_SECOPTS_ALWAYSENCRYPT) + code = afsconf_ClientAuthSecure(dir, sc, scIndex); + else + code = afsconf_ClientAuth(dir, sc, scIndex); + + if (code) + goto out; + + /* The afsconf_ClientAuth functions will fall back to giving + * a rxnull object, which we don't want if localauth has been + * explicitly requested. Check for this, and bail out if we + * get one. Note that this leaks a security object at present + */ + if (!(flags & AFSCONF_SECOPTS_FALLBACK_NULL) && + *scIndex == RX_SECIDX_NULL) { + sc = NULL; + code = AFSCONF_NOTFOUND; + goto out; + } + + if (expires) + *expires = NEVERDATE; + } else { + if (info == NULL) { + code = afsconf_GetCellInfo(dir, cellName, NULL, &localInfo); + if (code) + goto out; + info = &localInfo; + } + + code = afsconf_ClientAuthToken(info, flags, sc, scIndex, expires); + if (code && !(flags & AFSCONF_SECOPTS_FALLBACK_NULL)) + goto out; + + /* If we didn't get a token, we'll just run anonymously */ + code = 0; + } + } + if (*sc == NULL) { + *sc = rxnull_NewClientSecurityObject(); + *scIndex = RX_SECIDX_NULL; + if (expires) + *expires = NEVERDATE; + } + +out: + return code; }