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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [rtems/] [c/] [src/] [librpc/] [src/] [rpc/] [svc_auth_des.c] - Blame information for rev 587

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 30 unneback
 
2
/*
3
 * Copyright (c) 1988 by Sun Microsystems, Inc.
4
 */
5
 
6
/*
7
 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
8
 * unrestricted use provided that this legend is included on all tape
9
 * media and as a part of the software program in whole or part.  Users
10
 * may copy or modify Sun RPC without charge, but are not authorized
11
 * to license or distribute it to anyone else except as part of a product or
12
 * program developed by the user.
13
 *
14
 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
15
 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
16
 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
17
 *
18
 * Sun RPC is provided with no support and without any obligation on the
19
 * part of Sun Microsystems, Inc. to assist in its use, correction,
20
 * modification or enhancement.
21
 *
22
 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
23
 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
24
 * OR ANY PART THEREOF.
25
 *
26
 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
27
 * or profits or other special, indirect and consequential damages, even if
28
 * Sun has been advised of the possibility of such damages.
29
 *
30
 * Sun Microsystems, Inc.
31
 * 2550 Garcia Avenue
32
 * Mountain View, California  94043
33
 */
34
 
35
/*
36
 * svcauth_des.c, server-side des authentication
37
 *
38
 * We insure for the service the following:
39
 * (1) The timestamp microseconds do not exceed 1 million.
40
 * (2) The timestamp plus the window is less than the current time.
41
 * (3) The timestamp is not less than the one previously
42
 *     seen in the current session.
43
 *
44
 * It is up to the server to determine if the window size is
45
 * too small .
46
 *
47
 */
48
 
49
#include <string.h>
50
#include <stdlib.h>
51
#include <unistd.h>
52
#include <rpc/des_crypt.h>
53
#include <sys/param.h>
54
#include <netinet/in.h>
55
#include <rpc/types.h>
56
#include <rpc/xdr.h>
57
#include <rpc/auth.h>
58
#include <rpc/auth_des.h>
59
#include <rpc/svc.h>
60
#include <rpc/rpc_msg.h>
61
#include <rpc/svc_auth.h>
62
 
63
#if defined(LIBC_SCCS) && !defined(lint)
64
/* from: static char sccsid[] =         "@(#)svcauth_des.c      2.3 89/07/11 4.0 RPCSRC; from 1.15 88/02/08 SMI"; */
65
static const char rcsid[] = "$FreeBSD: src/lib/libc/rpc/svc_auth_des.c,v 1.3 1999/08/28 00:00:48 peter Exp $";
66
#endif
67
 
68
#define debug(msg)       printf("svcauth_des: %s\n", msg) 
69
 
70
#define USEC_PER_SEC ((u_long) 1000000L)
71
#define BEFORE(t1, t2) timercmp(t1, t2, <)
72
 
73
/*
74
 * LRU cache of conversation keys and some other useful items.
75
 */
76
#define AUTHDES_CACHESZ 64
77
struct cache_entry {
78
        des_block key;          /* conversation key */
79
        char *rname;            /* client's name */
80
        u_int window;           /* credential lifetime window */
81
        struct timeval laststamp;       /* detect replays of creds */
82
        char *localcred;        /* generic local credential */
83
};
84
static struct cache_entry *authdes_cache/* [AUTHDES_CACHESZ] */;
85
static short *authdes_lru/* [AUTHDES_CACHESZ] */;
86
 
87
static void cache_init();       /* initialize the cache */
88
static short cache_spot();      /* find an entry in the cache */
89
static void cache_ref(/*short sid*/);   /* note that sid was ref'd */
90
 
91
static void invalidate();       /* invalidate entry in cache */
92
 
93
/*
94
 * cache statistics
95
 */
96
static struct {
97
        u_long ncachehits;      /* times cache hit, and is not replay */
98
        u_long ncachereplays;   /* times cache hit, and is replay */
99
        u_long ncachemisses;    /* times cache missed */
100
} svcauthdes_stats;
101
 
102
/*
103
 * Service side authenticator for AUTH_DES
104
 */
105
enum auth_stat
106
_svcauth_des(rqst, msg)
107
        register struct svc_req *rqst;
108
        register struct rpc_msg *msg;
109
{
110
 
111
        register long *ixdr;
112
        des_block cryptbuf[2];
113
        register struct authdes_cred *cred;
114
        struct authdes_verf verf;
115
        int status;
116
        register struct cache_entry *entry;
117
        short sid = 0;
118
        des_block *sessionkey;
119
        des_block ivec;
120
        u_int window;
121
        struct timeval timestamp;
122
        u_long namelen;
123
        struct area {
124
                struct authdes_cred area_cred;
125
                char area_netname[MAXNETNAMELEN+1];
126
        } *area;
127
 
128
        if (authdes_cache == NULL) {
129
                cache_init();
130
        }
131
 
132
        area = (struct area *)rqst->rq_clntcred;
133
        cred = (struct authdes_cred *)&area->area_cred;
134
 
135
        /*
136
         * Get the credential
137
         */
138
        ixdr = (long *)msg->rm_call.cb_cred.oa_base;
139
        cred->adc_namekind = IXDR_GET_ENUM(ixdr, enum authdes_namekind);
140
        switch (cred->adc_namekind) {
141
        case ADN_FULLNAME:
142
                namelen = IXDR_GET_U_LONG(ixdr);
143
                if (namelen > MAXNETNAMELEN) {
144
                        return (AUTH_BADCRED);
145
                }
146
                cred->adc_fullname.name = area->area_netname;
147
                bcopy((char *)ixdr, cred->adc_fullname.name,
148
                        (u_int)namelen);
149
                cred->adc_fullname.name[namelen] = 0;
150
                ixdr += (RNDUP(namelen) / BYTES_PER_XDR_UNIT);
151
                cred->adc_fullname.key.key.high = (u_long)*ixdr++;
152
                cred->adc_fullname.key.key.low = (u_long)*ixdr++;
153
                cred->adc_fullname.window = (u_long)*ixdr++;
154
                break;
155
        case ADN_NICKNAME:
156
                cred->adc_nickname = (u_long)*ixdr++;
157
                break;
158
        default:
159
                return (AUTH_BADCRED);
160
        }
161
 
162
        /*
163
         * Get the verifier
164
         */
165
        ixdr = (long *)msg->rm_call.cb_verf.oa_base;
166
        verf.adv_xtimestamp.key.high = (u_long)*ixdr++;
167
        verf.adv_xtimestamp.key.low =  (u_long)*ixdr++;
168
        verf.adv_int_u = (u_long)*ixdr++;
169
 
170
 
171
        /*
172
         * Get the conversation key
173
         */
174
        if (cred->adc_namekind == ADN_FULLNAME) {
175
                netobj pkey;
176
                char pkey_data[1024];
177
 
178
                sessionkey = &cred->adc_fullname.key;
179
                if (! getpublickey(cred->adc_fullname.name, pkey_data)) {
180
                        debug("getpublickey");
181
                        return(AUTH_BADCRED);
182
                }
183
                pkey.n_bytes = pkey_data;
184
                pkey.n_len = strlen(pkey_data) + 1;
185
                if (key_decryptsession_pk(cred->adc_fullname.name, &pkey,
186
                                       sessionkey) < 0) {
187
                        debug("decryptsessionkey");
188
                        return (AUTH_BADCRED); /* key not found */
189
                }
190
        } else { /* ADN_NICKNAME */
191
                sid = (short)cred->adc_nickname;
192
                if (sid >= AUTHDES_CACHESZ) {
193
                        debug("bad nickname");
194
                        return (AUTH_BADCRED);  /* garbled credential */
195
                }
196
                sessionkey = &authdes_cache[sid].key;
197
        }
198
 
199
 
200
        /*
201
         * Decrypt the timestamp
202
         */
203
        cryptbuf[0] = verf.adv_xtimestamp;
204
        if (cred->adc_namekind == ADN_FULLNAME) {
205
                cryptbuf[1].key.high = cred->adc_fullname.window;
206
                cryptbuf[1].key.low = verf.adv_winverf;
207
                ivec.key.high = ivec.key.low = 0;
208
                status = cbc_crypt((char *)sessionkey, (char *)cryptbuf,
209
                        2*sizeof(des_block), DES_DECRYPT | DES_HW,
210
                        (char *)&ivec);
211
        } else {
212
                status = ecb_crypt((char *)sessionkey, (char *)cryptbuf,
213
                        sizeof(des_block), DES_DECRYPT | DES_HW);
214
        }
215
        if (DES_FAILED(status)) {
216
                debug("decryption failure");
217
                return (AUTH_FAILED);   /* system error */
218
        }
219
 
220
        /*
221
         * XDR the decrypted timestamp
222
         */
223
        ixdr = (long *)cryptbuf;
224
        timestamp.tv_sec = IXDR_GET_LONG(ixdr);
225
        timestamp.tv_usec = IXDR_GET_LONG(ixdr);
226
 
227
        /*
228
         * Check for valid credentials and verifiers.
229
         * They could be invalid because the key was flushed
230
         * out of the cache, and so a new session should begin.
231
         * Be sure and send AUTH_REJECTED{CRED, VERF} if this is the case.
232
         */
233
        {
234
                struct timeval current;
235
                int nick;
236
                int winverf;
237
 
238
                if (cred->adc_namekind == ADN_FULLNAME) {
239
                        window = IXDR_GET_U_LONG(ixdr);
240
                        winverf = IXDR_GET_U_LONG(ixdr);
241
                        if (winverf != window - 1) {
242
                                debug("window verifier mismatch");
243
                                return (AUTH_BADCRED);  /* garbled credential */
244
                        }
245
                        sid = cache_spot(sessionkey, cred->adc_fullname.name,
246
                            &timestamp);
247
                        if (sid < 0) {
248
                                debug("replayed credential");
249
                                return (AUTH_REJECTEDCRED);     /* replay */
250
                        }
251
                        nick = 0;
252
                } else {        /* ADN_NICKNAME */
253
                        window = authdes_cache[sid].window;
254
                        nick = 1;
255
                }
256
 
257
                if ((u_long)timestamp.tv_usec >= USEC_PER_SEC) {
258
                        debug("invalid usecs");
259
                        /* cached out (bad key), or garbled verifier */
260
                        return (nick ? AUTH_REJECTEDVERF : AUTH_BADVERF);
261
                }
262
                if (nick && BEFORE(&timestamp,
263
                                   &authdes_cache[sid].laststamp)) {
264
                        debug("timestamp before last seen");
265
                        return (AUTH_REJECTEDVERF);     /* replay */
266
                }
267
                (void) gettimeofday(&current, (struct timezone *)NULL);
268
                current.tv_sec -= window;       /* allow for expiration */
269
                if (!BEFORE(&current, &timestamp)) {
270
                        debug("timestamp expired");
271
                        /* replay, or garbled credential */
272
                        return (nick ? AUTH_REJECTEDVERF : AUTH_BADCRED);
273
                }
274
        }
275
 
276
        /*
277
         * Set up the reply verifier
278
         */
279
        verf.adv_nickname = (u_long)sid;
280
 
281
        /*
282
         * xdr the timestamp before encrypting
283
         */
284
        ixdr = (long *)cryptbuf;
285
        IXDR_PUT_LONG(ixdr, timestamp.tv_sec - 1);
286
        IXDR_PUT_LONG(ixdr, timestamp.tv_usec);
287
 
288
        /*
289
         * encrypt the timestamp
290
         */
291
        status = ecb_crypt((char *)sessionkey, (char *)cryptbuf,
292
            sizeof(des_block), DES_ENCRYPT | DES_HW);
293
        if (DES_FAILED(status)) {
294
                debug("encryption failure");
295
                return (AUTH_FAILED);   /* system error */
296
        }
297
        verf.adv_xtimestamp = cryptbuf[0];
298
 
299
        /*
300
         * Serialize the reply verifier, and update rqst
301
         */
302
        ixdr = (long *)msg->rm_call.cb_verf.oa_base;
303
        *ixdr++ = (long)verf.adv_xtimestamp.key.high;
304
        *ixdr++ = (long)verf.adv_xtimestamp.key.low;
305
        *ixdr++ = (long)verf.adv_int_u;
306
 
307
        rqst->rq_xprt->xp_verf.oa_flavor = AUTH_DES;
308
        rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base;
309
        rqst->rq_xprt->xp_verf.oa_length =
310
                (char *)ixdr - msg->rm_call.cb_verf.oa_base;
311
 
312
        /*
313
         * We succeeded, commit the data to the cache now and
314
         * finish cooking the credential.
315
         */
316
        entry = &authdes_cache[sid];
317
        entry->laststamp = timestamp;
318
        cache_ref(sid);
319
        if (cred->adc_namekind == ADN_FULLNAME) {
320
                cred->adc_fullname.window = window;
321
                cred->adc_nickname = (u_long)sid;       /* save nickname */
322
                if (entry->rname != NULL) {
323
                        mem_free(entry->rname, strlen(entry->rname) + 1);
324
                }
325
                entry->rname = (char *)mem_alloc((u_int)strlen(cred->adc_fullname.name)
326
                                         + 1);
327
                if (entry->rname != NULL) {
328
                        (void) strcpy(entry->rname, cred->adc_fullname.name);
329
                } else {
330
                        debug("out of memory");
331
                }
332
                entry->key = *sessionkey;
333
                entry->window = window;
334
                invalidate(entry->localcred); /* mark any cached cred invalid */
335
        } else { /* ADN_NICKNAME */
336
                /*
337
                 * nicknames are cooked into fullnames
338
                 */
339
                cred->adc_namekind = ADN_FULLNAME;
340
                cred->adc_fullname.name = entry->rname;
341
                cred->adc_fullname.key = entry->key;
342
                cred->adc_fullname.window = entry->window;
343
        }
344
        return (AUTH_OK);       /* we made it!*/
345
}
346
 
347
 
348
/*
349
 * Initialize the cache
350
 */
351
static void
352
cache_init()
353
{
354
        register int i;
355
 
356
        authdes_cache = (struct cache_entry *)
357
                mem_alloc(sizeof(struct cache_entry) * AUTHDES_CACHESZ);
358
        bzero((char *)authdes_cache,
359
                sizeof(struct cache_entry) * AUTHDES_CACHESZ);
360
 
361
        authdes_lru = (short *)mem_alloc(sizeof(short) * AUTHDES_CACHESZ);
362
        /*
363
         * Initialize the lru list
364
         */
365
        for (i = 0; i < AUTHDES_CACHESZ; i++) {
366
                authdes_lru[i] = i;
367
        }
368
}
369
 
370
 
371
/*
372
 * Find the lru victim
373
 */
374
static short
375
cache_victim()
376
{
377
        return (authdes_lru[AUTHDES_CACHESZ-1]);
378
}
379
 
380
/*
381
 * Note that sid was referenced
382
 */
383
static void
384
cache_ref(sid)
385
        register short sid;
386
{
387
        register int i;
388
        register short curr;
389
        register short prev;
390
 
391
        prev = authdes_lru[0];
392
        authdes_lru[0] = sid;
393
        for (i = 1; prev != sid; i++) {
394
                curr = authdes_lru[i];
395
                authdes_lru[i] = prev;
396
                prev = curr;
397
        }
398
}
399
 
400
 
401
/*
402
 * Find a spot in the cache for a credential containing
403
 * the items given.  Return -1 if a replay is detected, otherwise
404
 * return the spot in the cache.
405
 */
406
static short
407
cache_spot(key, name, timestamp)
408
        register des_block *key;
409
        char *name;
410
        struct timeval *timestamp;
411
{
412
        register struct cache_entry *cp;
413
        register int i;
414
        register u_long hi;
415
 
416
        hi = key->key.high;
417
        for (cp = authdes_cache, i = 0; i < AUTHDES_CACHESZ; i++, cp++) {
418
                if (cp->key.key.high == hi &&
419
                    cp->key.key.low == key->key.low &&
420
                    cp->rname != NULL &&
421
                    bcmp(cp->rname, name, strlen(name) + 1) == 0) {
422
                        if (BEFORE(timestamp, &cp->laststamp)) {
423
                                svcauthdes_stats.ncachereplays++;
424
                                return (-1); /* replay */
425
                        }
426
                        svcauthdes_stats.ncachehits++;
427
                        return (i);     /* refresh */
428
                }
429
        }
430
        svcauthdes_stats.ncachemisses++;
431
        return (cache_victim());        /* new credential */
432
}
433
 
434
 
435
#if (defined(sun) || defined(vax) || defined(__FreeBSD__))
436
/*
437
 * Local credential handling stuff.
438
 * NOTE: bsd unix dependent.
439
 * Other operating systems should put something else here.
440
 */
