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