On Wed, Jun 14, 2006 at 01:49:40AM +0200, Karel Zak wrote:
>
> Hi guys,
Hi,
>
> here is a patch with negotiate-auth support based on GSSAPI. It's
> very useful feature for intranet web sites where is possible
> authenticate users by Kerberos. (This feature is already implemented
> in firefox and libcurl.)
>
> Karel
>
>
>
[snip]
> +http_negotiate_get(struct uri *uri, int *isnew, int alloc)
> +{
> + struct negotiate *neg;
> +
> + foreach (neg, negotiate_list) {
> + if (compare_uri(neg->uri, uri, URI_HTTP_REFERRER_HOST))
> + return neg;
> + }
> + if (!alloc)
> + return NULL;
> + if (isnew)
> + *isnew = 1;
> +
> + if (!(neg = mem_calloc(1, sizeof(*neg))))
> + return NULL;
> +
> + memset(neg, 0, sizeof(*neg));
> + neg->uri = get_uri_reference(uri);
> +
this should be rewritten (see doc/hacking.txt)
neg = mem_calloc(1, sizeof(*neg));
if (!neg)
return NULL;
neg->uri = get_uri_reference(uri);
Since mem_calloc() is used, memset() is superfluous.
> + return neg;
> +}
> +
> +static void
> +http_negotiate_save(struct negotiate *neg)
> +{
> + add_to_list(negotiate_list, neg);
> +}
> +
> +static void
> +http_negotiate_cleanup(struct negotiate *neg, int full)
> +{
> + OM_uint32 minor_status;
> +
> + if (neg->context != GSS_C_NO_CONTEXT)
> + gss_delete_sec_context(&minor_status, &neg->context,
> GSS_C_NO_BUFFER);
> +
> + if (neg->output_token.length != 0)
> + gss_release_buffer(&minor_status, &neg->output_token);
> +
> + if (full && neg->server_name)
> + gss_release_name(&minor_status, &neg->server_name);
> +
> + if (full && neg->input_token.length != 0) {
> + /* allocated by mem_free().. so beter not use
> gss_release_buffer() */
> + mem_free(neg->input_token.value);
> + neg->input_token.length = 0;
> + }
> +
> + if (full)
> + memset(neg, 0, sizeof(*neg));
> +}
What about:
if (full) {
if (neg->server_name)
gss_release_name(&minor_status, &neg->server_name);
if (neg->input_token.length != 0) {
/* allocated by mem_free().. so beter not use
gss_release_buffer() */
mem_free(neg->input_token.value);
neg->input_token.length = 0;
}
memset(neg, 0, sizeof(*neg));
}
I perhaps missed smt though.
> +
> +static int
> +http_negotiate_get_name(struct connection *conn, struct negotiate *neg)
> +{
> + OM_uint32 major_status, minor_status;
> + gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
> + char name[2048];
> + const char* service;
> + struct uri *uri = conn->proxied_uri;
> +
> + /* GSSAPI implementation by Globus (known as GSI) requires the name to
> be
> + of form "<service>/<fqdn>" instead of <service>@<fqdn> (ie. slash
> instead
> + of at-sign). Also GSI servers are often identified as 'host' not
> 'khttp'.
> + Change following lines if you want to use GSI */
> +
> + /* IIS uses the <service>@<fqdn> form but uses 'http' as the service
> name */
> +
> + if (neg->type == PROTOCOL_HTTP_GSSNEG)
> + service = "KHTTP";
> + else
> + service = "HTTP";
> +
> + token.length = strlen(service) + 1 + uri->hostlen + 1;
> + if (token.length + 1 > sizeof(name))
> + return -1;
> +
> + snprintf(name, token.length, "[EMAIL PROTECTED]", service,
> uri->hostlen, uri->host);
> +
> + token.value = (void *) name;
> + major_status = gss_import_name(&minor_status,
> + &token,
> + GSS_C_NT_HOSTBASED_SERVICE,
> + &neg->server_name);
> +
> + return GSS_ERROR(major_status) ? -1 : 0;
> +}
> +
> +#define GSSNEG_LEN sizeof("GSS-Negotiate")
> +#define NEG_LEN sizeof("Negotiate")
> +
> +static int
> +http_negotiate_parse_data(unsigned char *data, int type,
> + gss_buffer_desc *token)
> +{
> + int len = 0;
> + unsigned char *end;
> +
> + if (data==NULL || *data=='\0')
> + return 0;
> +
> + data += type==PROTOCOL_HTTP_GSSNEG ? GSSNEG_LEN : NEG_LEN;
> +
> + while(*data && isspace((int)*data))
> + data++;
> +
> + if (*data=='\0' || *data==ASCII_CR || *data==ASCII_LF)
> + return 0; /* no data */
> +
> + end = data;
> + while (isalnum((int) *end) || *end=='=')
> + end++;
Please add spaces around == operator.
> +
> + /* Ignore line if we encountered an unexpected char. */
> + if (*end != ASCII_CR && *end != ASCII_LF)
> + return 0;
> +
> + len = end - data;
> +
> + if (!len)
> + return 0;
> +
> + token->value = (void *) base64_decode_bin(data, len, &token->length);
> +
> + if (!token->value)
> + return -1;
> +
> + return 0;
> +}
> +
> +static int
> +http_negotiate_create_context(struct negotiate *neg)
> +{
> + OM_uint32 major_status, minor_status;
> +
> + major_status = gss_init_sec_context(&minor_status,
> + GSS_C_NO_CREDENTIAL,
> + &neg->context,
> + neg->server_name,
> + GSS_C_NO_OID,
> + GSS_C_DELEG_FLAG,
> + 0,
> + GSS_C_NO_CHANNEL_BINDINGS,
> + &neg->input_token,
> + NULL,
> + &neg->output_token,
> + NULL,
> + NULL);
> + neg->status = major_status;
> +
> + if (GSS_ERROR(major_status))
> + return -1;
> + if (neg->output_token.length == 0)
> + return -1;
> +
> + return 0;
> +}
> +
> +/*
> + * Register new negotiate-auth request
> + *
> + * It's possible that server sends to client input token (at least
> + * libcurl supports it) in WWW-Authenticate header, but ususaly
> + * is this input token undefined.
> + */
> +int
> +http_negotiate_input(struct connection *conn, struct uri *uri,
> + int type, unsigned char *data)
> +{
> + struct negotiate *neg;
> + int ret = 0, isnew = 0;
> +
> + neg = http_negotiate_get(uri, &isnew, 1);
> +
> + if (neg->context) {
> + if (type != PROTOCOL_HTTP_GSSNEG)
> + return -1;
> + }
> + neg->type = type;
> +
> + if (neg->context && neg->status == GSS_S_COMPLETE) {
> + /* We finished succesfully our part of authentication, but
> server
> + * rejected it (since we're again here). Exit with an error
> since we
> + * can't invent anything better */
> + http_negotiate_cleanup(neg, 1);
> + return -1;
> + }
> + if (neg->server_name == NULL && http_negotiate_get_name(conn, neg) < 0)
> + return -1;
> + if (data && http_negotiate_parse_data(data, type, &neg->input_token))
> + return -1;
> + if ((ret=http_negotiate_create_context(neg)) == 0 && isnew)
> + http_negotiate_save(neg);
Please write:
ret = http_negotiate_create_context(neg);
if (ret == 0 && isnew)
http_negotiate_save(neg);
> +
> + return ret;
> +}
> +
> +/*
> + * Fill output token to "Authorization: Negotiate <token>".
> + */
> +int
> +http_negotiate_output(struct uri *uri, struct string *header)
> +{
> + struct negotiate *neg;
> + char *encoded = NULL;
> + int len = 0;
> +
> + if (!(neg = http_negotiate_get(uri, NULL, 0)))
> + return -1;
Same as above.
> +
> + if (neg->output_token.length==0) {
' == '
> + if (http_negotiate_create_context(neg) < 0) {
> + /* full cleanup on error and ask for
> + new WWW-Authenticate from server */
> + http_negotiate_cleanup(neg, 1);
> + return -1;
> + }
> + }
> +
> + encoded = base64_encode_bin((unsigned char *) neg->output_token.value,
> + neg->output_token.length, &len);
> +
> + if (encoded==NULL || len==0)
> + return -1;
' == '
> +
> + add_to_string(header, "Authorization: ");
> + add_to_string(header, neg->type==PROTOCOL_HTTP_GSSNEG ?
> + "GSS-Negotiate " : "Negotiate ");
> + add_to_string(header, encoded);
> + add_crlf_to_string(header);
> +
> + http_negotiate_cleanup(neg, 0);
> +
> + mem_free(encoded);
> +
> + return 0;
> +}
> +
> diff --git a/src/protocol/http/http_negotiate.h
> b/src/protocol/http/http_negotiate.h
> new file mode 100644
> index 0000000..cfd240f
> --- /dev/null
> +++ b/src/protocol/http/http_negotiate.h
> @@ -0,0 +1,16 @@
> +
> +#ifndef EL__PROTOCOL_HTTP_HTTP_NEGOTIATE_H
> +#define EL__PROTOCOL_HTTP_HTTP_NEGOTIATE_H
> +
> +#define PROTOCOL_HTTP_GSSNEG 1
> +#define PROTOCOL_HTTP_NEG 2
> +
> +
> +int http_negotiate_input(struct connection *conn, struct uri *uri,
> + int type, unsigned char *data);
> +
> +int http_negotiate_output(struct uri *uri, struct string *header);
> +
> +
> +#endif /* EL_PROTOCOL_HTTP_HTTP_NEGOTIATE_H */
> +
> diff --git a/src/util/base64.c b/src/util/base64.c
> index 8a3918e..7f4e74e 100644
> --- a/src/util/base64.c
> +++ b/src/util/base64.c
> @@ -17,14 +17,21 @@ static unsigned char base64_chars[] = "A
> unsigned char *
> base64_encode(register unsigned char *in)
> {
> + assert(in && *in);
> + if_assert_failed return NULL;
> +
> + return base64_encode_bin((char *) in, strlen(in), NULL);
Why this type casting ?
> +}
> +
> +unsigned char *
> +base64_encode_bin(register unsigned char *in, int inlen, int *outlen)
> +{
> unsigned char *out;
> unsigned char *outstr;
> - int inlen;
>
> assert(in && *in);
> if_assert_failed return NULL;
>
> - inlen = strlen(in);
> out = outstr = mem_alloc((inlen / 3) * 4 + 4 + 1);
> if (!out) return NULL;
>
> @@ -49,16 +56,29 @@ base64_encode(register unsigned char *in
> }
> *out = 0;
>
> + if (outlen)
> + *outlen = out-outstr;
> +
> return outstr;
> }
>
> -/* Base64 decoding is used only with the CONFIG_FORMHIST feature, so i'll
> #ifdef it */
> -#ifdef CONFIG_FORMHIST
> +/* Base64 decoding is used only with the CONFIG_FORMHIST or CONFIG_GSSAPI
> + feature, so i'll #ifdef it */
> +#if defined(CONFIG_FORMHIST) || defined(CONFIG_GSSAPI)
> +
> +unsigned char *
> +base64_decode(register unsigned char *in)
> +{
> + assert(in && *in);
> + if_assert_failed return NULL;
> +
> + return base64_decode_bin(in, strlen(in), NULL);
> +}
>
> /* base64_decode: @in string to decode
> * returns the string decoded (must be freed by the caller) */
> unsigned char *
> -base64_decode(register unsigned char *in)
> +base64_decode_bin(register unsigned char *in, int inlen, int *outlen)
> {
> static unsigned char is_base64_char[256]; /* static to force
> initialization at zero */
> static unsigned char decode[256];
> @@ -71,7 +91,7 @@ base64_decode(register unsigned char *in
> assert(in && *in);
> if_assert_failed return NULL;
>
> - outstr = out = mem_alloc(strlen(in) / 4 * 3 + 1);
> + outstr = out = mem_alloc(inlen / 4 * 3 + 1);
> if (!outstr) return NULL;
>
> if (!once) {
> @@ -123,6 +143,10 @@ base64_decode(register unsigned char *in
> }
>
> *out = 0;
> +
> + if (outlen)
> + *outlen = out-outstr;
> +
> return outstr;
>
> decode_error:
> diff --git a/src/util/base64.h b/src/util/base64.h
> index cb5cd73..2bdf0e4 100644
> --- a/src/util/base64.h
> +++ b/src/util/base64.h
> @@ -4,4 +4,7 @@ #define EL__UTIL_BASE64_H
> unsigned char *base64_encode(unsigned char *);
> unsigned char *base64_decode(unsigned char *);
>
> +unsigned char *base64_encode_bin(unsigned char *, int, int *);
> +unsigned char *base64_decode_bin(unsigned char *, int, int *);
> +
> #endif
> _______________________________________________
> elinks-dev mailing list
> [email protected]
> http://linuxfromscratch.org/mailman/listinfo/elinks-dev
>
This patch looks great, apart from the ELinks style conformity POV ;)
Have a serious look at doc/hacking.txt, fix the patch accordingly, and
resubmit it.
Regards,
--
Zas
_______________________________________________
elinks-dev mailing list
[email protected]
http://linuxfromscratch.org/mailman/listinfo/elinks-dev