Use rfc3961 library to decrypt kerberos 5 tickets
[openafs.git] / src / auth / authcon.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12 #include <afs/stds.h>
13
14 #include <roken.h>
15
16 #ifdef IGNORE_SOME_GCC_WARNINGS
17 # pragma GCC diagnostic warning "-Wdeprecated-declarations"
18 #endif
19
20 #define HC_DEPRECATED
21 #include <hcrypto/des.h>
22
23 #include <rx/rxkad.h>
24 #include <rx/rx.h>
25
26 #include <afs/pthread_glock.h>
27
28 #include "cellconfig.h"
29 #include "keys.h"
30 #include "ktc.h"
31 #include "auth.h"
32
33 /* return a null security object if nothing else can be done */
34 static afs_int32
35 QuickAuth(struct rx_securityClass **astr, afs_int32 *aindex)
36 {
37     struct rx_securityClass *tc;
38     tc = rxnull_NewClientSecurityObject();
39     *astr = tc;
40     *aindex = RX_SECIDX_NULL;
41     return 0;
42 }
43
44 #if !defined(UKERNEL)
45 static int _afsconf_GetRxkadKrb5Key(void *arock, int kvno, int enctype, void *outkey,
46                                     size_t *keylen)
47 {
48     struct afsconf_dir *adir = arock;
49     struct afsconf_typedKey *kobj;
50     struct rx_opaque *keymat;
51     afsconf_keyType tktype;
52     int tkvno, tenctype;
53     int code;
54
55     code = afsconf_GetKeyByTypes(adir, afsconf_rxkad_krb5, kvno, enctype, &kobj);
56     if (code != 0)
57         return code;
58     afsconf_typedKey_values(kobj, &tktype, &tkvno, &tenctype, &keymat);
59     if (*keylen < keymat->len) {
60         afsconf_typedKey_put(&kobj);
61         return AFSCONF_BADKEY;
62     }
63     memcpy(outkey, keymat->val, keymat->len);
64     *keylen = keymat->len;
65     afsconf_typedKey_put(&kobj);
66     return 0;
67 }
68
69
70 /* Return an appropriate security class and index */
71 afs_int32
72 afsconf_ServerAuth(void *arock,
73                    struct rx_securityClass **astr,
74                    afs_int32 *aindex)
75 {
76     struct afsconf_dir *adir = (struct afsconf_dir *) arock;
77     struct rx_securityClass *tclass;
78
79     LOCK_GLOBAL_MUTEX;
80     tclass = (struct rx_securityClass *)
81         rxkad_NewKrb5ServerSecurityObject(0, adir, afsconf_GetKey,
82                                           _afsconf_GetRxkadKrb5Key, NULL);
83     if (tclass) {
84         *astr = tclass;
85         *aindex = RX_SECIDX_KAD;
86         UNLOCK_GLOBAL_MUTEX;
87         return 0;
88     } else {
89         UNLOCK_GLOBAL_MUTEX;
90         return 2;
91     }
92 }
93 #endif /* !defined(UKERNEL) */
94
95 static afs_int32
96 GenericAuth(struct afsconf_dir *adir,
97             struct rx_securityClass **astr,
98             afs_int32 *aindex,
99             rxkad_level enclevel)
100 {
101     char tbuffer[256];
102     struct ktc_encryptionKey key, session;
103     struct rx_securityClass *tclass;
104     afs_int32 kvno;
105     afs_int32 ticketLen;
106     afs_int32 code;
107
108     /* first, find the right key and kvno to use */
109     code = afsconf_GetLatestKey(adir, &kvno, &key);
110     if (code) {
111         return QuickAuth(astr, aindex);
112     }
113
114     /* next create random session key, using key for seed to good random */
115     DES_init_random_number_generator((DES_cblock *) &key);
116     code = DES_new_random_key((DES_cblock *) &session);
117     if (code) {
118         return QuickAuth(astr, aindex);
119     }
120
121     /* now create the actual ticket */
122     ticketLen = sizeof(tbuffer);
123     memset(tbuffer, '\0', sizeof(tbuffer));
124     code =
125         tkt_MakeTicket(tbuffer, &ticketLen, &key, AUTH_SUPERUSER, "", "", 0,
126                        0xffffffff, &session, 0, "afs", "");
127     /* parms were buffer, ticketlen, key to seal ticket with, principal
128      * name, instance and cell, start time, end time, session key to seal
129      * in ticket, inet host, server name and server instance */
130     if (code) {
131         return QuickAuth(astr, aindex);
132     }
133
134     /* Next, we have ticket, kvno and session key, authenticate the connection.
135      * We use a magic # instead of a constant because of basic compilation
136      * order when compiling the system from scratch (rx/rxkad.h isn't installed
137      * yet). */
138     tclass = (struct rx_securityClass *)
139         rxkad_NewClientSecurityObject(enclevel, &session, kvno, ticketLen,
140                                       tbuffer);
141     *astr = tclass;
142     *aindex = RX_SECIDX_KAD;
143     return 0;
144 }
145
146 /* build a fake ticket for 'afs' using keys from adir, returning an
147  * appropriate security class and index
148  */
149 afs_int32
150 afsconf_ClientAuth(void *arock, struct rx_securityClass ** astr,
151                    afs_int32 * aindex)
152 {
153     struct afsconf_dir * adir = (struct afsconf_dir *) arock;
154     afs_int32 rc;
155
156     LOCK_GLOBAL_MUTEX;
157     rc = GenericAuth(adir, astr, aindex, rxkad_clear);
158     UNLOCK_GLOBAL_MUTEX;
159     return rc;
160 }
161
162 /* build a fake ticket for 'afs' using keys from adir, returning an
163  * appropriate security class and index.  This one, unlike the above,
164  * tells rxkad to encrypt the data, too.
165  */
166 afs_int32
167 afsconf_ClientAuthSecure(void *arock,
168                          struct rx_securityClass **astr,
169                          afs_int32 *aindex)
170 {
171     struct afsconf_dir *adir = (struct afsconf_dir *) arock;
172     afs_int32 rc;
173
174     LOCK_GLOBAL_MUTEX;
175     rc = GenericAuth(adir, astr, aindex, rxkad_crypt);
176     UNLOCK_GLOBAL_MUTEX;
177     return rc;
178 }
179
180 /*!
181  * Build a security class from the user's current tokens
182  *
183  * This function constructs an RX security class from a user's current
184  * tokens.
185  *
186  * @param[in] info      The cell information structure
187  * @param[in] flags     Security flags describing the desired mechanism
188  * @param[out] sc       The selected security class
189  * @param[out] scIndex  The index of the selected class
190  * @parma[out] expires  The expiry time of the tokens used to build the class
191  *
192  * Only the AFSCONF_SECOPTS_ALWAYSENCRYPT flag will modify the behaviour of
193  * this function - it determines whether a cleartext, or encrypting, security
194  * class is provided.
195  *
196  * @return
197  *     0 on success, non-zero on failure. An error code of
198  *     AFSCONF_NO_SECURITY_CLASS indicates that were were unable to build a
199  *     security class using the selected tokens.
200  */
201
202 afs_int32
203 afsconf_ClientAuthToken(struct afsconf_cell *info,
204                         afsconf_secflags flags,
205                         struct rx_securityClass **sc,
206                         afs_int32 *scIndex,
207                         time_t *expires)
208 {
209     struct ktc_setTokenData *tokenSet = NULL;
210     struct ktc_token ttoken;
211     int encryptLevel;
212     afs_int32 code;
213
214     *sc = NULL;
215     *scIndex = RX_SECIDX_NULL;
216
217     code = ktc_GetTokenEx(info->name, &tokenSet);
218     if (code)
219         goto out;
220
221     code = token_extractRxkad(tokenSet, &ttoken, NULL, NULL);
222     if (code == 0) {
223         /* XXX - We should think about how to handle this */
224         if (ttoken.kvno < 0 || ttoken.kvno > 256) {
225              fprintf(stderr,
226                     "funny kvno (%d) in ticket, proceeding\n",
227                     ttoken.kvno);
228         }
229         if (flags & AFSCONF_SECOPTS_ALWAYSENCRYPT)
230             encryptLevel = rxkad_crypt;
231         else
232             encryptLevel = rxkad_clear;
233         *sc = rxkad_NewClientSecurityObject(encryptLevel,
234                                             &ttoken.sessionKey,
235                                             ttoken.kvno,
236                                             ttoken.ticketLen,
237                                             ttoken.ticket);
238         *scIndex = RX_SECIDX_KAD;
239         if (expires)
240             *expires = ttoken.endTime;
241     }
242
243 out:
244     token_FreeSet(&tokenSet);
245
246     if (*sc == NULL)
247         return AFSCONF_NO_SECURITY_CLASS;
248
249     return code;
250 }
251
252 /*!
253  * Set the security flags to be used for a particular configuration
254  */
255 void
256 afsconf_SetSecurityFlags(struct afsconf_dir *dir,
257                          afsconf_secflags flags)
258 {
259     dir->securityFlags = flags;
260 }
261
262 /*!
263  * Build a set of security classes suitable for a server accepting
264  * incoming connections
265  */
266 #if !defined(UKERNEL)
267 void
268 afsconf_BuildServerSecurityObjects(void *rock,
269                                    struct rx_securityClass ***classes,
270                                    afs_int32 *numClasses)
271 {
272     struct afsconf_dir *dir = rock;
273
274     if (dir->securityFlags & AFSCONF_SECOPTS_ALWAYSENCRYPT)
275         *numClasses = 4;
276     else
277         *numClasses = 3;
278
279     *classes = calloc(*numClasses, sizeof(**classes));
280
281     (*classes)[0] = rxnull_NewServerSecurityObject();
282     (*classes)[1] = NULL;
283     (*classes)[2] = rxkad_NewKrb5ServerSecurityObject(0, dir,
284                                                       afsconf_GetKey,
285                                                       _afsconf_GetRxkadKrb5Key,
286                                                       NULL);
287
288     if (dir->securityFlags & AFSCONF_SECOPTS_ALWAYSENCRYPT)
289         (*classes)[3] = rxkad_NewKrb5ServerSecurityObject(rxkad_crypt, dir,
290                                                           afsconf_GetKey,
291                                                           _afsconf_GetRxkadKrb5Key,
292                                                           NULL);
293 }
294 #endif
295
296 /*!
297  * Pick a security class to use for an outgoing connection
298  *
299  * This function selects an RX security class to use for an outgoing
300  * connection, based on the set of security flags provided.
301  *
302  * @param[in] dir
303  *      The configuration directory structure for this cell. If NULL,
304  *      no classes requiring local configuration will be returned.
305  * @param[in] flags
306  *      A set of flags to determine the properties of the security class which
307  *      is selected
308  *      - AFSCONF_SECOPTS_NOAUTH - return an anonymous secirty class
309  *      - AFSCONF_SECOPTS_LOCALAUTH - use classes which have local key
310  *              material available.
311  *      - AFSCONF_SECOPTS_ALWAYSENCRYPT - use classes in encrypting, rather
312  *              than authentication or integrity modes.
313  *      - AFSCONF_SECOPTS_FALLBACK_NULL - if no suitable class can be found,
314  *              then fallback to the rxnull security class.
315  * @param[in] info
316  *      The cell information structure for the current cell. If this is NULL,
317  *      then use a version locally obtained using the cellName.
318  * @param[in] cellName
319  *      The cellName to use when obtaining cell information (may be NULL if
320  *      info is specified)
321  * @param[out] sc
322  *      The selected security class
323  * @param[out] scIndex
324  *      The index of the selected security class
325  * @param[out] expires
326  *      The expiry time of the tokens used to construct the class. Will be
327  *      NEVER_DATE if the class has an unlimited lifetime. If NULL, the
328  *      function won't store the expiry date.
329  *
330  * @return
331  *      Returns 0 on success, or a com_err error code on failure.
332  */
333 afs_int32
334 afsconf_PickClientSecObj(struct afsconf_dir *dir, afsconf_secflags flags,
335                          struct afsconf_cell *info,
336                          char *cellName, struct rx_securityClass **sc,
337                          afs_int32 *scIndex, time_t *expires) {
338     struct afsconf_cell localInfo;
339     afs_int32 code = 0;
340
341     *sc = NULL;
342     *scIndex = RX_SECIDX_NULL;
343     if (expires)
344         *expires = 0;
345
346     if ( !(flags & AFSCONF_SECOPTS_NOAUTH) ) {
347         if (!dir)
348             return AFSCONF_NOCELLDB;
349
350         if (flags & AFSCONF_SECOPTS_LOCALAUTH) {
351             if (flags & AFSCONF_SECOPTS_ALWAYSENCRYPT)
352                 code = afsconf_ClientAuthSecure(dir, sc, scIndex);
353             else
354                 code = afsconf_ClientAuth(dir, sc, scIndex);
355
356             if (code)
357                 goto out;
358
359             /* The afsconf_ClientAuth functions will fall back to giving
360              * a rxnull object, which we don't want if localauth has been
361              * explicitly requested. Check for this, and bail out if we
362              * get one. Note that this leaks a security object at present
363              */
364             if (!(flags & AFSCONF_SECOPTS_FALLBACK_NULL) &&
365                 *scIndex == RX_SECIDX_NULL) {
366                 sc = NULL;
367                 code = AFSCONF_NOTFOUND;
368                 goto out;
369             }
370
371             if (expires)
372                 *expires = NEVERDATE;
373         } else {
374             if (info == NULL) {
375                 code = afsconf_GetCellInfo(dir, cellName, NULL, &localInfo);
376                 if (code)
377                     goto out;
378                 info = &localInfo;
379             }
380
381             code = afsconf_ClientAuthToken(info, flags, sc, scIndex, expires);
382             if (code && !(flags & AFSCONF_SECOPTS_FALLBACK_NULL))
383                 goto out;
384
385             /* If we didn't get a token, we'll just run anonymously */
386             code = 0;
387         }
388     }
389     if (*sc == NULL) {
390         *sc = rxnull_NewClientSecurityObject();
391         *scIndex = RX_SECIDX_NULL;
392         if (expires)
393             *expires = NEVERDATE;
394     }
395
396 out:
397     return code;
398 }