Files
heimdal/lib/krb5/principal.c
Johan Danielsson bb61967b67 Add krb5_make_principal.
git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@2815 ec53bebd-3082-4978-b11e-865c3cabbd6b
1997-08-08 22:02:50 +00:00

592 lines
13 KiB
C

/*
* Copyright (c) 1997 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Kungliga Tekniska
* Högskolan and its contributors.
*
* 4. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "krb5_locl.h"
RCSID("$Id$");
/* Public principal handling functions */
#define num_components(P) ((P)->name.name_string.len)
#define princ_type(P) ((P)->name.name_type)
void
krb5_free_principal(krb5_context context,
krb5_principal p)
{
if(p){
free_Principal(p);
free(p);
}
}
krb5_error_code
krb5_parse_name(krb5_context context,
const char *name,
krb5_principal *principal)
{
general_string *comp;
general_string realm;
int ncomp;
char *p;
char *q;
char *s;
char *start;
int n;
char c;
int got_realm = 0;
/* count number of component */
ncomp = 1;
for(p = (char*)name; *p; p++){
if(*p=='\\'){
if(!p[1])
return KRB5_PARSE_MALFORMED;
p++;
} else if(*p == '/')
ncomp++;
}
comp = calloc(ncomp, sizeof(*comp));
n = 0;
start = q = p = s = strdup(name);
while(*p){
c = *p++;
if(c == '\\'){
c = *p++;
if(c == 'n')
c = '\n';
else if(c == 't')
c = '\t';
else if(c == 'b')
c = '\b';
else if(c == '0')
c = '\0';
}else if(c == '/' || c == '@'){
if(got_realm){
exit:
while(n>0){
free(comp[--n]);
}
free(comp);
free(s);
return KRB5_PARSE_MALFORMED;
}else{
comp[n] = malloc(q - start + 1);
strncpy(comp[n], start, q - start);
comp[n][q - start] = 0;
n++;
}
if(c == '@')
got_realm = 1;
start = q;
continue;
}
if(got_realm && (c == ':' || c == '/' || c == '\0'))
goto exit;
*q++ = c;
}
if(got_realm){
realm = malloc(q - start + 1);
strncpy(realm, start, q - start);
realm[q - start] = 0;
}else{
krb5_get_default_realm (context, &realm);
comp[n] = malloc(q - start + 1);
strncpy(comp[n], start, q - start);
comp[n][q - start] = 0;
n++;
}
*principal = malloc(sizeof(**principal));
(*principal)->name.name_type = KRB5_NT_PRINCIPAL;
(*principal)->name.name_string.val = comp;
num_components(*principal) = n;
(*principal)->realm = realm;
free(s);
return 0;
}
static void quote_string(char *s, int len, char **out)
{
char *q;
char *p = *out;
int c=0;
len = strlen(s);
for(q = s; q < s + len; q++){
if(*q == '\n')
c = 'n';
else if(*q == '\t')
c = 't';
else if(*q == '\b')
c = 'b';
else if(*q == '\0')
c = '0';
else if(*q == '/')
c='/';
else if(*q == '@')
c = '@';
if(c){
*p++ = '\\';
*p++ = c;
c = 0;
}else
*p++ = *q;
}
*out = p;
}
krb5_error_code
krb5_unparse_name(krb5_context context,
krb5_principal principal,
char **name)
{
int size;
char *p;
char *s;
int i;
int ncomp = num_components(principal);
size = 2 * strlen(principal->realm) + 1;
for (i = 0; i < ncomp; i++)
size += 2 * strlen(principal->name.name_string.val[i]) + 1;
s = malloc(size);
p = s;
for(i = 0; i < ncomp; i++){
if(i) *p++ = '/';
quote_string(
principal->name.name_string.val[i], 0,
&p);
}
*p++ = '@';
quote_string(principal->realm, 0, &p);
*p = 0;
*name = s;
return 0;
}
krb5_error_code
krb5_unparse_name_ext(krb5_context context,
krb5_const_principal principal,
char **name,
size_t *size)
{
fprintf(stderr, "krb5_unparse_name_ext: not implemented\n");
abort();
}
krb5_realm*
krb5_princ_realm(krb5_context context,
krb5_principal principal)
{
return &principal->realm;
}
void
krb5_princ_set_realm(krb5_context context,
krb5_principal principal,
krb5_realm *realm)
{
principal->realm = *realm;
}
krb5_error_code
krb5_build_principal(krb5_context context,
krb5_principal *principal,
int rlen,
const char *realm,
...)
{
krb5_error_code ret;
va_list ap;
va_start(ap, realm);
ret = krb5_build_principal_va(context, principal, rlen, realm, ap);
va_end(ap);
return ret;
}
krb5_error_code
krb5_principal_set_component(krb5_context context, krb5_principal p,
int n, void *data, size_t len)
{
general_string *tmp = p->name.name_string.val;
if(num_components(p) <= n){
int s = n + 10;
tmp = realloc(tmp, s * sizeof(*tmp));
if(!tmp)
return ENOMEM;
memset(tmp + num_components(p), 0,
(s - num_components(p)) * sizeof(*tmp));
p->name.name_string.val = tmp;
num_components(p)= s;
}
if(p->name.name_string.val[n])
free(p->name.name_string.val[n]);
p->name.name_string.val[n] = malloc(len + 1);
strncpy(p->name.name_string.val[n], data, len);
p->name.name_string.val[n][len] = 0;
return 0;
}
static void
va_ext_princ(krb5_context context, krb5_principal p, va_list ap)
{
int n = 0;
while(1){
char *s;
int len;
len = va_arg(ap, int);
if(len == 0)
break;
s = va_arg(ap, char*);
krb5_principal_set_component(context, p, n, s, len);
n++;
}
num_components(p) = n;
}
static void
va_princ(krb5_context context, krb5_principal p, va_list ap)
{
int n = 0;
while(1){
char *s;
int len;
s = va_arg(ap, char*);
if(s == NULL)
break;
len = strlen(s);
krb5_principal_set_component(context, p, n, s, len);
n++;
}
num_components(p) = n;
}
static krb5_error_code
build_principal(krb5_context context,
krb5_principal *principal,
int rlen,
const char *realm,
void (*func)(krb5_context, krb5_principal, va_list),
va_list ap)
{
krb5_principal p;
int n;
p = calloc(1, sizeof(*p));
if (p == NULL)
return ENOMEM;
princ_type(p) = KRB5_NT_PRINCIPAL;
p->realm = strdup(realm);
if(p->realm == NULL){
free(p);
return ENOMEM;
}
(*func)(context, p, ap);
*principal = p;
return 0;
}
krb5_error_code
krb5_make_principal(krb5_context context,
krb5_principal *principal,
krb5_realm realm,
...)
{
krb5_error_code ret;
krb5_realm r = NULL;
va_list ap;
if(realm == NULL){
ret = krb5_get_default_realm(context, &r);
if(ret)
return ret;
realm = r;
}
va_start(ap, realm);
ret = krb5_build_principal_va(context, principal, strlen(realm), realm, ap);
va_end(ap);
if(r)
free(r);
return ret;
}
krb5_error_code
krb5_build_principal_va(krb5_context context,
krb5_principal *principal,
int rlen,
const char *realm,
va_list ap)
{
return build_principal(context, principal, rlen, realm, va_princ, ap);
}
/* Not part of MIT K5 API */
krb5_error_code
krb5_build_principal_va_ext(krb5_context context,
krb5_principal *principal,
int rlen,
const char *realm,
va_list ap)
{
return build_principal(context, principal, rlen, realm, va_ext_princ, ap);
}
krb5_error_code
krb5_build_principal_ext(krb5_context context,
krb5_principal *principal,
int rlen,
const char *realm,
...)
{
krb5_error_code ret;
va_list ap;
va_start(ap, realm);
ret = krb5_build_principal_va_ext(context, principal, rlen, realm, ap);
va_end(ap);
return ret;
}
krb5_error_code
krb5_copy_principal(krb5_context context,
krb5_const_principal inprinc,
krb5_principal *outprinc)
{
krb5_principal p;
int i;
p = calloc(1, sizeof(*p));
if (p == NULL)
return ENOMEM;
copy_PrincipalName(&inprinc->name, &p->name);
copy_Realm(&inprinc->realm, &p->realm);
*outprinc = p;
return 0;
}
krb5_boolean
krb5_principal_compare(krb5_context context,
krb5_const_principal princ1,
krb5_const_principal princ2)
{
int i;
if(!krb5_realm_compare(context, princ1, princ2))
return FALSE;
if(num_components(princ1) != num_components(princ2))
return FALSE;
for(i = 0; i < num_components(princ1); i++){
if(strcmp(princ1->name.name_string.val[i],
princ2->name.name_string.val[i]) != 0)
return FALSE;
}
return TRUE;
}
krb5_boolean
krb5_realm_compare(krb5_context context,
krb5_const_principal princ1,
krb5_const_principal princ2)
{
return strcmp(princ1->realm, princ2->realm) == 0;
}
krb5_error_code
krb5_425_conv_principal(krb5_context context,
const char *name,
const char *instance,
const char *realm,
krb5_principal *princ)
{
const char *p;
krb5_error_code ret;
char *domain = NULL;
p = krb5_config_get_string(context->cf,
"realms",
realm,
"v4_name_convert",
name,
NULL);
if(p)
name = p;
if(instance[0] == 0)
instance = NULL;
if(instance){
p = krb5_config_get_string(context->cf,
"realms",
realm,
"v4_instance_convert",
instance,
NULL);
if(p)
instance = p;
else{
p = krb5_config_get_string(context->cf,
"realms",
realm,
"default_domain",
NULL);
if(p){
asprintf(&domain, "%s.%s", instance, p);
instance = domain;
}
}
}
ret = krb5_build_principal(context, princ,
strlen(realm),
realm,
name,
instance,
0);
if(domain)
free(domain);
return ret;
}
krb5_error_code
krb5_524_conv_principal(krb5_context context,
const krb5_principal principal,
char *name,
char *instance,
char *realm)
{
char *n, *i, *r;
char tmpinst[40];
r = principal->realm;
switch(principal->name.name_string.len){
case 1:
n = principal->name.name_string.val[0];
i = "";
break;
case 2:
n = principal->name.name_string.val[0];
i = principal->name.name_string.val[1];
break;
default:
return KRB5_PARSE_MALFORMED;
}
if(strcmp(n, "host") == 0){
char *p;
n = "rcmd";
strncpy(tmpinst, i, sizeof(tmpinst));
tmpinst[sizeof(tmpinst) - 1] = 0;
p = strchr(tmpinst, '.');
if(p) *p = 0;
i = tmpinst;
}
if(strlen(r) >= 40)
return KRB5_PARSE_MALFORMED;
if(strlen(n) >= 40)
return KRB5_PARSE_MALFORMED;
if(strlen(i) >= 40)
return KRB5_PARSE_MALFORMED;
strcpy(realm, r);
strcpy(name, n);
strcpy(instance, i);
return 0;
}
krb5_error_code
krb5_sname_to_principal (krb5_context context,
const char *hostname,
const char *sname,
int32_t type,
krb5_principal *ret_princ)
{
krb5_error_code ret;
char **r;
ret = krb5_get_host_realm (context, hostname, &r);
if (ret)
return ret;
if (type == KRB5_NT_SRV_HST) {
struct hostent *hostent;
char *h;
hostent = gethostbyname (hostname);
if (hostent != NULL)
hostname = hostent->h_name;
h = strdup (hostname);
if (h == NULL) {
krb5_free_host_realm (context, r);
return ENOMEM;
}
strlwr (h);
ret = krb5_build_principal (context,
ret_princ,
strlen(r[0]),
r[0],
sname,
h,
NULL);
krb5_free_host_realm (context, r);
free (h);
return ret;
} else if (type == KRB5_NT_UNKNOWNN) {
ret = krb5_build_principal (context,
ret_princ,
strlen(r[0]),
r[0],
sname,
hostname,
NULL);
krb5_free_host_realm (context, r);
return ret;
} else {
krb5_free_host_realm (context, r);
return KRB5_SNAME_UNSUPP_NAMETYPE;
}
}