1142 lines
		
	
	
		
			38 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1142 lines
		
	
	
		
			38 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2021 Kungliga Tekniska Högskolan
 | |
|  * (Royal Institute of Technology, Stockholm, Sweden).
 | |
|  * All rights reserved.
 | |
|  *
 | |
|  * Redistribution and use in source and binary forms, with or without
 | |
|  * modification, are permitted provided that the following conditions
 | |
|  * are met:
 | |
|  *
 | |
|  * 1. Redistributions of source code must retain the above copyright
 | |
|  *    notice, this list of conditions and the following disclaimer.
 | |
|  *
 | |
|  * 2. Redistributions in binary form must reproduce the above copyright
 | |
|  *    notice, this list of conditions and the following disclaimer in the
 | |
|  *    documentation and/or other materials provided with the distribution.
 | |
|  *
 | |
|  * 3. Neither the name of the Institute nor the names of its contributors
 | |
|  *    may be used to endorse or promote products derived from this software
 | |
|  *    without specific prior written permission.
 | |
|  *
 | |
|  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
 | |
|  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | |
|  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | |
|  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 | |
|  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | |
|  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 | |
|  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | |
|  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | |
|  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | |
|  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | |
|  * SUCH DAMAGE.
 | |
|  */
 | |
| 
 | |
| #include "gsskrb5_locl.h"
 | |
| 
 | |
| /*
 | |
|  * (Not-yet-)Standard name attributes for Kerberos MNs,
 | |
|  * GSS_KRB5_NAME_ATTRIBUTE_BASE_URN + "...".
 | |
|  *
 | |
|  * I.e., "urn:ietf:kerberos:nameattr-...".  (XXX Register this URN namespace
 | |
|  * with IANA.)
 | |
|  *
 | |
|  * Note that we do use URN fragments.
 | |
|  *
 | |
|  * Specific attributes below the base URN:
 | |
|  *
 | |
|  *  - name access attributes:
 | |
|  *     - "realm"                    -> realm of name
 | |
|  *     - "name-ncomp"               -> count of name components
 | |
|  *     - "name-ncomp#<digit>"       -> name component N (0 <= N <= 9)
 | |
|  *
 | |
|  * Ticket and Authenticator access attributes:
 | |
|  *
 | |
|  *  - "transit-path"                -> encoding of the transited path
 | |
|  *  - "authenticator-authz-data"    -> encoding of all of the authz-data from
 | |
|  *                                     the AP-REQ's Authenticator
 | |
|  *  - "ticket-authz-data"           -> encoding of all of the authz-data from
 | |
|  *                                     the AP-REQ's Ticket
 | |
|  *  - "ticket-authz-data#pac"       -> the PAC
 | |
|  *  - "authz-data#<N>"              -> encoding of all of a specific auth-data
 | |
|  *                                     element type N (e.g., 2, meaning
 | |
|  *                                     AD-INTENDED-FOR-SERVER)
 | |
|  *
 | |
|  * Misc. attributes:
 | |
|  *
 | |
|  *  - "peer-realm"                  -> name of peer's realm (if this is an MN
 | |
|  *                                     resulting for establishing a security
 | |
|  *                                     context)
 | |
|  *  - "canonical-name"              -> exported name token and RFC1964 display
 | |
|  *                                     syntax of the name's canonical name
 | |
|  *
 | |
|  * Compatibility with MIT:
 | |
|  *
 | |
|  *  - "urn:mspac:"                  -> the PAC and its individual info buffers
 | |
|  *
 | |
|  * TODO:
 | |
|  *
 | |
|  *  - Add some sort of display syntax for transit path
 | |
|  *  - Add support for URN q-components or attribute prefixes to specify
 | |
|  *    alternative raw and/or display value encodings (JSON?)
 | |
|  *  - Add support for attributes for accessing other parts of the Ticket / KDC
 | |
|  *    reply enc-parts, like auth times
 | |
|  *  - Add support for getting PAC logon fields, including SIDs (one at a time)
 | |
|  *  - Add support for CAMMAC?
 | |
|  */
 | |
| 
 | |
| static int
 | |
| attr_eq(gss_const_buffer_t attr, const char *aname, size_t aname_len, \
 | |
| 	int prefix_check)
 | |
| {
 | |
|     if (attr->length < aname_len)
 | |
|         return 0;
 | |
| 
 | |
|     if (strncmp((char *)attr->value, aname, aname_len) != 0)
 | |
| 	return 0;
 | |
| 
 | |
|     return prefix_check || attr->length == aname_len;
 | |
| }
 | |
| 
 | |
| #define ATTR_EQ(a, an) (attr_eq(a, an, sizeof(an) - 1, FALSE))
 | |
| #define ATTR_EQ_PREFIX(a, an) (attr_eq(a, an, sizeof(an) - 1, TRUE))
 | |
| 
 | |
| /* Split attribute into prefix, suffix, and fragment.  See RFC6680. */
 | |
| static void
 | |
| split_attr(gss_const_buffer_t orig,
 | |
|            gss_buffer_t prefix,
 | |
|            gss_buffer_t attr,
 | |
|            gss_buffer_t frag,
 | |
|            int *is_urn)
 | |
| {
 | |
|     char *last = NULL;
 | |
|     char *p = orig->value;
 | |
| 
 | |
|     *attr = *orig;
 | |
|     prefix->value = orig->value;
 | |
|     prefix->length = 0;
 | |
|     frag->length = 0;
 | |
|     frag->value = NULL;
 | |
| 
 | |
|     /* FIXME We don't have a memrchr() in lib/roken */
 | |
|     for (p = memchr(p, ' ', orig->length);
 | |
|          p;
 | |
|          p = p ? memchr(p + 1, ' ', orig->length) : NULL) {
 | |
|         last = p;
 | |
|         prefix->length = last - (const char *)orig->value;
 | |
|         attr->value = last + 1;
 | |
|         attr->length = orig->length - (prefix->length + 1);
 | |
|     }
 | |
|     if (prefix->length == 0)
 | |
|         prefix->value = NULL;
 | |
| 
 | |
|     if ((*is_urn = (strncmp(attr->value, "urn:", sizeof("urn:") - 1) == 0)) &&
 | |
|         (p = memchr((char *)attr->value + 1, '#', attr->length - 1))) {
 | |
|         frag->value = ++p;
 | |
|         frag->length = attr->length - (p - (const char *)attr->value);
 | |
|         attr->length = --p - (const char *)attr->value;
 | |
|     }
 | |
| }
 | |
| 
 | |
| typedef OM_uint32 get_name_attr_f(OM_uint32 *,
 | |
|                                   const CompositePrincipal *,
 | |
|                                   gss_const_buffer_t,
 | |
|                                   gss_const_buffer_t,
 | |
|                                   gss_const_buffer_t,
 | |
|                                   int *,
 | |
|                                   int *,
 | |
|                                   gss_buffer_t,
 | |
|                                   gss_buffer_t,
 | |
|                                   int *);
 | |
| 
 | |
| typedef OM_uint32 set_name_attr_f(OM_uint32 *,
 | |
|                                   CompositePrincipal *,
 | |
|                                   gss_const_buffer_t,
 | |
|                                   gss_const_buffer_t,
 | |
|                                   gss_const_buffer_t,
 | |
|                                   int,
 | |
|                                   gss_buffer_t);
 | |
| 
 | |
| typedef OM_uint32 del_name_attr_f(OM_uint32 *,
 | |
|                                   CompositePrincipal *,
 | |
|                                   gss_const_buffer_t,
 | |
|                                   gss_const_buffer_t,
 | |
|                                   gss_const_buffer_t);
 | |
| typedef get_name_attr_f *get_name_attr_fp;
 | |
| typedef set_name_attr_f *set_name_attr_fp;
 | |
| typedef del_name_attr_f *del_name_attr_fp;
 | |
| 
 | |
| static get_name_attr_f get_realm;
 | |
| static get_name_attr_f get_ncomps;
 | |
| static get_name_attr_f get_peer_realm;
 | |
| static get_name_attr_f get_pac;
 | |
| static get_name_attr_f get_authz_data;
 | |
| static get_name_attr_f get_ticket_authz_data;
 | |
| static get_name_attr_f get_authenticator_authz_data;
 | |
| static set_name_attr_f set_authenticator_authz_data;
 | |
| static get_name_attr_f get_transited;
 | |
| static get_name_attr_f get_canonical_name;
 | |
| 
 | |
| #define NB(n) \
 | |
|     GSS_KRB5_NAME_ATTRIBUTE_BASE_URN n, n, \
 | |
|     sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN n) - 1, \
 | |
|     sizeof(n) - 1
 | |
| #define NM(n) \
 | |
|     "urn:mspac:" n, n, sizeof("urn:mspac:" n) - 1, sizeof(n) - 1
 | |
| 
 | |
| static struct krb5_name_attrs {
 | |
|     const char *fullname;
 | |
|     const char *name;
 | |
|     size_t fullnamelen;
 | |
|     size_t namelen;
 | |
|     get_name_attr_fp getter;
 | |
|     set_name_attr_fp setter;
 | |
|     del_name_attr_fp deleter;
 | |
|     unsigned int indicate:1;
 | |
|     unsigned int is_krb5_name_attr_urn:1;
 | |
| } name_attrs[] = {
 | |
|     /* XXX We should sort these so we can binary search them */
 | |
|     { NB("realm"),          get_realm,      NULL, NULL, 1, 1 },
 | |
|     { NB("name-ncomp"),     get_ncomps,     NULL, NULL, 1, 1 },
 | |
|     { NB("name-ncomp#0"),   get_ncomps,     NULL, NULL, 1, 1 },
 | |
|     { NB("name-ncomp#1"),   get_ncomps,     NULL, NULL, 1, 1 },
 | |
|     { NB("name-ncomp#2"),   get_ncomps,     NULL, NULL, 1, 1 },
 | |
|     { NB("name-ncomp#3"),   get_ncomps,     NULL, NULL, 1, 1 },
 | |
|     { NB("name-ncomp#4"),   get_ncomps,     NULL, NULL, 1, 1 },
 | |
|     { NB("name-ncomp#5"),   get_ncomps,     NULL, NULL, 1, 1 },
 | |
|     { NB("name-ncomp#6"),   get_ncomps,     NULL, NULL, 1, 1 },
 | |
|     { NB("name-ncomp#7"),   get_ncomps,     NULL, NULL, 1, 1 },
 | |
|     { NB("name-ncomp#8"),   get_ncomps,     NULL, NULL, 1, 1 },
 | |
|     { NB("name-ncomp#9"),   get_ncomps,     NULL, NULL, 1, 1 },
 | |
|     { NB("peer-realm"),     get_peer_realm, NULL, NULL, 1, 1 },
 | |
|     { NB("ticket-authz-data#pac"), get_pac, NULL, NULL, 1, 1 },
 | |
|     { NM(""),                   get_pac,    NULL, NULL, 1, 0 },
 | |
|     { NM("logon-info"),         get_pac,    NULL, NULL, 1, 0 },
 | |
|     { NM("credentials-info"),   get_pac,    NULL, NULL, 1, 0 },
 | |
|     { NM("server-checksum"),    get_pac,    NULL, NULL, 1, 0 },
 | |
|     { NM("privsvr-checksum"),   get_pac,    NULL, NULL, 1, 0 },
 | |
|     { NM("client-info"),        get_pac,    NULL, NULL, 1, 0 },
 | |
|     { NM("delegation-info"),    get_pac,    NULL, NULL, 1, 0 },
 | |
|     { NM("upn-dns-info"),       get_pac,    NULL, NULL, 1, 0 },
 | |
|     { NM("ticket-checksum"),    get_pac,    NULL, NULL, 1, 0 },
 | |
|     { NM("attributes-info"),    get_pac,    NULL, NULL, 1, 0 },
 | |
|     { NM("requestor-sid"),      get_pac,    NULL, NULL, 1, 0 },
 | |
|     { NB("ticket-authz-data#kdc-issued"),
 | |
|          get_ticket_authz_data, NULL, NULL, 1, 1 },
 | |
|     { NB("ticket-authz-data"),
 | |
|          get_ticket_authz_data, NULL, NULL, 1, 1 },
 | |
|     { NB("authenticator-authz-data"),
 | |
|          get_authenticator_authz_data,
 | |
|          set_authenticator_authz_data, NULL, 1, 1 },
 | |
|     { NB("authz-data"),     get_authz_data,  NULL, NULL, 1, 1 },
 | |
|     { NB("transit-path"),   get_transited,   NULL, NULL, 1, 1 },
 | |
|     { NB("canonical-name"), get_canonical_name, NULL, NULL, 1, 1 },
 | |
| };
 | |
| 
 | |
| OM_uint32 GSSAPI_CALLCONV
 | |
| _gsskrb5_get_name_attribute(OM_uint32 *minor_status,
 | |
|                             gss_name_t name,
 | |
|                             gss_buffer_t original_attr,
 | |
|                             int *authenticated,
 | |
|                             int *complete,
 | |
|                             gss_buffer_t value,
 | |
|                             gss_buffer_t display_value,
 | |
|                             int *more)
 | |
