Merge branch 'nfsd-next' of git://linux-nfs.org/~bfields/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 16 Nov 2013 20:04:02 +0000 (12:04 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 16 Nov 2013 20:04:02 +0000 (12:04 -0800)
Pull nfsd changes from Bruce Fields:
 "This includes miscellaneous bugfixes and cleanup and a performance fix
  for write-heavy NFSv4 workloads.

  (The most significant nfsd-relevant change this time is actually in
  the delegation patches that went through Viro, fixing a long-standing
  bug that can cause NFSv4 clients to miss updates made by non-nfs users
  of the filesystem.  Those enable some followup nfsd patches which I
  have queued locally, but those can wait till 3.14)"

* 'nfsd-next' of git://linux-nfs.org/~bfields/linux: (24 commits)
  nfsd: export proper maximum file size to the client
  nfsd4: improve write performance with better sendspace reservations
  svcrpc: remove an unnecessary assignment
  sunrpc: comment typo fix
  Revert "nfsd: remove_stid can be incorporated into nfs4_put_delegation"
  nfsd4: fix discarded security labels on setattr
  NFSD: Add support for NFS v4.2 operation checking
  nfsd4: nfsd_shutdown_net needs state lock
  NFSD: Combine decode operations for v4 and v4.1
  nfsd: -EINVAL on invalid anonuid/gid instead of silent failure
  nfsd: return better errors to exportfs
  nfsd: fh_update should error out in unexpected cases
  nfsd4: need to destroy revoked delegations in destroy_client
  nfsd: no need to unhash_stid before free
  nfsd: remove_stid can be incorporated into nfs4_put_delegation
  nfsd: nfs4_open_delegation needs to remove_stid rather than unhash_stid
  nfsd: nfs4_free_stid
  nfsd: fix Kconfig syntax
  sunrpc: trim off EC bytes in GSSAPI v2 unwrap
  gss_krb5: document that we ignore sequence number
  ...

12 files changed:
fs/nfsd/Kconfig
fs/nfsd/export.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfsfh.c
include/linux/nfs4.h
net/sunrpc/auth_gss/gss_krb5_unseal.c
net/sunrpc/auth_gss/gss_krb5_wrap.c
net/sunrpc/auth_gss/gss_rpc_upcall.c
net/sunrpc/auth_gss/gss_rpc_xdr.c
net/sunrpc/auth_gss/svcauth_gss.c
net/sunrpc/svc.c

index dc8f1ef..f994e75 100644 (file)
@@ -95,7 +95,7 @@ config NFSD_V4_SECURITY_LABEL
        Smack policies on NFSv4 files, say N.
 
        WARNING: there is still a chance of backwards-incompatible protocol changes.
-       For now we recommend "Y" only for developers and testers."
+       For now we recommend "Y" only for developers and testers.
 
 config NFSD_FAULT_INJECTION
        bool "NFS server manual fault injection"
index 5f38ea3..8513c59 100644 (file)
@@ -536,16 +536,12 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
                if (err)
                        goto out3;
                exp.ex_anon_uid= make_kuid(&init_user_ns, an_int);
-               if (!uid_valid(exp.ex_anon_uid))
-                       goto out3;
 
                /* anon gid */
                err = get_int(&mesg, &an_int);
                if (err)
                        goto out3;
                exp.ex_anon_gid= make_kgid(&init_user_ns, an_int);
-               if (!gid_valid(exp.ex_anon_gid))
-                       goto out3;
 
                /* fsid */
                err = get_int(&mesg, &an_int);
@@ -583,6 +579,26 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
                                   exp.ex_uuid);
                if (err)
                        goto out4;
+               /*
+                * No point caching this if it would immediately expire.
+                * Also, this protects exportfs's dummy export from the
+                * anon_uid/anon_gid checks:
+                */
+               if (exp.h.expiry_time < seconds_since_boot())
+                       goto out4;
+               /*
+                * For some reason exportfs has been passing down an
+                * invalid (-1) uid & gid on the "dummy" export which it
+                * uses to test export support.  To make sure exportfs
+                * sees errors from check_export we therefore need to
+                * delay these checks till after check_export:
+                */
+               err = -EINVAL;
+               if (!uid_valid(exp.ex_anon_uid))
+                       goto out4;
+               if (!gid_valid(exp.ex_anon_gid))
+                       goto out4;
+               err = 0;
        }
 
        expp = svc_export_lookup(&exp);
