Move epoch and cid generation into the rx core
[openafs.git] / src / rxkad / rxkad_client.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 /* The rxkad security object.  Authentication using a DES-encrypted
11  * Kerberos-style ticket.  These are the client-only routines.  They do not
12  * make any use of DES. */
13
14 #include <afsconfig.h>
15 #include <afs/param.h>
16 #include <afs/stds.h>
17
18 #ifdef KERNEL
19 #ifndef UKERNEL
20 #include "h/types.h"
21 #include "h/time.h"
22 #if defined(AFS_AIX_ENV) || defined(AFS_AUX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_XBSD_ENV)
23 #include "h/systm.h"
24 #endif
25 #ifdef AFS_LINUX20_ENV
26 #include "h/socket.h"
27 #endif
28 #ifndef AFS_OBSD_ENV
29 #include "netinet/in.h"
30 #endif
31 #else /* !UKERNEL */
32 #include "afs/sysincludes.h"
33 #endif /* !UKERNEL */
34 #else /* ! KERNEL */
35 #include <roken.h>
36 #include <afs/opr.h>
37 #endif /* KERNEL */
38
39
40 #include <rx/rx.h>
41 #include <rx/xdr.h>
42 #include <rx/rx_packet.h>
43
44 #include "rxkad.h"
45 #include "stats.h"
46 #include "private_data.h"
47 #define XPRT_RXKAD_CLIENT
48
49 #ifndef max
50 #define max(a,b)    ((a) < (b)? (b) : (a))
51 #endif /* max */
52
53 static struct rx_securityOps rxkad_client_ops = {
54     rxkad_Close,
55     rxkad_NewConnection,        /* every new connection */
56     rxkad_PreparePacket,        /* once per packet creation */
57     0,                          /* send packet (once per retrans.) */
58     0,
59     0,
60     0,
61     rxkad_GetResponse,          /* respond to challenge packet */
62     0,
63     rxkad_CheckPacket,          /* check data packet */
64     rxkad_DestroyConnection,
65     rxkad_GetStats,
66     0,
67     0,
68     0,
69 };
70
71 /* Allocate a new client security object.  Called with the encryption level,
72  * the session key and the ticket for the other side obtained from the
73  * AuthServer.  Refers to export control to determine level. */
74
75 struct rx_securityClass *
76 rxkad_NewClientSecurityObject(rxkad_level level,
77                               struct ktc_encryptionKey *sessionkey,
78                               afs_int32 kvno, int ticketLen, char *ticket)
79 {
80     struct rx_securityClass *tsc;
81     struct rxkad_cprivate *tcp;
82     int code;
83     int size, psize;
84
85     rxkad_Init();
86
87     size = sizeof(struct rx_securityClass);
88     tsc = rxi_Alloc(size);
89     memset((void *)tsc, 0, size);
90     tsc->refCount = 1;          /* caller gets one for free */
91     tsc->ops = &rxkad_client_ops;
92
93     psize = PDATA_SIZE(ticketLen);
94     tcp = rxi_Alloc(psize);
95     memset((void *)tcp, 0, psize);
96     tsc->privateData = (char *)tcp;
97     tcp->type |= rxkad_client;
98     tcp->level = level;
99     code = fc_keysched(sessionkey, tcp->keysched);
100     if (code) {
101         rxi_Free(tcp, psize);
102         rxi_Free(tsc, sizeof(struct rx_securityClass));
103         return 0;               /* bad key */
104     }
105     memcpy((void *)tcp->ivec, (void *)sessionkey, sizeof(tcp->ivec));
106     tcp->kvno = kvno;           /* key version number */
107     tcp->ticketLen = ticketLen; /* length of ticket */
108     if (tcp->ticketLen > MAXKTCTICKETLEN) {
109         rxi_Free(tcp, psize);
110         rxi_Free(tsc, sizeof(struct rx_securityClass));
111         return 0;               /* bad key */
112     }
113     memcpy(tcp->ticket, ticket, ticketLen);
114
115     INC_RXKAD_STATS(clientObjects);
116     return tsc;
117 }
118
119 /* client: respond to a challenge packet */
120
121 int
122 rxkad_GetResponse(struct rx_securityClass *aobj, struct rx_connection *aconn,
123                   struct rx_packet *apacket)
124 {
125     struct rxkad_cprivate *tcp;
126     char *tp;
127     int v2;                     /* whether server is old style or v2 */
128     afs_int32 challengeID;
129     rxkad_level level;
130     char *response;
131     int responseSize, missing;
132     struct rxkad_v2ChallengeResponse r_v2;
133     struct rxkad_oldChallengeResponse r_old;
134
135     tcp = (struct rxkad_cprivate *)aobj->privateData;
136
137     if (!(tcp->type & rxkad_client))
138         return RXKADINCONSISTENCY;
139
140     v2 = (rx_Contiguous(apacket) > sizeof(struct rxkad_oldChallenge));
141     tp = rx_DataOf(apacket);
142
143     if (v2) {                   /* v2 challenge */
144         struct rxkad_v2Challenge *c_v2;
145         if (rx_GetDataSize(apacket) < sizeof(struct rxkad_v2Challenge))
146             return RXKADPACKETSHORT;
147         c_v2 = (struct rxkad_v2Challenge *)tp;
148         challengeID = ntohl(c_v2->challengeID);
149         level = ntohl(c_v2->level);
150     } else {                    /* old format challenge */
151         struct rxkad_oldChallenge *c_old;
152         if (rx_GetDataSize(apacket) < sizeof(struct rxkad_oldChallenge))
153             return RXKADPACKETSHORT;
154         c_old = (struct rxkad_oldChallenge *)tp;
155         challengeID = ntohl(c_old->challengeID);
156         level = ntohl(c_old->level);
157     }
158
159     if (level > tcp->level)
160         return RXKADLEVELFAIL;
161     INC_RXKAD_STATS(challenges[rxkad_LevelIndex(tcp->level)]);
162     if (v2) {
163         int i;
164         afs_uint32 xor[2];
165         memset((void *)&r_v2, 0, sizeof(r_v2));
166         r_v2.version = htonl(RXKAD_CHALLENGE_PROTOCOL_VERSION);
167         r_v2.spare = 0;
168         (void)rxkad_SetupEndpoint(aconn, &r_v2.encrypted.endpoint);
169         (void)rxi_GetCallNumberVector(aconn, r_v2.encrypted.callNumbers);
170         for (i = 0; i < RX_MAXCALLS; i++) {
171             if (r_v2.encrypted.callNumbers[i] < 0)
172                 return RXKADINCONSISTENCY;
173             r_v2.encrypted.callNumbers[i] =
174                 htonl(r_v2.encrypted.callNumbers[i]);
175         }
176         r_v2.encrypted.incChallengeID = htonl(challengeID + 1);
177         r_v2.encrypted.level = htonl((afs_int32) tcp->level);
178         r_v2.kvno = htonl(tcp->kvno);
179         r_v2.ticketLen = htonl(tcp->ticketLen);
180         r_v2.encrypted.endpoint.cksum = rxkad_CksumChallengeResponse(&r_v2);
181         memcpy((void *)xor, (void *)tcp->ivec, 2 * sizeof(afs_int32));
182         fc_cbc_encrypt(&r_v2.encrypted, &r_v2.encrypted,
183                        sizeof(r_v2.encrypted), tcp->keysched, xor, ENCRYPT);
184         response = (char *)&r_v2;
185         responseSize = sizeof(r_v2);
186     } else {
187         memset((void *)&r_old, 0, sizeof(r_old));
188         r_old.encrypted.incChallengeID = htonl(challengeID + 1);
189         r_old.encrypted.level = htonl((afs_int32) tcp->level);
190         r_old.kvno = htonl(tcp->kvno);
191         r_old.ticketLen = htonl(tcp->ticketLen);
192         fc_ecb_encrypt(&r_old.encrypted, &r_old.encrypted, tcp->keysched,
193                        ENCRYPT);
194         response = (char *)&r_old;
195         responseSize = sizeof(r_old);
196     }
197
198     if (RX_MAX_PACKET_DATA_SIZE < responseSize + tcp->ticketLen)
199         return RXKADPACKETSHORT;        /* not enough space */
200
201     rx_computelen(apacket, missing);
202     missing = responseSize + tcp->ticketLen - missing;
203     if (missing > 0)
204         if (rxi_AllocDataBuf(apacket, missing, RX_PACKET_CLASS_SEND) > 0)
205             return RXKADPACKETSHORT;    /* not enough space */
206
207     /* copy response and ticket into packet */
208     rx_packetwrite(apacket, 0, responseSize, response);
209     rx_packetwrite(apacket, responseSize, tcp->ticketLen, tcp->ticket);
210
211     rx_SetDataSize(apacket, responseSize + tcp->ticketLen);
212     return 0;
213 }