Merge from HEAD - make Samba compile with -Wwrite-strings without additional
[tprouty/samba.git] / source / libsmb / asn1.c
index 17b1ee1089f5b4cbd40a79322dd766b441e7fca8..b967927871604dbd7b4e0bfc117cb575b7beab56 100644 (file)
@@ -1,6 +1,5 @@
 /* 
-   Unix SMB/Netbios implementation.
-   Version 3.0
+   Unix SMB/CIFS implementation.
    simple SPNEGO routines
    Copyright (C) Andrew Tridgell 2001
    
@@ -32,11 +31,14 @@ BOOL asn1_write(ASN1_DATA *data, const void *p, int len)
 {
        if (data->has_error) return False;
        if (data->length < data->ofs+len) {
-               data->data = Realloc(data->data, data->ofs+len);
-               if (!data->data) {
+               uint8 *newp;
+               newp = Realloc(data->data, data->ofs+len);
+               if (!newp) {
+                       SAFE_FREE(data->data);
                        data->has_error = True;
                        return False;
                }
+               data->data = newp;
                data->length = data->ofs+len;
        }
        memcpy(data->data + data->ofs, p, len);
@@ -84,13 +86,18 @@ BOOL asn1_pop_tag(ASN1_DATA *data)
        /* yes, this is ugly. We don't know in advance how many bytes the length
           of a tag will take, so we assumed 1 byte. If we were wrong then we 
           need to correct our mistake */
-       if (len > 127) {
+       if (len > 255) {
                data->data[nesting->start] = 0x82;
                if (!asn1_write_uint8(data, 0)) return False;
                if (!asn1_write_uint8(data, 0)) return False;
                memmove(data->data+nesting->start+3, data->data+nesting->start+1, len);
                data->data[nesting->start+1] = len>>8;
                data->data[nesting->start+2] = len&0xff;
+       } else if (len > 127) {
+               data->data[nesting->start] = 0x81;
+               if (!asn1_write_uint8(data, 0)) return False;
+               memmove(data->data+nesting->start+2, data->data+nesting->start+1, len);
+               data->data[nesting->start+1] = len;
        } else {
                data->data[nesting->start] = len;
        }
@@ -100,24 +107,43 @@ BOOL asn1_pop_tag(ASN1_DATA *data)
        return True;
 }
 
+
+/* write an integer */
+BOOL asn1_write_Integer(ASN1_DATA *data, int i)
+{
+       if (!asn1_push_tag(data, ASN1_INTEGER)) return False;
+       do {
+               asn1_write_uint8(data, i);
+               i = i >> 8;
+       } while (i);
+       return asn1_pop_tag(data);
+}
+
 /* write an object ID to a ASN1 buffer */
 BOOL asn1_write_OID(ASN1_DATA *data, const char *OID)
 {
        unsigned v, v2;
-       char *p = (char *)OID;
+       const char *p = (const char *)OID;
+       char *newp;
 
-       if (!asn1_push_tag(data, ASN1_OID)) return False;
-       v = strtol(p, &p, 10);
-       v2 = strtol(p, &p, 10);
-       if (!asn1_write_uint8(data, 40*v + v2)) return False;
+       if (!asn1_push_tag(data, ASN1_OID))
+               return False;
+       v = strtol(p, &newp, 10);
+       p = newp;
+       v2 = strtol(p, &newp, 10);
+       p = newp;
+       if (!asn1_write_uint8(data, 40*v + v2))
+               return False;
 
        while (*p) {
-               v = strtol(p, &p, 10);
+               v = strtol(p, &newp, 10);
+               p = newp;
                if (v >= (1<<28)) asn1_write_uint8(data, 0x80 | ((v>>28)&0xff));
                if (v >= (1<<21)) asn1_write_uint8(data, 0x80 | ((v>>21)&0xff));
                if (v >= (1<<14)) asn1_write_uint8(data, 0x80 | ((v>>14)&0xff));
                if (v >= (1<<7)) asn1_write_uint8(data, 0x80 | ((v>>7)&0xff));
-               if (!asn1_write_uint8(data, v&0x7f)) return False;
+               if (!asn1_write_uint8(data, v&0x7f))
+                       return False;
        }
        return asn1_pop_tag(data);
 }
