~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/heimdal/lib/krb5/principal.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 page_principal The principal handing functions.
 
36
 *
 
37
 * A Kerberos principal is a email address looking string that
 
38
 * contains to parts separeted by a @.  The later part is the kerbero
 
39
 * realm the principal belongs to and the former 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
RCSID("$Id$");
 
61
 
 
62
#define princ_num_comp(P) ((P)->name.name_string.len)
 
63
#define princ_type(P) ((P)->name.name_type)
 
64
#define princ_comp(P) ((P)->name.name_string.val)
 
65
#define princ_ncomp(P, N) ((P)->name.name_string.val[(N)])
 
66
#define princ_realm(P) ((P)->realm)
 
67
 
 
68
/**
 
69
 * Frees a Kerberos principal allocated by the library with
 
70
 * krb5_parse_name(), krb5_make_principal() or any other related
 
71
 * principal functions.
 
72
 *
 
73
 * @param context A Kerberos context.
 
74
 * @param p a principal to free.
 
75
 *
 
76
 * @return An krb5 error code, see krb5_get_error_message().
 
77
 *
 
78
 * @ingroup krb5_principal
 
79
 */
 
80
 
 
81
 
 
82
 
 
83
void KRB5_LIB_FUNCTION
 
84
krb5_free_principal(krb5_context context,
 
85
                    krb5_principal p)
 
86
{
 
87
    if(p){
 
88
        free_Principal(p);
 
89
        free(p);
 
90
    }
 
91
}
 
92
 
 
93
void KRB5_LIB_FUNCTION
 
94
krb5_principal_set_type(krb5_context context,
 
95
                        krb5_principal principal,
 
96
                        int type)
 
97
{
 
98
    princ_type(principal) = type;
 
99
}
 
100
 
 
101
int KRB5_LIB_FUNCTION
 
102
krb5_principal_get_type(krb5_context context,
 
103
                        krb5_const_principal principal)
 
104
{
 
105
    return princ_type(principal);
 
106
}
 
107
 
 
108
const char* KRB5_LIB_FUNCTION
 
109
krb5_principal_get_realm(krb5_context context,
 
110
                         krb5_const_principal principal)
 
111
{
 
112
    return princ_realm(principal);
 
113
}                       
 
114
 
 
115
const char* KRB5_LIB_FUNCTION
 
116
krb5_principal_get_comp_string(krb5_context context,
 
117
                               krb5_const_principal principal,
 
118
                               unsigned int component)
 
119
{
 
120
    if(component >= princ_num_comp(principal))
 
121
       return NULL;
 
122
    return princ_ncomp(principal, component);
 
123
}
 
124
 
 
125
/**
 
126
 * Get number of component is principal.
 
127
 *
 
128
 * @param context Kerberos 5 context
 
129
 * @param principal principal to query
 
130
 * @return number of components in string
 
131
 * @ingroup krb5
 
132
 */
 
133
 
 
134
unsigned int KRB5_LIB_FUNCTION
 
135
krb5_principal_get_num_comp(krb5_context context,
 
136
                            krb5_const_principal principal)
 
137
{
 
138
    return princ_num_comp(principal);
 
139
}
 
140
 
 
141
krb5_error_code KRB5_LIB_FUNCTION
 
142
krb5_parse_name_flags(krb5_context context,
 
143
                      const char *name,
 
144
                      int flags,
 
145
                      krb5_principal *principal)
 
