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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [net/] [sunrpc/] [svcauth_des.c] - Diff between revs 1275 and 1765

Only display areas with differences | Details | Blame | View Log

Rev 1275 Rev 1765
/*
/*
 * linux/net/sunrpc/svcauth_des.c
 * linux/net/sunrpc/svcauth_des.c
 *
 *
 * Server-side AUTH_DES handling.
 * Server-side AUTH_DES handling.
 *
 *
 * Copyright (C) 1996, 1997 Olaf Kirch <okir@monad.swb.de>
 * Copyright (C) 1996, 1997 Olaf Kirch <okir@monad.swb.de>
 */
 */
 
 
#include <linux/types.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/sunrpc/types.h>
#include <linux/sunrpc/types.h>
#include <linux/sunrpc/xdr.h>
#include <linux/sunrpc/xdr.h>
#include <linux/sunrpc/svcauth.h>
#include <linux/sunrpc/svcauth.h>
#include <linux/sunrpc/svcsock.h>
#include <linux/sunrpc/svcsock.h>
 
 
#define RPCDBG_FACILITY RPCDBG_AUTH
#define RPCDBG_FACILITY RPCDBG_AUTH
 
 
/*
/*
 * DES cedential cache.
 * DES cedential cache.
 * The cache is indexed by fullname/key to allow for multiple sessions
 * The cache is indexed by fullname/key to allow for multiple sessions
 * by the same user from different hosts.
 * by the same user from different hosts.
 * It would be tempting to use the client's IP address rather than the
 * It would be tempting to use the client's IP address rather than the
 * conversation key as an index, but that could become problematic for
 * conversation key as an index, but that could become problematic for
 * multi-homed hosts that distribute traffic across their interfaces.
 * multi-homed hosts that distribute traffic across their interfaces.
 */
 */
struct des_cred {
struct des_cred {
        struct des_cred *       dc_next;
        struct des_cred *       dc_next;
        char *                  dc_fullname;
        char *                  dc_fullname;
        u32                     dc_nickname;
        u32                     dc_nickname;
        des_cblock              dc_key;         /* conversation key */
        des_cblock              dc_key;         /* conversation key */
        des_cblock              dc_xkey;        /* encrypted conv. key */
        des_cblock              dc_xkey;        /* encrypted conv. key */
        des_key_schedule        dc_keysched;
        des_key_schedule        dc_keysched;
};
};
 
 
#define ADN_FULLNAME            0
#define ADN_FULLNAME            0
#define ADN_NICKNAME            1
#define ADN_NICKNAME            1
 
 
/*
/*
 * The default slack allowed when checking for replayed credentials
 * The default slack allowed when checking for replayed credentials
 * (in milliseconds).
 * (in milliseconds).
 */
 */
#define DES_REPLAY_SLACK        2000
#define DES_REPLAY_SLACK        2000
 
 
/*
/*
 * Make sure we don't place more than one call to the key server at
 * Make sure we don't place more than one call to the key server at
 * a time.
 * a time.
 */
 */
static int                      in_keycall = 0;
static int                      in_keycall = 0;
 
 
#define FAIL(err) \
#define FAIL(err) \
        { if (data) put_cred(data);                     \
        { if (data) put_cred(data);                     \
          *authp = rpc_autherr_##err;                   \
          *authp = rpc_autherr_##err;                   \
          return;                                       \
          return;                                       \
        }
        }
 
 
void
void
svcauth_des(struct svc_rqst *rqstp, u32 *statp, u32 *authp)
svcauth_des(struct svc_rqst *rqstp, u32 *statp, u32 *authp)
{
{
        struct svc_buf  *argp = &rqstp->rq_argbuf;
        struct svc_buf  *argp = &rqstp->rq_argbuf;
        struct svc_buf  *resp = &rqstp->rq_resbuf;
        struct svc_buf  *resp = &rqstp->rq_resbuf;
        struct svc_cred *cred = &rqstp->rq_cred;
        struct svc_cred *cred = &rqstp->rq_cred;
        struct des_cred *data = NULL;
        struct des_cred *data = NULL;
        u32             cryptkey[2];
        u32             cryptkey[2];
        u32             cryptbuf[4];
        u32             cryptbuf[4];
        u32             *p = argp->buf;
        u32             *p = argp->buf;
        int             len   = argp->len, slen, i;
        int             len   = argp->len, slen, i;
 
 
        *authp = rpc_auth_ok;
        *authp = rpc_auth_ok;
 
 
        if ((argp->len -= 3) < 0) {
        if ((argp->len -= 3) < 0) {
                *statp = rpc_garbage_args;
                *statp = rpc_garbage_args;
                return;
                return;
        }
        }
 
 
        p++;                                    /* skip length field */
        p++;                                    /* skip length field */
        namekind = ntohl(*p++);                 /* fullname/nickname */
        namekind = ntohl(*p++);                 /* fullname/nickname */
 
 
        /* Get the credentials */
        /* Get the credentials */
        if (namekind == ADN_NICKNAME) {
        if (namekind == ADN_NICKNAME) {
                /* If we can't find the cached session key, initiate a
                /* If we can't find the cached session key, initiate a
                 * new session. */
                 * new session. */
                if (!(data = get_cred_bynick(*p++)))
                if (!(data = get_cred_bynick(*p++)))
                        FAIL(rejectedcred);
                        FAIL(rejectedcred);
        } else if (namekind == ADN_FULLNAME) {
        } else if (namekind == ADN_FULLNAME) {
                p = xdr_decode_string(p, &fullname, &len, RPC_MAXNETNAMELEN);
                p = xdr_decode_string(p, &fullname, &len, RPC_MAXNETNAMELEN);
                if (p == NULL)
                if (p == NULL)
                        FAIL(badcred);
                        FAIL(badcred);
                cryptkey[0] = *p++;              /* get the encrypted key */
                cryptkey[0] = *p++;              /* get the encrypted key */
                cryptkey[1] = *p++;
                cryptkey[1] = *p++;
                cryptbuf[2] = *p++;             /* get the encrypted window */
                cryptbuf[2] = *p++;             /* get the encrypted window */
        } else {
        } else {
                FAIL(badcred);
                FAIL(badcred);
        }
        }
 
 
        /* If we're just updating the key, silently discard the request. */
        /* If we're just updating the key, silently discard the request. */
        if (data && data->dc_locked) {
        if (data && data->dc_locked) {
                *authp = rpc_autherr_dropit;
                *authp = rpc_autherr_dropit;
                _put_cred(data);        /* release but don't unlock */
                _put_cred(data);        /* release but don't unlock */
                return;
                return;
        }
        }
 
 
        /* Get the verifier flavor and length */
        /* Get the verifier flavor and length */
        if (ntohl(*p++) != RPC_AUTH_DES && ntohl(*p++) != 12)
        if (ntohl(*p++) != RPC_AUTH_DES && ntohl(*p++) != 12)
                FAIL(badverf);
                FAIL(badverf);
 
 
        cryptbuf[0] = *p++;                      /* encrypted time stamp */
        cryptbuf[0] = *p++;                      /* encrypted time stamp */
        cryptbuf[1] = *p++;
        cryptbuf[1] = *p++;
        cryptbuf[3] = *p++;                     /* 0 or window - 1 */
        cryptbuf[3] = *p++;                     /* 0 or window - 1 */
 
 
        if (namekind == ADN_NICKNAME) {
        if (namekind == ADN_NICKNAME) {
                status = des_ecb_encrypt((des_block *) cryptbuf,
                status = des_ecb_encrypt((des_block *) cryptbuf,
                                         (des_block *) cryptbuf,
                                         (des_block *) cryptbuf,
                                         data->dc_keysched, DES_DECRYPT);
                                         data->dc_keysched, DES_DECRYPT);
        } else {
        } else {
                /* We first have to decrypt the new session key and
                /* We first have to decrypt the new session key and
                 * fill in the UNIX creds. */
                 * fill in the UNIX creds. */
                if (!(data = get_cred_byname(rqstp, authp, fullname, cryptkey)))
                if (!(data = get_cred_byname(rqstp, authp, fullname, cryptkey)))
                        return;
                        return;
                status = des_cbc_encrypt((des_cblock *) cryptbuf,
                status = des_cbc_encrypt((des_cblock *) cryptbuf,
                                         (des_cblock *) cryptbuf, 16,
                                         (des_cblock *) cryptbuf, 16,
                                         data->dc_keysched,
                                         data->dc_keysched,
                                         (des_cblock *) &ivec,
                                         (des_cblock *) &ivec,
                                         DES_DECRYPT);
                                         DES_DECRYPT);
        }
        }
        if (status) {
        if (status) {
                printk("svcauth_des: DES decryption failed (status %d)\n",
                printk("svcauth_des: DES decryption failed (status %d)\n",
                                status);
                                status);
                FAIL(badverf);
                FAIL(badverf);
        }
        }
 
 
        /* Now check the whole lot */
        /* Now check the whole lot */
        if (namekind == ADN_FULLNAME) {
        if (namekind == ADN_FULLNAME) {
                unsigned long   winverf;
                unsigned long   winverf;
 
 
                data->dc_window = ntohl(cryptbuf[2]);
                data->dc_window = ntohl(cryptbuf[2]);
                winverf = ntohl(cryptbuf[2]);
                winverf = ntohl(cryptbuf[2]);
                if (window != winverf - 1) {
                if (window != winverf - 1) {
                        printk("svcauth_des: bad window verifier!\n");
                        printk("svcauth_des: bad window verifier!\n");
                        FAIL(badverf);
                        FAIL(badverf);
                }
                }
        }
        }
 
 
        /* XDR the decrypted timestamp */
        /* XDR the decrypted timestamp */
        cryptbuf[0] = ntohl(cryptbuf[0]);
        cryptbuf[0] = ntohl(cryptbuf[0]);
        cryptbuf[1] = ntohl(cryptbuf[1]);
        cryptbuf[1] = ntohl(cryptbuf[1]);
        if (cryptbuf[1] > 1000000) {
        if (cryptbuf[1] > 1000000) {
                dprintk("svcauth_des: bad usec value %u\n", cryptbuf[1]);
                dprintk("svcauth_des: bad usec value %u\n", cryptbuf[1]);
                if (namekind == ADN_NICKNAME)
                if (namekind == ADN_NICKNAME)
                        FAIL(rejectedverf);
                        FAIL(rejectedverf);
                FAIL(badverf);
                FAIL(badverf);
        }
        }
 
 
        /*
        /*
         * Check for replayed credentials. We must allow for reordering
         * Check for replayed credentials. We must allow for reordering
         * of requests by the network, and the OS scheduler, hence we
         * of requests by the network, and the OS scheduler, hence we
         * cannot expect timestamps to be increasing monotonically.
         * cannot expect timestamps to be increasing monotonically.
         * This opens a small security hole, therefore the replay_slack
         * This opens a small security hole, therefore the replay_slack
         * value shouldn't be too large.
         * value shouldn't be too large.
         */
         */
        if ((delta = cryptbuf[0] - data->dc_timestamp[0]) <= 0) {
        if ((delta = cryptbuf[0] - data->dc_timestamp[0]) <= 0) {
                switch (delta) {
                switch (delta) {
                case -1:
                case -1:
                        delta = -1000000;
                        delta = -1000000;
                case 0:
                case 0:
                        delta += cryptbuf[1] - data->dc_timestamp[1];
                        delta += cryptbuf[1] - data->dc_timestamp[1];
                        break;
                        break;
                default:
                default:
                        delta = -1000000;
                        delta = -1000000;
                }
                }
                if (delta < DES_REPLAY_SLACK)
                if (delta < DES_REPLAY_SLACK)
                        FAIL(rejectedverf);
                        FAIL(rejectedverf);
#ifdef STRICT_REPLAY_CHECKS
#ifdef STRICT_REPLAY_CHECKS
                /* TODO: compare time stamp to last five timestamps cached
                /* TODO: compare time stamp to last five timestamps cached
                 * and reject (drop?) request if a match is found. */
                 * and reject (drop?) request if a match is found. */
#endif
#endif
        }
        }
 
 
        now = xtime;
        now = xtime;
        now.tv_secs -= data->dc_window;
        now.tv_secs -= data->dc_window;
        if (now.tv_secs < cryptbuf[0] ||
        if (now.tv_secs < cryptbuf[0] ||
            (now.tv_secs == cryptbuf[0] && now.tv_usec < cryptbuf[1]))
            (now.tv_secs == cryptbuf[0] && now.tv_usec < cryptbuf[1]))
                FAIL(rejectedverf);
                FAIL(rejectedverf);
 
 
        /* Okay, we're done. Update the lot */
        /* Okay, we're done. Update the lot */
        if (namekind == ADN_FULLNAME)
        if (namekind == ADN_FULLNAME)
                data->dc_valid = 1;
                data->dc_valid = 1;
        data->dc_timestamp[0] = cryptbuf[0];
        data->dc_timestamp[0] = cryptbuf[0];
        data->dc_timestamp[1] = cryptbuf[1];
        data->dc_timestamp[1] = cryptbuf[1];
 
 
        put_cred(data);
        put_cred(data);
        return;
        return;
garbage:
garbage:
        *statp = rpc_garbage_args;
        *statp = rpc_garbage_args;
        return;
        return;
}
}
 
 
/*
/*
 * Call the keyserver to obtain the decrypted conversation key and
 * Call the keyserver to obtain the decrypted conversation key and
 * UNIX creds. We use a Linux-specific keycall extension that does
 * UNIX creds. We use a Linux-specific keycall extension that does
 * both things in one go.
 * both things in one go.
 */
 */
static struct des_cred *
static struct des_cred *
get_cred_byname(struct svc_rqst *rqstp, u32 *authp, char *fullname, u32 *cryptkey)
get_cred_byname(struct svc_rqst *rqstp, u32 *authp, char *fullname, u32 *cryptkey)
{
{
        static int      in_keycall = 0;
        static int      in_keycall = 0;
        struct des_cred *cred;
        struct des_cred *cred;
 
 
        if (in_keycall) {
        if (in_keycall) {
                *authp = rpc_autherr_dropit;
                *authp = rpc_autherr_dropit;
                return NULL;
                return NULL;
        }
        }
        in_keycall = 1;
        in_keycall = 1;
        in_keycall = 0;
        in_keycall = 0;
        return cred;
        return cred;
}
}
 
 

powered by: WebSVN 2.1.0

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