index f36a30a..105d6fa 100644 (file)
@@ -402,11 +402,16 @@ static void remove_stid(struct nfs4_stid *s)
        idr_remove(stateids, s->sc_stateid.si_opaque.so_id);
 }
 
+static void nfs4_free_stid(struct kmem_cache *slab, struct nfs4_stid *s)
+{
+       kmem_cache_free(slab, s);
+}
+
 void
 nfs4_put_delegation(struct nfs4_delegation *dp)
 {
        if (atomic_dec_and_test(&dp->dl_count)) {
-               kmem_cache_free(deleg_slab, dp);
+               nfs4_free_stid(deleg_slab, &dp->dl_stid);
                num_delegations--;
        }
 }
@@ -610,7 +615,7 @@ static void close_generic_stateid(struct nfs4_ol_stateid *stp)
 static void free_generic_stateid(struct nfs4_ol_stateid *stp)
 {
        remove_stid(&stp->st_stid);
-       kmem_cache_free(stateid_slab, stp);
+       nfs4_free_stid(stateid_slab, &stp->st_stid);
 }
 
 static void release_lock_stateid(struct nfs4_ol_stateid *stp)
@@ -668,7 +673,6 @@ static void unhash_open_stateid(struct nfs4_ol_stateid *stp)
 static void release_open_stateid(struct nfs4_ol_stateid *stp)
 {
        unhash_open_stateid(stp);
-       unhash_stid(&stp->st_stid);
        free_generic_stateid(stp);
 }
 
@@ -690,7 +694,6 @@ static void release_last_closed_stateid(struct nfs4_openowner *oo)
        struct nfs4_ol_stateid *s = oo->oo_last_closed_stid;
 
        if (s) {
-               unhash_stid(&s->st_stid);
                free_generic_stateid(s);
                oo->oo_last_closed_stid = NULL;
        }
@@ -1127,6 +1130,11 @@ destroy_client(struct nfs4_client *clp)
                dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru);
                destroy_delegation(dp);
        }
+       list_splice_init(&clp->cl_revoked, &reaplist);
+       while (!list_empty(&reaplist)) {
+               dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru);
+               destroy_revoked_delegation(dp);
+       }
        while (!list_empty(&clp->cl_openowners)) {
                oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient);
                release_openowner(oo);
@@ -3154,7 +3162,7 @@ nfs4_open_delegation(struct net *net, struct svc_fh *fh,
        open->op_delegate_type = NFS4_OPEN_DELEGATE_READ;
        return;
 out_free:
-       unhash_stid(&dp->dl_stid);
+       remove_stid(&dp->dl_stid);
        nfs4_put_delegation(dp);
 out_no_deleg:
        open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE;
@@ -3995,10 +4003,9 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 
        nfsd4_close_open_stateid(stp);
 
-       if (cstate->minorversion) {
-               unhash_stid(&stp->st_stid);
+       if (cstate->minorversion)
                free_generic_stateid(stp);
-       else
+       else
                oo->oo_last_closed_stid = stp;
 
        if (list_empty(&oo->oo_owner.so_stateids)) {
@@ -5119,7 +5126,6 @@ out_recovery:
        return ret;
 }
 
-/* should be called with the state lock held */
 void
 nfs4_state_shutdown_net(struct net *net)
 {
@@ -5130,6 +5136,7 @@ nfs4_state_shutdown_net(struct net *net)
        cancel_delayed_work_sync(&nn->laundromat_work);
        locks_end_grace(&nn->nfsd4_manager);
 
+       nfs4_lock_state();
        INIT_LIST_HEAD(&reaplist);
        spin_lock(&recall_lock);
        list_for_each_safe(pos, next, &nn->del_recall_lru) {
@@ -5144,6 +5151,7 @@ nfs4_state_shutdown_net(struct net *net)
 
        nfsd4_client_tracking_exit(net);
        nfs4_state_destroy_net(net);
+       nfs4_unlock_state();
 }
 
 void
index d9454fe..088de13 100644 (file)
@@ -411,6 +411,7 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
                label->data = kzalloc(dummy32 + 1, GFP_KERNEL);
                if (!label->data)
                        return nfserr_jukebox;
+               label->len = dummy32;
                defer_free(argp, kfree, label->data);
                memcpy(label->data, buf, dummy32);
        }
@@ -945,13 +946,16 @@ static __be32
 nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_confirm *open_conf)
 {
        DECODE_HEAD;
-                   
+
+       if (argp->minorversion >= 1)
+               return nfserr_notsupp;
+
        status = nfsd4_decode_stateid(argp, &open_conf->oc_req_stateid);
        if (status)
                return status;
        READ_BUF(4);
        READ32(open_conf->oc_seqid);
-                                                       
+
        DECODE_TAIL;
 }
 
@@ -990,6 +994,14 @@ nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, struct nfsd4_putfh *putfh)
        DECODE_TAIL;
 }
 