146
{
 
147
    krb5_error_code ret;
 
148
    heim_general_string *comp;
 
149
    heim_general_string realm = NULL;
 
150
    int ncomp;
 
151
 
 
152
    const char *p;
 
153
    char *q;
 
154
    char *s;
 
155
    char *start;
 
156
 
 
157
    int n;
 
158
    char c;
 
159
    int got_realm = 0;
 
160
    int first_at = 1;
 
161
    int enterprise = (flags & KRB5_PRINCIPAL_PARSE_ENTERPRISE);
 
162
 
 
163
    *principal = NULL;
 
164
 
 
165
#define RFLAGS (KRB5_PRINCIPAL_PARSE_NO_REALM|KRB5_PRINCIPAL_PARSE_MUST_REALM)
 
166
 
 
167
    if ((flags & RFLAGS) == RFLAGS) {
 
168
        krb5_set_error_message(context, KRB5_ERR_NO_SERVICE,
 
169
                               N_("Can't require both realm and "
 
170
                                  "no realm at the same time", ""));
 
171
        return KRB5_ERR_NO_SERVICE;
 
172
    }
 
173
#undef RFLAGS
 
174
 
 
175
    /* count number of component,
 
176
     * enterprise names only have one component
 
177
     */
 
178
    ncomp = 1;
 
179
    if (!enterprise) {
 
180
        for(p = name; *p; p++){
 
181
            if(*p=='\\'){
 
182
                if(!p[1]) {
 
183
                    krb5_set_error_message(context, KRB5_PARSE_MALFORMED,
 
184
                                           N_("trailing \\ in principal name", ""));
 
185
                    return KRB5_PARSE_MALFORMED;
 
186
                }
 
187
                p++;
 
188
            } else if(*p == '/')
 
189
                ncomp++;
 
190
            else if(*p == '@')
 
191
                break;
 
192
        }
 
193
    }
 
194
    comp = calloc(ncomp, sizeof(*comp));
 
195
    if (comp == NULL) {
 
196
        krb5_set_error_message(context, ENOMEM,
 
197
                               N_("malloc: out of memory", ""));
 
198
        return ENOMEM;
 
199
    }
 
200
 
 
201
    n = 0;
 
202
    p = start = q = s = strdup(name);
 
203
    if (start == NULL) {
 
204
        free (comp);
 
205
        krb5_set_error_message(context, ENOMEM,
 
206
                               N_("malloc: out of memory", ""));
 
207
        return ENOMEM;
 
208
    }
 
209
    while(*p){
 
210
        c = *p++;
 
211
        if(c == '\\'){
 
212
            c = *p++;
 
213
            if(c == 'n')
 
214
                c = '\n';
 
215
            else if(c == 't')
 
216
                c = '\t';
 
217
            else if(c == 'b')
 
218
                c = '\b';
 
219
            else if(c == '0')
 
220
                c = '\0';
 
221
            else if(c == '\0') {
 
222
                ret = KRB5_PARSE_MALFORMED;
 
223
                krb5_set_error_message(context, ret,
 
224
                                       N_("trailing \\ in principal name", ""));
 
225
                goto exit;
 
226
            }
 
227
        }else if(enterprise && first_at) {
 
228
            if (c == '@')
 
229
                first_at = 0;
 
230
        }else if((c == '/' && !enterprise) || c == '@'){
 
231
            if(got_realm){
 
232
                ret = KRB5_PARSE_MALFORMED;
 
233
                krb5_set_error_message(context, ret,
 
234
                                       N_("part after realm in principal name", ""));
 
235
                goto exit;
 
236
            }else{
 
237
                comp[n] = malloc(q - start + 1);
 
238
                if (comp[n] == NULL) {
 
239
                    ret = ENOMEM;
 
240
                    krb5_set_error_message(context, ret,
 
241
                                           N_("malloc: out of memory", ""));
 
242
                    goto exit;
 
243
                }
 
244
                memcpy(comp[n], start, q - start);
 
245
                comp[n][q - start] = 0;
 
246
                n++;
 
247
            }
 
248
            if(c == '@')
 
249
                got_realm = 1;
 
250
            start = q;
 
251
            continue;
 
252
        }
 
253
        if(got_realm && (c == '/' || c == '\0')) {
 
254
            ret = KRB5_PARSE_MALFORMED;
 
255
            krb5_set_error_message(context, ret,
 
256
                                   N_("part after realm in principal name", ""));
 
257
            goto exit;
 
258
        }
 
259
        *q++ = c;
 
260
    }
 
261
    if(got_realm){
 
262
        if (flags & KRB5_PRINCIPAL_PARSE_NO_REALM) {
 
263
            ret = KRB5_PARSE_MALFORMED;
 
264
            krb5_set_error_message(context, ret,
 
265
                                   N_("realm found in 'short' principal "
 
266
                                      "expected to be without one", ""));
 
267
            goto exit;
 
268
        }
 
269
        realm = malloc(q - start + 1);
 
270
        if (realm == NULL) {
 
271
            ret = ENOMEM;
 
272
            krb5_set_error_message(context, ret,
 
273
                                   N_("malloc: out of memory", ""));
 
274
            goto exit;
 
275
        }
 
276
        memcpy(realm, start, q - start);
 
277
        realm[q - start] = 0;
 
278
    }else{
 
279
        if (flags & KRB5_PRINCIPAL_PARSE_MUST_REALM) {
 
280
            ret = KRB5_PARSE_MALFORMED;
 
281
            krb5_set_error_message(context, ret,
 
282
                                   N_("realm NOT found in principal "
 
283
                                      "expected to be with one", ""));
 
284
            goto exit;
 
285
        } else if (flags & KRB5_PRINCIPAL_PARSE_NO_REALM) {
 
286
            realm = NULL;
 
287
        } else {
 
288
            ret = krb5_get_default_realm (context, &realm);
 
289
            if (ret)
 
290
                goto exit;
 
291
        }
 
292
 
 
293
        comp[n] = malloc(q - start + 1);
 
294
        if (comp[n] == NULL) {
 
295
            ret = ENOMEM;
 
296
            krb5_set_error_message(context, ret,
 
297
                                   N_("malloc: out of memory", ""));
 
298
            goto exit;
 
299
        }
 
300
        memcpy(comp[n], start, q - start);
 
301
        comp[n][q - start] = 0;
 
302
        n++;
 
303
    }
 
304
    *principal = malloc(sizeof(**principal));
 
305
    if (*principal == NULL) {
 
306
        ret = ENOMEM;
 
307
        krb5_set_error_message(context, ret,
 
308
                               N_("malloc: out of memory", ""));
 
309
        goto exit;
 
310
    }
 
311
    if (enterprise)
 
312
        (*principal)->name.name_type = KRB5_NT_ENTERPRISE_PRINCIPAL;
 
313
    else
 
314
        (*principal)->name.name_type = KRB5_NT_PRINCIPAL;
 
315
    (*principal)->name.name_string.val = comp;
 
316
    princ_num_comp(*principal) = n;
 
317
    (*principal)->realm = realm;
 
318
    free(s);
 
319
    return 0;
 
320
exit:
 
321
    while(n>0){
 
322
        free(comp[--n]);
 
323
    }
 
324
    free(comp);
 
325
    free(realm);
 
326
    free(s);
 
327
    return ret;
 
328
}
 
329
 
 
330
krb5_error_code KRB5_LIB_FUNCTION
 
331
krb5_parse_name(krb5_context context,
 
332
                const char *name,
 
333
                krb5_principal *principal)
 
334
{
 
335
    return krb5_parse_name_flags(context, name, 0, principal);
 
336
}
 
337
 
 
338
static const char quotable_chars[] = " \n\t\b\\/@";
 
339
static const char replace_chars[] = " ntb\\/@";
 
340
static const char nq_chars[] = "    \\/@";
 
341
 
 
342
#define add_char(BASE, INDEX, LEN, C) do { if((INDEX) < (LEN)) (BASE)[(INDEX)++] = (C); }while(0);
 
343
 
 
344
static size_t
 
345
quote_string(const char *s, char *out, size_t idx, size_t len, int display)
 
346
{
 
347
    const char *p, *q;
 
348
    for(p = s; *p && idx < len; p++){
 
349
        q = strchr(quotable_chars, *p);
 
350
        if (q && display) {
 
351
            add_char(out, idx, len, replace_chars[q - quotable_chars]);
 
352
        } else if (q) {
 
353
            add_char(out, idx, len, '\\');
 
354
            add_char(out, idx, len, replace_chars[q - quotable_chars]);
 
355
        }else
 
356
            add_char(out, idx, len, *p);
 
357
    }
 
358
    if(idx < len)
 
359
        out[idx] = '\0';
 
360
    return idx;
 
361
}
 
362
 
 
363
 
 
364
static krb5_error_code
 
365
unparse_name_fixed(krb5_context context,
 
366
                   krb5_const_principal principal,
 
367
                   char *name,
 
368
                   size_t len,
 
369
                   int flags)
 
370
{
 
371
    size_t idx = 0;
 
372
    int i;
 
373
    int short_form = (flags & KRB5_PRINCIPAL_UNPARSE_SHORT) != 0;
 
374
    int no_realm = (flags & KRB5_PRINCIPAL_UNPARSE_NO_REALM) != 0;
 
375
    int display = (flags & KRB5_PRINCIPAL_UNPARSE_DISPLAY) != 0;
 
376
 
 
377
    if (!no_realm && princ_realm(principal) == NULL) {
 
378
        krb5_set_error_message(context, ERANGE,
 
379
                               N_("Realm missing from principal, "
 
380
                                  "can't unparse", ""));
 
381
        return ERANGE;
 
382
    }
 
383
 
 
384
    for(i = 0; i < princ_num_comp(principal); i++){
 
385
        if(i)
 
386
            add_char(name, idx, len, '/');
 
387
        idx = quote_string(princ_ncomp(principal, i), name, idx, len, display);
 
388
        if(idx == len) {
 
389
            krb5_set_error_message(context, ERANGE,
 
390
                                   N_("Out of space printing principal", ""));
 
391
            return ERANGE;
 
392
        }
 
393
    }
 
394
    /* add realm if different from default realm */
 
395
    if(short_form && !no_realm) {
 
396
        krb5_realm r;
 
397
        krb5_error_code ret;
 
398
        ret = krb5_get_default_realm(context, &r);
 
399
        if(ret)
 
400
            return ret;
 
401
        if(strcmp(princ_realm(principal), r) != 0)
 
402
            short_form = 0;
 
403
        free(r);
 
404
    }
 
405
    if(!short_form && !no_realm) {
 
406
        add_char(name, idx, len, '@');
 
407
        idx = quote_string(princ_realm(principal), name, idx, len, display);
 
408
        if(idx == len) {
 
409
            krb5_set_error_message(context, ERANGE,
 
410
                                   N_("Out of space printing "
 
411
                                      "realm of principal", ""));
 
412
            return ERANGE;
 
413
        }
 
414
    }
 
415
    return 0;
 
416
}
 
417
 
 
418
krb5_error_code KRB5_LIB_FUNCTION
 
419
krb5_unparse_name_fixed(krb5_context context,
 
420
                        krb5_const_principal principal,
 
421
                        char *name,
 
422
                        size_t len)
 
423
{
 
424
    return unparse_name_fixed(context, principal, name, len, 0);
 
425
}
 
426
 
 
427
krb5_error_code KRB5_LIB_FUNCTION
 
428
krb5_unparse_name_fixed_short(krb5_context context,
 
429
                              krb5_const_principal principal,
 
430
                              char *name,
 
431
                              size_t len)
 
432
{
 
433
    return unparse_name_fixed(context, principal, name, len,
 
434
                              KRB5_PRINCIPAL_UNPARSE_SHORT);
 
435
}
 
436
 
 
437
krb5_error_code KRB5_LIB_FUNCTION
 
438
krb5_unparse_name_fixed_flags(krb5_context context,
 
439
                              krb5_const_principal principal,
 
440
                              int flags,
 
441
                              char *name,
 
442
                              size_t len)
 
443
{
 
444
    return unparse_name_fixed(context, principal, name, len, flags);
 
445
}
 
446
 
 
447
static krb5_error_code
 
448
unparse_name(krb5_context context,
 
449
             krb5_const_principal principal,
 
450
             char **name,
 
451
             int flags)
 
452
{
 
453
    size_t len = 0, plen;
 
454
    int i;
 
455
    krb5_error_code ret;
 
456
    /* count length */
 
457
    if (princ_realm(principal)) {
 
458
        plen = strlen(princ_realm(principal));
 
459
 
 
460
        if(strcspn(princ_realm(principal), quotable_chars) == plen)
 
461
            len += plen;
 
462
        else
 
463
            len += 2*plen;
 
464
        len++; /* '@' */
 
465
    }
 
466
    for(i = 0; i < princ_num_comp(principal); i++){
 
467
        plen = strlen(princ_ncomp(principal, i));
 
468
        if(strcspn(princ_ncomp(principal, i), quotable_chars) == plen)
 
469
            len += plen;
 
470
        else
 
471
            len += 2*plen;
 
472
        len++;
 
473
    }
 
474
    len++; /* '\0' */
 
475
    *name = malloc(len);
 
476
    if(*name == NULL) {
 
477
        krb5_set_error_message(context, ENOMEM,
 
478
                               N_("malloc: out of memory", ""));
 
479
        return ENOMEM;
 
480
    }
 
481
    ret = unparse_name_fixed(context, principal, *name, len, flags);
 
482
    if(ret) {
 
483
        free(*name);
 
484
        *name = NULL;
 
485
    }
 
486
    return ret;
 
487
}
 
488
 
 
489
krb5_error_code KRB5_LIB_FUNCTION
 
490
krb5_unparse_name(krb5_context context,
 
491
                  krb5_const_principal principal,
 
492
                  char **name)
 
493
{
 
494
    return unparse_name(context, principal, name, 0);
 
495
}
 
496
 
 
497
krb5_error_code KRB5_LIB_FUNCTION
 
498
krb5_unparse_name_flags(krb5_context context,
 
499
                        krb5_const_principal principal,
 
500
                        int flags,
 
501
                        char **name)
 
502
{
 
503
    return unparse_name(context, principal, name, flags);
 
504
}
 
505
 
 
506
krb5_error_code KRB5_LIB_FUNCTION
 
507
krb5_unparse_name_short(krb5_context context,
 
508
                        krb5_const_principal principal,
 
509
                        char **name)
 
510
{
 
511
    return unparse_name(context, principal, name, KRB5_PRINCIPAL_UNPARSE_SHORT);
 
512
}
 
513
 
 
514
#if 0 /* not implemented */
 
515
 
 
516
krb5_error_code KRB5_LIB_FUNCTION
 
517
krb5_unparse_name_ext(krb5_context context,
 
518
                      krb5_const_principal principal,
 
519
                      char **name,
 
520
                      size_t *size)
 
521
{
 
522
    krb5_abortx(context, "unimplemented krb5_unparse_name_ext called");
 
523
}
 
524
 
 
525
#endif
 
526
 
 
527
krb5_realm * KRB5_LIB_FUNCTION
 
528
krb5_princ_realm(krb5_context context,
 
529
                 krb5_principal principal)
 
530
{
 
531
    return &princ_realm(principal);
 
532
}
 
533
 
 
534
 
 
535
void KRB5_LIB_FUNCTION
 
536
krb5_princ_set_realm(krb5_context context,
 
537
                     krb5_principal principal,
 
538
                     krb5_realm *realm)
 
539
{
 
540
    princ_realm(principal) = *realm;
 
541
}
 
542
 
 
543
krb5_error_code KRB5_LIB_FUNCTION
 
544
krb5_principal_set_realm(krb5_context context,
 
545
                         krb5_principal principal,
 
546
                         krb5_const_realm realm)
 
547
{
 
548
    if (princ_realm(principal))
 
549
        free(princ_realm(principal));
 
550
 
 
551
    princ_realm(principal) = strdup(realm);
 
552
    if (princ_realm(principal) == NULL) {
 
553
        krb5_set_error_message(context, ENOMEM,
 
554
                               N_("malloc: out of memory", ""));
 
555
        return ENOMEM;
 
556
    }
 
557
    return 0;
 
558
}
 
559
 
 
560
 
 
561
krb5_error_code KRB5_LIB_FUNCTION
 
562
krb5_build_principal(krb5_context context,
 
563
                     krb5_principal *principal,
 
564
                     int rlen,
 
565
                     krb5_const_realm realm,
 
566
                     ...)
 
