diff options
-rw-r--r-- | source3/smbd/password.c | 41 | ||||
-rw-r--r-- | source3/smbd/sesssetup.c | 421 |
2 files changed, 271 insertions, 191 deletions
diff --git a/source3/smbd/password.c b/source3/smbd/password.c index 847b8db082..a1590f2a58 100644 --- a/source3/smbd/password.c +++ b/source3/smbd/password.c @@ -1,18 +1,19 @@ -/* +/* Unix SMB/CIFS implementation. Password and authentication handling Copyright (C) Andrew Tridgell 1992-1998 - + Copyright (C) Jeremy Allison 2007. + 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/>. */ @@ -76,7 +77,8 @@ static user_struct *get_valid_user_struct_internal(uint16 vuid, user_struct *get_valid_user_struct(uint16 vuid) { - return get_valid_user_struct_internal(vuid, SERVER_ALLOCATED_REQUIRED_YES); + return get_valid_user_struct_internal(vuid, + SERVER_ALLOCATED_REQUIRED_YES); } BOOL is_partial_auth_vuid(uint16 vuid) @@ -461,7 +463,8 @@ BOOL user_in_netgroup(const char *user, const char *ngname) yp_get_default_domain(&mydomain); if(mydomain == NULL) { - DEBUG(5,("Unable to get default yp domain, let's try without specifying it\n")); + DEBUG(5,("Unable to get default yp domain, " + "let's try without specifying it\n")); } DEBUG(5,("looking for user %s of domain %s in netgroup %s\n", @@ -479,7 +482,7 @@ BOOL user_in_netgroup(const char *user, const char *ngname) fstrcpy(lowercase_user, user); strlower_m(lowercase_user); - + DEBUG(5,("looking for user %s of domain %s in netgroup %s\n", lowercase_user, mydomain?mydomain:"(ANY)", ngname)); @@ -568,7 +571,7 @@ BOOL user_in_list(const char *user,const char **list) return True; } } - + list++; } return(False); @@ -654,7 +657,7 @@ static char *validate_group(char *group, DATA_BLOB password,int snum) endnetgrent(); } #endif - + #ifdef HAVE_GETGRENT { struct group *gptr; @@ -727,26 +730,26 @@ static char *validate_group(char *group, DATA_BLOB password,int snum) Note this is *NOT* used when logging on using sessionsetup_and_X. ****************************************************************************/ -BOOL authorise_login(int snum, fstring user, DATA_BLOB password, +BOOL authorise_login(int snum, fstring user, DATA_BLOB password, BOOL *guest) { BOOL ok = False; - + #ifdef DEBUG_PASSWORD DEBUG(100,("authorise_login: checking authorisation on " "user=%s pass=%s\n", user,password.data)); #endif *guest = False; - + /* there are several possibilities: 1) login as the given user with given password - 2) login as a previously registered username with the given + 2) login as a previously registered username with the given password 3) login as a session list username with the given password 4) login as a previously validated user/password pair 5) login as the "user =" user with given password - 6) login as the "user =" user with no password + 6) login as the "user =" user with no password (guest connection) 7) login as guest user with no password @@ -765,14 +768,14 @@ BOOL authorise_login(int snum, fstring user, DATA_BLOB password, if (!user_list) return(False); - + for (auser=strtok(user_list,LIST_SEP); !ok && auser; auser = strtok(NULL,LIST_SEP)) { fstring user2; fstrcpy(user2,auser); if (!user_ok(user2,snum)) continue; - + if (password_ok(user2,password)) { ok = True; fstrcpy(user,user2); @@ -784,15 +787,15 @@ BOOL authorise_login(int snum, fstring user, DATA_BLOB password, SAFE_FREE(user_list); } - + /* check the user= fields and the given password */ if (!ok && lp_username(snum)) { char *auser; pstring user_list; pstrcpy(user_list,lp_username(snum)); - + pstring_sub(user_list,"%S",lp_servicename(snum)); - + for (auser=strtok(user_list,LIST_SEP); auser && !ok; auser = strtok(NULL,LIST_SEP)) { if (*auser == '@') { diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c index e63511c368..4c45806b02 100644 --- a/source3/smbd/sesssetup.c +++ b/source3/smbd/sesssetup.c @@ -6,17 +6,18 @@ Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002 Copyright (C) Luke Howard 2003 Copyright (C) Volker Lendecke 2007 + Copyright (C) Jeremy Allison 2007 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/>. */ @@ -35,11 +36,12 @@ uint32 global_client_caps = 0; on a logon error possibly map the error to success if "map to guest" is set approriately */ -static NTSTATUS do_map_to_guest(NTSTATUS status, auth_serversupplied_info **server_info, +static NTSTATUS do_map_to_guest(NTSTATUS status, + auth_serversupplied_info **server_info, const char *user, const char *domain) { if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) { - if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) || + if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) || (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) { DEBUG(3,("No such user %s [%s] - using guest account\n", user, domain)); @@ -49,7 +51,8 @@ static NTSTATUS do_map_to_guest(NTSTATUS status, auth_serversupplied_info **serv if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) { if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) { - DEBUG(3,("Registered username %s for guest access\n",user)); + DEBUG(3,("Registered username %s for guest access\n", + user)); status = make_server_info_guest(server_info); } } @@ -96,8 +99,9 @@ static int push_signature(uint8 **outbuf) Start the signing engine if needed. Don't fail signing here. ****************************************************************************/ -static void sessionsetup_start_signing_engine(const auth_serversupplied_info *server_info, - const uint8 *inbuf) +static void sessionsetup_start_signing_engine( + const auth_serversupplied_info *server_info, + const uint8 *inbuf) { if (!server_info->guest && !srv_signing_started()) { /* We need to start the signing engine @@ -106,7 +110,7 @@ static void sessionsetup_start_signing_engine(const auth_serversupplied_info *se * correct one. Subsequent packets will * be correct. */ - srv_check_sign_mac((char *)inbuf, False); + srv_check_sign_mac((char *)inbuf, False); } } @@ -140,14 +144,14 @@ static void reply_sesssetup_blob(connection_struct *conn, } /**************************************************************************** - Do a 'guest' logon, getting back the + Do a 'guest' logon, getting back the ****************************************************************************/ -static NTSTATUS check_guest_password(auth_serversupplied_info **server_info) +static NTSTATUS check_guest_password(auth_serversupplied_info **server_info) { struct auth_context *auth_context; auth_usersupplied_info *user_info = NULL; - + NTSTATUS nt_status; unsigned char chal[8]; @@ -155,7 +159,8 @@ static NTSTATUS check_guest_password(auth_serversupplied_info **server_info) DEBUG(3,("Got anonymous request\n")); - if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context, chal))) { + if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context, + chal))) { return nt_status; } @@ -163,8 +168,10 @@ static NTSTATUS check_guest_password(auth_serversupplied_info **server_info) (auth_context->free)(&auth_context); return NT_STATUS_NO_MEMORY; } - - nt_status = auth_context->check_ntlm_password(auth_context, user_info, server_info); + + nt_status = auth_context->check_ntlm_password(auth_context, + user_info, + server_info); (auth_context->free)(&auth_context); free_user_info(&user_info); return nt_status; @@ -204,14 +211,17 @@ static BOOL make_krb5_skew_error(DATA_BLOB *pblob_out) kerr = smb_krb5_parse_name(context, host_princ_s, &host_princ); if (kerr) { - DEBUG(10,("make_krb5_skew_error: smb_krb5_parse_name failed for name %s: Error %s\n", + DEBUG(10,("make_krb5_skew_error: smb_krb5_parse_name failed " + "for name %s: Error %s\n", host_princ_s, error_message(kerr) )); goto out; } - - kerr = smb_krb5_mk_error(context, KRB5KRB_AP_ERR_SKEW, host_princ, &reply); + + kerr = smb_krb5_mk_error(context, KRB5KRB_AP_ERR_SKEW, + host_princ, &reply); if (kerr) { - DEBUG(10,("make_krb5_skew_error: smb_krb5_mk_error failed: Error %s\n", + DEBUG(10,("make_krb5_skew_error: smb_krb5_mk_error " + "failed: Error %s\n", error_message(kerr) )); goto out; } @@ -283,39 +293,46 @@ static void reply_spnego_kerberos(connection_struct *conn, return; } - ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket, - &client, &pac_data, &ap_rep, + ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket, + &client, &pac_data, &ap_rep, &session_key, True); data_blob_free(&ticket); if (!NT_STATUS_IS_OK(ret)) { #if 0 - /* Experiment that failed. See "only happens with a KDC" comment below. */ + /* Experiment that failed. + * See "only happens with a KDC" comment below. */ if (NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) { /* - * Windows in this case returns NT_STATUS_MORE_PROCESSING_REQUIRED - * with a negTokenTarg blob containing an krb5_error struct ASN1 encoded - * containing KRB5KRB_AP_ERR_SKEW. The client then fixes its - * clock and continues rather than giving an error. JRA. + * Windows in this case returns + * NT_STATUS_MORE_PROCESSING_REQUIRED + * with a negTokenTarg blob containing an krb5_error + * struct ASN1 encoded containing KRB5KRB_AP_ERR_SKEW. + * The client then fixes its clock and continues rather + * than giving an error. JRA. * -- Looks like this only happens with a KDC. JRA. */ BOOL ok = make_krb5_skew_error(&ap_rep); if (!ok) { talloc_destroy(mem_ctx); - return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE)); + return ERROR_NT(nt_status_squash( + NT_STATUS_LOGON_FAILURE)); } - ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_ERROR); - response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD); - reply_sesssetup_blob(conn, inbuf, outbuf, response, NT_STATUS_MORE_PROCESSING_REQUIRED); + ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, + TOK_ID_KRB_ERROR); + response = spnego_gen_auth_response(&ap_rep_wrapped, + ret, OID_KERBEROS5_OLD); + reply_sesssetup_blob(conn, inbuf, outbuf, response, + NT_STATUS_MORE_PROCESSING_REQUIRED); /* - * In this one case we don't invalidate the intermediate vuid. - * as we're expecting the client to re-use it for the next - * sessionsetupX packet. JRA. + * In this one case we don't invalidate the + * intermediate vuid as we're expecting the client + * to re-use it for the next sessionsetupX packet. JRA. */ *p_invalidate_vuid = False; @@ -331,7 +348,8 @@ static void reply_spnego_kerberos(connection_struct *conn, ret = NT_STATUS_LOGON_FAILURE; } #endif - DEBUG(1,("Failed to verify incoming ticket with error %s!\n", nt_errstr(ret))); + DEBUG(1,("Failed to verify incoming ticket with error %s!\n", + nt_errstr(ret))); talloc_destroy(mem_ctx); reply_nterror(req, nt_status_squash(ret)); return; @@ -380,8 +398,9 @@ static void reply_spnego_kerberos(connection_struct *conn, domain = p+1; if (logon_info && logon_info->info3.hdr_logon_dom.uni_str_len) { - - unistr2_to_ascii(netbios_domain_name, &logon_info->info3.uni_logon_dom, -1); + unistr2_to_ascii(netbios_domain_name, + &logon_info->info3.uni_logon_dom, + -1); domain = netbios_domain_name; DEBUG(10, ("Mapped to [%s] (using PAC)\n", domain)); @@ -422,7 +441,7 @@ static void reply_spnego_kerberos(connection_struct *conn, } fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client); - + /* lookup the passwd struct, create a new user if necessary */ username_was_mapped = map_username( user ); @@ -435,7 +454,8 @@ static void reply_spnego_kerberos(connection_struct *conn, /* do this before an eventual mappign to guest occurs */ ret = smb_pam_accountcheck(pw->pw_name); if ( !NT_STATUS_IS_OK(ret)) { - DEBUG(1, ("PAM account restriction prevents user login\n")); + DEBUG(1,("PAM account restriction " + "prevents user login\n")); data_blob_free(&ap_rep); data_blob_free(&session_key); TALLOC_FREE(mem_ctx); @@ -447,19 +467,20 @@ static void reply_spnego_kerberos(connection_struct *conn, if (!pw) { /* this was originally the behavior of Samba 2.2, if a user - did not have a local uid but has been authenticated, then + did not have a local uid but has been authenticated, then map them to a guest account */ - if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){ + if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){ map_domainuser_to_guest = True; fstrcpy(user,lp_guestaccount()); pw = smb_getpwnam( mem_ctx, user, real_username, True ); - } + } /* extra sanity check that the guest account is valid */ if ( !pw ) { - DEBUG(1,("Username %s is invalid on this system\n", user)); + DEBUG(1,("Username %s is invalid on this system\n", + user)); SAFE_FREE(client); data_blob_free(&ap_rep); data_blob_free(&session_key); @@ -471,17 +492,17 @@ static void reply_spnego_kerberos(connection_struct *conn, } /* setup the string used by %U */ - + sub_set_smb_name( real_username ); reload_services(True); if ( map_domainuser_to_guest ) { make_server_info_guest(&server_info); } else if (logon_info) { - /* pass the unmapped username here since map_username() + /* pass the unmapped username here since map_username() will be called again from inside make_server_info_info3() */ - - ret = make_server_info_info3(mem_ctx, client, domain, + + ret = make_server_info_info3(mem_ctx, client, domain, &server_info, &logon_info->info3); if ( !NT_STATUS_IS_OK(ret) ) { DEBUG(1,("make_server_info_info3 failed: %s!\n", @@ -513,15 +534,16 @@ static void reply_spnego_kerberos(connection_struct *conn, * %D. */ if (server_info->sam_account != NULL) { - pdb_set_domain(server_info->sam_account, domain, PDB_SET); + pdb_set_domain(server_info->sam_account, + domain, PDB_SET); } } server_info->was_mapped |= username_was_mapped; - + /* we need to build the token for the user. make_server_info_guest() already does this */ - + if ( !server_info->ptok ) { ret = create_local_token( server_info ); if ( !NT_STATUS_IS_OK(ret) ) { @@ -562,11 +584,11 @@ static void reply_spnego_kerberos(connection_struct *conn, reload_services( True ); SSVAL(req->outbuf, smb_vwv3, 0); - + if (server_info->guest) { SSVAL(req->outbuf,smb_vwv2,1); } - + SSVAL(req->outbuf, smb_uid, sess_vuid); sessionsetup_start_signing_engine(server_info, req->inbuf); @@ -576,11 +598,13 @@ static void reply_spnego_kerberos(connection_struct *conn, /* wrap that up in a nice GSS-API wrapping */ if (NT_STATUS_IS_OK(ret)) { - ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_AP_REP); + ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, + TOK_ID_KRB_AP_REP); } else { ap_rep_wrapped = data_blob_null; } - response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD); + response = spnego_gen_auth_response(&ap_rep_wrapped, ret, + OID_KERBEROS5_OLD); reply_sesssetup_blob(conn, req, response, ret); data_blob_free(&ap_rep); @@ -612,10 +636,10 @@ static void reply_spnego_ntlmssp(connection_struct *conn, if (NT_STATUS_IS_OK(nt_status)) { server_info = (*auth_ntlmssp_state)->server_info; } else { - nt_status = do_map_to_guest(nt_status, - &server_info, - (*auth_ntlmssp_state)->ntlmssp_state->user, - (*auth_ntlmssp_state)->ntlmssp_state->domain); + nt_status = do_map_to_guest(nt_status, + &server_info, + (*auth_ntlmssp_state)->ntlmssp_state->user, + (*auth_ntlmssp_state)->ntlmssp_state->domain); } reply_outbuf(req, 4, 0); @@ -624,7 +648,10 @@ static void reply_spnego_ntlmssp(connection_struct *conn, if (NT_STATUS_IS_OK(nt_status)) { DATA_BLOB nullblob = data_blob_null; - DATA_BLOB session_key = data_blob((*auth_ntlmssp_state)->ntlmssp_state->session_key.data, (*auth_ntlmssp_state)->ntlmssp_state->session_key.length); + DATA_BLOB session_key = + data_blob( + (*auth_ntlmssp_state)->ntlmssp_state->session_key.data, + (*auth_ntlmssp_state)->ntlmssp_state->session_key.length); if (!is_partial_auth_vuid(vuid)) { data_blob_free(&session_key); @@ -661,7 +688,8 @@ static void reply_spnego_ntlmssp(connection_struct *conn, out: if (wrap) { - response = spnego_gen_auth_response(ntlmssp_blob, nt_status, OID_NTLMSSP); + response = spnego_gen_auth_response(ntlmssp_blob, + nt_status, OID_NTLMSSP); } else { response = *ntlmssp_blob; } @@ -688,7 +716,8 @@ static void reply_spnego_ntlmssp(connection_struct *conn, Is this a krb5 mechanism ? ****************************************************************************/ -NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in, DATA_BLOB *pblob_out, BOOL *p_is_krb5) +NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in, DATA_BLOB *pblob_out, + BOOL *p_is_krb5) { char *OIDs[ASN1_MAX_OIDS]; int i; @@ -701,22 +730,22 @@ NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in, DATA_BLOB *pblob_out, BOOL * } /* only look at the first OID for determining the mechToken -- - accoirding to RFC2478, we should choose the one we want - and renegotiate, but i smell a client bug here.. - - Problem observed when connecting to a member (samba box) - of an AD domain as a user in a Samba domain. Samba member - server sent back krb5/mskrb5/ntlmssp as mechtypes, but the - client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an + according to RFC2478, we should choose the one we want + and renegotiate, but i smell a client bug here.. + + Problem observed when connecting to a member (samba box) + of an AD domain as a user in a Samba domain. Samba member + server sent back krb5/mskrb5/ntlmssp as mechtypes, but the + client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an NTLMSSP mechtoken. --jerry */ -#ifdef HAVE_KRB5 +#ifdef HAVE_KRB5 if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 || strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) { *p_is_krb5 = True; } #endif - + for (i=0;OIDs[i];i++) { DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i])); free(OIDs[i]); @@ -739,7 +768,8 @@ static void reply_spnego_negotiate(connection_struct *conn, BOOL got_kerberos_mechanism = False; NTSTATUS status; - status = parse_spnego_mechanisms(blob1, &secblob, &got_kerberos_mechanism); + status = parse_spnego_mechanisms(blob1, &secblob, + &got_kerberos_mechanism); if (!NT_STATUS_IS_OK(status)) { /* Kill the intermediate vuid */ invalidate_vuid(vuid); @@ -747,10 +777,12 @@ static void reply_spnego_negotiate(connection_struct *conn, return; } - DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n", (unsigned long)secblob.length)); + DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n", + (unsigned long)secblob.length)); #ifdef HAVE_KRB5 - if ( got_kerberos_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) { + if ( got_kerberos_mechanism && ((lp_security()==SEC_ADS) || + lp_use_kerberos_keytab()) ) { BOOL destroy_vuid = True; reply_spnego_kerberos(conn, req, &secblob, vuid, &destroy_vuid); @@ -775,7 +807,7 @@ static void reply_spnego_negotiate(connection_struct *conn, return; } - status = auth_ntlmssp_update(*auth_ntlmssp_state, + status = auth_ntlmssp_update(*auth_ntlmssp_state, secblob, &chal); data_blob_free(&secblob); @@ -820,11 +852,14 @@ static void reply_spnego_auth(connection_struct *conn, /* Might be a second negTokenTarg packet */ BOOL got_krb5_mechanism = False; - status = parse_spnego_mechanisms(auth, &secblob, &got_krb5_mechanism); + status = parse_spnego_mechanisms(auth, &secblob, + &got_krb5_mechanism); if (NT_STATUS_IS_OK(status)) { - DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n", (unsigned long)secblob.length)); + DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n", + (unsigned long)secblob.length)); #ifdef HAVE_KRB5 - if ( got_krb5_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) { + if ( got_krb5_mechanism && ((lp_security()==SEC_ADS) || + lp_use_kerberos_keytab()) ) { BOOL destroy_vuid = True; reply_spnego_kerberos(conn, req, &secblob, vuid, &destroy_vuid); @@ -842,7 +877,7 @@ static void reply_spnego_auth(connection_struct *conn, /* If we get here it wasn't a negTokenTarg auth packet. */ data_blob_free(&secblob); - + if (!*auth_ntlmssp_state) { /* Kill the intermediate vuid */ invalidate_vuid(vuid); @@ -852,8 +887,8 @@ static void reply_spnego_auth(connection_struct *conn, NT_STATUS_INVALID_PARAMETER)); return; } - - status = auth_ntlmssp_update(*auth_ntlmssp_state, + + status = auth_ntlmssp_update(*auth_ntlmssp_state, auth, &auth_reply); data_blob_free(&auth); @@ -861,7 +896,7 @@ static void reply_spnego_auth(connection_struct *conn, reply_spnego_ntlmssp(conn, req, vuid, auth_ntlmssp_state, &auth_reply, status, True); - + data_blob_free(&auth_reply); /* and tell smbd that we have already replied to this packet */ @@ -905,11 +940,13 @@ static struct pending_auth_data *get_pending_auth_data(uint16 smbpid) } /**************************************************************************** - Check the size of an SPNEGO blob. If we need more return NT_STATUS_MORE_PROCESSING_REQUIRED, - else return NT_STATUS_OK. Don't allow the blob to be more than 64k. + Check the size of an SPNEGO blob. If we need more return + NT_STATUS_MORE_PROCESSING_REQUIRED, else return NT_STATUS_OK. Don't allow + the blob to be more than 64k. ****************************************************************************/ -static NTSTATUS check_spnego_blob_complete(uint16 smbpid, uint16 vuid, DATA_BLOB *pblob) +static NTSTATUS check_spnego_blob_complete(uint16 smbpid, uint16 vuid, + DATA_BLOB *pblob) { struct pending_auth_data *pad = NULL; ASN1_DATA data; @@ -932,7 +969,8 @@ static NTSTATUS check_spnego_blob_complete(uint16 smbpid, uint16 vuid, DATA_BLOB /* Integer wrap paranoia.... */ - if (pad->partial_data.length + copy_len < pad->partial_data.length || + if (pad->partial_data.length + copy_len < + pad->partial_data.length || pad->partial_data.length + copy_len < copy_len) { DEBUG(2,("check_spnego_blob_complete: integer wrap " @@ -1039,7 +1077,8 @@ static NTSTATUS check_spnego_blob_complete(uint16 smbpid, uint16 vuid, DATA_BLOB /* Refuse the blob if it's bigger than 64k. */ if (needed_len > 65536) { - DEBUG(2,("check_spnego_blob_complete: needed_len too large (%u)\n", + DEBUG(2,("check_spnego_blob_complete: needed_len " + "too large (%u)\n", (unsigned int)needed_len )); return NT_STATUS_INVALID_PARAMETER; } @@ -1092,7 +1131,7 @@ static void reply_sesssetup_and_X_spnego(connection_struct *conn, } } - + p = (uint8 *)smb_buf(req->inbuf); if (data_blob_len == 0) { @@ -1116,7 +1155,7 @@ static void reply_sesssetup_and_X_spnego(connection_struct *conn, sizeof(native_lanman), STR_TERMINATE); p2 += srvstr_pull_buf(req->inbuf, smb_flag2, primary_domain, p2, sizeof(primary_domain), STR_TERMINATE); - DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n", + DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n", native_os, native_lanman, primary_domain)); if ( ra_type == RA_WIN2K ) { @@ -1124,24 +1163,25 @@ static void reply_sesssetup_and_X_spnego(connection_struct *conn, if ( !strlen(native_os) && !strlen(native_lanman) ) set_remote_arch(RA_VISTA); - - /* Windows 2003 doesn't set the native lanman string, + + /* Windows 2003 doesn't set the native lanman string, but does set primary domain which is a bug I think */ - + if ( !strlen(native_lanman) ) { ra_lanman_string( primary_domain ); } else { ra_lanman_string( native_lanman ); } } - + /* Did we get a valid vuid ? */ if (!is_partial_auth_vuid(vuid)) { /* No, then try and see if this is an intermediate sessionsetup * for a large SPNEGO packet. */ struct pending_auth_data *pad = get_pending_auth_data(smbpid); if (pad) { - DEBUG(10,("reply_sesssetup_and_X_spnego: found pending vuid %u\n", + DEBUG(10,("reply_sesssetup_and_X_spnego: found " + "pending vuid %u\n", (unsigned int)pad->vuid )); vuid = pad->vuid; } @@ -1172,7 +1212,8 @@ static void reply_sesssetup_and_X_spnego(connection_struct *conn, status = check_spnego_blob_complete(smbpid, vuid, &blob1); if (!NT_STATUS_IS_OK(status)) { - if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { + if (!NT_STATUS_EQUAL(status, + NT_STATUS_MORE_PROCESSING_REQUIRED)) { /* Real error - kill the intermediate vuid */ invalidate_vuid(vuid); } @@ -1217,9 +1258,9 @@ static void reply_sesssetup_and_X_spnego(connection_struct *conn, status = auth_ntlmssp_update(vuser->auth_ntlmssp_state, blob1, &chal); - + data_blob_free(&blob1); - + reply_spnego_ntlmssp(conn, req, vuid, &vuser->auth_ntlmssp_state, &chal, status, False); @@ -1267,7 +1308,8 @@ static int shutdown_other_smbds(struct db_record *rec, static void setup_new_vc_session(void) { - DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x compatible we would close all old resources.\n")); + DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x " + "compatible we would close all old resources.\n")); #if 0 conn_close_all(); invalidate_all_vuids(); @@ -1284,7 +1326,7 @@ static void setup_new_vc_session(void) void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req) { int sess_vuid; - int smb_bufsize; + int smb_bufsize; DATA_BLOB lm_resp; DATA_BLOB nt_resp; DATA_BLOB plaintext_password; @@ -1305,8 +1347,6 @@ void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req) DATA_BLOB session_key; - - START_PROFILE(SMBsesssetupX); ZERO_STRUCT(lm_resp); @@ -1326,6 +1366,7 @@ void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req) "negotiated.\n")); reply_nterror(req, nt_status_squash( NT_STATUS_LOGON_FAILURE)); + END_PROFILE(SMBsesssetupX); return; } @@ -1334,7 +1375,7 @@ void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req) } reply_sesssetup_and_X_spnego(conn, req); - + END_PROFILE(SMBsesssetupX); return; } @@ -1343,7 +1384,8 @@ void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req) if (Protocol < PROTOCOL_NT1) { uint16 passlen1 = SVAL(req->inbuf,smb_vwv7); - /* Never do NT status codes with protocols before NT1 as we don't get client caps. */ + /* Never do NT status codes with protocols before NT1 as we + * don't get client caps. */ remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES); if ((passlen1 > MAX_PASS_LEN) @@ -1351,6 +1393,7 @@ void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req) smb_buf(req->inbuf)))) { reply_nterror(req, nt_status_squash( NT_STATUS_INVALID_PARAMETER)); + END_PROFILE(SMBsesssetupX); return; } @@ -1375,49 +1418,55 @@ void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req) char *p = smb_buf(req->inbuf); char *save_p = smb_buf(req->inbuf); uint16 byte_count; - + if(global_client_caps == 0) { global_client_caps = IVAL(req->inbuf,smb_vwv11); - + if (!(global_client_caps & CAP_STATUS32)) { - remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES); + remove_from_common_flags2( + FLAGS2_32_BIT_ERROR_CODES); } - /* client_caps is used as final determination if client is NT or Win95. - This is needed to return the correct error codes in some - circumstances. + /* client_caps is used as final determination if + * client is NT or Win95. This is needed to return + * the correct error codes in some circumstances. */ - - if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) { - if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) { + + if(ra_type == RA_WINNT || ra_type == RA_WIN2K || + ra_type == RA_WIN95) { + if(!(global_client_caps & (CAP_NT_SMBS| + CAP_STATUS32))) { set_remote_arch( RA_WIN95); } } } if (!doencrypt) { - /* both Win95 and WinNT stuff up the password lengths for - non-encrypting systems. Uggh. - - if passlen1==24 its a win95 system, and its setting the - password length incorrectly. Luckily it still works with the - default code because Win95 will null terminate the password - anyway - - if passlen1>0 and passlen2>0 then maybe its a NT box and its - setting passlen2 to some random value which really stuffs - things up. we need to fix that one. */ - - if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1) + /* both Win95 and WinNT stuff up the password + * lengths for non-encrypting systems. Uggh. + + if passlen1==24 its a win95 system, and its setting + the password length incorrectly. Luckily it still + works with the default code because Win95 will null + terminate the password anyway + + if passlen1>0 and passlen2>0 then maybe its a NT box + and its setting passlen2 to some random value which + really stuffs things up. we need to fix that one. */ + + if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && + passlen2 != 1) { passlen2 = 0; + } } - + /* check for nasty tricks */ if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(req->inbuf, p)) { reply_nterror(req, nt_status_squash( NT_STATUS_INVALID_PARAMETER)); + END_PROFILE(SMBsesssetupX); return; } @@ -1425,11 +1474,12 @@ void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req) || passlen2 > smb_bufrem(req->inbuf, p+passlen1)) { reply_nterror(req, nt_status_squash( NT_STATUS_INVALID_PARAMETER)); + END_PROFILE(SMBsesssetupX); return; } /* Save the lanman2 password and the NT md4 password. */ - + if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) { doencrypt = False; } @@ -1442,9 +1492,12 @@ void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req) BOOL unic= smb_flag2 & FLAGS2_UNICODE_STRINGS; #if 0 - /* This was the previous fix. Not sure if it's still valid. JRA. */ - if ((ra_type == RA_WINNT) && (passlen2 == 0) && unic && passlen1) { - /* NT4.0 stuffs up plaintext unicode password lengths... */ + /* This was the previous fix. Not sure if it's still + * valid. JRA. */ + if ((ra_type == RA_WINNT) && (passlen2 == 0) + && unic && passlen1) { + /* NT4.0 stuffs up plaintext unicode password + * lengths... */ srvstr_pull(inbuf, pass, smb_buf(inbuf) + 1, sizeof(pass), passlen1, STR_TERMINATE); #endif @@ -1462,7 +1515,7 @@ void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req) } plaintext_password = data_blob(pass, strlen(pass)+1); } - + p += passlen1 + passlen2; p += srvstr_pull_buf(req->inbuf, req->flags2, user, p, sizeof(user), STR_TERMINATE); @@ -1474,23 +1527,26 @@ void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req) native_lanman, p, sizeof(native_lanman), STR_TERMINATE); - /* not documented or decoded by Ethereal but there is one more string - in the extra bytes which is the same as the PrimaryDomain when using - extended security. Windows NT 4 and 2003 use this string to store - the native lanman string. Windows 9x does not include a string here - at all so we have to check if we have any extra bytes left */ - + /* not documented or decoded by Ethereal but there is one more + * string in the extra bytes which is the same as the + * PrimaryDomain when using extended security. Windows NT 4 + * and 2003 use this string to store the native lanman string. + * Windows 9x does not include a string here at all so we have + * to check if we have any extra bytes left */ + byte_count = SVAL(req->inbuf, smb_vwv13); - if ( PTR_DIFF(p, save_p) < byte_count) + if ( PTR_DIFF(p, save_p) < byte_count) { p += srvstr_pull_buf(req->inbuf, req->flags2, primary_domain, p, sizeof(primary_domain), STR_TERMINATE); - else + } else { fstrcpy( primary_domain, "null" ); + } - DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n", - domain, native_os, native_lanman, primary_domain)); + DEBUG(3,("Domain=[%s] NativeOS=[%s] NativeLanMan=[%s] " + "PrimaryDomain=[%s]\n", + domain, native_os, native_lanman, primary_domain)); if ( ra_type == RA_WIN2K ) { if ( strlen(native_lanman) == 0 ) @@ -1505,16 +1561,21 @@ void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req) setup_new_vc_session(); } - DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name())); + DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", + domain, user, get_remote_machine_name())); if (*user) { if (global_spnego_negotiated) { - - /* This has to be here, because this is a perfectly valid behaviour for guest logons :-( */ - - DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt at 'normal' session setup after negotiating spnego.\n")); + + /* This has to be here, because this is a perfectly + * valid behaviour for guest logons :-( */ + + DEBUG(0,("reply_sesssetup_and_X: Rejecting attempt " + "at 'normal' session setup after " + "negotiating spnego.\n")); reply_nterror(req, nt_status_squash( NT_STATUS_LOGON_FAILURE)); + END_PROFILE(SMBsesssetupX); return; } fstrcpy(sub_user, user); @@ -1525,7 +1586,7 @@ void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req) sub_set_smb_name(sub_user); reload_services(True); - + if (lp_security() == SEC_SHARE) { /* in share level we should ignore any passwords */ @@ -1539,67 +1600,79 @@ void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req) /* Then force it to null for the benfit of the code below */ *user = 0; } - + if (!*user) { 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")); + DEBUG(0, ("reply_sesssetup_and_X: Attempted encrypted " + "session setup without negprot denied!\n")); reply_nterror(req, nt_status_squash( NT_STATUS_LOGON_FAILURE)); + END_PROFILE(SMBsesssetupX); return; } - nt_status = make_user_info_for_reply_enc(&user_info, user, domain, - lm_resp, nt_resp); + nt_status = make_user_info_for_reply_enc(&user_info, user, + domain, + lm_resp, nt_resp); if (NT_STATUS_IS_OK(nt_status)) { - nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context, - user_info, - &server_info); + nt_status = negprot_global_auth_context->check_ntlm_password( + negprot_global_auth_context, + user_info, + &server_info); } } else { struct auth_context *plaintext_auth_context = NULL; const uint8 *chal; - nt_status = make_auth_context_subsystem(&plaintext_auth_context); + nt_status = make_auth_context_subsystem( + &plaintext_auth_context); if (NT_STATUS_IS_OK(nt_status)) { - chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context); - - if (!make_user_info_for_reply(&user_info, + chal = plaintext_auth_context->get_ntlm_challenge( + plaintext_auth_context); + + if (!make_user_info_for_reply(&user_info, user, domain, chal, plaintext_password)) { nt_status = NT_STATUS_NO_MEMORY; } - + if (NT_STATUS_IS_OK(nt_status)) { - nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context, - user_info, - &server_info); - - (plaintext_auth_context->free)(&plaintext_auth_context); + nt_status = plaintext_auth_context->check_ntlm_password( + plaintext_auth_context, + user_info, + &server_info); + + (plaintext_auth_context->free)( + &plaintext_auth_context); } } } free_user_info(&user_info); - + if (!NT_STATUS_IS_OK(nt_status)) { - nt_status = do_map_to_guest(nt_status, &server_info, user, domain); + nt_status = do_map_to_guest(nt_status, &server_info, + user, domain); } - + if (!NT_STATUS_IS_OK(nt_status)) { data_blob_free(&nt_resp); data_blob_free(&lm_resp); data_blob_clear_free(&plaintext_password); reply_nterror(req, nt_status_squash(nt_status)); + END_PROFILE(SMBsesssetupX); return; } - /* Ensure we can't possible take a code path leading to a null defref. */ + /* Ensure we can't possible take a code path leading to a + * null defref. */ if (!server_info) { reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE)); + END_PROFILE(SMBsesssetupX); return; } @@ -1611,24 +1684,26 @@ void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req) data_blob_free(&lm_resp); data_blob_clear_free(&plaintext_password); reply_nterror(req, nt_status_squash(nt_status)); + END_PROFILE(SMBsesssetupX); return; } if (server_info->user_session_key.data) { - session_key = data_blob(server_info->user_session_key.data, server_info->user_session_key.length); + session_key = data_blob(server_info->user_session_key.data, + server_info->user_session_key.length); } else { session_key = data_blob_null; } data_blob_clear_free(&plaintext_password); - + /* it's ok - setup a reply */ reply_outbuf(req, 3, 0); if (Protocol >= PROTOCOL_NT1) { push_signature(&req->outbuf); /* perhaps grab OS version here?? */ } - + if (server_info->guest) { SSVAL(req->outbuf,smb_vwv2,1); } @@ -1647,6 +1722,7 @@ void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req) data_blob_free(&nt_resp); data_blob_free(&lm_resp); data_blob_free(&session_key); + END_PROFILE(SMBsesssetupX); reply_nterror(req, nt_status_squash( NT_STATUS_LOGON_FAILURE)); } @@ -1662,6 +1738,7 @@ void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req) data_blob_free(&session_key); reply_nterror(req, nt_status_squash( NT_STATUS_LOGON_FAILURE)); + END_PROFILE(SMBsesssetupX); return; } @@ -1673,15 +1750,15 @@ void reply_sesssetup_and_X(connection_struct *conn, struct smb_request *req) data_blob_free(&nt_resp); data_blob_free(&lm_resp); - + SSVAL(req->outbuf,smb_uid,sess_vuid); SSVAL(req->inbuf,smb_uid,sess_vuid); - + if (!done_sesssetup) max_send = MIN(max_send,smb_bufsize); - + done_sesssetup = True; - + END_PROFILE(SMBsesssetupX); chain_reply_new(req); return; |