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