summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVolker Lendecke <vlendec@samba.org>2003-08-01 07:59:23 +0000
committerVolker Lendecke <vlendec@samba.org>2003-08-01 07:59:23 +0000
commitf5b5a9793a5adb8df356f4798102cdc45dc586d2 (patch)
tree7999e2d4f6c18b35cdc3fcc7d86af2f3a95c130b
parent66ba34188c8300a8b4d5f266a392dc1924d9f755 (diff)
downloadsamba-f5b5a9793a5adb8df356f4798102cdc45dc586d2.tar.gz
samba-f5b5a9793a5adb8df356f4798102cdc45dc586d2.tar.bz2
samba-f5b5a9793a5adb8df356f4798102cdc45dc586d2.zip
Add ntlmssp client support to ntlm_auth. Find the corresponding cyrus sasl
module under http://samba.sernet.de/cyrus-gss-spnego.diff Volker (This used to be commit a82f6a00969f7ea377626c28ec05ace04f8135a9)
-rw-r--r--source3/utils/ntlm_auth.c335
1 files changed, 310 insertions, 25 deletions
diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c
index fbe32768a3..1d36a7ce52 100644
--- a/source3/utils/ntlm_auth.c
+++ b/source3/utils/ntlm_auth.c
@@ -33,7 +33,8 @@ enum squid_mode {
SQUID_2_4_BASIC,
SQUID_2_5_BASIC,
SQUID_2_5_NTLMSSP,
- GSS_SPNEGO
+ GSS_SPNEGO,
+ GSS_SPNEGO_CLIENT
};
@@ -378,7 +379,7 @@ static void offer_gss_spnego_mechs(void) {
}
reply_base64 = base64_encode_data_blob(token);
- x_fprintf(x_stdout, "TT %s\n", reply_base64);
+ x_fprintf(x_stdout, "TT %s *\n", reply_base64);
SAFE_FREE(reply_base64);
data_blob_free(&token);
@@ -393,10 +394,12 @@ static void manage_gss_spnego_request(enum squid_mode squid_mode,
SPNEGO_DATA spnego;
DATA_BLOB request, token;
NTSTATUS status;
- char *reply_base64;
- pstring reply;
ssize_t len;
+ const char *reply_code;
+ char *reply_base64;
+ pstring reply_argument;
+
if (strlen(buf) < 2) {
if (ntlmssp_state != NULL) {
@@ -430,8 +433,8 @@ static void manage_gss_spnego_request(enum squid_mode squid_mode,
}
request = base64_decode_data_blob(buf + 3);
-
len = read_spnego_data(request, &spnego);
+ data_blob_free(&request);
if (len == -1) {
DEBUG(1, ("GSS-SPNEGO query [%s] invalid", buf));
@@ -470,7 +473,6 @@ static void manage_gss_spnego_request(enum squid_mode squid_mode,
DEBUG(1, ("Client wants a new NTLMSSP challenge, but "
"already got one\n"));
x_fprintf(x_stdout, "BH\n");
-
ntlmssp_server_end(&ntlmssp_state);
return;
}
@@ -488,7 +490,7 @@ static void manage_gss_spnego_request(enum squid_mode squid_mode,
spnego.type = SPNEGO_NEG_TOKEN_TARG;
spnego.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE;
- spnego.negTokenTarg.supportedMech = OID_NTLMSSP;
+ spnego.negTokenTarg.supportedMech = strdup(OID_NTLMSSP);
status = ntlmssp_server_update(ntlmssp_state,
spnego.negTokenInit.mechToken,
@@ -516,25 +518,20 @@ static void manage_gss_spnego_request(enum squid_mode squid_mode,
}
- if ( !NT_STATUS_IS_OK(status) &&
- !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) ) {
-
- /* Neither ok nor more work to do, so reject */
-
- x_fprintf(x_stdout, "NA %s\n", nt_errstr(status));
- DEBUG(10, ("NTLMSSP %s\n", nt_errstr(status)));
- return;
- }
-
- pstr_sprintf(reply, "TT");
-
if (NT_STATUS_IS_OK(status)) {
- pstr_sprintf(reply, "AF %s\\%s",
- ntlmssp_state->domain, ntlmssp_state->user);
-
spnego.negTokenTarg.negResult = SPNEGO_ACCEPT_COMPLETED;
-
- DEBUG(10, ("NTLMSSP OK!\n"));
+ reply_code = "AF";
+ pstr_sprintf(reply_argument, "%s\\%s",
+ ntlmssp_state->domain, ntlmssp_state->user);
+ } else if (NT_STATUS_EQUAL(status,
+ NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ spnego.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE;
+ reply_code = "TT";
+ pstr_sprintf(reply_argument, "*");
+ } else {
+ spnego.negTokenTarg.negResult = SPNEGO_REJECT;
+ reply_code = "NA";
+ pstrcpy(reply_argument, nt_errstr(status));
}
len = write_spnego_data(&token, &spnego);
@@ -547,7 +544,10 @@ static void manage_gss_spnego_request(enum squid_mode squid_mode,
}
reply_base64 = base64_encode_data_blob(token);
- x_fprintf(x_stdout, "%s %s\n", reply, reply_base64);
+
+ x_fprintf(x_stdout, "%s %s %s\n",
+ reply_code, reply_base64, reply_argument);
+
SAFE_FREE(reply_base64);
data_blob_free(&token);
@@ -558,6 +558,287 @@ static void manage_gss_spnego_request(enum squid_mode squid_mode,
return;
}
+static NTLMSSP_CLIENT_STATE *client_ntlmssp_state = NULL;
+
+static void manage_client_ntlmssp_init(SPNEGO_DATA spnego)
+{
+ NTSTATUS status;
+ DATA_BLOB null_blob = data_blob(NULL, 0);
+ DATA_BLOB to_server;
+ char *to_server_base64;
+ const char *my_mechs[] = {OID_NTLMSSP, NULL};
+
+ DEBUG(10, ("Got spnego negTokenInit with NTLMSSP\n"));
+
+ if (client_ntlmssp_state != NULL) {
+ DEBUG(1, ("Request for initial SPNEGO request where "
+ "we already have a state\n"));
+ x_fprintf(x_stdout, "BH\n");
+ return;
+ }
+
+ if ( (opt_username == NULL) || (opt_domain == NULL) ) {
+ DEBUG(1, ("Need username and domain for NTLMSSP\n"));
+ x_fprintf(x_stdout, "BH\n");
+ return;
+ }
+
+ if (opt_password == NULL) {
+
+ /* Request a password from the calling process. After
+ sending it, the calling process should retry with
+ the negTokenInit. */
+
+ DEBUG(10, ("Requesting password\n"));
+ x_fprintf(x_stdout, "PW\n");
+ return;
+ }
+
+ status = ntlmssp_client_start(&client_ntlmssp_state);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Could not start NTLMSSP client: %s\n",
+ nt_errstr(status)));
+ x_fprintf(x_stdout, "BH\n");
+ ntlmssp_client_end(&client_ntlmssp_state);
+ return;
+ }
+
+ status = ntlmssp_set_username(client_ntlmssp_state, opt_username);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Could not set username: %s\n",
+ nt_errstr(status)));
+ x_fprintf(x_stdout, "BH\n");
+ ntlmssp_client_end(&client_ntlmssp_state);
+ return;
+ }
+
+ status = ntlmssp_set_domain(client_ntlmssp_state, opt_domain);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Could not set domain: %s\n",
+ nt_errstr(status)));
+ x_fprintf(x_stdout, "BH\n");
+ ntlmssp_client_end(&client_ntlmssp_state);
+ return;
+ }
+
+ status = ntlmssp_set_password(client_ntlmssp_state, opt_password);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Could not set password: %s\n",
+ nt_errstr(status)));
+ x_fprintf(x_stdout, "BH\n");
+ ntlmssp_client_end(&client_ntlmssp_state);
+ return;
+ }
+
+ spnego.type = SPNEGO_NEG_TOKEN_INIT;
+ spnego.negTokenInit.mechTypes = my_mechs;
+ spnego.negTokenInit.reqFlags = 0;
+ spnego.negTokenInit.mechListMIC = null_blob;
+
+ status = ntlmssp_client_update(client_ntlmssp_state, null_blob,
+ &spnego.negTokenInit.mechToken);
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ DEBUG(1, ("Expected MORE_PROCESSING_REQUIRED, got: %s\n",
+ nt_errstr(status)));
+ x_fprintf(x_stdout, "BH\n");
+ ntlmssp_client_end(&client_ntlmssp_state);
+ return;
+ }
+
+ write_spnego_data(&to_server, &spnego);
+ data_blob_free(&spnego.negTokenInit.mechToken);
+
+ to_server_base64 = base64_encode_data_blob(to_server);
+ data_blob_free(&to_server);
+ x_fprintf(x_stdout, "KK %s\n", to_server_base64);
+ SAFE_FREE(to_server_base64);
+ return;
+}
+
+static void manage_client_ntlmssp_targ(SPNEGO_DATA spnego)
+{
+ NTSTATUS status;
+ DATA_BLOB null_blob = data_blob(NULL, 0);
+ DATA_BLOB request;
+ DATA_BLOB to_server;
+ char *to_server_base64;
+
+ DEBUG(10, ("Got spnego negTokenTarg with NTLMSSP\n"));
+
+ if (client_ntlmssp_state == NULL) {
+ DEBUG(1, ("Got NTLMSSP tArg without a client state\n"));
+ x_fprintf(x_stdout, "BH\n");
+ ntlmssp_client_end(&client_ntlmssp_state);
+ return;
+ }
+
+ if (spnego.negTokenTarg.negResult == SPNEGO_REJECT) {
+ x_fprintf(x_stdout, "NA\n");
+ ntlmssp_client_end(&client_ntlmssp_state);
+ return;
+ }
+
+ if (spnego.negTokenTarg.negResult == SPNEGO_ACCEPT_COMPLETED) {
+ x_fprintf(x_stdout, "AF\n");
+ ntlmssp_client_end(&client_ntlmssp_state);
+ return;
+ }
+
+ status = ntlmssp_client_update(client_ntlmssp_state,
+ spnego.negTokenTarg.responseToken,
+ &request);
+
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ DEBUG(1, ("Expected MORE_PROCESSING_REQUIRED from "
+ "ntlmssp_client_update, got: %s\n",
+ nt_errstr(status)));
+ x_fprintf(x_stdout, "BH\n");
+ data_blob_free(&request);
+ ntlmssp_client_end(&client_ntlmssp_state);
+ return;
+ }
+
+ spnego.type = SPNEGO_NEG_TOKEN_TARG;
+ spnego.negTokenTarg.negResult = SPNEGO_ACCEPT_INCOMPLETE;
+ spnego.negTokenTarg.supportedMech = OID_NTLMSSP;
+ spnego.negTokenTarg.responseToken = request;
+ spnego.negTokenTarg.mechListMIC = null_blob;
+
+ write_spnego_data(&to_server, &spnego);
+ data_blob_free(&request);
+
+ to_server_base64 = base64_encode_data_blob(to_server);
+ data_blob_free(&to_server);
+ x_fprintf(x_stdout, "KK %s\n", to_server_base64);
+ SAFE_FREE(to_server_base64);
+ return;
+}
+
+static void manage_client_krb5_init(SPNEGO_DATA spnego)
+{
+ DEBUG(1, ("to be done ... \n"));
+ x_fprintf(x_stdout, "BH\n");
+ return;
+}
+
+static void manage_client_krb5_targ(SPNEGO_DATA spnego)
+{
+ DEBUG(1, ("Got a negTokenTarg with a Kerberos token. This should not "
+ "happen!\n"));
+ x_fprintf(x_stdout, "BH\n");
+ return;
+}
+
+static void manage_gss_spnego_client_request(enum squid_mode squid_mode,
+ char *buf, int length)
+{
+ DATA_BLOB request;
+ SPNEGO_DATA spnego;
+ ssize_t len;
+
+ if (strlen(buf) <= 3) {
+ DEBUG(1, ("SPNEGO query [%s] too short\n", buf));
+ x_fprintf(x_stdout, "BH\n");
+ return;
+ }
+
+ request = base64_decode_data_blob(buf+3);
+
+ if (strncmp(buf, "PW ", 3) == 0) {
+
+ /* We asked for a password and obviously got it :-) */
+
+ opt_password = strndup(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, "TT ", 3) != 0) &&
+ (strncmp(buf, "AF ", 3) != 0) &&
+ (strncmp(buf, "NA ", 3) != 0) ) {
+ DEBUG(1, ("SPNEGO request [%s] invalid\n", buf));
+ x_fprintf(x_stdout, "BH\n");
+ data_blob_free(&request);
+ return;
+ }
+
+ /* So we got a server challenge to generate a SPNEGO
+ client-to-server request... */
+
+ len = read_spnego_data(request, &spnego);
+ data_blob_free(&request);
+
+ if (len == -1) {
+ DEBUG(1, ("Could not read SPNEGO data for [%s]\n", buf));
+ x_fprintf(x_stdout, "BH\n");
+ return;
+ }
+
+ if (spnego.type == SPNEGO_NEG_TOKEN_INIT) {
+
+ /* The server offers a list of mechanisms */
+
+ const char **mechType = spnego.negTokenInit.mechTypes;
+
+ while (*mechType != NULL) {
+
+ if (strcmp(*mechType, OID_NTLMSSP) == 0) {
+ manage_client_ntlmssp_init(spnego);
+ goto out;
+ }
+
+ if (strcmp(*mechType, OID_KERBEROS5_OLD) == 0) {
+ manage_client_krb5_init(spnego);
+ goto out;
+ }
+
+ mechType++;
+ }
+
+ DEBUG(1, ("Server offered no compatible mechanism\n"));
+ x_fprintf(x_stdout, "BH\n");
+ return;
+ }
+
+ if (spnego.type == SPNEGO_NEG_TOKEN_TARG) {
+
+ if (strcmp(spnego.negTokenTarg.supportedMech,
+ OID_NTLMSSP) == 0) {
+ manage_client_ntlmssp_targ(spnego);
+ goto out;
+ }
+
+ if (strcmp(spnego.negTokenTarg.supportedMech,
+ OID_KERBEROS5_OLD) == 0) {
+ manage_client_krb5_targ(spnego);
+ goto out;
+ }
+
+ }
+
+ DEBUG(1, ("Got an SPNEGO token I could not handle [%s]!\n", buf));
+ x_fprintf(x_stdout, "BH\n");
+ return;
+
+ out:
+ free_spnego_data(&spnego);
+ return;
+}
+
static void manage_squid_request(enum squid_mode squid_mode)
{
char buf[SQUID_BUFFER_SIZE+1];
@@ -601,6 +882,8 @@ static void manage_squid_request(enum squid_mode squid_mode)
manage_squid_ntlmssp_request(squid_mode, buf, length);
} else if (squid_mode == GSS_SPNEGO) {
manage_gss_spnego_request(squid_mode, buf, length);
+ } else if (squid_mode == GSS_SPNEGO_CLIENT) {
+ manage_gss_spnego_client_request(squid_mode, buf, length);
}
}
@@ -1554,6 +1837,8 @@ enum {
squid_stream(SQUID_2_4_BASIC);
} else if (strcmp(helper_protocol, "gss-spnego")== 0) {
squid_stream(GSS_SPNEGO);
+ } else if (strcmp(helper_protocol, "gss-spnego-client") == 0) {
+ squid_stream(GSS_SPNEGO_CLIENT);
} else {
x_fprintf(x_stderr, "unknown helper protocol [%s]\n", helper_protocol);
exit(1);