Пример #1
0
void free_S3(S3 *s3)
{
	if(s3) {
		ne_buffer_destroy(s3->key_info.nb_name);
		ne_buffer_destroy(s3->key_info.nb_etag);
		ne_buffer_destroy(s3->key_info.nb_storage_class);
		ne_buffer_destroy(s3->key_info.nb_owner_id);
		ne_buffer_destroy(s3->key_info.nb_owner_display_name);
		memset(s3->access_id,0,64);
		memset(s3->secret_key,0,64);
		ne_sock_exit();
		free(s3);
	}
}
Пример #2
0
/* Read the contents of file FILENAME into *DATUM. */
static int read_to_datum(const char *filename, gnutls_datum *datum)
{
    FILE *f = fopen(filename, "r");
    ne_buffer *buf;
    char tmp[4192];
    size_t len;

    if (!f) {
        return -1;
    }

    buf = ne_buffer_ncreate(8192);
    while ((len = fread(tmp, 1, sizeof tmp, f)) > 0) {
        ne_buffer_append(buf, tmp, len);
    }

    if (!feof(f)) {
        fclose(f);
        ne_buffer_destroy(buf);
        return -1;
    }
    
    fclose(f);

    datum->size = ne_buffer_size(buf);
    datum->data = (unsigned char *)ne_buffer_finish(buf);
    return 0;
}
Пример #3
0
/* Discover all locks on URI */
int ne_lock_discover(ne_session *sess, const char *uri, 
		     ne_lock_result callback, void *userdata)
{
    ne_propfind_handler *handler;
    struct discover_ctx ctx = {0};
    int ret;
    
    ctx.results = callback;
    ctx.userdata = userdata;
    ctx.session = sess;
    ctx.cdata = ne_buffer_create();

    handler = ne_propfind_create(sess, uri, NE_DEPTH_ZERO,"PROPFIND");

    ne_propfind_set_private(handler, ld_create, &ctx);
    
    ne_xml_push_handler(ne_propfind_get_parser(handler), 
                        ld_startelm, ld_cdata, end_element_ldisc, handler);
    
    ret = ne_propfind_named(handler, lock_props, discover_results, &ctx);
    
    ne_buffer_destroy(ctx.cdata);
    ne_propfind_destroy(handler);

    return ret;
}
Пример #4
0
static object_query_t *set_object_raw(object_query_t *req) {
	int             resp_code;
	object_query_t *resp      = NULL;
	ne_buffer      *req_body  = NULL;
	ne_buffer      *resp_body = NULL;

	assert(NULL != req);

	/* Sanity check */
	assert(SET_OBJECT_REQUEST == req->type);
	assert(RAW_POST           == req->mode);

	/* Serialise request POST data */
	req_body = set_object_serialise_raw(req);

	/* Send request */
	resp_body = ne_buffer_create();

	assert(NULL != resp_body);

	resp_code = send_http_request(session,
		"POST", "/set_obj.htm", NULL, req_body, resp_body);

	/*
	 * Repeat in case of 401 - Unauthorised
	 *
	 * Note that this is a WA of NMC sending Connection: close
	 * header in the 401 response, in which case neon closes
	 * connection (quite rightfully).
	 */
	if (401 == resp_code)
		resp_code = send_http_request(session,
			"POST", "/set_obj.htm", NULL, req_body, resp_body);

	/* Deserialise response */
	if (200 == resp_code)
		resp = set_object_deserialise_raw(resp_body);

	/* Cleanup */
	if (NULL != req_body)
		ne_buffer_destroy(req_body);

	if (NULL != resp_body)
		ne_buffer_destroy(resp_body);

	return resp;
}
static int simple(void) {
    ne_buffer *s = ne_buffer_create();
    ON(s == NULL);
    ne_buffer_zappend(s, "abcde");
    ONCMP(s->data, "abcde");
    ON(ne_buffer_size(s) != 5);
    ne_buffer_destroy(s);
    return OK;
}
static int grow(void)
{
    ne_buffer *s = ne_buffer_ncreate(2);
    ON(s == NULL);
    ne_buffer_append(s, "a", 1);
    ne_buffer_grow(s, 4);
    ONCMP(s->data, "a");
    ne_buffer_destroy(s);
    return OK;
}
static int buf_concat(void)
{
    ne_buffer *s = ne_buffer_create();
    ON(s == NULL);
    ne_buffer_concat(s, "a", "b", "c", "d", "e", "f", "g", NULL);
    ONCMP(s->data, "abcdefg");
    ON(ne_buffer_size(s) != 7);
    ne_buffer_destroy(s);
    return OK;
}
Пример #8
0
int s3_get_bucket(S3 *s3,const char *bucket,
	const char *prefix,const char *marker,int max_keys,const char *delimiter,
	const S3KeyInfoCallback *key_info_cb)
{
	ne_request *req;
	int err, retry;
	ne_buffer *params;

	if(!s3) return -1;
	if(!bucket) return -1;

	params = ne_buffer_create();
	if(prefix) ne_buffer_concat(params,"prefix=",prefix,"/&",NULL);
	if(marker) ne_buffer_concat(params,"marker=",marker,"&",NULL);
	if(max_keys >= 0) {
		char mk[16];
		snprintf(mk,16,"%d",max_keys);
		mk[15] = 0;
		ne_buffer_concat(params,"max_keys=",max_keys,"&",NULL);
	}
	if(delimiter) ne_buffer_concat(params,"delimiter=",delimiter,"&",NULL);

	s3_begin_session(s3);

	req = s3_new_request(s3,"GET",bucket,NULL,params->data,NULL);

	ne_buffer_destroy(params);

	// send to server
	do {
		err = ne_begin_request(req);
		if(err != NE_OK) err = -EIO;
		else {
			if(ne_get_status(req)->code != 200) {
				s3_handle_error_response(s3,req);
				err = -EACCES;
			} else {
				s3->key_info.key_info_cb = key_info_cb;
				s3_parse_xml_response(s3,
					req,
					s3_xml_key_info_startelm,
					s3_xml_key_info_cdata,
					s3_xml_key_info_endelm,
					&s3->key_info
				);
			}
			retry = ne_end_request(req);
		}
	} while(retry == NE_RETRY);

	ne_request_destroy(req);
	s3_end_session(s3);

	return err;
}
static int buf_concat3(void)
{
    ne_buffer *s = ne_buffer_create();
    ON(s == NULL);
    ne_buffer_zappend(s, "foobar");
    ne_buffer_concat(s, "norman", NULL);
    ONCMP(s->data, "foobarnorman");
    ON(ne_buffer_size(s) != 12);
    ne_buffer_destroy(s);
    return OK;
}
Пример #10
0
static int buf_concat2(void)
{
#define RES "alphabetagammadeltaepsilonetatheta"
    ne_buffer *s = ne_buffer_create();
    ON(s == NULL);
    ne_buffer_concat(s, "alpha", "beta", "gamma", "delta", "epsilon", 
		     "eta", "theta", NULL);
    ONCMP(s->data, RES);
    ON(ne_buffer_size(s) != strlen(RES));
    ne_buffer_destroy(s);
    return OK;
}
Пример #11
0
static int buf_print(void)
{
    ne_buffer *buf = ne_buffer_create();

    ne_buffer_czappend(buf, "foo-");
    ne_buffer_snprintf(buf, 20, "bar-%s-asda", "norman");
    ne_buffer_czappend(buf, "-bloo");
    ONN("snprintf return value", ne_buffer_snprintf(buf, 2, "---") != 1);
    
    ONCMP(buf->data, "foo-bar-norman-asda-bloo-");

    ne_buffer_destroy(buf);
    
    return OK;
}
Пример #12
0
static int alter(void) {
    ne_buffer *s = ne_buffer_create();
    char *d;
    ON(s == NULL);
    ne_buffer_zappend(s, "abcdefg");
    d = s->data;
    ON(d == NULL);
    d[2] = '\0';
    ne_buffer_altered(s);
    ONCMP(s->data, "ab");
    ON(ne_buffer_size(s) != 2);
    ne_buffer_zappend(s, "hijkl");
    ONCMP(s->data, "abhijkl");
    ne_buffer_destroy(s);
    return OK;
}
Пример #13
0
static int append(void)
{
    ne_buffer *s = ne_buffer_create();
    ON(s == NULL);
    ne_buffer_append(s, "a", 1);
    ne_buffer_append(s, "b", 1);
    ne_buffer_append(s, "c", 1);
    ONCMP(s->data, "abc");
    ON(ne_buffer_size(s) != 3);
    ne_buffer_zappend(s, "hello");
    ONCMP(s->data, "abchello");
    ne_buffer_czappend(s, "world");
    ONCMP(s->data, "abchelloworld");
    ON(ne_buffer_size(s) != 13);
    ne_buffer_destroy(s);
    return OK;
}    
Пример #14
0
int ne_lock_refresh(ne_session *sess, struct ne_lock *lock)
{
    ne_request *req = ne_request_create(sess, "LOCK", lock->uri.path);
    ne_xml_parser *parser = ne_xml_create();
    int ret;
    struct lock_ctx ctx;

    memset(&ctx, 0, sizeof ctx);
    ctx.cdata = ne_buffer_create();
    ctx.req = req;
    ctx.token = lock->token;

    /* Handle the response and update *lock appropriately. */
    ne_xml_push_handler(parser, lk_startelm, lk_cdata, lk_endelm, &ctx);
    
    /* For a lock refresh, submitting only this lock token must be
     * sufficient. */
    ne_print_request_header(req, "If", "(<%s>)", lock->token);
    add_timeout_header(req, lock->timeout);

    ret = ne_xml_dispatch_request(req, parser);

    if (ret == NE_OK) {
        if (ne_get_status(req)->klass != 2) {
            ret = NE_ERROR; /* and use default session error */
        } else if (ne_xml_failed(parser)) {
	    ret = NE_ERROR;
	    ne_set_error(sess, "%s", ne_xml_get_error(parser));
	} else if (!ctx.found) {
            ne_set_error(sess, _("No activelock for <%s> returned in "
                                 "LOCK refresh response"), lock->token);
            ret = NE_ERROR;
        } else /* success! */ {
            /* update timeout for passed-in lock structure. */
            lock->timeout = ctx.active.timeout;
        }
    }

    ne_lock_free(&ctx.active);
    ne_buffer_destroy(ctx.cdata);
    ne_request_destroy(req);
    ne_xml_destroy(parser);

    return ret;
}
Пример #15
0
static object_query_t *set_object_form(object_query_t *req) {
	int       resp_code;
	ne_buffer *req_body = NULL;

	const char *ct = "multipart/form-data; boundary=" FORM_POST_BOUNDARY;

	/* TODO: Single request doesn't seem to work
	if (1 == object_query_size(req))
		ct = "application/x-form-urlencoded";
	*/

	assert(NULL != req);

	/* Sanity check */
	assert(SET_OBJECT_REQUEST == req->type);
	assert(FORM_POST          == req->mode);

	/* Serialise request POST data */
	req_body = set_object_serialise_form(req);

	/* Send request (response is ignored by the proto. spec v3) */
	resp_code = send_http_request(session,
		"POST", "/Forms/set_obj_2", ct, req_body, NULL);

	/*
	 * Repeat in case of 401 - Unauthorised
	 *
	 * Note that this is a WA of NMC sending Connection: close
	 * header in the 401 response, in which case neon closes
	 * connection (quite rightfully).
	 */
	if (401 == resp_code) {
		resp_code = send_http_request(session,
			"POST", "/Forms/set_obj_2", ct, req_body, NULL);
	}

	/* Cleanup */
	if (NULL != req_body)
		ne_buffer_destroy(req_body);

	return NULL;
}
Пример #16
0
static int qappend(void)
{
    static const struct {
        const char *in;
        size_t inlen;
        const char *out;
    } ts[] = {
        { "", 0, "" },
        { "a", 1, "a" },
        { "b", 2, "b\\x00" },
        { "alpha\0alpha", 11, "alpha\\x00alpha" },
        { "a\tb", 3, "a\\x09b" },
        { NULL }
    };
    unsigned n;

    for (n = 0; ts[n].in; n++) {
        ne_buffer *buf = ne_buffer_create();
        char *s;
        const unsigned char *in = (const unsigned char *)ts[n].in;

        ne_buffer_qappend(buf, in, ts[n].inlen);

        ONCMP(buf->data, ts[n].out);

        ONV(strlen(buf->data) + 1 != buf->used,
            ("bad buffer length for '%s': %" NE_FMT_SIZE_T, 
             ts[n].out, buf->used));
        
        s = ne_strnqdup(in, ts[n].inlen);
        
        ONCMP(s, ts[n].out);

        ne_free(s);
        ne_buffer_destroy(buf);
    }

    return OK;
}
Пример #17
0
int ne_acl_set(ne_session *sess, const char *uri,
               ne_acl_entry *entries, int numentries)
{
    int ret;
    ne_request *req = ne_request_create(sess, "ACL", uri);
    ne_buffer *body = acl_body(entries, numentries);

#ifdef NE_HAVE_DAV
    ne_lock_using_resource(req, uri, 0);
#endif

    ne_set_request_body_buffer(req, body->data, ne_buffer_size(body));
    ne_add_request_header(req, "Content-Type", NE_XML_MEDIA_TYPE);
    ret = ne_request_dispatch(req);

    ne_buffer_destroy(body);

    if (ret == NE_OK && ne_get_status(req)->code == 207) {
        ret = NE_ERROR;
    }

    ne_request_destroy(req);
    return ret;
}
Пример #18
0
static ne_request *s3_new_request(const S3 *s3,const char *method,const char *bucket,const char *key,const char *params,const char *content_type)
{
	ne_buffer *date, *signing_string, *request_str;
	ne_request *req;
	char *sig, *p;
	time_t t;

	if(!s3) return NULL;
	if(!method) return NULL;
	if(!bucket) return NULL;
	if(!s3->session) return NULL;

	// create some string buffers
	date = ne_buffer_create();
	signing_string = ne_buffer_create();
	request_str = ne_buffer_create();

	// get the time
	t = time(NULL);
	ne_buffer_zappend(date,asctime(gmtime(&t)));
	if(date->data[date->used - 2] == '\n')
		date->data[date->used - 2] = 0;
	ne_buffer_altered(date);

	// create request
	if(key) ne_buffer_concat(request_str,"/",bucket,"/",key,NULL);
	else ne_buffer_concat(request_str,"/",bucket,NULL);

	if(params && params[0] != 0) {
		ne_buffer_zappend(request_str,"?");
		ne_buffer_zappend(request_str,params);
	}

	req = ne_request_create(s3->session,method,request_str->data);

	// Add date header
	ne_add_request_header(req,"Date",date->data);

	// Add content-type header
	if(content_type) ne_add_request_header(req,"Content-Type",content_type);
	else content_type = "";

	// construct signing string
	p = strrchr(request_str->data,'?');
	if(p) {
		*p = 0;
		ne_buffer_altered(request_str);
	}
	ne_buffer_concat(signing_string,method,"\n\n",content_type,"\n",date->data,"\n",request_str->data,NULL);
	// sign the string
	sig = s3_sign_string(s3,signing_string->data);

	// construct signed header
	ne_print_request_header(req,"Authorization","AWS %s:%s",s3->access_id,sig);

	ne_buffer_destroy(date);
	ne_buffer_destroy(signing_string);
	ne_buffer_destroy(request_str);
	free(sig);

	return req;
}
Пример #19
0
int ne_lock(ne_session *sess, struct ne_lock *lock) 
{
    ne_request *req = ne_request_create(sess, "LOCK", lock->uri.path);
    ne_buffer *body = ne_buffer_create();
    ne_xml_parser *parser = ne_xml_create();
    int ret, parse_failed;
    struct lock_ctx ctx;

    memset(&ctx, 0, sizeof ctx);
    ctx.cdata = ne_buffer_create();    
    ctx.req = req;

    ne_xml_push_handler(parser, lk_startelm, lk_cdata, lk_endelm, &ctx);
    
    /* Create the body */
    ne_buffer_concat(body, "<?xml version=\"1.0\" encoding=\"utf-8\"?>" EOL
		    "<lockinfo xmlns='DAV:'>" EOL " <lockscope>",
		    lock->scope==ne_lockscope_exclusive?
		    "<exclusive/>":"<shared/>",
		    "</lockscope>" EOL
		    "<locktype><write/></locktype>", NULL);

    if (lock->owner) {
	ne_buffer_concat(body, "<owner>", lock->owner, "</owner>" EOL, NULL);
    }
    ne_buffer_zappend(body, "</lockinfo>" EOL);

    ne_set_request_body_buffer(req, body->data, ne_buffer_size(body));
    /* ne_add_request_header(req, "Content-Type", NE_XML_MEDIA_TYPE); */
    /* Just to test whether sever accepts both text/xml and application/xml */
    ne_add_request_header(req, "Content-Type", "text/xml");
    ne_add_depth_header(req, lock->depth);
    add_timeout_header(req, lock->timeout);
    
    /* TODO: 
     * By 2518, we need this only if we are creating a lock-null resource.
     * Since we don't KNOW whether the lock we're given is a lock-null
     * or not, we cover our bases.
     */
    ne_lock_using_parent(req, lock->uri.path);
    /* This one is clearer from 2518 sec 8.10.4. */
    ne_lock_using_resource(req, lock->uri.path, lock->depth);

    ret = ne_xml_dispatch_request(req, parser);

    ne_buffer_destroy(body);
    ne_buffer_destroy(ctx.cdata);
    parse_failed = ne_xml_failed(parser);
    
    if (ret == NE_OK && ne_get_status(req)->klass == 2) {
	if (ctx.token == NULL) {
	    ret = NE_ERROR;
	    ne_set_error(sess, _("No Lock-Token header given"));
	}
	else if (parse_failed) {
	    ret = NE_ERROR;
	    ne_set_error(sess, "%s", ne_xml_get_error(parser));
	}
	else if (ne_get_status(req)->code == 207) {
	    ret = NE_ERROR;
	    /* TODO: set the error string appropriately */
	}
	else if (ctx.found) {
	    /* it worked: copy over real lock details if given. */
            if (lock->token) ne_free(lock->token);
	    lock->token = ctx.token;
            ctx.token = NULL;
	    if (ctx.active.timeout != NE_TIMEOUT_INVALID)
		lock->timeout = ctx.active.timeout;
	    lock->scope = ctx.active.scope;
	    lock->type = ctx.active.type;
	    if (ctx.active.depth >= 0)
		lock->depth = ctx.active.depth;
	    if (ctx.active.owner) {
		if (lock->owner) ne_free(lock->owner);
		lock->owner = ctx.active.owner;
		ctx.active.owner = NULL;
	    }
	} else {
	    ret = NE_ERROR;
	    ne_set_error(sess, _("Response missing activelock for %s"), 
			 ctx.token);
	}
    } else if (ret == NE_OK /* && status != 2xx */) {
	ret = NE_ERROR;
    }

    ne_lock_free(&ctx.active);
    if (ctx.token) ne_free(ctx.token);
    ne_request_destroy(req);
    ne_xml_destroy(parser);

    return ret;
}
Пример #20
0
/* Continue a GSS-API Negotiate exchange, using input TOKEN if
 * non-NULL.  Returns non-zero on error. */
