svcauthdes.c revision 67dbe2be0c0f1e2eb428b89088bb5667e8f0b9f6
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
* Portions of this source code were derived from Berkeley 4.3 BSD
* under license from the Regents of the University of California.
*/
/*
* svcauth_des.c, server-side des authentication
*
* We insure for the service the following:
* (1) The timestamp microseconds do not exceed 1 million.
* (2) The timestamp plus the window is less than the current time.
* (3) The timestamp is not less than the one previously
* seen in the current session.
*
* It is up to the server to determine if the window size is
* too small.
*/
#include <rpc/auth_des.h>
#include <rpc/svc_auth.h>
#include <rpc/des_crypt.h>
#define USEC_PER_SEC 1000000
/*
* Cache of conversation keys and some other useful items.
* The hash table size is controled via authdes_cachesz variable.
* The authdes_cachesz has to be the power of 2.
*/
#define AUTHDES_CACHE_TABLE_SZ 1024
static int authdes_cachesz = AUTHDES_CACHE_TABLE_SZ;
/* low water mark for the number of cache entries */
static int low_cache_entries = 128;
struct authdes_cache_entry {
char *rname; /* client's name */
};
static struct kmem_cache *authdes_cache_handle;
static struct authdes_cache_entry *authdes_cache_new(char *,
static void authdes_cache_reclaim(void *);
static void sweep_cache();
/*
* After 12 hours, check and delete cache entries that have been
* idled for more than 10 hours.
*/
static time_t authdes_last_swept = 0;
/*
* cache statistics
*/
static int authdes_ncache = 0; /* number of current cached entries */
static int authdes_ncachehits = 0; /* #times cache hit */
static int authdes_ncachemisses = 0; /* #times cache missed */
/*
* Service side authenticator for AUTH_DES
*/
enum auth_stat
{
struct authdes_cred *cred;
struct authdes_verf verf;
int status;
struct authdes_cache_entry *nick_entry;
struct area {
struct authdes_cred area_cred;
} *area;
if (authdes_cache == NULL) {
sizeof (struct authdes_cache_entry *) * authdes_cachesz,
KM_SLEEP);
}
/* LINTED pointer alignment */
/*
* Get the credential
*/
/* LINTED pointer alignment */
switch (cred->adc_namekind) {
case ADN_FULLNAME:
if (namelen > MAXNETNAMELEN)
return (AUTH_BADCRED);
break;
case ADN_NICKNAME:
break;
default:
return (AUTH_BADCRED);
}
/*
* Get the verifier
*/
/* LINTED pointer alignment */
/*
* Get the conversation key
*/
if (!nick) { /* ADN_FULLNAME */
RPC_SUCCESS) {
return (AUTH_BADCRED); /* key not found */
}
} else { /* ADN_NICKNAME */
cred->adc_nickname);
return (AUTH_BADCRED); /* need refresh */
}
}
/*
* Decrypt the timestamp
*/
if (!nick) { /* ADN_FULLNAME */
} else { /* ADN_NICKNAME */
sizeof (des_block), DES_DECRYPT);
}
if (DES_FAILED(status)) {
if (nick) {
}
return (AUTH_FAILED); /* system error */
}
/*
* XDR the decrypted timestamp
*/
/*
* Check for valid credentials and verifiers.
* They could be invalid because the key was flushed
* out of the cache, and so a new session should begin.
* Be sure and send AUTH_REJECTED{CRED, VERF} if this is the case.
*/
if (!nick) { /* ADN_FULLNAME */
winverf);
return (AUTH_BADCRED); /* garbled credential */
}
} else { /* ADN_NICKNAME */
}
/* cached out (bad key), or garbled verifier */
if (nick) {
}
}
gethrestime(&now);
/* replay, or garbled credential */
if (nick) {
}
}
/*
* xdr the timestamp before encrypting
*/
/*
* encrypt the timestamp
*/
sizeof (des_block), DES_ENCRYPT);
if (DES_FAILED(status)) {
if (nick) {
}
return (AUTH_FAILED); /* system error */
}
/*
* If a ADN_FULLNAME, create a new nickname cache entry.
*/
if (!nick) {
sessionkey, window))) {
return (AUTH_FAILED);
}
}
/*
* Serialize the reply verifier, and update rqst
*/
/* LINTED pointer alignment */
return (AUTH_BADVERF);
}
/*
* We succeeded and finish cooking the credential.
* nicknames are cooked into fullnames
*/
if (!nick) {
} else { /* ADN_NICKNAME */
}
/*
* For every authdes_sweep_interval, delete cache entries that have been
* idled for authdes_cache_time.
*/
sweep_cache();
return (AUTH_OK); /* we made it! */
}
/*
* Initialization upon loading the rpcsec module.
*/
void
svcauthdes_init(void)
{
/*
* Allocate des cache handle
*/
}
/*
* Final actions upon exiting the rpcsec module.
*/
void
svcauthdes_fini(void)
{
}
/*
* Local credential handling stuff.
* NOTE: bsd unix dependent.
* Other operating systems should put something else here.
*/
struct bsdcred {
short valid; /* valid creds */
short grouplen; /* length of cached groups */
};
/*
* Map a des credential into a unix cred.
* We cache the credential here so the application does
* not have to make an rpc call every time to interpret
* the credential.
*/
int
{
int i_grouplen;
struct authdes_cache_entry *nickentry;
return (0);
}
/* LINTED pointer alignment */
/*
* not in cache: lookup
*/
/*
* Probably a host principal, since at this
* point we have valid keys. Note that later
* if the principal is not in the root list
* for NFS, we will be mapped to that exported
* file system's anonymous user, typically
* NOBODY. keyserv KEY_GETCRED will fail for a
* root-netnames so we assume root here.
* Currently NFS is the only caller of this
* routine. If other RPC services call this
* routine, it is up to that service to
* differentiate between local and remote
* roots.
*/
i_uid = 0;
i_gid = 0;
i_grouplen = 0;
}
}
/*
* cached credentials
*/
return (0);
}
return (1);
}
/*
* Create a new cache_entry and put it in authdes_cache table.
* Caller should have already locked the authdes_cache table.
*/
struct authdes_cache_entry *
int index;
return (NULL);
}
return (NULL);
}
return (NULL);
}
/* put new into the hash table */
}
/* update the LRU list */
} else {
}
return (new);
}
/*
* Get an existing cache entry from authdes_cache table.
* The caller should have locked the authdes_cache table.
*/
struct authdes_cache_entry *
/* find it, update the LRU list */
} else {
}
}
return (cur);
}
}
return (NULL);
}
/*
* authdes_cache_reclaim() is called by the kernel memory allocator
* when memory is low. This routine will reclaim 25% of the least recent
* used cache entries above the low water mark (low_cache_entries).
* If the cache entries have already hit the low water mark, it will
* return 1 cache entry.
*/
/*ARGSUSED*/
void
authdes_cache_reclaim(void *pdata) {
struct authdes_cache_entry *p;
int n, i;
n = authdes_ncache - low_cache_entries;
n = n > 0 ? n/4 : 1;
for (i = 0; i < n; i++) {
break;
/* Update the hash linked list */
} else {
}
}
/* update the LRU linked list */
mutex_destroy(&p->lock);
}
}
/*
* Walk through the LRU doubly-linked list and delete the cache
* entries that have not been used for more than authdes_cache_time.
*
* Caller should have locked the cache table.
*/
void
sweep_cache() {
struct authdes_cache_entry *p;
IS_ALIGNED(p);
NOT_DEAD(p);
/*
* If the last LRU entry idled less than authdes_cache_time,
* we are done with the sweeping.
*/
break;
/* update the hash linked list */
} else {
}
}
/* update the LRU linked list */
mutex_destroy(&p->lock);
}
}