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