static int continue_negotiate(auth_session *sess, const char *token)
{
    unsigned int major, minor;
    gss_buffer_desc input = GSS_C_EMPTY_BUFFER;
    gss_buffer_desc output = GSS_C_EMPTY_BUFFER;
    unsigned char *bintoken = NULL;
    int ret;

    if (token) {
        input.length = ne_unbase64(token, &bintoken);
        if (input.length == 0) {
            NE_DEBUG(NE_DBG_HTTPAUTH, "gssapi: Invalid input [%s].\n",
                     token);
            return -1;
        }
        input.value = bintoken;
        NE_DEBUG(NE_DBG_HTTPAUTH, "gssapi: Continuation token [%s]\n", token);
    }
    else if (sess->gssctx != GSS_C_NO_CONTEXT) {
        NE_DEBUG(NE_DBG_HTTPAUTH, "gssapi: Reset incomplete context.\n");
        gss_delete_sec_context(&minor, &sess->gssctx, GSS_C_NO_BUFFER);
    }

    major = gss_init_sec_context(&minor, GSS_C_NO_CREDENTIAL, &sess->gssctx,
                                 sess->gssname, sess->gssmech, 
                                 GSS_C_MUTUAL_FLAG, GSS_C_INDEFINITE, 
                                 GSS_C_NO_CHANNEL_BINDINGS,
                                 &input, &sess->gssmech, &output, NULL, NULL);

    /* done with the input token. */
    if (bintoken) ne_free(bintoken);

    if (GSS_ERROR(major)) {
        ne_buffer *err = ne_buffer_create();
        int flag = 0;

        make_gss_error(err, &flag, major, GSS_C_GSS_CODE);
        make_gss_error(err, &flag, minor, GSS_C_MECH_CODE);
        NE_DEBUG(NE_DBG_HTTPAUTH, "gssapi: Error: %s\n", err->data);
        ne_set_error(sess->sess, _("GSSAPI authentication error (%s)"), 
                     err->data);
        ne_buffer_destroy(err);
        return -1;
    }

    if (major == GSS_S_CONTINUE_NEEDED || major == GSS_S_COMPLETE) {
        NE_DEBUG(NE_DBG_HTTPAUTH, "gssapi: init_sec_context OK. (major=%d)\n",
                 major);
        ret = 0;
    } 
    else {
        NE_DEBUG(NE_DBG_HTTPAUTH, "gssapi: Init failure %d.\n", major);
        ret = -1;
    }

    if (major != GSS_S_CONTINUE_NEEDED) {
        /* context no longer needed: destroy it */
        gss_delete_sec_context(&minor, &sess->gssctx, GSS_C_NO_BUFFER);
    }

    if (output.length) {
        sess->gssapi_token = ne_base64(output.value, output.length);
        NE_DEBUG(NE_DBG_HTTPAUTH, "gssapi: Output token: [%s]\n", 
                 sess->gssapi_token);
        gss_release_buffer(&minor, &output);
    } else {
        NE_DEBUG(NE_DBG_HTTPAUTH, "gssapi: No output token.\n");
    }

    return ret;
}
Пример #21
0
/* Check certificate identity.  Returns zero if identity matches; 1 if
 * identity does not match, or <0 if the certificate had no identity.
 * If 'identity' is non-NULL, store the malloc-allocated identity in
 * *identity.  Logic specified by RFC 2818 and RFC 3280. */