567
{
 
568
    krb5_error_code ret;
 
569
    va_list ap;
 
570
    va_start(ap, realm);
 
571
    ret = krb5_build_principal_va(context, principal, rlen, realm, ap);
 
572
    va_end(ap);
 
573
    return ret;
 
574
}
 
575
 
 
576
static krb5_error_code
 
577
append_component(krb5_context context, krb5_principal p,
 
578
                 const char *comp,
 
579
                 size_t comp_len)
 
580
{
 
581
    heim_general_string *tmp;
 
582
    size_t len = princ_num_comp(p);
 
583
 
 
584
    tmp = realloc(princ_comp(p), (len + 1) * sizeof(*tmp));
 
585
    if(tmp == NULL) {
 
586
        krb5_set_error_message(context, ENOMEM,
 
587
                               N_("malloc: out of memory", ""));
 
588
        return ENOMEM;
 
589
    }
 
590
    princ_comp(p) = tmp;
 
591
    princ_ncomp(p, len) = malloc(comp_len + 1);
 
592
    if (princ_ncomp(p, len) == NULL) {
 
593
        krb5_set_error_message(context, ENOMEM,
 
594
                               N_("malloc: out of memory", ""));
 
595
        return ENOMEM;
 
596
    }
 
597
    memcpy (princ_ncomp(p, len), comp, comp_len);
 
598
    princ_ncomp(p, len)[comp_len] = '\0';
 
599
    princ_num_comp(p)++;
 
600
    return 0;
 
601
}
 
602
 
 
603
static void
 
604
va_ext_princ(krb5_context context, krb5_principal p, va_list ap)
 
605
{
 
606
    while(1){
 
607
        const char *s;
 
608
        int len;
 
609
        len = va_arg(ap, int);
 
610
        if(len == 0)
 
611
            break;
 
612
        s = va_arg(ap, const char*);
 
613
        append_component(context, p, s, len);
 
614
    }
 
615
}
 
616
 
 
617
static void
 
618
va_princ(krb5_context context, krb5_principal p, va_list ap)
 
619
{
 
620
    while(1){
 
621
        const char *s;
 
622
        s = va_arg(ap, const char*);
 
623
        if(s == NULL)
 
624
            break;
 
625
        append_component(context, p, s, strlen(s));
 
626
    }
 
627
}
 
628
 
 
629
 
 
630
static krb5_error_code
 
631
build_principal(krb5_context context,
 
632
                krb5_principal *principal,
 
633
                int rlen,
 
634
                krb5_const_realm realm,
 
635
                void (*func)(krb5_context, krb5_principal, va_list),
 
636
                va_list ap)
 
637
{
 
638
    krb5_principal p;
 
639
 
 
640
    p = calloc(1, sizeof(*p));
 
641
    if (p == NULL) {
 
642
        krb5_set_error_message(context, ENOMEM,
 
643
                               N_("malloc: out of memory", ""));
 
644
        return ENOMEM;
 
645
    }
 
646
    princ_type(p) = KRB5_NT_PRINCIPAL;
 
647
 
 
648
    princ_realm(p) = strdup(realm);
 
649
    if(p->realm == NULL){
 
650
        free(p);
 
651
        krb5_set_error_message(context, ENOMEM,
 
652
                               N_("malloc: out of memory", ""));
 
653
        return ENOMEM;
 
654
    }
 
655
 
 
656
    (*func)(context, p, ap);
 
657
    *principal = p;
 
658
    return 0;
 
659
}
 
660
 
 
661
krb5_error_code KRB5_LIB_FUNCTION
 
662
krb5_make_principal(krb5_context context,
 
663
                    krb5_principal *principal,
 
664
                    krb5_const_realm realm,
 
665
                    ...)
 
666
{
 
667
    krb5_error_code ret;
 
668
    krb5_realm r = NULL;
 
669
    va_list ap;
 
670
    if(realm == NULL) {
 
671
        ret = krb5_get_default_realm(context, &r);
 
672
        if(ret)
 
673
            return ret;
 
674
        realm = r;
 
675
    }
 
676
    va_start(ap, realm);
 
677
    ret = krb5_build_principal_va(context, principal, strlen(realm), realm, ap);
 
678
    va_end(ap);
 
679
    if(r)
 
680
        free(r);
 
681
    return ret;
 
682
}
 
683
 
 
684
krb5_error_code KRB5_LIB_FUNCTION
 
685
krb5_build_principal_va(krb5_context context,
 
686
                        krb5_principal *principal,
 
687
                        int rlen,
 
688
                        krb5_const_realm realm,
 
689
                        va_list ap)
 
690
{
 
691
    return build_principal(context, principal, rlen, realm, va_princ, ap);
 
692
}
 
693
 
 
694
krb5_error_code KRB5_LIB_FUNCTION
 
695
krb5_build_principal_va_ext(krb5_context context,
 
696
                            krb5_principal *principal,
 
697
                            int rlen,
 
698
                            krb5_const_realm realm,
 
699
                            va_list ap)
 
700
{
 
701
    return build_principal(context, principal, rlen, realm, va_ext_princ, ap);
 
702
}
 
703
 
 
704
 
 
705
krb5_error_code KRB5_LIB_FUNCTION
 
706
krb5_build_principal_ext(krb5_context context,
 
707
                         krb5_principal *principal,
 
708
                         int rlen,
 
709
                         krb5_const_realm realm,
 
710
                         ...)
 
711
{
 
712
    krb5_error_code ret;
 
713
    va_list ap;
 
714
    va_start(ap, realm);
 
715
    ret = krb5_build_principal_va_ext(context, principal, rlen, realm, ap);
 
716
    va_end(ap);
 
717
    return ret;
 
718
}
 
719
 
 
720
 
 
721
krb5_error_code KRB5_LIB_FUNCTION
 
722
krb5_copy_principal(krb5_context context,
 
723
                    krb5_const_principal inprinc,
 
724
                    krb5_principal *outprinc)
 
725
{
 
726
    krb5_principal p = malloc(sizeof(*p));
 
727
    if (p == NULL) {
 
728
        krb5_set_error_message(context, ENOMEM,
 
729
                               N_("malloc: out of memory", ""));
 
730
        return ENOMEM;
 
731
    }
 
732
    if(copy_Principal(inprinc, p)) {
 
733
        free(p);
 
734
        krb5_set_error_message(context, ENOMEM,
 
735
                               N_("malloc: out of memory", ""));
 
736
        return ENOMEM;
 
737
    }
 
738
    *outprinc = p;
 
739
    return 0;
 
740
}
 
741
 
 
742
/*
 
743
 * return TRUE iff princ1 == princ2 (without considering the realm)
 
744
 */
 
745
 
 
746
krb5_boolean KRB5_LIB_FUNCTION
 
747
krb5_principal_compare_any_realm(krb5_context context,
 
748
                                 krb5_const_principal princ1,
 
749
                                 krb5_const_principal princ2)
 
750
{
 
751
    int i;
 
752
    if(princ_num_comp(princ1) != princ_num_comp(princ2))
 
753
        return FALSE;
 
754
    for(i = 0; i < princ_num_comp(princ1); i++){
 
755
        if(strcmp(princ_ncomp(princ1, i), princ_ncomp(princ2, i)) != 0)
 
756
            return FALSE;
 
757
    }
 
758
    return TRUE;
 
759
}
 
760
 
 
761
krb5_boolean KRB5_LIB_FUNCTION
 
762
_krb5_principal_compare_PrincipalName(krb5_context context,
 
763
                                      krb5_const_principal princ1,
 
764
                                      PrincipalName *princ2)
 
765
{
 
766
    int i;
 
767
    if (princ_num_comp(princ1) != princ2->name_string.len)
 
768
        return FALSE;
 
769
    for(i = 0; i < princ_num_comp(princ1); i++){
 
770
        if(strcmp(princ_ncomp(princ1, i), princ2->name_string.val[i]) != 0)
 
771
            return FALSE;
 
772
    }
 
773
    return TRUE;
 
774
}
 
775
 
 
776
 
 
777
/*
 
778
 * return TRUE iff princ1 == princ2
 
779
 */
 
780
 
 
781
krb5_boolean KRB5_LIB_FUNCTION
 
782
krb5_principal_compare(krb5_context context,
 
783
                       krb5_const_principal princ1,
 
784
                       krb5_const_principal princ2)
 
785
{
 
786
    if(!krb5_realm_compare(context, princ1, princ2))
 
787
        return FALSE;
 
788
    return krb5_principal_compare_any_realm(context, princ1, princ2);
 
789
}
 
790
 
 
791
/*
 
792
 * return TRUE iff realm(princ1) == realm(princ2)
 
793
 */
 
794
 
 
795
krb5_boolean KRB5_LIB_FUNCTION
 
796
krb5_realm_compare(krb5_context context,
 
797
                   krb5_const_principal princ1,
 
798
                   krb5_const_principal princ2)
 
799
{
 
800
    return strcmp(princ_realm(princ1), princ_realm(princ2)) == 0;
 
801
}
 
802
 
 
803
/*
 
804
 * return TRUE iff princ matches pattern
 
805
 */
 
806
 
 
807
krb5_boolean KRB5_LIB_FUNCTION
 
808
krb5_principal_match(krb5_context context,
 
809
                     krb5_const_principal princ,
 
810
                     krb5_const_principal pattern)
 
811
{
 
812
    int i;
 
813
    if(princ_num_comp(princ) != princ_num_comp(pattern))
 
814
        return FALSE;
 
815
    if(fnmatch(princ_realm(pattern), princ_realm(princ), 0) != 0)
 
816
        return FALSE;
 
817
    for(i = 0; i < princ_num_comp(princ); i++){
 
818
        if(fnmatch(princ_ncomp(pattern, i), princ_ncomp(princ, i), 0) != 0)
 
819
            return FALSE;
 
820
    }
 
821
    return TRUE;
 
822
}
 
823
 
 
824
 
 
825
static struct v4_name_convert {
 
826
    const char *from;
 
827
    const char *to;
 
828
} default_v4_name_convert[] = {
 
829
    { "ftp",    "ftp" },
 
830
    { "hprop",  "hprop" },
 
831
    { "pop",    "pop" },
 
832
    { "imap",   "imap" },
 
833
    { "rcmd",   "host" },
 
834
    { "smtp",   "smtp" },
 
835
    { NULL, NULL }
 
836
};
 
837
 
 
838
/*
 
839
 * return the converted instance name of `name' in `realm'.
 
840
 * look in the configuration file and then in the default set above.
 
841
 * return NULL if no conversion is appropriate.
 
842
 */
 
843
 
 
844
static const char*
 
845
get_name_conversion(krb5_context context, const char *realm, const char *name)
 
846
{
 
847
    struct v4_name_convert *q;
 
848
    const char *p;
 
849
 
 
850
    p = krb5_config_get_string(context, NULL, "realms", realm,
 
851
                               "v4_name_convert", "host", name, NULL);
 
852
    if(p == NULL)
 
853
        p = krb5_config_get_string(context, NULL, "libdefaults",
 
854
                                   "v4_name_convert", "host", name, NULL);
 
855
    if(p)
 
856
        return p;
 
857
 
 
858
    /* XXX should be possible to override default list */
 
859
    p = krb5_config_get_string(context, NULL,
 
860
                               "realms",
 
861
                               realm,
 
862
                               "v4_name_convert",
 
863
                               "plain",
 
864
                               name,
 
865
                               NULL);
 
866
    if(p)
 
867
        return NULL;
 
868
    p = krb5_config_get_string(context, NULL,
 
869
                               "libdefaults",
 
870
                               "v4_name_convert",
 
871
                               "plain",
 
872
                               name,
 
873
                               NULL);
 
874
    if(p)
 
875
        return NULL;
 
876
    for(q = default_v4_name_convert; q->from; q++)
 
877
        if(strcmp(q->from, name) == 0)
 
878
            return q->to;
 
879
    return NULL;
 
880
}
 
881
 
 
882
/*
 
883
 * convert the v4 principal `name.instance@realm' to a v5 principal in `princ'.
 
884
 * if `resolve', use DNS.
 
885
 * if `func', use that function for validating the conversion
 
886
 */
 
887
 
 
888
krb5_error_code KRB5_LIB_FUNCTION
 
889
krb5_425_conv_principal_ext2(krb5_context context,
 
890
                             const char *name,
 
891
                             const char *instance,
 
892
                             const char *realm,
 
893
                             krb5_boolean (*func)(krb5_context,
 
894
                                                  void *, krb5_principal),
 
895
                             void *funcctx,
 
896
                             krb5_boolean resolve,
 
897
                             krb5_principal *princ)
 