+static __be32
+nfsd4_decode_putpubfh(struct nfsd4_compoundargs *argp, void *p)
+{
+       if (argp->minorversion == 0)
+               return nfs_ok;
+       return nfserr_notsupp;
+}
+
 static __be32
 nfsd4_decode_read(struct nfsd4_compoundargs *argp, struct nfsd4_read *read)
 {
@@ -1061,6 +1073,9 @@ nfsd4_decode_renew(struct nfsd4_compoundargs *argp, clientid_t *clientid)
 {
        DECODE_HEAD;
 
+       if (argp->minorversion >= 1)
+               return nfserr_notsupp;
+
        READ_BUF(sizeof(clientid_t));
        COPYMEM(clientid, sizeof(clientid_t));
 
@@ -1111,6 +1126,9 @@ nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclient
 {
        DECODE_HEAD;
 
+       if (argp->minorversion >= 1)
+               return nfserr_notsupp;
+
        READ_BUF(NFS4_VERIFIER_SIZE);
        COPYMEM(setclientid->se_verf.data, NFS4_VERIFIER_SIZE);
 
@@ -1137,6 +1155,9 @@ nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_s
 {
        DECODE_HEAD;
 
+       if (argp->minorversion >= 1)
+               return nfserr_notsupp;
+
        READ_BUF(8 + NFS4_VERIFIER_SIZE);
        COPYMEM(&scd_c->sc_clientid, 8);
        COPYMEM(&scd_c->sc_confirm, NFS4_VERIFIER_SIZE);
@@ -1220,6 +1241,9 @@ nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_rel
 {
        DECODE_HEAD;
 
+       if (argp->minorversion >= 1)
+               return nfserr_notsupp;
+
        READ_BUF(12);
        COPYMEM(&rlockowner->rl_clientid, sizeof(clientid_t));
        READ32(rlockowner->rl_owner.len);
@@ -1519,7 +1543,7 @@ static nfsd4_dec nfsd4_dec_ops[] = {
        [OP_OPEN_CONFIRM]       = (nfsd4_dec)nfsd4_decode_open_confirm,
        [OP_OPEN_DOWNGRADE]     = (nfsd4_dec)nfsd4_decode_open_downgrade,
        [OP_PUTFH]              = (nfsd4_dec)nfsd4_decode_putfh,
-       [OP_PUTPUBFH]           = (nfsd4_dec)nfsd4_decode_noop,
+       [OP_PUTPUBFH]           = (nfsd4_dec)nfsd4_decode_putpubfh,
        [OP_PUTROOTFH]          = (nfsd4_dec)nfsd4_decode_noop,
        [OP_READ]               = (nfsd4_dec)nfsd4_decode_read,
        [OP_READDIR]            = (nfsd4_dec)nfsd4_decode_readdir,
@@ -1536,46 +1560,6 @@ static nfsd4_dec nfsd4_dec_ops[] = {
        [OP_VERIFY]             = (nfsd4_dec)nfsd4_decode_verify,
        [OP_WRITE]              = (nfsd4_dec)nfsd4_decode_write,
        [OP_RELEASE_LOCKOWNER]  = (nfsd4_dec)nfsd4_decode_release_lockowner,
-};
-
-static nfsd4_dec nfsd41_dec_ops[] = {
-       [OP_ACCESS]             = (nfsd4_dec)nfsd4_decode_access,
-       [OP_CLOSE]              = (nfsd4_dec)nfsd4_decode_close,
-       [OP_COMMIT]             = (nfsd4_dec)nfsd4_decode_commit,
-       [OP_CREATE]             = (nfsd4_dec)nfsd4_decode_create,
-       [OP_DELEGPURGE]         = (nfsd4_dec)nfsd4_decode_notsupp,
-       [OP_DELEGRETURN]        = (nfsd4_dec)nfsd4_decode_delegreturn,
-       [OP_GETATTR]            = (nfsd4_dec)nfsd4_decode_getattr,
-       [OP_GETFH]              = (nfsd4_dec)nfsd4_decode_noop,
-       [OP_LINK]               = (nfsd4_dec)nfsd4_decode_link,
-       [OP_LOCK]               = (nfsd4_dec)nfsd4_decode_lock,
-       [OP_LOCKT]              = (nfsd4_dec)nfsd4_decode_lockt,
-       [OP_LOCKU]              = (nfsd4_dec)nfsd4_decode_locku,
-       [OP_LOOKUP]             = (nfsd4_dec)nfsd4_decode_lookup,
-       [OP_LOOKUPP]            = (nfsd4_dec)nfsd4_decode_noop,
-       [OP_NVERIFY]            = (nfsd4_dec)nfsd4_decode_verify,
-       [OP_OPEN]               = (nfsd4_dec)nfsd4_decode_open,
-       [OP_OPENATTR]           = (nfsd4_dec)nfsd4_decode_notsupp,
-       [OP_OPEN_CONFIRM]       = (nfsd4_dec)nfsd4_decode_notsupp,
-       [OP_OPEN_DOWNGRADE]     = (nfsd4_dec)nfsd4_decode_open_downgrade,
-       [OP_PUTFH]              = (nfsd4_dec)nfsd4_decode_putfh,
-       [OP_PUTPUBFH]           = (nfsd4_dec)nfsd4_decode_notsupp,
-       [OP_PUTROOTFH]          = (nfsd4_dec)nfsd4_decode_noop,
-       [OP_READ]               = (nfsd4_dec)nfsd4_decode_read,
-       [OP_READDIR]            = (nfsd4_dec)nfsd4_decode_readdir,
-       [OP_READLINK]           = (nfsd4_dec)nfsd4_decode_noop,
-       [OP_REMOVE]             = (nfsd4_dec)nfsd4_decode_remove,
-       [OP_RENAME]             = (nfsd4_dec)nfsd4_decode_rename,
-       [OP_RENEW]              = (nfsd4_dec)nfsd4_decode_notsupp,
-       [OP_RESTOREFH]          = (nfsd4_dec)nfsd4_decode_noop,
-       [OP_SAVEFH]             = (nfsd4_dec)nfsd4_decode_noop,
-       [OP_SECINFO]            = (nfsd4_dec)nfsd4_decode_secinfo,
-       [OP_SETATTR]            = (nfsd4_dec)nfsd4_decode_setattr,
-       [OP_SETCLIENTID]        = (nfsd4_dec)nfsd4_decode_notsupp,
-       [OP_SETCLIENTID_CONFIRM]= (nfsd4_dec)nfsd4_decode_notsupp,
-       [OP_VERIFY]             = (nfsd4_dec)nfsd4_decode_verify,
-       [OP_WRITE]              = (nfsd4_dec)nfsd4_decode_write,
-       [OP_RELEASE_LOCKOWNER]  = (nfsd4_dec)nfsd4_decode_notsupp,
 
        /* new operations for NFSv4.1 */
        [OP_BACKCHANNEL_CTL]    = (nfsd4_dec)nfsd4_decode_backchannel_ctl,
@@ -1599,24 +1583,53 @@ static nfsd4_dec nfsd41_dec_ops[] = {
        [OP_RECLAIM_COMPLETE]   = (nfsd4_dec)nfsd4_decode_reclaim_complete,
 };
 
-struct nfsd4_minorversion_ops {
-       nfsd4_dec *decoders;
-       int nops;
-};
+static inline bool
+nfsd4_opnum_in_range(struct nfsd4_compoundargs *argp, struct nfsd4_op *op)
+{
+       if (op->opnum < FIRST_NFS4_OP)
+               return false;
+       else if (argp->minorversion == 0 && op->opnum > LAST_NFS40_OP)
+               return false;
+       else if (argp->minorversion == 1 && op->opnum > LAST_NFS41_OP)
+               return false;
+       else if (argp->minorversion == 2 && op->opnum > LAST_NFS42_OP)
+               return false;
+       return true;
+}
 
-static struct nfsd4_minorversion_ops nfsd4_minorversion[] = {
-       [0] = { nfsd4_dec_ops, ARRAY_SIZE(nfsd4_dec_ops) },
-       [1] = { nfsd41_dec_ops, ARRAY_SIZE(nfsd41_dec_ops) },
-       [2] = { nfsd41_dec_ops, ARRAY_SIZE(nfsd41_dec_ops) },
-};
+/*
+ * Return a rough estimate of the maximum possible reply size.  Note the
+ * estimate includes rpc headers so is meant to be passed to
+ * svc_reserve, not svc_reserve_auth.
+ *
+ * Also note the current compound encoding permits only one operation to
+ * use pages beyond the first one, so the maximum possible length is the
+ * maximum over these values, not the sum.
+ */
+static int nfsd4_max_reply(u32 opnum)
+{
+       switch (opnum) {
+       case OP_READLINK:
+       case OP_READDIR:
+               /*
+                * Both of these ops take a single page for data and put
+                * the head and tail in another page:
+                */
+               return 2 * PAGE_SIZE;
+       case OP_READ:
+               return INT_MAX;
+       default:
+               return PAGE_SIZE;
+       }
+}
 
 static __be32
 nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
 {
        DECODE_HEAD;
        struct nfsd4_op *op;
-       struct nfsd4_minorversion_ops *ops;
        bool cachethis = false;
+       int max_reply = PAGE_SIZE;
        int i;
 
        READ_BUF(4);
@@ -1640,10 +1653,9 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
                }
        }
 
-       if (argp->minorversion >= ARRAY_SIZE(nfsd4_minorversion))
+       if (argp->minorversion > NFSD_SUPPORTED_MINOR_VERSION)
                argp->opcnt = 0;
 
-       ops = &nfsd4_minorversion[argp->minorversion];
        for (i = 0; i < argp->opcnt; i++) {
                op = &argp->ops[i];
                op->replay = NULL;
@@ -1651,8 +1663,8 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
                READ_BUF(4);
                READ32(op->opnum);
 
-               if (op->opnum >= FIRST_NFS4_OP && op->opnum <= LAST_NFS4_OP)
-                       op->status = ops->decoders[op->opnum](argp, &op->u);
+               if (nfsd4_opnum_in_range(argp, op))
+                       op->status = nfsd4_dec_ops[op->opnum](argp, &op->u);
                else {
                        op->opnum = OP_ILLEGAL;
                        op->status = nfserr_op_illegal;
@@ -1667,10 +1679,14 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
                 * op in the compound wants to be cached:
                 */
                cachethis |= nfsd4_cache_this_op(op);
+
+               max_reply = max(max_reply, nfsd4_max_reply(op->opnum));
        }
        /* Sessions make the DRC unnecessary: */
        if (argp->minorversion)
                cachethis = false;
+       if (max_reply != INT_MAX)
+               svc_reserve(argp->rqstp, max_reply);
        argp->rqstp->rq_cachetype = cachethis ? RC_REPLBUFF : RC_NOCACHE;
 
        DECODE_TAIL;
@@ -2375,7 +2391,7 @@ out_acl:
        if (bmval0 & FATTR4_WORD0_MAXFILESIZE) {
                if ((buflen -= 8) < 0)
                        goto out_resource;
-               WRITE64(~(u64)0);
+               WRITE64(exp->ex_path.mnt->mnt_sb->s_maxbytes);
        }
        if (bmval0 & FATTR4_WORD0_MAXLINK) {
                if ((buflen -= 4) < 0)
index 3d0e15a..3c37b16 100644 (file)
@@ -598,22 +598,20 @@ fh_update(struct svc_fh *fhp)
                _fh_update_old(dentry, fhp->fh_export, &fhp->fh_handle);
        } else {
                if (fhp->fh_handle.fh_fileid_type != FILEID_ROOT)
-                       goto out;
+                       return 0;
 
                _fh_update(fhp, fhp->fh_export, dentry);
                if (fhp->fh_handle.fh_fileid_type == FILEID_INVALID)
                        return nfserr_opnotsupp;
        }
-out:
        return 0;
-
 out_bad:
        printk(KERN_ERR "fh_update: fh not verified!\n");
-       goto out;
+       return nfserr_serverfault;
 out_negative:
        printk(KERN_ERR "fh_update: %pd2 still negative!\n",
                dentry);
-       goto out;
+       return nfserr_serverfault;
 }
 
 /*
index c6f41b6..c163706 100644 (file)
@@ -118,6 +118,9 @@ Needs to be updated if more operations are defined in future.*/
 
 #define FIRST_NFS4_OP  OP_ACCESS
 #define LAST_NFS4_OP   OP_RECLAIM_COMPLETE
+#define LAST_NFS40_OP  OP_RELEASE_LOCKOWNER
+#define LAST_NFS41_OP  OP_RECLAIM_COMPLETE
+#define LAST_NFS42_OP  OP_RECLAIM_COMPLETE
 
 enum nfsstat4 {
        NFS4_OK = 0,
index 6cd930f..6c981dd 100644 (file)
@@ -150,7 +150,6 @@ gss_verify_mic_v2(struct krb5_ctx *ctx,
        struct xdr_netobj cksumobj = {.len = sizeof(cksumdata),
                                      .data = cksumdata};
        s32 now;
-       u64 seqnum;
        u8 *ptr = read_token->data;
        u8 *cksumkey;
        u8 flags;
@@ -197,9 +196,10 @@ gss_verify_mic_v2(struct krb5_ctx *ctx,
        if (now > ctx->endtime)
                return GSS_S_CONTEXT_EXPIRED;
 
-       /* do sequencing checks */
-
-       seqnum = be64_to_cpup((__be64 *)ptr + 8);
+       /*
+        * NOTE: the sequence number at ptr + 8 is skipped, rpcsec_gss
+        * doesn't want it checked; see page 6 of rfc 2203.
+        */
 
        return GSS_S_COMPLETE;
 }
index 1da52d1..42560e5 100644 (file)
@@ -489,7 +489,6 @@ static u32
 gss_unwrap_kerberos_v2(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
 {
        s32             now;
-       u64             seqnum;
        u8              *ptr;
        u8              flags = 0x00;
        u16             ec, rrc;
@@ -525,7 +524,10 @@ gss_unwrap_kerberos_v2(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
        ec = be16_to_cpup((__be16 *)(ptr + 4));
        rrc = be16_to_cpup((__be16 *)(ptr + 6));
 
-       seqnum = be64_to_cpup((__be64 *)(ptr + 8));
+       /*
+        * NOTE: the sequence number at ptr + 8 is skipped, rpcsec_gss
+        * doesn't want it checked; see page 6 of rfc 2203.
+        */
 
        if (rrc != 0)
                rotate_left(offset + 16, buf, rrc);
@@ -574,8 +576,8 @@ gss_unwrap_kerberos_v2(struct krb5_ctx *kctx, int offset, struct xdr_buf *buf)
        buf->head[0].iov_len -= GSS_KRB5_TOK_HDR_LEN + headskip;
        buf->len -= GSS_KRB5_TOK_HDR_LEN + headskip;
 
-       /* Trim off the checksum blob */
-       xdr_buf_trim(buf, GSS_KRB5_TOK_HDR_LEN + tailskip);
+       /* Trim off the trailing "extra count" and checksum blob */
+       xdr_buf_trim(buf, ec + GSS_KRB5_TOK_HDR_LEN + tailskip);
        return GSS_S_COMPLETE;
 }
 
index f1eb0d1..458f85e 100644 (file)
@@ -298,7 +298,8 @@ int gssp_accept_sec_context_upcall(struct net *net,
        if (res.context_handle) {
                data->out_handle = rctxh.exported_context_token;
                data->mech_oid.len = rctxh.mech.len;
-               memcpy(data->mech_oid.data, rctxh.mech.data,
+               if (rctxh.mech.data)
+                       memcpy(data->mech_oid.data, rctxh.mech.data,
                                                data->mech_oid.len);
                client_name = rctxh.src_name.display_name;
        }
index f0f78c5..1ec19f6 100644 (file)
@@ -559,6 +559,8 @@ static int gssx_enc_cred(struct xdr_stream *xdr,
 
        /* cred->elements */
        err = dummy_enc_credel_array(xdr, &cred->elements);
+       if (err)
+               return err;
 
        /* cred->cred_handle_reference */
        err = gssx_enc_buffer(xdr, &cred->cred_handle_reference);
@@ -740,22 +742,20 @@ void gssx_enc_accept_sec_context(struct rpc_rqst *req,
                goto done;
 
        /* arg->context_handle */
-       if (arg->context_handle) {
+       if (arg->context_handle)
                err = gssx_enc_ctx(xdr, arg->context_handle);
-               if (err)
-                       goto done;
-       } else {
+       else
                err = gssx_enc_bool(xdr, 0);
-       }
+       if (err)
+               goto done;
 
        /* arg->cred_handle */
-       if (arg->cred_handle) {
+       if (arg->cred_handle)
                err = gssx_enc_cred(xdr, arg->cred_handle);
-               if (err)
-                       goto done;
-       } else {
+       else
                err = gssx_enc_bool(xdr, 0);
-       }
+       if (err)
+               goto done;
 
        /* arg->input_token */
        err = gssx_enc_in_token(xdr, &arg->input_token);
@@ -763,13 +763,12 @@ void gssx_enc_accept_sec_context(struct rpc_rqst *req,
                goto done;
 
        /* arg->input_cb */
-       if (arg->input_cb) {
+       if (arg->input_cb)
                err = gssx_enc_cb(xdr, arg->input_cb);
-               if (err)
-                       goto done;
-       } else {
+       else
                err = gssx_enc_bool(xdr, 0);
-       }
+       if (err)
+               goto done;
 
        err = gssx_enc_bool(xdr, arg->ret_deleg_cred);
        if (err)
index 09fb638..008cdad 100644 (file)
@@ -1167,8 +1167,8 @@ static int gss_proxy_save_rsc(struct cache_detail *cd,
        if (!ud->found_creds) {
                /* userspace seem buggy, we should always get at least a
                 * mapping to nobody */
-               dprintk("RPC:       No creds found, marking Negative!\n");
-               set_bit(CACHE_NEGATIVE, &rsci.h.flags);
+               dprintk("RPC:       No creds found!\n");
+               goto out;
        } else {
 
                /* steal creds */
index b974571..e7fbe36 100644 (file)
@@ -1104,8 +1104,6 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv)
        rqstp->rq_vers = vers = svc_getnl(argv);        /* version number */
        rqstp->rq_proc = proc = svc_getnl(argv);        /* procedure number */
 
-       progp = serv->sv_program;
-
        for (progp = serv->sv_program; progp; progp = progp->pg_next)
                if (prog == progp->pg_prog)
                        break;