| {
 | |
|     gss_buffer_desc prefix, attr, suffix, frag;
 | |
|     size_t i;
 | |
|     int is_krb5_name_attr_urn = 0;
 | |
|     int is_urn = 0;
 | |
| 
 | |
|     *minor_status = 0;
 | |
|     if (authenticated)
 | |
|         *authenticated = 0;
 | |
|     if (complete)
 | |
|         *complete = 0;
 | |
|     if (more)
 | |
|         *more = 0;
 | |
|     if (value) {
 | |
|         value->length = 0;
 | |
|         value->value = NULL;
 | |
|     }
 | |
|     if (display_value) {
 | |
|         display_value->length = 0;
 | |
|         display_value->value = NULL;
 | |
|     }
 | |
| 
 | |
|     suffix.value = NULL;
 | |
|     suffix.length = 0;
 | |
| 
 | |
|     split_attr(original_attr, &prefix, &attr, &frag, &is_urn);
 | |
| 
 | |
|     if (prefix.length || !is_urn)
 | |
|         return GSS_S_UNAVAILABLE;
 | |
| 
 | |
|     is_krb5_name_attr_urn =
 | |
|         ATTR_EQ_PREFIX(&attr, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN);
 | |
|     if (is_krb5_name_attr_urn) {
 | |
|         suffix.value =
 | |
|             (char *)attr.value + sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN) - 1;
 | |
|         suffix.length = attr.length - (sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN) - 1);
 | |
|     }
 | |
| 
 | |
|     for (i = 0; i < sizeof(name_attrs)/sizeof(name_attrs[0]); i++) {
 | |
|         if (!name_attrs[i].getter)
 | |
|             continue;
 | |
|         if (name_attrs[i].is_krb5_name_attr_urn && is_krb5_name_attr_urn) {
 | |
|             if (!attr_eq(&suffix, name_attrs[i].name, name_attrs[i].namelen, 0))
 | |
|                 continue;
 | |
|         } else if (!name_attrs[i].is_krb5_name_attr_urn && !is_krb5_name_attr_urn) {
 | |
|             if (!attr_eq(&attr, name_attrs[i].fullname, name_attrs[i].fullnamelen, 0))
 | |
|                 continue;
 | |
|         } else
 | |
|             continue;
 | |
| 
 | |
|         return name_attrs[i].getter(minor_status,
 | |
|                                     (const CompositePrincipal *)name,
 | |
|                                     &prefix, &attr, &frag, authenticated,
 | |
|                                     complete, value, display_value, more);
 | |
|     }
 | |
|     return GSS_S_UNAVAILABLE;
 | |
| }
 | |
| 
 | |
| OM_uint32 GSSAPI_CALLCONV
 | |
| _gsskrb5_set_name_attribute(OM_uint32 *minor_status,
 | |
|                             gss_name_t name,
 | |
|                             int complete,
 | |
|                             gss_buffer_t original_attr,
 | |
|                             gss_buffer_t value)
 | |
| {
 | |
|     gss_buffer_desc prefix, attr, suffix, frag;
 | |
|     size_t i;
 | |
|     int is_krb5_name_attr_urn = 0;
 | |
|     int is_urn = 0;
 | |
| 
 | |
|     *minor_status = 0;
 | |
| 
 | |
|     suffix.value = NULL;
 | |
|     suffix.length = 0;
 | |
| 
 | |
|     split_attr(original_attr, &prefix, &attr, &frag, &is_urn);
 | |
| 
 | |
|     if (prefix.length || !is_urn)
 | |
|         return GSS_S_UNAVAILABLE;
 | |
| 
 | |
|     is_krb5_name_attr_urn =
 | |
|         ATTR_EQ_PREFIX(&attr, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN);
 | |
|     if (is_krb5_name_attr_urn) {
 | |
|         suffix.value =
 | |
|             (char *)attr.value + sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN) - 1;
 | |
|         suffix.length = attr.length - (sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN) - 1);
 | |
|     }
 | |
| 
 | |
|     for (i = 0; i < sizeof(name_attrs)/sizeof(name_attrs[0]); i++) {
 | |
|         if (!name_attrs[i].setter)
 | |
|             continue;
 | |
|         if (name_attrs[i].is_krb5_name_attr_urn && is_krb5_name_attr_urn) {
 | |
|             if (!attr_eq(&suffix, name_attrs[i].name, name_attrs[i].namelen, 0))
 | |
|                 continue;
 | |
|         } else if (!name_attrs[i].is_krb5_name_attr_urn && !is_krb5_name_attr_urn) {
 | |
|             if (!attr_eq(&attr, name_attrs[i].name, name_attrs[i].namelen, 0))
 | |
|                 continue;
 | |
|         } else
 | |
|             continue;
 | |
| 
 | |
|         return name_attrs[i].setter(minor_status, (CompositePrincipal *)name,
 | |
|                                     &prefix, &attr, &frag, complete, value);
 | |
|     }
 | |
|     return GSS_S_UNAVAILABLE;
 | |
| }
 | |
| 
 | |
| OM_uint32 GSSAPI_CALLCONV
 | |
| _gsskrb5_delete_name_attribute(OM_uint32 *minor_status,
 | |
|                                gss_name_t name,
 | |
|                                gss_buffer_t original_attr)
 | |
| {
 | |
|     gss_buffer_desc prefix, attr, suffix, frag;
 | |
|     size_t i;
 | |
|     int is_krb5_name_attr_urn = 0;
 | |
|     int is_urn = 0;
 | |
| 
 | |
|     *minor_status = 0;
 | |
| 
 | |
|     suffix.value = NULL;
 | |
|     suffix.length = 0;
 | |
| 
 | |
|     split_attr(original_attr, &prefix, &attr, &frag, &is_urn);
 | |
| 
 | |
|     if (prefix.length || !is_urn)
 | |
|         return GSS_S_UNAVAILABLE;
 | |
| 
 | |
|     is_krb5_name_attr_urn =
 | |
|         ATTR_EQ_PREFIX(&attr, GSS_KRB5_NAME_ATTRIBUTE_BASE_URN);
 | |
|     if (is_krb5_name_attr_urn) {
 | |
|         suffix.value =
 | |
|             (char *)attr.value + sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN) - 1;
 | |
|         suffix.length = attr.length - (sizeof(GSS_KRB5_NAME_ATTRIBUTE_BASE_URN) - 1);
 | |
|     }
 | |
| 
 | |
|     for (i = 0; i < sizeof(name_attrs)/sizeof(name_attrs[0]); i++) {
 | |
|         if (!name_attrs[i].deleter)
 | |
|             continue;
 | |
|         if (name_attrs[i].is_krb5_name_attr_urn && is_krb5_name_attr_urn) {
 | |
|             if (!attr_eq(&suffix, name_attrs[i].name, name_attrs[i].namelen, 0))
 | |
|                 continue;
 | |
|         } else if (!name_attrs[i].is_krb5_name_attr_urn && !is_krb5_name_attr_urn) {
 | |
|             if (!attr_eq(&attr, name_attrs[i].fullname, name_attrs[i].fullnamelen, 0))
 | |
|                 continue;
 | |
|         } else
 | |
|             continue;
 | |
| 
 | |
|         return name_attrs[i].deleter(minor_status, (CompositePrincipal *)name,
 | |
|                                     &prefix, &attr, &frag);
 | |
|     }
 | |
|     return GSS_S_UNAVAILABLE;
 | |
| }
 | |
| 
 | |
| OM_uint32 GSSAPI_CALLCONV
 | |
