#include <linux/crypto.h>
+
+static inline int msg_last_segidx(struct lustre_msg *msg)
+{
+ LASSERT(msg->lm_bufcount > 0);
+ return msg->lm_bufcount - 1;
+}
+static inline int msg_last_seglen(struct lustre_msg *msg)
+{
+ return msg->lm_buflens[msg_last_segidx(msg)];
+}
+
/********************************************
* wire data swabber *
********************************************/
static
int gss_sign_msg(struct lustre_msg *msg,
struct gss_ctx *mechctx,
- __u32 proc, __u32 seq,
+ __u32 proc, __u32 seq, __u32 svc,
rawobj_t *handle)
{
struct gss_header *ghdr;
rawobj_t text[3], mic;
- int textcnt, mic_idx = msg->lm_bufcount - 1;
+ int textcnt, max_textcnt, mic_idx;
__u32 major;
- LASSERT(msg->lm_bufcount >= 3);
+ LASSERT(msg->lm_bufcount >= 2);
/* gss hdr */
LASSERT(msg->lm_buflens[0] >=
ghdr->gh_flags = 0;
ghdr->gh_proc = proc;
ghdr->gh_seq = seq;
- ghdr->gh_svc = PTLRPC_GSS_SVC_INTEGRITY;
+ ghdr->gh_svc = svc;
if (!handle) {
/* fill in a fake one */
ghdr->gh_handle.len = 0;
memcpy(ghdr->gh_handle.data, handle->data, handle->len);
}
+ /* no actual signature for null mode */
+ if (svc == SPTLRPC_SVC_NULL)
+ return lustre_msg_size_v2(msg->lm_bufcount, msg->lm_buflens);
+
/* MIC */
- for (textcnt = 0; textcnt < mic_idx; textcnt++) {
+ mic_idx = msg_last_segidx(msg);
+ max_textcnt = (svc == SPTLRPC_SVC_AUTH) ? 1 : mic_idx;
+
+ for (textcnt = 0; textcnt < max_textcnt; textcnt++) {
text[textcnt].len = msg->lm_buflens[textcnt];
text[textcnt].data = lustre_msg_buf(msg, textcnt, 0);
}
*/
static
__u32 gss_verify_msg(struct lustre_msg *msg,
- struct gss_ctx *mechctx)
+ struct gss_ctx *mechctx,
+ __u32 svc)
{
- rawobj_t text[3];
- rawobj_t mic;
- int textcnt, mic_idx = msg->lm_bufcount - 1;
- __u32 major;
+ rawobj_t text[3], mic;
+ int textcnt, max_textcnt;
+ int mic_idx;
+ __u32 major;
+
+ LASSERT(msg->lm_bufcount >= 2);
+
+ if (svc == SPTLRPC_SVC_NULL)
+ return GSS_S_COMPLETE;
- for (textcnt = 0; textcnt < mic_idx; textcnt++) {
+ mic_idx = msg_last_segidx(msg);
+ max_textcnt = (svc == SPTLRPC_SVC_AUTH) ? 1 : mic_idx;
+
+ for (textcnt = 0; textcnt < max_textcnt; textcnt++) {
text[textcnt].len = msg->lm_buflens[textcnt];
text[textcnt].data = lustre_msg_buf(msg, textcnt, 0);
}
if (!test_and_set_bit(PTLRPC_CTX_DEAD_BIT, &ctx->cc_flags)) {
cfs_time_t now;
- clear_bit(PTLRPC_CTX_UPTODATE_BIT, &ctx->cc_flags);
+ if (!ctx->cc_early_expire)
+ clear_bit(PTLRPC_CTX_UPTODATE_BIT, &ctx->cc_flags);
now = cfs_time_current_sec();
if (ctx->cc_expire && cfs_time_aftereq(now, ctx->cc_expire))
void gss_cli_ctx_uptodate(struct gss_cli_ctx *gctx)
{
- struct ptlrpc_cli_ctx *ctx = &gctx->gc_base;
- unsigned long ctx_expiry;
+ struct ptlrpc_cli_ctx *ctx = &gctx->gc_base;
+ unsigned long ctx_expiry;
if (lgss_inquire_context(gctx->gc_mechctx, &ctx_expiry)) {
CERROR("ctx %p(%u): unable to inquire, expire it now\n",
*/
set_bit(PTLRPC_CTX_UPTODATE_BIT, &ctx->cc_flags);
- CWARN("%s ctx %p(%u->%s), will expire at %lu(%lds lifetime)\n",
- (ctx->cc_sec->ps_flags & PTLRPC_SEC_FL_REVERSE ?
- "server installed reverse" : "client refreshed"),
- ctx, ctx->cc_vcred.vc_uid, sec2target_str(ctx->cc_sec),
- ctx->cc_expire, (long) (ctx->cc_expire - get_seconds()));
+ if (sec_is_reverse(ctx->cc_sec))
+ CDEBUG(D_SEC, "server installed reverse ctx %p, "
+ "will expire at %lu(%lds lifetime)\n",
+ ctx, ctx->cc_expire,
+ ctx->cc_expire - cfs_time_current_sec());
+ else
+ CWARN("client refreshed ctx %p(%u->%s), will expire at "
+ "%lu(%lds lifetime)\n", ctx, ctx->cc_vcred.vc_uid,
+ sec2target_str(ctx->cc_sec), ctx->cc_expire,
+ ctx->cc_expire - cfs_time_current_sec());
+
+ /*
+ * install reverse svc ctx, but only for forward connection
+ * and root context
+ */
+ if (!sec_is_reverse(ctx->cc_sec) && ctx->cc_vcred.vc_uid == 0) {
+ gss_sec_install_rctx(ctx->cc_sec->ps_import,
+ ctx->cc_sec, ctx);
+ }
}
static
return (ctx->cc_vcred.vc_uid == vcred->vc_uid);
}
-static
void gss_cli_ctx_flags2str(unsigned long flags, char *buf, int bufsize)
{
buf[0] = '\0';
+ if (flags & PTLRPC_CTX_NEW)
+ strncat(buf, "new,", bufsize);
if (flags & PTLRPC_CTX_UPTODATE)
strncat(buf, "uptodate,", bufsize);
if (flags & PTLRPC_CTX_DEAD)
buf[strlen(buf) - 1] = '\0';
}
-int gss_cli_ctx_display(struct ptlrpc_cli_ctx *ctx, char *buf, int bufsize)
-{
- struct gss_cli_ctx *gctx;
- char flags_str[40];
- int written;
-
- gctx = container_of(ctx, struct gss_cli_ctx, gc_base);
-
- gss_cli_ctx_flags2str(ctx->cc_flags, flags_str, sizeof(flags_str));
-
- written = snprintf(buf, bufsize,
- "UID %d:\n"
- " flags: %s\n"
- " seqwin: %d\n"
- " sequence: %d\n",
- ctx->cc_vcred.vc_uid,
- flags_str,
- gctx->gc_win,
- atomic_read(&gctx->gc_seq));
-
- if (gctx->gc_mechctx) {
- written += lgss_display(gctx->gc_mechctx,
- buf + written, bufsize - written);
- }
-
- return written;
-}
-
int gss_cli_ctx_sign(struct ptlrpc_cli_ctx *ctx,
struct ptlrpc_request *req)
{
struct gss_cli_ctx *gctx;
- __u32 seq;
+ __u32 seq, svc;
int rc;
ENTRY;
LASSERT(req->rq_reqbuf);
- LASSERT(req->rq_reqbuf->lm_bufcount >= 3);
+ LASSERT(req->rq_reqbuf->lm_bufcount >= 2);
LASSERT(req->rq_cli_ctx == ctx);
/* nothing to do for context negotiation RPCs */
RETURN(0);
gctx = container_of(ctx, struct gss_cli_ctx, gc_base);
+ svc = SEC_FLAVOR_SVC(req->rq_sec_flavor);
redo:
seq = atomic_inc_return(&gctx->gc_seq);
rc = gss_sign_msg(req->rq_reqbuf, gctx->gc_mechctx,
- gctx->gc_proc, seq, &gctx->gc_handle);
+ gctx->gc_proc, seq, svc,
+ &gctx->gc_handle);
if (rc < 0)
RETURN(rc);
* of them we should repack this rpc, because sent it too late might
* lead to the sequence number fall behind the window on server and
* be dropped. also applies to gss_cli_ctx_seal().
+ *
+ * Note: null mode dosen't check sequence number.
*/
- if (atomic_read(&gctx->gc_seq) - seq > GSS_SEQ_REPACK_THRESHOLD) {
+ if (svc != SPTLRPC_SVC_NULL &&
+ atomic_read(&gctx->gc_seq) - seq > GSS_SEQ_REPACK_THRESHOLD) {
int behind = atomic_read(&gctx->gc_seq) - seq;
gss_stat_oos_record_cli(behind);
CWARN("server respond error (%08x/%08x) for ctx fini\n",
errhdr->gh_major, errhdr->gh_minor);
rc = -EINVAL;
- } else if (ctx->cc_sec->ps_flags & PTLRPC_SEC_FL_REVERSE) {
+ } else if (sec_is_reverse(ctx->cc_sec)) {
CWARN("reverse server respond error (%08x/%08x)\n",
errhdr->gh_major, errhdr->gh_minor);
rc = -EINVAL;
RETURN(0);
}
- if (msg->lm_bufcount < 3 || msg->lm_bufcount > 4) {
+ if (msg->lm_bufcount < 2 || msg->lm_bufcount > 4) {
CERROR("unexpected bufcount %u\n", msg->lm_bufcount);
RETURN(-EPROTO);
}
RETURN(-EPROTO);
}
- if (ghdr->gh_svc != PTLRPC_GSS_SVC_INTEGRITY) {
- CERROR("unexpected svc %d\n", ghdr->gh_svc);
+ if (ghdr->gh_svc != reqhdr->gh_svc) {
+ CERROR("svc %u mismatch, expect %u\n",
+ ghdr->gh_svc, reqhdr->gh_svc);
RETURN(-EPROTO);
}
if (lustre_msg_swabbed(msg))
gss_header_swabber(ghdr);
- major = gss_verify_msg(msg, gctx->gc_mechctx);
+ major = gss_verify_msg(msg, gctx->gc_mechctx, reqhdr->gh_svc);
if (major != GSS_S_COMPLETE)
RETURN(-EPERM);
ghdr->gh_flags = 0;
ghdr->gh_proc = gctx->gc_proc;
ghdr->gh_seq = atomic_inc_return(&gctx->gc_seq);
- ghdr->gh_svc = PTLRPC_GSS_SVC_PRIVACY;
+ ghdr->gh_svc = SPTLRPC_SVC_PRIV;
ghdr->gh_handle.len = gctx->gc_handle.len;
memcpy(ghdr->gh_handle.data, gctx->gc_handle.data, gctx->gc_handle.len);
sec->ps_import = class_import_get(imp);
sec->ps_lock = SPIN_LOCK_UNLOCKED;
atomic_set(&sec->ps_busy, 0);
- INIT_LIST_HEAD(&sec->ps_gc_list);
+ CFS_INIT_LIST_HEAD(&sec->ps_gc_list);
if (!ctx) {
sec->ps_gc_interval = GSS_GC_INTERVAL;
sec->ps_gc_next = cfs_time_current_sec() + sec->ps_gc_interval;
} else {
- LASSERT(sec->ps_flags & PTLRPC_SEC_FL_REVERSE);
+ LASSERT(sec_is_reverse(sec));
/* never do gc on reverse sec */
sec->ps_gc_interval = 0;
flags & PTLRPC_SEC_FL_BULK)
sptlrpc_enc_pool_add_user();
- CWARN("create %s%s@%p\n", (ctx ? "reverse " : ""),
- policy->sp_name, gsec);
+ CDEBUG(D_SEC, "create %s%s@%p\n", (ctx ? "reverse " : ""),
+ policy->sp_name, gsec);
return 0;
}
gctx->gc_win = 0;
atomic_set(&gctx->gc_seq, 0);
- INIT_HLIST_NODE(&ctx->cc_hash);
+ CFS_INIT_HLIST_NODE(&ctx->cc_cache);
atomic_set(&ctx->cc_refcount, 0);
ctx->cc_sec = sec;
ctx->cc_ops = ctxops;
ctx->cc_flags = PTLRPC_CTX_NEW;
ctx->cc_vcred = *vcred;
spin_lock_init(&ctx->cc_lock);
- INIT_LIST_HEAD(&ctx->cc_req_list);
+ CFS_INIT_LIST_HEAD(&ctx->cc_req_list);
+ CFS_INIT_LIST_HEAD(&ctx->cc_gc_chain);
/* take a ref on belonging sec */
atomic_inc(&sec->ps_busy);
- CWARN("%s@%p: create ctx %p(%u->%s)\n",
- sec->ps_policy->sp_name, ctx->cc_sec,
- ctx, ctx->cc_vcred.vc_uid, sec2target_str(ctx->cc_sec));
+ CDEBUG(D_SEC, "%s@%p: create ctx %p(%u->%s)\n",
+ sec->ps_policy->sp_name, ctx->cc_sec,
+ ctx, ctx->cc_vcred.vc_uid, sec2target_str(ctx->cc_sec));
return 0;
}
gss_cli_ctx_finalize(gctx);
}
- CWARN("%s@%p: destroy ctx %p(%u->%s)\n",
- sec->ps_policy->sp_name, ctx->cc_sec,
- ctx, ctx->cc_vcred.vc_uid, sec2target_str(ctx->cc_sec));
+ if (sec_is_reverse(sec))
+ CDEBUG(D_SEC, "reverse sec %p: destroy ctx %p\n",
+ ctx->cc_sec, ctx);
+ else
+ CWARN("%s@%p: destroy ctx %p(%u->%s)\n",
+ sec->ps_policy->sp_name, ctx->cc_sec,
+ ctx, ctx->cc_vcred.vc_uid, sec2target_str(ctx->cc_sec));
if (atomic_dec_and_test(&sec->ps_busy)) {
LASSERT(atomic_read(&sec->ps_refcount) == 0);
}
static
-int gss_alloc_reqbuf_auth(struct ptlrpc_sec *sec,
+int gss_alloc_reqbuf_intg(struct ptlrpc_sec *sec,
struct ptlrpc_request *req,
- int msgsize)
+ int svc, int msgsize)
{
struct sec_flavor_config *conf;
- int bufsize, txtsize;
- int buflens[5], bufcnt = 2;
+ int bufsize, txtsize;
+ int buflens[5], bufcnt = 2;
ENTRY;
/*
+ * on-wire data layout:
* - gss header
* - lustre message
- * - user descriptor
- * - bulk sec descriptor
- * - signature
+ * - user descriptor (optional)
+ * - bulk sec descriptor (optional)
+ * - signature (optional)
+ * - svc == NULL: NULL
+ * - svc == AUTH: signature of gss header
+ * - svc == INTG: signature of all above
+ *
+ * if this is context negotiation, reserver fixed space
+ * at the last (signature) segment regardless of svc mode.
*/
+
buflens[0] = PTLRPC_GSS_HEADER_SIZE;
+ txtsize = buflens[0];
+
buflens[1] = msgsize;
- txtsize = buflens[0] + buflens[1];
+ if (svc == SPTLRPC_SVC_INTG)
+ txtsize += buflens[1];
if (SEC_FLAVOR_HAS_USER(req->rq_sec_flavor)) {
buflens[bufcnt] = sptlrpc_current_user_desc_size();
- txtsize += buflens[bufcnt];
+ if (svc == SPTLRPC_SVC_INTG)
+ txtsize += buflens[bufcnt];
bufcnt++;
}
conf = &req->rq_import->imp_obd->u.cli.cl_sec_conf;
buflens[bufcnt] = bulk_sec_desc_size(conf->sfc_bulk_csum, 1,
req->rq_bulk_read);
- txtsize += buflens[bufcnt];
+ if (svc == SPTLRPC_SVC_INTG)
+ txtsize += buflens[bufcnt];
bufcnt++;
}
- buflens[bufcnt++] = req->rq_ctx_init ? GSS_CTX_INIT_MAX_LEN :
- gss_cli_payload(req->rq_cli_ctx, txtsize, 0);
+ if (req->rq_ctx_init)
+ buflens[bufcnt++] = GSS_CTX_INIT_MAX_LEN;
+ else if (svc != SPTLRPC_SVC_NULL)
+ buflens[bufcnt++] = gss_cli_payload(req->rq_cli_ctx, txtsize,0);
bufsize = lustre_msg_size_v2(bufcnt, buflens);
int msgsize)
{
struct sec_flavor_config *conf;
- int ibuflens[3], ibufcnt;
- int buflens[3];
- int clearsize, wiresize;
+ int ibuflens[3], ibufcnt;
+ int buflens[3];
+ int clearsize, wiresize;
ENTRY;
LASSERT(req->rq_clrbuf == NULL);
/* Inner (clear) buffers
* - lustre message
- * - user descriptor
- * - bulk checksum
+ * - user descriptor (optional)
+ * - bulk checksum (optional)
*/
+
ibufcnt = 1;
ibuflens[0] = msgsize;
* - signature of gss header
* - cipher text
*/
+
buflens[0] = PTLRPC_GSS_HEADER_SIZE;
buflens[1] = gss_cli_payload(req->rq_cli_ctx, buflens[0], 0);
buflens[2] = gss_cli_payload(req->rq_cli_ctx, clearsize, 1);
struct ptlrpc_request *req,
int msgsize)
{
+ int svc = SEC_FLAVOR_SVC(req->rq_sec_flavor);
+
LASSERT(!SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor) ||
(req->rq_bulk_read || req->rq_bulk_write));
- switch (SEC_FLAVOR_SVC(req->rq_sec_flavor)) {
- case SPTLRPC_SVC_NONE:
+ switch (svc) {
+ case SPTLRPC_SVC_NULL:
case SPTLRPC_SVC_AUTH:
- return gss_alloc_reqbuf_auth(sec, req, msgsize);
+ case SPTLRPC_SVC_INTG:
+ return gss_alloc_reqbuf_intg(sec, req, svc, msgsize);
case SPTLRPC_SVC_PRIV:
return gss_alloc_reqbuf_priv(sec, req, msgsize);
default:
- LBUG();
+ LASSERTF(0, "bad flavor %x\n", req->rq_sec_flavor);
+ return 0;
}
- return 0;
}
void gss_free_reqbuf(struct ptlrpc_sec *sec,
struct ptlrpc_request *req)
{
- int privacy;
+ int privacy;
ENTRY;
LASSERT(!req->rq_pool || req->rq_reqbuf);
EXIT;
}
-int gss_alloc_repbuf(struct ptlrpc_sec *sec,
- struct ptlrpc_request *req,
- int msgsize)
+static int do_alloc_repbuf(struct ptlrpc_request *req, int bufsize)
+{
+ bufsize = size_roundup_power2(bufsize);
+
+ OBD_ALLOC(req->rq_repbuf, bufsize);
+ if (!req->rq_repbuf)
+ return -ENOMEM;
+
+ req->rq_repbuf_len = bufsize;
+ return 0;
+}
+
+static
+int gss_alloc_repbuf_intg(struct ptlrpc_sec *sec,
+ struct ptlrpc_request *req,
+ int svc, int msgsize)
{
struct sec_flavor_config *conf;
- int privacy = (SEC_FLAVOR_SVC(req->rq_sec_flavor) == SPTLRPC_SVC_PRIV);
- int bufsize, txtsize;
- int buflens[4], bufcnt;
- ENTRY;
+ int txtsize;
+ int buflens[4], bufcnt = 2;
- LASSERT(!SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor) ||
- (req->rq_bulk_read || req->rq_bulk_write));
+ /*
+ * on-wire data layout:
+ * - gss header
+ * - lustre message
+ * - bulk sec descriptor (optional)
+ * - signature (optional)
+ * - svc == NULL: NULL
+ * - svc == AUTH: signature of gss header
+ * - svc == INTG: signature of all above
+ *
+ * if this is context negotiation, reserver fixed space
+ * at the last (signature) segment regardless of svc mode.
+ */
- if (privacy) {
- bufcnt = 1;
- buflens[0] = msgsize;
- if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) {
- conf = &req->rq_import->imp_obd->u.cli.cl_sec_conf;
- buflens[bufcnt++] = bulk_sec_desc_size(
- conf->sfc_bulk_csum, 0,
- req->rq_bulk_read);
- }
- txtsize = lustre_msg_size_v2(bufcnt, buflens);
- txtsize += GSS_MAX_CIPHER_BLOCK;
+ buflens[0] = PTLRPC_GSS_HEADER_SIZE;
+ txtsize = buflens[0];
- bufcnt = 3;
- buflens[0] = PTLRPC_GSS_HEADER_SIZE;
- buflens[1] = gss_cli_payload(req->rq_cli_ctx, buflens[0], 0);
- buflens[2] = gss_cli_payload(req->rq_cli_ctx, txtsize, 1);
- } else {
- bufcnt = 2;
- buflens[0] = PTLRPC_GSS_HEADER_SIZE;
- buflens[1] = msgsize;
- txtsize = buflens[0] + buflens[1];
+ buflens[1] = msgsize;
+ if (svc == SPTLRPC_SVC_INTG)
+ txtsize += buflens[1];
- if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) {
- conf = &req->rq_import->imp_obd->u.cli.cl_sec_conf;
- buflens[bufcnt] = bulk_sec_desc_size(
- conf->sfc_bulk_csum, 0,
- req->rq_bulk_read);
+ if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) {
+ conf = &req->rq_import->imp_obd->u.cli.cl_sec_conf;
+ buflens[bufcnt] = bulk_sec_desc_size(conf->sfc_bulk_csum, 0,
+ req->rq_bulk_read);
+ if (svc == SPTLRPC_SVC_INTG)
txtsize += buflens[bufcnt];
- bufcnt++;
- }
- buflens[bufcnt++] = req->rq_ctx_init ? GSS_CTX_INIT_MAX_LEN :
- gss_cli_payload(req->rq_cli_ctx, txtsize, 0);
+ bufcnt++;
}
- bufsize = lustre_msg_size_v2(bufcnt, buflens);
- bufsize = size_roundup_power2(bufsize);
+ if (req->rq_ctx_init)
+ buflens[bufcnt++] = GSS_CTX_INIT_MAX_LEN;
+ else if (svc != SPTLRPC_SVC_NULL)
+ buflens[bufcnt++] = gss_cli_payload(req->rq_cli_ctx, txtsize,0);
- OBD_ALLOC(req->rq_repbuf, bufsize);
- if (!req->rq_repbuf)
- return -ENOMEM;
+ return do_alloc_repbuf(req, lustre_msg_size_v2(bufcnt, buflens));
+}
- req->rq_repbuf_len = bufsize;
- return 0;
+static
+int gss_alloc_repbuf_priv(struct ptlrpc_sec *sec,
+ struct ptlrpc_request *req,
+ int msgsize)
+{
+ struct sec_flavor_config *conf;
+ int txtsize;
+ int buflens[3], bufcnt;
+
+ /* Inner (clear) buffers
+ * - lustre message
+ * - bulk checksum (optional)
+ */
+
+ bufcnt = 1;
+ buflens[0] = msgsize;
+
+ if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) {
+ conf = &req->rq_import->imp_obd->u.cli.cl_sec_conf;
+ buflens[bufcnt++] = bulk_sec_desc_size(
+ conf->sfc_bulk_csum, 0,
+ req->rq_bulk_read);
+ }
+ txtsize = lustre_msg_size_v2(bufcnt, buflens);
+ txtsize += GSS_MAX_CIPHER_BLOCK;
+
+ /* Wrapper (wire) buffers
+ * - gss header
+ * - signature of gss header
+ * - cipher text
+ */
+
+ bufcnt = 3;
+ buflens[0] = PTLRPC_GSS_HEADER_SIZE;
+ buflens[1] = gss_cli_payload(req->rq_cli_ctx, buflens[0], 0);
+ buflens[2] = gss_cli_payload(req->rq_cli_ctx, txtsize, 1);
+
+ return do_alloc_repbuf(req, lustre_msg_size_v2(bufcnt, buflens));
+}
+
+int gss_alloc_repbuf(struct ptlrpc_sec *sec,
+ struct ptlrpc_request *req,
+ int msgsize)
+{
+ int svc = SEC_FLAVOR_SVC(req->rq_sec_flavor);
+ ENTRY;
+
+ LASSERT(!SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor) ||
+ (req->rq_bulk_read || req->rq_bulk_write));
+
+ switch (svc) {
+ case SPTLRPC_SVC_NULL:
+ case SPTLRPC_SVC_AUTH:
+ case SPTLRPC_SVC_INTG:
+ return gss_alloc_repbuf_intg(sec, req, svc, msgsize);
+ case SPTLRPC_SVC_PRIV:
+ return gss_alloc_repbuf_priv(sec, req, msgsize);
+ default:
+ LASSERTF(0, "bad flavor %x\n", req->rq_sec_flavor);
+ return 0;
+ }
}
void gss_free_repbuf(struct ptlrpc_sec *sec,
return newmsg_size;
}
-static inline int msg_last_seglen(struct lustre_msg *msg)
-{
- return msg->lm_buflens[msg->lm_bufcount - 1];
-}
-
static
-int gss_enlarge_reqbuf_auth(struct ptlrpc_sec *sec,
+int gss_enlarge_reqbuf_intg(struct ptlrpc_sec *sec,
struct ptlrpc_request *req,
+ int svc,
int segment, int newsize)
{
struct lustre_msg *newbuf;
- int txtsize, sigsize, i;
+ int txtsize, sigsize = 0, i;
int newmsg_size, newbuf_size;
/*
- * embedded msg is at seg 1; signature is at the last seg
+ * gss header is at seg 0;
+ * embedded msg is at seg 1;
+ * signature (if any) is at the last seg
*/
LASSERT(req->rq_reqbuf);
LASSERT(req->rq_reqbuf_len > req->rq_reqlen);
LASSERT(req->rq_reqbuf->lm_bufcount >= 2);
LASSERT(lustre_msg_buf(req->rq_reqbuf, 1, 0) == req->rq_reqmsg);
- /* compute new embedded msg size */
+ /* 1. compute new embedded msg size */
newmsg_size = get_enlarged_msgsize(req->rq_reqmsg, segment, newsize);
LASSERT(newmsg_size >= req->rq_reqbuf->lm_buflens[1]);
- /* compute new wrapper msg size */
- for (txtsize = 0, i = 0; i < req->rq_reqbuf->lm_bufcount; i++)
- txtsize += req->rq_reqbuf->lm_buflens[i];
- txtsize += newmsg_size - req->rq_reqbuf->lm_buflens[1];
+ /* 2. compute new wrapper msg size */
+ if (svc == SPTLRPC_SVC_NULL) {
+ /* no signature, get size directly */
+ newbuf_size = get_enlarged_msgsize(req->rq_reqbuf,
+ 1, newmsg_size);
+ } else {
+ txtsize = req->rq_reqbuf->lm_buflens[0];
+
+ if (svc == SPTLRPC_SVC_INTG) {
+ for (i = 1; i < req->rq_reqbuf->lm_bufcount; i++)
+ txtsize += req->rq_reqbuf->lm_buflens[i];
+ txtsize += newmsg_size - req->rq_reqbuf->lm_buflens[1];
+ }
+
+ sigsize = gss_cli_payload(req->rq_cli_ctx, txtsize, 0);
+ LASSERT(sigsize >= msg_last_seglen(req->rq_reqbuf));
- sigsize = gss_cli_payload(req->rq_cli_ctx, txtsize, 0);
- LASSERT(sigsize >= msg_last_seglen(req->rq_reqbuf));
- newbuf_size = get_enlarged_msgsize2(req->rq_reqbuf, 1, newmsg_size,
- req->rq_reqbuf->lm_bufcount - 1,
- sigsize);
+ newbuf_size = get_enlarged_msgsize2(
+ req->rq_reqbuf,
+ 1, newmsg_size,
+ msg_last_segidx(req->rq_reqbuf),
+ sigsize);
+ }
/* request from pool should always have enough buffer */
LASSERT(!req->rq_pool || req->rq_reqbuf_len >= newbuf_size);
req->rq_reqmsg = lustre_msg_buf(req->rq_reqbuf, 1, 0);
}
- _sptlrpc_enlarge_msg_inplace(req->rq_reqbuf,
- req->rq_reqbuf->lm_bufcount - 1, sigsize);
+ /* do enlargement, from wrapper to embedded, from end to begin */
+ if (svc != SPTLRPC_SVC_NULL)
+ _sptlrpc_enlarge_msg_inplace(req->rq_reqbuf,
+ msg_last_segidx(req->rq_reqbuf),
+ sigsize);
+
_sptlrpc_enlarge_msg_inplace(req->rq_reqbuf, 1, newmsg_size);
_sptlrpc_enlarge_msg_inplace(req->rq_reqmsg, segment, newsize);
struct ptlrpc_request *req,
int segment, int newsize)
{
+ int svc = SEC_FLAVOR_SVC(req->rq_sec_flavor);
+
LASSERT(!req->rq_ctx_init && !req->rq_ctx_fini);
- switch (SEC_FLAVOR_SVC(req->rq_sec_flavor)) {
+ switch (svc) {
+ case SPTLRPC_SVC_NULL:
case SPTLRPC_SVC_AUTH:
- return gss_enlarge_reqbuf_auth(sec, req, segment, newsize);
+ case SPTLRPC_SVC_INTG:
+ return gss_enlarge_reqbuf_intg(sec, req, svc, segment, newsize);
case SPTLRPC_SVC_PRIV:
return gss_enlarge_reqbuf_priv(sec, req, segment, newsize);
default:
static
int gss_svc_sign(struct ptlrpc_request *req,
struct ptlrpc_reply_state *rs,
- struct gss_svc_reqctx *grctx)
+ struct gss_svc_reqctx *grctx,
+ int svc)
{
int rc;
ENTRY;
rc = gss_sign_msg(rs->rs_repbuf, grctx->src_ctx->gsc_mechctx,
PTLRPC_GSS_PROC_DATA, grctx->src_wirectx.gw_seq,
- NULL);
+ svc, NULL);
if (rc < 0)
RETURN(rc);
CDEBUG(D_SEC, "processing gss init(%d) request from %s\n", gw->gw_proc,
libcfs_nid2str(req->rq_peer.nid));
+ req->rq_ctx_init = 1;
+
if (gw->gw_proc == PTLRPC_GSS_PROC_INIT && gw->gw_handle.len != 0) {
CERROR("proc %u: invalid handle length %u\n",
gw->gw_proc, gw->gw_handle.len);
if (rc != SECSVC_OK)
RETURN(rc);
+ if (grctx->src_ctx->gsc_usr_mds || grctx->src_ctx->gsc_usr_root)
+ CWARN("user from %s authenticated as %s\n",
+ libcfs_nid2str(req->rq_peer.nid),
+ grctx->src_ctx->gsc_usr_mds ? "mds" : "root");
+ else
+ CWARN("accept user %u from %s\n", grctx->src_ctx->gsc_uid,
+ libcfs_nid2str(req->rq_peer.nid));
+
if (SEC_FLAVOR_HAS_USER(req->rq_sec_flavor)) {
if (reqbuf->lm_bufcount < 4) {
CERROR("missing user descriptor\n");
*/
static
int gss_svc_verify_request(struct ptlrpc_request *req,
- struct gss_svc_ctx *gctx,
+ struct gss_svc_reqctx *grctx,
struct gss_wire_ctx *gw,
__u32 *major)
{
+ struct gss_svc_ctx *gctx = grctx->src_ctx;
struct lustre_msg *msg = req->rq_reqbuf;
int offset = 2;
ENTRY;
*major = GSS_S_COMPLETE;
- if (msg->lm_bufcount < 3) {
+ if (msg->lm_bufcount < 2) {
CERROR("Too few segments (%u) in request\n", msg->lm_bufcount);
RETURN(-EINVAL);
}
+ if (gw->gw_svc == SPTLRPC_SVC_NULL)
+ goto verified;
+
if (gss_check_seq_num(&gctx->gsc_seqdata, gw->gw_seq, 0)) {
CERROR("phase 0: discard replayed req: seq %u\n", gw->gw_seq);
*major = GSS_S_DUPLICATE_TOKEN;
RETURN(-EACCES);
}
- *major = gss_verify_msg(msg, gctx->gsc_mechctx);
+ *major = gss_verify_msg(msg, gctx->gsc_mechctx, gw->gw_svc);
if (*major != GSS_S_COMPLETE)
RETURN(-EACCES);
RETURN(-EACCES);
}
+verified:
/* user descriptor */
if (SEC_FLAVOR_HAS_USER(req->rq_sec_flavor)) {
- if (msg->lm_bufcount < (offset + 1 + 1)) {
+ if (msg->lm_bufcount < (offset + 1)) {
CERROR("no user desc included\n");
RETURN(-EINVAL);
}
/* check bulk cksum data */
if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) {
- if (msg->lm_bufcount < (offset + 1 + 1)) {
+ if (msg->lm_bufcount < (offset + 1)) {
CERROR("no bulk checksum included\n");
RETURN(-EINVAL);
}
if (bulk_sec_desc_unpack(msg, offset))
RETURN(-EINVAL);
+
+ grctx->src_reqbsd = lustre_msg_buf(msg, offset, 0);
+ grctx->src_reqbsd_size = lustre_msg_buflen(msg, offset);
}
req->rq_reqmsg = lustre_msg_buf(msg, 1, 0);
static
int gss_svc_unseal_request(struct ptlrpc_request *req,
- struct gss_svc_ctx *gctx,
+ struct gss_svc_reqctx *grctx,
struct gss_wire_ctx *gw,
__u32 *major)
{
+ struct gss_svc_ctx *gctx = grctx->src_ctx;
struct lustre_msg *msg = req->rq_reqbuf;
int msglen, offset = 1;
ENTRY;
if (bulk_sec_desc_unpack(msg, offset))
RETURN(-EINVAL);
+
+ grctx->src_reqbsd = lustre_msg_buf(msg, offset, 0);
+ grctx->src_reqbsd_size = lustre_msg_buflen(msg, offset);
}
req->rq_reqmsg = lustre_msg_buf(req->rq_reqbuf, 0, 0);
}
switch (gw->gw_svc) {
- case PTLRPC_GSS_SVC_INTEGRITY:
- rc = gss_svc_verify_request(req, grctx->src_ctx, gw, &major);
+ case SPTLRPC_SVC_NULL:
+ case SPTLRPC_SVC_AUTH:
+ case SPTLRPC_SVC_INTG:
+ rc = gss_svc_verify_request(req, grctx, gw, &major);
break;
- case PTLRPC_GSS_SVC_PRIVACY:
- rc = gss_svc_unseal_request(req, grctx->src_ctx, gw, &major);
+ case SPTLRPC_SVC_PRIV:
+ rc = gss_svc_unseal_request(req, grctx, gw, &major);
break;
default:
CERROR("unsupported gss service %d\n", gw->gw_svc);
struct gss_wire_ctx *gw)
{
struct gss_svc_reqctx *grctx = gss_svc_ctx2reqctx(req->rq_svc_ctx);
- int replen = sizeof(struct ptlrpc_body);
__u32 major;
ENTRY;
+ req->rq_ctx_fini = 1;
+ req->rq_no_reply = 1;
+
grctx->src_ctx = gss_svc_upcall_get_ctx(req, gw);
if (!grctx->src_ctx) {
CWARN("invalid gss context handle for destroy.\n");
RETURN(SECSVC_DROP);
}
- if (gw->gw_svc != PTLRPC_GSS_SVC_INTEGRITY) {
+ if (gw->gw_svc != SPTLRPC_SVC_INTG) {
CERROR("svc %u is not supported in destroy.\n", gw->gw_svc);
RETURN(SECSVC_DROP);
}
- if (gss_svc_verify_request(req, grctx->src_ctx, gw, &major))
- RETURN(SECSVC_DROP);
-
- if (lustre_pack_reply_v2(req, 1, &replen, NULL))
+ if (gss_svc_verify_request(req, grctx, gw, &major))
RETURN(SECSVC_DROP);
- CWARN("gss svc destroy ctx %p(%u->%s)\n", grctx->src_ctx,
- grctx->src_ctx->gsc_uid, libcfs_nid2str(req->rq_peer.nid));
+ CWARN("destroy svc ctx %p(%u->%s)\n", grctx->src_ctx,
+ grctx->src_ctx->gsc_uid, libcfs_nid2str(req->rq_peer.nid));
gss_svc_upcall_destroy_ctx(grctx->src_ctx);
{
struct gss_svc_reqctx *grctx;
struct ptlrpc_reply_state *rs;
- struct ptlrpc_bulk_sec_desc *bsd;
- int privacy;
+ int privacy, svc, bsd_off = 0;
int ibuflens[2], ibufcnt = 0;
int buflens[4], bufcnt;
int txtsize, wmsg_size, rs_size;
RETURN(-EPROTO);
}
+ svc = SEC_FLAVOR_SVC(req->rq_sec_flavor);
+
grctx = gss_svc_ctx2reqctx(req->rq_svc_ctx);
if (gss_svc_reqctx_is_special(grctx))
privacy = 0;
else
- privacy = (SEC_FLAVOR_SVC(req->rq_sec_flavor) ==
- SPTLRPC_SVC_PRIV);
+ privacy = (svc == SPTLRPC_SVC_PRIV);
if (privacy) {
/* Inner buffer */
ibuflens[0] = msglen;
if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) {
- LASSERT(req->rq_reqbuf->lm_bufcount >= 2);
- bsd = lustre_msg_buf(req->rq_reqbuf,
- req->rq_reqbuf->lm_bufcount - 1,
- sizeof(*bsd));
+ LASSERT(grctx->src_reqbsd);
+ bsd_off = ibufcnt;
ibuflens[ibufcnt++] = bulk_sec_desc_size(
- bsd->bsd_csum_alg, 0,
- req->rq_bulk_read);
+ grctx->src_reqbsd->bsd_csum_alg,
+ 0, req->rq_bulk_read);
}
txtsize = lustre_msg_size_v2(ibufcnt, ibuflens);
bufcnt = 2;
buflens[0] = PTLRPC_GSS_HEADER_SIZE;
buflens[1] = msglen;
- txtsize = buflens[0] + buflens[1];
+
+ txtsize = buflens[0];
+ if (svc == SPTLRPC_SVC_INTG)
+ txtsize += buflens[1];
if (SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor)) {
- LASSERT(req->rq_reqbuf->lm_bufcount >= 4);
- bsd = lustre_msg_buf(req->rq_reqbuf,
- req->rq_reqbuf->lm_bufcount - 2,
- sizeof(*bsd));
+ LASSERT(grctx->src_reqbsd);
+ bsd_off = bufcnt;
buflens[bufcnt] = bulk_sec_desc_size(
- bsd->bsd_csum_alg, 0,
- req->rq_bulk_read);
- txtsize += buflens[bufcnt];
+ grctx->src_reqbsd->bsd_csum_alg,
+ 0, req->rq_bulk_read);
+ if (svc == SPTLRPC_SVC_INTG)
+ txtsize += buflens[bufcnt];
bufcnt++;
}
- buflens[bufcnt++] = gss_svc_payload(grctx, txtsize, 0);
+
+ if (gss_svc_reqctx_is_special(grctx) ||
+ svc != SPTLRPC_SVC_NULL)
+ buflens[bufcnt++] = gss_svc_payload(grctx, txtsize, 0);
}
wmsg_size = lustre_msg_size_v2(bufcnt, buflens);
rs->rs_repbuf = (struct lustre_msg *) (rs + 1);
rs->rs_repbuf_len = wmsg_size;
+ /* initialize the buffer */
if (privacy) {
lustre_init_msg_v2(rs->rs_repbuf, ibufcnt, ibuflens, NULL);
rs->rs_msg = lustre_msg_buf(rs->rs_repbuf, 0, msglen);
lustre_init_msg_v2(rs->rs_repbuf, bufcnt, buflens, NULL);
rs->rs_repbuf->lm_secflvr = req->rq_sec_flavor;
- rs->rs_msg = (struct lustre_msg *)
- lustre_msg_buf(rs->rs_repbuf, 1, 0);
+ rs->rs_msg = lustre_msg_buf(rs->rs_repbuf, 1, 0);
+ }
+
+ if (bsd_off) {
+ grctx->src_repbsd = lustre_msg_buf(rs->rs_repbuf, bsd_off, 0);
+ grctx->src_repbsd_size = lustre_msg_buflen(rs->rs_repbuf,
+ bsd_off);
}
gss_svc_reqctx_addref(grctx);
}
LASSERT(cipher_obj.len <= cipher_buflen);
+ /*
+ * we are about to override data at rs->rs_repbuf, nullify pointers
+ * to which to catch further illegal usage.
+ */
+ grctx->src_repbsd = NULL;
+ grctx->src_repbsd_size = 0;
+
/* now the real wire data */
buflens[0] = PTLRPC_GSS_HEADER_SIZE;
buflens[1] = gss_estimate_payload(gctx->gsc_mechctx, buflens[0], 0);
ghdr->gh_flags = 0;
ghdr->gh_proc = PTLRPC_GSS_PROC_DATA;
ghdr->gh_seq = grctx->src_wirectx.gw_seq;
- ghdr->gh_svc = PTLRPC_GSS_SVC_PRIVACY;
+ ghdr->gh_svc = SPTLRPC_SVC_PRIV;
ghdr->gh_handle.len = 0;
/* header signature */
LASSERT(grctx->src_ctx);
switch (gw->gw_svc) {
- case PTLRPC_GSS_SVC_INTEGRITY:
- rc = gss_svc_sign(req, rs, grctx);
+ case SPTLRPC_SVC_NULL:
+ case SPTLRPC_SVC_AUTH:
+ case SPTLRPC_SVC_INTG:
+ rc = gss_svc_sign(req, rs, grctx, gw->gw_svc);
break;
- case PTLRPC_GSS_SVC_PRIVACY:
+ case SPTLRPC_SVC_PRIV:
rc = gss_svc_seal(req, rs, grctx);
break;
default:
LASSERT(rs->rs_svc_ctx);
grctx = container_of(rs->rs_svc_ctx, struct gss_svc_reqctx, src_base);
+ /* paranoid, maybe not necessary */
+ grctx->src_reqbsd = NULL;
+ grctx->src_repbsd = NULL;
+
gss_svc_reqctx_decref(grctx);
rs->rs_svc_ctx = NULL;