blob: d1ee67ff32c55c78f818443dbc66f414cad4ec72 [file] [log] [blame]
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
#include "sasl-internal.h"
#include "engine/engine-internal.h"
static const char ANONYMOUS[] = "ANONYMOUS";
static const char EXTERNAL[] = "EXTERNAL";
static const char PLAIN[] = "PLAIN";
bool pni_init_server(pn_transport_t* transport)
{
return true;
}
bool pni_init_client(pn_transport_t* transport)
{
return true;
}
void pni_sasl_impl_free(pn_transport_t *transport)
{
free(transport->sasl->impl_context);
}
// Client handles ANONYMOUS or PLAIN mechanisms if offered
bool pni_process_mechanisms(pn_transport_t *transport, const char *mechs)
{
// Check whether offered EXTERNAL, PLAIN or ANONYMOUS
// Look for "EXTERNAL" in mechs
const char *found = strstr(mechs, EXTERNAL);
// Make sure that string is separated and terminated and allowed
if (found && (found==mechs || found[-1]==' ') && (found[8]==0 || found[8]==' ') &&
pni_included_mech(transport->sasl->included_mechanisms, pn_bytes(8, found))) {
transport->sasl->selected_mechanism = pn_strdup(EXTERNAL);
if (transport->sasl->username) {
size_t size = strlen(transport->sasl->username);
char *iresp = (char *) malloc(size);
if (!iresp) return false;
transport->sasl->impl_context = iresp;
memmove(iresp, transport->sasl->username, size);
transport->sasl->bytes_out.start = iresp;
transport->sasl->bytes_out.size = size;
} else {
static const char empty[] = "";
transport->sasl->bytes_out.start = empty;
transport->sasl->bytes_out.size = 0;
}
return true;
}
// Look for "PLAIN" in mechs
found = strstr(mechs, PLAIN);
// Make sure that string is separated and terminated, allowed
// and we have a username and password and connection is encrypted or we allow insecure
if (found && (found==mechs || found[-1]==' ') && (found[5]==0 || found[5]==' ') &&
pni_included_mech(transport->sasl->included_mechanisms, pn_bytes(5, found)) &&
(transport->sasl->external_ssf > 0 || transport->sasl->allow_insecure_mechs) &&
transport->sasl->username && transport->sasl->password) {
transport->sasl->selected_mechanism = pn_strdup(PLAIN);
size_t usize = strlen(transport->sasl->username);
size_t psize = strlen(transport->sasl->password);
size_t size = usize + psize + 2;
char *iresp = (char *) malloc(size);
if (!iresp) return false;
transport->sasl->impl_context = iresp;
iresp[0] = 0;
memmove(&iresp[1], transport->sasl->username, usize);
iresp[usize + 1] = 0;
memmove(&iresp[usize + 2], transport->sasl->password, psize);
transport->sasl->bytes_out.start = iresp;
transport->sasl->bytes_out.size = size;
// Zero out password and dealloc
free(memset(transport->sasl->password, 0, psize));
transport->sasl->password = NULL;
return true;
}
// Look for "ANONYMOUS" in mechs
found = strstr(mechs, ANONYMOUS);
// Make sure that string is separated and terminated and allowed
if (found && (found==mechs || found[-1]==' ') && (found[9]==0 || found[9]==' ') &&
pni_included_mech(transport->sasl->included_mechanisms, pn_bytes(9, found))) {
transport->sasl->selected_mechanism = pn_strdup(ANONYMOUS);
if (transport->sasl->username) {
size_t size = strlen(transport->sasl->username);
char *iresp = (char *) malloc(size);
if (!iresp) return false;
transport->sasl->impl_context = iresp;
memmove(iresp, transport->sasl->username, size);
transport->sasl->bytes_out.start = iresp;
transport->sasl->bytes_out.size = size;
} else {
static const char anon[] = "anonymous";
transport->sasl->bytes_out.start = anon;
transport->sasl->bytes_out.size = sizeof anon-1;
}
return true;
}
return false;
}
// Server will offer only ANONYMOUS and EXTERNAL if appropriate
int pni_sasl_impl_list_mechs(pn_transport_t *transport, char **mechlist)
{
// If we have an external authid then we can offer EXTERNAL
if (transport->sasl && transport->sasl->external_auth) {
*mechlist = pn_strdup("EXTERNAL ANONYMOUS");
return 2;
} else {
*mechlist = pn_strdup("ANONYMOUS");
return 1;
}
}
void pni_process_init(pn_transport_t *transport, const char *mechanism, const pn_bytes_t *recv)
{
// Check that mechanism is ANONYMOUS and it is allowed
if (strcmp(mechanism, ANONYMOUS)==0 &&
pni_included_mech(transport->sasl->included_mechanisms, pn_bytes(sizeof(ANONYMOUS)-1, ANONYMOUS))) {
transport->sasl->username = "anonymous";
transport->sasl->outcome = PN_SASL_OK;
transport->authenticated = true;
pni_sasl_set_desired_state(transport, SASL_POSTED_OUTCOME);
} else if (strcmp(mechanism, EXTERNAL)==0 &&
transport->sasl->external_auth &&
pni_included_mech(transport->sasl->included_mechanisms, pn_bytes(sizeof(EXTERNAL)-1, EXTERNAL))) {
transport->sasl->username = transport->sasl->external_auth;
transport->sasl->outcome = PN_SASL_OK;
transport->authenticated = true;
pni_sasl_set_desired_state(transport, SASL_POSTED_OUTCOME);
} else {
transport->sasl->outcome = PN_SASL_AUTH;
pni_sasl_set_desired_state(transport, SASL_POSTED_OUTCOME);
}
}
/* The default implementation neither sends nor receives challenges or responses */
void pni_process_challenge(pn_transport_t *transport, const pn_bytes_t *recv)
{
}
void pni_process_response(pn_transport_t *transport, const pn_bytes_t *recv)
{
}
bool pni_sasl_impl_can_encrypt(pn_transport_t *transport)
{
return false;
}
ssize_t pni_sasl_impl_max_encrypt_size(pn_transport_t *transport)
{
return 0;
}
ssize_t pni_sasl_impl_encode(pn_transport_t *transport, pn_bytes_t in, pn_bytes_t *out)
{
return 0;
}
ssize_t pni_sasl_impl_decode(pn_transport_t *transport, pn_bytes_t in, pn_bytes_t *out)
{
return 0;
}
bool pn_sasl_extended(void)
{
return false;
}