2 * linux/net/sunrpc/svcauth_des.c
4 * Server-side AUTH_DES handling.
6 * Copyright (C) 1996, 1997 Olaf Kirch <okir@monad.swb.de>
9 #include <linux/types.h>
10 #include <linux/sched.h>
11 #include <linux/sunrpc/types.h>
12 #include <linux/sunrpc/xdr.h>
13 #include <linux/sunrpc/svcauth.h>
14 #include <linux/sunrpc/svcsock.h>
16 #define RPCDBG_FACILITY RPCDBG_AUTH
19 * DES cedential cache.
20 * The cache is indexed by fullname/key to allow for multiple sessions
21 * by the same user from different hosts.
22 * It would be tempting to use the client's IP address rather than the
23 * conversation key as an index, but that could become problematic for
24 * multi-homed hosts that distribute traffic across their interfaces.
27 struct des_cred * dc_next;
30 des_cblock dc_key; /* conversation key */
31 des_cblock dc_xkey; /* encrypted conv. key */
32 des_key_schedule dc_keysched;
35 #define ADN_FULLNAME 0
36 #define ADN_NICKNAME 1
39 * The default slack allowed when checking for replayed credentials
42 #define DES_REPLAY_SLACK 2000
45 * Make sure we don't place more than one call to the key server at
48 static int in_keycall;
51 { if (data) put_cred(data); \
52 *authp = rpc_autherr_##err; \
57 svcauth_des(struct svc_rqst *rqstp, u32 *statp, u32 *authp)
59 struct svc_buf *argp = &rqstp->rq_argbuf;
60 struct svc_buf *resp = &rqstp->rq_resbuf;
61 struct svc_cred *cred = &rqstp->rq_cred;
62 struct des_cred *data = NULL;
66 int len = argp->len, slen, i;
70 if ((argp->len -= 3) < 0) {
71 *statp = rpc_garbage_args;
75 p++; /* skip length field */
76 namekind = ntohl(*p++); /* fullname/nickname */
78 /* Get the credentials */
79 if (namekind == ADN_NICKNAME) {
80 /* If we can't find the cached session key, initiate a
82 if (!(data = get_cred_bynick(*p++)))
84 } else if (namekind == ADN_FULLNAME) {
85 p = xdr_decode_string(p, &fullname, &len, RPC_MAXNETNAMELEN);
88 cryptkey[0] = *p++; /* get the encrypted key */
90 cryptbuf[2] = *p++; /* get the encrypted window */
95 /* If we're just updating the key, silently discard the request. */
96 if (data && data->dc_locked) {
97 *authp = rpc_autherr_dropit;
98 _put_cred(data); /* release but don't unlock */
102 /* Get the verifier flavor and length */
103 if (ntohl(*p++) != RPC_AUTH_DES && ntohl(*p++) != 12)
106 cryptbuf[0] = *p++; /* encrypted time stamp */
108 cryptbuf[3] = *p++; /* 0 or window - 1 */
110 if (namekind == ADN_NICKNAME) {
111 status = des_ecb_encrypt((des_block *) cryptbuf,
112 (des_block *) cryptbuf,
113 data->dc_keysched, DES_DECRYPT);
115 /* We first have to decrypt the new session key and
116 * fill in the UNIX creds. */
117 if (!(data = get_cred_byname(rqstp, authp, fullname, cryptkey)))
119 status = des_cbc_encrypt((des_cblock *) cryptbuf,
120 (des_cblock *) cryptbuf, 16,
122 (des_cblock *) &ivec,
126 printk("svcauth_des: DES decryption failed (status %d)\n",
131 /* Now check the whole lot */
132 if (namekind == ADN_FULLNAME) {
133 unsigned long winverf;
135 data->dc_window = ntohl(cryptbuf[2]);
136 winverf = ntohl(cryptbuf[2]);
137 if (window != winverf - 1) {
138 printk("svcauth_des: bad window verifier!\n");
143 /* XDR the decrypted timestamp */
144 cryptbuf[0] = ntohl(cryptbuf[0]);
145 cryptbuf[1] = ntohl(cryptbuf[1]);
146 if (cryptbuf[1] > 1000000) {
147 dprintk("svcauth_des: bad usec value %u\n", cryptbuf[1]);
148 if (namekind == ADN_NICKNAME)
154 * Check for replayed credentials. We must allow for reordering
155 * of requests by the network, and the OS scheduler, hence we
156 * cannot expect timestamps to be increasing monotonically.
157 * This opens a small security hole, therefore the replay_slack
158 * value shouldn't be too large.
160 if ((delta = cryptbuf[0] - data->dc_timestamp[0]) <= 0) {
165 delta += cryptbuf[1] - data->dc_timestamp[1];
170 if (delta < DES_REPLAY_SLACK)
172 #ifdef STRICT_REPLAY_CHECKS
173 /* TODO: compare time stamp to last five timestamps cached
174 * and reject (drop?) request if a match is found. */
179 now.tv_secs -= data->dc_window;
180 if (now.tv_secs < cryptbuf[0] ||
181 (now.tv_secs == cryptbuf[0] && now.tv_usec < cryptbuf[1]))
184 /* Okay, we're done. Update the lot */
185 if (namekind == ADN_FULLNAME)
187 data->dc_timestamp[0] = cryptbuf[0];
188 data->dc_timestamp[1] = cryptbuf[1];
193 *statp = rpc_garbage_args;
198 * Call the keyserver to obtain the decrypted conversation key and
199 * UNIX creds. We use a Linux-specific keycall extension that does
200 * both things in one go.
202 static struct des_cred *
203 get_cred_byname(struct svc_rqst *rqstp, u32 *authp, char *fullname, u32 *cryptkey)
205 static int in_keycall;
206 struct des_cred *cred;
209 *authp = rpc_autherr_dropit;