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