1
2
3
4
5
6
7
8
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>
15
16#define RPCDBG_FACILITY RPCDBG_AUTH
17
18
19
20
21
22
23
24
25
26struct des_cred {
27 struct des_cred * dc_next;
28 char * dc_fullname;
29 u32 dc_nickname;
30 des_cblock dc_key;
31 des_cblock dc_xkey;
32 des_key_schedule dc_keysched;
33};
34
35#define ADN_FULLNAME 0
36#define ADN_NICKNAME 1
37
38
39
40
41
42#define DES_REPLAY_SLACK 2000
43
44
45
46
47
48static int in_keycall = 0;
49
50#define FAIL(err) \
51 { if (data) put_cred(data); \
52 *authp = rpc_autherr_##err; \
53 return; \
54 }
55
56void
57svcauth_des(struct svc_rqst *rqstp, u32 *statp, u32 *authp)
58{
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;
63 u32 cryptkey[2];
64 u32 cryptbuf[4];
65 u32 *p = argp->buf;
66 int len = argp->len, slen, i;
67
68 *authp = rpc_auth_ok;
69
70 if ((argp->len -= 3) < 0) {
71 *statp = rpc_garbage_args;
72 return;
73 }
74
75 p++;
76 namekind = ntohl(*p++);
77
78
79 if (namekind == ADN_NICKNAME) {
80
81
82 if (!(data = get_cred_bynick(*p++)))
83 FAIL(rejectedcred);
84 } else if (namekind == ADN_FULLNAME) {
85 p = xdr_decode_string(p, &fullname, &len, RPC_MAXNETNAMELEN);
86 if (p == NULL)
87 FAIL(badcred);
88 cryptkey[0] = *p++;
89 cryptkey[1] = *p++;
90 cryptbuf[2] = *p++;
91 } else {
92 FAIL(badcred);
93 }
94
95
96 if (data && data->dc_locked) {
97 *authp = rpc_autherr_dropit;
98 _put_cred(data);
99 return;
100 }
101
102
103 if (ntohl(*p++) != RPC_AUTH_DES && ntohl(*p++) != 12)
104 FAIL(badverf);
105
106 cryptbuf[0] = *p++;
107 cryptbuf[1] = *p++;
108 cryptbuf[3] = *p++;
109
110 if (namekind == ADN_NICKNAME) {
111 status = des_ecb_encrypt((des_block *) cryptbuf,
112 (des_block *) cryptbuf,
113 data->dc_keysched, DES_DECRYPT);
114 } else {
115
116
117 if (!(data = get_cred_byname(rqstp, authp, fullname, cryptkey)))
118 return;
119 status = des_cbc_encrypt((des_cblock *) cryptbuf,
120 (des_cblock *) cryptbuf, 16,
121 data->dc_keysched,
122 (des_cblock *) &ivec,
123 DES_DECRYPT);
124 }
125 if (status) {
126 printk("svcauth_des: DES decryption failed (status %d)\n",
127 status);
128 FAIL(badverf);
129 }
130
131
132 if (namekind == ADN_FULLNAME) {
133 unsigned long winverf;
134
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");
139 FAIL(badverf);
140 }
141 }
142
143
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)
149 FAIL(rejectedverf);
150 FAIL(badverf);
151 }
152
153
154
155
156
157
158
159
160 if ((delta = cryptbuf[0] - data->dc_timestamp[0]) <= 0) {
161 switch (delta) {
162 case -1:
163 delta = -1000000;
164 case 0:
165 delta += cryptbuf[1] - data->dc_timestamp[1];
166 break;
167 default:
168 delta = -1000000;
169 }
170 if (delta < DES_REPLAY_SLACK)
171 FAIL(rejectedverf);
172#ifdef STRICT_REPLAY_CHECKS
173
174
175#endif
176 }
177
178 now = xtime;
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]))
182 FAIL(rejectedverf);
183
184
185 if (namekind == ADN_FULLNAME)
186 data->dc_valid = 1;
187 data->dc_timestamp[0] = cryptbuf[0];
188 data->dc_timestamp[1] = cryptbuf[1];
189
190 put_cred(data);
191 return;
192garbage:
193 *statp = rpc_garbage_args;
194 return;
195}
196
197
198
199
200
201
202static struct des_cred *
203get_cred_byname(struct svc_rqst *rqstp, u32 *authp, char *fullname, u32 *cryptkey)
204{
205 static int in_keycall = 0;
206 struct des_cred *cred;
207
208 if (in_keycall) {
209 *authp = rpc_autherr_dropit;
210 return NULL;
211 }
212 in_keycall = 1;
213 in_keycall = 0;
214 return cred;
215}
216