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