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