SUNRPC: Use xdr_stream to encode Reply verifier in svcauth_unix_accept()
[linux-2.6-microblaze.git] / net / sunrpc / svcauth_unix.c
index b1efc34..e3981e1 100644 (file)
@@ -729,23 +729,38 @@ out:
 
 EXPORT_SYMBOL_GPL(svcauth_unix_set_client);
 
+/**
+ * svcauth_null_accept - Decode and validate incoming RPC_AUTH_NULL credential
+ * @rqstp: RPC transaction
+ *
+ * Return values:
+ *   %SVC_OK: Both credential and verifier are valid
+ *   %SVC_DENIED: Credential or verifier is not valid
+ *   %SVC_GARBAGE: Failed to decode credential or verifier
+ *   %SVC_CLOSE: Temporary failure
+ *
+ * rqstp->rq_auth_stat is set as mandated by RFC 5531.
+ */
 static int
 svcauth_null_accept(struct svc_rqst *rqstp)
 {
-       struct kvec     *argv = &rqstp->rq_arg.head[0];
-       struct kvec     *resv = &rqstp->rq_res.head[0];
+       struct xdr_stream *xdr = &rqstp->rq_arg_stream;
        struct svc_cred *cred = &rqstp->rq_cred;
+       u32 flavor, len;
+       void *body;
 
-       if (argv->iov_len < 3*4)
+       /* Length of Call's credential body field: */
+       if (xdr_stream_decode_u32(xdr, &len) < 0)
                return SVC_GARBAGE;
-
-       if (svc_getu32(argv) != 0) {
-               dprintk("svc: bad null cred\n");
+       if (len != 0) {
                rqstp->rq_auth_stat = rpc_autherr_badcred;
                return SVC_DENIED;
        }
-       if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) {
-               dprintk("svc: bad null verf\n");
+
+       /* Call's verf field: */
+       if (xdr_stream_decode_opaque_auth(xdr, &flavor, &body, &len) < 0)
+               return SVC_GARBAGE;
+       if (flavor != RPC_AUTH_NULL || len != 0) {
                rqstp->rq_auth_stat = rpc_autherr_badverf;
                return SVC_DENIED;
        }
@@ -757,9 +772,10 @@ svcauth_null_accept(struct svc_rqst *rqstp)
        if (cred->cr_group_info == NULL)
                return SVC_CLOSE; /* kmalloc failure - client must retry */
 
-       /* Put NULL verifier */
-       svc_putnl(resv, RPC_AUTH_NULL);
-       svc_putnl(resv, 0);
+       svcxdr_init_encode(rqstp);
+       if (xdr_stream_encode_opaque_auth(&rqstp->rq_res_stream,
+                                         RPC_AUTH_NULL, NULL, 0) < 0)
+               return SVC_CLOSE;
 
        rqstp->rq_cred.cr_flavor = RPC_AUTH_NULL;
        return SVC_OK;
@@ -789,25 +805,39 @@ struct auth_ops svcauth_null = {
 };
 
 
+/**
+ * svcauth_tls_accept - Decode and validate incoming RPC_AUTH_TLS credential
+ * @rqstp: RPC transaction
+ *
+ * Return values:
+ *   %SVC_OK: Both credential and verifier are valid
+ *   %SVC_DENIED: Credential or verifier is not valid
+ *   %SVC_GARBAGE: Failed to decode credential or verifier
+ *   %SVC_CLOSE: Temporary failure
+ *
+ * rqstp->rq_auth_stat is set as mandated by RFC 5531.
+ */
 static int
 svcauth_tls_accept(struct svc_rqst *rqstp)
 {
+       struct xdr_stream *xdr = &rqstp->rq_arg_stream;
        struct svc_cred *cred = &rqstp->rq_cred;
-       struct kvec *argv = rqstp->rq_arg.head;
        struct kvec *resv = rqstp->rq_res.head;
+       u32 flavor, len;
+       void *body;
 
-       if (argv->iov_len < XDR_UNIT * 3)
+       /* Length of Call's credential body field: */
+       if (xdr_stream_decode_u32(xdr, &len) < 0)
                return SVC_GARBAGE;
-
-       /* Call's cred length */
-       if (svc_getu32(argv) != xdr_zero) {
+       if (len != 0) {
                rqstp->rq_auth_stat = rpc_autherr_badcred;
                return SVC_DENIED;
        }
 
-       /* Call's verifier flavor and its length */
-       if (svc_getu32(argv) != rpc_auth_null ||
-           svc_getu32(argv) != xdr_zero) {
+       /* Call's verf field: */
+       if (xdr_stream_decode_opaque_auth(xdr, &flavor, &body, &len) < 0)
+               return SVC_GARBAGE;
+       if (flavor != RPC_AUTH_NULL || len != 0) {
                rqstp->rq_auth_stat = rpc_autherr_badverf;
                return SVC_DENIED;
        }
@@ -818,12 +848,12 @@ svcauth_tls_accept(struct svc_rqst *rqstp)
                return SVC_DENIED;
        }
 
-       /* Mapping to nobody uid/gid is required */
+       /* Signal that mapping to nobody uid/gid is required */
        cred->cr_uid = INVALID_UID;
        cred->cr_gid = INVALID_GID;
        cred->cr_group_info = groups_alloc(0);
        if (cred->cr_group_info == NULL)
-               return SVC_CLOSE; /* kmalloc failure - client must retry */
+               return SVC_CLOSE;
 
        /* Reply's verifier */
        svc_putnl(resv, RPC_AUTH_NULL);
@@ -835,6 +865,7 @@ svcauth_tls_accept(struct svc_rqst *rqstp)
                svc_putnl(resv, 0);
 
        rqstp->rq_cred.cr_flavor = RPC_AUTH_TLS;
+       svcxdr_init_encode(rqstp);
        return SVC_OK;
 }
 
@@ -848,26 +879,42 @@ struct auth_ops svcauth_tls = {
 };
 
 
+/**
+ * svcauth_unix_accept - Decode and validate incoming RPC_AUTH_SYS credential
+ * @rqstp: RPC transaction
+ *
+ * Return values:
+ *   %SVC_OK: Both credential and verifier are valid
+ *   %SVC_DENIED: Credential or verifier is not valid
+ *   %SVC_GARBAGE: Failed to decode credential or verifier
+ *   %SVC_CLOSE: Temporary failure
+ *
+ * rqstp->rq_auth_stat is set as mandated by RFC 5531.
+ */
 static int
 svcauth_unix_accept(struct svc_rqst *rqstp)
 {
-       struct kvec     *argv = &rqstp->rq_arg.head[0];
-       struct kvec     *resv = &rqstp->rq_res.head[0];
+       struct xdr_stream *xdr = &rqstp->rq_arg_stream;
        struct svc_cred *cred = &rqstp->rq_cred;
        struct user_namespace *userns;
-       u32             slen, i;
-       int             len   = argv->iov_len;
+       u32 flavor, len, i;
+       void *body;
+       __be32 *p;
 
-       if ((len -= 3*4) < 0)
+       /*
+        * This implementation ignores the length of the Call's
+        * credential body field and the timestamp and machinename
+        * fields.
+        */
+       p = xdr_inline_decode(xdr, XDR_UNIT * 3);
+       if (!p)
+               return SVC_GARBAGE;
+       len = be32_to_cpup(p + 2);
+       if (len > RPC_MAX_MACHINENAME)
+               return SVC_GARBAGE;
+       if (!xdr_inline_decode(xdr, len))
                return SVC_GARBAGE;
 
-       svc_getu32(argv);                       /* length */
-       svc_getu32(argv);                       /* time stamp */
-       slen = XDR_QUADLEN(svc_getnl(argv));    /* machname length */
-       if (slen > 64 || (len -= (slen + 3)*4) < 0)
-               goto badcred;
-       argv->iov_base = (void*)((__be32*)argv->iov_base + slen);       /* skip machname */
-       argv->iov_len -= slen*4;
        /*
         * Note: we skip uid_valid()/gid_valid() checks here for
         * backwards compatibility with clients that use -1 id's.
@@ -877,27 +924,41 @@ svcauth_unix_accept(struct svc_rqst *rqstp)
         */
        userns = (rqstp->rq_xprt && rqstp->rq_xprt->xpt_cred) ?
                rqstp->rq_xprt->xpt_cred->user_ns : &init_user_ns;
-       cred->cr_uid = make_kuid(userns, svc_getnl(argv)); /* uid */
-       cred->cr_gid = make_kgid(userns, svc_getnl(argv)); /* gid */
-       slen = svc_getnl(argv);                 /* gids length */
-       if (slen > UNX_NGROUPS || (len -= (slen + 2)*4) < 0)
+       if (xdr_stream_decode_u32(xdr, &i) < 0)
+               return SVC_GARBAGE;
+       cred->cr_uid = make_kuid(userns, i);
+       if (xdr_stream_decode_u32(xdr, &i) < 0)
+               return SVC_GARBAGE;
+       cred->cr_gid = make_kgid(userns, i);
+
+       if (xdr_stream_decode_u32(xdr, &len) < 0)
+               return SVC_GARBAGE;
+       if (len > UNX_NGROUPS)
                goto badcred;
-       cred->cr_group_info = groups_alloc(slen);
+       p = xdr_inline_decode(xdr, XDR_UNIT * len);
+       if (!p)
+               return SVC_GARBAGE;
+       cred->cr_group_info = groups_alloc(len);
        if (cred->cr_group_info == NULL)
                return SVC_CLOSE;
-       for (i = 0; i < slen; i++) {
-               kgid_t kgid = make_kgid(userns, svc_getnl(argv));
+       for (i = 0; i < len; i++) {
+               kgid_t kgid = make_kgid(userns, be32_to_cpup(p++));
                cred->cr_group_info->gid[i] = kgid;
        }
        groups_sort(cred->cr_group_info);
-       if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) {
+
+       /* Call's verf field: */
+       if (xdr_stream_decode_opaque_auth(xdr, &flavor, &body, &len) < 0)
+               return SVC_GARBAGE;
+       if (flavor != RPC_AUTH_NULL || len != 0) {
                rqstp->rq_auth_stat = rpc_autherr_badverf;
                return SVC_DENIED;
        }
 
-       /* Put NULL verifier */
-       svc_putnl(resv, RPC_AUTH_NULL);
-       svc_putnl(resv, 0);
+       svcxdr_init_encode(rqstp);
+       if (xdr_stream_encode_opaque_auth(&rqstp->rq_res_stream,
+                                         RPC_AUTH_NULL, NULL, 0) < 0)
+               return SVC_CLOSE;
 
        rqstp->rq_cred.cr_flavor = RPC_AUTH_UNIX;
        return SVC_OK;