| /* |
| * |
| * 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; |
| } |