898
{
 
899
    const char *p;
 
900
    krb5_error_code ret;
 
901
    krb5_principal pr;
 
902
    char host[MAXHOSTNAMELEN];
 
903
    char local_hostname[MAXHOSTNAMELEN];
 
904
 
 
905
    /* do the following: if the name is found in the
 
906
       `v4_name_convert:host' part, is assumed to be a `host' type
 
907
       principal, and the instance is looked up in the
 
908
       `v4_instance_convert' part. if not found there the name is
 
909
       (optionally) looked up as a hostname, and if that doesn't yield
 
910
       anything, the `default_domain' is appended to the instance
 
911
       */
 
912
 
 
913
    if(instance == NULL)
 
914
        goto no_host;
 
915
    if(instance[0] == 0){
 
916
        instance = NULL;
 
917
        goto no_host;
 
918
    }
 
919
    p = get_name_conversion(context, realm, name);
 
920
    if(p == NULL)
 
921
        goto no_host;
 
922
    name = p;
 
923
    p = krb5_config_get_string(context, NULL, "realms", realm,
 
924
                               "v4_instance_convert", instance, NULL);
 
925
    if(p){
 
926
        instance = p;
 
927
        ret = krb5_make_principal(context, &pr, realm, name, instance, NULL);
 
928
        if(func == NULL || (*func)(context, funcctx, pr)){
 
929
            *princ = pr;
 
930
            return 0;
 
931
        }
 
932
        krb5_free_principal(context, pr);
 
933
        *princ = NULL;
 
934
        krb5_clear_error_message (context);
 
935
        return HEIM_ERR_V4_PRINC_NO_CONV;
 
936
    }
 
937
    if(resolve){
 
938
        krb5_boolean passed = FALSE;
 
939
        char *inst = NULL;
 
940
#ifdef USE_RESOLVER
 
941
        struct dns_reply *r;
 
942
 
 
943
        r = dns_lookup(instance, "aaaa");
 
944
        if (r) {
 
945
            if (r->head && r->head->type == T_AAAA) {
 
946
                inst = strdup(r->head->domain);
 
947
                passed = TRUE;
 
948
            }
 
949
            dns_free_data(r);
 
950
        } else {
 
951
            r = dns_lookup(instance, "a");
 
952
            if (r) {
 
953
                if(r->head && r->head->type == T_A) {
 
954
                    inst = strdup(r->head->domain);
 
955
                    passed = TRUE;
 
956
                }
 
957
                dns_free_data(r);
 
958
            }
 
959
        }
 
960
#else
 
961
        struct addrinfo hints, *ai;
 
962
        
 
963
        memset (&hints, 0, sizeof(hints));
 
964
        hints.ai_flags = AI_CANONNAME;
 
965
        ret = getaddrinfo(instance, NULL, &hints, &ai);
 
966
        if (ret == 0) {
 
967
            const struct addrinfo *a;
 
968
            for (a = ai; a != NULL; a = a->ai_next) {
 
969
                if (a->ai_canonname != NULL) {
 
970
                    inst = strdup (a->ai_canonname);
 
971
                    passed = TRUE;
 
972
                    break;
 
973
                }
 
974
            }
 
975
            freeaddrinfo (ai);
 
976
        }
 
977
#endif
 
978
        if (passed) {
 
979
            if (inst == NULL) {
 
980
                krb5_set_error_message(context, ENOMEM,
 
981
                                       N_("malloc: out of memory", ""));
 
982
                return ENOMEM;
 
983
            }
 
984
            strlwr(inst);
 
985
            ret = krb5_make_principal(context, &pr, realm, name, inst,
 
986
                                      NULL);
 
987
            free (inst);
 
988
            if(ret == 0) {
 
989
                if(func == NULL || (*func)(context, funcctx, pr)){
 
990
                    *princ = pr;
 
991
                    return 0;
 
992
                }
 
993
                krb5_free_principal(context, pr);
 
994
            }
 
995
        }
 
996
    }
 
997
    if(func != NULL) {
 
998
        snprintf(host, sizeof(host), "%s.%s", instance, realm);
 
999
        strlwr(host);
 
1000
        ret = krb5_make_principal(context, &pr, realm, name, host, NULL);
 
1001
        if((*func)(context, funcctx, pr)){
 
1002
            *princ = pr;
 
1003
            return 0;
 
1004
        }
 
1005
        krb5_free_principal(context, pr);
 
1006
    }
 
1007
 
 
1008
    /*
 
1009
     * if the instance is the first component of the local hostname,
 
1010
     * the converted host should be the long hostname.
 
1011
     */
 
1012
 
 
1013
    if (func == NULL &&
 
1014
        gethostname (local_hostname, sizeof(local_hostname)) == 0 &&
 
1015
        strncmp(instance, local_hostname, strlen(instance)) == 0 &&
 
1016
        local_hostname[strlen(instance)] == '.') {
 
1017
        strlcpy(host, local_hostname, sizeof(host));
 
1018
        goto local_host;
 
1019
    }
 
1020
 
 
1021
    {
 
1022
        char **domains, **d;
 
1023
        domains = krb5_config_get_strings(context, NULL, "realms", realm,
 
1024
                                          "v4_domains", NULL);
 
1025
        for(d = domains; d && *d; d++){
 
1026
            snprintf(host, sizeof(host), "%s.%s", instance, *d);
 
1027
            ret = krb5_make_principal(context, &pr, realm, name, host, NULL);
 
1028
            if(func == NULL || (*func)(context, funcctx, pr)){
 
1029
                *princ = pr;
 
1030
                krb5_config_free_strings(domains);
 
1031
                return 0;
 
1032
            }
 
1033
            krb5_free_principal(context, pr);
 
1034
        }
 
1035
        krb5_config_free_strings(domains);
 
1036
    }
 
1037
 
 
1038
 
 
1039
    p = krb5_config_get_string(context, NULL, "realms", realm,
 
1040
                               "default_domain", NULL);
 
1041
    if(p == NULL){
 
1042
        /* this should be an error, just faking a name is not good */
 
1043
        krb5_clear_error_message (context);
 
1044
        return HEIM_ERR_V4_PRINC_NO_CONV;
 
1045
    }
 
1046
        
 
1047
    if (*p == '.')
 
1048
        ++p;
 
1049
    snprintf(host, sizeof(host), "%s.%s", instance, p);
 
1050
local_host:
 
1051
    ret = krb5_make_principal(context, &pr, realm, name, host, NULL);
 
1052
    if(func == NULL || (*func)(context, funcctx, pr)){
 
1053
        *princ = pr;
 
1054
        return 0;
 
1055
    }
 
1056
    krb5_free_principal(context, pr);
 
1057
    krb5_clear_error_message (context);
 
1058
    return HEIM_ERR_V4_PRINC_NO_CONV;
 
1059
no_host:
 
1060
    p = krb5_config_get_string(context, NULL,
 
1061
                               "realms",
 
1062
                               realm,
 
1063
                               "v4_name_convert",
 
1064
                               "plain",
 
1065
                               name,
 
1066
                               NULL);
 
1067
    if(p == NULL)
 
1068
        p = krb5_config_get_string(context, NULL,
 
1069
                                   "libdefaults",
 
1070
                                   "v4_name_convert",
 
1071
                                   "plain",
 
1072
                                   name,
 
1073
                                   NULL);
 
1074
    if(p)
 
1075
        name = p;
 
1076
 
 
1077
    ret = krb5_make_principal(context, &pr, realm, name, instance, NULL);
 
1078
    if(func == NULL || (*func)(context, funcctx, pr)){
 
1079
        *princ = pr;
 
1080
        return 0;
 
1081
    }
 
1082
    krb5_free_principal(context, pr);
 
1083
    krb5_clear_error_message (context);
 
1084
    return HEIM_ERR_V4_PRINC_NO_CONV;
 
1085
}
 
1086
 
 
1087
static krb5_boolean
 
1088
convert_func(krb5_context conxtext, void *funcctx, krb5_principal principal)
 
1089
{
 
1090
    krb5_boolean (*func)(krb5_context, krb5_principal) = funcctx;
 
1091
    return (*func)(conxtext, principal);
 
1092
}
 
1093
 
 
1094
krb5_error_code KRB5_LIB_FUNCTION
 
1095
krb5_425_conv_principal_ext(krb5_context context,
 
1096
                            const char *name,
 
1097
                            const char *instance,
 
1098
                            const char *realm,
 
1099
                            krb5_boolean (*func)(krb5_context, krb5_principal),
 
1100
                            krb5_boolean resolve,
 
1101
                            krb5_principal *principal)
 
1102
{
 
1103
    return krb5_425_conv_principal_ext2(context,
 
1104
                                        name,
 
1105
                                        instance,
 
1106
                                        realm,
 
1107
                                        func ? convert_func : NULL,
 
1108
                                        func,
 
1109
                                        resolve,
 
1110
                                        principal);
 
1111
}
 
1112
 
 
1113
 
 
1114
 
 
1115
krb5_error_code KRB5_LIB_FUNCTION
 
1116
krb5_425_conv_principal(krb5_context context,
 
1117
                        const char *name,
 
1118
                        const char *instance,
 
1119
                        const char *realm,
 
1120
                        krb5_principal *princ)
 
1121
{
 
1122
    krb5_boolean resolve = krb5_config_get_bool(context,
 
1123
                                                NULL,
 
1124
                                                "libdefaults",
 
1125
                                                "v4_instance_resolve",
 
1126
                                                NULL);
 
1127
 
 
1128
    return krb5_425_conv_principal_ext(context, name, instance, realm,
 
1129
                                       NULL, resolve, princ);
 
1130
}
 
1131
 
 
1132
 
 
1133
static int
 
1134
check_list(const krb5_config_binding *l, const char *name, const char **out)
 
1135
{
 
1136
    while(l){
 
1137
        if (l->type != krb5_config_string)
 
1138
            continue;
 
1139
        if(strcmp(name, l->u.string) == 0) {
 
1140
            *out = l->name;
 
1141
            return 1;
 
1142
        }
 
1143
        l = l->next;
 
1144
    }
 
1145
    return 0;
 
1146
}
 
1147
 
 
1148
static int
 
1149
name_convert(krb5_context context, const char *name, const char *realm,
 
1150
             const char **out)
 
1151
{
 
1152
    const krb5_config_binding *l;
 
1153
    l = krb5_config_get_list (context,
 
1154
                              NULL,
 
1155
                              "realms",
 
1156
                              realm,
 
1157
                              "v4_name_convert",
 
1158
                              "host",
 
1159
                              NULL);
 
1160
    if(l && check_list(l, name, out))
 
1161
        return KRB5_NT_SRV_HST;
 
1162
    l = krb5_config_get_list (context,
 
1163
                              NULL,
 
1164
                              "libdefaults",
 
1165
                              "v4_name_convert",
 
1166
                              "host",
 
1167
                              NULL);
 
1168
    if(l && check_list(l, name, out))
 
1169
        return KRB5_NT_SRV_HST;
 
1170
    l = krb5_config_get_list (context,
 
1171
                              NULL,
 
1172
                              "realms",
 
1173
                              realm,
 
1174
                              "v4_name_convert",
 
1175
                              "plain",
 
1176
                              NULL);
 
1177
    if(l && check_list(l, name, out))
 
1178
        return KRB5_NT_UNKNOWN;
 
1179
    l = krb5_config_get_list (context,
 
1180
                              NULL,
 
1181
                              "libdefaults",
 
1182
                              "v4_name_convert",
 
1183
                              "host",
 
1184
                              NULL);
 
1185
    if(l && check_list(l, name, out))
 
1186
        return KRB5_NT_UNKNOWN;
 
1187
 
 
1188
    /* didn't find it in config file, try built-in list */
 
1189
    {
 
1190
        struct v4_name_convert *q;
 
1191
        for(q = default_v4_name_convert; q->from; q++) {
 
1192
            if(strcmp(name, q->to) == 0) {
 
1193
                *out = q->from;
 
1194
                return KRB5_NT_SRV_HST;
 
1195
            }
 
1196
        }
 
1197
    }
 
1198
    return -1;
 
1199
}
 
1200
 
 
1201
/*
 
1202
 * convert the v5 principal in `principal' into a v4 corresponding one
 
1203
 * in `name, instance, realm'
 
1204
 * this is limited interface since there's no length given for these
 
1205
 * three parameters.  They have to be 40 bytes each (ANAME_SZ).
 
1206
 */
 
1207
 
 
1208
krb5_error_code KRB5_LIB_FUNCTION
 
1209
krb5_524_conv_principal(krb5_context context,
 
1210
                        const krb5_principal principal,
 
1211
                        char *name,
 
1212
                        char *instance,
 
1213
                        char *realm)
 
