}
}
cache_get(&item->h);
- //set_bit(CACHE_HASHED, &item->h.flags);
+ set_bit(CACHE_HASHED, &item->h.flags);
item->h.next = *head;
*head = &item->h;
rsi_cache.entries++;
}
}
read_unlock(&rsi_cache.hash_lock);
- } while ((get_seconds() - starttime) <= 15);
- CERROR("15s timeout while waiting cache refill\n");
+ } while ((get_seconds() - starttime) <= SVCSEC_UPCALL_TIMEOUT);
+ CERROR("%ds timeout while waiting cache refill\n",
+ SVCSEC_UPCALL_TIMEOUT);
return NULL;
}
struct rsc {
struct cache_head h;
rawobj_t handle;
- __u32 remote_realm;
+ __u32 remote_realm:1,
+ auth_usr_mds:1,
+ auth_usr_oss:1;
struct vfs_cred cred;
uid_t mapped_uid;
struct gss_svc_seq_data seqdata;
read_unlock(&rsc_cache.hash_lock);
RETURN(tmp);
}
-
+
static int rsc_parse(struct cache_detail *cd,
char *mesg, int mlen)
{
/* contexthandle expiry [ uid gid N <n gids> mechname
* ...mechdata... ] */
char *buf = mesg;
- int len, rv;
+ int len, rv, tmp_int;
struct rsc *rsci, *res = NULL;
time_t expiry;
int status = -EINVAL;
goto out;
/* remote flag */
- rv = get_int(&mesg, (int *)&rsci->remote_realm);
+ rv = get_int(&mesg, &tmp_int);
if (rv) {
CERROR("fail to get remote flag\n");
goto out;
}
+ rsci->remote_realm = (tmp_int != 0);
+
+ /* mds user flag */
+ rv = get_int(&mesg, &tmp_int);
+ if (rv) {
+ CERROR("fail to get mds user flag\n");
+ goto out;
+ }
+ rsci->auth_usr_mds = (tmp_int != 0);
+
+ /* oss user flag */
+ rv = get_int(&mesg, &tmp_int);
+ if (rv) {
+ CERROR("fail to get oss user flag\n");
+ goto out;
+ }
+ rsci->auth_usr_oss = (tmp_int != 0);
/* mapped uid */
rv = get_int(&mesg, (int *)&rsci->mapped_uid);
kgss_mech_put(gm);
goto out;
}
- expiry = (time_t) ctx_expiry;
+ expiry = (time_t) gss_roundup_expire_time(ctx_expiry);
kgss_mech_put(gm);
}
int n;
ENTRY;
+ if (uid == -1)
+ CWARN("flush all gss contexts\n");
+
write_lock(&rsc_cache.hash_lock);
for (n = 0; n < RSC_HASHMAX; n++) {
for (ch = &rsc_cache.hash_table[n]; *ch;) {
rscp = container_of(*ch, struct rsc, h);
- if (uid == -1 || rscp->cred.vc_uid == uid) {
- /* it seems simply set NEGATIVE doesn't work */
- *ch = (*ch)->next;
- rscp->h.next = NULL;
- cache_get(&rscp->h);
- set_bit(CACHE_NEGATIVE, &rscp->h.flags);
- clear_bit(CACHE_HASHED, &rscp->h.flags);
- CDEBUG(D_SEC, "flush rsc %p for uid %u\n",
- rscp, rscp->cred.vc_uid);
- rsc_put(&rscp->h, &rsc_cache);
- rsc_cache.entries--;
+
+ if (uid != -1 && rscp->cred.vc_uid != uid) {
+ ch = &((*ch)->next);
continue;
}
- ch = &((*ch)->next);
+
+ /* it seems simply set NEGATIVE doesn't work */
+ *ch = (*ch)->next;
+ rscp->h.next = NULL;
+ cache_get(&rscp->h);
+ set_bit(CACHE_NEGATIVE, &rscp->h.flags);
+ clear_bit(CACHE_HASHED, &rscp->h.flags);
+ if (uid != -1)
+ CWARN("flush rsc %p(%u) for uid %u\n", rscp,
+ *((__u32 *) rscp->handle.data),
+ rscp->cred.vc_uid);
+ rsc_put(&rscp->h, &rsc_cache);
+ rsc_cache.entries--;
}
}
write_unlock(&rsc_cache.hash_lock);
static struct cache_req my_chandle = {my_defer};
/* Implements sequence number algorithm as specified in RFC 2203. */
+static inline void __dbg_dump_seqwin(struct gss_svc_seq_data *sd)
+{
+ char buf[sizeof(sd->sd_win)*2+1];
+ int i;
+
+ for (i = 0; i < sizeof(sd->sd_win); i++)
+ sprintf(&buf[i+i], "%02x", ((__u8 *) sd->sd_win)[i]);
+ CWARN("dump seqwin: %s\n", buf);
+}
+
+static inline void __dbg_seq_jump(struct gss_svc_seq_data *sd, __u32 seq_num)
+{
+ CWARN("seq jump to %u, cur max %u!\n", seq_num, sd->sd_max);
+ __dbg_dump_seqwin(sd);
+}
+
+static inline void __dbg_seq_increase(struct gss_svc_seq_data *sd, __u32 seq_num)
+{
+ int n = seq_num - sd->sd_max;
+ int i, notset=0;
+
+ for (i = 0; i < n; i++) {
+ if (!test_bit(i, sd->sd_win))
+ notset++;
+ }
+ if (!notset)
+ return;
+
+ CWARN("seq increase to %u, cur max %u\n", seq_num, sd->sd_max);
+ __dbg_dump_seqwin(sd);
+}
+
static int
gss_check_seq_num(struct gss_svc_seq_data *sd, __u32 seq_num)
{
spin_lock(&sd->sd_lock);
if (seq_num > sd->sd_max) {
if (seq_num >= sd->sd_max + GSS_SEQ_WIN) {
+ __dbg_seq_jump(sd, seq_num);
memset(sd->sd_win, 0, sizeof(sd->sd_win));
sd->sd_max = seq_num;
} else {
+ __dbg_seq_increase(sd, seq_num);
while(sd->sd_max < seq_num) {
sd->sd_max++;
__clear_bit(sd->sd_max % GSS_SEQ_WIN,
gss_pack_err_notify(struct ptlrpc_request *req,
__u32 major, __u32 minor)
{
- struct gss_svc_data *svcdata = req->rq_sec_svcdata;
+ struct gss_svc_data *svcdata = req->rq_svcsec_data;
__u32 reslen, *resp, *reslenp;
char nidstr[PTL_NALFMT_SIZE];
const __u32 secdata_len = 7 * 4;
resp = (__u32 *) req->rq_reply_state->rs_repbuf;
/* header */
- *resp++ = cpu_to_le32(PTLRPC_SEC_GSS);
- *resp++ = cpu_to_le32(PTLRPC_SEC_TYPE_NONE);
+ *resp++ = cpu_to_le32(PTLRPCS_FLVR_GSS_NONE);
+ *resp++ = cpu_to_le32(PTLRPCS_SVC_NONE);
*resp++ = cpu_to_le32(req->rq_replen);
reslenp = resp++;
* obj1(fake), obj2(fake)
*/
*resp++ = cpu_to_le32(PTLRPC_SEC_GSS_VERSION);
- *resp++ = cpu_to_le32(PTLRPC_SEC_GSS_KRB5I);
- *resp++ = cpu_to_le32(PTLRPC_GSS_PROC_ERR);
+ *resp++ = cpu_to_le32(PTLRPCS_FLVR_KRB5I);
+ *resp++ = cpu_to_le32(PTLRPCS_GSS_PROC_ERR);
*resp++ = cpu_to_le32(major);
*resp++ = cpu_to_le32(minor);
*resp++ = 0;
__u32 *secdata, __u32 seclen,
enum ptlrpcs_error *res)
{
- struct gss_svc_data *svcdata = req->rq_sec_svcdata;
+ struct gss_svc_data *svcdata = req->rq_svcsec_data;
struct rsc *rsci;
struct rsi *rsikey, *rsip;
rawobj_t tmpobj;
req->rq_peer.peer_id.nid, nidstr));
svcdata->is_init = 1;
- svcdata->reserve_len = 6 * 4 +
+ svcdata->reserve_len = 7 * 4 +
size_round4(rsip->out_handle.len) +
size_round4(rsip->out_token.len);
/* header */
resp = (__u32 *) req->rq_reply_state->rs_repbuf;
- *resp++ = cpu_to_le32(PTLRPC_SEC_GSS);
- *resp++ = cpu_to_le32(PTLRPC_SEC_TYPE_NONE);
+ *resp++ = cpu_to_le32(PTLRPCS_FLVR_GSS_NONE);
+ *resp++ = cpu_to_le32(PTLRPCS_SVC_NONE);
*resp++ = cpu_to_le32(req->rq_replen);
reslenp = resp++;
resp += req->rq_replen / 4;
reslen = svcdata->reserve_len;
- /* gss reply:
- * status, major, minor, seq, out_handle, out_token
+ /* gss reply: (conform to err notify format)
+ * x, x, seq, major, minor, handle, token
*/
- *resp++ = cpu_to_le32(PTLRPCS_OK);
+ *resp++ = 0;
+ *resp++ = 0;
+ *resp++ = cpu_to_le32(GSS_SEQ_WIN);
*resp++ = cpu_to_le32(rsip->major_status);
*resp++ = cpu_to_le32(rsip->minor_status);
- *resp++ = cpu_to_le32(GSS_SEQ_WIN);
- reslen -= (4 * 4);
+ reslen -= (5 * 4);
if (rawobj_serialize(&rsip->out_handle,
&resp, &reslen)) {
dump_rsi(rsip);
*res = PTLRPCS_OK;
- req->rq_auth_uid = rsci->cred.vc_uid;
req->rq_remote_realm = rsci->remote_realm;
+ req->rq_auth_usr_mds = rsci->auth_usr_mds;
+ req->rq_auth_usr_oss = rsci->auth_usr_oss;
+ req->rq_auth_uid = rsci->cred.vc_uid;
req->rq_mapped_uid = rsci->mapped_uid;
+ if (req->rq_auth_usr_mds) {
+ CWARN("usr from %s authenticated as mds svc cred\n",
+ portals_nid2str(req->rq_peer.peer_ni->pni_number,
+ req->rq_peer.peer_id.nid, nidstr));
+ }
+ if (req->rq_auth_usr_oss) {
+ CWARN("usr from %s authenticated as oss svc cred\n",
+ portals_nid2str(req->rq_peer.peer_ni->pni_number,
+ req->rq_peer.peer_id.nid, nidstr));
+ }
+
/* This is simplified since right now we doesn't support
* INIT_CONTINUE yet.
*/
}
switch (gc->gc_svc) {
- case PTLRPC_GSS_SVC_INTEGRITY:
+ case PTLRPCS_GSS_SVC_INTEGRITY:
major = gss_svc_verify_request(req, rsci, gc, secdata, seclen);
if (major == GSS_S_COMPLETE)
break;
portals_nid2str(req->rq_peer.peer_ni->pni_number,
req->rq_peer.peer_id.nid, nidstr));
goto notify_err;
- case PTLRPC_GSS_SVC_PRIVACY:
+ case PTLRPCS_GSS_SVC_PRIVACY:
major = gss_svc_unseal_request(req, rsci, gc, secdata, seclen);
if (major == GSS_S_COMPLETE)
break;
GOTO(out, rc = SVC_DROP);
}
- req->rq_auth_uid = rsci->cred.vc_uid;
req->rq_remote_realm = rsci->remote_realm;
+ req->rq_auth_usr_mds = rsci->auth_usr_mds;
+ req->rq_auth_usr_oss = rsci->auth_usr_oss;
+ req->rq_auth_uid = rsci->cred.vc_uid;
req->rq_mapped_uid = rsci->mapped_uid;
*res = PTLRPCS_OK;
__u32 *secdata, __u32 seclen,
enum ptlrpcs_error *res)
{
- struct gss_svc_data *svcdata = req->rq_sec_svcdata;
+ struct gss_svc_data *svcdata = req->rq_svcsec_data;
struct rsc *rsci;
char nidstr[PTL_NALFMT_SIZE];
int rc;
RETURN(SVC_DROP);
}
- if (gc->gc_svc != PTLRPC_GSS_SVC_INTEGRITY) {
+ if (gc->gc_svc != PTLRPCS_GSS_SVC_INTEGRITY) {
CERROR("service %d is not supported in destroy.\n",
gc->gc_svc);
GOTO(out, rc = SVC_DROP);
struct gss_svc_data *svcdata;
struct rpc_gss_wire_cred *gc;
struct ptlrpcs_wire_hdr *sec_hdr;
- __u32 seclen, *secdata, version;
+ __u32 subflavor, seclen, *secdata, version;
int rc;
ENTRY;
*res = PTLRPCS_BADCRED;
sec_hdr = buf_to_sec_hdr(req->rq_reqbuf);
- LASSERT(sec_hdr->flavor == PTLRPC_SEC_GSS);
+ LASSERT(SEC_FLAVOR_MAJOR(sec_hdr->flavor) == PTLRPCS_FLVR_MAJOR_GSS);
seclen = req->rq_reqbuf_len - sizeof(*sec_hdr) - sec_hdr->msg_len;
secdata = (__u32 *) buf_to_sec_data(req->rq_reqbuf);
RETURN(SVC_DROP);
}
- LASSERT(!req->rq_sec_svcdata);
+ LASSERT(!req->rq_svcsec_data);
OBD_ALLOC(svcdata, sizeof(*svcdata));
if (!svcdata) {
CERROR("fail to alloc svcdata\n");
RETURN(SVC_DROP);
}
- req->rq_sec_svcdata = svcdata;
+ req->rq_svcsec_data = svcdata;
gc = &svcdata->clcred;
/* Now secdata/seclen is what we want to parse
*/
version = le32_to_cpu(*secdata++); /* version */
- svcdata->subflavor = le32_to_cpu(*secdata++); /* subflavor */
+ subflavor = le32_to_cpu(*secdata++); /* subflavor */
gc->gc_proc = le32_to_cpu(*secdata++); /* proc */
gc->gc_seq = le32_to_cpu(*secdata++); /* seq */
gc->gc_svc = le32_to_cpu(*secdata++); /* service */
seclen -= 5 * 4;
CDEBUG(D_SEC, "wire gss_hdr: %u/%u/%u/%u/%u\n",
- version, svcdata->subflavor, gc->gc_proc,
+ version, subflavor, gc->gc_proc,
gc->gc_seq, gc->gc_svc);
if (version != PTLRPC_SEC_GSS_VERSION) {
GOTO(err_free, rc = SVC_DROP);
}
- if (rawobj_extract(&gc->gc_ctx, &secdata, &seclen)) {
+ /* We _must_ alloc new storage for gc_ctx. In case of recovery
+ * request will be saved to delayed handling, at that time the
+ * incoming buffer might have already been released.
+ */
+ if (rawobj_extract_alloc(&gc->gc_ctx, &secdata, &seclen)) {
CERROR("fail to obtain gss context handle\n");
GOTO(err_free, rc = SVC_DROP);
}
}
err_free:
- if (rc == SVC_DROP && req->rq_sec_svcdata) {
- OBD_FREE(req->rq_sec_svcdata, sizeof(struct gss_svc_data));
- req->rq_sec_svcdata = NULL;
+ if (rc == SVC_DROP && req->rq_svcsec_data) {
+ OBD_FREE(req->rq_svcsec_data, sizeof(struct gss_svc_data));
+ req->rq_svcsec_data = NULL;
}
RETURN(rc);
gss_svcsec_authorize(struct ptlrpc_request *req)
{
struct ptlrpc_reply_state *rs = req->rq_reply_state;
- struct gss_svc_data *gsd = (struct gss_svc_data *)req->rq_sec_svcdata;
+ struct gss_svc_data *gsd = (struct gss_svc_data *)req->rq_svcsec_data;
struct rpc_gss_wire_cred *gc = &gsd->clcred;
struct rsc *rscp;
struct ptlrpcs_wire_hdr *sec_hdr;
rscp = gss_svc_searchbyctx(&gc->gc_ctx);
if (!rscp) {
- CERROR("ctx disapeared under us?\n");
+ CERROR("ctx %u disapeared under us\n",
+ *((__u32 *) gc->gc_ctx.data));
RETURN(-EINVAL);
}
sec_hdr = (struct ptlrpcs_wire_hdr *) rs->rs_repbuf;
switch (gc->gc_svc) {
- case PTLRPC_GSS_SVC_INTEGRITY:
+ case PTLRPCS_GSS_SVC_INTEGRITY:
/* prepare various pointers */
lmsg.len = req->rq_replen;
lmsg.data = (__u8 *) (rs->rs_repbuf + sizeof(*sec_hdr));
vlen = rs->rs_repbuf_len - sizeof(*sec_hdr) - lmsg.len;
seclen = vlen;
- sec_hdr->flavor = cpu_to_le32(PTLRPC_SEC_GSS);
- sec_hdr->sectype = cpu_to_le32(PTLRPC_SEC_TYPE_AUTH);
+ sec_hdr->flavor = cpu_to_le32(PTLRPCS_FLVR_GSS_AUTH);
sec_hdr->msg_len = cpu_to_le32(req->rq_replen);
/* standard gss hdr */
LASSERT(vlen >= 7 * 4);
*vp++ = cpu_to_le32(PTLRPC_SEC_GSS_VERSION);
- *vp++ = cpu_to_le32(PTLRPC_SEC_GSS_KRB5I);
+ *vp++ = cpu_to_le32(PTLRPCS_FLVR_KRB5I);
*vp++ = cpu_to_le32(RPC_GSS_PROC_DATA);
*vp++ = cpu_to_le32(gc->gc_seq);
- *vp++ = cpu_to_le32(PTLRPC_GSS_SVC_INTEGRITY);
+ *vp++ = cpu_to_le32(PTLRPCS_GSS_SVC_INTEGRITY);
*vp++ = 0; /* fake ctx handle */
vpsave = vp++; /* reserve size */
vlen -= 7 * 4;
sec_hdr->sec_len = cpu_to_le32(seclen);
rs->rs_repdata_len += size_round(seclen);
break;
- case PTLRPC_GSS_SVC_PRIVACY:
+ case PTLRPCS_GSS_SVC_PRIVACY:
vp = (__u32 *) (rs->rs_repbuf + sizeof(*sec_hdr));
vlen = rs->rs_repbuf_len - sizeof(*sec_hdr);
seclen = vlen;
- sec_hdr->flavor = cpu_to_le32(PTLRPC_SEC_GSS);
- sec_hdr->sectype = cpu_to_le32(PTLRPC_SEC_TYPE_PRIV);
+ sec_hdr->flavor = cpu_to_le32(PTLRPCS_FLVR_GSS_PRIV);
sec_hdr->msg_len = cpu_to_le32(0);
/* standard gss hdr */
LASSERT(vlen >= 7 * 4);
*vp++ = cpu_to_le32(PTLRPC_SEC_GSS_VERSION);
- *vp++ = cpu_to_le32(PTLRPC_SEC_GSS_KRB5I);
+ *vp++ = cpu_to_le32(PTLRPCS_FLVR_KRB5I);
*vp++ = cpu_to_le32(RPC_GSS_PROC_DATA);
*vp++ = cpu_to_le32(gc->gc_seq);
- *vp++ = cpu_to_le32(PTLRPC_GSS_SVC_PRIVACY);
+ *vp++ = cpu_to_le32(PTLRPCS_GSS_SVC_PRIVACY);
*vp++ = 0; /* fake ctx handle */
vpsave = vp++; /* reserve size */
vlen -= 7 * 4;
void gss_svcsec_cleanup_req(struct ptlrpc_svcsec *svcsec,
struct ptlrpc_request *req)
{
- struct gss_svc_data *gsd = (struct gss_svc_data *) req->rq_sec_svcdata;
+ struct gss_svc_data *gsd = (struct gss_svc_data *) req->rq_svcsec_data;
if (!gsd) {
CDEBUG(D_SEC, "no svc_data present. do nothing\n");
return;
}
- /* gsd->clclred.gc_ctx is NOT allocated, just set pointer
- * to the incoming packet buffer, so don't need free it
- */
+ /* gc_ctx is allocated, see gss_svcsec_accept() */
+ rawobj_free(&gsd->clcred.gc_ctx);
+
OBD_FREE(gsd, sizeof(*gsd));
- req->rq_sec_svcdata = NULL;
+ req->rq_svcsec_data = NULL;
return;
}
struct ptlrpc_request *req,
int msgsize)
{
- struct gss_svc_data *svcdata = req->rq_sec_svcdata;
+ struct gss_svc_data *svcdata = req->rq_svcsec_data;
ENTRY;
/* just return the pre-set reserve_len for init/fini/err cases.
CDEBUG(D_SEC, "is_fini, reserver size 0\n");
RETURN(0);
} else {
- if (svcdata->clcred.gc_svc == PTLRPC_GSS_SVC_NONE ||
- svcdata->clcred.gc_svc == PTLRPC_GSS_SVC_INTEGRITY)
+ if (svcdata->clcred.gc_svc == PTLRPCS_GSS_SVC_NONE ||
+ svcdata->clcred.gc_svc == PTLRPCS_GSS_SVC_INTEGRITY)
RETURN(size_round(GSS_MAX_AUTH_PAYLOAD));
- else if (svcdata->clcred.gc_svc == PTLRPC_GSS_SVC_PRIVACY)
+ else if (svcdata->clcred.gc_svc == PTLRPCS_GSS_SVC_PRIVACY)
RETURN(size_round16(GSS_MAX_AUTH_PAYLOAD + msgsize +
GSS_PRIVBUF_PREFIX_LEN +
GSS_PRIVBUF_SUFFIX_LEN));
struct ptlrpc_request *req,
int msgsize)
{
- struct gss_svc_data *gsd = (struct gss_svc_data *) req->rq_sec_svcdata;
+ struct gss_svc_data *gsd = (struct gss_svc_data *) req->rq_svcsec_data;
struct ptlrpc_reply_state *rs;
int msg_payload, sec_payload;
int privacy, rc;
LASSERT(gsd);
if (!gsd->is_init && !gsd->is_init_continue &&
!gsd->is_fini && !gsd->is_err_notify &&
- gsd->clcred.gc_svc == PTLRPC_GSS_SVC_PRIVACY)
+ gsd->clcred.gc_svc == PTLRPCS_GSS_SVC_PRIVACY)
privacy = 1;
else
privacy = 0;
struct ptlrpc_svcsec svcsec_gss = {
.pss_owner = THIS_MODULE,
- .pss_name = "GSS_SVCSEC",
- .pss_flavor = {PTLRPC_SEC_GSS, 0},
+ .pss_name = "svcsec.gss",
+ .pss_flavor = PTLRPCS_FLVR_MAJOR_GSS,
.accept = gss_svcsec_accept,
.authorize = gss_svcsec_authorize,
.alloc_repbuf = gss_svcsec_alloc_repbuf,
void gss_svc_exit(void)
{
int rc;
- if ((rc = cache_unregister(&rsi_cache)))
- CERROR("unregister rsi cache: %d\n", rc);
+
+ /* XXX rsi didn't take module refcount. without really
+ * cleanup it we can't simply go, later user-space operations
+ * will certainly cause oops.
+ * use space might slow or stuck on something, wait it for
+ * a bit -- bad hack.
+ */
+ while ((rc = cache_unregister(&rsi_cache))) {
+ CERROR("unregister rsi cache: %d. Try again\n", rc);
+ schedule_timeout(2 * HZ);
+ cache_purge(&rsi_cache);
+ }
+
if ((rc = cache_unregister(&rsc_cache)))
CERROR("unregister rsc cache: %d\n", rc);
if ((rc = svcsec_unregister(&svcsec_gss)))