114ae162cSJ. Bruce Fields #include <linux/types.h> 214ae162cSJ. Bruce Fields #include <linux/slab.h> 314ae162cSJ. Bruce Fields #include <linux/jiffies.h> 414ae162cSJ. Bruce Fields #include <linux/sunrpc/gss_krb5.h> 514ae162cSJ. Bruce Fields #include <linux/random.h> 614ae162cSJ. Bruce Fields #include <linux/pagemap.h> 714ae162cSJ. Bruce Fields #include <asm/scatterlist.h> 814ae162cSJ. Bruce Fields #include <linux/crypto.h> 914ae162cSJ. Bruce Fields 1014ae162cSJ. Bruce Fields #ifdef RPC_DEBUG 1114ae162cSJ. Bruce Fields # define RPCDBG_FACILITY RPCDBG_AUTH 1214ae162cSJ. Bruce Fields #endif 1314ae162cSJ. Bruce Fields 1414ae162cSJ. Bruce Fields static inline int 1514ae162cSJ. Bruce Fields gss_krb5_padding(int blocksize, int length) 1614ae162cSJ. Bruce Fields { 1714ae162cSJ. Bruce Fields /* Most of the code is block-size independent but currently we 1814ae162cSJ. Bruce Fields * use only 8: */ 1914ae162cSJ. Bruce Fields BUG_ON(blocksize != 8); 2014ae162cSJ. Bruce Fields return 8 - (length & 7); 2114ae162cSJ. Bruce Fields } 2214ae162cSJ. Bruce Fields 2314ae162cSJ. Bruce Fields static inline void 2414ae162cSJ. Bruce Fields gss_krb5_add_padding(struct xdr_buf *buf, int offset, int blocksize) 2514ae162cSJ. Bruce Fields { 2614ae162cSJ. Bruce Fields int padding = gss_krb5_padding(blocksize, buf->len - offset); 2714ae162cSJ. Bruce Fields char *p; 2814ae162cSJ. Bruce Fields struct kvec *iov; 2914ae162cSJ. Bruce Fields 3014ae162cSJ. Bruce Fields if (buf->page_len || buf->tail[0].iov_len) 3114ae162cSJ. Bruce Fields iov = &buf->tail[0]; 3214ae162cSJ. Bruce Fields else 3314ae162cSJ. Bruce Fields iov = &buf->head[0]; 3414ae162cSJ. Bruce Fields p = iov->iov_base + iov->iov_len; 3514ae162cSJ. Bruce Fields iov->iov_len += padding; 3614ae162cSJ. Bruce Fields buf->len += padding; 3714ae162cSJ. Bruce Fields memset(p, padding, padding); 3814ae162cSJ. Bruce Fields } 3914ae162cSJ. Bruce Fields 4014ae162cSJ. Bruce Fields static inline int 4114ae162cSJ. Bruce Fields gss_krb5_remove_padding(struct xdr_buf *buf, int blocksize) 4214ae162cSJ. Bruce Fields { 4314ae162cSJ. Bruce Fields u8 *ptr; 4414ae162cSJ. Bruce Fields u8 pad; 4514ae162cSJ. Bruce Fields int len = buf->len; 4614ae162cSJ. Bruce Fields 4714ae162cSJ. Bruce Fields if (len <= buf->head[0].iov_len) { 4814ae162cSJ. Bruce Fields pad = *(u8 *)(buf->head[0].iov_base + len - 1); 4914ae162cSJ. Bruce Fields if (pad > buf->head[0].iov_len) 5014ae162cSJ. Bruce Fields return -EINVAL; 5114ae162cSJ. Bruce Fields buf->head[0].iov_len -= pad; 5214ae162cSJ. Bruce Fields goto out; 5314ae162cSJ. Bruce Fields } else 5414ae162cSJ. Bruce Fields len -= buf->head[0].iov_len; 5514ae162cSJ. Bruce Fields if (len <= buf->page_len) { 5614ae162cSJ. Bruce Fields int last = (buf->page_base + len - 1) 5714ae162cSJ. Bruce Fields >>PAGE_CACHE_SHIFT; 5814ae162cSJ. Bruce Fields int offset = (buf->page_base + len - 1) 5914ae162cSJ. Bruce Fields & (PAGE_CACHE_SIZE - 1); 6014ae162cSJ. Bruce Fields ptr = kmap_atomic(buf->pages[last], KM_SKB_SUNRPC_DATA); 6114ae162cSJ. Bruce Fields pad = *(ptr + offset); 6214ae162cSJ. Bruce Fields kunmap_atomic(ptr, KM_SKB_SUNRPC_DATA); 6314ae162cSJ. Bruce Fields goto out; 6414ae162cSJ. Bruce Fields } else 6514ae162cSJ. Bruce Fields len -= buf->page_len; 6614ae162cSJ. Bruce Fields BUG_ON(len > buf->tail[0].iov_len); 6714ae162cSJ. Bruce Fields pad = *(u8 *)(buf->tail[0].iov_base + len - 1); 6814ae162cSJ. Bruce Fields out: 6914ae162cSJ. Bruce Fields /* XXX: NOTE: we do not adjust the page lengths--they represent 7014ae162cSJ. Bruce Fields * a range of data in the real filesystem page cache, and we need 7114ae162cSJ. Bruce Fields * to know that range so the xdr code can properly place read data. 7214ae162cSJ. Bruce Fields * However adjusting the head length, as we do above, is harmless. 7314ae162cSJ. Bruce Fields * In the case of a request that fits into a single page, the server 7414ae162cSJ. Bruce Fields * also uses length and head length together to determine the original 7514ae162cSJ. Bruce Fields * start of the request to copy the request for deferal; so it's 7614ae162cSJ. Bruce Fields * easier on the server if we adjust head and tail length in tandem. 7714ae162cSJ. Bruce Fields * It's not really a problem that we don't fool with the page and 7814ae162cSJ. Bruce Fields * tail lengths, though--at worst badly formed xdr might lead the 7914ae162cSJ. Bruce Fields * server to attempt to parse the padding. 8014ae162cSJ. Bruce Fields * XXX: Document all these weird requirements for gss mechanism 8114ae162cSJ. Bruce Fields * wrap/unwrap functions. */ 8214ae162cSJ. Bruce Fields if (pad > blocksize) 8314ae162cSJ. Bruce Fields return -EINVAL; 8414ae162cSJ. Bruce Fields if (buf->len > pad) 8514ae162cSJ. Bruce Fields buf->len -= pad; 8614ae162cSJ. Bruce Fields else 8714ae162cSJ. Bruce Fields return -EINVAL; 8814ae162cSJ. Bruce Fields return 0; 8914ae162cSJ. Bruce Fields } 9014ae162cSJ. Bruce Fields 9114ae162cSJ. Bruce Fields static inline void 9214ae162cSJ. Bruce Fields make_confounder(char *p, int blocksize) 9314ae162cSJ. Bruce Fields { 9414ae162cSJ. Bruce Fields static u64 i = 0; 9514ae162cSJ. Bruce Fields u64 *q = (u64 *)p; 9614ae162cSJ. Bruce Fields 9714ae162cSJ. Bruce Fields /* rfc1964 claims this should be "random". But all that's really 9814ae162cSJ. Bruce Fields * necessary is that it be unique. And not even that is necessary in 9914ae162cSJ. Bruce Fields * our case since our "gssapi" implementation exists only to support 10014ae162cSJ. Bruce Fields * rpcsec_gss, so we know that the only buffers we will ever encrypt 10114ae162cSJ. Bruce Fields * already begin with a unique sequence number. Just to hedge my bets 10214ae162cSJ. Bruce Fields * I'll make a half-hearted attempt at something unique, but ensuring 10314ae162cSJ. Bruce Fields * uniqueness would mean worrying about atomicity and rollover, and I 10414ae162cSJ. Bruce Fields * don't care enough. */ 10514ae162cSJ. Bruce Fields 10614ae162cSJ. Bruce Fields BUG_ON(blocksize != 8); 10714ae162cSJ. Bruce Fields *q = i++; 10814ae162cSJ. Bruce Fields } 10914ae162cSJ. Bruce Fields 11014ae162cSJ. Bruce Fields /* Assumptions: the head and tail of inbuf are ours to play with. 11114ae162cSJ. Bruce Fields * The pages, however, may be real pages in the page cache and we replace 11214ae162cSJ. Bruce Fields * them with scratch pages from **pages before writing to them. */ 11314ae162cSJ. Bruce Fields /* XXX: obviously the above should be documentation of wrap interface, 11414ae162cSJ. Bruce Fields * and shouldn't be in this kerberos-specific file. */ 11514ae162cSJ. Bruce Fields 11614ae162cSJ. Bruce Fields /* XXX factor out common code with seal/unseal. */ 11714ae162cSJ. Bruce Fields 11814ae162cSJ. Bruce Fields u32 11900fd6e14SJ. Bruce Fields gss_wrap_kerberos(struct gss_ctx *ctx, int offset, 12014ae162cSJ. Bruce Fields struct xdr_buf *buf, struct page **pages) 12114ae162cSJ. Bruce Fields { 12214ae162cSJ. Bruce Fields struct krb5_ctx *kctx = ctx->internal_ctx_id; 12314ae162cSJ. Bruce Fields s32 checksum_type; 1249e57b302SJ. Bruce Fields char cksumdata[16]; 1259e57b302SJ. Bruce Fields struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata}; 12614ae162cSJ. Bruce Fields int blocksize = 0, plainlen; 12714ae162cSJ. Bruce Fields unsigned char *ptr, *krb5_hdr, *msg_start; 12814ae162cSJ. Bruce Fields s32 now; 12914ae162cSJ. Bruce Fields int headlen; 13014ae162cSJ. Bruce Fields struct page **tmp_pages; 13114ae162cSJ. Bruce Fields 13214ae162cSJ. Bruce Fields dprintk("RPC: gss_wrap_kerberos\n"); 13314ae162cSJ. Bruce Fields 13414ae162cSJ. Bruce Fields now = get_seconds(); 13514ae162cSJ. Bruce Fields 13614ae162cSJ. Bruce Fields switch (kctx->signalg) { 13714ae162cSJ. Bruce Fields case SGN_ALG_DES_MAC_MD5: 13814ae162cSJ. Bruce Fields checksum_type = CKSUMTYPE_RSA_MD5; 13914ae162cSJ. Bruce Fields break; 14014ae162cSJ. Bruce Fields default: 14114ae162cSJ. Bruce Fields dprintk("RPC: gss_krb5_seal: kctx->signalg %d not" 14214ae162cSJ. Bruce Fields " supported\n", kctx->signalg); 14314ae162cSJ. Bruce Fields goto out_err; 14414ae162cSJ. Bruce Fields } 14514ae162cSJ. Bruce Fields if (kctx->sealalg != SEAL_ALG_NONE && kctx->sealalg != SEAL_ALG_DES) { 14614ae162cSJ. Bruce Fields dprintk("RPC: gss_krb5_seal: kctx->sealalg %d not supported\n", 14714ae162cSJ. Bruce Fields kctx->sealalg); 14814ae162cSJ. Bruce Fields goto out_err; 14914ae162cSJ. Bruce Fields } 15014ae162cSJ. Bruce Fields 15114ae162cSJ. Bruce Fields blocksize = crypto_tfm_alg_blocksize(kctx->enc); 15214ae162cSJ. Bruce Fields gss_krb5_add_padding(buf, offset, blocksize); 15314ae162cSJ. Bruce Fields BUG_ON((buf->len - offset) % blocksize); 15414ae162cSJ. Bruce Fields plainlen = blocksize + buf->len - offset; 15514ae162cSJ. Bruce Fields 15614ae162cSJ. Bruce Fields headlen = g_token_size(&kctx->mech_used, 22 + plainlen) - 15714ae162cSJ. Bruce Fields (buf->len - offset); 15814ae162cSJ. Bruce Fields 15914ae162cSJ. Bruce Fields ptr = buf->head[0].iov_base + offset; 16014ae162cSJ. Bruce Fields /* shift data to make room for header. */ 16114ae162cSJ. Bruce Fields /* XXX Would be cleverer to encrypt while copying. */ 16214ae162cSJ. Bruce Fields /* XXX bounds checking, slack, etc. */ 16314ae162cSJ. Bruce Fields memmove(ptr + headlen, ptr, buf->head[0].iov_len - offset); 16414ae162cSJ. Bruce Fields buf->head[0].iov_len += headlen; 16514ae162cSJ. Bruce Fields buf->len += headlen; 16614ae162cSJ. Bruce Fields BUG_ON((buf->len - offset - headlen) % blocksize); 16714ae162cSJ. Bruce Fields 16814ae162cSJ. Bruce Fields g_make_token_header(&kctx->mech_used, 22 + plainlen, &ptr); 16914ae162cSJ. Bruce Fields 17014ae162cSJ. Bruce Fields 17114ae162cSJ. Bruce Fields *ptr++ = (unsigned char) ((KG_TOK_WRAP_MSG>>8)&0xff); 17214ae162cSJ. Bruce Fields *ptr++ = (unsigned char) (KG_TOK_WRAP_MSG&0xff); 17314ae162cSJ. Bruce Fields 17414ae162cSJ. Bruce Fields /* ptr now at byte 2 of header described in rfc 1964, section 1.2.1: */ 17514ae162cSJ. Bruce Fields krb5_hdr = ptr - 2; 17614ae162cSJ. Bruce Fields msg_start = krb5_hdr + 24; 17714ae162cSJ. Bruce Fields /* XXXJBF: */ BUG_ON(buf->head[0].iov_base + offset + headlen != msg_start + blocksize); 17814ae162cSJ. Bruce Fields 17914ae162cSJ. Bruce Fields *(u16 *)(krb5_hdr + 2) = htons(kctx->signalg); 18014ae162cSJ. Bruce Fields memset(krb5_hdr + 4, 0xff, 4); 18114ae162cSJ. Bruce Fields *(u16 *)(krb5_hdr + 4) = htons(kctx->sealalg); 18214ae162cSJ. Bruce Fields 18314ae162cSJ. Bruce Fields make_confounder(msg_start, blocksize); 18414ae162cSJ. Bruce Fields 18514ae162cSJ. Bruce Fields /* XXXJBF: UGH!: */ 18614ae162cSJ. Bruce Fields tmp_pages = buf->pages; 18714ae162cSJ. Bruce Fields buf->pages = pages; 18814ae162cSJ. Bruce Fields if (make_checksum(checksum_type, krb5_hdr, 8, buf, 18914ae162cSJ. Bruce Fields offset + headlen - blocksize, &md5cksum)) 19014ae162cSJ. Bruce Fields goto out_err; 19114ae162cSJ. Bruce Fields buf->pages = tmp_pages; 19214ae162cSJ. Bruce Fields 19314ae162cSJ. Bruce Fields switch (kctx->signalg) { 19414ae162cSJ. Bruce Fields case SGN_ALG_DES_MAC_MD5: 19514ae162cSJ. Bruce Fields if (krb5_encrypt(kctx->seq, NULL, md5cksum.data, 19614ae162cSJ. Bruce Fields md5cksum.data, md5cksum.len)) 19714ae162cSJ. Bruce Fields goto out_err; 19814ae162cSJ. Bruce Fields memcpy(krb5_hdr + 16, 19914ae162cSJ. Bruce Fields md5cksum.data + md5cksum.len - KRB5_CKSUM_LENGTH, 20014ae162cSJ. Bruce Fields KRB5_CKSUM_LENGTH); 20114ae162cSJ. Bruce Fields 20214ae162cSJ. Bruce Fields dprintk("RPC: make_seal_token: cksum data: \n"); 20314ae162cSJ. Bruce Fields print_hexl((u32 *) (krb5_hdr + 16), KRB5_CKSUM_LENGTH, 0); 20414ae162cSJ. Bruce Fields break; 20514ae162cSJ. Bruce Fields default: 20614ae162cSJ. Bruce Fields BUG(); 20714ae162cSJ. Bruce Fields } 20814ae162cSJ. Bruce Fields 20914ae162cSJ. Bruce Fields /* XXX would probably be more efficient to compute checksum 21014ae162cSJ. Bruce Fields * and encrypt at the same time: */ 21114ae162cSJ. Bruce Fields if ((krb5_make_seq_num(kctx->seq, kctx->initiate ? 0 : 0xff, 21214ae162cSJ. Bruce Fields kctx->seq_send, krb5_hdr + 16, krb5_hdr + 8))) 21314ae162cSJ. Bruce Fields goto out_err; 21414ae162cSJ. Bruce Fields 21514ae162cSJ. Bruce Fields if (gss_encrypt_xdr_buf(kctx->enc, buf, offset + headlen - blocksize, 21614ae162cSJ. Bruce Fields pages)) 21714ae162cSJ. Bruce Fields goto out_err; 21814ae162cSJ. Bruce Fields 21914ae162cSJ. Bruce Fields kctx->seq_send++; 22014ae162cSJ. Bruce Fields 22114ae162cSJ. Bruce Fields return ((kctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE); 22214ae162cSJ. Bruce Fields out_err: 22314ae162cSJ. Bruce Fields return GSS_S_FAILURE; 22414ae162cSJ. Bruce Fields } 22514ae162cSJ. Bruce Fields 22614ae162cSJ. Bruce Fields u32 22700fd6e14SJ. Bruce Fields gss_unwrap_kerberos(struct gss_ctx *ctx, int offset, struct xdr_buf *buf) 22814ae162cSJ. Bruce Fields { 22914ae162cSJ. Bruce Fields struct krb5_ctx *kctx = ctx->internal_ctx_id; 23014ae162cSJ. Bruce Fields int signalg; 23114ae162cSJ. Bruce Fields int sealalg; 23214ae162cSJ. Bruce Fields s32 checksum_type; 2339e57b302SJ. Bruce Fields char cksumdata[16]; 2349e57b302SJ. Bruce Fields struct xdr_netobj md5cksum = {.len = 0, .data = cksumdata}; 23514ae162cSJ. Bruce Fields s32 now; 23614ae162cSJ. Bruce Fields int direction; 23714ae162cSJ. Bruce Fields s32 seqnum; 23814ae162cSJ. Bruce Fields unsigned char *ptr; 23914ae162cSJ. Bruce Fields int bodysize; 24014ae162cSJ. Bruce Fields u32 ret = GSS_S_DEFECTIVE_TOKEN; 24114ae162cSJ. Bruce Fields void *data_start, *orig_start; 24214ae162cSJ. Bruce Fields int data_len; 24314ae162cSJ. Bruce Fields int blocksize; 24414ae162cSJ. Bruce Fields 24514ae162cSJ. Bruce Fields dprintk("RPC: gss_unwrap_kerberos\n"); 24614ae162cSJ. Bruce Fields 24714ae162cSJ. Bruce Fields ptr = (u8 *)buf->head[0].iov_base + offset; 24814ae162cSJ. Bruce Fields if (g_verify_token_header(&kctx->mech_used, &bodysize, &ptr, 24914ae162cSJ. Bruce Fields buf->len - offset)) 25014ae162cSJ. Bruce Fields goto out; 25114ae162cSJ. Bruce Fields 25214ae162cSJ. Bruce Fields if ((*ptr++ != ((KG_TOK_WRAP_MSG>>8)&0xff)) || 25314ae162cSJ. Bruce Fields (*ptr++ != (KG_TOK_WRAP_MSG &0xff)) ) 25414ae162cSJ. Bruce Fields goto out; 25514ae162cSJ. Bruce Fields 25614ae162cSJ. Bruce Fields /* XXX sanity-check bodysize?? */ 25714ae162cSJ. Bruce Fields 25814ae162cSJ. Bruce Fields /* get the sign and seal algorithms */ 25914ae162cSJ. Bruce Fields 26014ae162cSJ. Bruce Fields signalg = ptr[0] + (ptr[1] << 8); 26114ae162cSJ. Bruce Fields sealalg = ptr[2] + (ptr[3] << 8); 26214ae162cSJ. Bruce Fields 26314ae162cSJ. Bruce Fields /* Sanity checks */ 26414ae162cSJ. Bruce Fields 26514ae162cSJ. Bruce Fields if ((ptr[4] != 0xff) || (ptr[5] != 0xff)) 26614ae162cSJ. Bruce Fields goto out; 26714ae162cSJ. Bruce Fields 26814ae162cSJ. Bruce Fields if (sealalg == 0xffff) 26914ae162cSJ. Bruce Fields goto out; 27014ae162cSJ. Bruce Fields 27114ae162cSJ. Bruce Fields /* in the current spec, there is only one valid seal algorithm per 27214ae162cSJ. Bruce Fields key type, so a simple comparison is ok */ 27314ae162cSJ. Bruce Fields 27414ae162cSJ. Bruce Fields if (sealalg != kctx->sealalg) 27514ae162cSJ. Bruce Fields goto out; 27614ae162cSJ. Bruce Fields 27714ae162cSJ. Bruce Fields /* there are several mappings of seal algorithms to sign algorithms, 27814ae162cSJ. Bruce Fields but few enough that we can try them all. */ 27914ae162cSJ. Bruce Fields 28014ae162cSJ. Bruce Fields if ((kctx->sealalg == SEAL_ALG_NONE && signalg > 1) || 28114ae162cSJ. Bruce Fields (kctx->sealalg == SEAL_ALG_1 && signalg != SGN_ALG_3) || 28214ae162cSJ. Bruce Fields (kctx->sealalg == SEAL_ALG_DES3KD && 28314ae162cSJ. Bruce Fields signalg != SGN_ALG_HMAC_SHA1_DES3_KD)) 28414ae162cSJ. Bruce Fields goto out; 28514ae162cSJ. Bruce Fields 28614ae162cSJ. Bruce Fields if (gss_decrypt_xdr_buf(kctx->enc, buf, 28714ae162cSJ. Bruce Fields ptr + 22 - (unsigned char *)buf->head[0].iov_base)) 28814ae162cSJ. Bruce Fields goto out; 28914ae162cSJ. Bruce Fields 29014ae162cSJ. Bruce Fields /* compute the checksum of the message */ 29114ae162cSJ. Bruce Fields 29214ae162cSJ. Bruce Fields /* initialize the the cksum */ 29314ae162cSJ. Bruce Fields switch (signalg) { 29414ae162cSJ. Bruce Fields case SGN_ALG_DES_MAC_MD5: 29514ae162cSJ. Bruce Fields checksum_type = CKSUMTYPE_RSA_MD5; 29614ae162cSJ. Bruce Fields break; 29714ae162cSJ. Bruce Fields default: 29814ae162cSJ. Bruce Fields ret = GSS_S_DEFECTIVE_TOKEN; 29914ae162cSJ. Bruce Fields goto out; 30014ae162cSJ. Bruce Fields } 30114ae162cSJ. Bruce Fields 30214ae162cSJ. Bruce Fields switch (signalg) { 30314ae162cSJ. Bruce Fields case SGN_ALG_DES_MAC_MD5: 30414ae162cSJ. Bruce Fields ret = make_checksum(checksum_type, ptr - 2, 8, buf, 30514ae162cSJ. Bruce Fields ptr + 22 - (unsigned char *)buf->head[0].iov_base, &md5cksum); 30614ae162cSJ. Bruce Fields if (ret) 30714ae162cSJ. Bruce Fields goto out; 30814ae162cSJ. Bruce Fields 30914ae162cSJ. Bruce Fields ret = krb5_encrypt(kctx->seq, NULL, md5cksum.data, 31014ae162cSJ. Bruce Fields md5cksum.data, md5cksum.len); 31114ae162cSJ. Bruce Fields if (ret) 31214ae162cSJ. Bruce Fields goto out; 31314ae162cSJ. Bruce Fields 31414ae162cSJ. Bruce Fields if (memcmp(md5cksum.data + 8, ptr + 14, 8)) { 31514ae162cSJ. Bruce Fields ret = GSS_S_BAD_SIG; 31614ae162cSJ. Bruce Fields goto out; 31714ae162cSJ. Bruce Fields } 31814ae162cSJ. Bruce Fields break; 31914ae162cSJ. Bruce Fields default: 32014ae162cSJ. Bruce Fields ret = GSS_S_DEFECTIVE_TOKEN; 32114ae162cSJ. Bruce Fields goto out; 32214ae162cSJ. Bruce Fields } 32314ae162cSJ. Bruce Fields 32414ae162cSJ. Bruce Fields /* it got through unscathed. Make sure the context is unexpired */ 32514ae162cSJ. Bruce Fields 32614ae162cSJ. Bruce Fields now = get_seconds(); 32714ae162cSJ. Bruce Fields 32814ae162cSJ. Bruce Fields ret = GSS_S_CONTEXT_EXPIRED; 32914ae162cSJ. Bruce Fields if (now > kctx->endtime) 33014ae162cSJ. Bruce Fields goto out; 33114ae162cSJ. Bruce Fields 33214ae162cSJ. Bruce Fields /* do sequencing checks */ 33314ae162cSJ. Bruce Fields 33414ae162cSJ. Bruce Fields ret = GSS_S_BAD_SIG; 33514ae162cSJ. Bruce Fields if ((ret = krb5_get_seq_num(kctx->seq, ptr + 14, ptr + 6, &direction, 33614ae162cSJ. Bruce Fields &seqnum))) 33714ae162cSJ. Bruce Fields goto out; 33814ae162cSJ. Bruce Fields 33914ae162cSJ. Bruce Fields if ((kctx->initiate && direction != 0xff) || 34014ae162cSJ. Bruce Fields (!kctx->initiate && direction != 0)) 34114ae162cSJ. Bruce Fields goto out; 34214ae162cSJ. Bruce Fields 34314ae162cSJ. Bruce Fields /* Copy the data back to the right position. XXX: Would probably be 34414ae162cSJ. Bruce Fields * better to copy and encrypt at the same time. */ 34514ae162cSJ. Bruce Fields 34614ae162cSJ. Bruce Fields blocksize = crypto_tfm_alg_blocksize(kctx->enc); 34714ae162cSJ. Bruce Fields data_start = ptr + 22 + blocksize; 34814ae162cSJ. Bruce Fields orig_start = buf->head[0].iov_base + offset; 34914ae162cSJ. Bruce Fields data_len = (buf->head[0].iov_base + buf->head[0].iov_len) - data_start; 35014ae162cSJ. Bruce Fields memmove(orig_start, data_start, data_len); 35114ae162cSJ. Bruce Fields buf->head[0].iov_len -= (data_start - orig_start); 35214ae162cSJ. Bruce Fields buf->len -= (data_start - orig_start); 35314ae162cSJ. Bruce Fields 35414ae162cSJ. Bruce Fields ret = GSS_S_DEFECTIVE_TOKEN; 35514ae162cSJ. Bruce Fields if (gss_krb5_remove_padding(buf, blocksize)) 35614ae162cSJ. Bruce Fields goto out; 35714ae162cSJ. Bruce Fields 35814ae162cSJ. Bruce Fields ret = GSS_S_COMPLETE; 35914ae162cSJ. Bruce Fields out: 36014ae162cSJ. Bruce Fields return ret; 36114ae162cSJ. Bruce Fields } 362