afsconf: Rework security flags
[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  * Set the security flags to be used for a particular configuration
239  */
240 void
241 afsconf_SetSecurityFlags(struct afsconf_dir *dir,
242                          afsconf_secflags flags)
243 {
244     dir->securityFlags = flags;
245 }
246
247 /*!
248  * Build a set of security classes suitable for a server accepting
249  * incoming connections
250  */
251 #if !defined(UKERNEL)
252 void
253 afsconf_BuildServerSecurityObjects(void *rock,
254                                    struct rx_securityClass ***classes,
255                                    afs_int32 *numClasses)
256 {
257     struct afsconf_dir *dir = rock;
258
259     if (dir->securityFlags & AFSCONF_SECOPTS_ALWAYSENCRYPT)
260         *numClasses = 4;
261     else
262         *numClasses = 3;
263
264     *classes = calloc(*numClasses, sizeof(**classes));
265
266     (*classes)[0] = rxnull_NewServerSecurityObject();
267     (*classes)[1] = NULL;
268     (*classes)[2] = rxkad_NewServerSecurityObject(0, dir,
269                                                   afsconf_GetKey, NULL);
270
271     if (dir->securityFlags & AFSCONF_SECOPTS_ALWAYSENCRYPT)
272         (*classes)[3] = rxkad_NewServerSecurityObject(rxkad_crypt, dir,
273                                                       afsconf_GetKey, NULL);
274 }
275 #endif
276
277 /*!
278  * Pick a security class to use for an outgoing connection
279  *
280  * This function selects an RX security class to use for an outgoing
281  * connection, based on the set of security flags provided.
282  *
283  * @param[in] dir
284  *      The configuration directory structure for this cell. If NULL,
285  *      no classes requiring local configuration will be returned.
286  * @param[in] flags
287  *      A set of flags to determine the properties of the security class which
288  *      is selected
289  *      - AFSCONF_SECOPTS_NOAUTH - return an anonymous secirty class
290  *      - AFSCONF_SECOPTS_LOCALAUTH - use classes which have local key
291  *              material available.
292  *      - AFSCONF_SECOPTS_ALWAYSENCRYPT - use classes in encrypting, rather
293  *              than authentication or integrity modes.
294  *      - AFSCONF_SECOPTS_FALLBACK_NULL - if no suitable class can be found,
295  *              then fallback to the rxnull security class.
296  * @param[in] info
297  *      The cell information structure for the current cell. If this is NULL,
298  *      then use a version locally obtained using the cellName.
299  * @param[in] cellName
300  *      The cellName to use when obtaining cell information (may be NULL if
301  *      info is specified)
302  * @param[out] sc
303  *      The selected security class
304  * @param[out] scIndex
305  *      The index of the selected security class
306  * @param[out] expires
307  *      The expiry time of the tokens used to construct the class. Will be
308  *      NEVER_DATE if the class has an unlimited lifetime. If NULL, the
309  *      function won't store the expiry date.
310  *
311  * @return
312  *      Returns 0 on success, or a com_err error code on failure.
313  */
314 afs_int32
315 afsconf_PickClientSecObj(struct afsconf_dir *dir, afsconf_secflags flags,
316                          struct afsconf_cell *info,
317                          char *cellName, struct rx_securityClass **sc,
318                          afs_int32 *scIndex, time_t *expires) {
319     struct afsconf_cell localInfo;
320     afs_int32 code = 0;
321
322     *sc = NULL;
323     *scIndex = RX_SECIDX_NULL;
324     if (expires)
325         *expires = 0;
326
327     if ( !(flags & AFSCONF_SECOPTS_NOAUTH) ) {
328         if (!dir)
329             return AFSCONF_NOCELLDB;
330
331         if (flags & AFSCONF_SECOPTS_LOCALAUTH) {
332             if (flags & AFSCONF_SECOPTS_ALWAYSENCRYPT)
333                 code = afsconf_ClientAuthSecure(dir, sc, scIndex);
334             else
335                 code = afsconf_ClientAuth(dir, sc, scIndex);
336
337             if (code)
338                 goto out;
339
340             /* The afsconf_ClientAuth functions will fall back to giving
341              * a rxnull object, which we don't want if localauth has been
342              * explicitly requested. Check for this, and bail out if we
343              * get one. Note that this leaks a security object at present
344              */
345             if (scIndex == RX_SECIDX_NULL) {
346                 sc = NULL;
347                 code = AFSCONF_NOTFOUND;
348                 goto out;
349             }
350
351             if (expires)
352                 *expires = NEVERDATE;
353         } else {
354             if (info == NULL) {
355                 code = afsconf_GetCellInfo(dir, cellName, NULL, &localInfo);
356                 if (code)
357                     goto out;
358                 info = &localInfo;
359             }
360
361             code = afsconf_ClientAuthToken(info, flags, sc, scIndex, expires);
362             if (code && !(flags & AFSCONF_SECOPTS_FALLBACK_NULL))
363                 goto out;
364
365             /* If we didn't get a token, we'll just run anonymously */
366             code = 0;
367         }
368     }
369     if (*sc == NULL) {
370         *sc = rxnull_NewClientSecurityObject();
371         *scIndex = RX_SECIDX_NULL;
372         if (expires)
373             *expires = NEVERDATE;
374     }
375
376 out:
377     return code;
378 }