📄 auth_gss.c
字号:
struct rpc_cred *cred = task->tk_msg.rpc_cred; struct gss_auth *gss_auth = container_of(task->tk_client->cl_auth, struct gss_auth, rpc_auth); struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); struct gss_upcall_msg *gss_msg; int err = 0; dprintk("RPC: %4u gss_refresh_upcall for uid %u\n", task->tk_pid, cred->cr_uid); gss_msg = gss_setup_upcall(task->tk_client, gss_auth, cred); if (IS_ERR(gss_msg)) { err = PTR_ERR(gss_msg); goto out; } spin_lock(&gss_auth->lock); if (gss_cred->gc_upcall != NULL) rpc_sleep_on(&gss_cred->gc_upcall->rpc_waitqueue, task, NULL, NULL); else if (gss_msg->ctx == NULL && gss_msg->msg.errno >= 0) { task->tk_timeout = 0; gss_cred->gc_upcall = gss_msg; /* gss_upcall_callback will release the reference to gss_upcall_msg */ atomic_inc(&gss_msg->count); rpc_sleep_on(&gss_msg->rpc_waitqueue, task, gss_upcall_callback, NULL); } else err = gss_msg->msg.errno; spin_unlock(&gss_auth->lock); gss_release_msg(gss_msg);out: dprintk("RPC: %4u gss_refresh_upcall for uid %u result %d\n", task->tk_pid, cred->cr_uid, err); return err;}static inline intgss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred){ struct rpc_cred *cred = &gss_cred->gc_base; struct gss_upcall_msg *gss_msg; DEFINE_WAIT(wait); int err = 0; dprintk("RPC: gss_upcall for uid %u\n", cred->cr_uid); gss_msg = gss_setup_upcall(gss_auth->client, gss_auth, cred); if (IS_ERR(gss_msg)) { err = PTR_ERR(gss_msg); goto out; } for (;;) { prepare_to_wait(&gss_msg->waitqueue, &wait, TASK_INTERRUPTIBLE); spin_lock(&gss_auth->lock); if (gss_msg->ctx != NULL || gss_msg->msg.errno < 0) { spin_unlock(&gss_auth->lock); break; } spin_unlock(&gss_auth->lock); if (signalled()) { err = -ERESTARTSYS; goto out_intr; } schedule(); } if (gss_msg->ctx) gss_cred_set_ctx(cred, gss_get_ctx(gss_msg->ctx)); else err = gss_msg->msg.errno;out_intr: finish_wait(&gss_msg->waitqueue, &wait); gss_release_msg(gss_msg);out: dprintk("RPC: gss_create_upcall for uid %u result %d\n", cred->cr_uid, err); return err;}static ssize_tgss_pipe_upcall(struct file *filp, struct rpc_pipe_msg *msg, char __user *dst, size_t buflen){ char *data = (char *)msg->data + msg->copied; ssize_t mlen = msg->len; ssize_t left; if (mlen > buflen) mlen = buflen; left = copy_to_user(dst, data, mlen); if (left < 0) { msg->errno = left; return left; } mlen -= left; msg->copied += mlen; msg->errno = 0; return mlen;}#define MSG_BUF_MAXSIZE 1024static ssize_tgss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen){ const void *p, *end; void *buf; struct rpc_clnt *clnt; struct gss_auth *gss_auth; struct rpc_cred *cred; struct gss_upcall_msg *gss_msg; struct gss_cl_ctx *ctx; uid_t uid; int err = -EFBIG; if (mlen > MSG_BUF_MAXSIZE) goto out; err = -ENOMEM; buf = kmalloc(mlen, GFP_KERNEL); if (!buf) goto out; clnt = RPC_I(filp->f_dentry->d_inode)->private; err = -EFAULT; if (copy_from_user(buf, src, mlen)) goto err; end = (const void *)((char *)buf + mlen); p = simple_get_bytes(buf, end, &uid, sizeof(uid)); if (IS_ERR(p)) { err = PTR_ERR(p); goto err; } err = -ENOMEM; ctx = gss_alloc_context(); if (ctx == NULL) goto err; err = 0; gss_auth = container_of(clnt->cl_auth, struct gss_auth, rpc_auth); p = gss_fill_context(p, end, ctx, gss_auth->mech); if (IS_ERR(p)) { err = PTR_ERR(p); if (err != -EACCES) goto err_put_ctx; } spin_lock(&gss_auth->lock); gss_msg = __gss_find_upcall(gss_auth, uid); if (gss_msg) { if (err == 0 && gss_msg->ctx == NULL) gss_msg->ctx = gss_get_ctx(ctx); gss_msg->msg.errno = err; __gss_unhash_msg(gss_msg); spin_unlock(&gss_auth->lock); gss_release_msg(gss_msg); } else { struct auth_cred acred = { .uid = uid }; spin_unlock(&gss_auth->lock); cred = rpcauth_lookup_credcache(clnt->cl_auth, &acred, 0); if (IS_ERR(cred)) { err = PTR_ERR(cred); goto err_put_ctx; } gss_cred_set_ctx(cred, gss_get_ctx(ctx)); } gss_put_ctx(ctx); kfree(buf); dprintk("RPC: gss_pipe_downcall returning length %Zu\n", mlen); return mlen;err_put_ctx: gss_put_ctx(ctx);err: kfree(buf);out: dprintk("RPC: gss_pipe_downcall returning %d\n", err); return err;}static voidgss_pipe_release(struct inode *inode){ struct rpc_inode *rpci = RPC_I(inode); struct rpc_clnt *clnt; struct rpc_auth *auth; struct gss_auth *gss_auth; clnt = rpci->private; auth = clnt->cl_auth; gss_auth = container_of(auth, struct gss_auth, rpc_auth); spin_lock(&gss_auth->lock); while (!list_empty(&gss_auth->upcalls)) { struct gss_upcall_msg *gss_msg; gss_msg = list_entry(gss_auth->upcalls.next, struct gss_upcall_msg, list); gss_msg->msg.errno = -EPIPE; atomic_inc(&gss_msg->count); __gss_unhash_msg(gss_msg); spin_unlock(&gss_auth->lock); gss_release_msg(gss_msg); spin_lock(&gss_auth->lock); } spin_unlock(&gss_auth->lock);}static voidgss_pipe_destroy_msg(struct rpc_pipe_msg *msg){ struct gss_upcall_msg *gss_msg = container_of(msg, struct gss_upcall_msg, msg); static unsigned long ratelimit; if (msg->errno < 0) { dprintk("RPC: gss_pipe_destroy_msg releasing msg %p\n", gss_msg); atomic_inc(&gss_msg->count); gss_unhash_msg(gss_msg); if (msg->errno == -ETIMEDOUT) { unsigned long now = jiffies; if (time_after(now, ratelimit)) { printk(KERN_WARNING "RPC: AUTH_GSS upcall timed out.\n" "Please check user daemon is running!\n"); ratelimit = now + 15*HZ; } } gss_release_msg(gss_msg); }}/* * NOTE: we have the opportunity to use different * parameters based on the input flavor (which must be a pseudoflavor) */static struct rpc_auth *gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor){ struct gss_auth *gss_auth; struct rpc_auth * auth; int err = -ENOMEM; /* XXX? */ dprintk("RPC: creating GSS authenticator for client %p\n",clnt); if (!try_module_get(THIS_MODULE)) return ERR_PTR(err); if (!(gss_auth = kmalloc(sizeof(*gss_auth), GFP_KERNEL))) goto out_dec; gss_auth->client = clnt; err = -EINVAL; gss_auth->mech = gss_mech_get_by_pseudoflavor(flavor); if (!gss_auth->mech) { printk(KERN_WARNING "%s: Pseudoflavor %d not found!", __FUNCTION__, flavor); goto err_free; } gss_auth->service = gss_pseudoflavor_to_service(gss_auth->mech, flavor); if (gss_auth->service == 0) goto err_put_mech; INIT_LIST_HEAD(&gss_auth->upcalls); spin_lock_init(&gss_auth->lock); auth = &gss_auth->rpc_auth; auth->au_cslack = GSS_CRED_SLACK >> 2; auth->au_rslack = GSS_VERF_SLACK >> 2; auth->au_ops = &authgss_ops; auth->au_flavor = flavor; atomic_set(&auth->au_count, 1); err = rpcauth_init_credcache(auth, GSS_CRED_EXPIRE); if (err) goto err_put_mech; snprintf(gss_auth->path, sizeof(gss_auth->path), "%s/%s", clnt->cl_pathname, gss_auth->mech->gm_name); gss_auth->dentry = rpc_mkpipe(gss_auth->path, clnt, &gss_upcall_ops, RPC_PIPE_WAIT_FOR_OPEN); if (IS_ERR(gss_auth->dentry)) { err = PTR_ERR(gss_auth->dentry); goto err_put_mech; } return auth;err_put_mech: gss_mech_put(gss_auth->mech);err_free: kfree(gss_auth);out_dec: module_put(THIS_MODULE); return ERR_PTR(err);}static voidgss_destroy(struct rpc_auth *auth){ struct gss_auth *gss_auth; dprintk("RPC: destroying GSS authenticator %p flavor %d\n", auth, auth->au_flavor); gss_auth = container_of(auth, struct gss_auth, rpc_auth); rpc_unlink(gss_auth->path); gss_mech_put(gss_auth->mech); rpcauth_free_credcache(auth); kfree(gss_auth); module_put(THIS_MODULE);}/* gss_destroy_cred (and gss_destroy_ctx) are used to clean up after failure * to create a new cred or context, so they check that things have been * allocated before freeing them. */static voidgss_destroy_ctx(struct gss_cl_ctx *ctx){ dprintk("RPC: gss_destroy_ctx\n"); if (ctx->gc_gss_ctx) gss_delete_sec_context(&ctx->gc_gss_ctx); kfree(ctx->gc_wire_ctx.data); kfree(ctx);}static voidgss_destroy_cred(struct rpc_cred *rc){ struct gss_cred *cred = container_of(rc, struct gss_cred, gc_base); dprintk("RPC: gss_destroy_cred \n"); if (cred->gc_ctx) gss_put_ctx(cred->gc_ctx); kfree(cred);}/* * Lookup RPCSEC_GSS cred for the current process */static struct rpc_cred *gss_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int taskflags){ return rpcauth_lookup_credcache(auth, acred, taskflags);}static struct rpc_cred *gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int taskflags){ struct gss_auth *gss_auth = container_of(auth, struct gss_auth, rpc_auth); struct gss_cred *cred = NULL; int err = -ENOMEM; dprintk("RPC: gss_create_cred for uid %d, flavor %d\n", acred->uid, auth->au_flavor); if (!(cred = kmalloc(sizeof(*cred), GFP_KERNEL))) goto out_err; memset(cred, 0, sizeof(*cred)); atomic_set(&cred->gc_count, 1); cred->gc_uid = acred->uid; /* * Note: in order to force a call to call_refresh(), we deliberately * fail to flag the credential as RPCAUTH_CRED_UPTODATE. */ cred->gc_flags = 0; cred->gc_base.cr_ops = &gss_credops; cred->gc_service = gss_auth->service; do { err = gss_create_upcall(gss_auth, cred); } while (err == -EAGAIN); if (err < 0) goto out_err; return &cred->gc_base;out_err: dprintk("RPC: gss_create_cred failed with error %d\n", err); if (cred) gss_destroy_cred(&cred->gc_base); return ERR_PTR(err);}static intgss_match(struct auth_cred *acred, struct rpc_cred *rc, int taskflags){ struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base); /* Don't match with creds that have expired. */ if (gss_cred->gc_ctx && time_after(jiffies, gss_cred->gc_ctx->gc_expiry)) return 0; return (rc->cr_uid == acred->uid);}/** Marshal credentials.* Maybe we should keep a cached credential for performance reasons.*/static u32 *gss_marshal(struct rpc_task *task, u32 *p){ struct rpc_cred *cred = task->tk_msg.rpc_cred; struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred); u32 *cred_len; struct rpc_rqst *req = task->tk_rqstp; u32 maj_stat = 0; struct xdr_netobj mic; struct kvec iov; struct xdr_buf verf_buf; dprintk("RPC: %4u gss_marshal\n", task->tk_pid); *p++ = htonl(RPC_AUTH_GSS); cred_len = p++; spin_lock(&ctx->gc_seq_lock); req->rq_seqno = ctx->gc_seq++; spin_unlock(&ctx->gc_seq_lock); *p++ = htonl((u32) RPC_GSS_VERSION); *p++ = htonl((u32) ctx->gc_proc); *p++ = htonl((u32) req->rq_seqno); *p++ = htonl((u32) gss_cred->gc_service); p = xdr_encode_netobj(p, &ctx->gc_wire_ctx); *cred_len = htonl((p - (cred_len + 1)) << 2); /* We compute the checksum for the verifier over the xdr-encoded bytes * starting with the xid and ending at the end of the credential: */ iov.iov_base = xprt_skip_transport_header(task->tk_xprt, req->rq_snd_buf.head[0].iov_base); iov.iov_len = (u8 *)p - (u8 *)iov.iov_base; xdr_buf_from_iov(&iov, &verf_buf); /* set verifier flavor*/ *p++ = htonl(RPC_AUTH_GSS); mic.data = (u8 *)(p + 1); maj_stat = gss_get_mic(ctx->gc_gss_ctx, &verf_buf, &mic); if (maj_stat == GSS_S_CONTEXT_EXPIRED) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -