#include "gssapiP_generic.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <gssapi/gssapi_generic.h>
#include <errno.h>
#include <ctype.h>
OM_uint32
generic_gss_release_oid(OM_uint32 *minor_status, gss_OID *oid)
{
*minor_status = 0;
if (oid == NULL || *oid == GSS_C_NO_OID)
return(GSS_S_COMPLETE);
if ((*oid != GSS_C_NT_USER_NAME) &&
(*oid != GSS_C_NT_MACHINE_UID_NAME) &&
(*oid != GSS_C_NT_STRING_UID_NAME) &&
(*oid != GSS_C_NT_HOSTBASED_SERVICE) &&
(*oid != GSS_C_NT_ANONYMOUS) &&
(*oid != GSS_C_NT_EXPORT_NAME) &&
(*oid != GSS_C_NT_COMPOSITE_EXPORT) &&
(*oid != gss_nt_service_name)) {
free((*oid)->elements);
free(*oid);
}
*oid = GSS_C_NO_OID;
return(GSS_S_COMPLETE);
}
OM_uint32
generic_gss_copy_oid(OM_uint32 *minor_status,
const gss_OID_desc * const oid,
gss_OID *new_oid)
{
gss_OID p;
*minor_status = 0;
p = (gss_OID) malloc(sizeof(gss_OID_desc));
if (!p) {
*minor_status = ENOMEM;
return GSS_S_FAILURE;
}
p->length = oid->length;
p->elements = malloc(p->length);
if (!p->elements) {
free(p);
return GSS_S_FAILURE;
}
memcpy(p->elements, oid->elements, p->length);
*new_oid = p;
return(GSS_S_COMPLETE);
}
OM_uint32
generic_gss_create_empty_oid_set(OM_uint32 *minor_status, gss_OID_set *oid_set)
{
*minor_status = 0;
if (oid_set == NULL)
return GSS_S_CALL_INACCESSIBLE_WRITE;
if ((*oid_set = (gss_OID_set) gssalloc_malloc(sizeof(gss_OID_set_desc)))) {
memset(*oid_set, 0, sizeof(gss_OID_set_desc));
return(GSS_S_COMPLETE);
}
else {
*minor_status = ENOMEM;
return(GSS_S_FAILURE);
}
}
OM_uint32
generic_gss_add_oid_set_member(OM_uint32 *minor_status,
const gss_OID_desc * const member_oid,
gss_OID_set *oid_set)
{
gss_OID elist;
gss_OID lastel;
*minor_status = 0;
if (member_oid == NULL || member_oid->length == 0 ||
member_oid->elements == NULL)
return (GSS_S_CALL_INACCESSIBLE_READ);
if (oid_set == NULL)
return GSS_S_CALL_INACCESSIBLE_WRITE;
elist = (*oid_set)->elements;
if (((*oid_set)->elements = (gss_OID) gssalloc_malloc(((*oid_set)->count+1) *
sizeof(gss_OID_desc)))) {
if (elist)
memcpy((*oid_set)->elements,
elist,
((*oid_set)->count * sizeof(gss_OID_desc)));
lastel = &(*oid_set)->elements[(*oid_set)->count];
if ((lastel->elements =
(void *) gssalloc_malloc((size_t) member_oid->length))) {
memcpy(lastel->elements, member_oid->elements,
(size_t) member_oid->length);
lastel->length = member_oid->length;
(*oid_set)->count++;
if (elist)
gssalloc_free(elist);
*minor_status = 0;
return(GSS_S_COMPLETE);
}
else
gssalloc_free((*oid_set)->elements);
}
(*oid_set)->elements = elist;
*minor_status = ENOMEM;
return(GSS_S_FAILURE);
}
OM_uint32
generic_gss_test_oid_set_member(OM_uint32 *minor_status,
const gss_OID_desc * const member,
gss_OID_set set,
int * present)
{
OM_uint32 i;
int result;
*minor_status = 0;
if (member == NULL || set == NULL)
return (GSS_S_CALL_INACCESSIBLE_READ);
if (present == NULL)
return (GSS_S_CALL_INACCESSIBLE_WRITE);
result = 0;
for (i=0; i<set->count; i++) {
if ((set->elements[i].length == member->length) &&
!memcmp(set->elements[i].elements,
member->elements,
(size_t) member->length)) {
result = 1;
break;
}
}
*present = result;
return(GSS_S_COMPLETE);
}
OM_uint32
generic_gss_oid_to_str(OM_uint32 *minor_status,
const gss_OID_desc * const oid,
gss_buffer_t oid_str)
{
unsigned long number, n;
OM_uint32 i;
int first;
unsigned char *cp;
struct k5buf buf;
*minor_status = 0;
if (oid_str != GSS_C_NO_BUFFER) {
oid_str->length = 0;
oid_str->value = NULL;
}
if (oid == NULL || oid->length == 0 || oid->elements == NULL)
return (GSS_S_CALL_INACCESSIBLE_READ);
if (oid_str == GSS_C_NO_BUFFER)
return (GSS_S_CALL_INACCESSIBLE_WRITE);
cp = (unsigned char *) oid->elements;
number = (unsigned long) cp[0];
k5_buf_init_dynamic(&buf);
k5_buf_add(&buf, "{ ");
number = 0;
cp = (unsigned char *) oid->elements;
first = 1;
for (i = 0; i < oid->length; i++) {
number = (number << 7) | (cp[i] & 0x7f);
if ((cp[i] & 0x80) == 0) {
if (first) {
n = (number < 40) ? 0 : (number < 80) ? 1 : 2;
k5_buf_add_fmt(&buf, "%lu %lu ", n, number - (n * 40));
first = 0;
} else {
k5_buf_add_fmt(&buf, "%lu ", number);
}
number = 0;
}
}
k5_buf_add_len(&buf, "}\0", 2);
return k5buf_to_gss(minor_status, &buf, oid_str);
}
static size_t
arc_encoded_length(unsigned long arc)
{
size_t len = 1;
for (arc >>= 7; arc; arc >>= 7)
len++;
return len;
}
static void
arc_encode(unsigned long arc, unsigned char **bufp)
{
unsigned char *p;
p = *bufp = *bufp + arc_encoded_length(arc);
*--p = arc & 0x7f;
for (arc >>= 7; arc; arc >>= 7)
*--p = (arc & 0x7f) | 0x80;
}
static int
get_arc(const unsigned char **bufp, const unsigned char *end,
unsigned long *arc_out)
{
const unsigned char *p = *bufp;
unsigned long arc = 0, newval;
if (p == end || !isdigit(*p))
return 0;
for (; p < end && isdigit(*p); p++) {
newval = arc * 10 + (*p - '0');
if (newval < arc)
return 0;
arc = newval;
}
while (p < end && (isspace(*p) || *p == '.'))
p++;
*bufp = p;
*arc_out = arc;
return 1;
}
OM_uint32
generic_gss_str_to_oid(OM_uint32 *minor_status,
gss_buffer_t oid_str,
gss_OID *oid_out)
{
const unsigned char *p, *end, *arc3_start;
unsigned char *out;
unsigned long arc, arc1, arc2;
size_t nbytes;
int brace = 0;
gss_OID oid;
*minor_status = 0;
if (oid_out != NULL)
*oid_out = GSS_C_NO_OID;
if (GSS_EMPTY_BUFFER(oid_str))
return (GSS_S_CALL_INACCESSIBLE_READ);
if (oid_out == NULL)
return (GSS_S_CALL_INACCESSIBLE_WRITE);
brace = 0;
p = oid_str->value;
end = p + oid_str->length;
while (p < end && isspace(*p))
p++;
if (p < end && *p == '{') {
brace = 1;
p++;
}
while (p < end && isspace(*p))
p++;
if (!get_arc(&p, end, &arc1) || !get_arc(&p, end, &arc2))
return (GSS_S_FAILURE);
if (arc1 > 2 || (arc1 < 2 && arc2 > 39) || arc2 > ULONG_MAX - 80)
return (GSS_S_FAILURE);
arc3_start = p;
nbytes = arc_encoded_length(arc1 * 40 + arc2);
while (get_arc(&p, end, &arc))
nbytes += arc_encoded_length(arc);
if (brace && (p == end || *p != '}'))
return (GSS_S_FAILURE);
oid = malloc(sizeof(*oid));
if (oid == NULL)
return (GSS_S_FAILURE);
oid->elements = malloc(nbytes);
if (oid->elements == NULL) {
free(oid);
return (GSS_S_FAILURE);
}
oid->length = nbytes;
out = oid->elements;
arc_encode(arc1 * 40 + arc2, &out);
p = arc3_start;
while (get_arc(&p, end, &arc))
arc_encode(arc, &out);
assert(out - nbytes == oid->elements);
*oid_out = oid;
return(GSS_S_COMPLETE);
}
OM_uint32
generic_gss_oid_compose(OM_uint32 *minor_status,
const char *prefix,
size_t prefix_len,
int suffix,
gss_OID_desc *oid)
{
int osuffix, i;
size_t nbytes;
unsigned char *op;
if (oid == GSS_C_NO_OID) {
*minor_status = EINVAL;
return GSS_S_FAILURE;
}
if (oid->length < prefix_len) {
*minor_status = ERANGE;
return GSS_S_FAILURE;
}
memcpy(oid->elements, prefix, prefix_len);
nbytes = 0;
osuffix = suffix;
while (suffix) {
nbytes++;
suffix >>= 7;
}
suffix = osuffix;
if (oid->length < prefix_len + nbytes) {
*minor_status = ERANGE;
return GSS_S_FAILURE;
}
op = (unsigned char *) oid->elements + prefix_len + nbytes;
i = -1;
while (suffix) {
op[i] = (unsigned char)suffix & 0x7f;
if (i != -1)
op[i] |= 0x80;
i--;
suffix >>= 7;
}
oid->length = prefix_len + nbytes;
*minor_status = 0;
return GSS_S_COMPLETE;
}
OM_uint32
generic_gss_oid_decompose(OM_uint32 *minor_status,
const char *prefix,
size_t prefix_len,
gss_OID_desc *oid,
int *suffix)
{
size_t i, slen;
unsigned char *op;
if (oid->length < prefix_len ||
memcmp(oid->elements, prefix, prefix_len) != 0) {
return GSS_S_BAD_MECH;
}
op = (unsigned char *) oid->elements + prefix_len;
*suffix = 0;
slen = oid->length - prefix_len;
for (i = 0; i < slen; i++) {
*suffix = (*suffix << 7) | (op[i] & 0x7f);
if (i + 1 != slen && (op[i] & 0x80) == 0) {
*minor_status = EINVAL;
return GSS_S_FAILURE;
}
}
return GSS_S_COMPLETE;
}
OM_uint32
generic_gss_copy_oid_set(OM_uint32 *minor_status,
const gss_OID_set_desc * const oidset,
gss_OID_set *new_oidset)
{
gss_OID_set_desc *copy;
OM_uint32 minor = 0;
OM_uint32 major = GSS_S_COMPLETE;
OM_uint32 i;
if (minor_status != NULL)
*minor_status = 0;
if (new_oidset != NULL)
*new_oidset = GSS_C_NO_OID_SET;
if (oidset == GSS_C_NO_OID_SET)
return (GSS_S_CALL_INACCESSIBLE_READ);
if (new_oidset == NULL)
return (GSS_S_CALL_INACCESSIBLE_WRITE);
if ((copy = (gss_OID_set_desc *) gssalloc_calloc(1, sizeof (*copy))) == NULL) {
major = GSS_S_FAILURE;
goto done;
}
if ((copy->elements = (gss_OID_desc *)
gssalloc_calloc(oidset->count, sizeof (*copy->elements))) == NULL) {
major = GSS_S_FAILURE;
goto done;
}
copy->count = oidset->count;
for (i = 0; i < copy->count; i++) {
gss_OID_desc *out = ©->elements[i];
gss_OID_desc *in = &oidset->elements[i];
if ((out->elements = (void *) gssalloc_malloc(in->length)) == NULL) {
major = GSS_S_FAILURE;
goto done;
}
(void) memcpy(out->elements, in->elements, in->length);
out->length = in->length;
}
*new_oidset = copy;
done:
if (major != GSS_S_COMPLETE) {
(void) generic_gss_release_oid_set(&minor, ©);
}
return (major);
}