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