Whamcloud - gitweb
New release 2.15.64
[fs/lustre-release.git] / lustre / ptlrpc / gss / gss_cli_upcall.c
index 04eab5a..7ada030 100644 (file)
@@ -47,6 +47,7 @@
 #include <lustre_net.h>
 #include <lustre_import.h>
 #include <lustre_sec.h>
+#include <uapi/linux/lustre/lgss.h>
 
 #include "gss_err.h"
 #include "gss_internal.h"
@@ -64,12 +65,13 @@ int ctx_init_pack_request(struct obd_import *imp,
                          long token_size,
                          char __user *token)
 {
-       struct lustre_msg       *msg = req->rq_reqbuf;
-       struct gss_sec          *gsec;
-       struct gss_header       *ghdr;
+       struct lustre_msg *msg = req->rq_reqbuf;
+       struct gss_sec *gsec;
+       struct gss_header *ghdr;
        struct ptlrpc_user_desc *pud;
-       __u32                   *p, size, offset = 2;
-       rawobj_t                 obj;
+       __u32 total_size;
+       __u32 *p, size, offset = 2;
+       rawobj_t obj;
 
        LASSERT(msg->lm_bufcount <= 4);
        LASSERT(req->rq_cli_ctx);
@@ -126,16 +128,23 @@ int ctx_init_pack_request(struct obd_import *imp,
                LBUG();
 
        /* 4. now the token */
-       LASSERT(size >= (sizeof(__u32) + token_size));
+       total_size = sizeof(__u32) + token_size;
+       if (size < total_size) {
+               CERROR("%s: security token is too large (%d > %d): rc = %d\n",
+                      imp->imp_obd->obd_name, total_size, size, -E2BIG);
+               return -E2BIG;
+       }
        *p++ = cpu_to_le32(((__u32) token_size));
        if (copy_from_user(p, token, token_size)) {
                CERROR("can't copy token\n");
                return -EFAULT;
        }
-       size -= sizeof(__u32) + cfs_size_round4(token_size);
 
-       req->rq_reqdata_len = lustre_shrink_msg(req->rq_reqbuf, offset,
+       if (size > sizeof(__u32) + round_up(token_size, 4)) {
+               size -= sizeof(__u32) + round_up(token_size, 4);
+               req->rq_reqdata_len = lustre_shrink_msg(req->rq_reqbuf, offset,
                                             msg->lm_buflens[offset] - size, 0);
+       }
        return 0;
 }
 
@@ -163,8 +172,8 @@ int ctx_init_parse_reply(struct lustre_msg *msg, int swabbed,
                 return -EPROTO;
         }
 
-        if (outlen < (4 + 2) * 4 + cfs_size_round4(ghdr->gh_handle.len) +
-                     cfs_size_round4(msg->lm_buflens[2])) {
+       if (outlen < (4 + 2) * 4 + round_up(ghdr->gh_handle.len, 4) +
+                    round_up(msg->lm_buflens[2], 4)) {
                 CERROR("output buffer size %ld too small\n", outlen);
                 return -EFAULT;
         }
@@ -211,25 +220,9 @@ int ctx_init_parse_reply(struct lustre_msg *msg, int swabbed,
        return effective;
 }
 
-/* XXX move to where lgssd could see */
-struct lgssd_ioctl_param {
-        int             version;        /* in   */
-        int             secid;          /* in   */
-       char __user    *uuid;           /* in   */
-        int             lustre_svc;     /* in   */
-        uid_t           uid;            /* in   */
-        gid_t           gid;            /* in   */
-        long            send_token_size;/* in   */
-       char __user    *send_token;     /* in   */
-        long            reply_buf_size; /* in   */
-       char __user    *reply_buf;      /* in   */
-        long            status;         /* out  */
-        long            reply_length;   /* out  */
-};
-
 int gss_do_ctx_init_rpc(char __user *buffer, unsigned long count)
 {
-       struct obd_import *imp, *imp0;
+       struct obd_import *imp = NULL, *imp0;
        struct ptlrpc_request *req;
        struct lgssd_ioctl_param param;
        struct obd_device *obd;
@@ -237,44 +230,55 @@ int gss_do_ctx_init_rpc(char __user *buffer, unsigned long count)
        long lsize;
        int rc;
 
-        if (count != sizeof(param)) {
-                CERROR("ioctl size %lu, expect %lu, please check lgss_keyring "
-                       "version\n", count, (unsigned long) sizeof(param));
-                RETURN(-EINVAL);
-        }
+       if (count != sizeof(param)) {
+               CERROR("ioctl size %lu, expect %lu, please check lgss_keyring version\n",
+                      count, (unsigned long) sizeof(param));
+               RETURN(-EINVAL);
+       }
        if (copy_from_user(&param, buffer, sizeof(param))) {
-                CERROR("failed copy data from lgssd\n");
-                RETURN(-EFAULT);
-        }
+               CERROR("failed copy data from lgssd\n");
+               RETURN(-EFAULT);
+       }
 
-        if (param.version != GSSD_INTERFACE_VERSION) {
-                CERROR("gssd interface version %d (expect %d)\n",
-                        param.version, GSSD_INTERFACE_VERSION);
-                RETURN(-EINVAL);
-        }
+       if (param.version != GSSD_INTERFACE_VERSION) {
+               CERROR("gssd interface version %d (expect %d)\n",
+                      param.version, GSSD_INTERFACE_VERSION);
+               RETURN(-EINVAL);
+       }
 
-        /* take name */
-        if (strncpy_from_user(obdname, param.uuid, sizeof(obdname)) <= 0) {
-                CERROR("Invalid obdname pointer\n");
-                RETURN(-EFAULT);
-        }
+       /* take name */
+       if (strncpy_from_user(obdname, (const char __user *)param.uuid,
+                             sizeof(obdname)) <= 0) {
+               CERROR("Invalid obdname pointer\n");
+               RETURN(-EFAULT);
+       }
 
-        obd = class_name2obd(obdname);
-        if (!obd) {
-                CERROR("no such obd %s\n", obdname);
-                RETURN(-EINVAL);
-        }
+       obd = class_name2obd(obdname);
+       if (!obd) {
+               rc = -EINVAL;
+               CERROR("%s: no such obd: rc = %d\n", obdname, rc);
+               RETURN(rc);
+       }
 
-        if (unlikely(!obd->obd_set_up)) {
-                CERROR("obd %s not setup\n", obdname);
-                RETURN(-EINVAL);
-        }
+       if (unlikely(!obd->obd_set_up)) {
+               rc = -EINVAL;
+               CERROR("%s: obd not setup: rc = %d\n", obdname, rc);
+               RETURN(rc);
+       }
 
        spin_lock(&obd->obd_dev_lock);
        if (obd->obd_stopping) {
-               CERROR("obd %s has stopped\n", obdname);
+               rc = -EINVAL;
+               CERROR("%s: obd has stopped: rc = %d\n", obdname, rc);
                spin_unlock(&obd->obd_dev_lock);
-               RETURN(-EINVAL);
+               RETURN(rc);
+       }
+
+       if (!obd->obd_type || obd->obd_magic != OBD_DEVICE_MAGIC) {
+               rc = -EINVAL;
+               CERROR("%s: obd not valid: rc = %d\n", obdname, rc);
+               spin_unlock(&obd->obd_dev_lock);
+               RETURN(rc);
        }
 
        if (strcmp(obd->obd_type->typ_name, LUSTRE_MDC_NAME) &&
@@ -282,90 +286,109 @@ int gss_do_ctx_init_rpc(char __user *buffer, unsigned long count)
            strcmp(obd->obd_type->typ_name, LUSTRE_MGC_NAME) &&
            strcmp(obd->obd_type->typ_name, LUSTRE_LWP_NAME) &&
            strcmp(obd->obd_type->typ_name, LUSTRE_OSP_NAME)) {
-               CERROR("obd %s is not a client device\n", obdname);
+               rc = -EINVAL;
+               CERROR("%s: obd is not a client device: rc = %d\n",
+                      obdname, rc);
                spin_unlock(&obd->obd_dev_lock);
-               RETURN(-EINVAL);
+               RETURN(rc);
        }
        spin_unlock(&obd->obd_dev_lock);
 
-       with_imp_locked(obd, imp0, rc)
-               imp = class_import_get(imp0);
+       with_imp_locked(obd, imp0, rc) {
+               if (!imp0->imp_obd || !imp0->imp_sec)
+                       rc = -ENODEV;
+               else
+                       imp = class_import_get(imp0);
+       }
        if (rc) {
-               CERROR("obd %s: import has gone\n", obd->obd_name);
-               RETURN(-EINVAL);
+               rc = -EINVAL;
+               CERROR("%s: import has gone: rc = %d\n", obd->obd_name, rc);
+               RETURN(rc);
        }
 
-        if (imp->imp_deactive) {
-                CERROR("import has been deactivated\n");
-                class_import_put(imp);
-                RETURN(-EINVAL);
-        }
+       if (imp->imp_deactive) {
+               rc = -EINVAL;
+               CERROR("%s: import has been deactivated: rc = %d\n",
+                      obd->obd_name, rc);
+               class_import_put(imp);
+               RETURN(rc);
+       }
 
-        req = ptlrpc_request_alloc_pack(imp, &RQF_SEC_CTX, LUSTRE_OBD_VERSION,
-                                        SEC_CTX_INIT);
-        if (req == NULL) {
-                param.status = -ENOMEM;
-                goto out_copy;
-        }
+       req = ptlrpc_request_alloc_pack(imp, &RQF_SEC_CTX, LUSTRE_OBD_VERSION,
+                                       SEC_CTX_INIT);
+       if (IS_ERR(req)) {
+               param.status = PTR_ERR(req);
+               req = NULL;
+               goto out_copy;
+       } else if (!req->rq_cli_ctx || !req->rq_cli_ctx->cc_sec) {
+               param.status = -ENOMEM;
+               goto out_copy;
+       }
 
-        if (req->rq_cli_ctx->cc_sec->ps_id != param.secid) {
-                CWARN("original secid %d, now has changed to %d, "
-                      "cancel this negotiation\n", param.secid,
-                      req->rq_cli_ctx->cc_sec->ps_id);
-                param.status = -EINVAL;
-                goto out_copy;
-        }
+       if (req->rq_cli_ctx->cc_sec->ps_id != param.secid) {
+               rc = -EINVAL;
+               CWARN("%s: original secid %d, now has changed to %d, cancel this negotiation: rc = %d\n",
+                     obd->obd_name, param.secid,
+                     req->rq_cli_ctx->cc_sec->ps_id, rc);
+               param.status = rc;
+               goto out_copy;
+       }
 
-        /* get token */
-        rc = ctx_init_pack_request(imp, req,
-                                   param.lustre_svc,
-                                   param.uid, param.gid,
-                                   param.send_token_size,
-                                   param.send_token);
-        if (rc) {
-                param.status = rc;
-                goto out_copy;
-        }
+       /* get token */
+       rc = ctx_init_pack_request(imp, req,
+                                  param.lustre_svc,
+                                  param.uid, param.gid,
+                                  param.send_token_size,
+                                  (char __user *)param.send_token);
+       if (rc) {
+               param.status = rc;
+               goto out_copy;
+       }
 
-        ptlrpc_request_set_replen(req);
-
-        rc = ptlrpc_queue_wait(req);
-        if (rc) {
-                /* If any _real_ denial be made, we expect server return
-                 * -EACCES reply or return success but indicate gss error
-                 * inside reply messsage. All other errors are treated as
-                 * timeout, caller might try the negotiation repeatedly,
-                 * leave recovery decisions to general ptlrpc layer.
-                 *
-                 * FIXME maybe some other error code shouldn't be treated
-                 * as timeout. */
-                param.status = rc;
-                if (rc != -EACCES)
-                        param.status = -ETIMEDOUT;
-                goto out_copy;
-        }
+       ptlrpc_request_set_replen(req);
+
+       rc = ptlrpc_queue_wait(req);
+       if (rc) {
+               /* If any _real_ denial be made, we expect server return
+                * -EACCES reply or return success but indicate gss error
+                * inside reply messsage. All other errors are treated as
+                * timeout, caller might try the negotiation repeatedly,
+                * leave recovery decisions to general ptlrpc layer.
+                *
+                * FIXME maybe some other error code shouldn't be treated
+                * as timeout.
+                */
+               param.status = rc;
+               if (rc != -EACCES)
+                       param.status = -ETIMEDOUT;
+               CDEBUG(D_SEC,
+                      "%s: ctx init req got %d, returning to userspace status %lld\n",
+                      obd->obd_name, rc, param.status);
+               goto out_copy;
+       }
 
        LASSERT(req->rq_repdata);
        lsize = ctx_init_parse_reply(req->rq_repdata,
                                     req_capsule_rep_need_swab(&req->rq_pill),
-                                    param.reply_buf, param.reply_buf_size);
+                                    (char __user *)param.reply_buf,
+                                    param.reply_buf_size);
        if (lsize < 0) {
                param.status = (int) lsize;
                goto out_copy;
        }
 
-        param.status = 0;
-        param.reply_length = lsize;
+       param.status = 0;
+       param.reply_length = lsize;
 
 out_copy:
        if (copy_to_user(buffer, &param, sizeof(param)))
-                rc = -EFAULT;
-        else
-                rc = 0;
+               rc = -EFAULT;
+       else
+               rc = 0;
 
-        class_import_put(imp);
-        ptlrpc_req_finished(req);
-        RETURN(rc);
+       class_import_put(imp);
+       ptlrpc_req_put(req);
+       RETURN(rc);
 }
 
 int gss_do_ctx_fini_rpc(struct gss_cli_ctx *gctx)
@@ -388,11 +411,11 @@ int gss_do_ctx_fini_rpc(struct gss_cli_ctx *gctx)
 
        might_sleep();
 
-       CWARN("%s ctx %p idx %#llx (%u->%s)\n",
-             sec_is_reverse(ctx->cc_sec) ?
-             "server finishing reverse" : "client finishing forward",
-             ctx, gss_handle_to_u64(&gctx->gc_handle),
-             ctx->cc_vcred.vc_uid, sec2target_str(ctx->cc_sec));
+       CDEBUG(D_SEC, "%s ctx %p idx %#llx (%u->%s)\n",
+              sec_is_reverse(ctx->cc_sec) ?
+              "server finishing reverse" : "client finishing forward",
+              ctx, gss_handle_to_u64(&gctx->gc_handle),
+              ctx->cc_vcred.vc_uid, sec2target_str(ctx->cc_sec));
 
         gctx->gc_proc = PTLRPC_GSS_PROC_DESTROY;
 
@@ -427,7 +450,7 @@ int gss_do_ctx_fini_rpc(struct gss_cli_ctx *gctx)
                       ctx->cc_vcred.vc_uid, sec2target_str(ctx->cc_sec), rc);
 
 out_ref:
-        ptlrpc_req_finished(req);
+       ptlrpc_req_put(req);
 out:
         RETURN(rc);
 }