2019-05-27 09:55:05 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2007-07-13 04:33:32 +04:00
/*
2005-04-17 02:20:36 +04:00
* The ASB .1 / BER parsing code is derived from ip_nat_snmp_basic . c which was in
* turn derived from the gxsnmp package by Gregory McLean & Jochen Friedrich
2007-07-13 04:33:32 +04:00
*
2005-04-17 02:20:36 +04:00
* Copyright ( c ) 2000 RP Internet ( www . rpi . net . au ) .
*/
# include <linux/module.h>
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/mm.h>
# include <linux/slab.h>
# include "cifspdu.h"
# include "cifsglob.h"
# include "cifs_debug.h"
# include "cifsproto.h"
/*****************************************************************************
*
* Basic ASN .1 decoding routines ( gxsnmp author Dirk Wisse )
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Class */
# define ASN1_UNI 0 /* Universal */
# define ASN1_APL 1 /* Application */
# define ASN1_CTX 2 /* Context */
# define ASN1_PRV 3 /* Private */
/* Tag */
# define ASN1_EOC 0 /* End Of Contents or N/A */
# define ASN1_BOL 1 /* Boolean */
# define ASN1_INT 2 /* Integer */
# define ASN1_BTS 3 /* Bit String */
# define ASN1_OTS 4 /* Octet String */
# define ASN1_NUL 5 /* Null */
# define ASN1_OJI 6 /* Object Identifier */
# define ASN1_OJD 7 /* Object Description */
# define ASN1_EXT 8 /* External */
2009-06-25 07:04:20 +04:00
# define ASN1_ENUM 10 /* Enumerated */
2005-04-17 02:20:36 +04:00
# define ASN1_SEQ 16 /* Sequence */
# define ASN1_SET 17 /* Set */
# define ASN1_NUMSTR 18 /* Numerical String */
# define ASN1_PRNSTR 19 /* Printable String */
# define ASN1_TEXSTR 20 /* Teletext String */
# define ASN1_VIDSTR 21 /* Video String */
# define ASN1_IA5STR 22 /* IA5 String */
# define ASN1_UNITIM 23 /* Universal Time */
# define ASN1_GENTIM 24 /* General Time */
# define ASN1_GRASTR 25 /* Graphical String */
# define ASN1_VISSTR 26 /* Visible String */
# define ASN1_GENSTR 27 /* General String */
/* Primitive / Constructed methods*/
# define ASN1_PRI 0 /* Primitive */
# define ASN1_CON 1 /* Constructed */
/*
* Error codes .
*/
# define ASN1_ERR_NOERROR 0
# define ASN1_ERR_DEC_EMPTY 2
# define ASN1_ERR_DEC_EOC_MISMATCH 3
# define ASN1_ERR_DEC_LENGTH_MISMATCH 4
# define ASN1_ERR_DEC_BADVALUE 5
# define SPNEGO_OID_LEN 7
# define NTLMSSP_OID_LEN 10
2007-11-03 08:11:06 +03:00
# define KRB5_OID_LEN 7
2009-06-25 07:04:20 +04:00
# define KRB5U2U_OID_LEN 8
2007-11-03 08:11:06 +03:00
# define MSKRB5_OID_LEN 7
2005-04-17 02:20:36 +04:00
static unsigned long SPNEGO_OID [ 7 ] = { 1 , 3 , 6 , 1 , 5 , 5 , 2 } ;
static unsigned long NTLMSSP_OID [ 10 ] = { 1 , 3 , 6 , 1 , 4 , 1 , 311 , 2 , 2 , 10 } ;
2007-11-03 08:11:06 +03:00
static unsigned long KRB5_OID [ 7 ] = { 1 , 2 , 840 , 113554 , 1 , 2 , 2 } ;
2009-06-25 07:04:20 +04:00
static unsigned long KRB5U2U_OID [ 8 ] = { 1 , 2 , 840 , 113554 , 1 , 2 , 2 , 3 } ;
2007-11-03 08:11:06 +03:00
static unsigned long MSKRB5_OID [ 7 ] = { 1 , 2 , 840 , 48018 , 1 , 2 , 2 } ;
2005-04-17 02:20:36 +04:00
2007-07-13 04:33:32 +04:00
/*
2005-04-17 02:20:36 +04:00
* ASN .1 context .
*/
struct asn1_ctx {
int error ; /* Error condition */
unsigned char * pointer ; /* Octet just to be decoded */
unsigned char * begin ; /* First octet */
unsigned char * end ; /* Octet after last octet */
} ;
/*
* Octet string ( not null terminated )
*/
struct asn1_octstr {
unsigned char * data ;
unsigned int len ;
} ;
static void
asn1_open ( struct asn1_ctx * ctx , unsigned char * buf , unsigned int len )
{
ctx - > begin = buf ;
ctx - > end = buf + len ;
ctx - > pointer = buf ;
ctx - > error = ASN1_ERR_NOERROR ;
}
static unsigned char
asn1_octet_decode ( struct asn1_ctx * ctx , unsigned char * ch )
{
if ( ctx - > pointer > = ctx - > end ) {
ctx - > error = ASN1_ERR_DEC_EMPTY ;
return 0 ;
}
* ch = * ( ctx - > pointer ) + + ;
return 1 ;
}
2009-06-25 07:04:20 +04:00
#if 0 /* will be needed later by spnego decoding/encoding of ntlmssp */
static unsigned char
asn1_enum_decode ( struct asn1_ctx * ctx , __le32 * val )
{
unsigned char ch ;
if ( ctx - > pointer > = ctx - > end ) {
ctx - > error = ASN1_ERR_DEC_EMPTY ;
return 0 ;
}
2010-01-29 10:57:49 +03:00
ch = * ( ctx - > pointer ) + + ; /* ch has 0xa, ptr points to length octet */
2009-06-25 07:04:20 +04:00
if ( ( ch ) = = ASN1_ENUM ) /* if ch value is ENUM, 0xa */
* val = * ( + + ( ctx - > pointer ) ) ; /* value has enum value */
else
return 0 ;
ctx - > pointer + + ;
return 1 ;
}
# endif
2005-04-17 02:20:36 +04:00
static unsigned char
asn1_tag_decode ( struct asn1_ctx * ctx , unsigned int * tag )
{
unsigned char ch ;
* tag = 0 ;
do {
if ( ! asn1_octet_decode ( ctx , & ch ) )
return 0 ;
* tag < < = 7 ;
* tag | = ch & 0x7F ;
} while ( ( ch & 0x80 ) = = 0x80 ) ;
return 1 ;
}
static unsigned char
asn1_id_decode ( struct asn1_ctx * ctx ,
unsigned int * cls , unsigned int * con , unsigned int * tag )
{
unsigned char ch ;
if ( ! asn1_octet_decode ( ctx , & ch ) )
return 0 ;
* cls = ( ch & 0xC0 ) > > 6 ;
* con = ( ch & 0x20 ) > > 5 ;
* tag = ( ch & 0x1F ) ;
if ( * tag = = 0x1F ) {
if ( ! asn1_tag_decode ( ctx , tag ) )
return 0 ;
}
return 1 ;
}
static unsigned char
asn1_length_decode ( struct asn1_ctx * ctx , unsigned int * def , unsigned int * len )
{
unsigned char ch , cnt ;
if ( ! asn1_octet_decode ( ctx , & ch ) )
return 0 ;
if ( ch = = 0x80 )
* def = 0 ;
else {
* def = 1 ;
if ( ch < 0x80 )
* len = ch ;
else {
cnt = ( unsigned char ) ( ch & 0x7F ) ;
* len = 0 ;
while ( cnt > 0 ) {
if ( ! asn1_octet_decode ( ctx , & ch ) )
return 0 ;
* len < < = 8 ;
* len | = ch ;
cnt - - ;
}
}
}
2008-06-04 20:16:33 +04:00
/* don't trust len bigger than ctx buffer */
if ( * len > ctx - > end - ctx - > pointer )
return 0 ;
2005-04-17 02:20:36 +04:00
return 1 ;
}
static unsigned char
asn1_header_decode ( struct asn1_ctx * ctx ,
unsigned char * * eoc ,
unsigned int * cls , unsigned int * con , unsigned int * tag )
{
2007-07-13 04:33:32 +04:00
unsigned int def = 0 ;
2005-09-16 07:44:50 +04:00
unsigned int len = 0 ;
2005-04-17 02:20:36 +04:00
if ( ! asn1_id_decode ( ctx , cls , con , tag ) )
return 0 ;
if ( ! asn1_length_decode ( ctx , & def , & len ) )
return 0 ;
2008-06-04 20:16:33 +04:00
/* primitive shall be definite, indefinite shall be constructed */
if ( * con = = ASN1_PRI & & ! def )
return 0 ;
2005-04-17 02:20:36 +04:00
if ( def )
* eoc = ctx - > pointer + len ;
else
* eoc = NULL ;
return 1 ;
}
static unsigned char
asn1_eoc_decode ( struct asn1_ctx * ctx , unsigned char * eoc )
{
unsigned char ch ;
if ( eoc = = NULL ) {
if ( ! asn1_octet_decode ( ctx , & ch ) )
return 0 ;
if ( ch ! = 0x00 ) {
ctx - > error = ASN1_ERR_DEC_EOC_MISMATCH ;
return 0 ;
}
if ( ! asn1_octet_decode ( ctx , & ch ) )
return 0 ;
if ( ch ! = 0x00 ) {
ctx - > error = ASN1_ERR_DEC_EOC_MISMATCH ;
return 0 ;
}
return 1 ;
} else {
if ( ctx - > pointer ! = eoc ) {
ctx - > error = ASN1_ERR_DEC_LENGTH_MISMATCH ;
return 0 ;
}
return 1 ;
}
}
/* static unsigned char asn1_null_decode(struct asn1_ctx *ctx,
unsigned char * eoc )
{
ctx - > pointer = eoc ;
return 1 ;
}
static unsigned char asn1_long_decode ( struct asn1_ctx * ctx ,
unsigned char * eoc , long * integer )
{
unsigned char ch ;
unsigned int len ;
if ( ! asn1_octet_decode ( ctx , & ch ) )
return 0 ;
* integer = ( signed char ) ch ;
len = 1 ;
while ( ctx - > pointer < eoc ) {
if ( + + len > sizeof ( long ) ) {
ctx - > error = ASN1_ERR_DEC_BADVALUE ;
return 0 ;
}
if ( ! asn1_octet_decode ( ctx , & ch ) )
return 0 ;
* integer < < = 8 ;
* integer | = ch ;
}
return 1 ;
}
static unsigned char asn1_uint_decode ( struct asn1_ctx * ctx ,
unsigned char * eoc ,
unsigned int * integer )
{
unsigned char ch ;
unsigned int len ;
if ( ! asn1_octet_decode ( ctx , & ch ) )
return 0 ;
* integer = ch ;
if ( ch = = 0 )
len = 0 ;
else
len = 1 ;
while ( ctx - > pointer < eoc ) {
if ( + + len > sizeof ( unsigned int ) ) {
ctx - > error = ASN1_ERR_DEC_BADVALUE ;
return 0 ;
}
if ( ! asn1_octet_decode ( ctx , & ch ) )
return 0 ;
* integer < < = 8 ;
* integer | = ch ;
}
return 1 ;
}
static unsigned char asn1_ulong_decode ( struct asn1_ctx * ctx ,
unsigned char * eoc ,
unsigned long * integer )
{
unsigned char ch ;
unsigned int len ;
if ( ! asn1_octet_decode ( ctx , & ch ) )
return 0 ;
* integer = ch ;
if ( ch = = 0 )
len = 0 ;
else
len = 1 ;
while ( ctx - > pointer < eoc ) {
if ( + + len > sizeof ( unsigned long ) ) {
ctx - > error = ASN1_ERR_DEC_BADVALUE ;
return 0 ;
}
if ( ! asn1_octet_decode ( ctx , & ch ) )
return 0 ;
* integer < < = 8 ;
* integer | = ch ;
}
return 1 ;
2007-07-13 04:33:32 +04:00
}
2005-04-17 02:20:36 +04:00
static unsigned char
asn1_octets_decode ( struct asn1_ctx * ctx ,
unsigned char * eoc ,
unsigned char * * octets , unsigned int * len )
{
unsigned char * ptr ;
* len = 0 ;
* octets = kmalloc ( eoc - ctx - > pointer , GFP_ATOMIC ) ;
if ( * octets = = NULL ) {
return 0 ;
}
ptr = * octets ;
while ( ctx - > pointer < eoc ) {
if ( ! asn1_octet_decode ( ctx , ( unsigned char * ) ptr + + ) ) {
kfree ( * octets ) ;
* octets = NULL ;
return 0 ;
}
( * len ) + + ;
}
return 1 ;
} */
static unsigned char
asn1_subid_decode ( struct asn1_ctx * ctx , unsigned long * subid )
{
unsigned char ch ;
* subid = 0 ;
do {
if ( ! asn1_octet_decode ( ctx , & ch ) )
return 0 ;
* subid < < = 7 ;
* subid | = ch & 0x7F ;
} while ( ( ch & 0x80 ) = = 0x80 ) ;
return 1 ;
}
2007-07-13 04:33:32 +04:00
static int
2005-04-17 02:20:36 +04:00
asn1_oid_decode ( struct asn1_ctx * ctx ,
unsigned char * eoc , unsigned long * * oid , unsigned int * len )
{
unsigned long subid ;
unsigned int size ;
unsigned long * optr ;
size = eoc - ctx - > pointer + 1 ;
2008-06-04 20:16:33 +04:00
/* first subid actually encodes first two subids */
2008-07-22 17:04:18 +04:00
if ( size < 2 | | size > UINT_MAX / sizeof ( unsigned long ) )
2008-06-04 20:16:33 +04:00
return 0 ;
treewide: kmalloc() -> kmalloc_array()
The kmalloc() function has a 2-factor argument form, kmalloc_array(). This
patch replaces cases of:
kmalloc(a * b, gfp)
with:
kmalloc_array(a * b, gfp)
as well as handling cases of:
kmalloc(a * b * c, gfp)
with:
kmalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kmalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kmalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The tools/ directory was manually excluded, since it has its own
implementation of kmalloc().
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kmalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kmalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kmalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kmalloc
+ kmalloc_array
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kmalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kmalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kmalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kmalloc(sizeof(THING) * C2, ...)
|
kmalloc(sizeof(TYPE) * C2, ...)
|
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(C1 * C2, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * E2
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-12 23:55:00 +03:00
* oid = kmalloc_array ( size , sizeof ( unsigned long ) , GFP_ATOMIC ) ;
2007-08-31 02:09:15 +04:00
if ( * oid = = NULL )
2005-04-17 02:20:36 +04:00
return 0 ;
optr = * oid ;
if ( ! asn1_subid_decode ( ctx , & subid ) ) {
kfree ( * oid ) ;
* oid = NULL ;
return 0 ;
}
if ( subid < 40 ) {
optr [ 0 ] = 0 ;
optr [ 1 ] = subid ;
} else if ( subid < 80 ) {
optr [ 0 ] = 1 ;
optr [ 1 ] = subid - 40 ;
} else {
optr [ 0 ] = 2 ;
optr [ 1 ] = subid - 80 ;
}
* len = 2 ;
optr + = 2 ;
while ( ctx - > pointer < eoc ) {
if ( + + ( * len ) > size ) {
ctx - > error = ASN1_ERR_DEC_BADVALUE ;
kfree ( * oid ) ;
* oid = NULL ;
return 0 ;
}
if ( ! asn1_subid_decode ( ctx , optr + + ) ) {
kfree ( * oid ) ;
* oid = NULL ;
return 0 ;
}
}
return 1 ;
}
static int
compare_oid ( unsigned long * oid1 , unsigned int oid1len ,
unsigned long * oid2 , unsigned int oid2len )
{
unsigned int i ;
if ( oid1len ! = oid2len )
return 0 ;
else {
for ( i = 0 ; i < oid1len ; i + + ) {
if ( oid1 [ i ] ! = oid2 [ i ] )
return 0 ;
}
return 1 ;
}
}
/* BB check for endian conversion issues here */
int
decode_negTokenInit ( unsigned char * security_blob , int length ,
2010-04-24 15:57:49 +04:00
struct TCP_Server_Info * server )
2005-04-17 02:20:36 +04:00
{
struct asn1_ctx ctx ;
unsigned char * end ;
unsigned char * sequence_end ;
unsigned long * oid = NULL ;
unsigned int cls , con , tag , oidlen , rc ;
/* cifs_dump_mem(" Received SecBlob ", security_blob, length); */
asn1_open ( & ctx , security_blob , length ) ;
2008-08-01 01:30:11 +04:00
/* GSSAPI header */
2005-04-17 02:20:36 +04:00
if ( asn1_header_decode ( & ctx , & end , & cls , & con , & tag ) = = 0 ) {
2013-05-05 07:12:25 +04:00
cifs_dbg ( FYI , " Error decoding negTokenInit header \n " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
} else if ( ( cls ! = ASN1_APL ) | | ( con ! = ASN1_CON )
| | ( tag ! = ASN1_EOC ) ) {
2013-05-05 07:12:25 +04:00
cifs_dbg ( FYI , " cls = %d con = %d tag = %d \n " , cls , con , tag ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
2008-08-01 01:30:11 +04:00
}
2005-04-17 02:20:36 +04:00
2008-08-01 01:30:11 +04:00
/* Check for SPNEGO OID -- remember to free obj->oid */
rc = asn1_header_decode ( & ctx , & end , & cls , & con , & tag ) ;
if ( rc ) {
if ( ( tag = = ASN1_OJI ) & & ( con = = ASN1_PRI ) & &
( cls = = ASN1_UNI ) ) {
rc = asn1_oid_decode ( & ctx , end , & oid , & oidlen ) ;
if ( rc ) {
rc = compare_oid ( oid , oidlen , SPNEGO_OID ,
SPNEGO_OID_LEN ) ;
kfree ( oid ) ;
}
} else
rc = 0 ;
}
2005-04-17 02:20:36 +04:00
2008-08-01 01:30:11 +04:00
/* SPNEGO OID not present or garbled -- bail out */
if ( ! rc ) {
2013-05-05 07:12:25 +04:00
cifs_dbg ( FYI , " Error decoding negTokenInit header \n " ) ;
2008-08-01 01:30:11 +04:00
return 0 ;
}
2005-04-17 02:20:36 +04:00
2009-06-25 07:04:20 +04:00
/* SPNEGO */
2008-08-01 01:30:11 +04:00
if ( asn1_header_decode ( & ctx , & end , & cls , & con , & tag ) = = 0 ) {
2013-05-05 07:12:25 +04:00
cifs_dbg ( FYI , " Error decoding negTokenInit \n " ) ;
2008-08-01 01:30:11 +04:00
return 0 ;
} else if ( ( cls ! = ASN1_CTX ) | | ( con ! = ASN1_CON )
| | ( tag ! = ASN1_EOC ) ) {
2013-05-05 07:12:25 +04:00
cifs_dbg ( FYI , " cls = %d con = %d tag = %d end = %p (%d) exit 0 \n " ,
cls , con , tag , end , * end ) ;
2008-08-01 01:30:11 +04:00
return 0 ;
}
2005-04-17 02:20:36 +04:00
2009-06-25 07:04:20 +04:00
/* negTokenInit */
2008-08-01 01:30:11 +04:00
if ( asn1_header_decode ( & ctx , & end , & cls , & con , & tag ) = = 0 ) {
2013-05-05 07:12:25 +04:00
cifs_dbg ( FYI , " Error decoding negTokenInit \n " ) ;
2008-08-01 01:30:11 +04:00
return 0 ;
} else if ( ( cls ! = ASN1_UNI ) | | ( con ! = ASN1_CON )
| | ( tag ! = ASN1_SEQ ) ) {
2013-05-05 07:12:25 +04:00
cifs_dbg ( FYI , " cls = %d con = %d tag = %d end = %p (%d) exit 1 \n " ,
cls , con , tag , end , * end ) ;
2008-08-01 01:30:11 +04:00
return 0 ;
}
2005-04-17 02:20:36 +04:00
2009-06-25 07:04:20 +04:00
/* sequence */
2008-08-01 01:30:11 +04:00
if ( asn1_header_decode ( & ctx , & end , & cls , & con , & tag ) = = 0 ) {
2013-05-05 07:12:25 +04:00
cifs_dbg ( FYI , " Error decoding 2nd part of negTokenInit \n " ) ;
2008-08-01 01:30:11 +04:00
return 0 ;
} else if ( ( cls ! = ASN1_CTX ) | | ( con ! = ASN1_CON )
| | ( tag ! = ASN1_EOC ) ) {
2013-05-05 07:12:25 +04:00
cifs_dbg ( FYI , " cls = %d con = %d tag = %d end = %p (%d) exit 0 \n " ,
cls , con , tag , end , * end ) ;
2008-08-01 01:30:11 +04:00
return 0 ;
}
2005-04-17 02:20:36 +04:00
2009-06-25 07:04:20 +04:00
/* sequence of */
2008-08-01 01:30:11 +04:00
if ( asn1_header_decode
( & ctx , & sequence_end , & cls , & con , & tag ) = = 0 ) {
2013-05-05 07:12:25 +04:00
cifs_dbg ( FYI , " Error decoding 2nd part of negTokenInit \n " ) ;
2008-08-01 01:30:11 +04:00
return 0 ;
} else if ( ( cls ! = ASN1_UNI ) | | ( con ! = ASN1_CON )
| | ( tag ! = ASN1_SEQ ) ) {
2013-05-05 07:12:25 +04:00
cifs_dbg ( FYI , " cls = %d con = %d tag = %d end = %p (%d) exit 1 \n " ,
cls , con , tag , end , * end ) ;
2008-08-01 01:30:11 +04:00
return 0 ;
}
2005-04-17 02:20:36 +04:00
2009-06-25 07:04:20 +04:00
/* list of security mechanisms */
2008-08-01 01:30:11 +04:00
while ( ! asn1_eoc_decode ( & ctx , sequence_end ) ) {
rc = asn1_header_decode ( & ctx , & end , & cls , & con , & tag ) ;
if ( ! rc ) {
2013-05-05 07:12:25 +04:00
cifs_dbg ( FYI , " Error decoding negTokenInit hdr exit2 \n " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2008-08-01 01:30:11 +04:00
if ( ( tag = = ASN1_OJI ) & & ( con = = ASN1_PRI ) ) {
if ( asn1_oid_decode ( & ctx , end , & oid , & oidlen ) ) {
2013-05-05 07:12:25 +04:00
cifs_dbg ( FYI , " OID len = %d oid = 0x%lx 0x%lx 0x%lx 0x%lx \n " ,
oidlen , * oid , * ( oid + 1 ) , * ( oid + 2 ) ,
* ( oid + 3 ) ) ;
2008-08-01 01:30:11 +04:00
if ( compare_oid ( oid , oidlen , MSKRB5_OID ,
2010-04-24 15:57:49 +04:00
MSKRB5_OID_LEN ) )
server - > sec_mskerberos = true ;
2010-09-09 01:10:58 +04:00
else if ( compare_oid ( oid , oidlen , KRB5U2U_OID ,
2010-04-24 15:57:49 +04:00
KRB5U2U_OID_LEN ) )
server - > sec_kerberosu2u = true ;
2010-09-09 01:10:58 +04:00
else if ( compare_oid ( oid , oidlen , KRB5_OID ,
2010-04-24 15:57:49 +04:00
KRB5_OID_LEN ) )
server - > sec_kerberos = true ;
2010-09-09 01:10:58 +04:00
else if ( compare_oid ( oid , oidlen , NTLMSSP_OID ,
2008-08-01 01:30:11 +04:00
NTLMSSP_OID_LEN ) )
2010-04-24 15:57:49 +04:00
server - > sec_ntlmssp = true ;
2008-08-01 01:30:11 +04:00
kfree ( oid ) ;
}
} else {
2013-05-05 07:12:25 +04:00
cifs_dbg ( FYI , " Should be an oid what is going on? \n " ) ;
2005-04-17 02:20:36 +04:00
}
2008-08-01 01:30:11 +04:00
}
2005-04-17 02:20:36 +04:00
2013-03-11 17:52:19 +04:00
/*
* We currently ignore anything at the end of the SPNEGO blob after
* the mechTypes have been parsed , since none of that info is
* used at the moment .
*/
2005-04-17 02:20:36 +04:00
return 1 ;
}