Coverage Report

Created: 2025-12-08 06:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/krb5/src/lib/krb5/krb/unparse.c
Line
Count
Source
1
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
/* lib/krb5/krb/unparse.c */
3
/*
4
 * Copyright 1990, 2008 by the Massachusetts Institute of Technology.
5
 * All Rights Reserved.
6
 *
7
 * Export of this software from the United States of America may
8
 *   require a specific license from the United States Government.
9
 *   It is the responsibility of any person or organization contemplating
10
 *   export to obtain such a license before exporting.
11
 *
12
 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13
 * distribute this software and its documentation for any purpose and
14
 * without fee is hereby granted, provided that the above copyright
15
 * notice appear in all copies and that both that copyright notice and
16
 * this permission notice appear in supporting documentation, and that
17
 * the name of M.I.T. not be used in advertising or publicity pertaining
18
 * to distribution of the software without specific, written prior
19
 * permission.  Furthermore if you modify this software you must label
20
 * your software as modified software and not distribute it in such a
21
 * fashion that it might be confused with the original M.I.T. software.
22
 * M.I.T. makes no representations about the suitability of
23
 * this software for any purpose.  It is provided "as is" without express
24
 * or implied warranty.
25
 */
26
27
/*
28
 * krb5_unparse_name() routine
29
 *
30
 * Rewritten by Theodore Ts'o to properly unparse principal names
31
 * which have the component or realm separator as part of one of their
32
 * components.
33
 */
34
35
36
#include "k5-int.h"
37
#include <stdio.h>
38
39
/*
40
 * converts the multi-part principal format used in the protocols to a
41
 * single-string representation of the name.
42
 *
43
 * The name returned is in allocated storage and should be freed by
44
 * the caller when finished.
45
 *
46
 * Conventions: / is used to separate components; @ is used to
47
 * separate the realm from the rest of the name.  If '/', '@', or '\0'
48
 * appear in any the component, they will be representing using
49
 * backslash encoding.  ("\/", "\@", or '\0', respectively)
50
 *
51
 * returns error
52
 *      KRB_PARSE_MALFORMED     principal is invalid (does not contain
53
 *                              at least 2 components)
54
 * also returns system errors
55
 *      ENOMEM                  unable to allocate memory for string
56
 */
57
58
16.9k
#define REALM_SEP       '@'
59
37.1k
#define COMPONENT_SEP   '/'
60
61
static int
62
component_length_quoted(const krb5_data *src, int flags)
63
5.84k
{
64
5.84k
    const char *cp = src->data;
65
5.84k
    int length = src->length;
66
5.84k
    int j;
67
5.84k
    int size = length;
68
69
5.84k
    if ((flags & KRB5_PRINCIPAL_UNPARSE_DISPLAY) == 0) {
70
5.02k
        int no_realm = (flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) &&
71
0
            !(flags & KRB5_PRINCIPAL_UNPARSE_SHORT);
72
73
20.8k
        for (j = 0; j < length; j++,cp++)
74
15.8k
            if ((!no_realm && *cp == REALM_SEP) ||
75
15.4k
                *cp == COMPONENT_SEP ||
76
15.0k
                *cp == '\0' || *cp == '\\' || *cp == '\t' ||
77
12.7k
                *cp == '\n' || *cp == '\b')
78
4.99k
                size++;
79
5.02k
    }
80
81
5.84k
    return size;
82
5.84k
}
83
84
static int
85
copy_component_quoting(char *dest, const krb5_data *src, int flags)
86
5.84k
{
87
5.84k
    int j;
88
5.84k
    const char *cp = src->data;
89
5.84k
    char *q = dest;
90
5.84k
    int length = src->length;
91
92
5.84k
    if (flags & KRB5_PRINCIPAL_UNPARSE_DISPLAY) {
93
823
        if (src->length > 0)
94
823
            memcpy(dest, src->data, src->length);
95
823
        return src->length;
96
823
    }
97
98
20.8k
    for (j=0; j < length; j++,cp++) {
99
15.8k
        int no_realm = (flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) &&
100
0
            !(flags & KRB5_PRINCIPAL_UNPARSE_SHORT);
101
102
15.8k
        switch (*cp) {
103
406
        case REALM_SEP:
104
406
            if (no_realm) {
105
0
                *q++ = *cp;
106
0
                break;
107
0
            }
108
794
        case COMPONENT_SEP:
109
1.31k
        case '\\':
110
1.31k
            *q++ = '\\';
111
1.31k
            *q++ = *cp;
112
1.31k
            break;
113
1.37k
        case '\t':
114
1.37k
            *q++ = '\\';
115
1.37k
            *q++ = 't';
116
1.37k
            break;
117
496
        case '\n':
118
496
            *q++ = '\\';
119
496
            *q++ = 'n';
120
496
            break;
121
1.41k
        case '\b':
122
1.41k
            *q++ = '\\';
123
1.41k
            *q++ = 'b';
124
1.41k
            break;
125
389
        case '\0':
126
389
            *q++ = '\\';
127
389
            *q++ = '0';
128
389
            break;
129
10.8k
        default:
130
10.8k
            *q++ = *cp;
131
15.8k
        }
132
15.8k
    }
133
5.02k
    return q - dest;
134
5.02k
}
135
136
static krb5_error_code
137
k5_unparse_name(krb5_context context, krb5_const_principal principal,
138
                int flags, char **name, unsigned int *size)
139
992
{
140
992
    char *q;
141
992
    krb5_int32 i;
142
992
    unsigned int totalsize = 0;
143
992
    char *default_realm = NULL;
144
992
    krb5_error_code ret = 0;
145
146
992
    if (!principal || !name)
147
0
        return KRB5_PARSE_MALFORMED;
148
149
992
    if (flags & KRB5_PRINCIPAL_UNPARSE_SHORT) {
150
        /* omit realm if local realm */
151
0
        krb5_principal_data p;
152
153
0
        ret = krb5_get_default_realm(context, &default_realm);
154
0
        if (ret != 0)
155
0
            goto cleanup;
156
157
0
        p.realm = string2data(default_realm);
158
159
0
        if (krb5_realm_compare(context, &p, principal))
160
0
            flags |= KRB5_PRINCIPAL_UNPARSE_NO_REALM;
161
0
    }
162
163
992
    if ((flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) == 0) {
164
711
        totalsize += component_length_quoted(&principal->realm, flags);
165
711
        totalsize++;            /* This is for the separator */
166
711
    }
167
168
6.12k
    for (i = 0; i < principal->length; i++) {
169
5.13k
        totalsize += component_length_quoted(&principal->data[i], flags);
170
5.13k
        totalsize++;    /* This is for the separator */
171
5.13k
    }
172
992
    if (principal->length == 0)
173
0
        totalsize++;
174
175
    /*
176
     * Allocate space for the ascii string; if space has been
177
     * provided, use it, realloc'ing it if necessary.
178
     *
179
     * We need only n-1 separators for n components, but we need
180
     * an extra byte for the NUL at the end.
181
     */
182
992
    if (size) {
183
0
        if (*name && (*size < totalsize)) {
184
0
            *name = realloc(*name, totalsize);
185
0
        } else {
186
0
            *name = malloc(totalsize);
187
0
        }
188
0
        *size = totalsize;
189
992
    } else {
190
992
        *name = malloc(totalsize);
191
992
    }
192
193
992
    if (!*name) {
194
0
        ret = ENOMEM;
195
0
        goto cleanup;
196
0
    }
197
198
992
    q = *name;
199
200
6.12k
    for (i = 0; i < principal->length; i++) {
201
5.13k
        q += copy_component_quoting(q, &principal->data[i], flags);
202
5.13k
        *q++ = COMPONENT_SEP;
203
5.13k
    }
204
205
992
    if (i > 0)
206
992
        q--;                /* Back up last component separator */
207
992
    if ((flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) == 0) {
208
711
        *q++ = REALM_SEP;
209
711
        q += copy_component_quoting(q, &principal->realm, flags);
210
711
    }
211
992
    *q++ = '\0';
212
213
992
cleanup:
214
992
    if (default_realm != NULL)
215
0
        krb5_free_default_realm(context, default_realm);
216
217
992
    return ret;
218
992
}
219
220
krb5_error_code KRB5_CALLCONV
221
krb5_unparse_name(krb5_context context, krb5_const_principal principal,
222
                  char **name)
223
440
{
224
440
    if (name != NULL)                      /* name == NULL will return error from _ext */
225
440
        *name = NULL;
226
227
440
    return k5_unparse_name(context, principal, 0, name, NULL);
228
440
}
229
230
krb5_error_code KRB5_CALLCONV
231
krb5_unparse_name_ext(krb5_context context, krb5_const_principal principal,
232
                      char **name, unsigned int *size)
233
0
{
234
0
    return k5_unparse_name(context, principal, 0, name, size);
235
0
}
236
237
krb5_error_code KRB5_CALLCONV
238
krb5_unparse_name_flags(krb5_context context, krb5_const_principal principal,
239
                        int flags, char **name)
240
552
{
241
552
    if (name != NULL)
242
552
        *name = NULL;
243
552
    return k5_unparse_name(context, principal, flags, name, NULL);
244
552
}
245
246
krb5_error_code KRB5_CALLCONV
247
krb5_unparse_name_flags_ext(krb5_context context, krb5_const_principal principal,
248
                            int flags, char **name, unsigned int *size)
249
0
{
250
0
    return k5_unparse_name(context, principal, flags, name, size);
251
0
}