diff options
author | Andrew Bartlett <abartlet@samba.org> | 2003-01-28 12:07:02 +0000 |
---|---|---|
committer | Andrew Bartlett <abartlet@samba.org> | 2003-01-28 12:07:02 +0000 |
commit | 1cba0a757970ffd8b81d61c88965010968ab3eff (patch) | |
tree | d776df92ed188a6818033b1dc1f1b3eadc22fe1e | |
parent | 23265259508e2a89c0386608c5f034fac635ca62 (diff) | |
download | samba-1cba0a757970ffd8b81d61c88965010968ab3eff.tar.gz samba-1cba0a757970ffd8b81d61c88965010968ab3eff.tar.bz2 samba-1cba0a757970ffd8b81d61c88965010968ab3eff.zip |
Merge from HEAD:
- NTLMSSP over SPENGO (sesssion-setup-and-x) cleanup and code refactor.
- also consequential changes to the NTLMSSP and SPNEGO parsing functions
- and the client code that uses the same functions
- Add ntlm_auth, a NTLMSSP authentication interface for use by applications
like Squid and Apache.
- also consquential changes to use common code for base64 encode/decode.
- Winbind changes to support ntlm_auth (I don't want this program to need
to read smb.conf, instead getting all it's details over the pipe).
- nmbd changes for fstrcat() instead of fstrcpy().
Andrew Bartlett
(This used to be commit fbb46da79cf322570a7e3318100c304bbf33409e)
-rw-r--r-- | source3/Makefile.in | 15 | ||||
-rw-r--r-- | source3/auth/auth.c | 10 | ||||
-rw-r--r-- | source3/include/asn_1.h | 4 | ||||
-rw-r--r-- | source3/include/auth.h | 9 | ||||
-rw-r--r-- | source3/include/ntlmssp.h | 19 | ||||
-rw-r--r-- | source3/lib/util_str.c | 94 | ||||
-rw-r--r-- | source3/libsmb/cliconnect.c | 7 | ||||
-rw-r--r-- | source3/libsmb/clispnego.c | 124 | ||||
-rw-r--r-- | source3/nmbd/nmbd_processlogon.c | 4 | ||||
-rw-r--r-- | source3/nsswitch/winbindd.c | 1 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_misc.c | 12 | ||||
-rw-r--r-- | source3/nsswitch/winbindd_nss.h | 4 | ||||
-rw-r--r-- | source3/smbd/sesssetup.c | 371 | ||||
-rw-r--r-- | source3/web/cgi.c | 31 |
14 files changed, 338 insertions, 367 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in index db9203e7cb..1c9f94efb1 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -111,7 +111,7 @@ BIN_PROGS1 = bin/smbclient@EXEEXT@ bin/net@EXEEXT@ bin/smbspool@EXEEXT@ \ BIN_PROGS2 = bin/smbcontrol@EXEEXT@ bin/smbtree@EXEEXT@ bin/tdbbackup@EXEEXT@ \ bin/nmblookup@EXEEXT@ bin/pdbedit@EXEEXT@ BIN_PROGS3 = bin/smbpasswd@EXEEXT@ bin/rpcclient@EXEEXT@ bin/smbcacls@EXEEXT@ \ - bin/profiles@EXEEXT@ bin/smbgroupedit@EXEEXT@ + bin/profiles@EXEEXT@ bin/smbgroupedit@EXEEXT@ bin/ntlm_auth@EXEEXT@ \ TORTURE_PROGS = bin/smbtorture@EXEEXT@ bin/msgtest@EXEEXT@ \ bin/masktest@EXEEXT@ bin/locktest@EXEEXT@ \ @@ -186,7 +186,8 @@ LIBSMB_OBJ = libsmb/clientgen.o libsmb/cliconnect.o libsmb/clifile.o \ libsmb/smberr.o libsmb/credentials.o libsmb/pwd_cache.o \ libsmb/clioplock.o libsmb/errormap.o libsmb/clirap2.o \ libsmb/passchange.o libsmb/unexpected.o libsmb/doserr.o \ - libsmb/namecache.o $(RPC_PARSE_OBJ1) + libsmb/namecache.o libsmb/ntlmssp.o \ + $(RPC_PARSE_OBJ1) LIBMSRPC_OBJ = rpc_client/cli_lsarpc.o rpc_client/cli_samr.o \ rpc_client/cli_netlogon.o rpc_client/cli_srvsvc.o \ @@ -256,7 +257,7 @@ UNIGRP_OBJ = libsmb/netlogon_unigrp.o AUTH_OBJ = auth/auth.o auth/auth_sam.o auth/auth_server.o auth/auth_domain.o \ auth/auth_rhosts.o auth/auth_unix.o auth/auth_util.o auth/auth_winbind.o \ - auth/auth_builtin.o auth/auth_compat.o \ + auth/auth_builtin.o auth/auth_compat.o auth/auth_ntlmssp.o \ $(PLAINTEXT_AUTH_OBJ) $(UNIGRP_OBJ) MANGLE_OBJ = smbd/mangle.o smbd/mangle_hash.o smbd/mangle_map.o smbd/mangle_hash2.o @@ -539,6 +540,8 @@ POPT_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \ TDBBACKUP_OBJ = tdb/tdbbackup.o $(TDBBASE_OBJ) +NTLM_AUTH_OBJ = utils/ntlm_auth.o $(LIBSMB_OBJ) $(POPT_LIB_OBJ) + ###################################################################### # now the rules... ###################################################################### @@ -869,6 +872,12 @@ bin/wbinfo@EXEEXT@: $(WBINFO_OBJ) $(PARAM_OBJ) $(LIB_OBJ) \ @$(LINK) -o $@ $(WBINFO_OBJ) $(PARAM_OBJ) $(LIB_OBJ) \ $(UBIQX_OBJ) $(SECRETS_OBJ) $(LIBS) @BUILD_POPT@ +bin/ntlm_auth@EXEEXT@: $(NTLM_AUTH_OBJ) $(PARAM_OBJ) $(LIB_OBJ) \ + $(UBIQX_OBJ) @BUILD_POPT@ bin/.dummy + @echo Linking $@ + @$(LINK) -o $@ $(NTLM_AUTH_OBJ) $(PARAM_OBJ) $(LIB_OBJ) \ + $(UBIQX_OBJ) $(LIBS) @BUILD_POPT@ + bin/pam_smbpass.@SHLIBEXT@: $(PAM_SMBPASS_PICOOBJ) @echo "Linking shared library $@" $(SHLD) $(LDSHFLAGS) -o $@ $(PAM_SMBPASS_PICOOBJ) -lpam $(DYNEXP) $(LIBS) -lc diff --git a/source3/auth/auth.c b/source3/auth/auth.c index 3c4448445a..5d56603b9f 100644 --- a/source3/auth/auth.c +++ b/source3/auth/auth.c @@ -57,7 +57,8 @@ static const uint8 *get_ntlm_challenge(struct auth_context *auth_context) TALLOC_CTX *mem_ctx; if (auth_context->challenge.length) { - DEBUG(5, ("get_ntlm_challenge (auth subsystem): returning previous challenge (normal)\n")); + DEBUG(5, ("get_ntlm_challenge (auth subsystem): returning previous challenge by module %s (normal)\n", + auth_context->challenge_set_by)); return auth_context->challenge.data; } @@ -190,6 +191,12 @@ static NTSTATUS check_ntlm_password(const struct auth_context *auth_context, DEBUG(3, ("check_ntlm_password: mapped user is: [%s]\\[%s]@[%s]\n", user_info->domain.str, user_info->internal_username.str, user_info->wksta_name.str)); + + if (auth_context->challenge.length != 8) { + DEBUG(0, ("check_ntlm_password: Invalid challenge stored for this auth context - cannot continue\n")); + return NT_STATUS_LOGON_FAILURE; + } + if (auth_context->challenge_set_by) DEBUG(10, ("check_ntlm_password: auth_context challenge created by %s\n", auth_context->challenge_set_by)); @@ -441,6 +448,7 @@ NTSTATUS make_auth_context_fixed(struct auth_context **auth_context, uchar chal[ } (*auth_context)->challenge = data_blob(chal, 8); + (*auth_context)->challenge_set_by = "fixed"; return nt_status; } diff --git a/source3/include/asn_1.h b/source3/include/asn_1.h index 7783ab4c2f..9cd873c18a 100644 --- a/source3/include/asn_1.h +++ b/source3/include/asn_1.h @@ -55,4 +55,8 @@ typedef struct { #define OID_KERBEROS5_OLD "1 2 840 48018 1 2 2" #define OID_KERBEROS5 "1 2 840 113554 1 2 2" +#define SPNGEO_NEG_RESULT_ACCEPT 0 +#define SPNGEO_NEG_RESULT_INCOMPLETE 1 +#define SPNGEO_NEG_RESULT_REJECT 2 + #endif /* _ASN_1_H */ diff --git a/source3/include/auth.h b/source3/include/auth.h index 846662d17c..e37f181082 100644 --- a/source3/include/auth.h +++ b/source3/include/auth.h @@ -149,4 +149,13 @@ struct auth_init_function_entry { auth_init_function init; }; + +typedef struct auth_ntlmssp_state +{ + TALLOC_CTX *mem_ctx; + struct auth_context *auth_context; + struct auth_serversupplied_info *server_info; + struct ntlmssp_state *ntlmssp_state; +} AUTH_NTLMSSP_STATE; + #endif /* _SMBAUTH_H_ */ diff --git a/source3/include/ntlmssp.h b/source3/include/ntlmssp.h index 673be83532..79d0446a77 100644 --- a/source3/include/ntlmssp.h +++ b/source3/include/ntlmssp.h @@ -71,9 +71,20 @@ typedef struct ntlmssp_state { TALLOC_CTX *mem_ctx; enum NTLMSSP_ROLE role; - struct auth_context *auth_context; - struct auth_serversupplied_info *server_info; BOOL unicode; - char *orig_user; - char *orig_domain; + char *user; + char *domain; + char *workstation; + DATA_BLOB lm_resp; + DATA_BLOB nt_resp; + DATA_BLOB chal; + void *auth_context; + const uint8 *(*get_challenge)(struct ntlmssp_state *ntlmssp_state); + NTSTATUS (*check_password)(struct ntlmssp_state *ntlmssp_state); + + const char *(*get_global_myname)(void); + const char *(*get_domain)(void); + + int server_role; } NTLMSSP_STATE; + diff --git a/source3/lib/util_str.c b/source3/lib/util_str.c index 799bc64cc6..2a9ee0a868 100644 --- a/source3/lib/util_str.c +++ b/source3/lib/util_str.c @@ -1535,6 +1535,100 @@ void rfc1738_unescape(char *buf) } } +static const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/*************************************************************************** +decode a base64 string into a DATA_BLOB - simple and slow algorithm + ***************************************************************************/ +DATA_BLOB base64_decode_data_blob(const char *s) +{ + int bit_offset, byte_offset, idx, i, n; + DATA_BLOB decoded = data_blob(s, strlen(s)+1); + unsigned char *d = decoded.data; + char *p; + + n=i=0; + + while (*s && (p=strchr_m(b64,*s))) { + idx = (int)(p - b64); + byte_offset = (i*6)/8; + bit_offset = (i*6)%8; + d[byte_offset] &= ~((1<<(8-bit_offset))-1); + if (bit_offset < 3) { + d[byte_offset] |= (idx << (2-bit_offset)); + n = byte_offset+1; + } else { + d[byte_offset] |= (idx >> (bit_offset-2)); + d[byte_offset+1] = 0; + d[byte_offset+1] |= (idx << (8-(bit_offset-2))) & 0xFF; + n = byte_offset+2; + } + s++; i++; + } + + /* fix up length */ + decoded.length = n; + return decoded; +} + +/*************************************************************************** +decode a base64 string in-place - wrapper for the above +***************************************************************************/ +void base64_decode(char *s) +{ + DATA_BLOB decoded = base64_decode_data_blob(s); + memcpy(s, decoded.data, decoded.length); + data_blob_free(&decoded); + + /* null terminate */ + s[decoded.length] = '\0'; +} + +/*************************************************************************** +encode a base64 string into a malloc()ed string caller to free. + +From SQUID: adopted from http://ftp.sunet.se/pub2/gnu/vm/base64-encode.c with adjustments +***************************************************************************/ +char * base64_encode_data_blob(DATA_BLOB data) +{ + int bits = 0; + int char_count = 0; + size_t out_cnt = 0; + size_t len = data.length; + size_t output_len = data.length * 2; + char *result = malloc(output_len); /* get us plenty of space */ + + while (len-- && out_cnt < (data.length * 2) - 5) { + int c = (unsigned char) *(data.data++); + bits += c; + char_count++; + if (char_count == 3) { + result[out_cnt++] = b64[bits >> 18]; + result[out_cnt++] = b64[(bits >> 12) & 0x3f]; + result[out_cnt++] = b64[(bits >> 6) & 0x3f]; + result[out_cnt++] = b64[bits & 0x3f]; + bits = 0; + char_count = 0; + } else { + bits <<= 8; + } + } + if (char_count != 0) { + bits <<= 16 - (8 * char_count); + result[out_cnt++] = b64[bits >> 18]; + result[out_cnt++] = b64[(bits >> 12) & 0x3f]; + if (char_count == 1) { + result[out_cnt++] = '='; + result[out_cnt++] = '='; + } else { + result[out_cnt++] = b64[(bits >> 6) & 0x3f]; + result[out_cnt++] = '='; + } + } + result[out_cnt] = '\0'; /* terminate */ + return result; +} + #ifdef VALGRIND size_t valgrind_strlen(const char *s) { diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index b758af41c4..389b7a1733 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -465,7 +465,8 @@ static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, const char *user, neg_flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_128 | - NTLMSSP_NEGOTIATE_NTLM; + NTLMSSP_NEGOTIATE_NTLM | + NTLMSSP_REQUEST_TARGET; memset(sess_key, 0, 16); @@ -476,8 +477,8 @@ static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, const char *user, "NTLMSSP", NTLMSSP_NEGOTIATE, neg_flags, - workgroup, strlen(workgroup), - cli->calling.name, strlen(cli->calling.name) + 1); + workgroup, + cli->calling.name); DEBUG(10, ("neg_flags: %0X, workgroup: %s, calling name %s\n", neg_flags, workgroup, cli->calling.name)); /* and wrap it in a SPNEGO wrapper */ diff --git a/source3/libsmb/clispnego.c b/source3/libsmb/clispnego.c index 55f49c5987..3e28baa417 100644 --- a/source3/libsmb/clispnego.c +++ b/source3/libsmb/clispnego.c @@ -387,51 +387,6 @@ BOOL spnego_parse_challenge(DATA_BLOB blob, /* - generate a spnego NTLMSSP challenge packet given two security blobs - The second challenge is optional -*/ -BOOL spnego_gen_challenge(DATA_BLOB *blob, - DATA_BLOB *chal1, DATA_BLOB *chal2) -{ - ASN1_DATA data; - - ZERO_STRUCT(data); - - asn1_push_tag(&data,ASN1_CONTEXT(1)); - asn1_push_tag(&data,ASN1_SEQUENCE(0)); - - asn1_push_tag(&data,ASN1_CONTEXT(0)); - asn1_write_enumerated(&data,1); - asn1_pop_tag(&data); - - asn1_push_tag(&data,ASN1_CONTEXT(1)); - asn1_write_OID(&data, OID_NTLMSSP); - asn1_pop_tag(&data); - - asn1_push_tag(&data,ASN1_CONTEXT(2)); - asn1_write_OctetString(&data, chal1->data, chal1->length); - asn1_pop_tag(&data); - - /* the second challenge is optional (XP doesn't send it) */ - if (chal2) { - asn1_push_tag(&data,ASN1_CONTEXT(3)); - asn1_write_OctetString(&data, chal2->data, chal2->length); - asn1_pop_tag(&data); - } - - asn1_pop_tag(&data); - asn1_pop_tag(&data); - - if (data.has_error) { - return False; - } - - *blob = data_blob(data.data, data.length); - asn1_free(&data); - return True; -} - -/* generate a SPNEGO NTLMSSP auth packet. This will contain the encrypted passwords */ DATA_BLOB spnego_gen_auth(DATA_BLOB blob) @@ -485,18 +440,37 @@ BOOL spnego_parse_auth(DATA_BLOB blob, DATA_BLOB *auth) /* generate a minimal SPNEGO NTLMSSP response packet. Doesn't contain much. */ -DATA_BLOB spnego_gen_auth_response(void) +DATA_BLOB spnego_gen_auth_response(DATA_BLOB *ntlmssp_reply, NTSTATUS nt_status) { ASN1_DATA data; DATA_BLOB ret; + uint8 negResult; - memset(&data, 0, sizeof(data)); + if (NT_STATUS_IS_OK(nt_status)) { + negResult = SPNGEO_NEG_RESULT_ACCEPT; + } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + negResult = SPNGEO_NEG_RESULT_INCOMPLETE; + } else { + negResult = SPNGEO_NEG_RESULT_REJECT; + } + + ZERO_STRUCT(data); asn1_push_tag(&data, ASN1_CONTEXT(1)); asn1_push_tag(&data, ASN1_SEQUENCE(0)); asn1_push_tag(&data, ASN1_CONTEXT(0)); - asn1_write_enumerated(&data, 0); + asn1_write_enumerated(&data, negResult); asn1_pop_tag(&data); + if (negResult == SPNGEO_NEG_RESULT_INCOMPLETE) { + asn1_push_tag(&data,ASN1_CONTEXT(1)); + asn1_write_OID(&data, OID_NTLMSSP); + asn1_pop_tag(&data); + + asn1_push_tag(&data,ASN1_CONTEXT(2)); + asn1_write_OctetString(&data, ntlmssp_reply->data, ntlmssp_reply->length); + asn1_pop_tag(&data); + } + asn1_pop_tag(&data); asn1_pop_tag(&data); @@ -514,8 +488,9 @@ DATA_BLOB spnego_gen_auth_response(void) format specifiers are: U = unicode string (input is unix string) - a = address (1 byte type, 1 byte length, unicode string, all inline) - A = ASCII string (pointer + length) Actually same as B + a = address (input is BOOL unicode, char *unix_string) + (1 byte type, 1 byte length, unicode/ASCII string, all inline) + A = ASCII string (input is unix string) B = data blob (pointer + length) b = data blob in header (pointer + length) D @@ -531,6 +506,7 @@ BOOL msrpc_gen(DATA_BLOB *blob, uint8 *b; int head_size=0, data_size=0; int head_ofs, data_ofs; + BOOL unicode; /* first scan the format to work out the header and body size */ va_start(ap, format); @@ -541,12 +517,21 @@ BOOL msrpc_gen(DATA_BLOB *blob, head_size += 8; data_size += str_charnum(s) * 2; break; + case 'A': + s = va_arg(ap, char *); + head_size += 8; + data_size += str_ascii_charnum(s); + break; case 'a': + unicode = va_arg(ap, BOOL); n = va_arg(ap, int); s = va_arg(ap, char *); - data_size += (str_charnum(s) * 2) + 4; + if (unicode) { + data_size += (str_charnum(s) * 2) + 4; + } else { + data_size += (str_ascii_charnum(s)) + 4; + } break; - case 'A': case 'B': b = va_arg(ap, uint8 *); head_size += 8; @@ -586,20 +571,39 @@ BOOL msrpc_gen(DATA_BLOB *blob, push_string(NULL, blob->data+data_ofs, s, n*2, STR_UNICODE|STR_NOALIGN); data_ofs += n*2; break; + case 'A': + s = va_arg(ap, char *); + n = str_ascii_charnum(s); + SSVAL(blob->data, head_ofs, n); head_ofs += 2; + SSVAL(blob->data, head_ofs, n); head_ofs += 2; + SIVAL(blob->data, head_ofs, data_ofs); head_ofs += 4; + push_string(NULL, blob->data+data_ofs, s, n, STR_ASCII|STR_NOALIGN); + data_ofs += n; + break; case 'a': + unicode = va_arg(ap, BOOL); n = va_arg(ap, int); SSVAL(blob->data, data_ofs, n); data_ofs += 2; s = va_arg(ap, char *); - n = str_charnum(s); - SSVAL(blob->data, data_ofs, n*2); data_ofs += 2; - if (0 < n) { - push_string(NULL, blob->data+data_ofs, s, n*2, - STR_UNICODE|STR_NOALIGN); + if (unicode) { + n = str_charnum(s); + SSVAL(blob->data, data_ofs, n*2); data_ofs += 2; + if (0 < n) { + push_string(NULL, blob->data+data_ofs, s, n*2, + STR_UNICODE|STR_NOALIGN); + } + data_ofs += n*2; + } else { + n = str_ascii_charnum(s); + SSVAL(blob->data, data_ofs, n); data_ofs += 2; + if (0 < n) { + push_string(NULL, blob->data+data_ofs, s, n, + STR_ASCII|STR_NOALIGN); + } + data_ofs += n; } - data_ofs += n*2; break; - case 'A': case 'B': b = va_arg(ap, uint8 *); n = va_arg(ap, int); @@ -714,7 +718,7 @@ BOOL msrpc_parse(DATA_BLOB *blob, break; case 'C': s = va_arg(ap, char *); - head_ofs += pull_string(NULL, p, blob->data+head_ofs, -1, + head_ofs += pull_string(NULL, p, blob->data+head_ofs, sizeof(p), blob->length - head_ofs, STR_ASCII|STR_TERMINATE); if (strcmp(s, p) != 0) { diff --git a/source3/nmbd/nmbd_processlogon.c b/source3/nmbd/nmbd_processlogon.c index 39724921a4..a702fc3015 100644 --- a/source3/nmbd/nmbd_processlogon.c +++ b/source3/nmbd/nmbd_processlogon.c @@ -272,8 +272,8 @@ reporting %s domain %s 0x%x ntversion=%x lm_nt token=%x lm_20 token=%x\n", pull_ucs2_fstring(asccomp, unicomp); DEBUG(3,("process_logon_packet: SAMLOGON user %s\n", ascuser)); - fstrcpy(reply_name,"\\\\"); /* Here it wants \\LOGONSERVER. */ - fstrcpy(reply_name+2,my_name); + fstrcpy(reply_name, "\\\\"); /* Here it wants \\LOGONSERVER. */ + fstrcat(reply_name, my_name); DEBUG(3,("process_logon_packet: SAMLOGON request from %s(%s) for %s, returning logon svr %s domain %s code %x token=%x\n", asccomp,inet_ntoa(p->ip), ascuser, reply_name, lp_workgroup(), diff --git a/source3/nsswitch/winbindd.c b/source3/nsswitch/winbindd.c index e1bb7179e5..b70a4dd3b4 100644 --- a/source3/nsswitch/winbindd.c +++ b/source3/nsswitch/winbindd.c @@ -264,6 +264,7 @@ static struct dispatch_table dispatch_table[] = { { WINBINDD_INFO, winbindd_info, "INFO" }, { WINBINDD_INTERFACE_VERSION, winbindd_interface_version, "INTERFACE_VERSION" }, { WINBINDD_DOMAIN_NAME, winbindd_domain_name, "DOMAIN_NAME" }, + { WINBINDD_NETBIOS_NAME, winbindd_netbios_name, "NETBIOS_NAME" }, /* WINS functions */ diff --git a/source3/nsswitch/winbindd_misc.c b/source3/nsswitch/winbindd_misc.c index 6b7ef382dd..0b283812b2 100644 --- a/source3/nsswitch/winbindd_misc.c +++ b/source3/nsswitch/winbindd_misc.c @@ -221,3 +221,15 @@ enum winbindd_result winbindd_domain_name(struct winbindd_cli_state *state) return WINBINDD_OK; } + +/* What's my name again? */ + +enum winbindd_result winbindd_netbios_name(struct winbindd_cli_state *state) +{ + + DEBUG(3, ("[%5d]: request netbios name\n", state->pid)); + + fstrcpy(state->response.data.netbios_name, global_myname()); + + return WINBINDD_OK; +} diff --git a/source3/nsswitch/winbindd_nss.h b/source3/nsswitch/winbindd_nss.h index 5c2db2ac2c..2c87a77100 100644 --- a/source3/nsswitch/winbindd_nss.h +++ b/source3/nsswitch/winbindd_nss.h @@ -36,7 +36,7 @@ /* Update this when you change the interface. */ -#define WINBIND_INTERFACE_VERSION 6 +#define WINBIND_INTERFACE_VERSION 7 /* Socket commands */ @@ -102,6 +102,7 @@ enum winbindd_cmd { /* this is like GETGRENT but gives an empty group list */ WINBINDD_GETGRLST, + WINBINDD_NETBIOS_NAME, /* The netbios name of the server */ /* Placeholder for end of cmd list */ WINBINDD_NUM_CMDS @@ -221,6 +222,7 @@ struct winbindd_response { fstring samba_version; } info; fstring domain_name; + fstring netbios_name; struct auth_reply { uint32 nt_status; diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c index f8e8e017e0..679f040b2c 100644 --- a/source3/smbd/sesssetup.c +++ b/source3/smbd/sesssetup.c @@ -23,7 +23,8 @@ #include "includes.h" uint32 global_client_caps = 0; -static struct auth_context *ntlmssp_auth_context = NULL; + +static struct auth_ntlmssp_state *global_ntlmssp_state; /* on a logon error possibly map the error to success if "map to guest" @@ -68,6 +69,37 @@ static void add_signature(char *outbuf) } /**************************************************************************** +send a security blob via a session setup reply +****************************************************************************/ +static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf, + DATA_BLOB blob, NTSTATUS nt_status) +{ + char *p; + + set_message(outbuf,4,0,True); + + /* we set NT_STATUS_MORE_PROCESSING_REQUIRED to tell the other end + that we aren't finished yet */ + + nt_status = nt_status_squash(nt_status); + SIVAL(outbuf, smb_rcls, NT_STATUS_V(nt_status)); + SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */ + SSVAL(outbuf, smb_vwv3, blob.length); + p = smb_buf(outbuf); + + /* should we cap this? */ + memcpy(p, blob.data, blob.length); + p += blob.length; + + p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE); + p += srvstr_push(outbuf, p, "Samba", -1, STR_TERMINATE); + p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE); + set_message_end(outbuf,p); + + return send_smb(smbd_server_fd(),outbuf); +} + +/**************************************************************************** Do a 'guest' logon, getting back the ****************************************************************************/ static NTSTATUS check_guest_password(auth_serversupplied_info **server_info) @@ -209,30 +241,54 @@ static int reply_spnego_kerberos(connection_struct *conn, /**************************************************************************** -send a security blob via a session setup reply -****************************************************************************/ -static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf, - DATA_BLOB blob, uint32 errcode) + send a session setup reply, wrapped in SPNEGO. + get vuid and check first. + end the NTLMSSP exchange context if we are OK/complete fail +***************************************************************************/ +static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *outbuf, + AUTH_NTLMSSP_STATE **auth_ntlmssp_state, + DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status) { - char *p; + BOOL ret; + DATA_BLOB response; + struct auth_serversupplied_info *server_info; + server_info = (*auth_ntlmssp_state)->server_info; - set_message(outbuf,4,0,True); + if (!NT_STATUS_IS_OK(nt_status)) { + nt_status = do_map_to_guest(nt_status, + &server_info, + (*auth_ntlmssp_state)->ntlmssp_state->user, + (*auth_ntlmssp_state)->ntlmssp_state->domain); + } - /* we set NT_STATUS_MORE_PROCESSING_REQUIRED to tell the other end - that we aren't finished yet */ + if (NT_STATUS_IS_OK(nt_status)) { + int sess_vuid; + sess_vuid = register_vuid(server_info, (*auth_ntlmssp_state)->ntlmssp_state->user /* check this for weird */); + + if (sess_vuid == -1) { + nt_status = NT_STATUS_LOGON_FAILURE; + } else { + + set_message(outbuf,4,0,True); + SSVAL(outbuf, smb_vwv3, 0); + + if ((*auth_ntlmssp_state)->server_info->guest) { + SSVAL(outbuf,smb_vwv2,1); + } + + SSVAL(outbuf,smb_uid,sess_vuid); + } + } - SIVAL(outbuf, smb_rcls, errcode); - SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */ - SSVAL(outbuf, smb_vwv3, blob.length); - p = smb_buf(outbuf); - memcpy(p, blob.data, blob.length); - p += blob.length; - p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE); - p += srvstr_push(outbuf, p, "Samba", -1, STR_TERMINATE); - p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE); - set_message_end(outbuf,p); - - return send_smb(smbd_server_fd(),outbuf); + response = spnego_gen_auth_response(ntlmssp_blob, nt_status); + ret = reply_sesssetup_blob(conn, outbuf, response, nt_status); + data_blob_free(&response); + + if (!ret || !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + auth_ntlmssp_end(&global_ntlmssp_state); + } + + return ret; } /**************************************************************************** @@ -247,12 +303,9 @@ static int reply_spnego_negotiate(connection_struct *conn, char *OIDs[ASN1_MAX_OIDS]; DATA_BLOB secblob; int i; - uint32 ntlmssp_command, neg_flags, chal_flags; - DATA_BLOB chal, spnego_chal; - const uint8 *cryptkey; + DATA_BLOB chal; BOOL got_kerberos = False; NTSTATUS nt_status; - char *cliname=NULL, *domname=NULL; /* parse out the OIDs and the first sec blob */ if (!parse_negTokenTarg(blob1, OIDs, &secblob)) { @@ -278,95 +331,26 @@ static int reply_spnego_negotiate(connection_struct *conn, } #endif - /* parse the NTLMSSP packet */ -#if 0 - file_save("secblob.dat", secblob.data, secblob.length); -#endif - - if (!msrpc_parse(&secblob, "CddAA", - "NTLMSSP", - &ntlmssp_command, - &neg_flags, - &cliname, - &domname)) { - return ERROR_NT(NT_STATUS_LOGON_FAILURE); - } - - data_blob_free(&secblob); - - if (ntlmssp_command != NTLMSSP_NEGOTIATE) { - return ERROR_NT(NT_STATUS_LOGON_FAILURE); - } - - debug_ntlmssp_flags(neg_flags); - - if (ntlmssp_auth_context) { - (ntlmssp_auth_context->free)(&ntlmssp_auth_context); + if (global_ntlmssp_state) { + auth_ntlmssp_end(&global_ntlmssp_state); } - if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&ntlmssp_auth_context))) { + nt_status = auth_ntlmssp_start(&global_ntlmssp_state); + if (!NT_STATUS_IS_OK(nt_status)) { return ERROR_NT(nt_status); } - cryptkey = ntlmssp_auth_context->get_ntlm_challenge(ntlmssp_auth_context); - - /* Give them the challenge. For now, ignore neg_flags and just - return the flags we want. Obviously this is not correct */ - - chal_flags = NTLMSSP_NEGOTIATE_UNICODE | - NTLMSSP_NEGOTIATE_128 | - NTLMSSP_NEGOTIATE_NTLM | - NTLMSSP_CHAL_TARGET_INFO; - - { - DATA_BLOB domain_blob, struct_blob; - fstring dnsname, dnsdomname; - - msrpc_gen(&domain_blob, - "U", - lp_workgroup()); - - fstrcpy(dnsdomname, (SEC_ADS == lp_security())?lp_realm():""); - strlower(dnsdomname); - - fstrcpy(dnsname, global_myname()); - fstrcat(dnsname, "."); - fstrcat(dnsname, dnsdomname); - strlower(dnsname); - - msrpc_gen(&struct_blob, "aaaaa", - 2, lp_workgroup(), - 1, global_myname(), - 4, dnsdomname, - 3, dnsname, - 0, ""); - - msrpc_gen(&chal, "CdUdbddB", - "NTLMSSP", - NTLMSSP_CHALLENGE, - lp_workgroup(), - chal_flags, - cryptkey, 8, - 0, 0, - struct_blob.data, struct_blob.length); - - data_blob_free(&domain_blob); - data_blob_free(&struct_blob); - } - - if (!spnego_gen_challenge(&spnego_chal, &chal, &chal)) { - DEBUG(3,("Failed to generate challenge\n")); - data_blob_free(&chal); - return ERROR_NT(NT_STATUS_LOGON_FAILURE); - } + nt_status = auth_ntlmssp_update(global_ntlmssp_state, + secblob, &chal); - /* now tell the client to send the auth packet */ - reply_sesssetup_blob(conn, outbuf, spnego_chal, NT_STATUS_V(NT_STATUS_MORE_PROCESSING_REQUIRED)); + data_blob_free(&secblob); + reply_spnego_ntlmssp(conn, outbuf, &global_ntlmssp_state, + &chal, nt_status); + data_blob_free(&chal); - data_blob_free(&spnego_chal); - /* and tell smbd that we have already replied to this packet */ + /* already replied */ return -1; } @@ -378,23 +362,8 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf, int length, int bufsize, DATA_BLOB blob1) { - DATA_BLOB auth, response; - char *workgroup = NULL, *user = NULL, *machine = NULL; - DATA_BLOB lmhash, nthash, sess_key; - DATA_BLOB plaintext_password = data_blob(NULL, 0); - uint32 ntlmssp_command, neg_flags; + DATA_BLOB auth, auth_reply; NTSTATUS nt_status; - int sess_vuid; - BOOL as_guest; - uint32 auth_flags = AUTH_FLAG_NONE; - auth_usersupplied_info *user_info = NULL; - auth_serversupplied_info *server_info = NULL; - - /* we must have setup the auth context by now */ - if (!ntlmssp_auth_context) { - DEBUG(2,("ntlmssp_auth_context is NULL in reply_spnego_auth\n")); - return ERROR_NT(NT_STATUS_LOGON_FAILURE); - } if (!spnego_parse_auth(blob1, &auth)) { #if 0 @@ -403,107 +372,15 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf, return ERROR_NT(NT_STATUS_LOGON_FAILURE); } - /* now the NTLMSSP encoded auth hashes */ - if (!msrpc_parse(&auth, "CdBBUUUBd", - "NTLMSSP", - &ntlmssp_command, - &lmhash, - &nthash, - &workgroup, - &user, - &machine, - &sess_key, - &neg_flags)) { - return ERROR_NT(NT_STATUS_LOGON_FAILURE); - } + nt_status = auth_ntlmssp_update(global_ntlmssp_state, + auth, &auth_reply); data_blob_free(&auth); - data_blob_free(&sess_key); - - DEBUG(3,("Got user=[%s] workgroup=[%s] machine=[%s] len1=%d len2=%d\n", - user, workgroup, machine, lmhash.length, nthash.length)); - - /* the client has given us its machine name (which we otherwise would not get on port 445). - we need to possibly reload smb.conf if smb.conf includes depend on the machine name */ - - set_remote_machine_name(machine); - - /* setup the string used by %U */ - sub_set_smb_name(user); - - reload_services(True); - -#if 0 - file_save("nthash1.dat", nthash.data, nthash.length); - file_save("lmhash1.dat", lmhash.data, lmhash.length); -#endif - - if (lmhash.length) { - auth_flags |= AUTH_FLAG_LM_RESP; - } - - if (nthash.length == 24) { - auth_flags |= AUTH_FLAG_NTLM_RESP; - } else if (nthash.length > 24) { - auth_flags |= AUTH_FLAG_NTLMv2_RESP; - }; - - nt_status = make_user_info_map(&user_info, user, workgroup, machine, - lmhash, nthash, plaintext_password, - auth_flags, True); - - /* it looks a bit weird, but this function returns int type... */ - if (!NT_STATUS_IS_OK(nt_status)) { - return ERROR_NT(NT_STATUS_NO_MEMORY); - } - - nt_status = ntlmssp_auth_context->check_ntlm_password(ntlmssp_auth_context, user_info, &server_info); - - if (!NT_STATUS_IS_OK(nt_status)) { - nt_status = do_map_to_guest(nt_status, &server_info, user, workgroup); - } - - SAFE_FREE(workgroup); - SAFE_FREE(machine); - - (ntlmssp_auth_context->free)(&ntlmssp_auth_context); - - free_user_info(&user_info); - - data_blob_free(&lmhash); - - data_blob_free(&nthash); - - if (!NT_STATUS_IS_OK(nt_status)) { - SAFE_FREE(user); - return ERROR_NT(nt_status_squash(nt_status)); - } - - as_guest = server_info->guest; - - sess_vuid = register_vuid(server_info, user); - free_server_info(&server_info); - - SAFE_FREE(user); - - if (sess_vuid == -1) { - return ERROR_NT(NT_STATUS_LOGON_FAILURE); - } - - set_message(outbuf,4,0,True); - SSVAL(outbuf, smb_vwv3, 0); - if (as_guest) { - SSVAL(outbuf,smb_vwv2,1); - } - - add_signature(outbuf); - - SSVAL(outbuf,smb_uid,sess_vuid); - SSVAL(inbuf,smb_uid,sess_vuid); - - response = spnego_gen_auth_response(); - reply_sesssetup_blob(conn, outbuf, response, 0); + reply_spnego_ntlmssp(conn, outbuf, &global_ntlmssp_state, + &auth_reply, nt_status); + + data_blob_free(&auth_reply); /* and tell smbd that we have already replied to this packet */ return -1; @@ -511,49 +388,16 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf, /**************************************************************************** -reply to a session setup spnego anonymous packet -****************************************************************************/ -static int reply_spnego_anonymous(connection_struct *conn, char *inbuf, char *outbuf, - int length, int bufsize) -{ - int sess_vuid; - auth_serversupplied_info *server_info = NULL; - NTSTATUS nt_status; - - nt_status = check_guest_password(&server_info); - - if (!NT_STATUS_IS_OK(nt_status)) { - return ERROR_NT(nt_status_squash(nt_status)); - } - - sess_vuid = register_vuid(server_info, lp_guestaccount()); - - free_server_info(&server_info); - - if (sess_vuid == -1) { - return ERROR_NT(NT_STATUS_LOGON_FAILURE); - } - - set_message(outbuf,4,0,True); - SSVAL(outbuf, smb_vwv3, 0); - add_signature(outbuf); - - SSVAL(outbuf,smb_uid,sess_vuid); - SSVAL(inbuf,smb_uid,sess_vuid); - - return chain_reply(inbuf,outbuf,length,bufsize); -} - - -/**************************************************************************** reply to a session setup command ****************************************************************************/ -static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,char *outbuf, +static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf, + char *outbuf, int length,int bufsize) { uint8 *p; DATA_BLOB blob1; int ret; + size_t bufrem; DEBUG(3,("Doing spnego session setup\n")); @@ -564,12 +408,13 @@ static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,cha p = (uint8 *)smb_buf(inbuf); if (SVAL(inbuf, smb_vwv7) == 0) { - /* an anonymous request */ - return reply_spnego_anonymous(conn, inbuf, outbuf, length, bufsize); + /* an invalid request */ + return ERROR_NT(NT_STATUS_LOGON_FAILURE); } + bufrem = smb_bufrem(inbuf, p); /* pull the spnego blob */ - blob1 = data_blob(p, SVAL(inbuf, smb_vwv7)); + blob1 = data_blob(p, MIN(bufrem, SVAL(inbuf, smb_vwv7))); #if 0 file_save("negotiate.dat", blob1.data, blob1.length); @@ -786,6 +631,10 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf, nt_status = check_guest_password(&server_info); } else if (doencrypt) { + if (!negprot_global_auth_context) { + DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted session setup without negprot denied!\n")); + return ERROR_NT(NT_STATUS_LOGON_FAILURE); + } nt_status = make_user_info_for_reply_enc(&user_info, user, domain, lm_resp, nt_resp); if (NT_STATUS_IS_OK(nt_status)) { @@ -830,10 +679,8 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf, } /* it's ok - setup a reply */ - if (Protocol < PROTOCOL_NT1) { - set_message(outbuf,3,0,True); - } else { - set_message(outbuf,3,0,True); + set_message(outbuf,3,0,True); + if (Protocol >= PROTOCOL_NT1) { add_signature(outbuf); /* perhaps grab OS version here?? */ } diff --git a/source3/web/cgi.c b/source3/web/cgi.c index 018dd3602f..35f3266283 100644 --- a/source3/web/cgi.c +++ b/source3/web/cgi.c @@ -291,37 +291,6 @@ static void cgi_web_auth(void) passwd_free(&pwd); } -/*************************************************************************** -decode a base64 string in-place - simple and slow algorithm - ***************************************************************************/ -static void base64_decode(char *s) -{ - const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - int bit_offset, byte_offset, idx, i, n; - unsigned char *d = (unsigned char *)s; - char *p; - - n=i=0; - - while (*s && (p=strchr_m(b64,*s))) { - idx = (int)(p - b64); - byte_offset = (i*6)/8; - bit_offset = (i*6)%8; - d[byte_offset] &= ~((1<<(8-bit_offset))-1); - if (bit_offset < 3) { - d[byte_offset] |= (idx << (2-bit_offset)); - n = byte_offset+1; - } else { - d[byte_offset] |= (idx >> (bit_offset-2)); - d[byte_offset+1] = 0; - d[byte_offset+1] |= (idx << (8-(bit_offset-2))) & 0xFF; - n = byte_offset+2; - } - s++; i++; - } - /* null terminate */ - d[n] = 0; -} /*************************************************************************** handle a http authentication line |