summaryrefslogtreecommitdiff
path: root/source4/utils
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2004-06-29 09:40:10 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 12:56:49 -0500
commitdc9f55dbec5f892b39d924d5fd033b5eec1e14e4 (patch)
treedd6932fb92fef55787b9a20671dd8c8f71ef3b6d /source4/utils
parenta440e8f3b518d25c5fb9c9fa896cb7704974f346 (diff)
downloadsamba-dc9f55dbec5f892b39d924d5fd033b5eec1e14e4.tar.gz
samba-dc9f55dbec5f892b39d924d5fd033b5eec1e14e4.tar.bz2
samba-dc9f55dbec5f892b39d924d5fd033b5eec1e14e4.zip
r1294: A nice, large, commit...
This implements gensec for Samba's server side, and brings gensec up to the standards of a full subsystem. This means that use of the subsystem is by gensec_* functions, not function pointers in structures (this is internal). This causes changes in all the existing gensec users. Our RPC server no longer contains it's own generalised security scheme, and now calls gensec directly. Gensec has also taken over the role of auth/auth_ntlmssp.c An important part of gensec, is the output of the 'session_info' struct. This is now reference counted, so that we can correctly free it when a pipe is closed, no matter if it was inherited, or created by per-pipe authentication. The schannel code is reworked, to be in the same file for client and server. ntlm_auth is reworked to use gensec. The major problem with this code is the way it relies on subsystem auto-initialisation. The primary reason for this commit now.is to allow these problems to be looked at, and fixed. There are problems with the new code: - I've tested it with smbtorture, but currently don't have VMware and valgrind working (this I'll fix soon). - The SPNEGO code is client-only at this point. - We still do not do kerberos. Andrew Bartlett (This used to be commit 07fd885fd488fd1051eacc905a2d4962f8a018ec)
Diffstat (limited to 'source4/utils')
-rw-r--r--source4/utils/ntlm_auth.c416
1 files changed, 215 insertions, 201 deletions
diff --git a/source4/utils/ntlm_auth.c b/source4/utils/ntlm_auth.c
index 7690a549f7..1ae9075fba 100644
--- a/source4/utils/ntlm_auth.c
+++ b/source4/utils/ntlm_auth.c
@@ -35,6 +35,7 @@ enum stdio_helper_mode {
SQUID_2_5_NTLMSSP,
NTLMSSP_CLIENT_1,
GSS_SPNEGO_CLIENT,
+ GSS_SPNEGO_SERVER,
NTLM_SERVER_1,
NUM_HELPER_MODES
};
@@ -44,19 +45,19 @@ enum stdio_helper_mode {
typedef void (*stdio_helper_function)(enum stdio_helper_mode stdio_helper_mode,
- char *buf, int length);
+ char *buf, int length, void **private);
static void manage_squid_basic_request (enum stdio_helper_mode stdio_helper_mode,
- char *buf, int length);
+ char *buf, int length, void **private);
-static void manage_squid_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode,
- char *buf, int length);
-
-static void manage_gensec_client_request (enum stdio_helper_mode stdio_helper_mode,
- char *buf, int length);
+static void manage_gensec_request (enum stdio_helper_mode stdio_helper_mode,
+ char *buf, int length, void **private);
static void manage_ntlm_server_1_request (enum stdio_helper_mode stdio_helper_mode,
- char *buf, int length);
+ char *buf, int length, void **private);
+
+static void manage_squid_request(enum stdio_helper_mode helper_mode,
+ stdio_helper_function fn, void *private);
static const struct {
enum stdio_helper_mode mode;
@@ -65,9 +66,10 @@ static const struct {
} stdio_helper_protocols[] = {
{ SQUID_2_4_BASIC, "squid-2.4-basic", manage_squid_basic_request},
{ SQUID_2_5_BASIC, "squid-2.5-basic", manage_squid_basic_request},
- { SQUID_2_5_NTLMSSP, "squid-2.5-ntlmssp", manage_squid_ntlmssp_request},
- { NTLMSSP_CLIENT_1, "ntlmssp-client-1", manage_gensec_client_request},
- { GSS_SPNEGO_CLIENT, "gss-spnego-client", manage_gensec_client_request},
+ { SQUID_2_5_NTLMSSP, "squid-2.5-ntlmssp", manage_gensec_request},
+ { GSS_SPNEGO_CLIENT, "gss-spnego-client", manage_gensec_request},
+ { GSS_SPNEGO_SERVER, "gss-spnego-server", manage_gensec_request},
+ { NTLMSSP_CLIENT_1, "ntlmssp-client-1", manage_gensec_request},
{ NTLM_SERVER_1, "ntlm-server-1", manage_ntlm_server_1_request},
{ NUM_HELPER_MODES, NULL, NULL}
};
@@ -172,149 +174,8 @@ static NTSTATUS local_pw_check_specified(const char *username,
}
-static NTSTATUS local_pw_check(struct ntlmssp_state *ntlmssp_state, DATA_BLOB *user_session_key, DATA_BLOB *lm_session_key)
-{
- NTSTATUS nt_status;
- uint8 lm_pw[16], nt_pw[16];
- uint8_t *lm_pwd, *nt_pwd;
-
- E_md4hash(opt_password, nt_pw);
- if (E_deshash(opt_password, lm_pw)) {
- lm_pwd = lm_pw;
- } else {
- lm_pwd = NULL;
- }
- nt_pwd = nt_pw;
-
- nt_status = ntlm_password_check(ntlmssp_state->mem_ctx,
- &ntlmssp_state->chal,
- &ntlmssp_state->lm_resp,
- &ntlmssp_state->nt_resp,
- NULL, NULL,
- ntlmssp_state->user,
- ntlmssp_state->user,
- ntlmssp_state->domain,
- lm_pwd, nt_pwd, user_session_key, lm_session_key);
-
- if (NT_STATUS_IS_OK(nt_status)) {
- ntlmssp_state->auth_context = talloc_asprintf(ntlmssp_state->mem_ctx,
- "%s%c%s", ntlmssp_state->domain,
- *lp_winbind_separator(),
- ntlmssp_state->user);
- } else {
- DEBUG(3, ("Login for user [%s]\\[%s]@[%s] failed due to [%s]\n",
- ntlmssp_state->domain, ntlmssp_state->user, ntlmssp_state->workstation,
- nt_errstr(nt_status)));
- ntlmssp_state->auth_context = NULL;
- }
- return nt_status;
-}
-
-static NTSTATUS ntlm_auth_start_ntlmssp_server(struct ntlmssp_state **ntlmssp_state)
-{
- NTSTATUS status = ntlmssp_server_start(ntlmssp_state);
-
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("Could not start NTLMSSP client: %s\n",
- nt_errstr(status)));
- return status;
- }
-
- /* Have we been given a local password, or should we ask winbind? */
- if (opt_password) {
- (*ntlmssp_state)->check_password = local_pw_check;
- (*ntlmssp_state)->get_domain = lp_workgroup;
- (*ntlmssp_state)->get_global_myname = global_myname;
- } else {
- DEBUG(0, ("Winbind not supported in Samba4 ntlm_auth yet, specify --password\n"));
- exit(1);
- }
- return NT_STATUS_OK;
-}
-
-static void manage_squid_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode,
- char *buf, int length)
-{
- static struct ntlmssp_state *ntlmssp_state = NULL;
- DATA_BLOB request, reply;
- NTSTATUS nt_status;
-
- if (strlen(buf) < 2) {
- DEBUG(1, ("NTLMSSP query [%s] invalid", buf));
- x_fprintf(x_stdout, "BH\n");
- return;
- }
-
- if (strlen(buf) > 3) {
- request = base64_decode_data_blob(buf + 3);
- } else {
- request = data_blob(NULL, 0);
- }
-
- if ((strncmp(buf, "PW ", 3) == 0)) {
- /* The calling application wants us to use a local password (rather than winbindd) */
-
- opt_password = strndup((const char *)request.data, request.length);
-
- if (opt_password == NULL) {
- DEBUG(1, ("Out of memory\n"));
- x_fprintf(x_stdout, "BH\n");
- data_blob_free(&request);
- return;
- }
-
- x_fprintf(x_stdout, "OK\n");
- data_blob_free(&request);
- return;
- }
-
- if (strncmp(buf, "YR", 2) == 0) {
- if (ntlmssp_state)
- ntlmssp_end(&ntlmssp_state);
- } else if (strncmp(buf, "KK", 2) == 0) {
-
- } else {
- DEBUG(1, ("NTLMSSP query [%s] invalid", buf));
- x_fprintf(x_stdout, "BH\n");
- return;
- }
-
- if (!ntlmssp_state) {
- if (!NT_STATUS_IS_OK(nt_status = ntlm_auth_start_ntlmssp_server(&ntlmssp_state))) {
- x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
- return;
- }
- }
-
- DEBUG(10, ("got NTLMSSP packet:\n"));
- dump_data(10, (const char *)request.data, request.length);
-
- nt_status = ntlmssp_update(ntlmssp_state, NULL, request, &reply);
-
- if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- char *reply_base64 = base64_encode_data_blob(reply);
- x_fprintf(x_stdout, "TT %s\n", reply_base64);
- SAFE_FREE(reply_base64);
- data_blob_free(&reply);
- DEBUG(10, ("NTLMSSP challenge\n"));
- } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED)) {
- x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
- DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status)));
-
- ntlmssp_end(&ntlmssp_state);
- } else if (!NT_STATUS_IS_OK(nt_status)) {
- x_fprintf(x_stdout, "NA %s\n", nt_errstr(nt_status));
- DEBUG(10, ("NTLMSSP %s\n", nt_errstr(nt_status)));
- } else {
- x_fprintf(x_stdout, "AF %s\n", (char *)ntlmssp_state->auth_context);
- DEBUG(10, ("NTLMSSP OK!\n"));
- }
-
- data_blob_free(&request);
-}
-
static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode,
- char *buf, int length)
+ char *buf, int length, void **private)
{
char *user, *pass;
user=buf;
@@ -340,16 +201,14 @@ static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode,
}
}
-static void manage_gensec_client_request(enum stdio_helper_mode stdio_helper_mode,
- char *buf, int length)
+/* This is a bit hairy, but the basic idea is to do a password callback
+ to the calling application. The callback comes from within gensec */
+
+static void manage_gensec_get_pw_request(enum stdio_helper_mode stdio_helper_mode,
+ char *buf, int length, void **private)
{
DATA_BLOB in;
- DATA_BLOB out;
- char *out_base64;
- static struct gensec_security gensec_state;
- NTSTATUS nt_status;
- BOOL first = False;
-
+ struct gensec_security **gensec_state = (struct gensec_security **)private;
if (strlen(buf) < 2) {
DEBUG(1, ("query [%s] invalid", buf));
x_fprintf(x_stdout, "BH\n");
@@ -364,11 +223,10 @@ static void manage_gensec_client_request(enum stdio_helper_mode stdio_helper_mod
if (strncmp(buf, "PW ", 3) == 0) {
- /* We asked for a password and obviously got it :-) */
-
- opt_password = strndup((const char *)in.data, in.length);
+ (*gensec_state)->password_callback_private = talloc_strndup((*gensec_state)->mem_ctx,
+ (const char *)in.data, in.length);
- if (opt_password == NULL) {
+ if ((*gensec_state)->password_callback_private == NULL) {
DEBUG(1, ("Out of memory\n"));
x_fprintf(x_stdout, "BH\n");
data_blob_free(&in);
@@ -379,39 +237,124 @@ static void manage_gensec_client_request(enum stdio_helper_mode stdio_helper_mod
data_blob_free(&in);
return;
}
+ DEBUG(1, ("Asked for (and expected) a password\n"));
+ x_fprintf(x_stdout, "BH\n");
+ data_blob_free(&in);
+}
+
+/*
+ * Callback for gensec, to ask the calling application for a password. Uses the above function
+ * for the stdio part of this.
+ */
+
+static NTSTATUS get_password(struct gensec_security *gensec_security, TALLOC_CTX *mem_ctx,
+ char **password)
+{
+ *password = NULL;
+
+ /* Ask for a password */
+ x_fprintf(x_stdout, "PW\n");
+ gensec_security->password_callback_private = NULL;
+
+ manage_squid_request(NUM_HELPER_MODES /* bogus */, manage_gensec_get_pw_request, &gensec_security);
+ *password = (char *)gensec_security->password_callback_private;
+ if (*password) {
+ return NT_STATUS_OK;
+ } else {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+}
+
+static void manage_gensec_request(enum stdio_helper_mode stdio_helper_mode,
+ char *buf, int length, void **private)
+{
+ DATA_BLOB in;
+ DATA_BLOB out = data_blob(NULL, 0);
+ char *out_base64 = NULL;
+ const char *reply_arg = NULL;
+ struct gensec_security **gensec_state = (struct gensec_security **)private;
+ NTSTATUS nt_status;
+ BOOL first = False;
+ const char *reply_code;
+
+ if (strlen(buf) < 2) {
+ DEBUG(1, ("query [%s] invalid", buf));
+ x_fprintf(x_stdout, "BH\n");
+ return;
+ }
+
+ if (strlen(buf) > 3) {
+ in = base64_decode_data_blob(buf + 3);
+ } else {
+ in = data_blob(NULL, 0);
+ }
+
if (strncmp(buf, "YR", 2) == 0) {
- if (gensec_state.ops) {
- gensec_state.ops->end(&gensec_state);
- gensec_state.ops = NULL;
+ if (gensec_state && *gensec_state) {
+ gensec_end(gensec_state);
+ *gensec_state = NULL;
}
+ } else if ( (strncmp(buf, "OK", 2) == 0)) {
+ /* do nothing */
+ data_blob_free(&in);
+ return;
} else if ( (strncmp(buf, "TT ", 3) != 0) &&
- (strncmp(buf, "AF ", 3) != 0) &&
- (strncmp(buf, "NA ", 3) != 0) ) {
+ (strncmp(buf, "KK ", 3) != 0) &&
+ (strncmp(buf, "AF ", 3) != 0) &&
+ (strncmp(buf, "NA ", 3) != 0) &&
+ (strncmp(buf, "PW ", 3) != 0)) {
DEBUG(1, ("SPNEGO request [%s] invalid\n", buf));
x_fprintf(x_stdout, "BH\n");
data_blob_free(&in);
return;
}
- if (!opt_password) {
- x_fprintf(x_stdout, "PW\n");
- data_blob_free(&in);
- return;
- }
-
/* setup gensec */
- if (!gensec_state.ops) {
- if (stdio_helper_mode == GSS_SPNEGO_CLIENT) {
- gensec_state.ops = gensec_security_by_oid(OID_SPNEGO);
- } else if (stdio_helper_mode == NTLMSSP_CLIENT_1) {
- gensec_state.ops = gensec_security_by_oid(OID_NTLMSSP);
- } else {
- exit(1);
+ if (!(gensec_state && *gensec_state)) {
+ switch (stdio_helper_mode) {
+ case GSS_SPNEGO_CLIENT:
+ case NTLMSSP_CLIENT_1:
+ /* setup the client side */
+
+ if (!NT_STATUS_IS_OK(gensec_client_start(gensec_state))) {
+ exit(1);
+ }
+ gensec_set_username(*gensec_state, opt_username);
+ gensec_set_domain(*gensec_state, opt_domain);
+ if (opt_password) {
+ if (!NT_STATUS_IS_OK(gensec_set_password(*gensec_state, opt_password))) {
+ DEBUG(1, ("Out of memory\n"));
+ x_fprintf(x_stdout, "BH\n");
+ data_blob_free(&in);
+ return;
+ }
+ } else {
+ gensec_set_password_callback(*gensec_state, get_password, NULL);
+ }
+
+ break;
+ case GSS_SPNEGO_SERVER:
+ case SQUID_2_5_NTLMSSP:
+ if (!NT_STATUS_IS_OK(gensec_server_start(gensec_state))) {
+ exit(1);
+ }
+ break;
+ default:
+ abort();
+ }
+
+ switch (stdio_helper_mode) {
+ case GSS_SPNEGO_CLIENT:
+ case GSS_SPNEGO_SERVER:
+ nt_status = gensec_start_mech_by_oid(*gensec_state, OID_SPNEGO);
+ break;
+ case NTLMSSP_CLIENT_1:
+ case SQUID_2_5_NTLMSSP:
+ nt_status = gensec_start_mech_by_oid(*gensec_state, OID_NTLMSSP);
+ break;
+ default:
+ abort();
}
- gensec_state.user.name = opt_username;
- gensec_state.user.domain = opt_domain;
- gensec_state.user.password = opt_password;
- nt_status = gensec_state.ops->client_start(&gensec_state);
if (!NT_STATUS_IS_OK(nt_status)) {
DEBUG(1, ("SPENGO login failed to initialise: %s\n", nt_errstr(nt_status)));
@@ -423,33 +366,104 @@ static void manage_gensec_client_request(enum stdio_helper_mode stdio_helper_mod
}
}
+ if (strncmp(buf, "PW ", 3) == 0) {
+
+ if (!NT_STATUS_IS_OK(gensec_set_password(*gensec_state,
+ talloc_strndup((*gensec_state)->mem_ctx,
+ (const char *)in.data,
+ in.length)))) {
+ DEBUG(1, ("Out of memory\n"));
+ x_fprintf(x_stdout, "BH\n");
+ data_blob_free(&in);
+ return;
+ }
+
+ x_fprintf(x_stdout, "OK\n");
+ data_blob_free(&in);
+ return;
+ }
+
/* update */
- nt_status = gensec_state.ops->update(&gensec_state, NULL, in, &out);
+ nt_status = gensec_update(*gensec_state, NULL, in, &out);
- if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ /* don't leak 'bad password'/'no such user' info to the network client */
+ nt_status = nt_status_squash(nt_status);
+ if (out.length) {
out_base64 = base64_encode_data_blob(out);
+ } else {
+ out_base64 = NULL;
+ }
+ if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ reply_arg = "*";
if (first) {
- x_fprintf(x_stdout, "YR %s\n", out_base64);
- } else {
- x_fprintf(x_stdout, "KK %s\n", out_base64);
+ reply_code = "YR";
+ } else if ((*gensec_state)->gensec_role == GENSEC_CLIENT) {
+ reply_code = "KK";
+ } else if ((*gensec_state)->gensec_role == GENSEC_SERVER) {
+ reply_code = "TT";
+ } else {
+ abort();
}
- SAFE_FREE(out_base64);
+ } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED)) {
+ reply_code = "BH";
+ reply_arg = nt_errstr(nt_status);
+ DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
+ } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_UNSUCCESSFUL)) {
+ reply_code = "BH";
+ reply_arg = nt_errstr(nt_status);
+ DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
} else if (!NT_STATUS_IS_OK(nt_status)) {
- DEBUG(1, ("SPENGO login failed: %s\n", nt_errstr(nt_status)));
- x_fprintf(x_stdout, "BH\n");
+ reply_code = "NA";
+ reply_arg = nt_errstr(nt_status);
+ DEBUG(1, ("GENSEC login failed: %s\n", nt_errstr(nt_status)));
+ } else if /* OK */ ((*gensec_state)->gensec_role == GENSEC_SERVER) {
+ struct auth_session_info *session_info;
+
+ nt_status = gensec_session_info(*gensec_state, &session_info);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ reply_code = "BH";
+ reply_arg = nt_errstr(nt_status);
+ DEBUG(1, ("GENSEC failed to retreive the session info: %s\n", nt_errstr(nt_status)));
+ } else {
+
+ reply_code = "AF";
+ reply_arg = talloc_asprintf((*gensec_state)->mem_ctx,
+ "%s%s%s", session_info->server_info->domain,
+ lp_winbind_separator(), session_info->server_info->account_name);
+ talloc_destroy(session_info->mem_ctx);
+ }
+ } else if ((*gensec_state)->gensec_role == GENSEC_SERVER) {
+ reply_code = "AF";
+ reply_arg = NULL;
} else {
- x_fprintf(x_stdout, "AF\n");
+ abort();
}
+ switch (stdio_helper_mode) {
+ case GSS_SPNEGO_SERVER:
+ if (out_base64) {
+ x_fprintf(x_stdout, "%s %s %s\n", reply_code, out_base64, reply_arg);
+ } else {
+ x_fprintf(x_stdout, "%s %s\n", reply_code, reply_arg);
+ }
+ default:
+ if (out_base64) {
+ x_fprintf(x_stdout, "%s %s\n", reply_code, out_base64);
+ } else {
+ x_fprintf(x_stdout, "%s %s\n", reply_code, reply_arg);
+ }
+ }
+
+ SAFE_FREE(out_base64);
return;
}
static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mode,
- char *buf, int length)
+ char *buf, int length, void **private)
{
char *request, *parameter;
static DATA_BLOB challenge;
@@ -643,7 +657,7 @@ static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mod
}
}
-static void manage_squid_request(enum stdio_helper_mode helper_mode, stdio_helper_function fn)
+static void manage_squid_request(enum stdio_helper_mode helper_mode, stdio_helper_function fn, void *private)
{
char buf[SQUID_BUFFER_SIZE+1];
int length;
@@ -684,16 +698,16 @@ static void manage_squid_request(enum stdio_helper_mode helper_mode, stdio_helpe
return;
}
- fn(helper_mode, buf, length);
+ fn(helper_mode, buf, length, private);
}
-
static void squid_stream(enum stdio_helper_mode stdio_mode, stdio_helper_function fn) {
/* initialize FDescs */
x_setbuf(x_stdout, NULL);
x_setbuf(x_stderr, NULL);
+ void *private = NULL;
while(1) {
- manage_squid_request(stdio_mode, fn);
+ manage_squid_request(stdio_mode, fn, &private);
}
}