@@ -148,6 +174,34 @@ BOOL asn1_write_BOOLEAN(ASN1_DATA *data, BOOL v)
        return !data->has_error;
 }
 
+/* write a BOOLEAN - hmm, I suspect this one is the correct one, and the 
+   above boolean is bogus. Need to check */
+BOOL asn1_write_BOOLEAN2(ASN1_DATA *data, BOOL v)
+{
+       asn1_push_tag(data, ASN1_BOOLEAN);
+       asn1_write_uint8(data, v);
+       asn1_pop_tag(data);
+       return !data->has_error;
+}
+
+/* check a BOOLEAN */
+BOOL asn1_check_BOOLEAN(ASN1_DATA *data, BOOL v)
+{
+       uint8 b = 0;
+
+       asn1_read_uint8(data, &b);
+       if (b != ASN1_BOOLEAN) {
+               data->has_error = True;
+               return False;
+       }
+       asn1_read_uint8(data, &b);
+       if (b != v) {
+               data->has_error = True;
+               return False;
+       }
+       return !data->has_error;
+}
+
 
 /* load a ASN1_DATA structure with a lump of data, ready to be parsed */
 BOOL asn1_load(ASN1_DATA *data, DATA_BLOB blob)
@@ -200,14 +254,13 @@ BOOL asn1_start_tag(ASN1_DATA *data, uint8 tag)
        asn1_read_uint8(data, &b);
        if (b & 0x80) {
                int n = b & 0x7f;
-               if (n != 2) {
-                       data->has_error = True;
-                       return False;
-               }
                asn1_read_uint8(data, &b);
-               nesting->taglen = b<<8;
-               asn1_read_uint8(data, &b);
-               nesting->taglen |= b;
+               nesting->taglen = b;
+               while (n > 1) {
+                       asn1_read_uint8(data, &b);
+                       nesting->taglen = (nesting->taglen << 8) | b;
+                       n--;
+               }
        } else {
                nesting->taglen = b;
        }
@@ -285,7 +338,7 @@ BOOL asn1_read_OID(ASN1_DATA *data, char **OID)
 }
 
 /* check that the next object ID is correct */
-BOOL asn1_check_OID(ASN1_DATA *data, char *OID)
+BOOL asn1_check_OID(ASN1_DATA *data, const char *OID)
 {
        char *id;
 
@@ -315,3 +368,50 @@ BOOL asn1_read_GeneralString(ASN1_DATA *data, char **s)
        asn1_end_tag(data);
        return !data->has_error;
 }
+
+/* read a octet string blob */
+BOOL asn1_read_OctetString(ASN1_DATA *data, DATA_BLOB *blob)
+{
+       int len;
+       ZERO_STRUCTP(blob);
+       if (!asn1_start_tag(data, ASN1_OCTET_STRING)) return False;
+       len = asn1_tag_remaining(data);
+       *blob = data_blob(NULL, len);
+       asn1_read(data, blob->data, len);
+       asn1_end_tag(data);
+       return !data->has_error;
+}
+
+/* read an interger */
+BOOL asn1_read_Integer(ASN1_DATA *data, int *i)
+{
+       uint8 b;
+       *i = 0;
+       
+       if (!asn1_start_tag(data, ASN1_INTEGER)) return False;
+       while (asn1_tag_remaining(data)>0) {
+               asn1_read_uint8(data, &b);
+               *i = (*i << 8) + b;
+       }
+       return asn1_end_tag(data);      
+       
+}
+
+/* check a enumarted value is correct */
+BOOL asn1_check_enumerated(ASN1_DATA *data, int v)
+{
+       uint8 b;
+       if (!asn1_start_tag(data, ASN1_ENUMERATED)) return False;
+       asn1_read_uint8(data, &b);
+       asn1_end_tag(data);
+       return !data->has_error && (v == b);
+}
+
+/* check a enumarted value is correct */
+BOOL asn1_write_enumerated(ASN1_DATA *data, uint8 v)
+{
+       if (!asn1_push_tag(data, ASN1_ENUMERATED)) return False;
+       asn1_write_uint8(data, v);
+       asn1_pop_tag(data);
+       return !data->has_error;
+}