Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
fec00732
Commit
fec00732
authored
Aug 23, 2004
by
Trond Myklebust
Browse files
Options
Browse Files
Download
Plain Diff
Merge
http://nfsclient.bkbits.net/linux-2.6
into fys.uio.no:/home/linux/bitkeeper/nfsclient-2.6
parents
865147c0
ecebe0fc
Changes
32
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
32 changed files
with
1253 additions
and
295 deletions
+1253
-295
fs/Kconfig
fs/Kconfig
+18
-2
fs/lockd/svclock.c
fs/lockd/svclock.c
+7
-2
fs/lockd/svcsubs.c
fs/lockd/svcsubs.c
+1
-1
fs/nfs/dir.c
fs/nfs/dir.c
+63
-58
fs/nfs/inode.c
fs/nfs/inode.c
+60
-94
fs/nfs/mount_clnt.c
fs/nfs/mount_clnt.c
+0
-2
fs/nfs/nfs2xdr.c
fs/nfs/nfs2xdr.c
+23
-4
fs/nfs/nfs3proc.c
fs/nfs/nfs3proc.c
+16
-8
fs/nfs/nfs3xdr.c
fs/nfs/nfs3xdr.c
+0
-4
fs/nfs/nfs4proc.c
fs/nfs/nfs4proc.c
+15
-11
fs/nfs/nfs4xdr.c
fs/nfs/nfs4xdr.c
+59
-37
fs/nfs/nfsroot.c
fs/nfs/nfsroot.c
+2
-4
fs/nfs/pagelist.c
fs/nfs/pagelist.c
+3
-12
fs/nfs/proc.c
fs/nfs/proc.c
+2
-0
fs/nfs/write.c
fs/nfs/write.c
+34
-31
include/linux/nfs.h
include/linux/nfs.h
+17
-0
include/linux/nfs4.h
include/linux/nfs4.h
+2
-0
include/linux/nfs_fs.h
include/linux/nfs_fs.h
+4
-4
include/linux/nfs_fs_sb.h
include/linux/nfs_fs_sb.h
+1
-0
include/linux/nfs_page.h
include/linux/nfs_page.h
+3
-5
include/linux/nfs_xdr.h
include/linux/nfs_xdr.h
+3
-1
include/linux/sunrpc/gss_asn1.h
include/linux/sunrpc/gss_asn1.h
+0
-1
include/linux/sunrpc/gss_spkm3.h
include/linux/sunrpc/gss_spkm3.h
+61
-0
net/sunrpc/auth_gss/Makefile
net/sunrpc/auth_gss/Makefile
+4
-0
net/sunrpc/auth_gss/auth_gss.c
net/sunrpc/auth_gss/auth_gss.c
+1
-1
net/sunrpc/auth_gss/gss_generic_token.c
net/sunrpc/auth_gss/gss_generic_token.c
+1
-1
net/sunrpc/auth_gss/gss_krb5_unseal.c
net/sunrpc/auth_gss/gss_krb5_unseal.c
+1
-1
net/sunrpc/auth_gss/gss_spkm3_mech.c
net/sunrpc/auth_gss/gss_spkm3_mech.c
+296
-0
net/sunrpc/auth_gss/gss_spkm3_seal.c
net/sunrpc/auth_gss/gss_spkm3_seal.c
+132
-0
net/sunrpc/auth_gss/gss_spkm3_token.c
net/sunrpc/auth_gss/gss_spkm3_token.c
+266
-0
net/sunrpc/auth_gss/gss_spkm3_unseal.c
net/sunrpc/auth_gss/gss_spkm3_unseal.c
+128
-0
net/sunrpc/clnt.c
net/sunrpc/clnt.c
+30
-11
No files found.
fs/Kconfig
View file @
fec00732
...
...
@@ -1415,8 +1415,8 @@ config NFS_V3
bool "Provide NFSv3 client support"
depends on NFS_FS
help
Say Y here if you want your NFS client to be able to speak
the newer
version
3 of the NFS protocol.
Say Y here if you want your NFS client to be able to speak
version
3 of the NFS protocol.
If unsure, say Y.
...
...
@@ -1560,6 +1560,22 @@ config RPCSEC_GSS_KRB5
If unsure, say N.
config RPCSEC_GSS_SPKM3
tristate "Secure RPC: SPKM3 mechanism (EXPERIMENTAL)"
depends on SUNRPC && EXPERIMENTAL
select SUNRPC_GSS
select CRYPTO
select CRYPTO_MD5
select CRYPTO_DES
help
Provides for secure RPC calls by means of a gss-api
mechanism based on the SPKM3 public-key mechanism.
Note: Requires an auxiliary userspace daemon which may be found on
http://www.citi.umich.edu/projects/nfsv4/
If unsure, say N.
config SMB_FS
tristate "SMB file system support (to mount Windows shares etc.)"
depends on INET
...
...
fs/lockd/svclock.c
View file @
fec00732
...
...
@@ -237,8 +237,13 @@ nlmsvc_delete_block(struct nlm_block *block, int unlock)
/* Remove block from list */
nlmsvc_remove_block
(
block
);
if
(
fl
->
fl_next
)
posix_unblock_lock
(
file
->
f_file
,
fl
);
if
(
unlock
)
{
fl
->
fl_type
=
F_UNLCK
;
posix_lock_file
(
file
->
f_file
,
fl
);
block
->
b_granted
=
0
;
}
/* If the block is in the middle of a GRANT callback,
* don't kill it yet. */
...
...
fs/lockd/svcsubs.c
View file @
fec00732
...
...
@@ -67,7 +67,7 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
down
(
&
nlm_file_sema
);
for
(
file
=
nlm_files
[
hash
];
file
;
file
=
file
->
f_next
)
if
(
!
memcmp
(
&
file
->
f_handle
,
f
,
sizeof
(
*
f
)
))
if
(
!
nfs_compare_fh
(
&
file
->
f_handle
,
f
))
goto
found
;
dprintk
(
"lockd: creating file for (%08x %08x %08x %08x %08x %08x)
\n
"
,
...
...
fs/nfs/dir.c
View file @
fec00732
...
...
@@ -610,7 +610,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
verifier
=
nfs_save_change_attribute
(
dir
);
error
=
nfs_cached_lookup
(
dir
,
dentry
,
&
fhandle
,
&
fattr
);
if
(
!
error
)
{
if
(
memcmp
(
NFS_FH
(
inode
),
&
fhandle
,
sizeof
(
struct
nfs_fh
))
!=
0
)
if
(
nfs_compare_fh
(
NFS_FH
(
inode
),
&
fhandle
)
)
goto
out_bad
;
if
(
nfs_lookup_verify_inode
(
inode
,
isopen
))
goto
out_zap_parent
;
...
...
@@ -623,7 +623,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
error
=
NFS_PROTO
(
dir
)
->
lookup
(
dir
,
&
dentry
->
d_name
,
&
fhandle
,
&
fattr
);
if
(
error
)
goto
out_bad
;
if
(
memcmp
(
NFS_FH
(
inode
),
&
fhandle
,
sizeof
(
struct
nfs_fh
))
!=
0
)
if
(
nfs_compare_fh
(
NFS_FH
(
inode
),
&
fhandle
)
)
goto
out_bad
;
if
((
error
=
nfs_refresh_inode
(
inode
,
&
fattr
))
!=
0
)
goto
out_bad
;
...
...
@@ -850,22 +850,22 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
unsigned
long
verifier
;
int
openflags
,
ret
=
0
;
/* NFS only supports OPEN for regular files */
if
(
inode
&&
!
S_ISREG
(
inode
->
i_mode
))
goto
no_open
;
parent
=
dget_parent
(
dentry
);
dir
=
parent
->
d_inode
;
if
(
!
is_atomic_open
(
dir
,
nd
))
goto
no_open
;
openflags
=
nd
->
intent
.
open
.
flags
;
if
(
openflags
&
O_CREAT
)
{
/* If this is a negative dentry, just drop it
*/
if
(
!
inode
)
/* We can't create new files in nfs_open_revalidate(), so we
* optimize away revalidation of negative dentries.
*/
if
(
inode
==
NULL
)
goto
out
;
/* If this is exclusive open, just revalidate */
if
(
openflags
&
O_EXCL
)
/* NFS only supports OPEN on regular files */
if
(
!
S_ISREG
(
inode
->
i_mode
))
goto
no_open
;
openflags
=
nd
->
intent
.
open
.
flags
;
/* We cannot do exclusive creation on a positive dentry */
if
((
openflags
&
(
O_CREAT
|
O_EXCL
))
==
(
O_CREAT
|
O_EXCL
))
goto
no_open
;
}
/* We can't create new files, or truncate existing ones here */
openflags
&=
~
(
O_CREAT
|
O_TRUNC
);
...
...
@@ -1299,19 +1299,6 @@ nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
dfprintk
(
VFS
,
"NFS: symlink(%s/%ld, %s, %s)
\n
"
,
dir
->
i_sb
->
s_id
,
dir
->
i_ino
,
dentry
->
d_name
.
name
,
symname
);
error
=
-
ENAMETOOLONG
;
switch
(
NFS_PROTO
(
dir
)
->
version
)
{
case
2
:
if
(
strlen
(
symname
)
>
NFS2_MAXPATHLEN
)
goto
out
;
break
;
case
3
:
if
(
strlen
(
symname
)
>
NFS3_MAXPATHLEN
)
goto
out
;
default:
break
;
}
#ifdef NFS_PARANOIA
if
(
dentry
->
d_inode
)
printk
(
"nfs_proc_symlink: %s/%s not negative!
\n
"
,
...
...
@@ -1341,8 +1328,6 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
d_drop
(
dentry
);
}
unlock_kernel
();
out:
return
error
;
}
...
...
@@ -1498,10 +1483,56 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
return
error
;
}
int
nfs_permission
(
struct
inode
*
inode
,
int
mask
,
struct
nameidata
*
nd
)
static
int
nfs_access_get_cached
(
struct
inode
*
inode
,
struct
rpc_cred
*
cred
,
struct
nfs_access_entry
*
res
)
{
struct
nfs_access_entry
*
cache
=
&
NFS_I
(
inode
)
->
cache_access
;
if
(
cache
->
cred
!=
cred
||
time_after
(
jiffies
,
cache
->
jiffies
+
NFS_ATTRTIMEO
(
inode
))
||
(
NFS_FLAGS
(
inode
)
&
NFS_INO_INVALID_ATTR
))
return
-
ENOENT
;
memcpy
(
res
,
cache
,
sizeof
(
*
res
));
return
0
;
}
static
void
nfs_access_add_cache
(
struct
inode
*
inode
,
struct
nfs_access_entry
*
set
)
{
struct
nfs_access_entry
*
cache
=
&
NFS_I
(
inode
)
->
cache_access
;
if
(
cache
->
cred
!=
set
->
cred
)
{
if
(
cache
->
cred
)
put_rpccred
(
cache
->
cred
);
cache
->
cred
=
get_rpccred
(
set
->
cred
);
}
cache
->
jiffies
=
set
->
jiffies
;
cache
->
mask
=
set
->
mask
;
}
static
int
nfs_do_access
(
struct
inode
*
inode
,
struct
rpc_cred
*
cred
,
int
mask
)
{
struct
nfs_access_entry
cache
;
int
status
;
status
=
nfs_access_get_cached
(
inode
,
cred
,
&
cache
);
if
(
status
==
0
)
goto
out
;
/* Be clever: ask server to check for all possible rights */
cache
.
mask
=
MAY_EXEC
|
MAY_WRITE
|
MAY_READ
;
cache
.
cred
=
cred
;
cache
.
jiffies
=
jiffies
;
status
=
NFS_PROTO
(
inode
)
->
access
(
inode
,
&
cache
);
if
(
status
!=
0
)
return
status
;
nfs_access_add_cache
(
inode
,
&
cache
);
out:
if
((
cache
.
mask
&
mask
)
==
mask
)
return
0
;
return
-
EACCES
;
}
int
nfs_permission
(
struct
inode
*
inode
,
int
mask
,
struct
nameidata
*
nd
)
{
struct
nfs_access_cache
*
cache
=
&
NFS_I
(
inode
)
->
cache_access
;
struct
rpc_cred
*
cred
;
int
mode
=
inode
->
i_mode
;
int
res
;
...
...
@@ -1542,24 +1573,7 @@ nfs_permission(struct inode *inode, int mask, struct nameidata *nd)
goto
out_notsup
;
cred
=
rpcauth_lookupcred
(
NFS_CLIENT
(
inode
)
->
cl_auth
,
0
);
if
(
cache
->
cred
==
cred
&&
time_before
(
jiffies
,
cache
->
jiffies
+
NFS_ATTRTIMEO
(
inode
))
&&
!
(
NFS_FLAGS
(
inode
)
&
NFS_INO_INVALID_ATTR
))
{
if
(
!
(
res
=
cache
->
err
))
{
/* Is the mask a subset of an accepted mask? */
if
((
cache
->
mask
&
mask
)
==
mask
)
goto
out
;
}
else
{
/* ...or is it a superset of a rejected mask? */
if
((
cache
->
mask
&
mask
)
==
cache
->
mask
)
goto
out
;
}
}
res
=
NFS_PROTO
(
inode
)
->
access
(
inode
,
cred
,
mask
);
if
(
!
res
||
res
==
-
EACCES
)
goto
add_cache
;
out:
res
=
nfs_do_access
(
inode
,
cred
,
mask
);
put_rpccred
(
cred
);
unlock_kernel
();
return
res
;
...
...
@@ -1568,15 +1582,6 @@ nfs_permission(struct inode *inode, int mask, struct nameidata *nd)
res
=
vfs_permission
(
inode
,
mask
);
unlock_kernel
();
return
res
;
add_cache:
cache
->
jiffies
=
jiffies
;
if
(
cache
->
cred
)
put_rpccred
(
cache
->
cred
);
cache
->
cred
=
cred
;
cache
->
mask
=
mask
;
cache
->
err
=
res
;
unlock_kernel
();
return
res
;
}
/*
...
...
fs/nfs/inode.c
View file @
fec00732
This diff is collapsed.
Click to expand it.
fs/nfs/mount_clnt.c
View file @
fec00732
...
...
@@ -108,7 +108,6 @@ xdr_decode_fhstatus(struct rpc_rqst *req, u32 *p, struct mnt_fhstatus *res)
{
struct
nfs_fh
*
fh
=
res
->
fh
;
memset
((
void
*
)
fh
,
0
,
sizeof
(
*
fh
));
if
((
res
->
status
=
ntohl
(
*
p
++
))
==
0
)
{
fh
->
size
=
NFS2_FHSIZE
;
memcpy
(
fh
->
data
,
p
,
NFS2_FHSIZE
);
...
...
@@ -121,7 +120,6 @@ xdr_decode_fhstatus3(struct rpc_rqst *req, u32 *p, struct mnt_fhstatus *res)
{
struct
nfs_fh
*
fh
=
res
->
fh
;
memset
((
void
*
)
fh
,
0
,
sizeof
(
*
fh
));
if
((
res
->
status
=
ntohl
(
*
p
++
))
==
0
)
{
int
size
=
ntohl
(
*
p
++
);
if
(
size
<=
NFS3_FHSIZE
)
{
...
...
fs/nfs/nfs2xdr.c
View file @
fec00732
...
...
@@ -77,8 +77,6 @@ xdr_encode_fhandle(u32 *p, struct nfs_fh *fhandle)
static
inline
u32
*
xdr_decode_fhandle
(
u32
*
p
,
struct
nfs_fh
*
fhandle
)
{
/* Zero handle first to allow comparisons */
memset
(
fhandle
,
0
,
sizeof
(
*
fhandle
));
/* NFSv2 handles have a fixed length */
fhandle
->
size
=
NFS2_FHSIZE
;
memcpy
(
fhandle
->
data
,
p
,
NFS2_FHSIZE
);
...
...
@@ -94,6 +92,23 @@ xdr_encode_time(u32 *p, struct timespec *timep)
return
p
;
}
static
inline
u32
*
xdr_encode_current_server_time
(
u32
*
p
,
struct
timespec
*
timep
)
{
/*
* Passing the invalid value useconds=1000000 is a
* Sun convention for "set to current server time".
* It's needed to make permissions checks for the
* "touch" program across v2 mounts to Solaris and
* Irix boxes work correctly. See description of
* sattr in section 6.1 of "NFS Illustrated" by
* Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5
*/
*
p
++
=
htonl
(
timep
->
tv_sec
);
*
p
++
=
htonl
(
1000000
);
return
p
;
}
static
inline
u32
*
xdr_decode_time
(
u32
*
p
,
struct
timespec
*
timep
)
{
...
...
@@ -142,15 +157,19 @@ xdr_encode_sattr(u32 *p, struct iattr *attr)
SATTR
(
p
,
attr
,
ATTR_GID
,
ia_gid
);
SATTR
(
p
,
attr
,
ATTR_SIZE
,
ia_size
);
if
(
attr
->
ia_valid
&
(
ATTR_ATIME
|
ATTR_ATIME_SET
)
)
{
if
(
attr
->
ia_valid
&
ATTR_ATIME_SET
)
{
p
=
xdr_encode_time
(
p
,
&
attr
->
ia_atime
);
}
else
if
(
attr
->
ia_valid
&
ATTR_ATIME
)
{
p
=
xdr_encode_current_server_time
(
p
,
&
attr
->
ia_atime
);
}
else
{
*
p
++
=
~
(
u32
)
0
;
*
p
++
=
~
(
u32
)
0
;
}
if
(
attr
->
ia_valid
&
(
ATTR_MTIME
|
ATTR_MTIME_SET
)
)
{
if
(
attr
->
ia_valid
&
ATTR_MTIME_SET
)
{
p
=
xdr_encode_time
(
p
,
&
attr
->
ia_mtime
);
}
else
if
(
attr
->
ia_valid
&
ATTR_MTIME
)
{
p
=
xdr_encode_current_server_time
(
p
,
&
attr
->
ia_mtime
);
}
else
{
*
p
++
=
~
(
u32
)
0
;
*
p
++
=
~
(
u32
)
0
;
...
...
fs/nfs/nfs3proc.c
View file @
fec00732
...
...
@@ -164,8 +164,7 @@ nfs3_proc_lookup(struct inode *dir, struct qstr *name,
return
status
;
}
static
int
nfs3_proc_access
(
struct
inode
*
inode
,
struct
rpc_cred
*
cred
,
int
mode
)
static
int
nfs3_proc_access
(
struct
inode
*
inode
,
struct
nfs_access_entry
*
entry
)
{
struct
nfs_fattr
fattr
;
struct
nfs3_accessargs
arg
=
{
...
...
@@ -178,8 +177,9 @@ nfs3_proc_access(struct inode *inode, struct rpc_cred *cred, int mode)
.
rpc_proc
=
&
nfs3_procedures
[
NFS3PROC_ACCESS
],
.
rpc_argp
=
&
arg
,
.
rpc_resp
=
&
res
,
.
rpc_cred
=
cred
.
rpc_cred
=
entry
->
cred
};
int
mode
=
entry
->
mask
;
int
status
;
dprintk
(
"NFS call access
\n
"
);
...
...
@@ -200,10 +200,16 @@ nfs3_proc_access(struct inode *inode, struct rpc_cred *cred, int mode)
}
status
=
rpc_call_sync
(
NFS_CLIENT
(
inode
),
&
msg
,
0
);
nfs_refresh_inode
(
inode
,
&
fattr
);
dprintk
(
"NFS reply access
\n
"
);
if
(
status
==
0
&&
(
arg
.
access
&
res
.
access
)
!=
arg
.
access
)
status
=
-
EACCES
;
if
(
status
==
0
)
{
entry
->
mask
=
0
;
if
(
res
.
access
&
NFS3_ACCESS_READ
)
entry
->
mask
|=
MAY_READ
;
if
(
res
.
access
&
(
NFS3_ACCESS_MODIFY
|
NFS3_ACCESS_EXTEND
|
NFS3_ACCESS_DELETE
))
entry
->
mask
|=
MAY_WRITE
;
if
(
res
.
access
&
(
NFS3_ACCESS_LOOKUP
|
NFS3_ACCESS_EXECUTE
))
entry
->
mask
|=
MAY_EXEC
;
}
dprintk
(
"NFS reply access, status = %d
\n
"
,
status
);
return
status
;
}
...
...
@@ -534,6 +540,8 @@ nfs3_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path,
};
int
status
;
if
(
path
->
len
>
NFS3_MAXPATHLEN
)
return
-
ENAMETOOLONG
;
dprintk
(
"NFS call symlink %s -> %s
\n
"
,
name
->
name
,
path
->
name
);
dir_attr
.
valid
=
0
;
fattr
->
valid
=
0
;
...
...
fs/nfs/nfs3xdr.c
View file @
fec00732
...
...
@@ -109,10 +109,6 @@ xdr_encode_fhandle(u32 *p, struct nfs_fh *fh)
static
inline
u32
*
xdr_decode_fhandle
(
u32
*
p
,
struct
nfs_fh
*
fh
)
{
/*
* Zero all nonused bytes
*/
memset
((
u8
*
)
fh
,
0
,
sizeof
(
*
fh
));
if
((
fh
->
size
=
ntohl
(
*
p
++
))
<=
NFS3_FHSIZE
)
{
memcpy
(
fh
->
data
,
p
,
fh
->
size
);
return
p
+
XDR_QUADLEN
(
fh
->
size
);
...
...
fs/nfs/nfs4proc.c
View file @
fec00732
...
...
@@ -734,9 +734,8 @@ static int nfs4_proc_lookup(struct inode *dir, struct qstr *name,
return
nfs4_map_errors
(
status
);
}
static
int
nfs4_proc_access
(
struct
inode
*
inode
,
struct
rpc_cred
*
cred
,
int
mode
)
static
int
nfs4_proc_access
(
struct
inode
*
inode
,
struct
nfs_access_entry
*
entry
)
{
int
status
;
struct
nfs4_accessargs
args
=
{
.
fh
=
NFS_FH
(
inode
),
};
...
...
@@ -745,8 +744,10 @@ static int nfs4_proc_access(struct inode *inode, struct rpc_cred *cred, int mode
.
rpc_proc
=
&
nfs4_procedures
[
NFSPROC4_CLNT_ACCESS
],
.
rpc_argp
=
&
args
,
.
rpc_resp
=
&
res
,
.
rpc_cred
=
cred
,
.
rpc_cred
=
entry
->
cred
,
};
int
mode
=
entry
->
mask
;
int
status
;
/*
* Determine which access bits we want to ask for...
...
...
@@ -758,8 +759,7 @@ static int nfs4_proc_access(struct inode *inode, struct rpc_cred *cred, int mode
args
.
access
|=
NFS4_ACCESS_MODIFY
|
NFS4_ACCESS_EXTEND
|
NFS4_ACCESS_DELETE
;
if
(
mode
&
MAY_EXEC
)
args
.
access
|=
NFS4_ACCESS_LOOKUP
;
}
else
{
}
else
{
if
(
mode
&
MAY_WRITE
)
args
.
access
|=
NFS4_ACCESS_MODIFY
|
NFS4_ACCESS_EXTEND
;
if
(
mode
&
MAY_EXEC
)
...
...
@@ -767,11 +767,13 @@ static int nfs4_proc_access(struct inode *inode, struct rpc_cred *cred, int mode
}
status
=
rpc_call_sync
(
NFS_CLIENT
(
inode
),
&
msg
,
0
);
if
(
!
status
)
{
if
(
args
.
access
!=
res
.
supported
)
{
printk
(
KERN_NOTICE
"NFS: server didn't support all access bits!
\n
"
);
status
=
-
ENOTSUPP
;
}
else
if
((
args
.
access
&
res
.
access
)
!=
args
.
access
)
status
=
-
EACCES
;
entry
->
mask
=
0
;
if
(
res
.
access
&
NFS4_ACCESS_READ
)
entry
->
mask
|=
MAY_READ
;
if
(
res
.
access
&
(
NFS4_ACCESS_MODIFY
|
NFS4_ACCESS_EXTEND
|
NFS4_ACCESS_DELETE
))
entry
->
mask
|=
MAY_WRITE
;
if
(
res
.
access
&
(
NFS4_ACCESS_LOOKUP
|
NFS4_ACCESS_EXECUTE
))
entry
->
mask
|=
MAY_EXEC
;
}
return
nfs4_map_errors
(
status
);
}
...
...
@@ -1090,12 +1092,14 @@ static int nfs4_proc_symlink(struct inode *dir, struct qstr *name,
.
fattr
=
fattr
,
};
struct
rpc_message
msg
=
{
.
rpc_proc
=
&
nfs4_procedures
[
NFSPROC4_CLNT_
CREATE
],
.
rpc_proc
=
&
nfs4_procedures
[
NFSPROC4_CLNT_
SYMLINK
],
.
rpc_argp
=
&
arg
,
.
rpc_resp
=
&
res
,
};
int
status
;
if
(
path
->
len
>
NFS4_MAXPATHLEN
)
return
-
ENAMETOOLONG
;
arg
.
u
.
symlink
=
path
;
fattr
->
valid
=
0
;
...
...
fs/nfs/nfs4xdr.c
View file @
fec00732
...
...
@@ -84,6 +84,7 @@ static int nfs_stat_to_errno(int);
((3+NFS4_FHSIZE) >> 2))
#define encode_getattr_maxsz (op_encode_hdr_maxsz + 3)
#define nfs4_name_maxsz (1 + ((3 + NFS4_MAXNAMLEN) >> 2))
#define nfs4_path_maxsz (1 + ((3 + NFS4_MAXPATHLEN) >> 2))
#define nfs4_fattr_bitmap_maxsz (36 + 2 * nfs4_name_maxsz)
#define decode_getattr_maxsz (op_decode_hdr_maxsz + 3 + \
nfs4_fattr_bitmap_maxsz)
...
...
@@ -118,8 +119,13 @@ static int nfs_stat_to_errno(int);
#define encode_link_maxsz (op_encode_hdr_maxsz + \
nfs4_name_maxsz)
#define decode_link_maxsz (op_decode_hdr_maxsz + 5)
#define encode_symlink_maxsz (op_encode_hdr_maxsz + \
1 + nfs4_name_maxsz + \
nfs4_path_maxsz + \
nfs4_fattr_bitmap_maxsz)
#define decode_symlink_maxsz (op_decode_hdr_maxsz + 8)
#define encode_create_maxsz (op_encode_hdr_maxsz + \
2 +
2 *
nfs4_name_maxsz + \
2 + nfs4_name_maxsz + \
nfs4_fattr_bitmap_maxsz)
#define decode_create_maxsz (op_decode_hdr_maxsz + 8)
#define NFS4_enc_compound_sz (1024)
/* XXX: large enough? */
...
...
@@ -313,6 +319,16 @@ static int nfs_stat_to_errno(int);
decode_savefh_maxsz + \
decode_putfh_maxsz + \
decode_link_maxsz)
#define NFS4_enc_symlink_sz (compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
encode_symlink_maxsz + \
encode_getattr_maxsz + \
encode_getfh_maxsz)
#define NFS4_dec_symlink_sz (compound_decode_hdr_maxsz + \
decode_putfh_maxsz + \
decode_symlink_maxsz + \
decode_getattr_maxsz + \
decode_getfh_maxsz)
#define NFS4_enc_create_sz (compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
encode_create_maxsz + \
...
...
@@ -927,7 +943,7 @@ static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
WRITE32
(
OP_READDIR
);
WRITE64
(
readdir
->
cookie
);
WRITEMEM
(
readdir
->
verifier
.
data
,
sizeof
(
readdir
->
verifier
.
data
));
WRITE32
(
readdir
->
count
>>
5
);
/* meaningless "dircount" field
*/
WRITE32
(
readdir
->
count
>>
1
);
/* We're not doing readdirplus
*/
WRITE32
(
readdir
->
count
);
WRITE32
(
2
);
WRITE32
(
FATTR4_WORD0_FILEID
);
...
...
@@ -1243,6 +1259,14 @@ static int nfs4_xdr_enc_create(struct rpc_rqst *req, uint32_t *p, const struct n
return
status
;
}
/*
* Encode SYMLINK request
*/
static
int
nfs4_xdr_enc_symlink
(
struct
rpc_rqst
*
req
,
uint32_t
*
p
,
const
struct
nfs4_create_arg
*
args
)
{
return
nfs4_xdr_enc_create
(
req
,
p
,
args
);
}
/*
* Encode GETATTR request
*/
...
...
@@ -2817,8 +2841,8 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n
struct
kvec
*
iov
=
rcvbuf
->
head
;
unsigned
int
nr
,
pglen
=
rcvbuf
->
page_len
;
uint32_t
*
end
,
*
entry
,
*
p
,
*
kaddr
;
uint32_t
len
,
attrlen
,
word
;
int
i
,
hdrlen
,
recvd
,
status
;
uint32_t
len
,
attrlen
;
int
hdrlen
,
recvd
,
status
;
status
=
decode_op_hdr
(
xdr
,
OP_READDIR
);
if
(
status
)
...
...
@@ -2845,36 +2869,18 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n
printk
(
KERN_WARNING
"NFS: giant filename in readdir (len 0x%x)
\n
"
,
len
);
goto
err_unmap
;
}
p
+=
XDR_QUADLEN
(
len
);
if
(
p
+
1
>
end
)
goto
short_pkt
;
len
=
ntohl
(
*
p
++
);
/* bitmap length */
if
(
len
>
10
)
{
printk
(
KERN_WARNING
"NFS: giant bitmap in readdir (len 0x%x)
\n
"
,
len
);
goto
err_unmap
;
}
if
(
p
+
len
+
1
>
end
)
goto
short_pkt
;
attrlen
=
0
;
for
(
i
=
0
;
i
<
len
;
i
++
)
{
word
=
ntohl
(
*
p
++
);
if
(
!
word
)
continue
;
else
if
(
i
==
0
&&
word
==
FATTR4_WORD0_FILEID
)
{
attrlen
=
8
;
continue
;
}
printk
(
KERN_WARNING
"NFS: unexpected bitmap word in readdir (0x%x)
\n
"
,
word
);
goto
err_unmap
;
}
if
(
ntohl
(
*
p
++
)
!=
attrlen
)
{
printk
(
KERN_WARNING
"NFS: unexpected attrlen in readdir
\n
"
);
goto
err_unmap
;
}
p
+=
XDR_QUADLEN
(
attrlen
);
p
+=
len
;
if
(
p
+
1
>
end
)
goto
short_pkt
;
attrlen
=
XDR_QUADLEN
(
ntohl
(
*
p
++
));
p
+=
attrlen
;
/* attributes */
if
(
p
+
2
>
end
)
goto
short_pkt
;
entry
=
p
;
}
if
(
!
nr
&&
(
entry
[
0
]
!=
0
||
entry
[
1
]
==
0
))
goto
short_pkt
;
...
...
@@ -3221,6 +3227,14 @@ static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_
return
status
;
}
/*
* Decode SYMLINK response
*/
static
int
nfs4_xdr_dec_symlink
(
struct
rpc_rqst
*
rqstp
,
uint32_t
*
p
,
struct
nfs4_create_res
*
res
)
{
return
nfs4_xdr_dec_create
(
rqstp
,
p
,
res
);
}
/*
* Decode GETATTR response
*/
...
...
@@ -3667,6 +3681,7 @@ static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, s
uint32_t
*
nfs4_decode_dirent
(
uint32_t
*
p
,
struct
nfs_entry
*
entry
,
int
plus
)
{
uint32_t
bitmap
[
1
]
=
{
0
};
uint32_t
len
;
if
(
!*
p
++
)
{
...
...
@@ -3690,10 +3705,16 @@ uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus)
entry
->
ino
=
1
;
len
=
ntohl
(
*
p
++
);
/* bitmap length */
if
(
len
>
0
)
{
bitmap
[
0
]
=
ntohl
(
*
p
);
p
+=
len
;
len
=
ntohl
(
*
p
++
);
/* attribute buffer length */
if
(
len
)
p
=
xdr_decode_hyper
(
p
,
&
entry
->
ino
);
}
len
=
XDR_QUADLEN
(
ntohl
(
*
p
++
));
/* attribute buffer length */
if
(
len
>
0
)
{
if
(
bitmap
[
0
]
==
FATTR4_WORD0_FILEID
)
xdr_decode_hyper
(
p
,
&
entry
->
ino
);
p
+=
len
;
}
entry
->
eof
=
!
p
[
0
]
&&
p
[
1
];
return
p
;
...
...
@@ -3756,7 +3777,7 @@ nfs_stat_to_errno(int stat)
if
(
nfs_errtbl
[
i
].
stat
==
stat
)
return
nfs_errtbl
[
i
].
errno
;
}
if
(
stat
<
0
)
{
if
(
stat
<
=
10000
||
stat
>
1010
0
)
{
/* The server is looney tunes. */
return
ESERVERFAULT
;
}
...
...
@@ -3804,6 +3825,7 @@ struct rpc_procinfo nfs4_procedures[] = {
PROC
(
REMOVE
,
enc_remove
,
dec_remove
),
PROC
(
RENAME
,
enc_rename
,
dec_rename
),
PROC
(
LINK
,
enc_link
,
dec_link
),
PROC
(
SYMLINK
,
enc_symlink
,
dec_symlink
),
PROC
(
CREATE
,
enc_create
,
dec_create
),
PROC
(
PATHCONF
,
enc_pathconf
,
dec_pathconf
),
PROC
(
STATFS
,
enc_statfs
,
dec_statfs
),
...
...
fs/nfs/nfsroot.c
View file @
fec00732
...
...
@@ -495,10 +495,8 @@ static int __init root_nfs_get_handle(void)
if
(
status
<
0
)
printk
(
KERN_ERR
"Root-NFS: Server returned error %d "
"while mounting %s
\n
"
,
status
,
nfs_path
);
else
{
nfs_data
.
root
.
size
=
fh
.
size
;
memcpy
(
nfs_data
.
root
.
data
,
fh
.
data
,
fh
.
size
);
}
else
nfs_copy_fh
(
nfs_data
.
root
,
fh
);
return
status
;
}
...
...
fs/nfs/pagelist.c
View file @
fec00732
...
...
@@ -21,11 +21,6 @@
#define NFS_PARANOIA 1
/*
* Spinlock
*/
spinlock_t
nfs_wreq_lock
=
SPIN_LOCK_UNLOCKED
;
static
kmem_cache_t
*
nfs_page_cachep
;
static
inline
struct
nfs_page
*
...
...
@@ -95,7 +90,7 @@ nfs_create_request(struct file *file, struct inode *inode,
req
->
wb_pgbase
=
offset
;
req
->
wb_bytes
=
count
;
req
->
wb_inode
=
inode
;
req
->
wb_count
=
1
;
atomic_set
(
&
req
->
wb_count
,
1
)
;
server
->
rpc_ops
->
request_init
(
req
,
file
);
return
req
;
...
...
@@ -137,12 +132,8 @@ void nfs_clear_request(struct nfs_page *req)
void
nfs_release_request
(
struct
nfs_page
*
req
)
{
spin_lock
(
&
nfs_wreq_lock
);
if
(
--
req
->
wb_count
)
{
spin_unlock
(
&
nfs_wreq_lock
);
if
(
!
atomic_dec_and_test
(
&
req
->
wb_count
))
return
;
}
spin_unlock
(
&
nfs_wreq_lock
);
#ifdef NFS_PARANOIA
BUG_ON
(
!
list_empty
(
&
req
->
wb_list
));
...
...
@@ -254,7 +245,7 @@ nfs_coalesce_requests(struct list_head *head, struct list_head *dst,
* If the number of requests is set to 0, the entire address_space
* starting at index idx_start, is scanned.
* The requests are *not* checked to ensure that they form a contiguous set.
* You must be holding the
nfs_w
req_lock when calling this function
* You must be holding the
inode's
req_lock when calling this function
*/
int
nfs_scan_list
(
struct
list_head
*
head
,
struct
list_head
*
dst
,
...
...
fs/nfs/proc.c
View file @
fec00732
...
...
@@ -400,6 +400,8 @@ nfs_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path,
};
int
status
;
if
(
path
->
len
>
NFS2_MAXPATHLEN
)
return
-
ENAMETOOLONG
;
dprintk
(
"NFS call symlink %s -> %s
\n
"
,
name
->
name
,
path
->
name
);
fattr
->
valid
=
0
;
status
=
rpc_call
(
NFS_CLIENT
(
dir
),
NFSPROC_SYMLINK
,
&
arg
,
NULL
,
0
);
...
...
fs/nfs/write.c
View file @
fec00732
...
...
@@ -389,7 +389,7 @@ nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
nfs_begin_data_update
(
inode
);
}
nfsi
->
npages
++
;
req
->
wb_count
++
;
atomic_inc
(
&
req
->
wb_count
)
;
return
0
;
}
...
...
@@ -399,21 +399,20 @@ nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
static
void
nfs_inode_remove_request
(
struct
nfs_page
*
req
)
{
struct
nfs_inode
*
nfsi
;
struct
inode
*
inode
;
struct
inode
*
inode
=
req
->
wb_inode
;
struct
nfs_inode
*
nfsi
=
NFS_I
(
inode
)
;
BUG_ON
(
!
NFS_WBACK_BUSY
(
req
));
spin_lock
(
&
nfs_wreq_lock
);
inode
=
req
->
wb_inode
;
nfsi
=
NFS_I
(
inode
);
spin_lock
(
&
nfsi
->
req_lock
);
radix_tree_delete
(
&
nfsi
->
nfs_page_tree
,
req
->
wb_index
);
nfsi
->
npages
--
;
if
(
!
nfsi
->
npages
)
{
spin_unlock
(
&
nfs
_w
req_lock
);
spin_unlock
(
&
nfs
i
->
req_lock
);
nfs_end_data_update_defer
(
inode
);
iput
(
inode
);
}
else
spin_unlock
(
&
nfs
_w
req_lock
);
spin_unlock
(
&
nfs
i
->
req_lock
);
nfs_clear_request
(
req
);
nfs_release_request
(
req
);
}
...
...
@@ -429,7 +428,7 @@ _nfs_find_request(struct inode *inode, unsigned long index)
req
=
(
struct
nfs_page
*
)
radix_tree_lookup
(
&
nfsi
->
nfs_page_tree
,
index
);
if
(
req
)
req
->
wb_count
++
;
atomic_inc
(
&
req
->
wb_count
)
;
return
req
;
}
...
...
@@ -437,10 +436,11 @@ static struct nfs_page *
nfs_find_request
(
struct
inode
*
inode
,
unsigned
long
index
)
{
struct
nfs_page
*
req
;
struct
nfs_inode
*
nfsi
=
NFS_I
(
inode
);
spin_lock
(
&
nfs
_w
req_lock
);
spin_lock
(
&
nfs
i
->
req_lock
);
req
=
_nfs_find_request
(
inode
,
index
);
spin_unlock
(
&
nfs
_w
req_lock
);
spin_unlock
(
&
nfs
i
->
req_lock
);
return
req
;
}
...
...
@@ -453,10 +453,10 @@ nfs_mark_request_dirty(struct nfs_page *req)
struct
inode
*
inode
=
req
->
wb_inode
;
struct
nfs_inode
*
nfsi
=
NFS_I
(
inode
);
spin_lock
(
&
nfs
_w
req_lock
);
spin_lock
(
&
nfs
i
->
req_lock
);
nfs_list_add_request
(
req
,
&
nfsi
->
dirty
);
nfsi
->
ndirty
++
;
spin_unlock
(
&
nfs
_w
req_lock
);
spin_unlock
(
&
nfs
i
->
req_lock
);
inc_page_state
(
nr_dirty
);
mark_inode_dirty
(
inode
);
}
...
...
@@ -481,10 +481,10 @@ nfs_mark_request_commit(struct nfs_page *req)
struct
inode
*
inode
=
req
->
wb_inode
;
struct
nfs_inode
*
nfsi
=
NFS_I
(
inode
);
spin_lock
(
&
nfs
_w
req_lock
);
spin_lock
(
&
nfs
i
->
req_lock
);
nfs_list_add_request
(
req
,
&
nfsi
->
commit
);
nfsi
->
ncommit
++
;
spin_unlock
(
&
nfs
_w
req_lock
);
spin_unlock
(
&
nfs
i
->
req_lock
);
inc_page_state
(
nr_unstable
);
mark_inode_dirty
(
inode
);
}
...
...
@@ -509,7 +509,7 @@ nfs_wait_on_requests(struct inode *inode, unsigned long idx_start, unsigned int
else
idx_end
=
idx_start
+
npages
-
1
;
spin_lock
(
&
nfs
_w
req_lock
);
spin_lock
(
&
nfs
i
->
req_lock
);
next
=
idx_start
;
while
(
radix_tree_gang_lookup
(
&
nfsi
->
nfs_page_tree
,
(
void
**
)
&
req
,
next
,
1
))
{
if
(
req
->
wb_index
>
idx_end
)
...
...
@@ -519,16 +519,16 @@ nfs_wait_on_requests(struct inode *inode, unsigned long idx_start, unsigned int
if
(
!
NFS_WBACK_BUSY
(
req
))
continue
;
req
->
wb_count
++
;
spin_unlock
(
&
nfs
_w
req_lock
);
atomic_inc
(
&
req
->
wb_count
)
;
spin_unlock
(
&
nfs
i
->
req_lock
);
error
=
nfs_wait_on_request
(
req
);
nfs_release_request
(
req
);
if
(
error
<
0
)
return
error
;
spin_lock
(
&
nfs
_w
req_lock
);
spin_lock
(
&
nfs
i
->
req_lock
);
res
++
;
}
spin_unlock
(
&
nfs
_w
req_lock
);
spin_unlock
(
&
nfs
i
->
req_lock
);
return
res
;
}
...
...
@@ -624,6 +624,7 @@ nfs_update_request(struct file* file, struct inode *inode, struct page *page,
unsigned
int
offset
,
unsigned
int
bytes
)
{
struct
nfs_server
*
server
=
NFS_SERVER
(
inode
);
struct
nfs_inode
*
nfsi
=
NFS_I
(
inode
);
struct
nfs_page
*
req
,
*
new
=
NULL
;
unsigned
long
rqend
,
end
;
...
...
@@ -635,19 +636,19 @@ nfs_update_request(struct file* file, struct inode *inode, struct page *page,
/* Loop over all inode entries and see if we find
* A request for the page we wish to update
*/
spin_lock
(
&
nfs
_w
req_lock
);
spin_lock
(
&
nfs
i
->
req_lock
);
req
=
_nfs_find_request
(
inode
,
page
->
index
);
if
(
req
)
{
if
(
!
nfs_lock_request_dontget
(
req
))
{
int
error
;
spin_unlock
(
&
nfs
_w
req_lock
);
spin_unlock
(
&
nfs
i
->
req_lock
);
error
=
nfs_wait_on_request
(
req
);
nfs_release_request
(
req
);
if
(
error
<
0
)
return
ERR_PTR
(
error
);
continue
;
}
spin_unlock
(
&
nfs
_w
req_lock
);
spin_unlock
(
&
nfs
i
->
req_lock
);
if
(
new
)
nfs_release_request
(
new
);
break
;
...
...
@@ -658,15 +659,15 @@ nfs_update_request(struct file* file, struct inode *inode, struct page *page,
nfs_lock_request_dontget
(
new
);
error
=
nfs_inode_add_request
(
inode
,
new
);
if
(
error
)
{
spin_unlock
(
&
nfs
_w
req_lock
);
spin_unlock
(
&
nfs
i
->
req_lock
);
nfs_unlock_request
(
new
);
return
ERR_PTR
(
error
);
}
spin_unlock
(
&
nfs
_w
req_lock
);
spin_unlock
(
&
nfs
i
->
req_lock
);
nfs_mark_request_dirty
(
new
);
return
new
;
}
spin_unlock
(
&
nfs
_w
req_lock
);
spin_unlock
(
&
nfs
i
->
req_lock
);
new
=
nfs_create_request
(
file
,
inode
,
page
,
offset
,
bytes
);
if
(
IS_ERR
(
new
))
...
...
@@ -1347,13 +1348,14 @@ nfs_commit_done(struct rpc_task *task)
int
nfs_flush_inode
(
struct
inode
*
inode
,
unsigned
long
idx_start
,
unsigned
int
npages
,
int
how
)
{
struct
nfs_inode
*
nfsi
=
NFS_I
(
inode
);
LIST_HEAD
(
head
);
int
res
,
error
=
0
;
spin_lock
(
&
nfs
_w
req_lock
);
spin_lock
(
&
nfs
i
->
req_lock
);
res
=
nfs_scan_dirty
(
inode
,
&
head
,
idx_start
,
npages
);
spin_unlock
(
&
nfs
_w
req_lock
);
spin_unlock
(
&
nfs
i
->
req_lock
);
if
(
res
)
error
=
nfs_flush_list
(
&
head
,
NFS_SERVER
(
inode
)
->
wpages
,
how
);
if
(
error
<
0
)
...
...
@@ -1365,18 +1367,19 @@ int nfs_flush_inode(struct inode *inode, unsigned long idx_start,
int
nfs_commit_inode
(
struct
inode
*
inode
,
unsigned
long
idx_start
,
unsigned
int
npages
,
int
how
)
{
struct
nfs_inode
*
nfsi
=
NFS_I
(
inode
);
LIST_HEAD
(
head
);
int
res
,
error
=
0
;
spin_lock
(
&
nfs
_w
req_lock
);
spin_lock
(
&
nfs
i
->
req_lock
);
res
=
nfs_scan_commit
(
inode
,
&
head
,
idx_start
,
npages
);
if
(
res
)
{
res
+=
nfs_scan_commit
(
inode
,
&
head
,
0
,
0
);
spin_unlock
(
&
nfs
_w
req_lock
);
spin_unlock
(
&
nfs
i
->
req_lock
);
error
=
nfs_commit_list
(
&
head
,
how
);
}
else
spin_unlock
(
&
nfs
_w
req_lock
);
spin_unlock
(
&
nfs
i
->
req_lock
);
if
(
error
<
0
)
return
error
;
return
res
;
...
...
include/linux/nfs.h
View file @
fec00732
...
...
@@ -8,6 +8,7 @@
#define _LINUX_NFS_H
#include <linux/sunrpc/msg_prot.h>
#include <linux/string.h>
#define NFS_PROGRAM 100003
#define NFS_PORT 2049
...
...
@@ -138,6 +139,22 @@ struct nfs_fh {
unsigned
char
data
[
NFS_MAXFHSIZE
];
};
/*
* Returns a zero iff the size and data fields match.
* Checks only "size" bytes in the data field.
*/
static
inline
int
nfs_compare_fh
(
const
struct
nfs_fh
*
a
,
const
struct
nfs_fh
*
b
)
{
return
a
->
size
!=
b
->
size
||
memcmp
(
a
->
data
,
b
->
data
,
a
->
size
)
!=
0
;
}
static
inline
void
nfs_copy_fh
(
struct
nfs_fh
*
target
,
const
struct
nfs_fh
*
source
)
{
target
->
size
=
source
->
size
;
memcpy
(
target
->
data
,
source
->
data
,
source
->
size
);
}
/*
* This is really a general kernel constant, but since nothing like
* this is defined in the kernel headers, I have to do it here.
...
...
include/linux/nfs4.h
View file @
fec00732
...
...
@@ -18,6 +18,7 @@
#define NFS4_VERIFIER_SIZE 8
#define NFS4_FHSIZE 128
#define NFS4_MAXPATHLEN PATH_MAX
#define NFS4_MAXNAMLEN NAME_MAX
#define NFS4_ACCESS_READ 0x0001
...
...
@@ -372,6 +373,7 @@ enum {
NFSPROC4_CLNT_REMOVE
,
NFSPROC4_CLNT_RENAME
,
NFSPROC4_CLNT_LINK
,
NFSPROC4_CLNT_SYMLINK
,
NFSPROC4_CLNT_CREATE
,
NFSPROC4_CLNT_PATHCONF
,
NFSPROC4_CLNT_STATFS
,
...
...
include/linux/nfs_fs.h
View file @
fec00732
...
...
@@ -75,13 +75,12 @@
#ifdef __KERNEL__
/*
* NFSv3
Access mode cache
* NFSv3
/v4 Access mode cache entry
*/
struct
nfs_access_
cache
{
struct
nfs_access_
entry
{
unsigned
long
jiffies
;
struct
rpc_cred
*
cred
;
int
mask
;
int
err
;
};
/*
...
...
@@ -137,7 +136,7 @@ struct nfs_inode {
*/
atomic_t
data_updates
;
struct
nfs_access_
cache
cache_access
;
struct
nfs_access_
entry
cache_access
;
/*
* This is the cookie verifier used for NFSv3 readdir
...
...
@@ -148,6 +147,7 @@ struct nfs_inode {
/*
* This is the list of dirty unwritten pages.
*/
spinlock_t
req_lock
;
struct
list_head
dirty
;
struct
list_head
commit
;
struct
radix_tree_root
nfs_page_tree
;
...
...
include/linux/nfs_fs_sb.h
View file @
fec00732
...
...
@@ -18,6 +18,7 @@ struct nfs_server {
unsigned
int
rpages
;
/* read size (in pages) */
unsigned
int
wsize
;
/* write size */
unsigned
int
wpages
;
/* write size (in pages) */
unsigned
int
wtmult
;
/* server disk block size */
unsigned
int
dtsize
;
/* readdir size */
unsigned
int
bsize
;
/* server block size */
unsigned
int
acregmin
;
/* attr cache timeouts */
...
...
include/linux/nfs_page.h
View file @
fec00732
...
...
@@ -40,8 +40,8 @@ struct nfs_page {
unsigned
long
wb_index
;
/* Offset >> PAGE_CACHE_SHIFT */
unsigned
int
wb_offset
,
/* Offset & ~PAGE_CACHE_MASK */
wb_pgbase
,
/* Start of page data */
wb_bytes
,
/* Length of request */
wb_count
;
/* reference count */
wb_bytes
;
/* Length of request */
atomic_t
wb_count
;
/* reference count */
unsigned
long
wb_flags
;
struct
nfs_writeverf
wb_verf
;
/* Commit cookie */
};
...
...
@@ -65,8 +65,6 @@ extern int nfs_coalesce_requests(struct list_head *, struct list_head *,
unsigned
int
);
extern
int
nfs_wait_on_request
(
struct
nfs_page
*
);
extern
spinlock_t
nfs_wreq_lock
;
/*
* Lock the page of an asynchronous request without incrementing the wb_count
*/
...
...
@@ -86,7 +84,7 @@ nfs_lock_request(struct nfs_page *req)
{
if
(
test_and_set_bit
(
PG_BUSY
,
&
req
->
wb_flags
))
return
0
;
req
->
wb_count
++
;
atomic_inc
(
&
req
->
wb_count
)
;
return
1
;
}
...
...
include/linux/nfs_xdr.h
View file @
fec00732
...
...
@@ -657,6 +657,8 @@ struct nfs_write_data {
void
(
*
complete
)
(
struct
nfs_write_data
*
,
int
);
};
struct
nfs_access_entry
;
/*
* RPC procedure vector for NFSv2/NFSv3 demuxing
*/
...
...
@@ -672,7 +674,7 @@ struct nfs_rpc_ops {
struct
iattr
*
);
int
(
*
lookup
)
(
struct
inode
*
,
struct
qstr
*
,
struct
nfs_fh
*
,
struct
nfs_fattr
*
);
int
(
*
access
)
(
struct
inode
*
,
struct
rpc_cred
*
,
int
);
int
(
*
access
)
(
struct
inode
*
,
struct
nfs_access_entry
*
);
int
(
*
readlink
)(
struct
inode
*
,
struct
page
*
);
int
(
*
read
)
(
struct
nfs_read_data
*
,
struct
file
*
);
int
(
*
write
)
(
struct
nfs_write_data
*
,
struct
file
*
);
...
...
include/linux/sunrpc/gss_asn1.h
View file @
fec00732
...
...
@@ -69,7 +69,6 @@ u32 g_verify_token_header(
struct
xdr_netobj
*
mech
,
int
*
body_size
,
unsigned
char
**
buf_in
,
int
tok_type
,
int
toksize
);
u32
g_get_mech_oid
(
struct
xdr_netobj
*
mech
,
struct
xdr_netobj
*
in_buf
);
...
...
include/linux/sunrpc/gss_spkm3.h
0 → 100644
View file @
fec00732
/*
* linux/include/linux/sunrpc/gss_spkm3.h
*
* Copyright (c) 2000 The Regents of the University of Michigan.
* All rights reserved.
*
* Andy Adamson <andros@umich.edu>
*/
#include <linux/sunrpc/auth_gss.h>
#include <linux/sunrpc/gss_err.h>
#include <linux/sunrpc/gss_asn1.h>
struct
spkm3_ctx
{
struct
xdr_netobj
ctx_id
;
/* per message context id */
int
qop
;
/* negotiated qop */
struct
xdr_netobj
mech_used
;
unsigned
int
ret_flags
;
unsigned
int
req_flags
;
struct
xdr_netobj
share_key
;
int
conf_alg
;
struct
crypto_tfm
*
derived_conf_key
;
int
intg_alg
;
struct
crypto_tfm
*
derived_integ_key
;
int
keyestb_alg
;
/* alg used to get share_key */
int
owf_alg
;
/* one way function */
};
/* from openssl/objects.h */
/* XXX need SEAL_ALG_NONE */
#define NID_md5 4
#define NID_dhKeyAgreement 28
#define NID_des_cbc 31
#define NID_sha1 64
#define NID_cast5_cbc 108
/* SPKM InnerContext Token types */
#define SPKM_ERROR_TOK 3
#define SPKM_MIC_TOK 4
#define SPKM_WRAP_TOK 5
#define SPKM_DEL_TOK 6
u32
spkm3_make_token
(
struct
spkm3_ctx
*
ctx
,
int
qop_req
,
struct
xdr_buf
*
text
,
struct
xdr_netobj
*
token
,
int
toktype
);
u32
spkm3_read_token
(
struct
spkm3_ctx
*
ctx
,
struct
xdr_netobj
*
read_token
,
struct
xdr_buf
*
message_buffer
,
int
*
qop_state
,
int
toktype
);
#define CKSUMTYPE_RSA_MD5 0x0007
s32
make_checksum
(
s32
cksumtype
,
char
*
header
,
int
hdrlen
,
struct
xdr_buf
*
body
,
struct
xdr_netobj
*
cksum
);
void
asn1_bitstring_len
(
struct
xdr_netobj
*
in
,
int
*
enclen
,
int
*
zerobits
);
int
decode_asn1_bitstring
(
struct
xdr_netobj
*
out
,
char
*
in
,
int
enclen
,
int
explen
);
void
spkm3_mic_header
(
unsigned
char
**
hdrbuf
,
unsigned
int
*
hdrlen
,
unsigned
char
*
ctxhdr
,
int
elen
,
int
zbit
);
void
spkm3_make_mic_token
(
unsigned
char
**
tokp
,
int
toklen
,
struct
xdr_netobj
*
mic_hdr
,
struct
xdr_netobj
*
md5cksum
,
int
md5elen
,
int
md5zbit
);
u32
spkm3_verify_mic_token
(
unsigned
char
**
tokp
,
int
*
mic_hdrlen
,
unsigned
char
**
cksum
);
net/sunrpc/auth_gss/Makefile
View file @
fec00732
...
...
@@ -12,3 +12,7 @@ obj-$(CONFIG_RPCSEC_GSS_KRB5) += rpcsec_gss_krb5.o
rpcsec_gss_krb5-objs
:=
gss_krb5_mech.o gss_krb5_seal.o gss_krb5_unseal.o
\
gss_krb5_seqnum.o
obj-$(CONFIG_RPCSEC_GSS_SPKM3)
+=
rpcsec_gss_spkm3.o
rpcsec_gss_spkm3-objs
:=
gss_spkm3_mech.o gss_spkm3_seal.o gss_spkm3_unseal.o
\
gss_spkm3_token.o
net/sunrpc/auth_gss/auth_gss.c
View file @
fec00732
...
...
@@ -397,7 +397,7 @@ gss_upcall(struct rpc_clnt *clnt, struct rpc_task *task, struct rpc_cred *cred)
spin_unlock
(
&
gss_auth
->
lock
);
}
gss_release_msg
(
gss_msg
);
dprintk
(
"RPC: %4u gss_upcall for uid %u result %d"
,
task
->
tk_pid
,
dprintk
(
"RPC: %4u gss_upcall for uid %u result %d
\n
"
,
task
->
tk_pid
,
uid
,
res
);
return
res
;
out_sleep:
...
...
net/sunrpc/auth_gss/gss_generic_token.c
View file @
fec00732
...
...
@@ -179,7 +179,7 @@ EXPORT_SYMBOL(g_make_token_header);
*/
u32
g_verify_token_header
(
struct
xdr_netobj
*
mech
,
int
*
body_size
,
unsigned
char
**
buf_in
,
int
tok
_type
,
int
tok
size
)
unsigned
char
**
buf_in
,
int
toksize
)
{
unsigned
char
*
buf
=
*
buf_in
;
int
seqsize
;
...
...
net/sunrpc/auth_gss/gss_krb5_unseal.c
View file @
fec00732
...
...
@@ -96,7 +96,7 @@ krb5_read_token(struct krb5_ctx *ctx,
dprintk
(
"RPC: krb5_read_token
\n
"
);
if
(
g_verify_token_header
(
&
ctx
->
mech_used
,
&
bodysize
,
&
ptr
,
toktype
,
if
(
g_verify_token_header
(
&
ctx
->
mech_used
,
&
bodysize
,
&
ptr
,
read_token
->
len
))
goto
out
;
...
...
net/sunrpc/auth_gss/gss_spkm3_mech.c
0 → 100644
View file @
fec00732
/*
* linux/net/sunrpc/gss_spkm3_mech.c
*
* Copyright (c) 2003 The Regents of the University of Michigan.
* All rights reserved.
*
* Andy Adamson <andros@umich.edu>
* J. Bruce Fields <bfields@umich.edu>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/sunrpc/auth.h>
#include <linux/in.h>
#include <linux/sunrpc/svcauth_gss.h>
#include <linux/sunrpc/gss_spkm3.h>
#include <linux/sunrpc/xdr.h>
#include <linux/crypto.h>
#ifdef RPC_DEBUG
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
struct
xdr_netobj
gss_mech_spkm3_oid
=
{
7
,
"
\053\006\001\005\005\001\003
"
};
static
inline
int
get_bytes
(
char
**
ptr
,
const
char
*
end
,
void
*
res
,
int
len
)
{
char
*
p
,
*
q
;
p
=
*
ptr
;
q
=
p
+
len
;
if
(
q
>
end
||
q
<
p
)
return
-
1
;
memcpy
(
res
,
p
,
len
);
*
ptr
=
q
;
return
0
;
}
static
inline
int
get_netobj
(
char
**
ptr
,
const
char
*
end
,
struct
xdr_netobj
*
res
)
{
char
*
p
,
*
q
;
p
=
*
ptr
;
if
(
get_bytes
(
&
p
,
end
,
&
res
->
len
,
sizeof
(
res
->
len
)))
return
-
1
;
q
=
p
+
res
->
len
;
if
(
res
->
len
==
0
)
goto
out_nocopy
;
if
(
q
>
end
||
q
<
p
)
return
-
1
;
if
(
!
(
res
->
data
=
kmalloc
(
res
->
len
,
GFP_KERNEL
)))
return
-
1
;
memcpy
(
res
->
data
,
p
,
res
->
len
);
out_nocopy:
*
ptr
=
q
;
return
0
;
}
static
inline
int
get_key
(
char
**
p
,
char
*
end
,
struct
crypto_tfm
**
res
,
int
*
resalg
)
{
struct
xdr_netobj
key
=
{
.
len
=
0
,
.
data
=
NULL
,
};
int
alg_mode
,
setkey
=
0
;
char
*
alg_name
;
if
(
get_bytes
(
p
,
end
,
resalg
,
sizeof
(
int
)))
goto
out_err
;
if
((
get_netobj
(
p
,
end
,
&
key
)))
goto
out_err
;
switch
(
*
resalg
)
{
case
NID_des_cbc
:
alg_name
=
"des"
;
alg_mode
=
CRYPTO_TFM_MODE_CBC
;
setkey
=
1
;
break
;
case
NID_md5
:
if
(
key
.
len
==
0
)
{
dprintk
(
"RPC: SPKM3 get_key: NID_md5 zero Key length
\n
"
);
}
alg_name
=
"md5"
;
alg_mode
=
0
;
setkey
=
0
;
break
;
case
NID_cast5_cbc
:
dprintk
(
"RPC: SPKM3 get_key: case cast5_cbc, UNSUPPORTED
\n
"
);
goto
out_err
;
break
;
default:
dprintk
(
"RPC: SPKM3 get_key: unsupported algorithm %d"
,
*
resalg
);
goto
out_err_free_key
;
}
if
(
!
(
*
res
=
crypto_alloc_tfm
(
alg_name
,
alg_mode
)))
goto
out_err_free_key
;
if
(
setkey
)
{
if
(
crypto_cipher_setkey
(
*
res
,
key
.
data
,
key
.
len
))
goto
out_err_free_tfm
;
}
if
(
key
.
len
>
0
)
kfree
(
key
.
data
);
return
0
;
out_err_free_tfm:
crypto_free_tfm
(
*
res
);
out_err_free_key:
if
(
key
.
len
>
0
)
kfree
(
key
.
data
);
out_err:
return
-
1
;
}
static
u32
gss_import_sec_context_spkm3
(
struct
xdr_netobj
*
inbuf
,
struct
gss_ctx
*
ctx_id
)
{
char
*
p
=
inbuf
->
data
;
char
*
end
=
inbuf
->
data
+
inbuf
->
len
;
struct
spkm3_ctx
*
ctx
;
if
(
!
(
ctx
=
kmalloc
(
sizeof
(
*
ctx
),
GFP_KERNEL
)))
goto
out_err
;
memset
(
ctx
,
0
,
sizeof
(
*
ctx
));
if
(
get_netobj
(
&
p
,
end
,
&
ctx
->
ctx_id
))
goto
out_err_free_ctx
;
if
(
get_bytes
(
&
p
,
end
,
&
ctx
->
qop
,
sizeof
(
ctx
->
qop
)))
goto
out_err_free_ctx_id
;
if
(
get_netobj
(
&
p
,
end
,
&
ctx
->
mech_used
))
goto
out_err_free_mech
;
if
(
get_bytes
(
&
p
,
end
,
&
ctx
->
ret_flags
,
sizeof
(
ctx
->
ret_flags
)))
goto
out_err_free_mech
;
if
(
get_bytes
(
&
p
,
end
,
&
ctx
->
req_flags
,
sizeof
(
ctx
->
req_flags
)))
goto
out_err_free_mech
;
if
(
get_netobj
(
&
p
,
end
,
&
ctx
->
share_key
))
goto
out_err_free_s_key
;
if
(
get_key
(
&
p
,
end
,
&
ctx
->
derived_conf_key
,
&
ctx
->
conf_alg
))
{
dprintk
(
"RPC: SPKM3 confidentiality key will be NULL
\n
"
);
}
if
(
get_key
(
&
p
,
end
,
&
ctx
->
derived_integ_key
,
&
ctx
->
intg_alg
))
{
dprintk
(
"RPC: SPKM3 integrity key will be NULL
\n
"
);
}
if
(
get_bytes
(
&
p
,
end
,
&
ctx
->
owf_alg
,
sizeof
(
ctx
->
owf_alg
)))
goto
out_err_free_s_key
;
if
(
get_bytes
(
&
p
,
end
,
&
ctx
->
owf_alg
,
sizeof
(
ctx
->
owf_alg
)))
goto
out_err_free_s_key
;
if
(
p
!=
end
)
goto
out_err_free_s_key
;
ctx_id
->
internal_ctx_id
=
ctx
;
dprintk
(
"Succesfully imported new spkm context.
\n
"
);
return
0
;
out_err_free_s_key:
kfree
(
ctx
->
share_key
.
data
);
out_err_free_mech:
kfree
(
ctx
->
mech_used
.
data
);
out_err_free_ctx_id:
kfree
(
ctx
->
ctx_id
.
data
);
out_err_free_ctx:
kfree
(
ctx
);
out_err:
return
GSS_S_FAILURE
;
}
void
gss_delete_sec_context_spkm3
(
void
*
internal_ctx
)
{
struct
spkm3_ctx
*
sctx
=
internal_ctx
;
if
(
sctx
->
derived_integ_key
)
crypto_free_tfm
(
sctx
->
derived_integ_key
);
if
(
sctx
->
derived_conf_key
)
crypto_free_tfm
(
sctx
->
derived_conf_key
);
if
(
sctx
->
share_key
.
data
)
kfree
(
sctx
->
share_key
.
data
);
if
(
sctx
->
mech_used
.
data
)
kfree
(
sctx
->
mech_used
.
data
);
kfree
(
sctx
);
}
u32
gss_verify_mic_spkm3
(
struct
gss_ctx
*
ctx
,
struct
xdr_buf
*
signbuf
,
struct
xdr_netobj
*
checksum
,
u32
*
qstate
)
{
u32
maj_stat
=
0
;
int
qop_state
=
0
;
struct
spkm3_ctx
*
sctx
=
ctx
->
internal_ctx_id
;
dprintk
(
"RPC: gss_verify_mic_spkm3 calling spkm3_read_token
\n
"
);
maj_stat
=
spkm3_read_token
(
sctx
,
checksum
,
signbuf
,
&
qop_state
,
SPKM_MIC_TOK
);
if
(
!
maj_stat
&&
qop_state
)
*
qstate
=
qop_state
;
dprintk
(
"RPC: gss_verify_mic_spkm3 returning %d
\n
"
,
maj_stat
);
return
maj_stat
;
}
u32
gss_get_mic_spkm3
(
struct
gss_ctx
*
ctx
,
u32
qop
,
struct
xdr_buf
*
message_buffer
,
struct
xdr_netobj
*
message_token
)
{
u32
err
=
0
;
struct
spkm3_ctx
*
sctx
=
ctx
->
internal_ctx_id
;
dprintk
(
"RPC: gss_get_mic_spkm3
\n
"
);
err
=
spkm3_make_token
(
sctx
,
qop
,
message_buffer
,
message_token
,
SPKM_MIC_TOK
);
return
err
;
}
static
struct
gss_api_ops
gss_spkm3_ops
=
{
.
gss_import_sec_context
=
gss_import_sec_context_spkm3
,
.
gss_get_mic
=
gss_get_mic_spkm3
,
.
gss_verify_mic
=
gss_verify_mic_spkm3
,
.
gss_delete_sec_context
=
gss_delete_sec_context_spkm3
,
};
static
struct
pf_desc
gss_spkm3_pfs
[]
=
{
{
RPC_AUTH_GSS_SPKM
,
0
,
RPC_GSS_SVC_NONE
,
"spkm3"
},
{
RPC_AUTH_GSS_SPKMI
,
0
,
RPC_GSS_SVC_INTEGRITY
,
"spkm3i"
},
};
static
struct
gss_api_mech
gss_spkm3_mech
=
{
.
gm_name
=
"spkm3"
,
.
gm_owner
=
THIS_MODULE
,
.
gm_ops
=
&
gss_spkm3_ops
,
.
gm_pf_num
=
ARRAY_SIZE
(
gss_spkm3_pfs
),
.
gm_pfs
=
gss_spkm3_pfs
,
};
static
int
__init
init_spkm3_module
(
void
)
{
int
status
;
status
=
gss_mech_register
(
&
gss_spkm3_mech
);
if
(
status
)
printk
(
"Failed to register spkm3 gss mechanism!
\n
"
);
return
0
;
}
static
void
__exit
cleanup_spkm3_module
(
void
)
{
gss_mech_unregister
(
&
gss_spkm3_mech
);
}
MODULE_LICENSE
(
"GPL"
);
module_init
(
init_spkm3_module
);
module_exit
(
cleanup_spkm3_module
);
net/sunrpc/auth_gss/gss_spkm3_seal.c
0 → 100644
View file @
fec00732
/*
* linux/net/sunrpc/gss_spkm3_seal.c
*
* Copyright (c) 2003 The Regents of the University of Michigan.
* All rights reserved.
*
* Andy Adamson <andros@umich.edu>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/sunrpc/gss_spkm3.h>
#include <linux/random.h>
#include <linux/crypto.h>
#ifdef RPC_DEBUG
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
/*
* spkm3_make_token()
*
* Only SPKM_MIC_TOK with md5 intg-alg is supported
*/
u32
spkm3_make_token
(
struct
spkm3_ctx
*
ctx
,
int
qop_req
,
struct
xdr_buf
*
text
,
struct
xdr_netobj
*
token
,
int
toktype
)
{
s32
checksum_type
;
char
tokhdrbuf
[
25
];
struct
xdr_netobj
md5cksum
=
{.
len
=
0
,
.
data
=
NULL
};
struct
xdr_netobj
mic_hdr
=
{.
len
=
0
,
.
data
=
tokhdrbuf
};
int
tmsglen
,
tokenlen
=
0
;
unsigned
char
*
ptr
;
s32
now
;
int
ctxelen
=
0
,
ctxzbit
=
0
;
int
md5elen
=
0
,
md5zbit
=
0
;
dprintk
(
"RPC: spkm3_make_token
\n
"
);
now
=
jiffies
;
if
(
qop_req
!=
0
)
goto
out_err
;
if
(
ctx
->
ctx_id
.
len
!=
16
)
{
dprintk
(
"RPC: spkm3_make_token BAD ctx_id.len %d
\n
"
,
ctx
->
ctx_id
.
len
);
goto
out_err
;
}
switch
(
ctx
->
intg_alg
)
{
case
NID_md5
:
checksum_type
=
CKSUMTYPE_RSA_MD5
;
break
;
default:
dprintk
(
"RPC: gss_spkm3_seal: ctx->signalg %d not"
" supported
\n
"
,
ctx
->
intg_alg
);
goto
out_err
;
}
/* XXX since we don't support WRAP, perhaps we don't care... */
if
(
ctx
->
conf_alg
!=
NID_cast5_cbc
)
{
dprintk
(
"RPC: gss_spkm3_seal: ctx->sealalg %d not supported
\n
"
,
ctx
->
conf_alg
);
goto
out_err
;
}
if
(
toktype
==
SPKM_MIC_TOK
)
{
tmsglen
=
0
;
/* Calculate checksum over the mic-header */
asn1_bitstring_len
(
&
ctx
->
ctx_id
,
&
ctxelen
,
&
ctxzbit
);
spkm3_mic_header
(
&
mic_hdr
.
data
,
&
mic_hdr
.
len
,
ctx
->
ctx_id
.
data
,
ctxelen
,
ctxzbit
);
if
(
make_checksum
(
checksum_type
,
mic_hdr
.
data
,
mic_hdr
.
len
,
text
,
&
md5cksum
))
goto
out_err
;
asn1_bitstring_len
(
&
md5cksum
,
&
md5elen
,
&
md5zbit
);
tokenlen
=
10
+
ctxelen
+
1
+
2
+
md5elen
+
1
;
/* Create token header using generic routines */
token
->
len
=
g_token_size
(
&
ctx
->
mech_used
,
tokenlen
+
tmsglen
);
ptr
=
token
->
data
;
g_make_token_header
(
&
ctx
->
mech_used
,
tokenlen
+
tmsglen
,
&
ptr
);
spkm3_make_mic_token
(
&
ptr
,
tokenlen
,
&
mic_hdr
,
&
md5cksum
,
md5elen
,
md5zbit
);
}
else
if
(
toktype
==
SPKM_WRAP_TOK
)
{
/* Not Supported */
dprintk
(
"RPC: gss_spkm3_seal: SPKM_WRAP_TOK not supported
\n
"
);
goto
out_err
;
}
kfree
(
md5cksum
.
data
);
/* XXX need to implement sequence numbers, and ctx->expired */
return
GSS_S_COMPLETE
;
out_err:
if
(
md5cksum
.
data
)
kfree
(
md5cksum
.
data
);
token
->
data
=
0
;
token
->
len
=
0
;
return
GSS_S_FAILURE
;
}
net/sunrpc/auth_gss/gss_spkm3_token.c
0 → 100644
View file @
fec00732
/*
* linux/net/sunrpc/gss_spkm3_token.c
*
* Copyright (c) 2003 The Regents of the University of Michigan.
* All rights reserved.
*
* Andy Adamson <andros@umich.edu>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/sunrpc/gss_spkm3.h>
#include <linux/random.h>
#include <linux/crypto.h>
#ifdef RPC_DEBUG
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
/*
* asn1_bitstring_len()
*
* calculate the asn1 bitstring length of the xdr_netobject
*/
void
asn1_bitstring_len
(
struct
xdr_netobj
*
in
,
int
*
enclen
,
int
*
zerobits
)
{
int
i
,
zbit
=
0
,
elen
=
in
->
len
;
char
*
ptr
;
ptr
=
&
in
->
data
[
in
->
len
-
1
];
/* count trailing 0's */
for
(
i
=
in
->
len
;
i
>
0
;
i
--
)
{
if
(
*
ptr
==
0
)
{
ptr
--
;
elen
--
;
}
else
break
;
}
/* count number of 0 bits in final octet */
ptr
=
&
in
->
data
[
elen
-
1
];
for
(
i
=
0
;
i
<
8
;
i
++
)
{
short
mask
=
0x01
;
if
(
!
((
mask
<<
i
)
&
*
ptr
))
zbit
++
;
else
break
;
}
*
enclen
=
elen
;
*
zerobits
=
zbit
;
}
/*
* decode_asn1_bitstring()
*
* decode a bitstring into a buffer of the expected length.
* enclen = bit string length
* explen = expected length (define in rfc)
*/
int
decode_asn1_bitstring
(
struct
xdr_netobj
*
out
,
char
*
in
,
int
enclen
,
int
explen
)
{
if
(
!
(
out
->
data
=
kmalloc
(
explen
,
GFP_KERNEL
)))
return
0
;
out
->
len
=
explen
;
memset
(
out
->
data
,
0
,
explen
);
memcpy
(
out
->
data
,
in
,
enclen
);
return
1
;
}
/*
* SPKMInnerContextToken choice SPKM_MIC asn1 token layout
*
* contextid is always 16 bytes plain data. max asn1 bitstring len = 17.
*
* tokenlen = pos[0] to end of token (max pos[45] with MD5 cksum)
*
* pos value
* ----------
* [0] a4 SPKM-MIC tag
* [1] ?? innertoken length (max 44)
*
*
* tok_hdr piece of checksum data starts here
*
* the maximum mic-header len = 9 + 17 = 26
* mic-header
* ----------
* [2] 30 SEQUENCE tag
* [3] ?? mic-header length: (max 23) = TokenID + ContextID
*
* TokenID - all fields constant and can be hardcoded
* -------
* [4] 02 Type 2
* [5] 02 Length 2
* [6][7] 01 01 TokenID (SPKM_MIC_TOK)
*
* ContextID - encoded length not constant, calculated
* ---------
* [8] 03 Type 3
* [9] ?? encoded length
* [10] ?? ctxzbit
* [11] contextid
*
* mic_header piece of checksum data ends here.
*
* int-cksum - encoded length not constant, calculated
* ---------
* [??] 03 Type 3
* [??] ?? encoded length
* [??] ?? md5zbit
* [??] int-cksum (NID_md5 = 16)
*
* maximum SPKM-MIC innercontext token length =
* 10 + encoded contextid_size(17 max) + 2 + encoded
* cksum_size (17 maxfor NID_md5) = 46
*/
/*
* spkm3_mic_header()
*
* Prepare the SPKM_MIC_TOK mic-header for check-sum calculation
* elen: 16 byte context id asn1 bitstring encoded length
*/
void
spkm3_mic_header
(
unsigned
char
**
hdrbuf
,
unsigned
int
*
hdrlen
,
unsigned
char
*
ctxdata
,
int
elen
,
int
zbit
)
{
char
*
hptr
=
*
hdrbuf
;
char
*
top
=
*
hdrbuf
;
*
(
u8
*
)
hptr
++
=
0x30
;
*
(
u8
*
)
hptr
++
=
elen
+
7
;
/* on the wire header length */
/* tokenid */
*
(
u8
*
)
hptr
++
=
0x02
;
*
(
u8
*
)
hptr
++
=
0x02
;
*
(
u8
*
)
hptr
++
=
0x01
;
*
(
u8
*
)
hptr
++
=
0x01
;
/* coniextid */
*
(
u8
*
)
hptr
++
=
0x03
;
*
(
u8
*
)
hptr
++
=
elen
+
1
;
/* add 1 to include zbit */
*
(
u8
*
)
hptr
++
=
zbit
;
memcpy
(
hptr
,
ctxdata
,
elen
);
hptr
+=
elen
;
*
hdrlen
=
hptr
-
top
;
}
/*
* spkm3_mic_innercontext_token()
*
* *tokp points to the beginning of the SPKM_MIC token described
* in rfc 2025, section 3.2.1:
*
*/
void
spkm3_make_mic_token
(
unsigned
char
**
tokp
,
int
toklen
,
struct
xdr_netobj
*
mic_hdr
,
struct
xdr_netobj
*
md5cksum
,
int
md5elen
,
int
md5zbit
)
{
unsigned
char
*
ict
=
*
tokp
;
*
(
u8
*
)
ict
++
=
0xa4
;
*
(
u8
*
)
ict
++
=
toklen
-
2
;
memcpy
(
ict
,
mic_hdr
->
data
,
mic_hdr
->
len
);
ict
+=
mic_hdr
->
len
;
*
(
u8
*
)
ict
++
=
0x03
;
*
(
u8
*
)
ict
++
=
md5elen
+
1
;
/* add 1 to include zbit */
*
(
u8
*
)
ict
++
=
md5zbit
;
memcpy
(
ict
,
md5cksum
->
data
,
md5elen
);
}
u32
spkm3_verify_mic_token
(
unsigned
char
**
tokp
,
int
*
mic_hdrlen
,
unsigned
char
**
cksum
)
{
struct
xdr_netobj
spkm3_ctx_id
=
{.
len
=
0
,
.
data
=
NULL
};
unsigned
char
*
ptr
=
*
tokp
;
int
ctxelen
;
u32
ret
=
GSS_S_DEFECTIVE_TOKEN
;
/* spkm3 innercontext token preamble */
if
((
ptr
[
0
]
!=
0xa4
)
||
(
ptr
[
2
]
!=
0x30
))
{
dprintk
(
"RPC: BAD SPKM ictoken preamble
\n
"
);
goto
out
;
}
*
mic_hdrlen
=
ptr
[
3
];
/* token type */
if
((
ptr
[
4
]
!=
0x02
)
||
(
ptr
[
5
]
!=
0x02
))
{
dprintk
(
"RPC: BAD asn1 SPKM3 token type
\n
"
);
goto
out
;
}
/* only support SPKM_MIC_TOK */
if
((
ptr
[
6
]
!=
0x01
)
||
(
ptr
[
7
]
!=
0x01
))
{
dprintk
(
"RPC: ERROR unsupported SPKM3 token
\n
"
);
goto
out
;
}
/* contextid */
if
(
ptr
[
8
]
!=
0x03
)
{
dprintk
(
"RPC: BAD SPKM3 asn1 context-id type
\n
"
);
goto
out
;
}
ctxelen
=
ptr
[
9
];
if
(
ctxelen
>
17
)
{
/* length includes asn1 zbit octet */
dprintk
(
"RPC: BAD SPKM3 contextid len %d
\n
"
,
ctxelen
);
goto
out
;
}
/* ignore ptr[10] */
if
(
!
decode_asn1_bitstring
(
&
spkm3_ctx_id
,
&
ptr
[
11
],
ctxelen
-
1
,
16
))
goto
out
;
/*
* in the current implementation: the optional int-alg is not present
* so the default int-alg (md5) is used the optional snd-seq field is
* also not present
*/
if
(
*
mic_hdrlen
!=
6
+
ctxelen
)
{
dprintk
(
"RPC: BAD SPKM_ MIC_TOK header len %d: we only support default int-alg (should be absent) and do not support snd-seq
\n
"
,
*
mic_hdrlen
);
goto
out
;
}
/* checksum */
*
cksum
=
(
&
ptr
[
10
]
+
ctxelen
);
/* ctxelen includes ptr[10] */
ret
=
GSS_S_COMPLETE
;
out:
if
(
spkm3_ctx_id
.
data
)
kfree
(
spkm3_ctx_id
.
data
);
return
ret
;
}
net/sunrpc/auth_gss/gss_spkm3_unseal.c
0 → 100644
View file @
fec00732
/*
* linux/net/sunrpc/gss_spkm3_unseal.c
*
* Copyright (c) 2003 The Regents of the University of Michigan.
* All rights reserved.
*
* Andy Adamson <andros@umich.edu>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/sunrpc/gss_spkm3.h>
#include <linux/crypto.h>
#ifdef RPC_DEBUG
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
/*
* spkm3_read_token()
*
* only SPKM_MIC_TOK with md5 intg-alg is supported
*/
u32
spkm3_read_token
(
struct
spkm3_ctx
*
ctx
,
struct
xdr_netobj
*
read_token
,
/* checksum */
struct
xdr_buf
*
message_buffer
,
/* signbuf */
int
*
qop_state
,
int
toktype
)
{
s32
code
;
struct
xdr_netobj
wire_cksum
=
{.
len
=
0
,
.
data
=
NULL
};
struct
xdr_netobj
md5cksum
=
{.
len
=
0
,
.
data
=
NULL
};
unsigned
char
*
ptr
=
(
unsigned
char
*
)
read_token
->
data
;
unsigned
char
*
cksum
;
int
bodysize
,
md5elen
;
int
mic_hdrlen
;
u32
ret
=
GSS_S_DEFECTIVE_TOKEN
;
dprintk
(
"RPC: spkm3_read_token read_token->len %d
\n
"
,
read_token
->
len
);
if
(
g_verify_token_header
((
struct
xdr_netobj
*
)
&
ctx
->
mech_used
,
&
bodysize
,
&
ptr
,
read_token
->
len
))
goto
out
;
/* decode the token */
if
(
toktype
==
SPKM_MIC_TOK
)
{
if
((
ret
=
spkm3_verify_mic_token
(
&
ptr
,
&
mic_hdrlen
,
&
cksum
)))
goto
out
;
if
(
*
cksum
++
!=
0x03
)
{
dprintk
(
"RPC: spkm3_read_token BAD checksum type
\n
"
);
goto
out
;
}
md5elen
=
*
cksum
++
;
cksum
++
;
/* move past the zbit */
if
(
!
decode_asn1_bitstring
(
&
wire_cksum
,
cksum
,
md5elen
-
1
,
16
))
goto
out
;
/* HARD CODED FOR MD5 */
/* compute the checksum of the message.
* ptr + 2 = start of header piece of checksum
* mic_hdrlen + 2 = length of header piece of checksum
*/
ret
=
GSS_S_DEFECTIVE_TOKEN
;
code
=
make_checksum
(
CKSUMTYPE_RSA_MD5
,
ptr
+
2
,
mic_hdrlen
+
2
,
message_buffer
,
&
md5cksum
);
if
(
code
)
goto
out
;
dprintk
(
"RPC: spkm3_read_token: digest wire_cksum.len %d:
\n
"
,
wire_cksum
.
len
);
dprintk
(
" md5cksum.data
\n
"
);
print_hexl
((
u32
*
)
md5cksum
.
data
,
16
,
0
);
dprintk
(
" cksum.data:
\n
"
);
print_hexl
((
u32
*
)
wire_cksum
.
data
,
wire_cksum
.
len
,
0
);
ret
=
GSS_S_BAD_SIG
;
code
=
memcmp
(
md5cksum
.
data
,
wire_cksum
.
data
,
wire_cksum
.
len
);
if
(
code
)
goto
out
;
}
else
{
dprintk
(
"RPC: BAD or UNSUPPORTED SPKM3 token type: %d
\n
"
,
toktype
);
goto
out
;
}
/* XXX: need to add expiration and sequencing */
ret
=
GSS_S_COMPLETE
;
out:
if
(
md5cksum
.
data
)
kfree
(
md5cksum
.
data
);
if
(
wire_cksum
.
data
)
kfree
(
wire_cksum
.
data
);
return
ret
;
}
net/sunrpc/clnt.c
View file @
fec00732
...
...
@@ -196,7 +196,15 @@ rpc_clone_client(struct rpc_clnt *clnt)
memcpy
(
new
,
clnt
,
sizeof
(
*
new
));
atomic_set
(
&
new
->
cl_count
,
1
);
atomic_set
(
&
new
->
cl_users
,
0
);
atomic_inc
(
&
new
->
cl_parent
->
cl_count
);
new
->
cl_parent
=
clnt
;
atomic_inc
(
&
clnt
->
cl_count
);
/* Duplicate portmapper */
rpc_init_wait_queue
(
&
new
->
cl_pmap_default
.
pm_bindwait
,
"bindwait"
);
/* Turn off autobind on clones */
new
->
cl_autobind
=
0
;
new
->
cl_oneshot
=
0
;
new
->
cl_dead
=
0
;
rpc_init_rtt
(
&
new
->
cl_rtt_default
,
clnt
->
cl_xprt
->
timeout
.
to_initval
);
if
(
new
->
cl_auth
)
atomic_inc
(
&
new
->
cl_auth
->
au_count
);
return
new
;
...
...
@@ -335,7 +343,7 @@ void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset)
*/
int
rpc_call_sync
(
struct
rpc_clnt
*
clnt
,
struct
rpc_message
*
msg
,
int
flags
)
{
struct
rpc_task
my_task
,
*
task
=
&
my_
task
;
struct
rpc_task
*
task
;
sigset_t
oldset
;
int
status
;
...
...
@@ -343,15 +351,15 @@ int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
if
(
clnt
->
cl_dead
)
return
-
EIO
;
if
(
flags
&
RPC_TASK_ASYNC
)
{
printk
(
"rpc_call_sync: Illegal flag combination for synchronous task
\n
"
);
flags
&=
~
RPC_TASK_ASYNC
;
}
BUG_ON
(
flags
&
RPC_TASK_ASYNC
);
rpc_clnt_sigmask
(
clnt
,
&
oldset
);
/* Create/initialize a new RPC task */
rpc_init_task
(
task
,
clnt
,
NULL
,
flags
);
status
=
-
ENOMEM
;
task
=
rpc_new_task
(
clnt
,
NULL
,
flags
);
if
(
task
==
NULL
)
goto
out
;
rpc_call_setup
(
task
,
msg
,
0
);
/* Set up the call info struct and execute the task */
...
...
@@ -362,6 +370,7 @@ int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
rpc_release_task
(
task
);
}
out:
rpc_clnt_sigunmask
(
clnt
,
&
oldset
);
return
status
;
...
...
@@ -958,8 +967,12 @@ call_header(struct rpc_task *task)
static
u32
*
call_verify
(
struct
rpc_task
*
task
)
{
u32
*
p
=
task
->
tk_rqstp
->
rq_rcv_buf
.
head
[
0
].
iov_base
,
n
;
struct
kvec
*
iov
=
&
task
->
tk_rqstp
->
rq_rcv_buf
.
head
[
0
];
int
len
=
task
->
tk_rqstp
->
rq_rcv_buf
.
len
>>
2
;
u32
*
p
=
iov
->
iov_base
,
n
;
if
((
len
-=
3
)
<
0
)
goto
garbage
;
p
+=
1
;
/* skip XID */
if
((
n
=
ntohl
(
*
p
++
))
!=
RPC_REPLY
)
{
...
...
@@ -969,9 +982,11 @@ call_verify(struct rpc_task *task)
if
((
n
=
ntohl
(
*
p
++
))
!=
RPC_MSG_ACCEPTED
)
{
int
error
=
-
EACCES
;
if
(
--
len
<
0
)
goto
garbage
;
if
((
n
=
ntohl
(
*
p
++
))
!=
RPC_AUTH_ERROR
)
{
printk
(
KERN_WARNING
"call_verify: RPC call rejected: %x
\n
"
,
n
);
}
else
}
else
if
(
--
len
<
0
)
switch
((
n
=
ntohl
(
*
p
++
)))
{
case
RPC_AUTH_REJECTEDCRED
:
case
RPC_AUTH_REJECTEDVERF
:
...
...
@@ -1002,7 +1017,8 @@ call_verify(struct rpc_task *task)
default:
printk
(
KERN_WARNING
"call_verify: unknown auth error: %x
\n
"
,
n
);
error
=
-
EIO
;
}
}
else
goto
garbage
;
dprintk
(
"RPC: %4d call_verify: call rejected %d
\n
"
,
task
->
tk_pid
,
n
);
rpc_exit
(
task
,
error
);
...
...
@@ -1012,6 +1028,9 @@ call_verify(struct rpc_task *task)
printk
(
KERN_WARNING
"call_verify: auth check failed
\n
"
);
goto
garbage
;
/* bad verifier, retry */
}
len
=
p
-
(
u32
*
)
iov
->
iov_base
-
1
;
if
(
len
<
0
)
goto
garbage
;
switch
((
n
=
ntohl
(
*
p
++
)))
{
case
RPC_SUCCESS
:
return
p
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment