⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 svcauth_unix.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
#include <linux/types.h>#include <linux/sched.h>#include <linux/module.h>#include <linux/sunrpc/types.h>#include <linux/sunrpc/xdr.h>#include <linux/sunrpc/svcsock.h>#include <linux/sunrpc/svcauth.h>#include <linux/sunrpc/gss_api.h>#include <linux/err.h>#include <linux/seq_file.h>#include <linux/hash.h>#include <linux/string.h>#include <net/sock.h>#define RPCDBG_FACILITY	RPCDBG_AUTH/* * AUTHUNIX and AUTHNULL credentials are both handled here. * AUTHNULL is treated just like AUTHUNIX except that the uid/gid * are always nobody (-2).  i.e. we do the same IP address checks for * AUTHNULL as for AUTHUNIX, and that is done here. */struct unix_domain {	struct auth_domain	h;	int	addr_changes;	/* other stuff later */};extern struct auth_ops svcauth_unix;struct auth_domain *unix_domain_find(char *name){	struct auth_domain *rv;	struct unix_domain *new = NULL;	rv = auth_domain_lookup(name, NULL);	while(1) {		if (rv) {			if (new && rv != &new->h)				auth_domain_put(&new->h);			if (rv->flavour != &svcauth_unix) {				auth_domain_put(rv);				return NULL;			}			return rv;		}		new = kmalloc(sizeof(*new), GFP_KERNEL);		if (new == NULL)			return NULL;		kref_init(&new->h.ref);		new->h.name = kstrdup(name, GFP_KERNEL);		if (new->h.name == NULL) {			kfree(new);			return NULL;		}		new->h.flavour = &svcauth_unix;		new->addr_changes = 0;		rv = auth_domain_lookup(name, &new->h);	}}static void svcauth_unix_domain_release(struct auth_domain *dom){	struct unix_domain *ud = container_of(dom, struct unix_domain, h);	kfree(dom->name);	kfree(ud);}/************************************************** * cache for IP address to unix_domain * as needed by AUTH_UNIX */#define	IP_HASHBITS	8#define	IP_HASHMAX	(1<<IP_HASHBITS)#define	IP_HASHMASK	(IP_HASHMAX-1)struct ip_map {	struct cache_head	h;	char			m_class[8]; /* e.g. "nfsd" */	struct in_addr		m_addr;	struct unix_domain	*m_client;	int			m_add_change;};static struct cache_head	*ip_table[IP_HASHMAX];static void ip_map_put(struct kref *kref){	struct cache_head *item = container_of(kref, struct cache_head, ref);	struct ip_map *im = container_of(item, struct ip_map,h);	if (test_bit(CACHE_VALID, &item->flags) &&	    !test_bit(CACHE_NEGATIVE, &item->flags))		auth_domain_put(&im->m_client->h);	kfree(im);}#if IP_HASHBITS == 8/* hash_long on a 64 bit machine is currently REALLY BAD for * IP addresses in reverse-endian (i.e. on a little-endian machine). * So use a trivial but reliable hash instead */static inline int hash_ip(__be32 ip){	int hash = (__force u32)ip ^ ((__force u32)ip>>16);	return (hash ^ (hash>>8)) & 0xff;}#endifstatic int ip_map_match(struct cache_head *corig, struct cache_head *cnew){	struct ip_map *orig = container_of(corig, struct ip_map, h);	struct ip_map *new = container_of(cnew, struct ip_map, h);	return strcmp(orig->m_class, new->m_class) == 0		&& orig->m_addr.s_addr == new->m_addr.s_addr;}static void ip_map_init(struct cache_head *cnew, struct cache_head *citem){	struct ip_map *new = container_of(cnew, struct ip_map, h);	struct ip_map *item = container_of(citem, struct ip_map, h);	strcpy(new->m_class, item->m_class);	new->m_addr.s_addr = item->m_addr.s_addr;}static void update(struct cache_head *cnew, struct cache_head *citem){	struct ip_map *new = container_of(cnew, struct ip_map, h);	struct ip_map *item = container_of(citem, struct ip_map, h);	kref_get(&item->m_client->h.ref);	new->m_client = item->m_client;	new->m_add_change = item->m_add_change;}static struct cache_head *ip_map_alloc(void){	struct ip_map *i = kmalloc(sizeof(*i), GFP_KERNEL);	if (i)		return &i->h;	else		return NULL;}static void ip_map_request(struct cache_detail *cd,				  struct cache_head *h,				  char **bpp, int *blen){	char text_addr[20];	struct ip_map *im = container_of(h, struct ip_map, h);	__be32 addr = im->m_addr.s_addr;	snprintf(text_addr, 20, "%u.%u.%u.%u",		 ntohl(addr) >> 24 & 0xff,		 ntohl(addr) >> 16 & 0xff,		 ntohl(addr) >>  8 & 0xff,		 ntohl(addr) >>  0 & 0xff);	qword_add(bpp, blen, im->m_class);	qword_add(bpp, blen, text_addr);	(*bpp)[-1] = '\n';}static struct ip_map *ip_map_lookup(char *class, struct in_addr addr);static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t expiry);static int ip_map_parse(struct cache_detail *cd,			  char *mesg, int mlen){	/* class ipaddress [domainname] */	/* should be safe just to use the start of the input buffer	 * for scratch: */	char *buf = mesg;	int len;	int b1,b2,b3,b4;	char c;	char class[8];	struct in_addr addr;	int err;	struct ip_map *ipmp;	struct auth_domain *dom;	time_t expiry;	if (mesg[mlen-1] != '\n')		return -EINVAL;	mesg[mlen-1] = 0;	/* class */	len = qword_get(&mesg, class, sizeof(class));	if (len <= 0) return -EINVAL;	/* ip address */	len = qword_get(&mesg, buf, mlen);	if (len <= 0) return -EINVAL;	if (sscanf(buf, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) != 4)		return -EINVAL;	expiry = get_expiry(&mesg);	if (expiry ==0)		return -EINVAL;	/* domainname, or empty for NEGATIVE */	len = qword_get(&mesg, buf, mlen);	if (len < 0) return -EINVAL;	if (len) {		dom = unix_domain_find(buf);		if (dom == NULL)			return -ENOENT;	} else		dom = NULL;	addr.s_addr =		htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);	ipmp = ip_map_lookup(class,addr);	if (ipmp) {		err = ip_map_update(ipmp,			     container_of(dom, struct unix_domain, h),			     expiry);	} else		err = -ENOMEM;	if (dom)		auth_domain_put(dom);	cache_flush();	return err;}static int ip_map_show(struct seq_file *m,		       struct cache_detail *cd,		       struct cache_head *h){	struct ip_map *im;	struct in_addr addr;	char *dom = "-no-domain-";	if (h == NULL) {		seq_puts(m, "#class IP domain\n");		return 0;	}	im = container_of(h, struct ip_map, h);	/* class addr domain */	addr = im->m_addr;	if (test_bit(CACHE_VALID, &h->flags) &&	    !test_bit(CACHE_NEGATIVE, &h->flags))		dom = im->m_client->h.name;	seq_printf(m, "%s %d.%d.%d.%d %s\n",		   im->m_class,		   ntohl(addr.s_addr) >> 24 & 0xff,		   ntohl(addr.s_addr) >> 16 & 0xff,		   ntohl(addr.s_addr) >>  8 & 0xff,		   ntohl(addr.s_addr) >>  0 & 0xff,		   dom		   );	return 0;}struct cache_detail ip_map_cache = {	.owner		= THIS_MODULE,	.hash_size	= IP_HASHMAX,	.hash_table	= ip_table,	.name		= "auth.unix.ip",	.cache_put	= ip_map_put,	.cache_request	= ip_map_request,	.cache_parse	= ip_map_parse,	.cache_show	= ip_map_show,	.match		= ip_map_match,	.init		= ip_map_init,	.update		= update,	.alloc		= ip_map_alloc,};static struct ip_map *ip_map_lookup(char *class, struct in_addr addr){	struct ip_map ip;	struct cache_head *ch;	strcpy(ip.m_class, class);	ip.m_addr = addr;	ch = sunrpc_cache_lookup(&ip_map_cache, &ip.h,				 hash_str(class, IP_HASHBITS) ^				 hash_ip(addr.s_addr));	if (ch)		return container_of(ch, struct ip_map, h);	else		return NULL;}static int ip_map_update(struct ip_map *ipm, struct unix_domain *udom, time_t expiry){	struct ip_map ip;	struct cache_head *ch;	ip.m_client = udom;	ip.h.flags = 0;	if (!udom)		set_bit(CACHE_NEGATIVE, &ip.h.flags);	else {		ip.m_add_change = udom->addr_changes;		/* if this is from the legacy set_client system call,		 * we need m_add_change to be one higher		 */		if (expiry == NEVER)			ip.m_add_change++;	}	ip.h.expiry_time = expiry;	ch = sunrpc_cache_update(&ip_map_cache,				 &ip.h, &ipm->h,				 hash_str(ipm->m_class, IP_HASHBITS) ^				 hash_ip(ipm->m_addr.s_addr));	if (!ch)		return -ENOMEM;	cache_put(ch, &ip_map_cache);	return 0;}int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom){	struct unix_domain *udom;	struct ip_map *ipmp;	if (dom->flavour != &svcauth_unix)		return -EINVAL;	udom = container_of(dom, struct unix_domain, h);	ipmp = ip_map_lookup("nfsd", addr);	if (ipmp)		return ip_map_update(ipmp, udom, NEVER);	else		return -ENOMEM;}int auth_unix_forget_old(struct auth_domain *dom){	struct unix_domain *udom;	if (dom->flavour != &svcauth_unix)		return -EINVAL;	udom = container_of(dom, struct unix_domain, h);	udom->addr_changes++;	return 0;}struct auth_domain *auth_unix_lookup(struct in_addr addr){	struct ip_map *ipm;	struct auth_domain *rv;	ipm = ip_map_lookup("nfsd", addr);	if (!ipm)		return NULL;	if (cache_check(&ip_map_cache, &ipm->h, NULL))		return NULL;	if ((ipm->m_client->addr_changes - ipm->m_add_change) >0) {		if (test_and_set_bit(CACHE_NEGATIVE, &ipm->h.flags) == 0)			auth_domain_put(&ipm->m_client->h);		rv = NULL;	} else {		rv = &ipm->m_client->h;		kref_get(&rv->ref);	}	cache_put(&ipm->h, &ip_map_cache);	return rv;}void svcauth_unix_purge(void){	cache_purge(&ip_map_cache);}static inline struct ip_map *ip_map_cached_get(struct svc_rqst *rqstp){	struct ip_map *ipm;	struct svc_sock *svsk = rqstp->rq_sock;	spin_lock(&svsk->sk_lock);	ipm = svsk->sk_info_authunix;	if (ipm != NULL) {		if (!cache_valid(&ipm->h)) {			/*			 * The entry has been invalidated since it was			 * remembered, e.g. by a second mount from the			 * same IP address.			 */			svsk->sk_info_authunix = NULL;			spin_unlock(&svsk->sk_lock);			cache_put(&ipm->h, &ip_map_cache);			return NULL;		}		cache_get(&ipm->h);	}	spin_unlock(&svsk->sk_lock);	return ipm;}static inline voidip_map_cached_put(struct svc_rqst *rqstp, struct ip_map *ipm){	struct svc_sock *svsk = rqstp->rq_sock;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -