auth: remove stale "magic number" comment
[openafs.git] / src / auth / authcon.c
index a462ad9..aa29f79 100644 (file)
 /*
  * 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 <afsconfig.h>
-#if defined(UKERNEL)
-#include "../afs/param.h"
-#else
 #include <afs/param.h>
-#endif
-
-RCSID("$Header$");
-
-#if defined(UKERNEL)
-#include "../afs/sysincludes.h"
-#include "../afs/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 <afs/stds.h>
-#include <afs/pthread_glock.h>
-#include <sys/types.h>
-#ifdef AFS_NT40_ENV
-#include <winsock2.h>
-#else
-#include <sys/file.h>
-#include <sys/time.h>
-#include <netinet/in.h>
-#include <netdb.h>
+
+#include <roken.h>
+
+#ifdef IGNORE_SOME_GCC_WARNINGS
+# pragma GCC diagnostic warning "-Wdeprecated-declarations"
 #endif
-#include <des.h>
+
+#define HC_DEPRECATED
+#include <hcrypto/des.h>
+#include <hcrypto/rand.h>
+
 #include <rx/rxkad.h>
 #include <rx/rx.h>
+
+#include <afs/pthread_glock.h>
+
 #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; {
-    register struct rx_securityClass *tc;
+static afs_int32
+QuickAuth(struct rx_securityClass **astr, afs_int32 *aindex)
+{
+    struct rx_securityClass *tc;
     tc = rxnull_NewClientSecurityObject();
     *astr = tc;
-    *aindex = 0;
+    *aindex = RX_SECIDX_NULL;
     return 0;
 }
 
-#if !defined(UKERNEL)
+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;
+}
+
+
 /* 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; {
-    register struct rx_securityClass *tclass;
-    
-    LOCK_GLOBAL_MUTEX
+afs_int32
+afsconf_ServerAuth(void *arock,
+                  struct rx_securityClass **astr,
+                  afs_int32 *aindex)
+{
+    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);
+       rxkad_NewKrb5ServerSecurityObject(0, adir, afsconf_GetKey,
+                                         _afsconf_GetRxkadKrb5Key, NULL);
     if (tclass) {
        *astr = tclass;
-       *aindex = 2;    /* kerberos security index */
-       UNLOCK_GLOBAL_MUTEX
+       *aindex = RX_SECIDX_KAD;
+       UNLOCK_GLOBAL_MUTEX;
        return 0;
-    }
-    else {
-       UNLOCK_GLOBAL_MUTEX
+    } else {
+       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; {
-    char tbuffer[256];
+
+static afs_int32
+GenericAuth(struct afsconf_dir *adir,
+           struct rx_securityClass **astr,
+           afs_int32 *aindex,
+           rxkad_level enclevel)
+{
+    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++;
+    }
+
+    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);
     }
-    
-    /* next create random session key, using key for seed to good random */
-    des_init_random_number_generator (&key);
-    code = des_random_key (&session);
+    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);
-    code = tkt_MakeTicket(tbuffer, &ticketLen, &key, AUTH_SUPERUSER, "", "", 0,
+
+    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 */
+       /* 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);
+       rxkad_NewClientSecurityObject(enclevel, &session, kvno, ticketLen,
+                                     tbuffer);
     *astr = tclass;
-    *aindex = 2;    /* kerberos security index */
+    *aindex = RX_SECIDX_KAD;
     return 0;
 }
 
 /* build a fake ticket for 'afs' using keys from adir, returning an
  * appropriate security class and index
  */
-afs_int32 afsconf_ClientAuth(struct afsconf_dir *adir, 
-       struct rx_securityClass **astr, afs_int32 *aindex)
+afs_int32
+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
+    LOCK_GLOBAL_MUTEX;
     rc = GenericAuth(adir, astr, aindex, rxkad_clear);
-    UNLOCK_GLOBAL_MUTEX
+    UNLOCK_GLOBAL_MUTEX;
     return rc;
 }
 
@@ -149,15 +193,232 @@ afs_int32 afsconf_ClientAuth(struct afsconf_dir *adir,
  * appropriate security class and index.  This one, unlike the above,
  * 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; {
+afs_int32
+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
+    LOCK_GLOBAL_MUTEX;
     rc = GenericAuth(adir, astr, aindex, rxkad_crypt);
-    UNLOCK_GLOBAL_MUTEX
+    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;
+}