heimdal:lib/krb5: verify_logonname() to handle multi component principal
[kai/samba-autobuild/.git] / source4 / heimdal / lib / krb5 / pac.c
index d50052c8bcb3c5499e3b106d4a3b26c8a68630b4..7c8ba50e9c49fdaed9bd7bef20253c0a543e264a 100644 (file)
@@ -87,7 +87,7 @@ HMAC_MD5_any_checksum(krb5_context context,
                      unsigned usage,
                      Checksum *result)
 {
-    struct key_data local_key;
+    struct _krb5_key_data local_key;
     krb5_error_code ret;
 
     memset(&local_key, 0, sizeof(local_key));
@@ -116,7 +116,7 @@ HMAC_MD5_any_checksum(krb5_context context,
  *
  */
 
-krb5_error_code
+KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
 krb5_pac_parse(krb5_context context, const void *ptr, size_t len,
               krb5_pac *pac)
 {
@@ -127,13 +127,13 @@ krb5_pac_parse(krb5_context context, const void *ptr, size_t len,
 
     p = calloc(1, sizeof(*p));
     if (p == NULL) {
-       ret = _krb5_enomem(context);
+       ret = krb5_enomem(context);
        goto out;
     }
 
     sp = krb5_storage_from_readonly_mem(ptr, len);
     if (sp == NULL) {
-       ret = _krb5_enomem(context);
+       ret = krb5_enomem(context);
        goto out;
     }
     krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
@@ -156,7 +156,7 @@ krb5_pac_parse(krb5_context context, const void *ptr, size_t len,
     p->pac = calloc(1,
                    sizeof(*p->pac) + (sizeof(p->pac->buffers[0]) * (tmp - 1)));
     if (p->pac == NULL) {
-       ret = _krb5_enomem(context);
+       ret = krb5_enomem(context);
        goto out;
     }
 
@@ -258,7 +258,7 @@ out:
     return ret;
 }
 
-krb5_error_code
+KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
 krb5_pac_init(krb5_context context, krb5_pac *pac)
 {
     krb5_error_code ret;
@@ -266,27 +266,27 @@ krb5_pac_init(krb5_context context, krb5_pac *pac)
 
     p = calloc(1, sizeof(*p));
     if (p == NULL) {
-       return _krb5_enomem(context);
+       return krb5_enomem(context);
     }
 
     p->pac = calloc(1, sizeof(*p->pac));
     if (p->pac == NULL) {
        free(p);
-       return _krb5_enomem(context);
+       return krb5_enomem(context);
     }
 
     ret = krb5_data_alloc(&p->data, PACTYPE_SIZE);
     if (ret) {
        free (p->pac);
        free(p);
-       return _krb5_enomem(context);
+       return krb5_enomem(context);
     }
 
     *pac = p;
     return 0;
 }
 
-krb5_error_code
+KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
 krb5_pac_add_buffer(krb5_context context, krb5_pac p,
                    uint32_t type, const krb5_data *data)
 {
@@ -300,7 +300,7 @@ krb5_pac_add_buffer(krb5_context context, krb5_pac p,
     ptr = realloc(p->pac,
                  sizeof(*p->pac) + (sizeof(p->pac->buffers[0]) * len));
     if (ptr == NULL)
-       return _krb5_enomem(context);
+       return krb5_enomem(context);
 
     p->pac = ptr;
 
@@ -367,7 +367,7 @@ krb5_pac_add_buffer(krb5_context context, krb5_pac p,
  * @ingroup krb5_pac
  */
 
-krb5_error_code
+KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
 krb5_pac_get_buffer(krb5_context context, krb5_pac p,
                    uint32_t type, krb5_data *data)
 {
@@ -397,7 +397,7 @@ krb5_pac_get_buffer(krb5_context context, krb5_pac p,
  *
  */
 
-krb5_error_code
+KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
 krb5_pac_get_types(krb5_context context,
                   krb5_pac p,
                   size_t *len,
@@ -408,7 +408,7 @@ krb5_pac_get_types(krb5_context context,
     *types = calloc(p->pac->numbuffers, sizeof(*types));
     if (*types == NULL) {
        *len = 0;
-       return _krb5_enomem(context);
+       return krb5_enomem(context);
     }
     for (i = 0; i < p->pac->numbuffers; i++)
        (*types)[i] = p->pac->buffers[i].type;
@@ -421,7 +421,7 @@ krb5_pac_get_types(krb5_context context,
  *
  */
 
-void
+KRB5_LIB_FUNCTION void KRB5_LIB_CALL
 krb5_pac_free(krb5_context context, krb5_pac pac)
 {
     krb5_data_free(&pac->data);
@@ -450,7 +450,7 @@ verify_checksum(krb5_context context,
     sp = krb5_storage_from_mem((char *)data->data + sig->offset_lo,
                               sig->buffersize);
     if (sp == NULL)
-       return _krb5_enomem(context);
+       return krb5_enomem(context);
 
     krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
 
@@ -460,11 +460,11 @@ verify_checksum(krb5_context context,
        sig->buffersize - krb5_storage_seek(sp, 0, SEEK_CUR);
     cksum.checksum.data = malloc(cksum.checksum.length);
     if (cksum.checksum.data == NULL) {
-       ret = _krb5_enomem(context);
+       ret = krb5_enomem(context);
        goto out;
     }
     ret = krb5_storage_read(sp, cksum.checksum.data, cksum.checksum.length);
-    if (ret != cksum.checksum.length) {
+    if (ret != (int)cksum.checksum.length) {
        ret = EINVAL;
        krb5_set_error_message(context, ret, "PAC checksum missing checksum");
        goto out;
@@ -546,7 +546,7 @@ create_checksum(krb5_context context,
      * http://blogs.msdn.com/b/openspecification/archive/2010/01/01/verifying-the-server-signature-in-kerberos-privilege-account-certificate.aspx
      * for Microsoft's explaination */
 
-    if (cksumtype == CKSUMTYPE_HMAC_MD5) {
+    if (cksumtype == (uint32_t)CKSUMTYPE_HMAC_MD5) {
        ret = HMAC_MD5_any_checksum(context, key, data, datalen,
                                    KRB5_KU_OTHER_CKSUM, &cksum);
     } else {
@@ -595,16 +595,17 @@ verify_logonname(krb5_context context,
                 krb5_const_principal principal)
 {
     krb5_error_code ret;
-    krb5_principal p2;
     uint32_t time1, time2;
     krb5_storage *sp;
     uint16_t len;
-    char *s;
+    char *s = NULL;
+    char *principal_string = NULL;
+    char *logon_string = NULL;
 
     sp = krb5_storage_from_readonly_mem((const char *)data->data + logon_name->offset_lo,
                                        logon_name->buffersize);
     if (sp == NULL)
-       return _krb5_enomem(context);
+       return krb5_enomem(context);
 
     krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
 
@@ -631,7 +632,7 @@ verify_logonname(krb5_context context,
     s = malloc(len);
     if (s == NULL) {
        krb5_storage_free(sp);
-       return _krb5_enomem(context);
+       return krb5_enomem(context);
     }
     ret = krb5_storage_read(sp, s, len);
     if (ret != len) {
@@ -648,7 +649,7 @@ verify_logonname(krb5_context context,
 
        ucs2 = malloc(sizeof(ucs2[0]) * ucs2len);
        if (ucs2 == NULL)
-           return _krb5_enomem(context);
+           return krb5_enomem(context);
 
        ret = wind_ucs2read(s, len, &flags, ucs2, &ucs2len);
        free(s);
@@ -664,29 +665,36 @@ verify_logonname(krb5_context context,
            return ret;
        }
        u8len += 1; /* Add space for NUL */
-       s = malloc(u8len);
-       if (s == NULL) {
+       logon_string = malloc(u8len);
+       if (logon_string == NULL) {
            free(ucs2);
-           return _krb5_enomem(context);
+           return krb5_enomem(context);
        }
-       ret = wind_ucs2utf8(ucs2, ucs2len, s, &u8len);
+       ret = wind_ucs2utf8(ucs2, ucs2len, logon_string, &u8len);
        free(ucs2);
        if (ret) {
-           free(s);
+           free(logon_string);
            krb5_set_error_message(context, ret, "Failed to convert to UTF-8");
            return ret;
        }
     }
-    ret = krb5_parse_name_flags(context, s, KRB5_PRINCIPAL_PARSE_NO_REALM, &p2);
-    free(s);
-    if (ret)
+    ret = krb5_unparse_name_flags(context, principal,
+                                 KRB5_PRINCIPAL_UNPARSE_NO_REALM |
+                                 KRB5_PRINCIPAL_UNPARSE_DISPLAY,
+                                 &principal_string);
+    if (ret) {
+       free(logon_string);
        return ret;
+    }
 
-    if (krb5_principal_compare_any_realm(context, principal, p2) != TRUE) {
+    ret = strcmp(logon_string, principal_string);
+    if (ret != 0) {
        ret = EINVAL;
-       krb5_set_error_message(context, ret, "PAC logon name mismatch");
+       krb5_set_error_message(context, ret, "PAC logon name [%s] mismatch principal name [%s]",
+                              logon_string, principal_string);
     }
-    krb5_free_principal(context, p2);
+    free(logon_string);
+    free(principal_string);
     return ret;
 out:
     return ret;
@@ -706,7 +714,7 @@ build_logon_name(krb5_context context,
     krb5_storage *sp;
     uint64_t t;
     char *s, *s2;
-    size_t i, len;
+    size_t s2_len;
 
     t = unix2nttime(authtime);
 
@@ -714,7 +722,7 @@ build_logon_name(krb5_context context,
 
     sp = krb5_storage_emem();
     if (sp == NULL)
-       return _krb5_enomem(context);
+       return krb5_enomem(context);
 
     krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
 
@@ -722,34 +730,67 @@ build_logon_name(krb5_context context,
     CHECK(ret, krb5_store_uint32(sp, t >> 32), out);
 
     ret = krb5_unparse_name_flags(context, principal,
-                                 KRB5_PRINCIPAL_UNPARSE_NO_REALM, &s);
+                                 KRB5_PRINCIPAL_UNPARSE_NO_REALM |
+                                 KRB5_PRINCIPAL_UNPARSE_DISPLAY,
+                                 &s);
     if (ret)
        goto out;
 
-    len = strlen(s);
+    {
+       size_t ucs2_len;
+       uint16_t *ucs2;
+       unsigned int flags;
 
-    CHECK(ret, krb5_store_uint16(sp, len * 2), out);
+       ret = wind_utf8ucs2_length(s, &ucs2_len);
+       if (ret) {
+           free(s);
+           krb5_set_error_message(context, ret, "Failed to count length of UTF-8 string");
+           return ret;
+       }
+
+       ucs2 = malloc(sizeof(ucs2[0]) * ucs2_len);
+       if (ucs2 == NULL) {
+           free(s);
+           return krb5_enomem(context);
+       }
 
-#if 1 /* cheat for now */
-    s2 = malloc(len * 2);
-    if (s2 == NULL) {
-       ret = _krb5_enomem(context);
+       ret = wind_utf8ucs2(s, ucs2, &ucs2_len);
        free(s);
-       goto out;
-    }
-    for (i = 0; i < len; i++) {
-       s2[i * 2] = s[i];
-       s2[i * 2 + 1] = 0;
+       if (ret) {
+           free(ucs2);
+           krb5_set_error_message(context, ret, "Failed to convert string to UCS-2");
+           return ret;
+       }
+
+       s2_len = (ucs2_len + 1) * 2;
+       s2 = malloc(s2_len);
+       if (ucs2 == NULL) {
+           free(ucs2);
+           return krb5_enomem(context);
+       }
+
+       flags = WIND_RW_LE;
+       ret = wind_ucs2write(ucs2, ucs2_len,
+                            &flags, s2, &s2_len);
+       free(ucs2);
+       if (ret) {
+           free(s2);
+           krb5_set_error_message(context, ret, "Failed to write to UCS-2 buffer");
+           return ret;
+       }
+
+       /*
+        * we do not want zero termination
+        */
+       s2_len = ucs2_len * 2;
     }
-    free(s);
-#else
-    /* write libwind code here */
-#endif
 
-    ret = krb5_storage_write(sp, s2, len * 2);
+    CHECK(ret, krb5_store_uint16(sp, s2_len), out);
+
+    ret = krb5_storage_write(sp, s2, s2_len);
     free(s2);
-    if (ret != len * 2) {
-       ret = _krb5_enomem(context);
+    if (ret != (int)s2_len) {
+       ret = krb5_enomem(context);
        goto out;
     }
     ret = krb5_storage_to_data(sp, logon);
@@ -780,7 +821,7 @@ out:
  * @ingroup krb5_pac
  */
 
-krb5_error_code
+KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
 krb5_pac_verify(krb5_context context,
                const krb5_pac pac,
                time_t authtime,
@@ -877,7 +918,7 @@ fill_zeros(krb5_context context, krb5_storage *sp, size_t len)
            l = sizeof(zeros);
        sret = krb5_storage_write(sp, zeros, l);
        if (sret <= 0)
-           return _krb5_enomem(context);
+           return krb5_enomem(context);
 
        len -= sret;
     }
@@ -932,7 +973,8 @@ _krb5_pac_sign(krb5_context context,
     size_t server_size, priv_size;
     uint32_t server_offset = 0, priv_offset = 0;
     uint32_t server_cksumtype = 0, priv_cksumtype = 0;
-    int i, num = 0;
+    int num = 0;
+    size_t i;
     krb5_data logon, d;
 
     krb5_data_zero(&logon);
@@ -949,7 +991,7 @@ _krb5_pac_sign(krb5_context context,
 
        ptr = realloc(p->pac, sizeof(*p->pac) + (sizeof(p->pac->buffers[0]) * (p->pac->numbuffers + num - 1)));
        if (ptr == NULL)
-           return _krb5_enomem(context);
+           return krb5_enomem(context);
 
        p->pac = ptr;
 
@@ -986,14 +1028,14 @@ _krb5_pac_sign(krb5_context context,
     /* Encode PAC */
     sp = krb5_storage_emem();
     if (sp == NULL)
-       return _krb5_enomem(context);
+       return krb5_enomem(context);
 
     krb5_storage_set_flags(sp, KRB5_STORAGE_BYTEORDER_LE);
 
     spdata = krb5_storage_emem();
     if (spdata == NULL) {
        krb5_storage_free(sp);
-       return _krb5_enomem(context);
+       return krb5_enomem(context);
     }
     krb5_storage_set_flags(spdata, KRB5_STORAGE_BYTEORDER_LE);
 
@@ -1031,7 +1073,7 @@ _krb5_pac_sign(krb5_context context,
 
            sret = krb5_storage_write(spdata, ptr, len);
            if (sret != len) {
-               ret = _krb5_enomem(context);
+               ret = krb5_enomem(context);
                goto out;
            }
            /* XXX if not aligned, fill_zeros */
@@ -1049,7 +1091,7 @@ _krb5_pac_sign(krb5_context context,
 
            end += len;
            e = ((end + PAC_ALIGNMENT - 1) / PAC_ALIGNMENT) * PAC_ALIGNMENT;
-           if (end != e) {
+           if ((int32_t)end != e) {
                CHECK(ret, fill_zeros(context, spdata, e - end), out);
            }
            end = e;
@@ -1066,16 +1108,16 @@ _krb5_pac_sign(krb5_context context,
        goto out;
     }
     ret = krb5_storage_write(sp, d.data, d.length);
-    if (ret != d.length) {
+    if (ret != (int)d.length) {
        krb5_data_free(&d);
-       ret = _krb5_enomem(context);
+       ret = krb5_enomem(context);
        goto out;
     }
     krb5_data_free(&d);
 
     ret = krb5_storage_to_data(sp, &d);
     if (ret) {
-       ret = _krb5_enomem(context);
+       ret = krb5_enomem(context);
        goto out;
     }