Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / auth / authcon.c
CommitLineData
805e021f
CE
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/* return a null security object if nothing else can be done */
35static afs_int32
36QuickAuth(struct rx_securityClass **astr, afs_int32 *aindex)
37{
38 struct rx_securityClass *tc;
39 tc = rxnull_NewClientSecurityObject();
40 *astr = tc;
41 *aindex = RX_SECIDX_NULL;
42 return 0;
43}
44
45static 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 */
71afs_int32
72afsconf_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
94static afs_int32
95GenericAuth(struct afsconf_dir *adir,
96 struct rx_securityClass **astr,
97 afs_int32 *aindex,
98 rxkad_level enclevel)
99{
100 int enctype_preflist[]={18, 17, 23, 16, 0};
101 char tbuffer[512];
102 struct ktc_encryptionKey key, session;
103 struct rx_securityClass *tclass;
104 afs_int32 kvno;
105 afs_int32 ticketLen;
106 afs_int32 code;
107 int use_krb5=0;
108 struct afsconf_typedKey *kobj;
109 struct rx_opaque *keymat;
110 int *et;
111
112 /* first, find the right key and kvno to use */
113
114 et = enctype_preflist;
115 while(*et != 0) {
116 code = afsconf_GetLatestKeyByTypes(adir, afsconf_rxkad_krb5, *et,
117 &kobj);
118 if (code == 0) {
119 afsconf_keyType tktype;
120 int tenctype;
121 afsconf_typedKey_values(kobj, &tktype, &kvno, &tenctype, &keymat);
122 RAND_add(keymat->val, keymat->len, 0.0);
123 use_krb5 = 1;
124 break;
125 }
126 et++;
127 }
128
129 if (use_krb5 == 0) {
130 code = afsconf_GetLatestKey(adir, &kvno, &key);
131 if (code) {
132 return QuickAuth(astr, aindex);
133 }
134 /* next create random session key, using key for seed to good random */
135 DES_init_random_number_generator((DES_cblock *) &key);
136 }
137 code = DES_new_random_key((DES_cblock *) &session);
138 if (code) {
139 if (use_krb5)
140 afsconf_typedKey_put(&kobj);
141 return QuickAuth(astr, aindex);
142 }
143
144 if (use_krb5) {
145 ticketLen = sizeof(tbuffer);
146 memset(tbuffer, '\0', sizeof(tbuffer));
147 code =
148 tkt_MakeTicket5(tbuffer, &ticketLen, *et, &kvno, keymat->val,
149 keymat->len, AUTH_SUPERUSER, "", "", 0, 0x7fffffff,
150 &session, "afs", "");
151 afsconf_typedKey_put(&kobj);
152 } else {
153 /* now create the actual ticket */
154 ticketLen = sizeof(tbuffer);
155 memset(tbuffer, '\0', sizeof(tbuffer));
156 code =
157 tkt_MakeTicket(tbuffer, &ticketLen, &key, AUTH_SUPERUSER, "", "", 0,
158 0xffffffff, &session, 0, "afs", "");
159 /* parms were buffer, ticketlen, key to seal ticket with, principal
160 * name, instance and cell, start time, end time, session key to seal
161 * in ticket, inet host, server name and server instance */
162 }
163 if (code) {
164 return QuickAuth(astr, aindex);
165 }
166
167 /* Next, we have ticket, kvno and session key, authenticate the connection.
168 * We use a magic # instead of a constant because of basic compilation
169 * order when compiling the system from scratch (rx/rxkad.h isn't installed
170 * yet). */
171 tclass = (struct rx_securityClass *)
172 rxkad_NewClientSecurityObject(enclevel, &session, kvno, ticketLen,
173 tbuffer);
174 *astr = tclass;
175 *aindex = RX_SECIDX_KAD;
176 return 0;
177}
178
179/* build a fake ticket for 'afs' using keys from adir, returning an
180 * appropriate security class and index
181 */
182afs_int32
183afsconf_ClientAuth(void *arock, struct rx_securityClass ** astr,
184 afs_int32 * aindex)
185{
186 struct afsconf_dir * adir = (struct afsconf_dir *) arock;
187 afs_int32 rc;
188
189 LOCK_GLOBAL_MUTEX;
190 rc = GenericAuth(adir, astr, aindex, rxkad_clear);
191 UNLOCK_GLOBAL_MUTEX;
192 return rc;
193}
194
195/* build a fake ticket for 'afs' using keys from adir, returning an
196 * appropriate security class and index. This one, unlike the above,
197 * tells rxkad to encrypt the data, too.
198 */
199afs_int32
200afsconf_ClientAuthSecure(void *arock,
201 struct rx_securityClass **astr,
202 afs_int32 *aindex)
203{
204 struct afsconf_dir *adir = (struct afsconf_dir *) arock;
205 afs_int32 rc;
206
207 LOCK_GLOBAL_MUTEX;
208 rc = GenericAuth(adir, astr, aindex, rxkad_crypt);
209 UNLOCK_GLOBAL_MUTEX;
210 return rc;
211}
212
213/*!
214 * Build a security class from the user's current tokens
215 *
216 * This function constructs an RX security class from a user's current
217 * tokens.
218 *
219 * @param[in] info The cell information structure
220 * @param[in] flags Security flags describing the desired mechanism
221 * @param[out] sc The selected security class
222 * @param[out] scIndex The index of the selected class
223 * @parma[out] expires The expiry time of the tokens used to build the class
224 *
225 * Only the AFSCONF_SECOPTS_ALWAYSENCRYPT flag will modify the behaviour of
226 * this function - it determines whether a cleartext, or encrypting, security
227 * class is provided.
228 *
229 * @return
230 * 0 on success, non-zero on failure. An error code of
231 * AFSCONF_NO_SECURITY_CLASS indicates that were were unable to build a
232 * security class using the selected tokens.
233 */
234
235afs_int32
236afsconf_ClientAuthToken(struct afsconf_cell *info,
237 afsconf_secflags flags,
238 struct rx_securityClass **sc,
239 afs_int32 *scIndex,
240 time_t *expires)
241{
242 struct ktc_setTokenData *tokenSet = NULL;
243 struct ktc_token ttoken;
244 int encryptLevel;
245 afs_int32 code;
246
247 *sc = NULL;
248 *scIndex = RX_SECIDX_NULL;
249
250 code = ktc_GetTokenEx(info->name, &tokenSet);
251 if (code)
252 goto out;
253
254 code = token_extractRxkad(tokenSet, &ttoken, NULL, NULL);
255 if (code == 0) {
256 /* XXX - We should think about how to handle this */
257 if (ttoken.kvno < 0 || ttoken.kvno > 256) {
258 fprintf(stderr,
259 "funny kvno (%d) in ticket, proceeding\n",
260 ttoken.kvno);
261 }
262 if (flags & AFSCONF_SECOPTS_ALWAYSENCRYPT)
263 encryptLevel = rxkad_crypt;
264 else
265 encryptLevel = rxkad_clear;
266 *sc = rxkad_NewClientSecurityObject(encryptLevel,
267 &ttoken.sessionKey,
268 ttoken.kvno,
269 ttoken.ticketLen,
270 ttoken.ticket);
271 *scIndex = RX_SECIDX_KAD;
272 if (expires)
273 *expires = ttoken.endTime;
274 }
275
276out:
277 token_FreeSet(&tokenSet);
278
279 if (*sc == NULL)
280 return AFSCONF_NO_SECURITY_CLASS;
281
282 return code;
283}
284
285/*!
286 * Set the security flags to be used for a particular configuration
287 */
288void
289afsconf_SetSecurityFlags(struct afsconf_dir *dir,
290 afsconf_secflags flags)
291{
292 dir->securityFlags = flags;
293}
294
295/*!
296 * Build a set of security classes suitable for a server accepting
297 * incoming connections
298 */
299void
300afsconf_BuildServerSecurityObjects(void *rock,
301 struct rx_securityClass ***classes,
302 afs_int32 *numClasses)
303{
304 struct afsconf_dir *dir = rock;
305
306 if (dir->securityFlags & AFSCONF_SECOPTS_ALWAYSENCRYPT)
307 *numClasses = 4;
308 else
309 *numClasses = 3;
310
311 *classes = calloc(*numClasses, sizeof(**classes));
312
313 (*classes)[RX_SECIDX_NULL] = rxnull_NewServerSecurityObject();
314 (*classes)[RX_SECIDX_VAB] = NULL;
315 (*classes)[RX_SECIDX_KAD] =
316 rxkad_NewKrb5ServerSecurityObject(0, dir, afsconf_GetKey,
317 _afsconf_GetRxkadKrb5Key, NULL);
318
319 if (dir->securityFlags & AFSCONF_SECOPTS_ALWAYSENCRYPT)
320 (*classes)[RX_SECIDX_KAE] =
321 rxkad_NewKrb5ServerSecurityObject(rxkad_crypt, dir, afsconf_GetKey,
322 _afsconf_GetRxkadKrb5Key, NULL);
323}
324
325/*!
326 * Pick a security class to use for an outgoing connection
327 *
328 * This function selects an RX security class to use for an outgoing
329 * connection, based on the set of security flags provided.
330 *
331 * @param[in] dir
332 * The configuration directory structure for this cell. If NULL,
333 * no classes requiring local configuration will be returned.
334 * @param[in] flags
335 * A set of flags to determine the properties of the security class which
336 * is selected
337 * - AFSCONF_SECOPTS_NOAUTH - return an anonymous secirty class
338 * - AFSCONF_SECOPTS_LOCALAUTH - use classes which have local key
339 * material available.
340 * - AFSCONF_SECOPTS_ALWAYSENCRYPT - use classes in encrypting, rather
341 * than authentication or integrity modes.
342 * - AFSCONF_SECOPTS_FALLBACK_NULL - if no suitable class can be found,
343 * then fallback to the rxnull security class.
344 * @param[in] info
345 * The cell information structure for the current cell. If this is NULL,
346 * then use a version locally obtained using the cellName.
347 * @param[in] cellName
348 * The cellName to use when obtaining cell information (may be NULL if
349 * info is specified)
350 * @param[out] sc
351 * The selected security class
352 * @param[out] scIndex
353 * The index of the selected security class
354 * @param[out] expires
355 * The expiry time of the tokens used to construct the class. Will be
356 * NEVER_DATE if the class has an unlimited lifetime. If NULL, the
357 * function won't store the expiry date.
358 *
359 * @return
360 * Returns 0 on success, or a com_err error code on failure.
361 */
362afs_int32
363afsconf_PickClientSecObj(struct afsconf_dir *dir, afsconf_secflags flags,
364 struct afsconf_cell *info,
365 char *cellName, struct rx_securityClass **sc,
366 afs_int32 *scIndex, time_t *expires) {
367 struct afsconf_cell localInfo;
368 afs_int32 code = 0;
369
370 *sc = NULL;
371 *scIndex = RX_SECIDX_NULL;
372 if (expires)
373 *expires = 0;
374
375 if ( !(flags & AFSCONF_SECOPTS_NOAUTH) ) {
376 if (!dir)
377 return AFSCONF_NOCELLDB;
378
379 if (flags & AFSCONF_SECOPTS_LOCALAUTH) {
380 if (flags & AFSCONF_SECOPTS_ALWAYSENCRYPT)
381 code = afsconf_ClientAuthSecure(dir, sc, scIndex);
382 else
383 code = afsconf_ClientAuth(dir, sc, scIndex);
384
385 if (code)
386 goto out;
387
388 /* The afsconf_ClientAuth functions will fall back to giving
389 * a rxnull object, which we don't want if localauth has been
390 * explicitly requested. Check for this, and bail out if we
391 * get one. Note that this leaks a security object at present
392 */
393 if (!(flags & AFSCONF_SECOPTS_FALLBACK_NULL) &&
394 *scIndex == RX_SECIDX_NULL) {
395 sc = NULL;
396 code = AFSCONF_NOTFOUND;
397 goto out;
398 }
399
400 if (expires)
401 *expires = NEVERDATE;
402 } else {
403 if (info == NULL) {
404 code = afsconf_GetCellInfo(dir, cellName, NULL, &localInfo);
405 if (code)
406 goto out;
407 info = &localInfo;
408 }
409
410 code = afsconf_ClientAuthToken(info, flags, sc, scIndex, expires);
411 if (code && !(flags & AFSCONF_SECOPTS_FALLBACK_NULL))
412 goto out;
413
414 /* If we didn't get a token, we'll just run anonymously */
415 code = 0;
416 }
417 }
418 if (*sc == NULL) {
419 *sc = rxnull_NewClientSecurityObject();
420 *scIndex = RX_SECIDX_NULL;
421 if (expires)
422 *expires = NEVERDATE;
423 }
424
425out:
426 return code;
427}