441
#define UNKNOWN         -2      /* grouplen, if cached cred is unknown user */
442
#define INVALID         -1      /* grouplen, if cache entry is invalid */
443
 
444
struct bsdcred {
445
        short uid;              /* cached uid */
446
        short gid;              /* cached gid */
447
        short grouplen; /* length of cached groups */
448
        short groups[NGROUPS];  /* cached groups */
449
};
450
 
451
/*
452
 * Map a des credential into a unix cred.
453
 * We cache the credential here so the application does
454
 * not have to make an rpc call every time to interpret
455
 * the credential.
456
 */
457
int
458
authdes_getucred(adc, uid, gid, grouplen, groups)
459
        struct authdes_cred *adc;
460
        uid_t *uid;
461
        gid_t *gid;
462
        int *grouplen;
463
        register gid_t *groups;
464
{
465
        unsigned sid;
466
        register int i;
467
        uid_t i_uid;
468
        gid_t i_gid;
469
        int i_grouplen;
470
        struct bsdcred *cred;
471
 
472
        sid = adc->adc_nickname;
473
        if (sid >= AUTHDES_CACHESZ) {
474
                debug("invalid nickname");
475
                return (0);
476
        }
477
        cred = (struct bsdcred *)authdes_cache[sid].localcred;
478
        if (cred == NULL) {
479
                cred = (struct bsdcred *)mem_alloc(sizeof(struct bsdcred));
480
                authdes_cache[sid].localcred = (char *)cred;
481
                cred->grouplen = INVALID;
482
        }
483
        if (cred->grouplen == INVALID) {
484
                /*
485
                 * not in cache: lookup
486
                 */
487
                if (!netname2user(adc->adc_fullname.name, &i_uid, &i_gid,
488
                        &i_grouplen, groups))
489
                {
490
                        debug("unknown netname");
491
                        cred->grouplen = UNKNOWN;       /* mark as lookup up, but not found */
492
                        return (0);
493
                }
494
                debug("missed ucred cache");
495
                *uid = cred->uid = i_uid;
496
                *gid = cred->gid = i_gid;
497
                *grouplen = cred->grouplen = i_grouplen;
498
                for (i = i_grouplen - 1; i >= 0; i--) {
499
                        cred->groups[i] = groups[i]; /* int to short */
500
                }
501
                return (1);
502
        } else if (cred->grouplen == UNKNOWN) {
503
                /*
504
                 * Already lookup up, but no match found
505
                 */
506
                return (0);
507
        }
508
 
509
        /*
510
         * cached credentials
511
         */
512
        *uid = cred->uid;
513
        *gid = cred->gid;
514
        *grouplen = cred->grouplen;
515
        for (i = cred->grouplen - 1; i >= 0; i--) {
516
                groups[i] = cred->groups[i];    /* short to int */
517
        }
518
        return (1);
519
}
520
 
521
static void
522
invalidate(cred)
523
        char *cred;
524
{
525
        if (cred == NULL) {
526
                return;
527
        }
528
        ((struct bsdcred *)cred)->grouplen = INVALID;
529
}
530
#endif
531
 

powered by: WebSVN 2.1.0

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