| _gsskrb5_inquire_name(OM_uint32 *minor_status,
 | |
|                       gss_name_t name,
 | |
|                       int *name_is_MN,
 | |
|                       gss_OID *MN_mech,
 | |
|                       gss_buffer_set_t *attrs)
 | |
| {
 | |
|     gss_buffer_desc prefix, attr, frag, a;
 | |
|     OM_uint32 major;
 | |
|     size_t i;
 | |
|     int authenticated, is_urn;
 | |
| 
 | |
|     *minor_status = 0;
 | |
|     if (name_is_MN)
 | |
|         *name_is_MN = 1;
 | |
|     if (MN_mech)
 | |
|         *MN_mech = GSS_KRB5_MECHANISM;
 | |
|     if (name == GSS_C_NO_NAME)
 | |
|         return GSS_S_CALL_INACCESSIBLE_READ;
 | |
|     if (attrs == NULL)
 | |
|         return GSS_S_CALL_INACCESSIBLE_WRITE;
 | |
| 
 | |
|     for (i = 0; i < sizeof(name_attrs)/sizeof(name_attrs[0]); i++) {
 | |
|         if (!name_attrs[i].indicate)
 | |
|             continue;
 | |
|         a.value = (void *)(uintptr_t)name_attrs[i].fullname;
 | |
|         a.length = name_attrs[i].fullnamelen;
 | |
|         split_attr(&a, &prefix, &attr, &frag, &is_urn);
 | |
|         major = name_attrs[i].getter(minor_status,
 | |
|                                      (const CompositePrincipal *)name,
 | |
|                                      &prefix, &attr, &frag, &authenticated,
 | |
|                                      NULL, NULL, NULL, NULL);
 | |
|         if (major == GSS_S_UNAVAILABLE)
 | |
|             continue;
 | |
|         if (major != GSS_S_COMPLETE)
 | |
|             break;
 | |
|         major = gss_add_buffer_set_member(minor_status, &a, attrs);
 | |
|     }
 | |
|     if (major == GSS_S_UNAVAILABLE)
 | |
|         major = GSS_S_COMPLETE;
 | |
|     return major;
 | |
| }
 | |
| 
 | |
| OM_uint32 GSSAPI_CALLCONV
 | |
| _gsskrb5_display_name_ext(OM_uint32 *minor_status,
 | |
|                           gss_name_t name,
 | |
|                           gss_OID display_as_name_type,
 | |
|                           gss_buffer_t display_name)
 | |
| {
 | |
|     krb5_const_principal p = (void *)name;
 | |
|     char *s = NULL;
 | |
| 
 | |
|     *minor_status = 0;
 | |
|     if (display_name == NULL)
 | |
|         return GSS_S_CALL_INACCESSIBLE_WRITE;
 | |
|     display_name->length = 0;
 | |
|     display_name->value = NULL;
 | |
| 
 | |
|     if (gss_oid_equal(display_as_name_type, GSS_C_NT_USER_NAME)) {
 | |
|         if (p->name.name_string.len != 1)
 | |
|             return GSS_S_UNAVAILABLE;
 | |
|         return _gsskrb5_localname(minor_status, name, GSS_KRB5_MECHANISM,
 | |
|                                   display_name);
 | |
|     }
 | |
|     if (!gss_oid_equal(display_as_name_type, GSS_C_NT_HOSTBASED_SERVICE) ||
 | |
|         p->name.name_string.len != 2 ||
 | |
|         strchr(p->name.name_string.val[0], '@') ||
 | |
|         strchr(p->name.name_string.val[1], '.') == NULL)
 | |
|         return GSS_S_UNAVAILABLE;
 | |
|     if (asprintf(&s, "%s@%s", p->name.name_string.val[0],
 | |
|                  p->name.name_string.val[1]) == -1 || s == NULL) {
 | |
|         *minor_status = ENOMEM;
 | |
|         return GSS_S_FAILURE;
 | |
|     }
 | |
|     display_name->length = strlen(s);
 | |
|     display_name->value = s;
 | |
|     return GSS_S_COMPLETE;
 | |
| }
 | |
| 
 | |
| OM_uint32 GSSAPI_CALLCONV
 | |
| _gsskrb5_export_name_composite(OM_uint32 *minor_status,
 | |
|                                gss_name_t name,
 | |
|                                gss_buffer_t exported_name)
 | |
| {
 | |
|     krb5_error_code kret;
 | |
|     gss_buffer_desc inner = GSS_C_EMPTY_BUFFER;
 | |
|     unsigned char *buf;
 | |
|     size_t sz;
 | |
| 
 | |
|     if (name == NULL)
 | |
|         return GSS_S_CALL_INACCESSIBLE_READ;
 | |
|     if (exported_name == NULL)
 | |
|         return GSS_S_CALL_INACCESSIBLE_WRITE;
 | |
| 
 | |
|     ASN1_MALLOC_ENCODE(CompositePrincipal, inner.value, inner.length,
 | |
|                        (void *)name, &sz, kret);
 | |
|     if (kret != 0) {
 | |
|         *minor_status = kret;
 | |
|         return GSS_S_FAILURE;
 | |
|     }
 | |
| 
 | |
|     exported_name->length = 10 + inner.length + GSS_KRB5_MECHANISM->length;
 | |
|     exported_name->value  = malloc(exported_name->length);
 | |
|     if (exported_name->value == NULL) {
 | |
| 	free(inner.value);
 | |
| 	*minor_status = ENOMEM;
 | |
| 	return GSS_S_FAILURE;
 | |
|     }
 | |
| 
 | |
|     /* TOK, MECH_OID_LEN, DER(MECH_OID), NAME_LEN, NAME */
 | |
| 
 | |
|     buf = exported_name->value;
 | |
|     buf[0] = 0x04;
 | |
|     buf[1] = 0x02;
 | |
|     buf[2] = ((GSS_KRB5_MECHANISM->length + 2) >> 8) & 0xff;
 | |
|     buf[3] = (GSS_KRB5_MECHANISM->length + 2) & 0xff;
 | |
|     buf[4] = 0x06;
 | |
|     buf[5] = (GSS_KRB5_MECHANISM->length) & 0xFF;
 | |
| 
 | |
|     memcpy(buf + 6, GSS_KRB5_MECHANISM->elements, GSS_KRB5_MECHANISM->length);
 | |
|     buf += 6 + GSS_KRB5_MECHANISM->length;
 | |
| 
 | |
|     buf[0] = (inner.length >> 24) & 0xff;
 | |
|     buf[1] = (inner.length >> 16) & 0xff;
 | |
|     buf[2] = (inner.length >> 8) & 0xff;
 | |
|     buf[3] = (inner.length) & 0xff;
 | |
|     buf += 4;
 | |
| 
 | |
|     memcpy(buf, inner.value, inner.length);
 | |
|     free(inner.value);
 | |
| 
 | |
|     *minor_status = 0;
 | |
|     return GSS_S_COMPLETE;
 | |
| }
 | |
| 
 | |
| #define CHECK_ENOMEM(v, dv) \
 | |
