1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-23 17:34:34 +03:00
samba-mirror/libcli/http/gensec/generic.c
Matthew DeVore 232054c09b lib/util: remove extra safe_string.h file
lib/util/safe_string.h is similar to source3/include/safe_string.h, but
the former has fewer checks. It is missing bcopy, strcasecmp, and
strncasecmp.

Add the missing elements to lib/util/safe_string.h remove the other
safe_string.h which is in the source3-specific path. To accomodate
existing uses of str(n?)casecmp, add #undef lines to source files where
they are used.

Signed-off-by: Matthew DeVore <matvore@google.com>
Reviewed-by: David Mulder <dmulder@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>

Autobuild-User(master): Jeremy Allison <jra@samba.org>
Autobuild-Date(master): Fri Aug 28 02:18:40 UTC 2020 on sn-devel-184
2020-08-28 02:18:40 +00:00

287 lines
7.7 KiB
C

/*
Unix SMB/CIFS implementation.
HTTP library - NTLM authentication mechanism gensec module
Copyright (C) 2014 Samuel Cabrero <samuelcabrero@kernevil.me>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include <tevent.h>
#include "lib/util/tevent_ntstatus.h"
#include "auth/auth.h"
#include "auth/gensec/gensec.h"
#include "auth/gensec/gensec_internal.h"
#include "lib/util/base64.h"
#undef strncasecmp
_PUBLIC_ NTSTATUS gensec_http_generic_init(TALLOC_CTX *);
struct gensec_http_generic_state {
struct gensec_security *sub;
DATA_BLOB prefix;
};
static NTSTATUS gensec_http_generic_client_start(struct gensec_security *gensec,
const char *prefix_str,
const char *mech_oid)
{
NTSTATUS status;
struct gensec_http_generic_state *state;
state = talloc_zero(gensec, struct gensec_http_generic_state);
if (state == NULL) {
return NT_STATUS_NO_MEMORY;
}
gensec->private_data = state;
state->prefix = data_blob_string_const(prefix_str);
status = gensec_subcontext_start(state, gensec, &state->sub);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
return gensec_start_mech_by_oid(state->sub, mech_oid);
}
static NTSTATUS gensec_http_ntlm_client_start(struct gensec_security *gensec)
{
return gensec_http_generic_client_start(gensec, "NTLM",
GENSEC_OID_NTLMSSP);
}
static NTSTATUS gensec_http_negotiate_client_start(struct gensec_security *gensec)
{
return gensec_http_generic_client_start(gensec, "Negotiate",
GENSEC_OID_SPNEGO);
}
struct gensec_http_generic_update_state {
struct gensec_security *gensec;
DATA_BLOB sub_in;
NTSTATUS status;
DATA_BLOB out;
};
static void gensec_http_generic_update_done(struct tevent_req *subreq);
static struct tevent_req *gensec_http_generic_update_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct gensec_security *gensec_ctx,
const DATA_BLOB in)
{
struct gensec_http_generic_state *http_generic =
talloc_get_type_abort(gensec_ctx->private_data,
struct gensec_http_generic_state);
struct tevent_req *req = NULL;
struct gensec_http_generic_update_state *state = NULL;
struct tevent_req *subreq = NULL;
req = tevent_req_create(mem_ctx, &state,
struct gensec_http_generic_update_state);
if (req == NULL) {
return NULL;
}
state->gensec = gensec_ctx;
if (in.length) {
int cmp;
DATA_BLOB b64b;
size_t skip = 0;
if (in.length < http_generic->prefix.length) {
tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
return tevent_req_post(req, ev);
}
cmp = strncasecmp((const char *)in.data,
(const char *)http_generic->prefix.data,
http_generic->prefix.length);
if (cmp != 0) {
tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
return tevent_req_post(req, ev);
}
if (in.length == http_generic->prefix.length) {
/*
* We expect more data, but the
* server just sent the prefix without
* a space prefixing base64 data.
*
* It means the server rejects
* the request with.
*/
tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
return tevent_req_post(req, ev);
}
if (in.data[http_generic->prefix.length] != ' ') {
tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
return tevent_req_post(req, ev);
}
skip = http_generic->prefix.length + 1;
b64b = data_blob_const(in.data + skip, in.length - skip);
if (b64b.length != 0) {
char *b64 = NULL;
/*
* ensure it's terminated with \0' before
* passing to base64_decode_data_blob_talloc().
*/
b64 = talloc_strndup(state, (const char *)b64b.data,
b64b.length);
if (tevent_req_nomem(b64, req)) {
return tevent_req_post(req, ev);
}
state->sub_in = base64_decode_data_blob_talloc(state,
b64);
TALLOC_FREE(b64);
if (tevent_req_nomem(state->sub_in.data, req)) {
return tevent_req_post(req, ev);
}
}
}
subreq = gensec_update_send(state, ev,
http_generic->sub,
state->sub_in);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
tevent_req_set_callback(subreq, gensec_http_generic_update_done, req);
return req;
}
static void gensec_http_generic_update_done(struct tevent_req *subreq)
{
struct tevent_req *req =
tevent_req_callback_data(subreq,
struct tevent_req);
struct gensec_http_generic_update_state *state =
tevent_req_data(req,
struct gensec_http_generic_update_state);
struct gensec_http_generic_state *http_generic =
talloc_get_type_abort(state->gensec->private_data,
struct gensec_http_generic_state);
NTSTATUS status;
DATA_BLOB sub_out = data_blob_null;
char *b64 = NULL;
char *str = NULL;
int prefix_length;
status = gensec_update_recv(subreq, state, &sub_out);
TALLOC_FREE(subreq);
state->status = status;
if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
status = NT_STATUS_OK;
}
if (tevent_req_nterror(req, status)) {
return;
}
if (sub_out.length == 0) {
tevent_req_done(req);
return;
}
b64 = base64_encode_data_blob(state, sub_out);
data_blob_free(&sub_out);
if (tevent_req_nomem(b64, req)) {
return;
}
prefix_length = http_generic->prefix.length;
str = talloc_asprintf(state, "%*.*s %s", prefix_length, prefix_length,
(const char *)http_generic->prefix.data, b64);
TALLOC_FREE(b64);
if (tevent_req_nomem(str, req)) {
return;
}
state->out = data_blob_string_const(str);
tevent_req_done(req);
}
static NTSTATUS gensec_http_generic_update_recv(struct tevent_req *req,
TALLOC_CTX *out_mem_ctx,
DATA_BLOB *out)
{
struct gensec_http_generic_update_state *state =
tevent_req_data(req,
struct gensec_http_generic_update_state);
NTSTATUS status;
*out = data_blob_null;
if (tevent_req_is_nterror(req, &status)) {
tevent_req_received(req);
return status;
}
*out = state->out;
talloc_steal(out_mem_ctx, state->out.data);
status = state->status;
tevent_req_received(req);
return status;
}
static const struct gensec_security_ops gensec_http_ntlm_security_ops = {
.name = "http_ntlm",
.auth_type = 0,
.client_start = gensec_http_ntlm_client_start,
.update_send = gensec_http_generic_update_send,
.update_recv = gensec_http_generic_update_recv,
.enabled = true,
.priority = GENSEC_EXTERNAL,
};
static const struct gensec_security_ops gensec_http_negotiate_security_ops = {
.name = "http_negotiate",
.auth_type = 0,
.client_start = gensec_http_negotiate_client_start,
.update_send = gensec_http_generic_update_send,
.update_recv = gensec_http_generic_update_recv,
.enabled = true,
.priority = GENSEC_EXTERNAL,
.glue = true,
};
_PUBLIC_ NTSTATUS gensec_http_generic_init(TALLOC_CTX *ctx)
{
NTSTATUS status;
status = gensec_register(ctx, &gensec_http_ntlm_security_ops);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("Failed to register '%s' gensec backend!\n",
gensec_http_ntlm_security_ops.name));
return status;
}
status = gensec_register(ctx, &gensec_http_negotiate_security_ops);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("Failed to register '%s' gensec backend!\n",
gensec_http_negotiate_security_ops.name));
return status;
}
return status;
}