remove unimplemented functions
[heimdal.git] / lib / krb5 / principal.c
blob5cac5e4ddf50a36c0b996adcd31523a14fa8c13c
1 /*
2 * Copyright (c) 1997 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by Kungliga Tekniska
20 * Högskolan and its contributors.
22 * 4. Neither the name of the Institute nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
39 #include "krb5_locl.h"
41 RCSID("$Id$");
43 /* Public principal handling functions */
45 #define princ_num_comp(P) ((P)->name.name_string.len)
46 #define princ_type(P) ((P)->name.name_type)
47 #define princ_comp(P) ((P)->name.name_string.val)
48 #define princ_ncomp(P, N) ((P)->name.name_string.val[(N)])
49 #define princ_realm(P) ((P)->realm)
51 void
52 krb5_free_principal(krb5_context context,
53 krb5_principal p)
55 if(p){
56 free_Principal(p);
57 free(p);
61 krb5_error_code
62 krb5_parse_name(krb5_context context,
63 const char *name,
64 krb5_principal *principal)
67 general_string *comp;
68 general_string realm;
69 int ncomp;
71 char *p;
72 char *q;
73 char *s;
74 char *start;
76 int n;
77 char c;
78 int got_realm = 0;
80 /* count number of component */
81 ncomp = 1;
82 for(p = (char*)name; *p; p++){
83 if(*p=='\\'){
84 if(!p[1])
85 return KRB5_PARSE_MALFORMED;
86 p++;
87 } else if(*p == '/')
88 ncomp++;
90 comp = calloc(ncomp, sizeof(*comp));
92 n = 0;
93 start = q = p = s = strdup(name);
94 while(*p){
95 c = *p++;
96 if(c == '\\'){
97 c = *p++;
98 if(c == 'n')
99 c = '\n';
100 else if(c == 't')
101 c = '\t';
102 else if(c == 'b')
103 c = '\b';
104 else if(c == '0')
105 c = '\0';
106 }else if(c == '/' || c == '@'){
107 if(got_realm){
108 exit:
109 while(n>0){
110 free(comp[--n]);
112 free(comp);
113 free(s);
114 return KRB5_PARSE_MALFORMED;
115 }else{
116 comp[n] = malloc(q - start + 1);
117 strncpy(comp[n], start, q - start);
118 comp[n][q - start] = 0;
119 n++;
121 if(c == '@')
122 got_realm = 1;
123 start = q;
124 continue;
126 if(got_realm && (c == ':' || c == '/' || c == '\0'))
127 goto exit;
128 *q++ = c;
130 if(got_realm){
131 realm = malloc(q - start + 1);
132 strncpy(realm, start, q - start);
133 realm[q - start] = 0;
134 }else{
135 krb5_get_default_realm (context, &realm);
137 comp[n] = malloc(q - start + 1);
138 strncpy(comp[n], start, q - start);
139 comp[n][q - start] = 0;
140 n++;
142 *principal = malloc(sizeof(**principal));
143 (*principal)->name.name_type = KRB5_NT_PRINCIPAL;
144 (*principal)->name.name_string.val = comp;
145 princ_num_comp(*principal) = n;
146 (*principal)->realm = realm;
147 free(s);
148 return 0;
151 static size_t
152 quote_string(char *s, char **out)
154 size_t len;
155 char *p;
156 char *tmp;
157 char c = 0;
158 tmp = *out;
159 if(tmp)
160 len = strlen(tmp);
161 else
162 len = 0;
163 for(p = s; *p; p++){
164 if(*p == '\n')
165 c = 'n';
166 else if(*p == '\t')
167 c = 't';
168 else if(*p == '\b')
169 c = 'b';
170 else if(*p == '\0')
171 c = '0';
172 else if(*p == '/')
173 c='/';
174 else if(*p == '@')
175 c = '@';
176 if(c){
177 tmp = realloc(tmp, len + 2);
178 tmp[len] = '\\';
179 tmp[len + 1] = c;
180 len += 2;
181 c = 0;
182 }else{
183 tmp = realloc(tmp, len + 1);
184 tmp[len] = *p;
185 len++;
188 tmp = realloc(tmp, len + 1);
189 tmp[len] = 0;
190 *out = tmp;
191 return len;
195 krb5_error_code
196 krb5_unparse_name(krb5_context context,
197 krb5_principal principal,
198 char **name)
200 size_t len;
201 char *s;
202 int i;
203 int ncomp = princ_num_comp(principal);
204 s = NULL;
205 for (i = 0; i < ncomp; i++){
206 if(i){
207 s = realloc(s, len + 2);
208 s[len] = '/';
209 s[len + 1] = 0;
211 len = quote_string(princ_ncomp(principal, i), &s);
213 s = realloc(s, len + 2);
214 s[len] = '@';
215 s[len + 1] = 0;
216 len = quote_string(princ_realm(principal), &s);
217 *name = s;
218 return 0;
222 #if 0 /* not implemented */
224 krb5_error_code
225 krb5_unparse_name_ext(krb5_context context,
226 krb5_const_principal principal,
227 char **name,
228 size_t *size)
230 fprintf(stderr, "krb5_unparse_name_ext: not implemented\n");
231 abort();
234 #endif
236 krb5_realm*
237 krb5_princ_realm(krb5_context context,
238 krb5_principal principal)
240 return &princ_realm(principal);
244 void
245 krb5_princ_set_realm(krb5_context context,
246 krb5_principal principal,
247 krb5_realm *realm)
249 princ_realm(principal) = *realm;
253 krb5_error_code
254 krb5_build_principal(krb5_context context,
255 krb5_principal *principal,
256 int rlen,
257 krb5_const_realm realm,
258 ...)
260 krb5_error_code ret;
261 va_list ap;
262 va_start(ap, realm);
263 ret = krb5_build_principal_va(context, principal, rlen, realm, ap);
264 va_end(ap);
265 return ret;
268 static krb5_error_code
269 append_component(krb5_context context, krb5_principal p,
270 general_string comp,
271 size_t comp_len)
273 general_string *tmp;
274 size_t len = princ_num_comp(p);
275 tmp = realloc(princ_comp(p), (len + 1) * sizeof(*tmp));
276 if(tmp == NULL)
277 return ENOMEM;
278 princ_comp(p) = tmp;
279 princ_ncomp(p, len) = malloc(comp_len + 1);
280 memcpy (princ_ncomp(p, len), comp, comp_len);
281 princ_ncomp(p, len)[comp_len] = '\0';
282 princ_num_comp(p)++;
283 return 0;
286 static void
287 va_ext_princ(krb5_context context, krb5_principal p, va_list ap)
289 while(1){
290 char *s;
291 int len;
292 len = va_arg(ap, int);
293 if(len == 0)
294 break;
295 s = va_arg(ap, char*);
296 append_component(context, p, s, len);
300 static void
301 va_princ(krb5_context context, krb5_principal p, va_list ap)
303 while(1){
304 char *s;
305 s = va_arg(ap, char*);
306 if(s == NULL)
307 break;
308 append_component(context, p, s, strlen(s));
313 static krb5_error_code
314 build_principal(krb5_context context,
315 krb5_principal *principal,
316 int rlen,
317 krb5_const_realm realm,
318 void (*func)(krb5_context, krb5_principal, va_list),
319 va_list ap)
321 krb5_principal p;
323 p = calloc(1, sizeof(*p));
324 if (p == NULL)
325 return ENOMEM;
326 princ_type(p) = KRB5_NT_PRINCIPAL;
328 princ_realm(p) = strdup(realm);
329 if(p->realm == NULL){
330 free(p);
331 return ENOMEM;
334 (*func)(context, p, ap);
335 *principal = p;
336 return 0;
339 krb5_error_code
340 krb5_make_principal(krb5_context context,
341 krb5_principal *principal,
342 krb5_const_realm realm,
343 ...)
345 krb5_error_code ret;
346 krb5_realm r = NULL;
347 va_list ap;
348 if(realm == NULL){
349 ret = krb5_get_default_realm(context, &r);
350 if(ret)
351 return ret;
352 realm = r;
354 va_start(ap, realm);
355 ret = krb5_build_principal_va(context, principal, strlen(realm), realm, ap);
356 va_end(ap);
357 if(r)
358 free(r);
359 return ret;
362 krb5_error_code
363 krb5_build_principal_va(krb5_context context,
364 krb5_principal *principal,
365 int rlen,
366 krb5_const_realm realm,
367 va_list ap)
369 return build_principal(context, principal, rlen, realm, va_princ, ap);
372 krb5_error_code
373 krb5_build_principal_va_ext(krb5_context context,
374 krb5_principal *principal,
375 int rlen,
376 krb5_const_realm realm,
377 va_list ap)
379 return build_principal(context, principal, rlen, realm, va_ext_princ, ap);
383 krb5_error_code
384 krb5_build_principal_ext(krb5_context context,
385 krb5_principal *principal,
386 int rlen,
387 krb5_const_realm realm,
388 ...)
390 krb5_error_code ret;
391 va_list ap;
392 va_start(ap, realm);
393 ret = krb5_build_principal_va_ext(context, principal, rlen, realm, ap);
394 va_end(ap);
395 return ret;
399 krb5_error_code
400 krb5_copy_principal(krb5_context context,
401 krb5_const_principal inprinc,
402 krb5_principal *outprinc)
404 krb5_principal p = malloc(sizeof(*p));
405 if (p == NULL)
406 return ENOMEM;
407 copy_Principal(inprinc, p);
408 *outprinc = p;
409 return 0;
413 krb5_boolean
414 krb5_principal_compare_any_realm(krb5_context context,
415 krb5_const_principal princ1,
416 krb5_const_principal princ2)
418 int i;
419 if(princ_num_comp(princ1) != princ_num_comp(princ2))
420 return FALSE;
421 for(i = 0; i < princ_num_comp(princ1); i++){
422 if(strcmp(princ_ncomp(princ1, i), princ_ncomp(princ2, i)) != 0)
423 return FALSE;
425 return TRUE;
428 krb5_boolean
429 krb5_principal_compare(krb5_context context,
430 krb5_const_principal princ1,
431 krb5_const_principal princ2)
433 if(!krb5_realm_compare(context, princ1, princ2))
434 return FALSE;
435 return krb5_principal_compare_any_realm(context, princ1, princ2);
439 krb5_boolean
440 krb5_realm_compare(krb5_context context,
441 krb5_const_principal princ1,
442 krb5_const_principal princ2)
444 return strcmp(princ_realm(princ1), princ_realm(princ2)) == 0;
447 krb5_error_code
448 krb5_425_conv_principal_ext(krb5_context context,
449 const char *name,
450 const char *instance,
451 const char *realm,
452 krb5_boolean (*func)(krb5_context, krb5_principal),
453 krb5_boolean resolve,
454 krb5_principal *princ)
456 const char *p;
457 krb5_error_code ret;
458 krb5_principal pr;
459 char host[128];
461 /* do the following: if the name is found in the
462 `v4_name_convert:host' part, is is assumed to be a `host' type
463 principal, and the instance is looked up in the
464 `v4_instance_convert' part. if not found there the name is
465 (optionally) looked up as a hostname, and if that doesn't yield
466 anything, the `default_domain' is appended to the instance
469 if(instance == NULL)
470 goto no_host;
471 if(instance[0] == 0){
472 instance = NULL;
473 goto no_host;
475 p = krb5_config_get_string(context->cf, "realms", realm,
476 "v4_name_convert", "host", name, NULL);
477 if(p == NULL)
478 p = krb5_config_get_string(context->cf, "libdefaults",
479 "v4_name_convert", "host", name, NULL);
480 if(p == NULL)
481 goto no_host;
482 name = p;
483 p = krb5_config_get_string(context->cf, "realms", realm,
484 "v4_instance_convert", instance, NULL);
485 if(p){
486 instance = p;
487 ret = krb5_make_principal(context, &pr, realm, name, instance, NULL);
488 if(func == NULL || (*func)(context, pr)){
489 *princ = pr;
490 return 0;
492 krb5_free_principal(context, pr);
493 *princ = NULL;
494 return HEIM_ERR_V4_PRINC_NO_CONV;
496 if(resolve){
497 struct hostent *hp = gethostbyname(instance);
498 if(hp){
499 instance = hp->h_name;
500 ret = krb5_make_principal(context, &pr,
501 realm, name, instance, NULL);
502 if(func == NULL || (*func)(context, pr)){
503 *princ = pr;
504 return 0;
506 krb5_free_principal(context, pr);
510 char **domains, **d;
511 domains = krb5_config_get_strings(context->cf, "realms", realm,
512 "v4_domains", NULL);
513 for(d = domains; d && *d; d++){
514 snprintf(host, sizeof(host), "%s.%s", instance, *d);
515 ret = krb5_make_principal(context, &pr, realm, name, host, NULL);
516 if(func == NULL || (*func)(context, pr)){
517 *princ = pr;
518 krb5_config_free_strings(domains);
519 return 0;
521 krb5_free_principal(context, pr);
523 krb5_config_free_strings(domains);
527 p = krb5_config_get_string(context->cf, "realms", realm,
528 "default_domain", NULL);
529 if(p == NULL){
530 /* should this be an error or should it silently
531 succeed? */
532 return HEIM_ERR_V4_PRINC_NO_CONV;
535 snprintf(host, sizeof(host), "%s.%s", instance, p);
536 ret = krb5_make_principal(context, &pr, realm, name, host, NULL);
537 if(func == NULL || (*func)(context, pr)){
538 *princ = pr;
539 return 0;
541 krb5_free_principal(context, pr);
542 return HEIM_ERR_V4_PRINC_NO_CONV;
543 no_host:
544 p = krb5_config_get_string(context->cf,
545 "realms",
546 realm,
547 "v4_name_convert",
548 "plain",
549 name,
550 NULL);
551 if(p == NULL)
552 p = krb5_config_get_string(context->cf,
553 "libdefaults",
554 "v4_name_convert",
555 "plain",
556 name,
557 NULL);
558 if(p)
559 name = p;
561 ret = krb5_make_principal(context, &pr, realm, name, instance, NULL);
562 if(func == NULL || (*func)(context, pr)){
563 *princ = pr;
564 return 0;
566 krb5_free_principal(context, pr);
567 return HEIM_ERR_V4_PRINC_NO_CONV;
570 krb5_error_code
571 krb5_425_conv_principal(krb5_context context,
572 const char *name,
573 const char *instance,
574 const char *realm,
575 krb5_principal *princ)
577 krb5_boolean resolve = krb5_config_get_bool(context->cf,
578 "libdefaults",
579 "v4_instance_resolve",
580 NULL);
582 return krb5_425_conv_principal_ext(context, name, instance, realm,
583 NULL, resolve, princ);
587 static char*
588 name_convert(krb5_context context, const char *name, const char *realm,
589 const char *section)
591 const krb5_config_binding *l;
592 l = krb5_config_get_list (context->cf,
593 "realms",
594 realm,
595 "v4_name_convert",
596 section,
597 NULL);
598 if(l == NULL)
599 l = krb5_config_get_list (context->cf,
600 "libdefaults",
601 "v4_name_convert",
602 section,
603 NULL);
605 while(l){
606 if (l->type != krb5_config_string)
607 continue;
608 if(strcmp(name, l->u.string) == 0)
609 return l->name;
610 l = l->next;
612 return NULL;
615 krb5_error_code
616 krb5_524_conv_principal(krb5_context context,
617 const krb5_principal principal,
618 char *name,
619 char *instance,
620 char *realm)
622 char *n, *i, *r;
623 char tmpinst[40];
624 int type = princ_type(principal);
626 r = principal->realm;
628 switch(principal->name.name_string.len){
629 case 1:
630 n = principal->name.name_string.val[0];
631 i = "";
632 break;
633 case 2:
634 n = principal->name.name_string.val[0];
635 i = principal->name.name_string.val[1];
636 break;
637 default:
638 return KRB5_PARSE_MALFORMED;
642 char *tmp = name_convert(context, n, r, "host");
643 if(tmp){
644 type = KRB5_NT_SRV_HST;
645 n = tmp;
646 }else{
647 tmp = name_convert(context, n, r, "plain");
648 if(tmp){
649 type = KRB5_NT_UNKNOWN;
650 n = tmp;
655 if(type == KRB5_NT_SRV_HST){
656 char *p;
657 strncpy(tmpinst, i, sizeof(tmpinst));
658 tmpinst[sizeof(tmpinst) - 1] = 0;
659 p = strchr(tmpinst, '.');
660 if(p) *p = 0;
661 i = tmpinst;
664 if(strlen(r) >= 40)
665 return KRB5_PARSE_MALFORMED;
666 if(strlen(n) >= 40)
667 return KRB5_PARSE_MALFORMED;
668 if(strlen(i) >= 40)
669 return KRB5_PARSE_MALFORMED;
670 strcpy(realm, r);
671 strcpy(name, n);
672 strcpy(instance, i);
673 return 0;
678 krb5_error_code
679 krb5_sname_to_principal (krb5_context context,
680 const char *hostname,
681 const char *sname,
682 int32_t type,
683 krb5_principal *ret_princ)
685 krb5_error_code ret;
686 char localhost[128];
687 char **realms, *host = NULL;
689 if(type != KRB5_NT_SRV_HST && type != KRB5_NT_UNKNOWN)
690 return KRB5_SNAME_UNSUPP_NAMETYPE;
691 if(hostname == NULL){
692 gethostname(localhost, sizeof(localhost));
693 hostname = localhost;
695 if(sname == NULL)
696 sname = "host";
697 if(type == KRB5_NT_SRV_HST){
698 struct hostent *hp;
699 hp = gethostbyname(hostname);
700 if(hp != NULL)
701 hostname = hp->h_name;
703 if(type == KRB5_NT_SRV_HST){
704 host = strdup(hostname);
705 if(host == NULL){
706 return ENOMEM;
708 strlwr(host);
709 hostname = host;
711 ret = krb5_get_host_realm(context, hostname, &realms);
712 if(ret)
713 return ret;
714 ret = krb5_make_principal(context, ret_princ, realms[0], sname,
715 hostname, NULL);
716 if(host)
717 free(host);
718 krb5_free_host_realm(context, realms);
719 return ret;