Merge tag 'xfs-for-linus-4.5-2' of git://git.kernel.org/pub/scm/linux/kernel/git...
[cascardo/linux.git] / fs / nfsd / nfs4state.c
index df5dba6..c484a2b 100644 (file)
@@ -98,7 +98,7 @@ static struct kmem_cache *odstate_slab;
 
 static void free_session(struct nfsd4_session *);
 
-static struct nfsd4_callback_ops nfsd4_cb_recall_ops;
+static const struct nfsd4_callback_ops nfsd4_cb_recall_ops;
 
 static bool is_session_dead(struct nfsd4_session *ses)
 {
@@ -1857,15 +1857,28 @@ static void copy_clid(struct nfs4_client *target, struct nfs4_client *source)
        target->cl_clientid.cl_id = source->cl_clientid.cl_id; 
 }
 
-static int copy_cred(struct svc_cred *target, struct svc_cred *source)
+int strdup_if_nonnull(char **target, char *source)
 {
-       if (source->cr_principal) {
-               target->cr_principal =
-                               kstrdup(source->cr_principal, GFP_KERNEL);
-               if (target->cr_principal == NULL)
+       if (source) {
+               *target = kstrdup(source, GFP_KERNEL);
+               if (!*target)
                        return -ENOMEM;
        } else
-               target->cr_principal = NULL;
+               *target = NULL;
+       return 0;
+}
+
+static int copy_cred(struct svc_cred *target, struct svc_cred *source)
+{
+       int ret;
+
+       ret = strdup_if_nonnull(&target->cr_principal, source->cr_principal);
+       if (ret)
+               return ret;
+       ret = strdup_if_nonnull(&target->cr_raw_principal,
+                                       source->cr_raw_principal);
+       if (ret)
+               return ret;
        target->cr_flavor = source->cr_flavor;
        target->cr_uid = source->cr_uid;
        target->cr_gid = source->cr_gid;
@@ -1969,6 +1982,9 @@ static bool mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp)
                return false;
        if (!svc_rqst_integrity_protected(rqstp))
                return false;
+       if (cl->cl_cred.cr_raw_principal)
+               return 0 == strcmp(cl->cl_cred.cr_raw_principal,
+                                               cr->cr_raw_principal);
        if (!cr->cr_principal)
                return false;
        return 0 == strcmp(cl->cl_cred.cr_principal, cr->cr_principal);
@@ -2240,7 +2256,8 @@ nfsd4_store_cache_entry(struct nfsd4_compoundres *resp)
        base = resp->cstate.data_offset;
        slot->sl_datalen = buf->len - base;
        if (read_bytes_from_xdr_buf(buf, base, slot->sl_data, slot->sl_datalen))
-               WARN("%s: sessions DRC could not cache compound\n", __func__);
+               WARN(1, "%s: sessions DRC could not cache compound\n",
+                    __func__);
        return;
 }
 
@@ -2365,10 +2382,27 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
        if (exid->flags & ~EXCHGID4_FLAG_MASK_A)
                return nfserr_inval;
 
+       new = create_client(exid->clname, rqstp, &verf);
+       if (new == NULL)
+               return nfserr_jukebox;
+
        switch (exid->spa_how) {
        case SP4_MACH_CRED:
-               if (!svc_rqst_integrity_protected(rqstp))
-                       return nfserr_inval;
+               if (!svc_rqst_integrity_protected(rqstp)) {
+                       status = nfserr_inval;
+                       goto out_nolock;
+               }
+               /*
+                * Sometimes userspace doesn't give us a principal.
+                * Which is a bug, really.  Anyway, we can't enforce
+                * MACH_CRED in that case, better to give up now:
+                */
+               if (!new->cl_cred.cr_principal &&
+                                       !new->cl_cred.cr_raw_principal) {
+                       status = nfserr_serverfault;
+                       goto out_nolock;
+               }
+               new->cl_mach_cred = true;
        case SP4_NONE:
                break;
        default:                                /* checked by xdr code */
@@ -2377,10 +2411,6 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
                return nfserr_encr_alg_unsupp;
        }
 
-       new = create_client(exid->clname, rqstp, &verf);
-       if (new == NULL)
-               return nfserr_jukebox;
-
        /* Cases below refer to rfc 5661 section 18.35.4: */
        spin_lock(&nn->client_lock);
        conf = find_confirmed_client_by_name(&exid->clname, nn);
@@ -2442,7 +2472,6 @@ out_new:
                        goto out;
        }
        new->cl_minorversion = cstate->minorversion;
-       new->cl_mach_cred = (exid->spa_how == SP4_MACH_CRED);
 
        gen_clid(new, nn);
        add_to_unconfirmed(new);
@@ -2460,6 +2489,7 @@ out_copy:
 
 out:
        spin_unlock(&nn->client_lock);
+out_nolock:
        if (new)
                expire_client(new);
        if (unconf)
@@ -3648,7 +3678,7 @@ static void nfsd4_cb_recall_release(struct nfsd4_callback *cb)
        nfs4_put_stid(&dp->dl_stid);
 }
 
-static struct nfsd4_callback_ops nfsd4_cb_recall_ops = {
+static const struct nfsd4_callback_ops nfsd4_cb_recall_ops = {
        .prepare        = nfsd4_cb_recall_prepare,
        .done           = nfsd4_cb_recall_done,
        .release        = nfsd4_cb_recall_release,
@@ -4541,8 +4571,7 @@ static void
 laundromat_main(struct work_struct *laundry)
 {
        time_t t;
-       struct delayed_work *dwork = container_of(laundry, struct delayed_work,
-                                                 work);
+       struct delayed_work *dwork = to_delayed_work(laundry);
        struct nfsd_net *nn = container_of(dwork, struct nfsd_net,
                                           laundromat_work);