1 |
/* |
/* cache.c - Cache operations for the nfs daemon. |
2 |
Copyright (C) 1996,98,99,2000,02 Free Software Foundation, Inc. |
Copyright (C) 1996,98,99,2000,02 Free Software Foundation, Inc. |
3 |
Written by Michael I. Bushnell, p/BSG. |
Written by Michael I. Bushnell, p/BSG. |
4 |
|
|
46 |
static int nfreeids; |
static int nfreeids; |
47 |
static int leastidlastuse; |
static int leastidlastuse; |
48 |
|
|
49 |
/* Compare I against the specified set of users/groups. */ |
/* Compare I against the specified set of users/groups. */ |
50 |
/* Use of int in decl of UIDS and GIDS is correct here; that's |
/* Use of int in decl of UIDS and GIDS is correct here; that's |
51 |
the NFS type because they come in in known 32 bit slots. */ |
the NFS type because they come in in known 32 bit slots. */ |
52 |
static int |
static int |
53 |
idspec_compare (struct idspec *i, int nuids, int ngids, |
idspec_compare (struct idspec *i, int nuids, int ngids, |
54 |
int *uids, int *gids) |
int *uids, int *gids) |
66 |
return 1; |
return 1; |
67 |
} |
} |
68 |
|
|
69 |
/* Compute a hash value for a given user spec */ |
/* Compute a hash value for a given user spec. */ |
70 |
static int |
static int |
71 |
idspec_hash (int nuids, int ngids, int *uids, int *gids) |
idspec_hash (int nuids, int ngids, int *uids, int *gids) |
72 |
{ |
{ |
81 |
return hash; |
return hash; |
82 |
} |
} |
83 |
|
|
84 |
/* Lookup a user spec in the hash table and allocate a reference */ |
/* Lookup a user spec in the hash table and allocate a reference. */ |
85 |
static struct idspec * |
static struct idspec * |
86 |
idspec_lookup (int nuids, int ngids, int *uids, int *gids) |
idspec_lookup (int nuids, int ngids, int *uids, int *gids) |
87 |
{ |
{ |
107 |
i->ngids = ngids; |
i->ngids = ngids; |
108 |
i->uids = malloc (nuids * sizeof (uid_t)); |
i->uids = malloc (nuids * sizeof (uid_t)); |
109 |
i->gids = malloc (ngids * sizeof (gid_t)); |
i->gids = malloc (ngids * sizeof (gid_t)); |
110 |
bcopy (uids, i->uids, nuids * sizeof (uid_t)); |
memcpy (i->uids, uids, nuids * sizeof (uid_t)); |
111 |
bcopy (gids, i->gids, ngids * sizeof (gid_t)); |
memcpy (i->gids, gids, ngids * sizeof (gid_t)); |
112 |
i->references = 1; |
i->references = 1; |
113 |
|
|
114 |
i->next = idhashtable[hash]; |
i->next = idhashtable[hash]; |
132 |
int firstgid; |
int firstgid; |
133 |
int i; |
int i; |
134 |
|
|
135 |
type = ntohl (*p++); |
type = ntohl (*p); |
136 |
|
p++; |
137 |
|
|
138 |
if (type != AUTH_UNIX) |
if (type != AUTH_UNIX) |
139 |
{ |
{ |
140 |
int size = ntohl (*p++); |
int size = ntohl (*p); |
141 |
|
p++; |
142 |
*credp = idspec_lookup (0, 0, 0, 0); |
*credp = idspec_lookup (0, 0, 0, 0); |
143 |
p += INTSIZE (size); |
p += INTSIZE (size); |
144 |
} |
} |
145 |
else |
else |
146 |
{ |
{ |
147 |
p++; /* skip size */ |
p++; /* Skip size. */ |
148 |
p++; /* skip seconds */ |
p++; /* Skip seconds. */ |
149 |
len = ntohl (*p++); |
len = ntohl (*p); |
150 |
p += INTSIZE (len); /* skip hostname */ |
p++; |
151 |
|
p += INTSIZE (len); /* Skip hostname. */ |
152 |
|
|
153 |
uid = p++; /* remember loc of uid */ |
uid = p++; /* Remember location of uid. */ |
154 |
*uid = ntohl (*uid); |
*uid = ntohl (*uid); |
155 |
|
|
156 |
firstgid = *p++; /* remember first gid */ |
firstgid = *(p++); /* Remember first gid. */ |
157 |
gids = p; /* here's where the array will start */ |
gids = p; /* Here is where the array will start. */ |
158 |
ngids = ntohl (*p++); |
ngids = ntohl (*p); |
159 |
|
p++; |
160 |
|
|
161 |
/* Now swap the first gid to be the first element of the array */ |
/* Now swap the first gid to be the first element of the |
162 |
|
array. */ |
163 |
*gids = firstgid; |
*gids = firstgid; |
164 |
ngids++; /* and count it */ |
ngids++; /* And count it. */ |
165 |
|
|
166 |
/* And byteswap the gids */ |
/* And byteswap the gids. */ |
167 |
for (i = 0; i < ngids; i++) |
for (i = 0; i < ngids; i++) |
168 |
gids[i] = ntohl (gids[i]); |
gids[i] = ntohl (gids[i]); |
169 |
|
|
172 |
*credp = idspec_lookup (1, ngids, uid, gids); |
*credp = idspec_lookup (1, ngids, uid, gids); |
173 |
} |
} |
174 |
|
|
175 |
/* Next is the verf field; skip it entirely */ |
/* Next is the verf field; skip it entirely. */ |
176 |
p++; /* skip id */ |
p++; /* Skip ID. */ |
177 |
len = htonl (*p++); |
len = htonl (*p); |
178 |
|
p++; |
179 |
p += INTSIZE (len); |
p += INTSIZE (len); |
180 |
|
|
181 |
return p; |
return p; |
241 |
} |
} |
242 |
} |
} |
243 |
|
|
244 |
/* If we didn't bail early, then this is valid */ |
/* If we didn't bail early, then this is valid. */ |
245 |
if (nfreeids) |
if (nfreeids) |
246 |
leastidlastuse = newleast; |
leastidlastuse = newleast; |
247 |
} |
} |
287 |
return p + NFS2_FHSIZE / sizeof (int); |
return p + NFS2_FHSIZE / sizeof (int); |
288 |
} |
} |
289 |
|
|
290 |
/* Not found */ |
/* Not found. */ |
291 |
|
|
292 |
/* First four bytes are our internal table of filesystems */ |
/* First four bytes are our internal table of filesystems. */ |
293 |
fsys = lookup_filesystem (*p); |
fsys = lookup_filesystem (*p); |
294 |
if (fsys == MACH_PORT_NULL |
if (fsys == MACH_PORT_NULL |
295 |
|| fsys_getfile (fsys, i->uids, i->nuids, i->gids, i->ngids, |
|| fsys_getfile (fsys, i->uids, i->nuids, i->gids, i->ngids, |
301 |
} |
} |
302 |
|
|
303 |
c = malloc (sizeof (struct cache_handle)); |
c = malloc (sizeof (struct cache_handle)); |
304 |
bcopy (p, c->handle, NFS2_FHSIZE); |
memcpy (c->handle, p, NFS2_FHSIZE); |
305 |
cred_ref (i); |
cred_ref (i); |
306 |
c->ids = i; |
c->ids = i; |
307 |
c->port = port; |
c->port = port; |
369 |
} |
} |
370 |
} |
} |
371 |
|
|
372 |
/* If we didn't bail early, then this is valid. */ |
/* If we didn't bail early, then this is valid. */ |
373 |
if (nfreefh) |
if (nfreefh) |
374 |
leastfhlastuse = newleast; |
leastfhlastuse = newleast; |
375 |
} |
} |
387 |
size_t handlelen = NFS2_FHSIZE - sizeof (int); |
size_t handlelen = NFS2_FHSIZE - sizeof (int); |
388 |
mach_port_t newport, ref; |
mach_port_t newport, ref; |
389 |
|
|
390 |
/* Authenticate USERPORT so that we can call file_getfh on it. */ |
/* Authenticate USERPORT so that we can call file_getfh on it. */ |
391 |
ref = mach_reply_port (); |
ref = mach_reply_port (); |
392 |
/* MAKE_SEND is safe becaue we destroy REF ourselves. */ |
/* MAKE_SEND is safe becaue we destroy REF ourselves. */ |
393 |
if (io_reauthenticate (userport, ref, MACH_MSG_TYPE_MAKE_SEND) |
if (io_reauthenticate (userport, ref, MACH_MSG_TYPE_MAKE_SEND) |
394 |
|| auth_user_authenticate (authserver, ref, MACH_MSG_TYPE_MAKE_SEND, |
|| auth_user_authenticate (authserver, ref, MACH_MSG_TYPE_MAKE_SEND, |
395 |
&newport)) |
&newport)) |
396 |
{ |
{ |
397 |
/* Reauthentication has failed, but maybe the filesystem will let |
/* Reauthentication has failed, but maybe the filesystem will let |
398 |
us call file_getfh anyway. */ |
us call file_getfh anyway. */ |
399 |
newport = userport; |
newport = userport; |
400 |
} |
} |
401 |
else |
else |
402 |
mach_port_deallocate (mach_task_self (), userport); |
mach_port_deallocate (mach_task_self (), userport); |
403 |
mach_port_destroy (mach_task_self (), ref); |
mach_port_destroy (mach_task_self (), ref); |
404 |
|
|
405 |
/* Fetch the file handle */ |
/* Fetch the file handle. */ |
406 |
*(int *)fhandle = fs; |
*(int *)fhandle = fs; |
407 |
err = file_getfh (newport, &bp, &handlelen); |
err = file_getfh (newport, &bp, &handlelen); |
408 |
mach_port_deallocate (mach_task_self (), newport); |
mach_port_deallocate (mach_task_self (), newport); |
410 |
return 0; |
return 0; |
411 |
if (bp != fhandle + sizeof (int)) |
if (bp != fhandle + sizeof (int)) |
412 |
{ |
{ |
413 |
bcopy (bp, fhandle + sizeof (int), NFS2_FHSIZE - sizeof (int)); |
memcpy (fhandle + sizeof (int), bp, NFS2_FHSIZE - sizeof (int)); |
414 |
munmap (bp, handlelen); |
munmap (bp, handlelen); |
415 |
} |
} |
416 |
|
|
417 |
/* Cache it */ |
/* Cache it. */ |
418 |
hash = fh_hash (fhandle, credc->ids); |
hash = fh_hash (fhandle, credc->ids); |
419 |
mutex_lock (&fhhashlock); |
mutex_lock (&fhhashlock); |
420 |
for (c = fhhashtable[hash]; c; c = c->next) |
for (c = fhhashtable[hash]; c; c = c->next) |
421 |
if (c->ids == credc->ids && ! bcmp (fhandle, c->handle, NFS2_FHSIZE)) |
if (c->ids == credc->ids && ! bcmp (fhandle, c->handle, NFS2_FHSIZE)) |
422 |
{ |
{ |
423 |
/* Return this one */ |
/* Return this one. */ |
424 |
if (c->references == 0) |
if (c->references == 0) |
425 |
nfreefh--; |
nfreefh--; |
426 |
c->references++; |
c->references++; |
429 |
} |
} |
430 |
|
|
431 |
/* Always call fsys_getfile so that we don't depend on the |
/* Always call fsys_getfile so that we don't depend on the |
432 |
particular open modes of the port passed in. */ |
particular open modes of the port passed in. */ |
433 |
|
|
434 |
err = fsys_getfile (lookup_filesystem (fs), |
err = fsys_getfile (lookup_filesystem (fs), |
435 |
credc->ids->uids, credc->ids->nuids, |
credc->ids->uids, credc->ids->nuids, |
442 |
return 0; |
return 0; |
443 |
} |
} |
444 |
|
|
445 |
/* Create it anew */ |
/* Create it anew. */ |
446 |
c = malloc (sizeof (struct cache_handle)); |
c = malloc (sizeof (struct cache_handle)); |
447 |
bcopy (fhandle, c->handle, NFS2_FHSIZE); |
memcpy (c->handle, fhandle, NFS2_FHSIZE); |
448 |
cred_ref (credc->ids); |
cred_ref (credc->ids); |
449 |
c->ids = credc->ids; |
c->ids = credc->ids; |
450 |
c->port = newport; |
c->port = newport; |
451 |
c->references = 1; |
c->references = 1; |
452 |
|
|
453 |
/* And add it to the hash table */ |
/* And add it to the hash table. */ |
454 |
c->next = fhhashtable[hash]; |
c->next = fhhashtable[hash]; |
455 |
if (c->next) |
if (c->next) |
456 |
c->next->prevp = &c->next; |
c->next->prevp = &c->next; |
470 |
|
|
471 |
/* Check the list of cached replies to see if this is a replay of a |
/* Check the list of cached replies to see if this is a replay of a |
472 |
previous transaction; if so, return the cache record. Otherwise, |
previous transaction; if so, return the cache record. Otherwise, |
473 |
create a new cache record. */ |
create a new cache record. */ |
474 |
struct cached_reply * |
struct cached_reply * |
475 |
check_cached_replies (int xid, |
check_cached_replies (int xid, |
476 |
struct sockaddr_in *sender) |
struct sockaddr_in *sender) |
496 |
cr = malloc (sizeof (struct cached_reply)); |
cr = malloc (sizeof (struct cached_reply)); |
497 |
mutex_init (&cr->lock); |
mutex_init (&cr->lock); |
498 |
mutex_lock (&cr->lock); |
mutex_lock (&cr->lock); |
499 |
bcopy (sender, &cr->source, sizeof (struct sockaddr_in)); |
memcpy (&cr->source, sender, sizeof (struct sockaddr_in)); |
500 |
cr->xid = xid; |
cr->xid = xid; |
501 |
cr->data = 0; |
cr->data = 0; |
502 |
cr->references = 1; |
cr->references = 1; |
512 |
} |
} |
513 |
|
|
514 |
/* A cached reply returned by check_cached_replies is now no longer |
/* A cached reply returned by check_cached_replies is now no longer |
515 |
needed by its caller. */ |
needed by its caller. */ |
516 |
void |
void |
517 |
release_cached_reply (struct cached_reply *cr) |
release_cached_reply (struct cached_reply *cr) |
518 |
{ |
{ |
565 |
} |
} |
566 |
} |
} |
567 |
|
|
568 |
/* If we didn't bail early, then this is valid */ |
/* If we didn't bail early, then this is valid. */ |
569 |
if (nfreereplies) |
if (nfreereplies) |
570 |
leastreplylastuse = newleast; |
leastreplylastuse = newleast; |
571 |
} |
} |