|     do { \
 | |
|         if (((v) && !(v)->value) || ((dv) && !(dv)->value)) { \
 | |
|             if ((v) && (v)->value) { \
 | |
|                 free((v)->value); \
 | |
|                 (v)->length = 0; \
 | |
|                 (v)->value = NULL; \
 | |
|             } \
 | |
|             *minor_status = ENOMEM; \
 | |
|             return GSS_S_FAILURE; \
 | |
|         } \
 | |
|     } while (0)
 | |
| 
 | |
| static OM_uint32
 | |
| get_realm(OM_uint32 *minor_status,
 | |
|           const CompositePrincipal *name,
 | |
|           gss_const_buffer_t prefix,
 | |
|           gss_const_buffer_t attr,
 | |
|           gss_const_buffer_t frag,
 | |
|           int *authenticated,
 | |
|           int *complete,
 | |
|           gss_buffer_t value,
 | |
|           gss_buffer_t display_value,
 | |
|           int *more)
 | |
| {
 | |
|     PrincipalNameAttrs *nameattrs = name->nameattrs;
 | |
| 
 | |
|     if (prefix->length || frag->length || !name->realm)
 | |
|         return GSS_S_UNAVAILABLE;
 | |
|     if (authenticated && nameattrs && nameattrs->authenticated)
 | |
|         *authenticated = 1;
 | |
|     if (complete)
 | |
|         *complete = 1;
 | |
|     if (value && (value->value = strdup(name->realm)))
 | |
|         value->length = strlen(name->realm);
 | |
|     if (display_value && (display_value->value = strdup(name->realm)))
 | |
|         display_value->length = strlen(name->realm);
 | |
|     CHECK_ENOMEM(value, display_value);
 | |
|     return GSS_S_COMPLETE;
 | |
| }
 | |
| 
 | |
| static OM_uint32
 | |
| get_ncomps(OM_uint32 *minor_status,
 | |
|            const CompositePrincipal *name,
 | |
|            gss_const_buffer_t prefix,
 | |
|            gss_const_buffer_t attr,
 | |
|            gss_const_buffer_t frag,
 | |
|            int *authenticated,
 | |
|            int *complete,
 | |
|            gss_buffer_t value,
 | |
|            gss_buffer_t display_value,
 | |
|            int *more)
 | |