1214
{
 
1215
    const char *n, *i, *r;
 
1216
    char tmpinst[40];
 
1217
    int type = princ_type(principal);
 
1218
    const int aname_sz = 40;
 
1219
 
 
1220
    r = principal->realm;
 
1221
 
 
1222
    switch(principal->name.name_string.len){
 
1223
    case 1:
 
1224
        n = principal->name.name_string.val[0];
 
1225
        i = "";
 
1226
        break;
 
1227
    case 2:
 
1228
        n = principal->name.name_string.val[0];
 
1229
        i = principal->name.name_string.val[1];
 
1230
        break;
 
1231
    default:
 
1232
        krb5_set_error_message(context, KRB5_PARSE_MALFORMED,
 
1233
                               N_("cannot convert a %d "
 
1234
                                  "component principal", ""),
 
1235
                               principal->name.name_string.len);
 
1236
        return KRB5_PARSE_MALFORMED;
 
1237
    }
 
1238
 
 
1239
    {
 
1240
        const char *tmp;
 
1241
        int t = name_convert(context, n, r, &tmp);
 
1242
        if(t >= 0) {
 
1243
            type = t;
 
1244
            n = tmp;
 
1245
        }
 
1246
    }
 
1247
 
 
1248
    if(type == KRB5_NT_SRV_HST){
 
1249
        char *p;
 
1250
 
 
1251
        strlcpy (tmpinst, i, sizeof(tmpinst));
 
1252
        p = strchr(tmpinst, '.');
 
1253
        if(p)
 
1254
            *p = 0;
 
1255
        i = tmpinst;
 
1256
    }
 
1257
 
 
1258
    if (strlcpy (name, n, aname_sz) >= aname_sz) {
 
1259
        krb5_set_error_message(context, KRB5_PARSE_MALFORMED,
 
1260
                               N_("too long name component to convert", ""));
 
1261
        return KRB5_PARSE_MALFORMED;
 
1262
    }
 
1263
    if (strlcpy (instance, i, aname_sz) >= aname_sz) {
 
1264
        krb5_set_error_message(context, KRB5_PARSE_MALFORMED,
 
1265
                               N_("too long instance component to convert", ""));
 
1266
        return KRB5_PARSE_MALFORMED;
 
1267
    }
 
1268
    if (strlcpy (realm, r, aname_sz) >= aname_sz) {
 
1269
        krb5_set_error_message(context, KRB5_PARSE_MALFORMED,
 
1270
                               N_("too long realm component to convert", ""));
 
1271
        return KRB5_PARSE_MALFORMED;
 
1272
    }
 
1273
    return 0;
 
1274
}
 
1275
 
 
1276
/**
 
1277
 * Create a principal for the service running on hostname. If
 
1278
 * KRB5_NT_SRV_HST is used, the hostname is canonization using DNS (or
 
1279
 * some other service), this is potentially insecure.
 
1280
 *
 
1281
 * @param context A Kerberos context.
 
1282
 * @param hostname hostname to use
 
1283
 * @param sname Service name to use
 
1284
 * @param type name type of pricipal, use KRB5_NT_SRV_HST or KRB5_NT_UNKNOWN.
 
1285
 * @param ret_princ return principal, free with krb5_free_principal().
 
1286
 *
 
1287
 * @return An krb5 error code, see krb5_get_error_message().
 
1288
 *
 
1289
 * @ingroup krb5_principal
 
1290
 */
 
1291
                        
 
1292
krb5_error_code KRB5_LIB_FUNCTION
 
1293
krb5_sname_to_principal (krb5_context context,
 
1294
                         const char *hostname,
 
1295
                         const char *sname,
 
1296
                         int32_t type,
 
1297
                         krb5_principal *ret_princ)
 
1298
{
 
1299
    krb5_error_code ret;
 
1300
    char localhost[MAXHOSTNAMELEN];
 
1301
    char **realms, *host = NULL;
 
1302
        
 
1303
    if(type != KRB5_NT_SRV_HST && type != KRB5_NT_UNKNOWN) {
 
1304
        krb5_set_error_message(context, KRB5_SNAME_UNSUPP_NAMETYPE,
 
1305
                               N_("unsupported name type %d", ""),
 
1306
                               (int)type);
 
1307
        return KRB5_SNAME_UNSUPP_NAMETYPE;
 
1308
    }
 
1309
    if(hostname == NULL) {
 
1310
        ret = gethostname(localhost, sizeof(localhost) - 1);
 
1311
        if (ret != 0) {
 
1312
            ret = errno;
 
1313
            krb5_set_error_message(context, ret,
 
1314
                                   N_("Failed to get local hostname", ""));
 
1315
            return ret;
 
1316
        }       
 
1317
        localhost[sizeof(localhost) - 1] = '\0';
 
1318
        hostname = localhost;
 
1319
    }
 
1320
    if(sname == NULL)
 
1321
        sname = "host";
 
1322
    if(type == KRB5_NT_SRV_HST) {
 
1323
        ret = krb5_expand_hostname_realms (context, hostname,
 
1324
                                           &host, &realms);
 
1325
        if (ret)
 
1326
            return ret;
 
1327
        strlwr(host);
 
1328
        hostname = host;
 
1329
    } else {
 
1330
        ret = krb5_get_host_realm(context, hostname, &realms);
 
1331
        if(ret)
 
1332
            return ret;
 
1333
    }
 
1334
 
 
1335
    ret = krb5_make_principal(context, ret_princ, realms[0], sname,
 
1336
                              hostname, NULL);
 
1337
    if(host)
 
1338
        free(host);
 
1339
    krb5_free_host_realm(context, realms);
 
1340
    return ret;
 
1341
}
 
1342
 
 
1343
static const struct {
 
1344
    const char *type;
 
1345
    int32_t value;
 
1346
} nametypes[] = {
 
1347
    { "UNKNOWN", KRB5_NT_UNKNOWN },
 
1348
    { "PRINCIPAL", KRB5_NT_PRINCIPAL },
 
1349
    { "SRV_INST", KRB5_NT_SRV_INST },
 
1350
    { "SRV_HST", KRB5_NT_SRV_HST },
 
1351
    { "SRV_XHST", KRB5_NT_SRV_XHST },
 
1352
    { "UID", KRB5_NT_UID },
 
1353
    { "X500_PRINCIPAL", KRB5_NT_X500_PRINCIPAL },
 
1354
    { "SMTP_NAME", KRB5_NT_SMTP_NAME },
 
1355
    { "ENTERPRISE_PRINCIPAL", KRB5_NT_ENTERPRISE_PRINCIPAL },
 
1356
    { "ENT_PRINCIPAL_AND_ID", KRB5_NT_ENT_PRINCIPAL_AND_ID },
 
1357
    { "MS_PRINCIPAL", KRB5_NT_MS_PRINCIPAL },
 
1358
    { "MS_PRINCIPAL_AND_ID", KRB5_NT_MS_PRINCIPAL_AND_ID },
 
1359
    { NULL }
 
1360
};
 
1361
 
 
1362
krb5_error_code
 
1363
krb5_parse_nametype(krb5_context context, const char *str, int32_t *nametype)
 
1364
{
 
1365
    size_t i;
 
1366
 
 
1367
    for(i = 0; nametypes[i].type; i++) {
 
1368
        if (strcasecmp(nametypes[i].type, str) == 0) {
 
1369
            *nametype = nametypes[i].value;
 
1370
            return 0;
 
1371
        }
 
1372
    }
 
1373
    krb5_set_error_message(context, KRB5_PARSE_MALFORMED,
 
1374
                           N_("Failed to find name type %s", ""), str);
 
1375
    return KRB5_PARSE_MALFORMED;
 
1376
}