OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [net/] [sunrpc/] [svcauth_des.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * linux/net/sunrpc/svcauth_des.c
3
 *
4
 * Server-side AUTH_DES handling.
5
 *
6
 * Copyright (C) 1996, 1997 Olaf Kirch <okir@monad.swb.de>
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
 * 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.
25
 */
26
struct des_cred {
27
        struct des_cred *       dc_next;
28
        char *                  dc_fullname;
29
        u32                     dc_nickname;
30
        des_cblock              dc_key;         /* conversation key */
31
        des_cblock              dc_xkey;        /* encrypted conv. key */
32
        des_key_schedule        dc_keysched;
33
};
34
 
35
#define ADN_FULLNAME            0
36
#define ADN_NICKNAME            1
37
 
38
/*
39
 * The default slack allowed when checking for replayed credentials
40
 * (in milliseconds).
41
 */
42
#define DES_REPLAY_SLACK        2000
43
 
44
/*
45
 * Make sure we don't place more than one call to the key server at
46
 * a time.
47
 */
48
static int                      in_keycall = 0;
49
 
50
#define FAIL(err) \
51
        { if (data) put_cred(data);                     \
52
          *authp = rpc_autherr_##err;                   \
53
          return;                                       \
54
        }
55
 
56
void
57
svcauth_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++;                                    /* skip length field */
76
        namekind = ntohl(*p++);                 /* fullname/nickname */
77
 
78
        /* Get the credentials */
79
        if (namekind == ADN_NICKNAME) {
80
                /* If we can't find the cached session key, initiate a
81
                 * new session. */
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++;              /* get the encrypted key */
89
                cryptkey[1] = *p++;
90
                cryptbuf[2] = *p++;             /* get the encrypted window */
91
        } else {
92
                FAIL(badcred);
93
        }
94
 
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 */
99
                return;
100
        }
101
 
102
        /* Get the verifier flavor and length */
103
        if (ntohl(*p++) != RPC_AUTH_DES && ntohl(*p++) != 12)
104
                FAIL(badverf);
105
 
106
        cryptbuf[0] = *p++;                      /* encrypted time stamp */
107
        cryptbuf[1] = *p++;
108
        cryptbuf[3] = *p++;                     /* 0 or window - 1 */
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
                /* 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)))
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
        /* Now check the whole lot */
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
        /* 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)
149
                        FAIL(rejectedverf);
150
                FAIL(badverf);
151
        }
152
 
153
        /*
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.
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
                /* TODO: compare time stamp to last five timestamps cached
174
                 * and reject (drop?) request if a match is found. */
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
        /* Okay, we're done. Update the lot */
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;
192
garbage:
193
        *statp = rpc_garbage_args;
194
        return;
195
}
196
 
197
/*
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.
201
 */
202
static struct des_cred *
203
get_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
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.