| {
 | |
|     PrincipalNameAttrs *nameattrs = name->nameattrs;
 | |
|     int n = -1;
 | |
| 
 | |
|     if (authenticated && nameattrs && nameattrs->authenticated)
 | |
|         *authenticated = 1;
 | |
|     if (complete)
 | |
|         *complete = 1;
 | |
| 
 | |
|     if (frag->length == 1 &&
 | |
|         ((const char *)frag->value)[0] >= '0' &&
 | |
|         ((const char *)frag->value)[0] <= '9') {
 | |
|         n = ((const char *)frag->value)[0] - '0';
 | |
|     } else if (frag->length == sizeof("all") - 1 &&
 | |
|                strncmp(frag->value, "all", sizeof("all") - 1) == 0) {
 | |
|         if (!more || *more < -1 || *more == 0 || *more > CHAR_MAX ||
 | |
|             *more > (int)name->name.name_string.len) {
 | |
|             *minor_status = EINVAL;
 | |
|             return GSS_S_UNAVAILABLE;
 | |
|         }
 | |
|         if (*more == -1) {
 | |
|             *more = name->name.name_string.len - 1;
 | |
|             n = 0;
 | |
|         } else {
 | |
|             n = name->name.name_string.len - *more;
 | |
|             (*more)--;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if (frag->length == 0) {
 | |
|         char *s = NULL;
 | |
| 
 | |
|         /* Outut count of components */
 | |
|         if (value && (value->value = malloc(sizeof(size_t)))) {
 | |
|             *((size_t *)value->value) = name->name.name_string.len;
 | |
|             value->length = sizeof(size_t);
 | |
|         }
 | |
|         if (display_value &&
 | |
|             asprintf(&s, "%u", (unsigned int)name->name.name_string.len) > 0) {
 | |
|             display_value->value = s;
 | |
|             display_value->length = strlen(display_value->value);
 | |
|         }
 | |
|     } else {
 | |
|         /*
 | |
|          * Output a component.  The value and the display value are the same in
 | |
|          * this case.
 | |
|          */
 | |
|         if (n < 0 || n >= name->name.name_string.len) {
 | |
|             *minor_status = EINVAL;
 | |
|             return GSS_S_UNAVAILABLE;
 | |
|         }
 | |
|         if (value && (value->value = strdup(name->name.name_string.val[n])))
 | |
|             value->length = strlen(name->name.name_string.val[n]);
 | |
|         if (display_value &&
 | |
|             (display_value->value = strdup(name->name.name_string.val[n])))
 | |
|             display_value->length = strlen(name->name.name_string.val[n]);
 | |
|     }
 | |
| 
 | |
|     CHECK_ENOMEM(value, display_value);
 | |
|     return GSS_S_COMPLETE;
 | |
| }
 | |
| 
 | |
| static OM_uint32
 | |
| get_peer_realm(OM_uint32 *minor_status,
 | |
|                const CompositePrincipal *name,
 | |
|                gss_const_buffer_t prefix,
 | |
|                gss_const_buffer_t attr,
 | |
|                gss_const_buffer_t frag,
 | |
|                int *authenticated,
 | |
|                int *complete,
 | |
|                gss_buffer_t value,
 | |
|                gss_buffer_t display_value,
 | |
|                int *more)
 | |
| {
 | |
|     PrincipalNameAttrs *nameattrs = name->nameattrs;
 | |
| 
 | |
|     if (prefix->length || frag->length || !nameattrs || !nameattrs->peer_realm)
 | |
|         return GSS_S_UNAVAILABLE;
 | |
|     if (authenticated)
 | |
|         *authenticated = 1;
 | |
|     if (complete)
 | |
|         *complete = 1;
 | |
|     if (value && (value->value = strdup(nameattrs->peer_realm[0])))
 | |
|         value->length = strlen(value->value);
 | |
|     if (display_value &&
 | |
|         (display_value->value = strdup(nameattrs->peer_realm[0])))
 | |
|         display_value->length = strlen(display_value->value);
 | |
| 
 | |
|     CHECK_ENOMEM(value, display_value);
 | |
|     return GSS_S_COMPLETE;
 | |
| }
 | |
| 
 | |
| static OM_uint32
 | |
| get_pac(OM_uint32 *minor_status,
 | |
|         const CompositePrincipal *name,
 | |
|         gss_const_buffer_t prefix,
 | |
|         gss_const_buffer_t attr,
 | |
|         gss_const_buffer_t frag,
 | |
|         int *authenticated,
 | |
|         int *complete,
 | |
|         gss_buffer_t value,
 | |
|         gss_buffer_t display_value,
 | |
|         int *more)
 | |
| {
 | |
|     krb5_error_code kret;
 | |
|     krb5_context context;
 | |
|     krb5_data data, pac_data;
 | |
|     krb5_data suffix;
 | |
|     PrincipalNameAttrs *nameattrs = name->nameattrs;
 | |
|     PrincipalNameAttrSrc *src = nameattrs ? nameattrs->source : NULL;
 | |
|     EncTicketPart *ticket = NULL;
 | |
| 
 | |
|     krb5_data_zero(&data);
 | |
|     krb5_data_zero(&pac_data);
 | |
| 
 | |
|     if (src) switch (src->element) {
 | |
|     case choice_PrincipalNameAttrSrc_enc_ticket_part:
 | |
|         ticket = &src->u.enc_ticket_part;
 | |
|         break;
 | |
|     case choice_PrincipalNameAttrSrc_enc_kdc_rep_part:
 | |
|     default:
 | |
|         return GSS_S_UNAVAILABLE;
 | |
|     }
 | |
| 
 | |
|     if (prefix->length || !authenticated || !ticket)
 | |
|         return GSS_S_UNAVAILABLE;
 | |
| 
 | |
|     GSSAPI_KRB5_INIT(&context);
 | |
| 
 | |
|     if (ATTR_EQ_PREFIX(attr, "urn:mspac:")) {
 | |
|         suffix.length = attr->length - (sizeof("urn:mspac:") - 1);
 | |
|         suffix.data = (char *)attr->value + sizeof("urn:mspac:") - 1;
 | |
|     } else if (ATTR_EQ_PREFIX(frag, "pac-")) {
 | |
|         suffix.length = frag->length - sizeof("pac-") - 1;
 | |
|         suffix.data = (char *)frag->value + sizeof("pac-") - 1;
 | |
|     } else
 | |
|         krb5_data_zero(&suffix); /* ticket-authz-data#pac */
 | |
| 
 | |
|     *authenticated = nameattrs->pac_verified;
 | |
|     if (complete)
 | |
|         *complete = 1;
 | |
| 
 | |
|     kret = _krb5_get_ad(context, ticket->authorization_data,
 | |
|                         NULL, KRB5_AUTHDATA_WIN2K_PAC, &pac_data);
 | |
|     if (kret == 0 && suffix.length) {
 | |
|         krb5_pac pac;
 | |
| 
 | |
|         kret = krb5_pac_parse(context, pac_data.data, pac_data.length, &pac);
 | |
|         if (kret == 0) {
 | |
|             kret = _krb5_pac_get_buffer_by_name(context, pac, &suffix,
 | |
|                                                 value ? &data : NULL);
 | |
|             krb5_pac_free(context, pac);
 | |
|         }
 | |
| 
 | |
|         if (value) {
 | |
|             value->length = data.length;
 | |
|             value->value = data.data;
 | |
|             krb5_data_zero(&data);
 | |
|         }
 | |
|     } else if (kret == 0 && value) {
 | |
|         value->length = pac_data.length;
 | |
|         value->value = pac_data.data;
 | |
|         krb5_data_zero(&pac_data);
 | |
|     }
 | |
| 
 | |
|     krb5_data_free(&pac_data);
 | |
|     krb5_data_free(&data);
 | |
|     *minor_status = kret;
 | |
|     if (kret == ENOENT)
 | |
|         return GSS_S_UNAVAILABLE;
 | |
|     return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE;
 | |
| }
 | |
| 
 | |
| static OM_uint32
 | |
| get_authz_data(OM_uint32 *minor_status,
 | |
|                const CompositePrincipal *name,
 | |
|                gss_const_buffer_t prefix,
 | |
|                gss_const_buffer_t attr,
 | |
|                gss_const_buffer_t frag,
 | |
|                int *authenticated,
 | |
|                int *complete,
 | |
|                gss_buffer_t value,
 | |
|                gss_buffer_t display_value,
 | |
|                int *more)
 | |
| {
 | |
|     krb5_error_code kret = 0;
 | |
|     PrincipalNameAttrs *nameattrs = name->nameattrs;
 | |
|     PrincipalNameAttrSrc *src = nameattrs ? nameattrs->source : NULL;
 | |
|     EncTicketPart *ticket = NULL;
 | |
|     krb5_context context;
 | |
|     krb5_data data;
 | |
|     char s[22];
 | |
|     char *end;
 | |
|     int64_t n;
 | |
| 
 | |
|     if (src) switch (src->element) {
 | |
|     case choice_PrincipalNameAttrSrc_enc_ticket_part:
 | |
|         ticket = &src->u.enc_ticket_part;
 | |
|         break;
 | |
|     case choice_PrincipalNameAttrSrc_enc_kdc_rep_part:
 | |
|     default:
 | |
|         return GSS_S_UNAVAILABLE;
 | |
|     }
 | |
| 
 | |
|     if (!nameattrs || !frag->length || frag->length > sizeof(s) - 1)
 | |
|         return GSS_S_UNAVAILABLE;
 | |
| 
 | |
|     /* Output a specific AD element from the ticket or authenticator */
 | |
|     krb5_data_zero(&data);
 | |
|     memcpy(s, frag->value, frag->length);
 | |
|     s[frag->length] = '\0';
 | |
|     errno = 0;
 | |
|     n = strtoll(s, &end, 10);
 | |
|     if (end[0] == '\0' && (errno || n > INT_MAX || n < INT_MIN)) {
 | |
|         *minor_status = ERANGE;
 | |
|         return GSS_S_UNAVAILABLE;
 | |
|     }
 | |
|     if (end[0] != '\0') {
 | |
|         *minor_status = EINVAL;
 | |
|         return GSS_S_UNAVAILABLE;
 | |
|     }
 | |
| 
 | |
|     if (authenticated)
 | |
|         *authenticated = 0;
 | |
|     if (complete)
 | |
|         *complete = 1;
 | |
| 
 | |
|     GSSAPI_KRB5_INIT(&context);
 | |
| 
 | |
|     kret = ENOENT;
 | |
|     if (ticket && ticket->authorization_data) {
 | |
|         kret = _krb5_get_ad(context, ticket->authorization_data,
 | |
|                             NULL, n, value ? &data : NULL);
 | |
| 
 | |
|         /* If it's from the ticket, it _may_ be authenticated: */
 | |
|         if (kret == 0 && authenticated) {
 | |
|             if (n == KRB5_AUTHDATA_KDC_ISSUED)
 | |
|                 *authenticated = nameattrs->kdc_issued_verified;
 | |
|             else if (n == KRB5_AUTHDATA_WIN2K_PAC)
 | |
|                 *authenticated = nameattrs->pac_verified;
 | |
|         }
 | |
|     }
 | |
|     if (kret == ENOENT && nameattrs->authenticator_ad &&
 | |
|         n != KRB5_AUTHDATA_KDC_ISSUED &&
 | |
|         n != KRB5_AUTHDATA_WIN2K_PAC) {
 | |
|         kret = _krb5_get_ad(context, nameattrs->authenticator_ad,
 | |
|                             NULL, n, value ? &data : NULL);
 | |
|     }
 | |
| 
 | |
|     if (value) {
 | |
|         value->length = data.length;
 | |
|         value->value = data.data;
 | |
|     }
 | |
|     *minor_status = kret;
 | |
|     if (kret == ENOENT)
 | |
|         return GSS_S_UNAVAILABLE;
 | |
|     return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE;
 | |
| }
 | |
| 
 | |
| static OM_uint32
 | |
| get_ticket_authz_data(OM_uint32 *minor_status,
 | |
|                       const CompositePrincipal *name,
 | |
|                       gss_const_buffer_t prefix,
 | |
|                       gss_const_buffer_t attr,
 | |
|                       gss_const_buffer_t frag,
 | |
|                       int *authenticated,
 | |
|                       int *complete,
 | |
|                       gss_buffer_t value,
 | |
|                       gss_buffer_t display_value,
 | |
|                       int *more)
 | |
| {
 | |
|     krb5_error_code kret = 0;
 | |
|     PrincipalNameAttrs *nameattrs = name->nameattrs;
 | |
|     PrincipalNameAttrSrc *src = nameattrs ? nameattrs->source : NULL;
 | |
|     EncTicketPart *ticket = NULL;
 | |
|     size_t sz;
 | |
| 
 | |
|     if (src) switch (src->element) {
 | |
|     case choice_PrincipalNameAttrSrc_enc_ticket_part:
 | |
|         ticket = &src->u.enc_ticket_part;
 | |
|         break;
 | |
|     case choice_PrincipalNameAttrSrc_enc_kdc_rep_part:
 | |
|     default:
 | |
|         return GSS_S_UNAVAILABLE;
 | |
|     }
 | |
| 
 | |
|     if (!ticket)
 | |
|         return GSS_S_UNAVAILABLE;
 | |
| 
 | |
|     if (complete)
 | |
|         *complete = 1;
 | |
| 
 | |
|     if (frag->length == sizeof("kdc-issued") - 1 &&
 | |
|         strncmp(frag->value, "kdc-issued", sizeof("kdc-issued") - 1) == 0) {
 | |
|         krb5_context context;
 | |
|         krb5_data data;
 | |
| 
 | |
|         GSSAPI_KRB5_INIT(&context);
 | |
|         if (authenticated)
 | |
|             *authenticated = nameattrs->kdc_issued_verified;
 | |
| 
 | |
|         kret = _krb5_get_ad(context, ticket->authorization_data,
 | |
|                             NULL, KRB5_AUTHDATA_KDC_ISSUED,
 | |
|                             value ? &data : NULL);
 | |
|         if (value) {
 | |
|             value->length = data.length;
 | |
|             value->value = data.data;
 | |
|         }
 | |
|         if (kret == ENOENT)
 | |
|             return GSS_S_UNAVAILABLE;
 | |
|         *minor_status = kret;
 | |
|         return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE;
 | |
|     } else if (frag->length) {
 | |
|         return GSS_S_UNAVAILABLE;
 | |
|     }
 | |
| 
 | |
|     /* Just because it's in the Ticket doesn't make it authenticated */
 | |
|     if (authenticated)
 | |
|         *authenticated = 0;
 | |
| 
 | |
|     if (value) {
 | |
|         ASN1_MALLOC_ENCODE(AuthorizationData, value->value, value->length,
 | |
|                            ticket->authorization_data, &sz, kret);
 | |
|         *minor_status = kret;
 | |
|     }
 | |
|     return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE;
 | |
| }
 | |
| 
 | |
| static OM_uint32
 | |
| get_authenticator_authz_data(OM_uint32 *minor_status,
 | |
|                              const CompositePrincipal *name,
 | |
|                              gss_const_buffer_t prefix,
 | |
|                              gss_const_buffer_t attr,
 | |
|                              gss_const_buffer_t frag,
 | |
|                              int *authenticated,
 | |
|                              int *complete,
 | |
|                              gss_buffer_t value,
 | |
|                              gss_buffer_t display_value,
 | |
|                              int *more)
 | |
| {
 | |
|     krb5_error_code kret = 0;
 | |
|     PrincipalNameAttrs *nameattrs = name->nameattrs;
 | |
|     size_t sz;
 | |
| 
 | |
|     if (!nameattrs || !nameattrs->authenticator_ad)
 | |
|         return GSS_S_UNAVAILABLE;
 | |
|     if (authenticated)
 | |
|         *authenticated = 0;
 | |
|     if (complete)
 | |
|         *complete = 1;
 | |
| 
 | |
|     if (value) {
 | |
|         ASN1_MALLOC_ENCODE(AuthorizationData, value->value, value->length,
 | |
|                            nameattrs->authenticator_ad, &sz, kret);
 | |
|         *minor_status = kret;
 | |
|     }
 | |
|     return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE;
 | |
| }
 | |
| 
 | |
| static OM_uint32
 | |
| set_authenticator_authz_data(OM_uint32 *minor_status,
 | |
|                              CompositePrincipal *name,
 | |
|                              gss_const_buffer_t prefix,
 | |
|                              gss_const_buffer_t attr,
 | |
|                              gss_const_buffer_t frag,
 | |
|                              int complete,
 | |
|                              gss_buffer_t value)
 | |
| {
 | |
|     AuthorizationDataElement e;
 | |
|     krb5_error_code kret;
 | |
|     size_t sz;
 | |
| 
 | |
|     if (!value)
 | |
|         return GSS_S_CALL_INACCESSIBLE_READ;
 | |
|     if (frag->length &&
 | |
|         !ATTR_EQ(frag, "if-relevant"))
 | |
|         return GSS_S_UNAVAILABLE;
 | |
| 
 | |
|     if ((name->nameattrs == NULL &&
 | |
|         (name->nameattrs = calloc(1, sizeof(*name->nameattrs))) == NULL) ||
 | |
|         (name->nameattrs->want_ad == NULL &&
 | |
|          (name->nameattrs->want_ad =
 | |
|           calloc(1, sizeof(*name->nameattrs->want_ad))) == NULL)) {
 | |
|         *minor_status = ENOMEM;
 | |
|         return GSS_S_FAILURE;
 | |
|     }
 | |
| 
 | |
|     memset(&e, 0, sizeof(e));
 | |
|     kret = decode_AuthorizationDataElement(value->value, value->length, &e,
 | |
|                                            &sz);
 | |
|     if (kret == 0) {
 | |
|         if (frag->length) {
 | |
|             AuthorizationData ir;
 | |
| 
 | |
|             ir.len = 0;
 | |
|             ir.val = NULL;
 | |
|             kret = add_AuthorizationData(&ir, &e);
 | |
|             free_AuthorizationDataElement(&e);
 | |
|             if (kret == 0) {
 | |
|                 e.ad_type = KRB5_AUTHDATA_IF_RELEVANT;
 | |
|                 ASN1_MALLOC_ENCODE(AuthorizationData, e.ad_data.data,
 | |
|                                    e.ad_data.length, &ir, &sz, kret);
 | |
|                 kret = add_AuthorizationData(name->nameattrs->want_ad, &e);
 | |
|             }
 | |
|             free_AuthorizationData(&ir);
 | |
|         } else {
 | |
|             kret = add_AuthorizationData(name->nameattrs->want_ad, &e);
 | |
|             free_AuthorizationDataElement(&e);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     *minor_status = kret;
 | |
|     return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE;
 | |
| }
 | |
| 
 | |
| static OM_uint32
 | |
| get_transited(OM_uint32 *minor_status,
 | |
|               const CompositePrincipal *name,
 | |
|               gss_const_buffer_t prefix,
 | |
|               gss_const_buffer_t attr,
 | |
|               gss_const_buffer_t frag,
 | |
|               int *authenticated,
 | |
|               int *complete,
 | |
|               gss_buffer_t value,
 | |
|               gss_buffer_t display_value,
 | |
|               int *more)
 | |
| {
 | |
|     krb5_error_code kret = 0;
 | |
|     PrincipalNameAttrs *nameattrs = name->nameattrs;
 | |
|     PrincipalNameAttrSrc *src = nameattrs ? nameattrs->source : NULL;
 | |
|     EncTicketPart *ticket = NULL;
 | |
|     size_t sz;
 | |
| 
 | |
|     if (src) switch (src->element) {
 | |
|     case choice_PrincipalNameAttrSrc_enc_kdc_rep_part:
 | |
|         break;
 | |
|     case choice_PrincipalNameAttrSrc_enc_ticket_part:
 | |
|         ticket = &src->u.enc_ticket_part;
 | |
|         break;
 | |
|     default:
 | |
|         return GSS_S_UNAVAILABLE;
 | |
|     }
 | |
| 
 | |
|     if (!nameattrs || !ticket)
 | |
|         return GSS_S_UNAVAILABLE;
 | |
| 
 | |
|     if (authenticated)
 | |
|         *authenticated = 1;
 | |
|     if (complete)
 | |
|         *complete = 1;
 | |
| 
 | |
|     if (value && ticket)
 | |
|         ASN1_MALLOC_ENCODE(TransitedEncoding, value->value, value->length,
 | |
|                            &ticket->transited, &sz, kret);
 | |
|     else if (value && nameattrs->transited)
 | |
|         ASN1_MALLOC_ENCODE(TransitedEncoding, value->value, value->length,
 | |
|                            nameattrs->transited, &sz, kret);
 | |
|     *minor_status = kret;
 | |
|     return kret == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE;
 | |
| }
 | |
| 
 | |
| static OM_uint32
 | |
| get_canonical_name(OM_uint32 *minor_status,
 | |
|                    const CompositePrincipal *name,
 | |
|                    gss_const_buffer_t prefix,
 | |
|                    gss_const_buffer_t attr,
 | |
|                    gss_const_buffer_t frag,
 | |
|                    int *authenticated,
 | |
|                    int *complete,
 | |
|                    gss_buffer_t value,
 | |
|                    gss_buffer_t display_value,
 | |
|                    int *more)
 | |
| {
 | |
|     krb5_error_code kret = 0;
 | |
|     PrincipalNameAttrs *nameattrs = name->nameattrs;
 | |
|     PrincipalNameAttrSrc *src = nameattrs ? nameattrs->source : NULL;
 | |
|     krb5_principal p = NULL;
 | |
|     krb5_context context;
 | |
|     EncTicketPart *ticket = NULL;
 | |
|     EncKDCRepPart *kdcrep = NULL;
 | |
| 
 | |
|     if (src) switch (src->element) {
 | |
|     case choice_PrincipalNameAttrSrc_enc_kdc_rep_part:
 | |
|         kdcrep = &src->u.enc_kdc_rep_part;
 | |
|         break;
 | |
|     case choice_PrincipalNameAttrSrc_enc_ticket_part:
 | |
|         ticket = &src->u.enc_ticket_part;
 | |
|         break;
 | |
|     default:
 | |
|         return GSS_S_UNAVAILABLE;
 | |
|     }
 | |
| 
 | |
|     GSSAPI_KRB5_INIT(&context);
 | |
| 
 | |
|     if (authenticated)
 | |
|         *authenticated = 1;
 | |
|     if (complete)
 | |
|         *complete = 1;
 | |
| 
 | |
|     if (kdcrep) {
 | |
|         kret = _krb5_principalname2krb5_principal(context, &p,
 | |
|                                                   kdcrep->sname,
 | |
|                                                   kdcrep->srealm);
 | |
|     } else if (ticket) {
 | |
|         krb5_data data;
 | |
|         krb5_pac pac = NULL;
 | |
| 
 | |
|         krb5_data_zero(&data);
 | |
| 
 | |
|         /* Use canonical name from PAC if available */
 | |
|         kret = _krb5_get_ad(context, ticket->authorization_data,
 | |
|                             NULL, KRB5_AUTHDATA_WIN2K_PAC, &data);
 | |
|         if (kret == 0)
 | |
|             kret = krb5_pac_parse(context, data.data, data.length, &pac);
 | |
|         if (kret == 0)
 | |
|             kret = _krb5_pac_get_canon_principal(context, pac, &p);
 | |
|         if (kret == 0 && authenticated)
 | |
|             *authenticated = nameattrs->pac_verified;
 | |
|         else if (kret == ENOENT)
 | |
|             kret = _krb5_principalname2krb5_principal(context, &p,
 | |
|                                                       ticket->cname,
 | |
|                                                       ticket->crealm);
 | |
| 
 | |
|         krb5_data_free(&data);
 | |
|         krb5_pac_free(context, pac);
 | |
|     } else
 | |
|         return GSS_S_UNAVAILABLE;
 | |
|     if (kret == 0 && value) {
 | |
|         OM_uint32 major;
 | |
|         /*
 | |
|          * Value is exported name token (exported composite name token
 | |
|          * should also work).
 | |
|          */
 | |
|         major = _gsskrb5_export_name(minor_status, (gss_name_t)p, value);
 | |
|         if (major != GSS_S_COMPLETE) {
 | |
|             krb5_free_principal(context, p);
 | |
|             return major;
 | |
|         }
 | |
|     }
 | |
|     if (kret == 0 && display_value) {
 | |
|         /* Display value is principal name display form */
 | |
|         kret = krb5_unparse_name(context, p,
 | |
|                                  (char **)&display_value->value);
 | |
|         if (kret == 0)
 | |
|             display_value->length = strlen(display_value->value);
 | |
|     }
 | |
| 
 | |
|     krb5_free_principal(context, p);
 | |
|     if (kret) {
 | |
|         if (value) {
 | |
|             free(value->value);
 | |
|             value->length = 0;
 | |
|             value->value = NULL;
 | |
|         }
 | |
|         *minor_status = kret;
 | |
|         return GSS_S_UNAVAILABLE;
 | |
|     }
 | |
|     return GSS_S_COMPLETE;
 | |
| }
 | 
