auth: Add afsconf_ClientAuthRXGK variants
[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 #include <hcrypto/rand.h>
23
24 #include <rx/rxkad.h>
25 #include <rx/rx.h>
26
27 #include <afs/pthread_glock.h>
28
29 #include "cellconfig.h"
30 #include "keys.h"
31 #include "ktc.h"
32 #include "auth.h"
33
34 #ifdef AFS_RXGK_ENV
35 # include <rx/rxgk.h>
36 #endif
37
38 /* return a null security object if nothing else can be done */
39 static afs_int32
40 QuickAuth(struct rx_securityClass **astr, afs_int32 *aindex)
41 {
42     struct rx_securityClass *tc;
43     tc = rxnull_NewClientSecurityObject();
44     *astr = tc;
45     *aindex = RX_SECIDX_NULL;
46     return 0;
47 }
48
49 static int _afsconf_GetRxkadKrb5Key(void *arock, int kvno, int enctype, void *outkey,
50                                     size_t *keylen)
51 {
52     struct afsconf_dir *adir = arock;
53     struct afsconf_typedKey *kobj;
54     struct rx_opaque *keymat;
55     afsconf_keyType tktype;
56     int tkvno, tenctype;
57     int code;
58
59     code = afsconf_GetKeyByTypes(adir, afsconf_rxkad_krb5, kvno, enctype, &kobj);
60     if (code != 0)
61         return code;
62     afsconf_typedKey_values(kobj, &tktype, &tkvno, &tenctype, &keymat);
63     if (*keylen < keymat->len) {
64         afsconf_typedKey_put(&kobj);
65         return AFSCONF_BADKEY;
66     }
67     memcpy(outkey, keymat->val, keymat->len);
68     *keylen = keymat->len;
69     afsconf_typedKey_put(&kobj);
70     return 0;
71 }
72
73
74 /* Return an appropriate security class and index */
75 afs_int32
76 afsconf_ServerAuth(void *arock,
77                    struct rx_securityClass **astr,
78                    afs_int32 *aindex)
79 {
80     struct afsconf_dir *adir = (struct afsconf_dir *) arock;
81     struct rx_securityClass *tclass;
82
83     LOCK_GLOBAL_MUTEX;
84     tclass = (struct rx_securityClass *)
85         rxkad_NewKrb5ServerSecurityObject(0, adir, afsconf_GetKey,
86                                           _afsconf_GetRxkadKrb5Key, NULL);
87     if (tclass) {
88         *astr = tclass;
89         *aindex = RX_SECIDX_KAD;
90         UNLOCK_GLOBAL_MUTEX;
91         return 0;
92     } else {
93         UNLOCK_GLOBAL_MUTEX;
94         return 2;
95     }
96 }
97
98 static afs_int32
99 GenericAuth(struct afsconf_dir *adir,
100             struct rx_securityClass **astr,
101             afs_int32 *aindex,
102             rxkad_level enclevel)
103 {
104     int enctype_preflist[]={18, 17, 23, 16, 0};
105     char tbuffer[512];
106     struct ktc_encryptionKey key, session;
107     struct rx_securityClass *tclass;
108     afs_int32 kvno;
109     afs_int32 ticketLen;
110     afs_int32 code;
111     int use_krb5=0;
112     struct afsconf_typedKey *kobj;
113     struct rx_opaque *keymat;
114     int *et;
115
116     /* first, find the right key and kvno to use */
117
118     et = enctype_preflist;
119     while(*et != 0) {
120         code = afsconf_GetLatestKeyByTypes(adir, afsconf_rxkad_krb5, *et,
121                                            &kobj);
122         if (code == 0) {
123             afsconf_keyType tktype;
124             int tenctype;
125             afsconf_typedKey_values(kobj, &tktype, &kvno, &tenctype, &keymat);
126             RAND_add(keymat->val, keymat->len, 0.0);
127             use_krb5 = 1;
128             break;
129         }
130         et++;
131     }
132
133     if (use_krb5 == 0) {
134         code = afsconf_GetLatestKey(adir, &kvno, &key);
135         if (code) {
136             return QuickAuth(astr, aindex);
137         }
138         /* next create random session key, using key for seed to good random */
139         DES_init_random_number_generator((DES_cblock *) &key);
140     }
141     code = DES_new_random_key((DES_cblock *) &session);
142     if (code) {
143         if (use_krb5)
144             afsconf_typedKey_put(&kobj);
145         return QuickAuth(astr, aindex);
146     }
147
148     if (use_krb5) {
149         ticketLen = sizeof(tbuffer);
150         memset(tbuffer, '\0', sizeof(tbuffer));
151         code =
152             tkt_MakeTicket5(tbuffer, &ticketLen, *et, &kvno, keymat->val,
153                             keymat->len, AUTH_SUPERUSER, "", "", 0, 0x7fffffff,
154                             &session, "afs", "");
155         afsconf_typedKey_put(&kobj);
156     } else {
157         /* now create the actual ticket */
158         ticketLen = sizeof(tbuffer);
159         memset(tbuffer, '\0', sizeof(tbuffer));
160         code =
161             tkt_MakeTicket(tbuffer, &ticketLen, &key, AUTH_SUPERUSER, "", "", 0,
162                            0xffffffff, &session, 0, "afs", "");
163         /* parms were buffer, ticketlen, key to seal ticket with, principal
164          * name, instance and cell, start time, end time, session key to seal
165          * in ticket, inet host, server name and server instance */
166     }
167     if (code) {
168         return QuickAuth(astr, aindex);
169     }
170
171     /* Next, we have ticket, kvno and session key, authenticate the connection.*/
172     tclass = (struct rx_securityClass *)
173         rxkad_NewClientSecurityObject(enclevel, &session, kvno, ticketLen,
174                                       tbuffer);
175     *astr = tclass;
176     *aindex = RX_SECIDX_KAD;
177     return 0;
178 }
179
180 /* build a fake ticket for 'afs' using keys from adir, returning an
181  * appropriate security class and index
182  */
183 afs_int32
184 afsconf_ClientAuth(void *arock, struct rx_securityClass ** astr,
185                    afs_int32 * aindex)
186 {
187     struct afsconf_dir * adir = (struct afsconf_dir *) arock;
188     afs_int32 rc;
189
190     LOCK_GLOBAL_MUTEX;
191     rc = GenericAuth(adir, astr, aindex, rxkad_clear);
192     UNLOCK_GLOBAL_MUTEX;
193     return rc;
194 }
195
196 /* build a fake ticket for 'afs' using keys from adir, returning an
197  * appropriate security class and index.  This one, unlike the above,
198  * tells rxkad to encrypt the data, too.
199  */
200 afs_int32
201 afsconf_ClientAuthSecure(void *arock,
202                          struct rx_securityClass **astr,
203                          afs_int32 *aindex)
204 {
205     struct afsconf_dir *adir = (struct afsconf_dir *) arock;
206     afs_int32 rc;
207
208     LOCK_GLOBAL_MUTEX;
209     rc = GenericAuth(adir, astr, aindex, rxkad_crypt);
210     UNLOCK_GLOBAL_MUTEX;
211     return rc;
212 }
213
214 /**
215  * Print an rxgk token and make a security class with it
216  *
217  * Print an rxgk token and build a security class from it, returning the
218  * correct index along with the class.
219  *
220  * As with the other ClientAuth variants, fall back to rxnull on errors.
221  * The caller can check the returned aindex if necessary.
222  *
223  * If 'crypt' is nonzero, use the _CRYPT security level. Otherwise, if 'auth'
224  * is nonzero, use the _AUTH security level. Otherwise, use _CLEAR.
225  */
226 static afs_int32
227 _ClientAuthRXGK(void *arock, struct rx_securityClass **aclass,
228                 afs_int32 *aindex, int crypt, int auth)
229 {
230 #ifdef AFS_RXGK_ENV
231     struct rx_securityClass *tclass;
232     struct rx_opaque token = RX_EMPTY_OPAQUE;
233     RXGK_Level level;
234     RXGK_TokenInfo tokeninfo;
235     rxgk_key cell_key = NULL, k0 = NULL;
236     afs_int32 code, kvno, cell_enctype, k0_enctype;
237
238     memset(&tokeninfo, 0, sizeof(tokeninfo));
239
240     if (crypt)
241         level = RXGK_LEVEL_CRYPT;
242     else if (auth)
243         level = RXGK_LEVEL_AUTH;
244     else
245         level = RXGK_LEVEL_CLEAR;
246
247     code = afsconf_GetLatestRXGKKey(arock, &kvno, &cell_enctype, &cell_key);
248     if (code != 0)
249         goto done;
250
251     /* assume that cell_key's enctype works for the our token's k0, too */
252     k0_enctype = cell_enctype;
253
254     tokeninfo.enctype = k0_enctype;
255     tokeninfo.level = level;
256     code = rxgk_print_token_and_key(&token, &tokeninfo, cell_key, kvno,
257                                     cell_enctype, &k0);
258     if (code != 0)
259         goto done;
260     tclass = rxgk_NewClientSecurityObject(level, k0_enctype, k0, &token);
261     if (tclass == NULL)
262         code = RXGK_INCONSISTENCY;
263  done:
264     rxgk_release_key(&cell_key);
265     rxgk_release_key(&k0);
266     rx_opaque_freeContents(&token);
267     if (code != 0)
268         return QuickAuth(aclass, aindex);
269     *aclass = tclass;
270     *aindex = RX_SECIDX_GK;
271     return code;
272 #else   /* AFS_RXGK_ENV */
273     return QuickAuth(aclass, aindex);
274 #endif  /* !AFS_RXGK_ENV */
275 }
276
277 afs_int32
278 afsconf_ClientAuthRXGKClear(void *arock, struct rx_securityClass **aclass,
279                             afs_int32 *aindex)
280 {
281     return _ClientAuthRXGK(arock, aclass, aindex, 0, 0);
282 }
283
284 afs_int32
285 afsconf_ClientAuthRXGKAuth(void *arock, struct rx_securityClass **aclass,
286                             afs_int32 *aindex)
287 {
288     return _ClientAuthRXGK(arock, aclass, aindex, 0, 1);
289 }
290
291 afs_int32
292 afsconf_ClientAuthRXGKCrypt(void *arock, struct rx_securityClass **aclass,
293                             afs_int32 *aindex)
294 {
295     return _ClientAuthRXGK(arock, aclass, aindex, 1, 0);
296 }
297
298 /*!
299  * Build a security class from the user's current tokens
300  *
301  * This function constructs an RX security class from a user's current
302  * tokens.
303  *
304  * @param[in] info      The cell information structure
305  * @param[in] flags     Security flags describing the desired mechanism
306  * @param[out] sc       The selected security class
307  * @param[out] scIndex  The index of the selected class
308  * @parma[out] expires  The expiry time of the tokens used to build the class
309  *
310  * Only the AFSCONF_SECOPTS_ALWAYSENCRYPT flag will modify the behaviour of
311  * this function - it determines whether a cleartext, or encrypting, security
312  * class is provided.
313  *
314  * @return
315  *     0 on success, non-zero on failure. An error code of
316  *     AFSCONF_NO_SECURITY_CLASS indicates that were were unable to build a
317  *     security class using the selected tokens.
318  */
319
320 afs_int32
321 afsconf_ClientAuthToken(struct afsconf_cell *info,
322                         afsconf_secflags flags,
323                         struct rx_securityClass **sc,
324                         afs_int32 *scIndex,
325                         time_t *expires)
326 {
327     struct ktc_setTokenData *tokenSet = NULL;
328     struct ktc_token ttoken;
329     int encryptLevel;
330     afs_int32 code;
331
332     *sc = NULL;
333     *scIndex = RX_SECIDX_NULL;
334
335     if ((flags & AFSCONF_SECOPTS_RXGK)) {
336         /* We don't support non-printed rxgk tokens yet */
337         code = AFSCONF_NO_SECURITY_CLASS;
338         goto out;
339     }
340
341     code = ktc_GetTokenEx(info->name, &tokenSet);
342     if (code)
343         goto out;
344
345     code = token_extractRxkad(tokenSet, &ttoken, NULL, NULL);
346     if (code == 0) {
347         /* XXX - We should think about how to handle this */
348         if (ttoken.kvno < 0 || ttoken.kvno > 256) {
349              fprintf(stderr,
350                     "funny kvno (%d) in ticket, proceeding\n",
351                     ttoken.kvno);
352         }
353         if (flags & AFSCONF_SECOPTS_ALWAYSENCRYPT)
354             encryptLevel = rxkad_crypt;
355         else
356             encryptLevel = rxkad_clear;
357         *sc = rxkad_NewClientSecurityObject(encryptLevel,
358                                             &ttoken.sessionKey,
359                                             ttoken.kvno,
360                                             ttoken.ticketLen,
361                                             ttoken.ticket);
362         *scIndex = RX_SECIDX_KAD;
363         if (expires)
364             *expires = ttoken.endTime;
365     }
366
367 out:
368     token_FreeSet(&tokenSet);
369
370     if (*sc == NULL)
371         return AFSCONF_NO_SECURITY_CLASS;
372
373     return code;
374 }
375
376 /*!
377  * Set the security flags to be used for a particular configuration
378  */
379 void
380 afsconf_SetSecurityFlags(struct afsconf_dir *dir,
381                          afsconf_secflags flags)
382 {
383     dir->securityFlags = flags;
384 }
385
386 /*!
387  * Build a set of security classes suitable for a server accepting
388  * incoming connections
389  */
390 void
391 afsconf_BuildServerSecurityObjects(void *rock,
392                                    struct rx_securityClass ***classes,
393                                    afs_int32 *numClasses)
394 {
395     struct afsconf_dir *dir = rock;
396
397     *numClasses = RX_SECIDX_GK+1;
398
399     *classes = calloc(*numClasses, sizeof(**classes));
400
401     (*classes)[RX_SECIDX_NULL] = rxnull_NewServerSecurityObject();
402     (*classes)[RX_SECIDX_KAD] =
403         rxkad_NewKrb5ServerSecurityObject(0, dir, afsconf_GetKey,
404                                           _afsconf_GetRxkadKrb5Key, NULL);
405
406     if (dir->securityFlags & AFSCONF_SECOPTS_ALWAYSENCRYPT)
407         (*classes)[RX_SECIDX_KAE] =
408             rxkad_NewKrb5ServerSecurityObject(rxkad_crypt, dir, afsconf_GetKey,
409                                               _afsconf_GetRxkadKrb5Key, NULL);
410 #ifdef AFS_RXGK_ENV
411     (*classes)[RX_SECIDX_GK] =
412         rxgk_NewServerSecurityObject(rock, afsconf_GetRXGKKey);
413 #endif
414 }
415
416 /*!
417  * Pick a security class to use for an outgoing connection
418  *
419  * This function selects an RX security class to use for an outgoing
420  * connection, based on the set of security flags provided.
421  *
422  * @param[in] dir
423  *      The configuration directory structure for this cell. If NULL,
424  *      no classes requiring local configuration will be returned.
425  * @param[in] flags
426  *      A set of flags to determine the properties of the security class which
427  *      is selected
428  *      - AFSCONF_SECOPTS_NOAUTH - return an anonymous secirty class
429  *      - AFSCONF_SECOPTS_LOCALAUTH - use classes which have local key
430  *              material available.
431  *      - AFSCONF_SECOPTS_ALWAYSENCRYPT - use classes in encrypting, rather
432  *              than authentication or integrity modes.
433  *      - AFSCONF_SECOPTS_FALLBACK_NULL - if no suitable class can be found,
434  *              then fallback to the rxnull security class.
435  *      - AFSCONF_SECOPTS_NEVERENCRYPT - avoid encrypting classes (currently
436  *              only valid with _RXGK)
437  *      - AFSCONF_SECOPTS_ALWAYSCLEAR - avoid encrypting or authenticating
438  *              classes (always use "clear" security classes) (currently
439  *              only valid with _RXGK)
440  *      - AFSCONF_SECOPTS_RXGK - only use rxgk security classes (currently
441  *              only valid with _LOCALAUTH)
442  * @param[in] info
443  *      The cell information structure for the current cell. If this is NULL,
444  *      then use a version locally obtained using the cellName.
445  * @param[in] cellName
446  *      The cellName to use when obtaining cell information (may be NULL if
447  *      info is specified)
448  * @param[out] sc
449  *      The selected security class
450  * @param[out] scIndex
451  *      The index of the selected security class
452  * @param[out] expires
453  *      The expiry time of the tokens used to construct the class. Will be
454  *      NEVER_DATE if the class has an unlimited lifetime. If NULL, the
455  *      function won't store the expiry date.
456  *
457  * @return
458  *      Returns 0 on success, or a com_err error code on failure.
459  */
460 afs_int32
461 afsconf_PickClientSecObj(struct afsconf_dir *dir, afsconf_secflags flags,
462                          struct afsconf_cell *info,
463                          char *cellName, struct rx_securityClass **sc,
464                          afs_int32 *scIndex, time_t *expires) {
465     struct afsconf_cell localInfo;
466     afs_int32 code = 0;
467
468     *sc = NULL;
469     *scIndex = RX_SECIDX_NULL;
470     if (expires)
471         *expires = 0;
472
473     if ( !(flags & AFSCONF_SECOPTS_NOAUTH) ) {
474         if (!dir)
475             return AFSCONF_NOCELLDB;
476
477         if (flags & AFSCONF_SECOPTS_LOCALAUTH) {
478             if ((flags & AFSCONF_SECOPTS_RXGK)) {
479                 if ((flags & AFSCONF_SECOPTS_ALWAYSCLEAR))
480                     code = afsconf_ClientAuthRXGKClear(dir, sc, scIndex);
481                 else if ((flags & AFSCONF_SECOPTS_NEVERENCRYPT))
482                     code = afsconf_ClientAuthRXGKAuth(dir, sc, scIndex);
483                 else
484                     code = afsconf_ClientAuthRXGKCrypt(dir, sc, scIndex);
485
486             } else if (flags & AFSCONF_SECOPTS_ALWAYSENCRYPT)
487                 code = afsconf_ClientAuthSecure(dir, sc, scIndex);
488             else
489                 code = afsconf_ClientAuth(dir, sc, scIndex);
490
491             if (code)
492                 goto out;
493
494             /* The afsconf_ClientAuth functions will fall back to giving
495              * a rxnull object, which we don't want if localauth has been
496              * explicitly requested. Check for this, and bail out if we
497              * get one. Note that this leaks a security object at present
498              */
499             if (!(flags & AFSCONF_SECOPTS_FALLBACK_NULL) &&
500                 *scIndex == RX_SECIDX_NULL) {
501                 sc = NULL;
502                 code = AFSCONF_NOTFOUND;
503                 goto out;
504             }
505
506             if (expires)
507                 *expires = NEVERDATE;
508         } else {
509             if (info == NULL) {
510                 code = afsconf_GetCellInfo(dir, cellName, NULL, &localInfo);
511                 if (code)
512                     goto out;
513                 info = &localInfo;
514             }
515
516             code = afsconf_ClientAuthToken(info, flags, sc, scIndex, expires);
517             if (code && !(flags & AFSCONF_SECOPTS_FALLBACK_NULL))
518                 goto out;
519
520             /* If we didn't get a token, we'll just run anonymously */
521             code = 0;
522         }
523     }
524     if (*sc == NULL) {
525         *sc = rxnull_NewClientSecurityObject();
526         *scIndex = RX_SECIDX_NULL;
527         if (expires)
528             *expires = NEVERDATE;
529     }
530
531 out:
532     return code;
533 }