#include <linux/err.h>
#include <linux/seq_file.h>
#include <linux/hash.h>
+#include <linux/string.h>
#define RPCDBG_FACILITY RPCDBG_AUTH
*/
-static char *strdup(char *s)
-{
- char *rv = kmalloc(strlen(s)+1, GFP_KERNEL);
- if (rv)
- strcpy(rv, s);
- return rv;
-}
-
struct unix_domain {
struct auth_domain h;
int addr_changes;
if (new == NULL)
return NULL;
cache_init(&new->h.h);
- new->h.name = strdup(name);
+ new->h.name = kstrdup(name, GFP_KERNEL);
new->h.flavour = RPC_AUTH_UNIX;
new->addr_changes = 0;
new->h.h.expiry_time = NEVER;
};
static struct cache_head *ip_table[IP_HASHMAX];
-void ip_map_put(struct cache_head *item, struct cache_detail *cd)
+static void ip_map_put(struct cache_head *item, struct cache_detail *cd)
{
struct ip_map *im = container_of(item, struct ip_map,h);
if (cache_put(item, cd)) {
}
}
+#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(unsigned long ip)
+{
+ int hash = ip ^ (ip>>16);
+ return (hash ^ (hash>>8)) & 0xff;
+}
+#endif
+
static inline int ip_map_hash(struct ip_map *item)
{
return hash_str(item->m_class, IP_HASHBITS) ^
- hash_long((unsigned long)item->m_addr.s_addr, IP_HASHBITS);
+ hash_ip((unsigned long)item->m_addr.s_addr);
}
static inline int ip_map_match(struct ip_map *item, struct ip_map *tmp)
{
struct cache_detail ip_map_cache = {
+ .owner = THIS_MODULE,
.hash_size = IP_HASHMAX,
.hash_table = ip_table,
.name = "auth.unix.ip",
cache_purge(&auth_domain_cache);
}
+static int
+svcauth_unix_set_client(struct svc_rqst *rqstp)
+{
+ struct ip_map key, *ipm;
+
+ rqstp->rq_client = NULL;
+ if (rqstp->rq_proc == 0)
+ return SVC_OK;
+
+ strcpy(key.m_class, rqstp->rq_server->sv_program->pg_class);
+ key.m_addr = rqstp->rq_addr.sin_addr;
+
+ ipm = ip_map_lookup(&key, 0);
+
+ if (ipm == NULL)
+ return SVC_DENIED;
+
+ switch (cache_check(&ip_map_cache, &ipm->h, &rqstp->rq_chandle)) {
+ default:
+ BUG();
+ case -EAGAIN:
+ return SVC_DROP;
+ case -ENOENT:
+ return SVC_DENIED;
+ case 0:
+ rqstp->rq_client = &ipm->m_client->h;
+ cache_get(&rqstp->rq_client->h);
+ ip_map_put(&ipm->h, &ip_map_cache);
+ break;
+ }
+ return SVC_OK;
+}
static int
svcauth_null_accept(struct svc_rqst *rqstp, u32 *authp)
{
struct kvec *argv = &rqstp->rq_arg.head[0];
struct kvec *resv = &rqstp->rq_res.head[0];
- int rv=0;
- struct ip_map key, *ipm;
+ struct svc_cred *cred = &rqstp->rq_cred;
+
+ cred->cr_group_info = NULL;
+ rqstp->rq_client = NULL;
if (argv->iov_len < 3*4)
return SVC_GARBAGE;
}
/* Signal that mapping to nobody uid/gid is required */
- rqstp->rq_cred.cr_uid = (uid_t) -1;
- rqstp->rq_cred.cr_gid = (gid_t) -1;
- rqstp->rq_cred.cr_group_info = groups_alloc(0);
- if (rqstp->rq_cred.cr_group_info == NULL)
+ cred->cr_uid = (uid_t) -1;
+ cred->cr_gid = (gid_t) -1;
+ cred->cr_group_info = groups_alloc(0);
+ if (cred->cr_group_info == NULL)
return SVC_DROP; /* kmalloc failure - client must retry */
/* Put NULL verifier */
svc_putu32(resv, RPC_AUTH_NULL);
svc_putu32(resv, 0);
- strcpy(key.m_class, rqstp->rq_server->sv_program->pg_class);
- key.m_addr = rqstp->rq_addr.sin_addr;
-
- ipm = ip_map_lookup(&key, 0);
-
- rqstp->rq_client = NULL;
-
- if (ipm)
- switch (cache_check(&ip_map_cache, &ipm->h, &rqstp->rq_chandle)) {
- case -EAGAIN:
- rv = SVC_DROP;
- break;
- case -ENOENT:
- rv = SVC_OK; /* rq_client is NULL */
- break;
- case 0:
- rqstp->rq_client = &ipm->m_client->h;
- cache_get(&rqstp->rq_client->h);
- ip_map_put(&ipm->h, &ip_map_cache);
- rv = SVC_OK;
- break;
- default: BUG();
- }
- else rv = SVC_DROP;
-
- if (rqstp->rq_client == NULL && rqstp->rq_proc != 0)
- *authp = rpc_autherr_badcred;
-
- return rv;
+ return SVC_OK;
}
static int
.flavour = RPC_AUTH_NULL,
.accept = svcauth_null_accept,
.release = svcauth_null_release,
+ .set_client = svcauth_unix_set_client,
};
-int
+static int
svcauth_unix_accept(struct svc_rqst *rqstp, u32 *authp)
{
struct kvec *argv = &rqstp->rq_arg.head[0];
struct svc_cred *cred = &rqstp->rq_cred;
u32 slen, i;
int len = argv->iov_len;
- int rv=0;
- struct ip_map key, *ipm;
cred->cr_group_info = NULL;
rqstp->rq_client = NULL;
return SVC_DENIED;
}
-
- strcpy(key.m_class, rqstp->rq_server->sv_program->pg_class);
- key.m_addr = rqstp->rq_addr.sin_addr;
-
-
- ipm = ip_map_lookup(&key, 0);
-
- if (ipm)
- switch (cache_check(&ip_map_cache, &ipm->h, &rqstp->rq_chandle)) {
- case -EAGAIN:
- rv = SVC_DROP;
- break;
- case -ENOENT:
- rv = SVC_OK; /* rq_client is NULL */
- break;
- case 0:
- rqstp->rq_client = &ipm->m_client->h;
- cache_get(&rqstp->rq_client->h);
- ip_map_put(&ipm->h, &ip_map_cache);
- rv = SVC_OK;
- break;
- default: BUG();
- }
- else rv = SVC_DROP;
-
- if (rv == SVC_OK && rqstp->rq_client == NULL && rqstp->rq_proc != 0)
- goto badcred;
-
/* Put NULL verifier */
svc_putu32(resv, RPC_AUTH_NULL);
svc_putu32(resv, 0);
- return rv;
+ return SVC_OK;
badcred:
*authp = rpc_autherr_badcred;
return SVC_DENIED;
}
-int
+static int
svcauth_unix_release(struct svc_rqst *rqstp)
{
/* Verifier (such as it is) is already in place.
.accept = svcauth_unix_accept,
.release = svcauth_unix_release,
.domain_release = svcauth_unix_domain_release,
+ .set_client = svcauth_unix_set_client,
};