static int check_identity(const ne_uri *server, X509 *cert, char **identity)
{
    STACK_OF(GENERAL_NAME) *names;
    int match = 0, found = 0;
    const char *hostname;
    
    hostname = server ? server->host : "";

    names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
    if (names) {
	int n;

        /* subjectAltName contains a sequence of GeneralNames */
	for (n = 0; n < sk_GENERAL_NAME_num(names) && !match; n++) {
	    GENERAL_NAME *nm = sk_GENERAL_NAME_value(names, n);
	    
            /* handle dNSName and iPAddress name extensions only. */
	    if (nm->type == GEN_DNS) {
		char *name = dup_ia5string(nm->d.ia5);
                if (identity && !found) *identity = ne_strdup(name);
		match = ne__ssl_match_hostname(name, strlen(name), hostname);
		free(name);
		found = 1;
            } 
            else if (nm->type == GEN_IPADD) {
                /* compare IP address with server IP address. */
                ne_inet_addr *ia;
                if (nm->d.ip->length == 4)
                    ia = ne_iaddr_make(ne_iaddr_ipv4, nm->d.ip->data);
                else if (nm->d.ip->length == 16)
                    ia = ne_iaddr_make(ne_iaddr_ipv6, nm->d.ip->data);
                else
                    ia = NULL;
                /* ne_iaddr_make returns NULL if address type is unsupported */
                if (ia != NULL) { /* address type was supported. */
                    char buf[128];

                    match = strcmp(hostname, 
                                   ne_iaddr_print(ia, buf, sizeof buf)) == 0;
                    found = 1;
                    ne_iaddr_free(ia);
                } else {
                    NE_DEBUG(NE_DBG_SSL, "iPAddress name with unsupported "
                             "address type (length %d), skipped.\n",
                             nm->d.ip->length);
                }
            } 
            else if (nm->type == GEN_URI) {
                char *name = dup_ia5string(nm->d.ia5);
                ne_uri uri;

                if (ne_uri_parse(name, &uri) == 0 && uri.host && uri.scheme) {
                    ne_uri tmp;

                    if (identity && !found) *identity = ne_strdup(name);
                    found = 1;

                    if (server) {
                        /* For comparison purposes, all that matters is
                         * host, scheme and port; ignore the rest. */
                        memset(&tmp, 0, sizeof tmp);
                        tmp.host = uri.host;
                        tmp.scheme = uri.scheme;
                        tmp.port = uri.port;
                        
                        match = ne_uri_cmp(server, &tmp) == 0;
                    }
                }

                ne_uri_free(&uri);
                free(name);
            }
	}
        /* free the whole stack. */
        sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free);
    }
    
    /* Check against the commonName if no DNS alt. names were found,
     * as per RFC3280. */
    if (!found) {
	X509_NAME *subj = X509_get_subject_name(cert);
	X509_NAME_ENTRY *entry;
	ne_buffer *cname = ne_buffer_ncreate(30);
	int idx = -1, lastidx;

	/* find the most specific commonName attribute. */
	do {
	    lastidx = idx;
	    idx = X509_NAME_get_index_by_NID(subj, NID_commonName, lastidx);
	} while (idx >= 0);
	
	if (lastidx < 0) {
            /* no commonName attributes at all. */
            ne_buffer_destroy(cname);
	    return -1;
        }

	/* extract the string from the entry */
        entry = X509_NAME_get_entry(subj, lastidx);
        if (append_dirstring(cname, X509_NAME_ENTRY_get_data(entry))) {
            ne_buffer_destroy(cname);
            return -1;
        }
        if (identity) *identity = ne_strdup(cname->data);
        match = ne__ssl_match_hostname(cname->data, cname->used - 1, hostname);
        ne_buffer_destroy(cname);
    }

    NE_DEBUG(NE_DBG_SSL, "Identity match for '%s': %s\n", hostname, 
             match ? "good" : "bad");
    return match ? 0 : 1;
}