LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/krb5 - principal.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 521 967 53.9 %
Date: 2024-04-21 15:09:00 Functions: 45 63 71.4 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 1997-2007 Kungliga Tekniska Högskolan
       3             :  * (Royal Institute of Technology, Stockholm, Sweden).
       4             :  * All rights reserved.
       5             :  *
       6             :  * Redistribution and use in source and binary forms, with or without
       7             :  * modification, are permitted provided that the following conditions
       8             :  * are met:
       9             :  *
      10             :  * 1. Redistributions of source code must retain the above copyright
      11             :  *    notice, this list of conditions and the following disclaimer.
      12             :  *
      13             :  * 2. Redistributions in binary form must reproduce the above copyright
      14             :  *    notice, this list of conditions and the following disclaimer in the
      15             :  *    documentation and/or other materials provided with the distribution.
      16             :  *
      17             :  * 3. Neither the name of the Institute nor the names of its contributors
      18             :  *    may be used to endorse or promote products derived from this software
      19             :  *    without specific prior written permission.
      20             :  *
      21             :  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
      22             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      23             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      24             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
      25             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      26             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      27             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      28             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      29             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      30             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      31             :  * SUCH DAMAGE.
      32             :  */
      33             : 
      34             : /**
      35             :  * @page krb5_principal_intro The principal handing functions.
      36             :  *
      37             :  * A Kerberos principal is a email address looking string that
      38             :  * contains two parts separated by @.  The second part is the kerberos
      39             :  * realm the principal belongs to and the first is a list of 0 or
      40             :  * more components. For example
      41             :  * @verbatim
      42             : lha@SU.SE
      43             : host/hummel.it.su.se@SU.SE
      44             : host/admin@H5L.ORG
      45             : @endverbatim
      46             :  *
      47             :  * See the library functions here: @ref krb5_principal
      48             :  */
      49             : 
      50             : #include "krb5_locl.h"
      51             : #ifdef HAVE_RES_SEARCH
      52             : #define USE_RESOLVER
      53             : #endif
      54             : #ifdef HAVE_ARPA_NAMESER_H
      55             : #include <arpa/nameser.h>
      56             : #endif
      57             : #include <fnmatch.h>
      58             : #include "resolve.h"
      59             : 
      60             : #define princ_num_comp(P) ((P)->name.name_string.len)
      61             : #define princ_type(P) ((P)->name.name_type)
      62             : #define princ_comp(P) ((P)->name.name_string.val)
      63             : #define princ_ncomp(P, N) ((P)->name.name_string.val[(N)])
      64             : #define princ_realm(P) ((P)->realm)
      65             : 
      66             : static krb5_error_code
      67     1369904 : set_default_princ_type(krb5_principal p, NAME_TYPE defnt)
      68             : {
      69     1369904 :     if (princ_num_comp(p) > 1 && strcmp(princ_ncomp(p, 0), KRB5_TGS_NAME) == 0)
      70      223512 :         princ_type(p) = KRB5_NT_SRV_INST;
      71     1146392 :     else if (princ_num_comp(p) > 1 && strcmp(princ_ncomp(p, 0), "host") == 0)
      72       54525 :         princ_type(p) = KRB5_NT_SRV_HST;
      73     1091867 :     else if (princ_num_comp(p) > 1 && strcmp(princ_ncomp(p, 0), "kca_service") == 0)
      74           0 :         princ_type(p) = KRB5_NT_SRV_HST;
      75     1091867 :     else if (princ_num_comp(p) == 2 &&
      76      488574 :              strcmp(princ_ncomp(p, 0), KRB5_WELLKNOWN_NAME) == 0)
      77         416 :         princ_type(p) = KRB5_NT_WELLKNOWN;
      78     1091451 :     else if (princ_num_comp(p) == 1 && strchr(princ_ncomp(p, 0), '@') != NULL)
      79         577 :         princ_type(p) = KRB5_NT_SMTP_NAME;
      80             :     else
      81     1090874 :         princ_type(p) = defnt;
      82     1369904 :     return 0;
      83             : }
      84             : 
      85             : static krb5_error_code append_component(krb5_context, krb5_principal,
      86             :                                         const char *, size_t);
      87             : 
      88             : /**
      89             :  * Frees a Kerberos principal allocated by the library with
      90             :  * krb5_parse_name(), krb5_make_principal() or any other related
      91             :  * principal functions.
      92             :  *
      93             :  * @param context A Kerberos context.
      94             :  * @param p a principal to free.
      95             :  *
      96             :  * @return An krb5 error code, see krb5_get_error_message().
      97             :  *
      98             :  * @ingroup krb5_principal
      99             :  */
     100             : 
     101             : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
     102    10588963 : krb5_free_principal(krb5_context context,
     103             :                     krb5_principal p)
     104             : {
     105    10588963 :     if(p){
     106     8755861 :         if (p->nameattrs && p->nameattrs->pac)
     107     1440517 :             heim_release(p->nameattrs->pac);
     108     8755861 :         free_Principal(p);
     109     8755861 :         free(p);
     110             :     }
     111    10588963 : }
     112             : 
     113             : /**
     114             :  * Set the type of the principal
     115             :  *
     116             :  * @param context A Kerberos context.
     117             :  * @param principal principal to set the type for
     118             :  * @param type the new type
     119             :  *
     120             :  * @return An krb5 error code, see krb5_get_error_message().
     121             :  *
     122             :  * @ingroup krb5_principal
     123             :  */
     124             : 
     125             : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
     126       96006 : krb5_principal_set_type(krb5_context context,
     127             :                         krb5_principal principal,
     128             :                         int type)
     129             : {
     130       96006 :     princ_type(principal) = type;
     131       96006 : }
     132             : 
     133             : /**
     134             :  * Get the type of the principal
     135             :  *
     136             :  * @param context A Kerberos context.
     137             :  * @param principal principal to get the type for
     138             :  *
     139             :  * @return the type of principal
     140             :  *
     141             :  * @ingroup krb5_principal
     142             :  */
     143             : 
     144             : KRB5_LIB_FUNCTION int KRB5_LIB_CALL
     145      611028 : krb5_principal_get_type(krb5_context context,
     146             :                         krb5_const_principal principal)
     147             : {
     148      611028 :     return princ_type(principal);
     149             : }
     150             : 
     151             : /**
     152             :  * Get the realm of the principal
     153             :  *
     154             :  * @param context A Kerberos context.
     155             :  * @param principal principal to get the realm for
     156             :  *
     157             :  * @return realm of the principal, don't free or use after krb5_principal is freed
     158             :  *
     159             :  * @ingroup krb5_principal
     160             :  */
     161             : 
     162             : KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
     163     1209516 : krb5_principal_get_realm(krb5_context context,
     164             :                          krb5_const_principal principal)
     165             : {
     166     1209516 :     return princ_realm(principal);
     167             : }
     168             : 
     169             : KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
     170     1479508 : krb5_principal_get_comp_string(krb5_context context,
     171             :                                krb5_const_principal principal,
     172             :                                unsigned int component)
     173             : {
     174     1479508 :     if(component >= princ_num_comp(principal))
     175      101615 :        return NULL;
     176     1374480 :     return princ_ncomp(principal, component);
     177             : }
     178             : 
     179             : /**
     180             :  * Get number of component is principal.
     181             :  *
     182             :  * @param context Kerberos 5 context
     183             :  * @param principal principal to query
     184             :  *
     185             :  * @return number of components in string
     186             :  *
     187             :  * @ingroup krb5_principal
     188             :  */
     189             : 
     190             : KRB5_LIB_FUNCTION unsigned int KRB5_LIB_CALL
     191     1364692 : krb5_principal_get_num_comp(krb5_context context,
     192             :                             krb5_const_principal principal)
     193             : {
     194     1364692 :     return princ_num_comp(principal);
     195             : }
     196             : 
     197             : /**
     198             :  * Parse a name into a krb5_principal structure, flags controls the behavior.
     199             :  *
     200             :  * @param context Kerberos 5 context
     201             :  * @param name name to parse into a Kerberos principal
     202             :  * @param flags flags to control the behavior
     203             :  * @param principal returned principal, free with krb5_free_principal().
     204             :  *
     205             :  * @return An krb5 error code, see krb5_get_error_message().
     206             :  *
     207             :  * @ingroup krb5_principal
     208             :  */
     209             : 
     210             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     211      719483 : krb5_parse_name_flags(krb5_context context,
     212             :                       const char *name,
     213             :                       int flags,
     214             :                       krb5_principal *principal)
     215             : {
     216       22730 :     krb5_error_code ret;
     217       22730 :     heim_general_string *comp;
     218      719483 :     heim_general_string realm = NULL;
     219       22730 :     int ncomp;
     220             : 
     221       22730 :     const char *p;
     222       22730 :     char *q;
     223       22730 :     char *s;
     224       22730 :     char *start;
     225             : 
     226       22730 :     int n;
     227       22730 :     char c;
     228      719483 :     int got_realm = 0;
     229      719483 :     int first_at = 1;
     230      719483 :     int no_realm = flags & KRB5_PRINCIPAL_PARSE_NO_REALM;
     231      719483 :     int require_realm = flags & KRB5_PRINCIPAL_PARSE_REQUIRE_REALM;
     232      719483 :     int enterprise = flags & KRB5_PRINCIPAL_PARSE_ENTERPRISE;
     233      719483 :     int ignore_realm = flags & KRB5_PRINCIPAL_PARSE_IGNORE_REALM;
     234      719483 :     int no_def_realm = flags & KRB5_PRINCIPAL_PARSE_NO_DEF_REALM;
     235             : 
     236      719483 :     *principal = NULL;
     237             : 
     238      719483 :     if (no_realm && require_realm) {
     239           0 :         krb5_set_error_message(context, EINVAL,
     240           0 :                                N_("Can't require both realm and "
     241             :                                   "no realm at the same time", ""));
     242           0 :         return EINVAL;
     243             :     }
     244             : 
     245             :     /* count number of component,
     246             :      * enterprise names only have one component
     247             :      */
     248      719483 :     ncomp = 1;
     249      719483 :     if (!enterprise) {
     250     7728807 :         for (p = name; *p; p++) {
     251     7552730 :             if (*p=='\\') {
     252        2663 :                 if (!p[1]) {
     253           0 :                     krb5_set_error_message(context, KRB5_PARSE_MALFORMED,
     254           0 :                                            N_("trailing \\ in principal name", ""));
     255           0 :                     return KRB5_PARSE_MALFORMED;
     256             :                 }
     257        2663 :                 p++;
     258     7550067 :             } else if (*p == '/')
     259      100441 :                 ncomp++;
     260     7449626 :             else if (*p == '@')
     261      424163 :                 break;
     262             :         }
     263             :     }
     264      719483 :     comp = calloc(ncomp, sizeof(*comp));
     265      719483 :     if (comp == NULL)
     266           0 :         return krb5_enomem(context);
     267             : 
     268      719483 :     n = 0;
     269      719483 :     p = start = q = s = strdup(name);
     270      719483 :     if (start == NULL) {
     271           0 :         free(comp);
     272           0 :         return krb5_enomem(context);
     273             :     }
     274    21437686 :     while (*p) {
     275    20718205 :         c = *p++;
     276    20718205 :         if (c == '\\') {
     277        2663 :             c = *p++;
     278        2663 :             if (c == 'n')
     279           0 :                 c = '\n';
     280        2663 :             else if (c == 't')
     281           0 :                 c = '\t';
     282        2663 :             else if (c == 'b')
     283           0 :                 c = '\b';
     284        2663 :             else if (c == '0') {
     285             :                 /*
     286             :                  * We'll ignore trailing embedded NULs in components and
     287             :                  * realms, but can't support any other embedded NULs.
     288             :                  */
     289           0 :                 while (*p) {
     290           0 :                     if ((*p == '/' || *p == '@') && !got_realm)
     291           0 :                         break;
     292           0 :                     if (*(p++) != '\\' || *(p++) != '0') {
     293           0 :                         ret = KRB5_PARSE_MALFORMED;
     294           0 :                         krb5_set_error_message(context, ret,
     295           0 :                                                N_("embedded NULs in principal "
     296             :                                                   "name not supported", ""));
     297           0 :                         goto exit;
     298             :                     }
     299             :                 }
     300           0 :                 continue;
     301        2663 :             } else if (c == '\0') {
     302           0 :                 ret = KRB5_PARSE_MALFORMED;
     303           0 :                 krb5_set_error_message(context, ret,
     304           0 :                                        N_("trailing \\ in principal name", ""));
     305           0 :                 goto exit;
     306             :             }
     307    20715542 :         } else if (enterprise && first_at) {
     308     1432082 :             if (c == '@')
     309      104447 :                 first_at = 0;
     310    19283460 :         } else if ((c == '/' && !enterprise) || c == '@') {
     311      539395 :             if (got_realm) {
     312           2 :                 ret = KRB5_PARSE_MALFORMED;
     313           2 :                 krb5_set_error_message(context, ret,
     314           2 :                                        N_("part after realm in principal name", ""));
     315           2 :                 goto exit;
     316             :             } else {
     317      539393 :                 comp[n] = malloc(q - start + 1);
     318      539393 :                 if (comp[n] == NULL) {
     319           0 :                     ret = krb5_enomem(context);
     320           0 :                     goto exit;
     321             :                 }
     322      539393 :                 memcpy(comp[n], start, q - start);
     323      539393 :                 comp[n][q - start] = 0;
     324      539393 :                 n++;
     325             :             }
     326      539393 :             if (c == '@')
     327      438952 :                 got_realm = 1;
     328      539393 :             start = q;
     329      539393 :             continue;
     330             :         }
     331    20178810 :         if (got_realm && (c == '/' || c == '\0')) {
     332           0 :             ret = KRB5_PARSE_MALFORMED;
     333           0 :             krb5_set_error_message(context, ret,
     334           0 :                                    N_("part after realm in principal name", ""));
     335           0 :             goto exit;
     336             :         }
     337    20178810 :         *q++ = c;
     338             :     }
     339      719481 :     if (got_realm) {
     340      438950 :         if (no_realm) {
     341           6 :             ret = KRB5_PARSE_MALFORMED;
     342           6 :             krb5_set_error_message(context, ret,
     343           6 :                                    N_("realm found in 'short' principal "
     344             :                                       "expected to be without one", ""));
     345           6 :             goto exit;
     346             :         }
     347      438944 :         if (!ignore_realm) {
     348      438944 :             realm = malloc(q - start + 1);
     349      438944 :             if (realm == NULL) {
     350           0 :                 ret = krb5_enomem(context);
     351           0 :                 goto exit;
     352             :             }
     353      438944 :             memcpy(realm, start, q - start);
     354      438944 :             realm[q - start] = 0;
     355             :         }
     356             :     } else {
     357      280531 :         if (require_realm) {
     358        2684 :             ret = KRB5_PARSE_MALFORMED;
     359        2684 :             krb5_set_error_message(context, ret,
     360        2684 :                                    N_("realm NOT found in principal "
     361             :                                       "expected to be with one", ""));
     362        2684 :             goto exit;
     363      277847 :         } else if (no_realm || no_def_realm) {
     364      245218 :             realm = NULL;
     365             :         } else {
     366       32629 :             ret = krb5_get_default_realm(context, &realm);
     367       32629 :             if (ret)
     368           0 :                 goto exit;
     369             :         }
     370             : 
     371      277847 :         comp[n] = malloc(q - start + 1);
     372      277847 :         if (comp[n] == NULL) {
     373           0 :             ret = krb5_enomem(context);
     374           0 :             goto exit;
     375             :         }
     376      277847 :         memcpy(comp[n], start, q - start);
     377      277847 :         comp[n][q - start] = 0;
     378      277847 :         n++;
     379             :     }
     380      716791 :     *principal = calloc(1, sizeof(**principal));
     381      716791 :     if (*principal == NULL) {
     382           0 :         ret = krb5_enomem(context);
     383           0 :         goto exit;
     384             :     }
     385      716791 :     (*principal)->name.name_string.val = comp;
     386      716791 :     princ_num_comp(*principal) = n;
     387      716791 :     (*principal)->realm = realm;
     388      716791 :     if (enterprise)
     389      104455 :         princ_type(*principal) = KRB5_NT_ENTERPRISE_PRINCIPAL;
     390             :     else
     391      612336 :         set_default_princ_type(*principal, KRB5_NT_PRINCIPAL);
     392      716791 :     free(s);
     393      716791 :     return 0;
     394        2692 : exit:
     395        3137 :     while (n>0) {
     396         445 :         free(comp[--n]);
     397             :     }
     398        2692 :     free(comp);
     399        2692 :     krb5_free_default_realm(context, realm);
     400        2692 :     free(s);
     401        2692 :     return ret;
     402             : }
     403             : 
     404             : /**
     405             :  * Parse a name into a krb5_principal structure
     406             :  *
     407             :  * @param context Kerberos 5 context
     408             :  * @param name name to parse into a Kerberos principal
     409             :  * @param principal returned principal, free with krb5_free_principal().
     410             :  *
     411             :  * @return An krb5 error code, see krb5_get_error_message().
     412             :  *
     413             :  * @ingroup krb5_principal
     414             :  */
     415             : 
     416             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     417      346664 : krb5_parse_name(krb5_context context,
     418             :                 const char *name,
     419             :                 krb5_principal *principal)
     420             : {
     421      346664 :     return krb5_parse_name_flags(context, name, 0, principal);
     422             : }
     423             : 
     424             : static const char quotable_chars[] = " \n\t\b\\/@";
     425             : static const char replace_chars[] = " ntb\\/@";
     426             : 
     427             : #define add_char(BASE, INDEX, LEN, C) do { if((INDEX) < (LEN)) (BASE)[(INDEX)++] = (C); }while(0);
     428             : 
     429             : static size_t
     430     2352318 : quote_string(const char *s, char *out, size_t idx, size_t len, int display)
     431             : {
     432       72147 :     const char *p, *q;
     433    38286006 :     for(p = s; *p && idx < len; p++){
     434    35933688 :         q = strchr(quotable_chars, *p);
     435    35933688 :         if (q && display) {
     436        6365 :             add_char(out, idx, len, replace_chars[q - quotable_chars]);
     437    35927323 :         } else if (q) {
     438       13852 :             add_char(out, idx, len, '\\');
     439       13852 :             add_char(out, idx, len, replace_chars[q - quotable_chars]);
     440             :         }else
     441    35913474 :             add_char(out, idx, len, *p);
     442             :     }
     443     2352318 :     if(idx < len)
     444     2352318 :         out[idx] = '\0';
     445     2352318 :     return idx;
     446             : }
     447             : 
     448             : 
     449             : static krb5_error_code
     450     1228355 : unparse_name_fixed(krb5_context context,
     451             :                    krb5_const_principal principal,
     452             :                    char *name,
     453             :                    size_t len,
     454             :                    int flags)
     455             : {
     456     1228355 :     size_t idx = 0;
     457       37879 :     size_t i;
     458     1228355 :     int short_form = (flags & KRB5_PRINCIPAL_UNPARSE_SHORT) != 0;
     459     1228355 :     int no_realm = (flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) != 0;
     460     1228355 :     int display = (flags & KRB5_PRINCIPAL_UNPARSE_DISPLAY) != 0;
     461             : 
     462     1228355 :     if (name == NULL) {
     463           0 :         krb5_set_error_message(context, EINVAL,
     464           0 :                                N_("Invalid name buffer, "
     465             :                                   "can't unparse", ""));
     466           0 :         return EINVAL;
     467             :     }
     468             : 
     469     1228355 :     if (len == 0) {
     470           0 :         krb5_set_error_message(context, ERANGE,
     471           0 :                                N_("Invalid name buffer length, "
     472             :                                   "can't unparse", ""));
     473           0 :         return ERANGE;
     474             :     }
     475             : 
     476     1228355 :     name[0] = '\0';
     477             : 
     478     1228355 :     if (!no_realm && princ_realm(principal) == NULL) {
     479           0 :         krb5_set_error_message(context, ERANGE,
     480           0 :                                N_("Realm missing from principal, "
     481             :                                   "can't unparse", ""));
     482           0 :         return ERANGE;
     483             :     }
     484             : 
     485     2717915 :     for(i = 0; i < princ_num_comp(principal); i++){
     486     1489560 :         if(i)
     487      261205 :             add_char(name, idx, len, '/');
     488     1489560 :         idx = quote_string(princ_ncomp(principal, i), name, idx, len, display);
     489     1489560 :         if(idx == len) {
     490           0 :             krb5_set_error_message(context, ERANGE,
     491           0 :                                    N_("Out of space printing principal", ""));
     492           0 :             return ERANGE;
     493             :         }
     494             :     }
     495             :     /* add realm if different from default realm */
     496     1228355 :     if(short_form && !no_realm) {
     497           0 :         krb5_realm r;
     498           0 :         krb5_error_code ret;
     499           0 :         ret = krb5_get_default_realm(context, &r);
     500           0 :         if(ret)
     501           0 :             return ret;
     502           0 :         if(strcmp(princ_realm(principal), r) != 0)
     503           0 :             short_form = 0;
     504           0 :         krb5_free_default_realm(context, r);
     505             :     }
     506     1228355 :     if(!short_form && !no_realm) {
     507      862758 :         add_char(name, idx, len, '@');
     508      862758 :         idx = quote_string(princ_realm(principal), name, idx, len, display);
     509      862758 :         if(idx == len) {
     510           0 :             krb5_set_error_message(context, ERANGE,
     511           0 :                                    N_("Out of space printing "
     512             :                                       "realm of principal", ""));
     513           0 :             return ERANGE;
     514             :         }
     515             :     }
     516     1190476 :     return 0;
     517             : }
     518             : 
     519             : /**
     520             :  * Unparse the principal name to a fixed buffer
     521             :  *
     522             :  * @param context A Kerberos context.
     523             :  * @param principal principal to unparse
     524             :  * @param name buffer to write name to
     525             :  * @param len length of buffer
     526             :  *
     527             :  * @return An krb5 error code, see krb5_get_error_message().
     528             :  *
     529             :  * @ingroup krb5_principal
     530             :  */
     531             : 
     532             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     533        5108 : krb5_unparse_name_fixed(krb5_context context,
     534             :                         krb5_const_principal principal,
     535             :                         char *name,
     536             :                         size_t len)
     537             : {
     538        5108 :     return unparse_name_fixed(context, principal, name, len, 0);
     539             : }
     540             : 
     541             : /**
     542             :  * Unparse the principal name to a fixed buffer. The realm is skipped
     543             :  * if its a default realm.
     544             :  *
     545             :  * @param context A Kerberos context.
     546             :  * @param principal principal to unparse
     547             :  * @param name buffer to write name to
     548             :  * @param len length of buffer
     549             :  *
     550             :  * @return An krb5 error code, see krb5_get_error_message().
     551             :  *
     552             :  * @ingroup krb5_principal
     553             :  */
     554             : 
     555             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     556           0 : krb5_unparse_name_fixed_short(krb5_context context,
     557             :                               krb5_const_principal principal,
     558             :                               char *name,
     559             :                               size_t len)
     560             : {
     561           0 :     return unparse_name_fixed(context, principal, name, len,
     562             :                               KRB5_PRINCIPAL_UNPARSE_SHORT);
     563             : }
     564             : 
     565             : /**
     566             :  * Unparse the principal name with unparse flags to a fixed buffer.
     567             :  *
     568             :  * @param context A Kerberos context.
     569             :  * @param principal principal to unparse
     570             :  * @param flags unparse flags
     571             :  * @param name buffer to write name to
     572             :  * @param len length of buffer
     573             :  *
     574             :  * @return An krb5 error code, see krb5_get_error_message().
     575             :  *
     576             :  * @ingroup krb5_principal
     577             :  */
     578             : 
     579             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     580           0 : krb5_unparse_name_fixed_flags(krb5_context context,
     581             :                               krb5_const_principal principal,
     582             :                               int flags,
     583             :                               char *name,
     584             :                               size_t len)
     585             : {
     586           0 :     return unparse_name_fixed(context, principal, name, len, flags);
     587             : }
     588             : 
     589             : static krb5_error_code
     590     1223247 : unparse_name(krb5_context context,
     591             :              krb5_const_principal principal,
     592             :              char **name,
     593             :              int flags)
     594             : {
     595     1223247 :     size_t len = 0, plen;
     596       37879 :     size_t i;
     597       37879 :     krb5_error_code ret;
     598             :     /* count length */
     599     1223247 :     if (princ_realm(principal)) {
     600     1191701 :         plen = strlen(princ_realm(principal));
     601             : 
     602     1191701 :         if(strcspn(princ_realm(principal), quotable_chars) == plen)
     603     1154985 :             len += plen;
     604             :         else
     605           0 :             len += 2*plen;
     606     1191701 :         len++; /* '@' */
     607             :     }
     608     2705009 :     for(i = 0; i < princ_num_comp(principal); i++){
     609     1481762 :         plen = strlen(princ_ncomp(principal, i));
     610     1481762 :         if(strcspn(princ_ncomp(principal, i), quotable_chars) == plen)
     611     1463340 :             len += plen;
     612             :         else
     613       18422 :             len += 2*plen;
     614     1481762 :         len++;
     615             :     }
     616     1223247 :     len++; /* '\0' */
     617     1223247 :     *name = malloc(len);
     618     1223247 :     if(*name == NULL)
     619           0 :         return krb5_enomem(context);
     620     1223247 :     ret = unparse_name_fixed(context, principal, *name, len, flags);
     621     1223247 :     if(ret) {
     622           0 :         free(*name);
     623           0 :         *name = NULL;
     624             :     }
     625     1185368 :     return ret;
     626             : }
     627             : 
     628             : /**
     629             :  * Unparse the Kerberos name into a string
     630             :  *
     631             :  * @param context Kerberos 5 context
     632             :  * @param principal principal to query
     633             :  * @param name resulting string, free with krb5_xfree()
     634             :  *
     635             :  * @return An krb5 error code, see krb5_get_error_message().
     636             :  *
     637             :  * @ingroup krb5_principal
     638             :  */
     639             : 
     640             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     641      681878 : krb5_unparse_name(krb5_context context,
     642             :                   krb5_const_principal principal,
     643             :                   char **name)
     644             : {
     645      681878 :     return unparse_name(context, principal, name, 0);
     646             : }
     647             : 
     648             : /**
     649             :  * Unparse the Kerberos name into a string
     650             :  *
     651             :  * @param context Kerberos 5 context
     652             :  * @param principal principal to query
     653             :  * @param flags flag to determine the behavior
     654             :  * @param name resulting string, free with krb5_xfree()
     655             :  *
     656             :  * @return An krb5 error code, see krb5_get_error_message().
     657             :  *
     658             :  * @ingroup krb5_principal
     659             :  */
     660             : 
     661             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     662      541369 : krb5_unparse_name_flags(krb5_context context,
     663             :                         krb5_const_principal principal,
     664             :                         int flags,
     665             :                         char **name)
     666             : {
     667      541369 :     return unparse_name(context, principal, name, flags);
     668             : }
     669             : 
     670             : /**
     671             :  * Unparse the principal name to a allocated buffer. The realm is
     672             :  * skipped if its a default realm.
     673             :  *
     674             :  * @param context A Kerberos context.
     675             :  * @param principal principal to unparse
     676             :  * @param name returned buffer, free with krb5_xfree()
     677             :  *
     678             :  * @return An krb5 error code, see krb5_get_error_message().
     679             :  *
     680             :  * @ingroup krb5_principal
     681             :  */
     682             : 
     683             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     684           0 : krb5_unparse_name_short(krb5_context context,
     685             :                         krb5_const_principal principal,
     686             :                         char **name)
     687             : {
     688           0 :     return unparse_name(context, principal, name, KRB5_PRINCIPAL_UNPARSE_SHORT);
     689             : }
     690             : 
     691             : /**
     692             :  * Set a new realm for a principal, and as a side-effect free the
     693             :  * previous realm.
     694             :  *
     695             :  * @param context A Kerberos context.
     696             :  * @param principal principal set the realm for
     697             :  * @param realm the new realm to set
     698             :  *
     699             :  * @return An krb5 error code, see krb5_get_error_message().
     700             :  *
     701             :  * @ingroup krb5_principal
     702             :  */
     703             : 
     704             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     705      433558 : krb5_principal_set_realm(krb5_context context,
     706             :                          krb5_principal principal,
     707             :                          krb5_const_realm realm)
     708             : {
     709      433558 :     if (princ_realm(principal))
     710      225656 :         free(princ_realm(principal));
     711             : 
     712      433558 :     if (realm == NULL)
     713           0 :         princ_realm(principal) = NULL;
     714      433558 :     else if ((princ_realm(principal) = strdup(realm)) == NULL)
     715           0 :         return krb5_enomem(context);
     716      421788 :     return 0;
     717             : }
     718             : 
     719             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     720           0 : krb5_principal_set_comp_string(krb5_context context,
     721             :                                krb5_principal principal,
     722             :                                unsigned int k,
     723             :                                const char *component)
     724             : {
     725           0 :     char *s;
     726           0 :     size_t i;
     727             : 
     728           0 :     for (i = princ_num_comp(principal); i <= k; i++)
     729           0 :         append_component(context, principal, "", 0);
     730           0 :     s = strdup(component);
     731           0 :     if (s == NULL)
     732           0 :         return krb5_enomem(context);
     733           0 :     free(princ_ncomp(principal, k));
     734           0 :     princ_ncomp(principal, k) = s;
     735           0 :     return 0;
     736             : }
     737             : 
     738             : #ifndef HEIMDAL_SMALLER
     739             : /**
     740             :  * Build a principal using vararg style building
     741             :  *
     742             :  * @param context A Kerberos context.
     743             :  * @param principal returned principal
     744             :  * @param rlen length of realm
     745             :  * @param realm realm name
     746             :  * @param ... a list of components ended with NULL.
     747             :  *
     748             :  * @return An krb5 error code, see krb5_get_error_message().
     749             :  *
     750             :  * @ingroup krb5_principal
     751             :  */
     752             : 
     753             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     754        3064 : krb5_build_principal(krb5_context context,
     755             :                      krb5_principal *principal,
     756             :                      int rlen,
     757             :                      krb5_const_realm realm,
     758             :                      ...)
     759             : {
     760          28 :     krb5_error_code ret;
     761          28 :     va_list ap;
     762        3064 :     va_start(ap, realm);
     763        3064 :     ret = krb5_build_principal_va(context, principal, rlen, realm, ap);
     764        3064 :     va_end(ap);
     765        3064 :     return ret;
     766             : }
     767             : #endif
     768             : 
     769             : /**
     770             :  * Build a principal using vararg style building
     771             :  *
     772             :  * @param context A Kerberos context.
     773             :  * @param principal returned principal
     774             :  * @param realm realm name
     775             :  * @param ... a list of components ended with NULL.
     776             :  *
     777             :  * @return An krb5 error code, see krb5_get_error_message().
     778             :  *
     779             :  * @ingroup krb5_principal
     780             :  */
     781             : 
     782             : /* coverity[+alloc : arg-*1] */
     783             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     784      739042 : krb5_make_principal(krb5_context context,
     785             :                     krb5_principal *principal,
     786             :                     krb5_const_realm realm,
     787             :                     ...)
     788             : {
     789       17539 :     krb5_error_code ret;
     790      739042 :     krb5_realm r = NULL;
     791       17539 :     va_list ap;
     792             : 
     793      739042 :     *principal = NULL;
     794             : 
     795      739042 :     if(realm == NULL) {
     796           1 :         ret = krb5_get_default_realm(context, &r);
     797           1 :         if(ret)
     798           0 :             return ret;
     799           1 :         realm = r;
     800             :     }
     801      739042 :     va_start(ap, realm);
     802      739042 :     ret = krb5_build_principal_va(context, principal, strlen(realm), realm, ap);
     803      739042 :     va_end(ap);
     804      739042 :     if(r)
     805           1 :         krb5_free_default_realm(context, r);
     806      721503 :     return ret;
     807             : }
     808             : 
     809             : static krb5_error_code
     810     1477131 : append_component(krb5_context context, krb5_principal p,
     811             :                  const char *comp,
     812             :                  size_t comp_len)
     813             : {
     814       34670 :     heim_general_string *tmp;
     815     1477131 :     size_t len = princ_num_comp(p);
     816             : 
     817     1477131 :     tmp = realloc(princ_comp(p), (len + 1) * sizeof(*tmp));
     818     1477131 :     if(tmp == NULL)
     819           0 :         return krb5_enomem(context);
     820     1477131 :     princ_comp(p) = tmp;
     821     1477131 :     princ_ncomp(p, len) = malloc(comp_len + 1);
     822     1477131 :     if (princ_ncomp(p, len) == NULL)
     823           0 :         return krb5_enomem(context);
     824     1477131 :     memcpy (princ_ncomp(p, len), comp, comp_len);
     825     1477131 :     princ_ncomp(p, len)[comp_len] = '\0';
     826     1477131 :     princ_num_comp(p)++;
     827     1477131 :     return 0;
     828             : }
     829             : 
     830             : static krb5_error_code
     831       15462 : va_ext_princ(krb5_context context, krb5_principal p, va_list ap)
     832             : {
     833       15462 :     krb5_error_code ret = 0;
     834             : 
     835       28186 :     while (1){
     836         455 :         const char *s;
     837         455 :         int len;
     838             : 
     839       43481 :         if ((len = va_arg(ap, int)) == 0)
     840       15295 :             break;
     841       28019 :         s = va_arg(ap, const char*);
     842       28019 :         if ((ret = append_component(context, p, s, len)) != 0)
     843           0 :             break;
     844             :     }
     845       15462 :     return ret;
     846             : }
     847             : 
     848             : static krb5_error_code
     849      742106 : va_princ(krb5_context context, krb5_principal p, va_list ap)
     850             : {
     851      742106 :     krb5_error_code ret = 0;
     852             : 
     853     1466679 :     while (1){
     854       51949 :         const char *s;
     855             : 
     856     2191218 :         if ((s = va_arg(ap, const char*)) == NULL)
     857      724539 :             break;
     858     1449112 :         if ((ret = append_component(context, p, s, strlen(s))) != 0)
     859           0 :             break;
     860             :     }
     861      742106 :     return ret;
     862             : }
     863             : 
     864             : static krb5_error_code
     865      757568 : build_principal(krb5_context context,
     866             :                 krb5_principal *principal,
     867             :                 int rlen,
     868             :                 krb5_const_realm realm,
     869             :                 krb5_error_code (*func)(krb5_context, krb5_principal, va_list),
     870             :                 va_list ap)
     871             : {
     872       17734 :     krb5_error_code ret;
     873       17734 :     krb5_principal p;
     874             : 
     875      757568 :     *principal = NULL;
     876      757568 :     p = calloc(1, sizeof(*p));
     877      757568 :     if (p == NULL)
     878           0 :         return krb5_enomem(context);
     879             : 
     880      757568 :     princ_realm(p) = strdup(realm);
     881      757568 :     if (p->realm == NULL) {
     882           0 :         free(p);
     883           0 :         return krb5_enomem(context);
     884             :     }
     885             : 
     886      757568 :     ret = func(context, p, ap);
     887      757568 :     if (ret == 0) {
     888      757568 :         *principal = p;
     889      757568 :         set_default_princ_type(p, KRB5_NT_PRINCIPAL);
     890             :     } else
     891           0 :         krb5_free_principal(context, p);
     892      739834 :     return ret;
     893             : }
     894             : 
     895             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     896      742106 : krb5_build_principal_va(krb5_context context,
     897             :                         krb5_principal *principal,
     898             :                         int rlen,
     899             :                         krb5_const_realm realm,
     900             :                         va_list ap)
     901             : {
     902      742106 :     return build_principal(context, principal, rlen, realm, va_princ, ap);
     903             : }
     904             : 
     905             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     906       15462 : krb5_build_principal_va_ext(krb5_context context,
     907             :                             krb5_principal *principal,
     908             :                             int rlen,
     909             :                             krb5_const_realm realm,
     910             :                             va_list ap)
     911             : {
     912       15462 :     return build_principal(context, principal, rlen, realm, va_ext_princ, ap);
     913             : }
     914             : 
     915             : 
     916             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     917       15462 : krb5_build_principal_ext(krb5_context context,
     918             :                          krb5_principal *principal,
     919             :                          int rlen,
     920             :                          krb5_const_realm realm,
     921             :                          ...)
     922             : {
     923         167 :     krb5_error_code ret;
     924         167 :     va_list ap;
     925       15462 :     va_start(ap, realm);
     926       15462 :     ret = krb5_build_principal_va_ext(context, principal, rlen, realm, ap);
     927       15462 :     va_end(ap);
     928       15462 :     return ret;
     929             : }
     930             : 
     931             : /**
     932             :  * Copy a principal
     933             :  *
     934             :  * @param context A Kerberos context.
     935             :  * @param inprinc principal to copy
     936             :  * @param outprinc copied principal, free with krb5_free_principal()
     937             :  *
     938             :  * @return An krb5 error code, see krb5_get_error_message().
     939             :  *
     940             :  * @ingroup krb5_principal
     941             :  */
     942             : 
     943             : 
     944             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     945     6584817 : krb5_copy_principal(krb5_context context,
     946             :                     krb5_const_principal inprinc,
     947             :                     krb5_principal *outprinc)
     948             : {
     949      142481 :     krb5_principal p;
     950             : 
     951     6584817 :     *outprinc = NULL;
     952             : 
     953     6584817 :     p = malloc(sizeof(*p));
     954     6584817 :     if (p == NULL)
     955           0 :         return krb5_enomem(context);
     956     6584817 :     if(copy_Principal(inprinc, p)) {
     957           0 :         free(p);
     958           0 :         return krb5_enomem(context);
     959             :     }
     960     6584817 :     if (inprinc->nameattrs && inprinc->nameattrs->pac)
     961     1419048 :         p->nameattrs->pac = heim_retain(inprinc->nameattrs->pac);
     962             : 
     963     6584817 :     *outprinc = p;
     964     6584817 :     return 0;
     965             : }
     966             : 
     967             : /**
     968             :  * Return TRUE iff princ1 == princ2 (without considering the realm)
     969             :  *
     970             :  * @param context Kerberos 5 context
     971             :  * @param princ1 first principal to compare
     972             :  * @param princ2 second principal to compare
     973             :  *
     974             :  * @return non zero if equal, 0 if not
     975             :  *
     976             :  * @ingroup krb5_principal
     977             :  * @see krb5_principal_compare()
     978             :  * @see krb5_realm_compare()
     979             :  */
     980             : 
     981             : KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
     982     1407921 : krb5_principal_compare_any_realm(krb5_context context,
     983             :                                  krb5_const_principal princ1,
     984             :                                  krb5_const_principal princ2)
     985             : {
     986       36074 :     size_t i;
     987     1407921 :     if(princ_num_comp(princ1) != princ_num_comp(princ2))
     988      166993 :         return FALSE;
     989     2608179 :     for(i = 0; i < princ_num_comp(princ1); i++){
     990     1801001 :         if(strcmp(princ_ncomp(princ1, i), princ_ncomp(princ2, i)) != 0)
     991      419794 :             return FALSE;
     992             :     }
     993      785060 :     return TRUE;
     994             : }
     995             : 
     996             : KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
     997        1152 : _krb5_principal_compare_PrincipalName(krb5_context context,
     998             :                                       krb5_const_principal princ1,
     999             :                                       PrincipalName *princ2)
    1000             : {
    1001           0 :     size_t i;
    1002        1152 :     if (princ_num_comp(princ1) != princ2->name_string.len)
    1003           0 :         return FALSE;
    1004        4032 :     for(i = 0; i < princ_num_comp(princ1); i++){
    1005        2880 :         if(strcmp(princ_ncomp(princ1, i), princ2->name_string.val[i]) != 0)
    1006           0 :             return FALSE;
    1007             :     }
    1008        1152 :     return TRUE;
    1009             : }
    1010             : 
    1011             : 
    1012             : /**
    1013             :  * Compares the two principals, including realm of the principals and returns
    1014             :  * TRUE if they are the same and FALSE if not.
    1015             :  *
    1016             :  * @param context Kerberos 5 context
    1017             :  * @param princ1 first principal to compare
    1018             :  * @param princ2 second principal to compare
    1019             :  *
    1020             :  * @ingroup krb5_principal
    1021             :  * @see krb5_principal_compare_any_realm()
    1022             :  * @see krb5_realm_compare()
    1023             :  */
    1024             : 
    1025             : /*
    1026             :  * return TRUE iff princ1 == princ2
    1027             :  */
    1028             : 
    1029             : KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
    1030     1871740 : krb5_principal_compare(krb5_context context,
    1031             :                        krb5_const_principal princ1,
    1032             :                        krb5_const_principal princ2)
    1033             : {
    1034     1871740 :     if (!krb5_realm_compare(context, princ1, princ2))
    1035      511139 :         return FALSE;
    1036     1348515 :     return krb5_principal_compare_any_realm(context, princ1, princ2);
    1037             : }
    1038             : 
    1039             : /**
    1040             :  * return TRUE iff realm(princ1) == realm(princ2)
    1041             :  *
    1042             :  * @param context Kerberos 5 context
    1043             :  * @param princ1 first principal to compare
    1044             :  * @param princ2 second principal to compare
    1045             :  *
    1046             :  * @ingroup krb5_principal
    1047             :  * @see krb5_principal_compare_any_realm()
    1048             :  * @see krb5_principal_compare()
    1049             :  */
    1050             : 
    1051             : KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
    1052     1905186 : krb5_realm_compare(krb5_context context,
    1053             :                    krb5_const_principal princ1,
    1054             :                    krb5_const_principal princ2)
    1055             : {
    1056     1905186 :     return strcmp(princ_realm(princ1), princ_realm(princ2)) == 0;
    1057             : }
    1058             : 
    1059             : /**
    1060             :  * return TRUE iff princ matches pattern
    1061             :  *
    1062             :  * @ingroup krb5_principal
    1063             :  */
    1064             : 
    1065             : KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
    1066           0 : krb5_principal_match(krb5_context context,
    1067             :                      krb5_const_principal princ,
    1068             :                      krb5_const_principal pattern)
    1069             : {
    1070           0 :     size_t i;
    1071           0 :     if(princ_num_comp(princ) != princ_num_comp(pattern))
    1072           0 :         return FALSE;
    1073           0 :     if(fnmatch(princ_realm(pattern), princ_realm(princ), 0) != 0)
    1074           0 :         return FALSE;
    1075           0 :     for(i = 0; i < princ_num_comp(princ); i++){
    1076           0 :         if(fnmatch(princ_ncomp(pattern, i), princ_ncomp(princ, i), 0) != 0)
    1077           0 :             return FALSE;
    1078             :     }
    1079           0 :     return TRUE;
    1080             : }
    1081             : 
    1082             : /*
    1083             :  * This is the original krb5_sname_to_principal(), renamed to be a
    1084             :  * helper of the new one.
    1085             :  */
    1086             : static krb5_error_code
    1087           0 : krb5_sname_to_principal_old(krb5_context context,
    1088             :                             const char *realm,
    1089             :                             const char *hostname,
    1090             :                             const char *sname,
    1091             :                             int32_t type,
    1092             :                             krb5_principal *ret_princ)
    1093             : {
    1094           0 :     krb5_error_code ret;
    1095           0 :     char localhost[MAXHOSTNAMELEN];
    1096           0 :     char **realms = NULL, *host = NULL;
    1097             : 
    1098           0 :     if(type != KRB5_NT_SRV_HST && type != KRB5_NT_UNKNOWN) {
    1099           0 :         krb5_set_error_message(context, KRB5_SNAME_UNSUPP_NAMETYPE,
    1100           0 :                                N_("unsupported name type %d", ""),
    1101             :                                (int)type);
    1102           0 :         return KRB5_SNAME_UNSUPP_NAMETYPE;
    1103             :     }
    1104           0 :     if(hostname == NULL) {
    1105           0 :         ret = gethostname(localhost, sizeof(localhost) - 1);
    1106           0 :         if (ret != 0) {
    1107           0 :             ret = errno;
    1108           0 :             krb5_set_error_message(context, ret,
    1109           0 :                                    N_("Failed to get local hostname", ""));
    1110           0 :             return ret;
    1111             :         }
    1112           0 :         localhost[sizeof(localhost) - 1] = '\0';
    1113           0 :         hostname = localhost;
    1114             :     }
    1115           0 :     if(sname == NULL)
    1116           0 :         sname = "host";
    1117           0 :     if(type == KRB5_NT_SRV_HST) {
    1118           0 :         if (realm)
    1119           0 :             ret = krb5_expand_hostname(context, hostname, &host);
    1120             :         else
    1121           0 :             ret = krb5_expand_hostname_realms(context, hostname,
    1122             :                                               &host, &realms);
    1123           0 :         if (ret)
    1124           0 :             return ret;
    1125           0 :         strlwr(host);
    1126           0 :         hostname = host;
    1127           0 :         if (!realm)
    1128           0 :             realm = realms[0];
    1129           0 :     } else if (!realm) {
    1130           0 :         ret = krb5_get_host_realm(context, hostname, &realms);
    1131           0 :         if(ret)
    1132           0 :             return ret;
    1133           0 :         realm = realms[0];
    1134             :     }
    1135             : 
    1136           0 :     ret = krb5_make_principal(context, ret_princ, realm, sname,
    1137             :                               hostname, NULL);
    1138           0 :     if(host)
    1139           0 :         free(host);
    1140           0 :     if (realms)
    1141           0 :         krb5_free_host_realm(context, realms);
    1142           0 :     return ret;
    1143             : }
    1144             : 
    1145             : static const struct {
    1146             :     const char *type;
    1147             :     int32_t value;
    1148             : } nametypes[] = {
    1149             :     { "UNKNOWN", KRB5_NT_UNKNOWN },
    1150             :     { "PRINCIPAL", KRB5_NT_PRINCIPAL },
    1151             :     { "SRV_INST", KRB5_NT_SRV_INST },
    1152             :     { "SRV_HST", KRB5_NT_SRV_HST },
    1153             :     { "SRV_XHST", KRB5_NT_SRV_XHST },
    1154             :     { "UID", KRB5_NT_UID },
    1155             :     { "X500_PRINCIPAL", KRB5_NT_X500_PRINCIPAL },
    1156             :     { "SMTP_NAME", KRB5_NT_SMTP_NAME },
    1157             :     { "ENTERPRISE_PRINCIPAL", KRB5_NT_ENTERPRISE_PRINCIPAL },
    1158             :     { "WELLKNOWN", KRB5_NT_WELLKNOWN },
    1159             :     { "SRV_HST_DOMAIN", KRB5_NT_SRV_HST_DOMAIN },
    1160             :     { "ENT_PRINCIPAL_AND_ID", KRB5_NT_ENT_PRINCIPAL_AND_ID },
    1161             :     { "MS_PRINCIPAL", KRB5_NT_MS_PRINCIPAL },
    1162             :     { "MS_PRINCIPAL_AND_ID", KRB5_NT_MS_PRINCIPAL_AND_ID },
    1163             :     { "SRV_HST_NEEDS_CANON", KRB5_NT_SRV_HST_NEEDS_CANON },
    1164             :     { NULL, 0 }
    1165             : };
    1166             : 
    1167             : /**
    1168             :  * Parse nametype string and return a nametype integer
    1169             :  *
    1170             :  * @ingroup krb5_principal
    1171             :  */
    1172             : 
    1173             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1174           0 : krb5_parse_nametype(krb5_context context, const char *str, int32_t *nametype)
    1175             : {
    1176           0 :     size_t i;
    1177             : 
    1178           0 :     for(i = 0; nametypes[i].type; i++) {
    1179           0 :         if (strcasecmp(nametypes[i].type, str) == 0) {
    1180           0 :             *nametype = nametypes[i].value;
    1181           0 :             return 0;
    1182             :         }
    1183             :     }
    1184           0 :     krb5_set_error_message(context, KRB5_PARSE_MALFORMED,
    1185           0 :                            N_("Failed to find name type %s", ""), str);
    1186           0 :     return KRB5_PARSE_MALFORMED;
    1187             : }
    1188             : 
    1189             : /**
    1190             :  * Returns true if name is Kerberos NULL name
    1191             :  *
    1192             :  * @ingroup krb5_principal
    1193             :  */
    1194             : 
    1195             : krb5_boolean KRB5_LIB_FUNCTION
    1196           0 : krb5_principal_is_null(krb5_context context, krb5_const_principal principal)
    1197             : {
    1198           0 :     if (principal->name.name_type == KRB5_NT_WELLKNOWN &&
    1199           0 :         principal->name.name_string.len == 2 &&
    1200           0 :         strcmp(principal->name.name_string.val[0], "WELLKNOWN") == 0 &&
    1201           0 :         strcmp(principal->name.name_string.val[1], "NULL") == 0)
    1202           0 :         return TRUE;
    1203           0 :     return FALSE;
    1204             : }
    1205             : 
    1206             : const char _krb5_wellknown_lkdc[] = "WELLKNOWN:COM.APPLE.LKDC";
    1207             : static const char lkdc_prefix[] = "LKDC:";
    1208             : 
    1209             : /**
    1210             :  * Returns true if name is Kerberos an LKDC realm
    1211             :  *
    1212             :  * @ingroup krb5_principal
    1213             :  */
    1214             : 
    1215             : krb5_boolean KRB5_LIB_FUNCTION
    1216         313 : krb5_realm_is_lkdc(const char *realm)
    1217             : {
    1218             : 
    1219         626 :     return strncmp(realm, lkdc_prefix, sizeof(lkdc_prefix)-1) == 0 ||
    1220         313 :         strncmp(realm, _krb5_wellknown_lkdc, sizeof(_krb5_wellknown_lkdc) - 1) == 0;
    1221             : }
    1222             : 
    1223             : /**
    1224             :  * Returns true if name is Kerberos an LKDC realm
    1225             :  *
    1226             :  * @ingroup krb5_principal
    1227             :  */
    1228             : 
    1229             : krb5_boolean KRB5_LIB_FUNCTION
    1230         124 : krb5_principal_is_lkdc(krb5_context context, krb5_const_principal principal)
    1231             : {
    1232         124 :     return krb5_realm_is_lkdc(principal->realm);
    1233             : }
    1234             : 
    1235             : /**
    1236             :  * Returns true if name is Kerberos an LKDC realm
    1237             :  *
    1238             :  * @ingroup krb5_principal
    1239             :  */
    1240             : 
    1241             : krb5_boolean KRB5_LIB_FUNCTION
    1242           0 : krb5_principal_is_pku2u(krb5_context context, krb5_const_principal principal)
    1243             : {
    1244           0 :     return strcmp(principal->realm, KRB5_PKU2U_REALM_NAME) == 0;
    1245             : }
    1246             : 
    1247             : /**
    1248             :  * Check if the cname part of the principal name is a krbtgt principal
    1249             :  *
    1250             :  * @ingroup krb5_principal
    1251             :  */
    1252             : 
    1253             : KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
    1254      652692 : krb5_principalname_is_krbtgt(krb5_context context, const PrincipalName *p)
    1255             : {
    1256     1284515 :     return 1 <= p->name_string.len &&
    1257     1283143 :         p->name_string.len <= 2 &&
    1258      651320 :         strcmp(p->name_string.val[0], KRB5_TGS_NAME) == 0;
    1259             : }
    1260             : 
    1261             : /**
    1262             :  * Check if the cname part of the principal is a krbtgt principal
    1263             :  *
    1264             :  * @ingroup krb5_principal
    1265             :  */
    1266             : 
    1267             : KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
    1268      600124 : krb5_principal_is_krbtgt(krb5_context context, krb5_const_principal p)
    1269             : {
    1270      600124 :     return krb5_principalname_is_krbtgt(context, &p->name);
    1271             : }
    1272             : 
    1273             : /**
    1274             :  * Returns true iff name is an WELLKNOWN:ORG.H5L.HOSTBASED-SERVICE
    1275             :  *
    1276             :  * @ingroup krb5_principal
    1277             :  */
    1278             : 
    1279             : krb5_boolean KRB5_LIB_FUNCTION
    1280           0 : krb5_principal_is_gss_hostbased_service(krb5_context context,
    1281             :                                         krb5_const_principal principal)
    1282             : {
    1283           0 :     if (principal == NULL)
    1284           0 :         return FALSE;
    1285           0 :     if (principal->name.name_string.len != 2)
    1286           0 :         return FALSE;
    1287           0 :     if (strcmp(principal->name.name_string.val[1], KRB5_GSS_HOSTBASED_SERVICE_NAME) != 0)
    1288           0 :         return FALSE;
    1289           0 :     return TRUE;
    1290             : }
    1291             : 
    1292             : /**
    1293             :  * Check if the cname part of the principal is a initial or renewed krbtgt principal
    1294             :  *
    1295             :  * @ingroup krb5_principal
    1296             :  */
    1297             : 
    1298             : krb5_boolean KRB5_LIB_FUNCTION
    1299      469379 : krb5_principal_is_root_krbtgt(krb5_context context, krb5_const_principal p)
    1300             : {
    1301      938692 :     return p->name.name_string.len == 2 &&
    1302      690675 :         strcmp(p->name.name_string.val[0], KRB5_TGS_NAME) == 0 &&
    1303      225109 :         strcmp(p->name.name_string.val[1], p->realm) == 0;
    1304             : }
    1305             : 
    1306             : /**
    1307             :  * Returns true iff name is WELLKNOWN/ANONYMOUS
    1308             :  *
    1309             :  * @ingroup krb5_principal
    1310             :  */
    1311             : 
    1312             : KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
    1313      127517 : krb5_principal_is_anonymous(krb5_context context,
    1314             :                              krb5_const_principal p,
    1315             :                              unsigned int flags)
    1316             : {
    1317             :     /*
    1318             :      * Heimdal versions 7.5 and below left the name-type at KRB5_NT_PRINCIPAL
    1319             :      * even with anonymous pkinit responses.  To retain interoperability with
    1320             :      * legacy KDCs, the name-type is not checked by the client after requesting
    1321             :      * a fully anonymous ticket.
    1322             :      */
    1323      127517 :     if (!(flags & KRB5_ANON_IGNORE_NAME_TYPE) &&
    1324      127517 :         p->name.name_type != KRB5_NT_WELLKNOWN &&
    1325      122830 :         p->name.name_type != KRB5_NT_UNKNOWN)
    1326      122830 :         return FALSE;
    1327             : 
    1328         104 :     if (p->name.name_string.len != 2 ||
    1329         104 :         strcmp(p->name.name_string.val[0], KRB5_WELLKNOWN_NAME) != 0 ||
    1330         104 :         strcmp(p->name.name_string.val[1], KRB5_ANON_NAME) != 0)
    1331           0 :         return FALSE;
    1332             : 
    1333             :     /*
    1334             :      * While unauthenticated clients SHOULD get "WELLKNOWN:ANONYMOUS" as their
    1335             :      * realm, Heimdal KDCs prior to 7.0 returned the requested realm.  While
    1336             :      * such tickets might lead *servers* to unwittingly grant access to fully
    1337             :      * anonymous clients, trusting that the client was authenticated to the
    1338             :      * realm in question, doing it right is the KDC's job, the client should
    1339             :      * not refuse such a ticket.
    1340             :      *
    1341             :      * If we ever do decide to enforce WELLKNOWN:ANONYMOUS for unauthenticated
    1342             :      * clients, it is essential that calls that pass KRB5_ANON_MATCH_ANY still
    1343             :      * ignore the realm, as in that case either case matches one of the two
    1344             :      * possible conditions.
    1345             :      */
    1346         104 :     if (flags & KRB5_ANON_MATCH_UNAUTHENTICATED)
    1347         104 :         return TRUE;
    1348             : 
    1349             :     /*
    1350             :      * Finally, authenticated clients that asked to be only anonymized do
    1351             :      * legitimately expect a non-anon realm.
    1352             :      */
    1353           0 :     return strcmp(p->realm, KRB5_ANON_REALM) != 0;
    1354             : }
    1355             : 
    1356             : /**
    1357             :  * Returns true iff name is WELLKNOWN/FEDERATED
    1358             :  *
    1359             :  * @ingroup krb5_principal
    1360             :  */
    1361             : 
    1362             : KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
    1363           0 : krb5_principal_is_federated(krb5_context context,
    1364             :                              krb5_const_principal p)
    1365             : {
    1366           0 :     if (p->name.name_type != KRB5_NT_WELLKNOWN &&
    1367           0 :         p->name.name_type != KRB5_NT_UNKNOWN)
    1368           0 :         return FALSE;
    1369             : 
    1370           0 :     if (p->name.name_string.len != 2 ||
    1371           0 :         strcmp(p->name.name_string.val[0], KRB5_WELLKNOWN_NAME) != 0 ||
    1372           0 :         strcmp(p->name.name_string.val[1], KRB5_FEDERATED_NAME) != 0)
    1373           0 :         return FALSE;
    1374             : 
    1375           0 :     return TRUE;
    1376             : }
    1377             : 
    1378             : static int
    1379           0 : tolower_ascii(int c)
    1380             : {
    1381           0 :     if (c >= 'A' && c <= 'Z')
    1382           0 :         return 'a' + (c - 'A');
    1383           0 :     return c;
    1384             : }
    1385             : 
    1386             : typedef enum krb5_name_canon_rule_type {
    1387             :         KRB5_NCRT_BOGUS = 0,
    1388             :         KRB5_NCRT_AS_IS,
    1389             :         KRB5_NCRT_QUALIFY,
    1390             :         KRB5_NCRT_NSS
    1391             : } krb5_name_canon_rule_type;
    1392             : 
    1393             : #ifdef UINT8_MAX
    1394             : #define MAXDOTS UINT8_MAX
    1395             : #else
    1396             : #define MAXDOTS (255U)
    1397             : #endif
    1398             : #ifdef UINT16_MAX
    1399             : #define MAXORDER UINT16_MAX
    1400             : #else
    1401             : #define MAXORDER (65535U)
    1402             : #endif
    1403             : 
    1404             : struct krb5_name_canon_rule_data {
    1405             :         krb5_name_canon_rule_type type;
    1406             :         krb5_name_canon_rule_options options;
    1407             :         uint8_t mindots;          /* match this many dots or more */
    1408             :         uint8_t maxdots;          /* match no more than this many dots */
    1409             :         uint16_t explicit_order;    /* given order */
    1410             :         uint16_t order;             /* actual order */
    1411             :         char *match_domain;         /* match this stem */
    1412             :         char *match_realm;          /* match this realm */
    1413             :         char *domain;               /* qualify with this domain */
    1414             :         char *realm;                /* qualify with this realm */
    1415             : };
    1416             : 
    1417             : /**
    1418             :  * Create a principal for the given service running on the given
    1419             :  * hostname. If KRB5_NT_SRV_HST is used, the hostname is canonicalized
    1420             :  * according the configured name canonicalization rules, with
    1421             :  * canonicalization delayed in some cases.  One rule involves DNS, which
    1422             :  * is insecure unless DNSSEC is used, but we don't use DNSSEC-capable
    1423             :  * resolver APIs here, so that if DNSSEC is used we wouldn't know it.
    1424             :  *
    1425             :  * Canonicalization is immediate (not delayed) only when there is only
    1426             :  * one canonicalization rule and that rule indicates that we should do a
    1427             :  * host lookup by name (i.e., DNS).
    1428             :  *
    1429             :  * @param context A Kerberos context.
    1430             :  * @param hostname hostname to use
    1431             :  * @param sname Service name to use
    1432             :  * @param type name type of principal, use KRB5_NT_SRV_HST or KRB5_NT_UNKNOWN.
    1433             :  * @param ret_princ return principal, free with krb5_free_principal().
    1434             :  *
    1435             :  * @return An krb5 error code, see krb5_get_error_message().
    1436             :  *
    1437             :  * @ingroup krb5_principal
    1438             :  */
    1439             : 
    1440             : /* coverity[+alloc : arg-*4] */
    1441             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1442        1748 : krb5_sname_to_principal(krb5_context context,
    1443             :                         const char *hostname,
    1444             :                         const char *sname,
    1445             :                         int32_t type,
    1446             :                         krb5_principal *ret_princ)
    1447             : {
    1448          28 :     char *realm, *remote_host;
    1449          28 :     krb5_error_code ret;
    1450          28 :     register char *cp;
    1451          28 :     char localname[MAXHOSTNAMELEN];
    1452             : 
    1453        1748 :     *ret_princ = NULL;
    1454             : 
    1455        1748 :     if ((type != KRB5_NT_UNKNOWN) &&
    1456          28 :         (type != KRB5_NT_SRV_HST))
    1457           0 :         return KRB5_SNAME_UNSUPP_NAMETYPE;
    1458             : 
    1459             :     /* if hostname is NULL, use local hostname */
    1460        1748 :     if (hostname == NULL) {
    1461           0 :         if (gethostname(localname, MAXHOSTNAMELEN))
    1462           0 :             return errno;
    1463           0 :         hostname = localname;
    1464             :     }
    1465             : 
    1466             :     /* if sname is NULL, use "host" */
    1467        1748 :     if (sname == NULL)
    1468           0 :         sname = "host";
    1469             : 
    1470        1748 :     remote_host = strdup(hostname);
    1471        1748 :     if (remote_host == NULL)
    1472           0 :         return krb5_enomem(context);
    1473             : 
    1474        1748 :     if (type == KRB5_NT_SRV_HST) {
    1475             :         krb5_name_canon_rule rules;
    1476             : 
    1477             :         /* Lower-case the hostname, because that's the convention */
    1478       16353 :         for (cp = remote_host; *cp; cp++)
    1479       14605 :             if (isupper((unsigned char) (*cp)))
    1480       12831 :                 *cp = tolower((unsigned char) (*cp));
    1481             : 
    1482             :         /*
    1483             :          * If there is only one name canon rule and it says to
    1484             :          * canonicalize the old way, do that now, as we used to.
    1485             :          */
    1486        1748 :         ret = _krb5_get_name_canon_rules(context, &rules);
    1487        1748 :         if (ret) {
    1488           0 :             _krb5_debug(context, 5, "Failed to get name canon rules: ret = %d",
    1489             :                         ret);
    1490           0 :             free(remote_host);
    1491           0 :             return ret;
    1492             :         }
    1493        1748 :         if (rules[0].type == KRB5_NCRT_NSS &&
    1494           0 :             rules[1].type == KRB5_NCRT_BOGUS) {
    1495           0 :             _krb5_debug(context, 5, "Using nss for name canon immediately");
    1496           0 :             ret = krb5_sname_to_principal_old(context, rules[0].realm,
    1497             :                                               remote_host, sname,
    1498             :                                               KRB5_NT_SRV_HST, ret_princ);
    1499           0 :             free(remote_host);
    1500           0 :             return ret;
    1501             :         }
    1502             :     }
    1503             : 
    1504             :     /* Remove trailing dots */
    1505        1748 :     if (remote_host[0]) {
    1506        1748 :         for (cp = remote_host + strlen(remote_host)-1;
    1507        1748 :              *cp == '.' && cp > remote_host;
    1508           0 :              cp--) {
    1509           0 :             *cp = '\0';
    1510             :         }
    1511             :     }
    1512             : 
    1513        1748 :     realm = ""; /* "Referral realm" */
    1514             : 
    1515        1748 :     ret = krb5_build_principal(context, ret_princ, strlen(realm),
    1516             :                                   realm, sname, remote_host,
    1517             :                                   (char *)0);
    1518             : 
    1519        1748 :     if (ret == 0 && type == KRB5_NT_SRV_HST) {
    1520             :         /*
    1521             :          * Hostname canonicalization is done elsewhere (in
    1522             :          * krb5_get_credentials() and krb5_kt_get_entry()).
    1523             :          *
    1524             :          * We overload the name type to indicate to those functions that
    1525             :          * this principal name requires canonicalization.
    1526             :          *
    1527             :          * We can't use the empty realm to denote the need to
    1528             :          * canonicalize the hostname too: it would mean that users who
    1529             :          * want to assert knowledge of a service's realm must also know
    1530             :          * the canonical hostname, but in practice they don't.
    1531             :          */
    1532        1748 :         (*ret_princ)->name.name_type = KRB5_NT_SRV_HST_NEEDS_CANON;
    1533             : 
    1534        1748 :         _krb5_debug(context, 5, "Building a delayed canon principal for %s/%s@",
    1535             :                 sname, remote_host);
    1536             :     }
    1537             : 
    1538        1748 :     free(remote_host);
    1539        1748 :     return ret;
    1540             : }
    1541             : 
    1542             : static void
    1543           0 : tolower_str(char *s)
    1544             : {
    1545           0 :     for (; *s != '\0'; s++) {
    1546           0 :         if (isupper((unsigned char)*s))
    1547           0 :             *s = tolower_ascii(*s);
    1548             :     }
    1549           0 : }
    1550             : 
    1551             : static krb5_error_code
    1552           0 : rule_parse_token(krb5_context context, krb5_name_canon_rule rule,
    1553             :                  const char *tok)
    1554             : {
    1555           0 :     long int n;
    1556           0 :     int needs_type = rule->type == KRB5_NCRT_BOGUS;
    1557             : 
    1558             :     /*
    1559             :      * Rules consist of a sequence of tokens, some of which indicate
    1560             :      * what type of rule the rule is, and some of which set rule options
    1561             :      * or ancilliary data.  Last rule type token wins.
    1562             :      */
    1563             : 
    1564             :     /* Rule type tokens: */
    1565           0 :     if (needs_type && strcmp(tok, "as-is") == 0) {
    1566           0 :         rule->type = KRB5_NCRT_AS_IS;
    1567           0 :     } else if (needs_type && strcmp(tok, "qualify") == 0) {
    1568           0 :         rule->type = KRB5_NCRT_QUALIFY;
    1569           0 :     } else if (needs_type && strcmp(tok, "nss") == 0) {
    1570           0 :         rule->type = KRB5_NCRT_NSS;
    1571             :     /* Rule options: */
    1572           0 :     } else if (strcmp(tok, "use_fast") == 0) {
    1573           0 :         rule->options |= KRB5_NCRO_USE_FAST;
    1574           0 :     } else if (strcmp(tok, "use_dnssec") == 0) {
    1575           0 :         rule->options |= KRB5_NCRO_USE_DNSSEC;
    1576           0 :     } else if (strcmp(tok, "ccache_only") == 0) {
    1577           0 :         rule->options |= KRB5_NCRO_GC_ONLY;
    1578           0 :     } else if (strcmp(tok, "no_referrals") == 0) {
    1579           0 :         rule->options |= KRB5_NCRO_NO_REFERRALS;
    1580           0 :     } else if (strcmp(tok, "use_referrals") == 0) {
    1581           0 :         rule->options &= ~KRB5_NCRO_NO_REFERRALS;
    1582           0 :         if (rule->realm == NULL) {
    1583           0 :             rule->realm = strdup("");
    1584           0 :             if (rule->realm == NULL)
    1585           0 :                 return krb5_enomem(context);
    1586             :         }
    1587           0 :     } else if (strcmp(tok, "lookup_realm") == 0) {
    1588           0 :         rule->options |= KRB5_NCRO_LOOKUP_REALM;
    1589           0 :         free(rule->realm);
    1590           0 :         rule->realm = NULL;
    1591             :     /* Rule ancilliary data: */
    1592           0 :     } else if (strncmp(tok, "domain=", strlen("domain=")) == 0) {
    1593           0 :         free(rule->domain);
    1594           0 :         rule->domain = strdup(tok + strlen("domain="));
    1595           0 :         if (rule->domain == NULL)
    1596           0 :             return krb5_enomem(context);
    1597           0 :         tolower_str(rule->domain);
    1598           0 :     } else if (strncmp(tok, "realm=", strlen("realm=")) == 0) {
    1599           0 :         free(rule->realm);
    1600           0 :         rule->realm = strdup(tok + strlen("realm="));
    1601           0 :         if (rule->realm == NULL)
    1602           0 :             return krb5_enomem(context);
    1603           0 :     } else if (strncmp(tok, "match_domain=", strlen("match_domain=")) == 0) {
    1604           0 :         free(rule->match_domain);
    1605           0 :         rule->match_domain = strdup(tok + strlen("match_domain="));
    1606           0 :         if (rule->match_domain == NULL)
    1607           0 :             return krb5_enomem(context);
    1608           0 :         tolower_str(rule->match_domain);
    1609           0 :     } else if (strncmp(tok, "match_realm=", strlen("match_realm=")) == 0) {
    1610           0 :         free(rule->match_realm);
    1611           0 :         rule->match_realm = strdup(tok + strlen("match_realm="));
    1612           0 :         if (rule->match_realm == NULL)
    1613           0 :             return krb5_enomem(context);
    1614           0 :     } else if (strncmp(tok, "mindots=", strlen("mindots=")) == 0) {
    1615           0 :         errno = 0;
    1616           0 :         n = strtol(tok + strlen("mindots="), NULL, 10);
    1617           0 :         if (errno == 0 && n > 0 && n <= MAXDOTS)
    1618           0 :             rule->mindots = n;
    1619           0 :     } else if (strncmp(tok, "maxdots=", strlen("maxdots=")) == 0) {
    1620           0 :         errno = 0;
    1621           0 :         n = strtol(tok + strlen("maxdots="), NULL, 10);
    1622           0 :         if (errno == 0 && n > 0 && n <= MAXDOTS)
    1623           0 :             rule->maxdots = n;
    1624           0 :     } else if (strncmp(tok, "order=", strlen("order=")) == 0) {
    1625           0 :         errno = 0;
    1626           0 :         n = strtol(tok + strlen("order="), NULL, 10);
    1627           0 :         if (errno == 0 && n > 0 && n <= MAXORDER)
    1628           0 :             rule->explicit_order = n;
    1629             :     } else {
    1630           0 :         _krb5_debug(context, 5,
    1631             :                     "Unrecognized name canonicalization rule token %s", tok);
    1632           0 :         return EINVAL;
    1633             :     }
    1634           0 :     return 0;
    1635             : }
    1636             : 
    1637             : static int
    1638           0 : rule_cmp(const void *a, const void *b)
    1639             : {
    1640           0 :     krb5_const_name_canon_rule left = a;
    1641           0 :     krb5_const_name_canon_rule right = b;
    1642             : 
    1643           0 :     if (left->type == KRB5_NCRT_BOGUS &&
    1644           0 :         right->type == KRB5_NCRT_BOGUS)
    1645           0 :         return 0;
    1646           0 :     if (left->type == KRB5_NCRT_BOGUS)
    1647           0 :         return 1;
    1648           0 :     if (right->type == KRB5_NCRT_BOGUS)
    1649           0 :         return -1;
    1650           0 :     if (left->explicit_order < right->explicit_order)
    1651           0 :         return -1;
    1652           0 :     if (left->explicit_order > right->explicit_order)
    1653           0 :         return 1;
    1654           0 :     return left->order - right->order;
    1655             : }
    1656             : 
    1657             : static krb5_error_code
    1658         281 : parse_name_canon_rules(krb5_context context, char **rulestrs,
    1659             :                        krb5_name_canon_rule *rules)
    1660             : {
    1661           5 :     krb5_error_code ret;
    1662           5 :     char *tok;
    1663           5 :     char *cp;
    1664           5 :     char **cpp;
    1665           5 :     size_t n;
    1666           5 :     size_t i, k;
    1667         281 :     int do_sort = 0;
    1668           5 :     krb5_name_canon_rule r;
    1669             : 
    1670         281 :     *rules = NULL;
    1671             : 
    1672         281 :     for (n =0, cpp = rulestrs; cpp != NULL && *cpp != NULL; cpp++)
    1673           0 :         n++;
    1674             : 
    1675         281 :     n += 2; /* Always at least one rule; two for the default case */
    1676             : 
    1677         281 :     if ((r = calloc(n, sizeof (*r))) == NULL)
    1678           0 :         return krb5_enomem(context);
    1679             : 
    1680         843 :     for (k = 0; k < n; k++) {
    1681         562 :         r[k].type = KRB5_NCRT_BOGUS;
    1682         562 :         r[k].match_domain = NULL;
    1683         562 :         r[k].match_realm = NULL;
    1684         562 :         r[k].domain = NULL;
    1685         562 :         r[k].realm = NULL;
    1686             :     }
    1687             : 
    1688         281 :     for (i = 0, k = 0; i < n && rulestrs != NULL && rulestrs[i] != NULL; i++) {
    1689           0 :         cp = rulestrs[i];
    1690           0 :         r[k].explicit_order = MAXORDER; /* mark order, see below */
    1691           0 :         r[k].maxdots = MAXDOTS;
    1692           0 :         r[k].order = k;         /* default order */
    1693             : 
    1694             :         /* Tokenize and parse value */
    1695           0 :         do {
    1696           0 :             tok = cp;
    1697           0 :             cp = strchr(cp, ':');   /* XXX use strtok_r() */
    1698           0 :             if (cp)
    1699           0 :                 *cp++ = '\0';       /* delimit token */
    1700           0 :             ret = rule_parse_token(context, &r[k], tok);
    1701           0 :             if (ret == EINVAL) {
    1702           0 :                 r[k].type = KRB5_NCRT_BOGUS;
    1703           0 :                 break;
    1704             :             }
    1705           0 :             if (ret) {
    1706           0 :                 _krb5_free_name_canon_rules(context, r);
    1707           0 :                 return ret;
    1708             :             }
    1709           0 :         } while (cp && *cp);
    1710           0 :         if (r[k].explicit_order != MAXORDER)
    1711           0 :             do_sort = 1;
    1712             : 
    1713             :         /* Validate parsed rule */
    1714           0 :         if (r[k].type == KRB5_NCRT_BOGUS ||
    1715           0 :             (r[k].type == KRB5_NCRT_QUALIFY && !r[k].domain) ||
    1716           0 :             (r[k].type == KRB5_NCRT_NSS && r[k].domain)) {
    1717             :             /* Invalid rule; mark it so and clean up */
    1718           0 :             r[k].type = KRB5_NCRT_BOGUS;
    1719           0 :             free(r[k].match_domain);
    1720           0 :             free(r[k].match_realm);
    1721           0 :             free(r[k].domain);
    1722           0 :             free(r[k].realm);
    1723           0 :             r[k].realm = NULL;
    1724           0 :             r[k].domain = NULL;
    1725           0 :             r[k].match_domain = NULL;
    1726           0 :             r[k].match_realm = NULL;
    1727           0 :             _krb5_debug(context, 5,
    1728             :                         "Ignoring invalid name canonicalization rule %lu",
    1729             :                         (unsigned long)i);
    1730           0 :             continue;
    1731             :         }
    1732           0 :         k++; /* good rule */
    1733             :     }
    1734             : 
    1735         281 :     if (do_sort) {
    1736             :         /*
    1737             :          * Note that we make make this a stable sort by using appareance
    1738             :          * and explicit order.
    1739             :          */
    1740           0 :         qsort(r, n, sizeof(r[0]), rule_cmp);
    1741             :     }
    1742             : 
    1743         281 :     if (r[0].type == KRB5_NCRT_BOGUS) {
    1744             :         /* No rules, or no valid rules */
    1745         281 :         if (context->flags & KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME) {
    1746           0 :             r[0].type = KRB5_NCRT_NSS;
    1747             :         } else {
    1748         281 :             r[0].type = KRB5_NCRT_AS_IS;
    1749             :         }
    1750             :     }
    1751             : 
    1752         281 :     *rules = r;
    1753         281 :     return 0; /* We don't communicate bad rule errors here */
    1754             : }
    1755             : 
    1756             : /*
    1757             :  * This exists only because the hostname canonicalization behavior in Heimdal
    1758             :  * (and other implementations of Kerberos) has been to use getaddrinfo(),
    1759             :  * unsafe though it is, for ages.  We can't fix it in one day.
    1760             :  */
    1761             : static void
    1762           0 : make_rules_safe(krb5_context context, krb5_name_canon_rule rules)
    1763             : {
    1764             :     /*
    1765             :      * If the only rule were to use the name service (getaddrinfo()) then we're
    1766             :      * bound to fail.  We could try to convert that rule to an as-is rule, but
    1767             :      * when we do get a validating resolver we'd be unhappy that we did such a
    1768             :      * conversion.  Better let the user get failures and make them think about
    1769             :      * their naming rules.
    1770             :      */
    1771           0 :     if (rules == NULL)
    1772           0 :         return;
    1773           0 :     for (; rules[0].type != KRB5_NCRT_BOGUS; rules++) {
    1774           0 :         if (rules->type == KRB5_NCRT_NSS)
    1775           0 :             rules->options |= KRB5_NCRO_USE_DNSSEC;
    1776             :         else
    1777           0 :             rules->options |= KRB5_NCRO_USE_FAST;
    1778             :     }
    1779             : }
    1780             : 
    1781             : /**
    1782             :  * This function returns an array of host-based service name
    1783             :  * canonicalization rules.  The array of rules is organized as a list.
    1784             :  * See the definition of krb5_name_canon_rule.
    1785             :  *
    1786             :  * @param context A Kerberos context.
    1787             :  * @param rules   Output location for array of rules.
    1788             :  */
    1789             : KRB5_LIB_FUNCTION krb5_error_code
    1790        3496 : _krb5_get_name_canon_rules(krb5_context context, krb5_name_canon_rule *rules)
    1791             : {
    1792          56 :     krb5_error_code ret;
    1793        3496 :     char **values = NULL;
    1794             : 
    1795        3496 :     *rules = context->name_canon_rules;
    1796        3496 :     if (*rules != NULL)
    1797        3164 :         return 0;
    1798             : 
    1799         281 :     values = krb5_config_get_strings(context, NULL,
    1800             :                                      "libdefaults", "name_canon_rules", NULL);
    1801         281 :     ret = parse_name_canon_rules(context, values, rules);
    1802         281 :     krb5_config_free_strings(values);
    1803         281 :     if (ret)
    1804           0 :         return ret;
    1805         281 :     if (*rules == NULL)
    1806           0 :         return krb5_enomem(context);
    1807             : 
    1808         281 :     if (krb5_config_get_bool_default(context, NULL, FALSE,
    1809             :                                      "libdefaults", "safe_name_canon", NULL))
    1810           0 :         make_rules_safe(context, *rules);
    1811             : 
    1812         281 :     heim_assert((*rules)[0].type != KRB5_NCRT_BOGUS,
    1813             :                 "internal error in parsing principal name "
    1814             :                 "canonicalization rules");
    1815             : 
    1816             :     /* Memoize */
    1817         281 :     context->name_canon_rules = *rules;
    1818             : 
    1819         281 :     return 0;
    1820             : }
    1821             : 
    1822             : static krb5_error_code
    1823           0 : get_host_realm(krb5_context context, const char *hostname, char **realm)
    1824             : {
    1825           0 :     krb5_error_code ret;
    1826           0 :     char **hrealms = NULL;
    1827             : 
    1828           0 :     *realm = NULL;
    1829           0 :     ret = krb5_get_host_realm(context, hostname, &hrealms);
    1830           0 :     if (ret)
    1831           0 :         return ret;
    1832           0 :     if (hrealms == NULL)
    1833           0 :         return KRB5_ERR_HOST_REALM_UNKNOWN; /* krb5_set_error() already done */
    1834           0 :     if (hrealms[0] == NULL) {
    1835           0 :         krb5_free_host_realm(context, hrealms);
    1836           0 :         return KRB5_ERR_HOST_REALM_UNKNOWN; /* krb5_set_error() already done */
    1837             :     }
    1838           0 :     *realm = strdup(hrealms[0]);
    1839           0 :     krb5_free_host_realm(context, hrealms);
    1840           0 :     if (*realm == NULL)
    1841           0 :         return krb5_enomem(context);
    1842           0 :     return 0;
    1843             : }
    1844             : 
    1845             : static int
    1846           0 : is_domain_suffix(const char *domain, const char *suffix)
    1847             : {
    1848           0 :     size_t dlen = strlen(domain);
    1849           0 :     size_t slen = strlen(suffix);
    1850             : 
    1851           0 :     if (dlen < slen + 2)
    1852           0 :         return 0;
    1853             : 
    1854           0 :     if (strcasecmp(domain + (dlen - slen), suffix) != 0)
    1855           0 :         return 0;
    1856             : 
    1857           0 :     if (domain[(dlen - slen) - 1] != '.')
    1858           0 :         return 0;
    1859           0 :     return 1;
    1860             : }
    1861             : 
    1862             : /*
    1863             :  * Applies a name canonicalization rule to a principal.
    1864             :  *
    1865             :  * Returns zero and no out_princ if the rule does not match.
    1866             :  * Returns zero and an out_princ if the rule does match.
    1867             :  */
    1868             : static krb5_error_code
    1869        1748 : apply_name_canon_rule(krb5_context context, krb5_name_canon_rule rules,
    1870             :                       size_t rule_idx, krb5_const_principal in_princ,
    1871             :                       krb5_principal *out_princ,
    1872             :                       krb5_name_canon_rule_options *rule_opts)
    1873             : {
    1874        1748 :     krb5_name_canon_rule rule = &rules[rule_idx];
    1875        1748 :     krb5_error_code ret = 0;
    1876        1748 :     unsigned int ndots = 0;
    1877        1748 :     krb5_principal nss = NULL;
    1878        1748 :     const char *sname = NULL;
    1879        1748 :     const char *orig_hostname = NULL;
    1880        1748 :     const char *new_hostname = NULL;
    1881        1748 :     const char *new_realm = NULL;
    1882        1748 :     const char *port = "";
    1883          28 :     const char *cp;
    1884        1748 :     char *hostname_sans_port = NULL;
    1885        1748 :     char *hostname_with_port = NULL;
    1886        1748 :     char *tmp_hostname = NULL;
    1887        1748 :     char *tmp_realm = NULL;
    1888             : 
    1889        1748 :     *out_princ = NULL; /* Signal no match */
    1890             : 
    1891        1748 :     if (rule_opts != NULL)
    1892        1748 :         *rule_opts = rule->options;
    1893             : 
    1894        1748 :     if (rule->type == KRB5_NCRT_BOGUS)
    1895           0 :         return 0; /* rule doesn't apply */
    1896             : 
    1897        1748 :     sname = krb5_principal_get_comp_string(context, in_princ, 0);
    1898        1748 :     orig_hostname = krb5_principal_get_comp_string(context, in_princ, 1);
    1899             : 
    1900             :     /*
    1901             :      * Some apps want to use the very non-standard svc/hostname:port@REALM
    1902             :      * form.  We do our best to support that here :(
    1903             :      */
    1904        1748 :     port = strchr(orig_hostname, ':');
    1905        1748 :     if (port != NULL) {
    1906           0 :         hostname_sans_port = strndup(orig_hostname, port - orig_hostname);
    1907           0 :         if (hostname_sans_port == NULL)
    1908           0 :             return krb5_enomem(context);
    1909           0 :         orig_hostname = hostname_sans_port;
    1910             :     }
    1911             : 
    1912        1748 :     _krb5_debug(context, 5, N_("Applying a name rule (type %d) to %s", ""),
    1913        1748 :                 rule->type, orig_hostname);
    1914             : 
    1915        1748 :     if (rule->mindots > 0 || rule->maxdots > 0) {
    1916           0 :         for (cp = strchr(orig_hostname, '.'); cp && *cp; cp = strchr(cp + 1, '.'))
    1917           0 :             ndots++;
    1918             :     }
    1919        1748 :     if (rule->mindots > 0 && ndots < rule->mindots)
    1920           0 :         goto out;
    1921        1748 :     if (ndots > rule->maxdots)
    1922           0 :         goto out;
    1923             : 
    1924        1748 :     if (rule->match_domain != NULL &&
    1925           0 :         !is_domain_suffix(orig_hostname, rule->match_domain))
    1926           0 :         goto out;
    1927             : 
    1928        1748 :     if (rule->match_realm != NULL &&
    1929           0 :         strcmp(rule->match_realm, in_princ->realm) != 0)
    1930           0 :         goto out;
    1931             : 
    1932        1748 :     new_realm = rule->realm;
    1933        1748 :     switch (rule->type) {
    1934        1720 :     case KRB5_NCRT_AS_IS:
    1935        1720 :         break;
    1936             : 
    1937           0 :     case KRB5_NCRT_QUALIFY:
    1938           0 :         heim_assert(rule->domain != NULL,
    1939             :                     "missing domain for qualify name canon rule");
    1940           0 :         if (asprintf(&tmp_hostname, "%s.%s", orig_hostname,
    1941           0 :                      rule->domain) == -1 || tmp_hostname == NULL) {
    1942           0 :             ret = krb5_enomem(context);
    1943           0 :             goto out;
    1944             :         }
    1945           0 :         new_hostname = tmp_hostname;
    1946           0 :         break;
    1947             : 
    1948           0 :     case KRB5_NCRT_NSS:
    1949           0 :         if ((rule->options & KRB5_NCRO_USE_DNSSEC)) {
    1950           0 :             ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN;
    1951           0 :             krb5_set_error_message(context, ret,
    1952             :                                    "Secure hostname resolution not supported");
    1953           0 :             goto out;
    1954             :         }
    1955           0 :         _krb5_debug(context, 5, "Using name service lookups");
    1956           0 :         ret = krb5_sname_to_principal_old(context, rule->realm,
    1957             :                                           orig_hostname, sname,
    1958             :                                           KRB5_NT_SRV_HST,
    1959             :                                           &nss);
    1960           0 :         if (rules[rule_idx + 1].type != KRB5_NCRT_BOGUS &&
    1961           0 :             (ret == KRB5_ERR_BAD_HOSTNAME ||
    1962             :              ret == KRB5_ERR_HOST_REALM_UNKNOWN)) {
    1963             :             /*
    1964             :              * Bad hostname / realm unknown -> rule inapplicable if
    1965             :              * there's more rules.  If it's the last rule then we want
    1966             :              * to return all errors from krb5_sname_to_principal_old()
    1967             :              * here.
    1968             :              */
    1969           0 :             ret = 0;
    1970           0 :             goto out;
    1971             :         }
    1972           0 :         if (ret)
    1973           0 :             goto out;
    1974             : 
    1975           0 :         new_hostname = krb5_principal_get_comp_string(context, nss, 1);
    1976           0 :         new_realm = krb5_principal_get_realm(context, nss);
    1977           0 :         break;
    1978             : 
    1979           0 :     default:
    1980             :         /* Can't happen */
    1981           0 :         ret = 0;
    1982           0 :         goto out;
    1983             :     }
    1984             : 
    1985             :     /*
    1986             :      * This rule applies.
    1987             :      *
    1988             :      * Copy in_princ and mutate the copy per the matched rule.
    1989             :      *
    1990             :      * This way we apply to principals with two or more components, such as
    1991             :      * domain-based names.
    1992             :      */
    1993        1748 :     ret = krb5_copy_principal(context, in_princ, out_princ);
    1994        1748 :     if (ret)
    1995           0 :         goto out;
    1996             : 
    1997        1748 :     if (new_realm == NULL && (rule->options & KRB5_NCRO_LOOKUP_REALM) != 0) {
    1998           0 :         ret = get_host_realm(context, new_hostname, &tmp_realm);
    1999           0 :         if (ret)
    2000           0 :             goto out;
    2001           0 :         new_realm = tmp_realm;
    2002             :     }
    2003             : 
    2004             :     /* If we stripped off a :port, add it back in */
    2005        1748 :     if (port != NULL && new_hostname != NULL) {
    2006           0 :         if (asprintf(&hostname_with_port, "%s%s", new_hostname, port) == -1 ||
    2007           0 :             hostname_with_port == NULL) {
    2008           0 :             ret = krb5_enomem(context);
    2009           0 :             goto out;
    2010             :         }
    2011           0 :         new_hostname = hostname_with_port;
    2012             :     }
    2013             : 
    2014        1748 :     if (new_realm != NULL &&
    2015           0 :         (ret = krb5_principal_set_realm(context, *out_princ, new_realm)))
    2016           0 :         goto out;
    2017        1748 :     if (new_hostname != NULL &&
    2018           0 :         (ret = krb5_principal_set_comp_string(context, *out_princ, 1, new_hostname)))
    2019           0 :         goto out;
    2020        1748 :     if (princ_type(*out_princ) == KRB5_NT_SRV_HST_NEEDS_CANON)
    2021        1748 :         princ_type(*out_princ) = KRB5_NT_SRV_HST;
    2022             : 
    2023             :     /* Trace rule application */
    2024             :     {
    2025          28 :         krb5_error_code ret2;
    2026          28 :         char *unparsed;
    2027             : 
    2028        1748 :         ret2 = krb5_unparse_name(context, *out_princ, &unparsed);
    2029        1748 :         if (ret2) {
    2030           0 :             _krb5_debug(context, 5,
    2031           0 :                         N_("Couldn't unparse canonicalized princicpal (%d)",
    2032             :                            ""),
    2033             :                         ret);
    2034             :         } else {
    2035        1748 :             _krb5_debug(context, 5,
    2036        1748 :                         N_("Name canon rule application yields %s", ""),
    2037             :                         unparsed);
    2038        1748 :             free(unparsed);
    2039             :         }
    2040             :     }
    2041             : 
    2042        1748 : out:
    2043        1748 :     free(hostname_sans_port);
    2044        1748 :     free(hostname_with_port);
    2045        1748 :     free(tmp_hostname);
    2046        1748 :     free(tmp_realm);
    2047        1748 :     krb5_free_principal(context, nss);
    2048        1748 :     if (ret)
    2049           0 :         krb5_set_error_message(context, ret,
    2050           0 :                                N_("Name canon rule application failed", ""));
    2051        1720 :     return ret;
    2052             : }
    2053             : 
    2054             : /**
    2055             :  * Free name canonicalization rules
    2056             :  */
    2057             : KRB5_LIB_FUNCTION void
    2058      753173 : _krb5_free_name_canon_rules(krb5_context context, krb5_name_canon_rule rules)
    2059             : {
    2060       17909 :     size_t k;
    2061             : 
    2062      753173 :     if (rules == NULL)
    2063      735264 :         return;
    2064             : 
    2065           0 :     for (k = 0; rules[k].type != KRB5_NCRT_BOGUS; k++) {
    2066           0 :         free(rules[k].match_domain);
    2067           0 :         free(rules[k].match_realm);
    2068           0 :         free(rules[k].domain);
    2069           0 :         free(rules[k].realm);
    2070             :     }
    2071           0 :     free(rules);
    2072             : }
    2073             : 
    2074             : struct krb5_name_canon_iterator_data {
    2075             :     krb5_name_canon_rule        rules;
    2076             :     krb5_const_principal        in_princ;   /* given princ */
    2077             :     krb5_const_principal        out_princ;  /* princ to be output */
    2078             :     krb5_principal              tmp_princ;  /* to be freed */
    2079             :     int                         is_trivial; /* no canon to be done */
    2080             :     int                         done;       /* no more rules to be applied */
    2081             :     size_t                      cursor;     /* current/next rule */
    2082             : };
    2083             : 
    2084             : /**
    2085             :  * Initialize name canonicalization iterator.
    2086             :  *
    2087             :  * @param context   Kerberos context
    2088             :  * @param in_princ  principal name to be canonicalized OR
    2089             :  * @param iter      output iterator object
    2090             :  */
    2091             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    2092      158730 : krb5_name_canon_iterator_start(krb5_context context,
    2093             :                                krb5_const_principal in_princ,
    2094             :                                krb5_name_canon_iterator *iter)
    2095             : {
    2096        5021 :     krb5_error_code ret;
    2097        5021 :     krb5_name_canon_iterator state;
    2098             : 
    2099      158730 :     *iter = NULL;
    2100             : 
    2101      158730 :     state = calloc(1, sizeof (*state));
    2102      158730 :     if (state == NULL)
    2103           0 :         return krb5_enomem(context);
    2104      158730 :     state->in_princ = in_princ;
    2105             : 
    2106      158730 :     if (princ_type(state->in_princ) == KRB5_NT_SRV_HST_NEEDS_CANON) {
    2107        1748 :         ret = _krb5_get_name_canon_rules(context, &state->rules);
    2108        1748 :         if (ret)
    2109           0 :             goto out;
    2110             :     } else {
    2111             :         /* Name needs no canon -> trivial iterator: in_princ is canonical */
    2112      156982 :         state->is_trivial = 1;
    2113             :     }
    2114             : 
    2115      158730 :     *iter = state;
    2116      158730 :     return 0;
    2117             : 
    2118           0 : out:
    2119           0 :     krb5_free_name_canon_iterator(context, state);
    2120           0 :     return krb5_enomem(context);
    2121             : }
    2122             : 
    2123             : /*
    2124             :  * Helper for name canon iteration.
    2125             :  */
    2126             : static krb5_error_code
    2127      160375 : name_canon_iterate(krb5_context context,
    2128             :                    krb5_name_canon_iterator *iter,
    2129             :                    krb5_name_canon_rule_options *rule_opts)
    2130             : {
    2131        5021 :     krb5_error_code ret;
    2132      160375 :     krb5_name_canon_iterator state = *iter;
    2133             : 
    2134      160375 :     if (rule_opts)
    2135      105985 :         *rule_opts = 0;
    2136             : 
    2137      160375 :     if (state == NULL)
    2138           0 :         return 0;
    2139             : 
    2140      160375 :     if (state->done) {
    2141        1645 :         krb5_free_name_canon_iterator(context, state);
    2142        1645 :         *iter = NULL;
    2143        1645 :         return 0;
    2144             :     }
    2145             : 
    2146      158730 :     if (state->is_trivial && !state->done) {
    2147      156982 :         state->out_princ = state->in_princ;
    2148      156982 :         state->done = 1;
    2149      156982 :         return 0;
    2150             :     }
    2151             : 
    2152        1748 :     heim_assert(state->rules != NULL &&
    2153             :                 state->rules[state->cursor].type != KRB5_NCRT_BOGUS,
    2154             :                 "Internal error during name canonicalization");
    2155             : 
    2156          28 :     do {
    2157        1748 :         krb5_free_principal(context, state->tmp_princ);
    2158        1748 :         ret = apply_name_canon_rule(context, state->rules, state->cursor,
    2159             :             state->in_princ, &state->tmp_princ, rule_opts);
    2160        1748 :         if (ret) {
    2161           0 :             krb5_free_name_canon_iterator(context, state);
    2162           0 :             *iter = NULL;
    2163           0 :             return ret;
    2164             :         }
    2165        1748 :         state->cursor++;
    2166        1748 :     } while (state->tmp_princ == NULL &&
    2167           0 :              state->rules[state->cursor].type != KRB5_NCRT_BOGUS);
    2168             : 
    2169        1748 :     if (state->rules[state->cursor].type == KRB5_NCRT_BOGUS)
    2170        1748 :         state->done = 1;
    2171             : 
    2172        1748 :     state->out_princ = state->tmp_princ;
    2173        1748 :     if (state->tmp_princ == NULL) {
    2174           0 :         krb5_free_name_canon_iterator(context, state);
    2175           0 :         *iter = NULL;
    2176           0 :         return 0;
    2177             :     }
    2178        1720 :     return 0;
    2179             : }
    2180             : 
    2181             : /**
    2182             :  * Iteratively apply name canon rules, outputing a principal and rule
    2183             :  * options each time.  Iteration completes when the @iter is NULL on
    2184             :  * return or when an error is returned.  Callers must free the iterator
    2185             :  * if they abandon it mid-way.
    2186             :  *
    2187             :  * @param context   Kerberos context
    2188             :  * @param iter      name canon rule iterator (input/output)
    2189             :  * @param try_princ output principal name
    2190             :  * @param rule_opts output rule options
    2191             :  */
    2192             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    2193      160375 : krb5_name_canon_iterate(krb5_context context,
    2194             :                         krb5_name_canon_iterator *iter,
    2195             :                         krb5_const_principal *try_princ,
    2196             :                         krb5_name_canon_rule_options *rule_opts)
    2197             : {
    2198        5021 :     krb5_error_code ret;
    2199             : 
    2200      160375 :     *try_princ = NULL;
    2201             : 
    2202      160375 :     ret = name_canon_iterate(context, iter, rule_opts);
    2203      160375 :     if (*iter)
    2204      158730 :         *try_princ = (*iter)->out_princ;
    2205      160375 :     return ret;
    2206             : }
    2207             : 
    2208             : /**
    2209             :  * Free a name canonicalization rule iterator.
    2210             :  */
    2211             : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
    2212      160375 : krb5_free_name_canon_iterator(krb5_context context,
    2213             :                               krb5_name_canon_iterator iter)
    2214             : {
    2215      160375 :     if (iter == NULL)
    2216        1645 :         return;
    2217      158730 :     if (iter->tmp_princ)
    2218        1748 :         krb5_free_principal(context, iter->tmp_princ);
    2219      158730 :     free(iter);
    2220             : }

Generated by: LCOV version 1.14