smbd/sesssetup.c

説明を見る。
00001 /* 
00002    Unix SMB/CIFS implementation.
00003    handle SMBsessionsetup
00004    Copyright (C) Andrew Tridgell 1998-2001
00005    Copyright (C) Andrew Bartlett      2001
00006    Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002
00007    Copyright (C) Luke Howard          2003
00008 
00009    This program is free software; you can redistribute it and/or modify
00010    it under the terms of the GNU General Public License as published by
00011    the Free Software Foundation; either version 2 of the License, or
00012    (at your option) any later version.
00013    
00014    This program is distributed in the hope that it will be useful,
00015    but WITHOUT ANY WARRANTY; without even the implied warranty of
00016    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017    GNU General Public License for more details.
00018    
00019    You should have received a copy of the GNU General Public License
00020    along with this program; if not, write to the Free Software
00021    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00022 */
00023 
00024 #include "includes.h"
00025 
00026 extern struct auth_context *negprot_global_auth_context;
00027 extern BOOL global_encrypted_passwords_negotiated;
00028 extern BOOL global_spnego_negotiated;
00029 extern enum protocol_types Protocol;
00030 extern int max_send;
00031 
00032 uint32 global_client_caps = 0;
00033 
00034 /*
00035   on a logon error possibly map the error to success if "map to guest"
00036   is set approriately
00037 */
00038 static NTSTATUS do_map_to_guest(NTSTATUS status, auth_serversupplied_info **server_info,
00039                                 const char *user, const char *domain)
00040 {
00041         if (NT_STATUS_EQUAL(status, NT_STATUS_NO_SUCH_USER)) {
00042                 if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) || 
00043                     (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
00044                         DEBUG(3,("No such user %s [%s] - using guest account\n",
00045                                  user, domain));
00046                         status = make_server_info_guest(server_info);
00047                 }
00048         }
00049 
00050         if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
00051                 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
00052                         DEBUG(3,("Registered username %s for guest access\n",user));
00053                         status = make_server_info_guest(server_info);
00054                 }
00055         }
00056 
00057         return status;
00058 }
00059 
00060 /****************************************************************************
00061  Add the standard 'Samba' signature to the end of the session setup.
00062 ****************************************************************************/
00063 
00064 static int add_signature(char *outbuf, char *p)
00065 {
00066         char *start = p;
00067         fstring lanman;
00068 
00069         fstr_sprintf( lanman, "Samba %s", SAMBA_VERSION_STRING);
00070 
00071         p += srvstr_push(outbuf, p, "Unix", BUFFER_SIZE - (p - outbuf), STR_TERMINATE);
00072         p += srvstr_push(outbuf, p, lanman, BUFFER_SIZE - (p - outbuf), STR_TERMINATE);
00073         p += srvstr_push(outbuf, p, lp_workgroup(), BUFFER_SIZE - (p - outbuf), STR_TERMINATE);
00074 
00075         return PTR_DIFF(p, start);
00076 }
00077 
00078 /****************************************************************************
00079  Start the signing engine if needed. Don't fail signing here.
00080 ****************************************************************************/
00081 
00082 static void sessionsetup_start_signing_engine(const auth_serversupplied_info *server_info, char *inbuf)
00083 {
00084         if (!server_info->guest && !srv_signing_started()) {
00085                 /* We need to start the signing engine
00086                  * here but a W2K client sends the old
00087                  * "BSRSPYL " signature instead of the
00088                  * correct one. Subsequent packets will
00089                  * be correct.
00090                  */
00091                 srv_check_sign_mac(inbuf, False);
00092         }
00093 }
00094 
00095 /****************************************************************************
00096  Send a security blob via a session setup reply.
00097 ****************************************************************************/
00098 
00099 static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
00100                                  DATA_BLOB blob, NTSTATUS nt_status)
00101 {
00102         char *p;
00103 
00104         if (!NT_STATUS_IS_OK(nt_status) && !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
00105                 ERROR_NT(nt_status_squash(nt_status));
00106         } else {
00107                 set_message(outbuf,4,0,True);
00108 
00109                 nt_status = nt_status_squash(nt_status);
00110                 SIVAL(outbuf, smb_rcls, NT_STATUS_V(nt_status));
00111                 SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */
00112                 SSVAL(outbuf, smb_vwv3, blob.length);
00113                 p = smb_buf(outbuf);
00114 
00115                 /* should we cap this? */
00116                 memcpy(p, blob.data, blob.length);
00117                 p += blob.length;
00118 
00119                 p += add_signature( outbuf, p );
00120 
00121                 set_message_end(outbuf,p);
00122         }
00123 
00124         show_msg(outbuf);
00125         return send_smb(smbd_server_fd(),outbuf);
00126 }
00127 
00128 /****************************************************************************
00129  Do a 'guest' logon, getting back the 
00130 ****************************************************************************/
00131 
00132 static NTSTATUS check_guest_password(auth_serversupplied_info **server_info) 
00133 {
00134         struct auth_context *auth_context;
00135         auth_usersupplied_info *user_info = NULL;
00136         
00137         NTSTATUS nt_status;
00138         unsigned char chal[8];
00139 
00140         ZERO_STRUCT(chal);
00141 
00142         DEBUG(3,("Got anonymous request\n"));
00143 
00144         if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context, chal))) {
00145                 return nt_status;
00146         }
00147 
00148         if (!make_user_info_guest(&user_info)) {
00149                 (auth_context->free)(&auth_context);
00150                 return NT_STATUS_NO_MEMORY;
00151         }
00152         
00153         nt_status = auth_context->check_ntlm_password(auth_context, user_info, server_info);
00154         (auth_context->free)(&auth_context);
00155         free_user_info(&user_info);
00156         return nt_status;
00157 }
00158 
00159 
00160 #ifdef HAVE_KRB5
00161 
00162 #if 0
00163 /* Experiment that failed. See "only happens with a KDC" comment below. */
00164 /****************************************************************************
00165  Cerate a clock skew error blob for a Windows client.
00166 ****************************************************************************/
00167 
00168 static BOOL make_krb5_skew_error(DATA_BLOB *pblob_out)
00169 {
00170         krb5_context context = NULL;
00171         krb5_error_code kerr = 0;
00172         krb5_data reply;
00173         krb5_principal host_princ = NULL;
00174         char *host_princ_s = NULL;
00175         BOOL ret = False;
00176 
00177         *pblob_out = data_blob(NULL,0);
00178 
00179         initialize_krb5_error_table();
00180         kerr = krb5_init_context(&context);
00181         if (kerr) {
00182                 return False;
00183         }
00184         /* Create server principal. */
00185         asprintf(&host_princ_s, "%s$@%s", global_myname(), lp_realm());
00186         if (!host_princ_s) {
00187                 goto out;
00188         }
00189         strlower_m(host_princ_s);
00190 
00191         kerr = smb_krb5_parse_name(context, host_princ_s, &host_princ);
00192         if (kerr) {
00193                 DEBUG(10,("make_krb5_skew_error: smb_krb5_parse_name failed for name %s: Error %s\n",
00194                         host_princ_s, error_message(kerr) ));
00195                 goto out;
00196         }
00197         
00198         kerr = smb_krb5_mk_error(context, KRB5KRB_AP_ERR_SKEW, host_princ, &reply);
00199         if (kerr) {
00200                 DEBUG(10,("make_krb5_skew_error: smb_krb5_mk_error failed: Error %s\n",
00201                         error_message(kerr) ));
00202                 goto out;
00203         }
00204 
00205         *pblob_out = data_blob(reply.data, reply.length);
00206         kerberos_free_data_contents(context,&reply);
00207         ret = True;
00208 
00209   out:
00210 
00211         if (host_princ_s) {
00212                 SAFE_FREE(host_princ_s);
00213         }
00214         if (host_princ) {
00215                 krb5_free_principal(context, host_princ);
00216         }
00217         krb5_free_context(context);
00218         return ret;
00219 }
00220 #endif
00221 
00222 /****************************************************************************
00223  Reply to a session setup spnego negotiate packet for kerberos.
00224 ****************************************************************************/
00225 
00226 static int reply_spnego_kerberos(connection_struct *conn, 
00227                                  char *inbuf, char *outbuf,
00228                                  int length, int bufsize,
00229                                  DATA_BLOB *secblob,
00230                                  BOOL *p_invalidate_vuid)
00231 {
00232         TALLOC_CTX *mem_ctx;
00233         DATA_BLOB ticket;
00234         char *client, *p, *domain;
00235         fstring netbios_domain_name;
00236         struct passwd *pw;
00237         fstring user;
00238         int sess_vuid;
00239         NTSTATUS ret;
00240         PAC_DATA *pac_data;
00241         DATA_BLOB ap_rep, ap_rep_wrapped, response;
00242         auth_serversupplied_info *server_info = NULL;
00243         DATA_BLOB session_key = data_blob(NULL, 0);
00244         uint8 tok_id[2];
00245         DATA_BLOB nullblob = data_blob(NULL, 0);
00246         fstring real_username;
00247         BOOL map_domainuser_to_guest = False;
00248         BOOL username_was_mapped;
00249         PAC_LOGON_INFO *logon_info = NULL;
00250 
00251         ZERO_STRUCT(ticket);
00252         ZERO_STRUCT(pac_data);
00253         ZERO_STRUCT(ap_rep);
00254         ZERO_STRUCT(ap_rep_wrapped);
00255         ZERO_STRUCT(response);
00256 
00257         /* Normally we will always invalidate the intermediate vuid. */
00258         *p_invalidate_vuid = True;
00259 
00260         mem_ctx = talloc_init("reply_spnego_kerberos");
00261         if (mem_ctx == NULL) {
00262                 return ERROR_NT(nt_status_squash(NT_STATUS_NO_MEMORY));
00263         }
00264 
00265         if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
00266                 talloc_destroy(mem_ctx);
00267                 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
00268         }
00269 
00270         ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket, &client, &pac_data, &ap_rep, &session_key);
00271 
00272         data_blob_free(&ticket);
00273 
00274         if (!NT_STATUS_IS_OK(ret)) {
00275 #if 0
00276                 /* Experiment that failed. See "only happens with a KDC" comment below. */
00277 
00278                 if (NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
00279 
00280                         /*
00281                          * Windows in this case returns NT_STATUS_MORE_PROCESSING_REQUIRED
00282                          * with a negTokenTarg blob containing an krb5_error struct ASN1 encoded
00283                          * containing KRB5KRB_AP_ERR_SKEW. The client then fixes its
00284                          * clock and continues rather than giving an error. JRA.
00285                          * -- Looks like this only happens with a KDC. JRA.
00286                          */
00287 
00288                         BOOL ok = make_krb5_skew_error(&ap_rep);
00289                         if (!ok) {
00290                                 talloc_destroy(mem_ctx);
00291                                 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
00292                         }
00293                         ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_ERROR);
00294                         response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
00295                         reply_sesssetup_blob(conn, outbuf, response, NT_STATUS_MORE_PROCESSING_REQUIRED);
00296 
00297                         /*
00298                          * In this one case we don't invalidate the intermediate vuid.
00299                          * as we're expecting the client to re-use it for the next
00300                          * sessionsetupX packet. JRA.
00301                          */
00302 
00303                         *p_invalidate_vuid = False;
00304 
00305                         data_blob_free(&ap_rep);
00306                         data_blob_free(&ap_rep_wrapped);
00307                         data_blob_free(&response);
00308                         talloc_destroy(mem_ctx);
00309                         return -1; /* already replied */
00310                 }
00311 #else
00312                 if (!NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
00313                         ret = NT_STATUS_LOGON_FAILURE;
00314                 }
00315 #endif
00316                 DEBUG(1,("Failed to verify incoming ticket with error %s!\n", nt_errstr(ret))); 
00317                 talloc_destroy(mem_ctx);
00318                 return ERROR_NT(nt_status_squash(ret));
00319         }
00320 
00321         DEBUG(3,("Ticket name is [%s]\n", client));
00322 
00323         p = strchr_m(client, '@');
00324         if (!p) {
00325                 DEBUG(3,("Doesn't look like a valid principal\n"));
00326                 data_blob_free(&ap_rep);
00327                 data_blob_free(&session_key);
00328                 SAFE_FREE(client);
00329                 talloc_destroy(mem_ctx);
00330                 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
00331         }
00332 
00333         *p = 0;
00334 
00335         /* save the PAC data if we have it */
00336 
00337         if (pac_data) {
00338                 logon_info = get_logon_info_from_pac(pac_data);
00339                 if (logon_info) {
00340                         netsamlogon_cache_store( client, &logon_info->info3 );
00341                 }
00342         }
00343 
00344         if (!strequal(p+1, lp_realm())) {
00345                 DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
00346                 if (!lp_allow_trusted_domains()) {
00347                         data_blob_free(&ap_rep);
00348                         data_blob_free(&session_key);
00349                         SAFE_FREE(client);
00350                         talloc_destroy(mem_ctx);
00351                         return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
00352                 }
00353         }
00354 
00355         /* this gives a fully qualified user name (ie. with full realm).
00356            that leads to very long usernames, but what else can we do? */
00357 
00358         domain = p+1;
00359 
00360         if (logon_info && logon_info->info3.hdr_logon_dom.uni_str_len) {
00361 
00362                 unistr2_to_ascii(netbios_domain_name, &logon_info->info3.uni_logon_dom, -1);
00363                 domain = netbios_domain_name;
00364                 DEBUG(10, ("Mapped to [%s] (using PAC)\n", domain));
00365 
00366         } else {
00367 
00368                 /* If we have winbind running, we can (and must) shorten the
00369                    username by using the short netbios name. Otherwise we will
00370                    have inconsistent user names. With Kerberos, we get the
00371                    fully qualified realm, with ntlmssp we get the short
00372                    name. And even w2k3 does use ntlmssp if you for example
00373                    connect to an ip address. */
00374 
00375                 struct winbindd_request wb_request;
00376                 struct winbindd_response wb_response;
00377                 NSS_STATUS wb_result;
00378 
00379                 ZERO_STRUCT(wb_request);
00380                 ZERO_STRUCT(wb_response);
00381 
00382                 DEBUG(10, ("Mapping [%s] to short name\n", domain));
00383 
00384                 fstrcpy(wb_request.domain_name, domain);
00385 
00386                 wb_result = winbindd_request_response(WINBINDD_DOMAIN_INFO,
00387                                              &wb_request, &wb_response);
00388 
00389                 if (wb_result == NSS_STATUS_SUCCESS) {
00390 
00391                         fstrcpy(netbios_domain_name,
00392                                 wb_response.data.domain_info.name);
00393                         domain = netbios_domain_name;
00394 
00395                         DEBUG(10, ("Mapped to [%s] (using Winbind)\n", domain));
00396                 } else {
00397                         DEBUG(3, ("Could not find short name -- winbind "
00398                                   "not running?\n"));
00399                 }
00400         }
00401 
00402         fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
00403         
00404         /* lookup the passwd struct, create a new user if necessary */
00405 
00406         username_was_mapped = map_username( user );
00407 
00408         pw = smb_getpwnam( mem_ctx, user, real_username, True );
00409 
00410         if (pw) {
00411                 /* if a real user check pam account restrictions */
00412                 /* only really perfomed if "obey pam restriction" is true */
00413                 /* do this before an eventual mappign to guest occurs */
00414                 ret = smb_pam_accountcheck(pw->pw_name);
00415                 if (  !NT_STATUS_IS_OK(ret)) {
00416                         DEBUG(1, ("PAM account restriction prevents user login\n"));
00417                         data_blob_free(&ap_rep);
00418                         data_blob_free(&session_key);
00419                         TALLOC_FREE(mem_ctx);
00420                         return ERROR_NT(nt_status_squash(ret));
00421                 }
00422         }
00423 
00424         if (!pw) {
00425 
00426                 /* this was originally the behavior of Samba 2.2, if a user
00427                    did not have a local uid but has been authenticated, then 
00428                    map them to a guest account */
00429 
00430                 if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){ 
00431                         map_domainuser_to_guest = True;
00432                         fstrcpy(user,lp_guestaccount());
00433                         pw = smb_getpwnam( mem_ctx, user, real_username, True );
00434                 } 
00435 
00436                 /* extra sanity check that the guest account is valid */
00437 
00438                 if ( !pw ) {
00439                         DEBUG(1,("Username %s is invalid on this system\n", user));
00440                         SAFE_FREE(client);
00441                         data_blob_free(&ap_rep);
00442                         data_blob_free(&session_key);
00443                         TALLOC_FREE(mem_ctx);
00444                         return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
00445                 }
00446         }
00447 
00448         /* setup the string used by %U */
00449         
00450         sub_set_smb_name( real_username );
00451         reload_services(True);
00452 
00453         if ( map_domainuser_to_guest ) {
00454                 make_server_info_guest(&server_info);
00455         } else if (logon_info) {
00456                 /* pass the unmapped username here since map_username() 
00457                    will be called again from inside make_server_info_info3() */
00458                 
00459                 ret = make_server_info_info3(mem_ctx, client, domain, 
00460                                              &server_info, &logon_info->info3);
00461                 if ( !NT_STATUS_IS_OK(ret) ) {
00462                         DEBUG(1,("make_server_info_info3 failed: %s!\n",
00463                                  nt_errstr(ret)));
00464                         SAFE_FREE(client);
00465                         data_blob_free(&ap_rep);
00466                         data_blob_free(&session_key);
00467                         TALLOC_FREE(mem_ctx);
00468                         return ERROR_NT(nt_status_squash(ret));
00469                 }
00470 
00471         } else {
00472                 ret = make_server_info_pw(&server_info, real_username, pw);
00473 
00474                 if ( !NT_STATUS_IS_OK(ret) ) {
00475                         DEBUG(1,("make_server_info_pw failed: %s!\n",
00476                                  nt_errstr(ret)));
00477                         SAFE_FREE(client);
00478                         data_blob_free(&ap_rep);
00479                         data_blob_free(&session_key);
00480                         TALLOC_FREE(mem_ctx);
00481                         return ERROR_NT(nt_status_squash(ret));
00482                 }
00483 
00484                 /* make_server_info_pw does not set the domain. Without this
00485                  * we end up with the local netbios name in substitutions for
00486                  * %D. */
00487 
00488                 if (server_info->sam_account != NULL) {
00489                         pdb_set_domain(server_info->sam_account, domain, PDB_SET);
00490                 }
00491         }
00492 
00493         server_info->was_mapped |= username_was_mapped;
00494         
00495         /* we need to build the token for the user. make_server_info_guest()
00496            already does this */
00497         
00498         if ( !server_info->ptok ) {
00499                 ret = create_local_token( server_info );
00500                 if ( !NT_STATUS_IS_OK(ret) ) {
00501                         SAFE_FREE(client);
00502                         data_blob_free(&ap_rep);
00503                         data_blob_free(&session_key);
00504                         TALLOC_FREE( mem_ctx );
00505                         TALLOC_FREE( server_info );
00506                         return ERROR_NT(nt_status_squash(ret));
00507                 }
00508         }
00509 
00510         /* register_vuid keeps the server info */
00511         /* register_vuid takes ownership of session_key, no need to free after this.
00512            A better interface would copy it.... */
00513         sess_vuid = register_vuid(server_info, session_key, nullblob, client);
00514 
00515         SAFE_FREE(client);
00516 
00517         if (sess_vuid == UID_FIELD_INVALID ) {
00518                 ret = NT_STATUS_LOGON_FAILURE;
00519         } else {
00520                 /* current_user_info is changed on new vuid */
00521                 reload_services( True );
00522 
00523                 set_message(outbuf,4,0,True);
00524                 SSVAL(outbuf, smb_vwv3, 0);
00525                         
00526                 if (server_info->guest) {
00527                         SSVAL(outbuf,smb_vwv2,1);
00528                 }
00529                 
00530                 SSVAL(outbuf, smb_uid, sess_vuid);
00531 
00532                 sessionsetup_start_signing_engine(server_info, inbuf);
00533         }
00534 
00535         /* wrap that up in a nice GSS-API wrapping */
00536         if (NT_STATUS_IS_OK(ret)) {
00537                 ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_AP_REP);
00538         } else {
00539                 ap_rep_wrapped = data_blob(NULL, 0);
00540         }
00541         response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
00542         reply_sesssetup_blob(conn, outbuf, response, ret);
00543 
00544         data_blob_free(&ap_rep);
00545         data_blob_free(&ap_rep_wrapped);
00546         data_blob_free(&response);
00547         TALLOC_FREE(mem_ctx);
00548 
00549         return -1; /* already replied */
00550 }
00551 #endif
00552 
00553 /****************************************************************************
00554  Send a session setup reply, wrapped in SPNEGO.
00555  Get vuid and check first.
00556  End the NTLMSSP exchange context if we are OK/complete fail
00557  This should be split into two functions, one to handle each
00558  leg of the NTLM auth steps.
00559 ***************************************************************************/
00560 
00561 static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *outbuf,
00562                                  uint16 vuid,
00563                                  AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
00564                                  DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status, 
00565                                  BOOL wrap) 
00566 {
00567         BOOL ret;
00568         DATA_BLOB response;
00569         struct auth_serversupplied_info *server_info = NULL;
00570 
00571         if (NT_STATUS_IS_OK(nt_status)) {
00572                 server_info = (*auth_ntlmssp_state)->server_info;
00573         } else {
00574                 nt_status = do_map_to_guest(nt_status, 
00575                                             &server_info, 
00576                                             (*auth_ntlmssp_state)->ntlmssp_state->user, 
00577                                             (*auth_ntlmssp_state)->ntlmssp_state->domain);
00578         }
00579 
00580         if (NT_STATUS_IS_OK(nt_status)) {
00581                 int sess_vuid;
00582                 DATA_BLOB nullblob = data_blob(NULL, 0);
00583                 DATA_BLOB session_key = data_blob((*auth_ntlmssp_state)->ntlmssp_state->session_key.data, (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);
00584 
00585                 /* register_vuid keeps the server info */
00586                 sess_vuid = register_vuid(server_info, session_key, nullblob, (*auth_ntlmssp_state)->ntlmssp_state->user);
00587                 (*auth_ntlmssp_state)->server_info = NULL;
00588 
00589                 if (sess_vuid == UID_FIELD_INVALID ) {
00590                         nt_status = NT_STATUS_LOGON_FAILURE;
00591                 } else {
00592                         
00593                         /* current_user_info is changed on new vuid */
00594                         reload_services( True );
00595 
00596                         set_message(outbuf,4,0,True);
00597                         SSVAL(outbuf, smb_vwv3, 0);
00598                         
00599                         if (server_info->guest) {
00600                                 SSVAL(outbuf,smb_vwv2,1);
00601                         }
00602                         
00603                         SSVAL(outbuf,smb_uid,sess_vuid);
00604 
00605                         sessionsetup_start_signing_engine(server_info, inbuf);
00606                 }
00607         }
00608 
00609         if (wrap) {
00610                 response = spnego_gen_auth_response(ntlmssp_blob, nt_status, OID_NTLMSSP);
00611         } else {
00612                 response = *ntlmssp_blob;
00613         }
00614 
00615         ret = reply_sesssetup_blob(conn, outbuf, response, nt_status);
00616         if (wrap) {
00617                 data_blob_free(&response);
00618         }
00619 
00620         /* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
00621            and the other end, that we are not finished yet. */
00622 
00623         if (!ret || !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
00624                 /* NB. This is *NOT* an error case. JRA */
00625                 auth_ntlmssp_end(auth_ntlmssp_state);
00626                 /* Kill the intermediate vuid */
00627                 invalidate_intermediate_vuid(vuid);
00628         }
00629 
00630         return ret;
00631 }
00632 
00633 /****************************************************************************
00634  Is this a krb5 mechanism ?
00635 ****************************************************************************/
00636 
00637 static NTSTATUS parse_spnego_mechanisms(DATA_BLOB blob_in, DATA_BLOB *pblob_out, BOOL *p_is_krb5)
00638 {
00639         char *OIDs[ASN1_MAX_OIDS];
00640         int i;
00641 
00642         *p_is_krb5 = False;
00643 
00644         /* parse out the OIDs and the first sec blob */
00645         if (!parse_negTokenTarg(blob_in, OIDs, pblob_out)) {
00646                 return NT_STATUS_LOGON_FAILURE;
00647         }
00648 
00649         /* only look at the first OID for determining the mechToken --
00650            accoirding to RFC2478, we should choose the one we want 
00651            and renegotiate, but i smell a client bug here..  
00652            
00653            Problem observed when connecting to a member (samba box) 
00654            of an AD domain as a user in a Samba domain.  Samba member 
00655            server sent back krb5/mskrb5/ntlmssp as mechtypes, but the 
00656            client (2ksp3) replied with ntlmssp/mskrb5/krb5 and an 
00657            NTLMSSP mechtoken.                 --jerry              */
00658 
00659 #ifdef HAVE_KRB5        
00660         if (strcmp(OID_KERBEROS5, OIDs[0]) == 0 ||
00661             strcmp(OID_KERBEROS5_OLD, OIDs[0]) == 0) {
00662                 *p_is_krb5 = True;
00663         }
00664 #endif
00665                 
00666         for (i=0;OIDs[i];i++) {
00667                 DEBUG(5,("parse_spnego_mechanisms: Got OID %s\n", OIDs[i]));
00668                 free(OIDs[i]);
00669         }
00670         return NT_STATUS_OK;
00671 }
00672 
00673 /****************************************************************************
00674  Reply to a session setup spnego negotiate packet.
00675 ****************************************************************************/
00676 
00677 static int reply_spnego_negotiate(connection_struct *conn, 
00678                                   char *inbuf,
00679                                   char *outbuf,
00680                                   uint16 vuid,
00681                                   int length, int bufsize,
00682                                   DATA_BLOB blob1,
00683                                   AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
00684 {
00685         DATA_BLOB secblob;
00686         DATA_BLOB chal;
00687         BOOL got_kerberos_mechanism = False;
00688         NTSTATUS status;
00689 
00690         status = parse_spnego_mechanisms(blob1, &secblob, &got_kerberos_mechanism);
00691         if (!NT_STATUS_IS_OK(status)) {
00692                 /* Kill the intermediate vuid */
00693                 invalidate_intermediate_vuid(vuid);
00694                 return ERROR_NT(nt_status_squash(status));
00695         }
00696 
00697         DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n", (unsigned long)secblob.length));
00698 
00699 #ifdef HAVE_KRB5
00700         if ( got_kerberos_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) {
00701                 BOOL destroy_vuid = True;
00702                 int ret = reply_spnego_kerberos(conn, inbuf, outbuf, 
00703                                                 length, bufsize, &secblob, &destroy_vuid);
00704                 data_blob_free(&secblob);
00705                 if (destroy_vuid) {
00706                         /* Kill the intermediate vuid */
00707                         invalidate_intermediate_vuid(vuid);
00708                 }
00709                 return ret;
00710         }
00711 #endif
00712 
00713         if (got_kerberos_mechanism) {
00714                 invalidate_intermediate_vuid(vuid);
00715                 DEBUG(3,("reply_spnego_negotiate: network "
00716                         "misconfiguration, client sent us a "
00717                         "krb5 ticket and kerberos security "
00718                         "not enabled"));
00719                 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
00720         }
00721 
00722         if (*auth_ntlmssp_state) {
00723                 auth_ntlmssp_end(auth_ntlmssp_state);
00724         }
00725 
00726         status = auth_ntlmssp_start(auth_ntlmssp_state);
00727         if (!NT_STATUS_IS_OK(status)) {
00728                 /* Kill the intermediate vuid */
00729                 invalidate_intermediate_vuid(vuid);
00730                 return ERROR_NT(nt_status_squash(status));
00731         }
00732 
00733         status = auth_ntlmssp_update(*auth_ntlmssp_state, 
00734                                         secblob, &chal);
00735 
00736         data_blob_free(&secblob);
00737 
00738         reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, auth_ntlmssp_state,
00739                              &chal, status, True);
00740 
00741         data_blob_free(&chal);
00742 
00743         /* already replied */
00744         return -1;
00745 }
00746 
00747 /****************************************************************************
00748  Reply to a session setup spnego auth packet.
00749 ****************************************************************************/
00750 
00751 static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
00752                              uint16 vuid,
00753                              int length, int bufsize,
00754                              DATA_BLOB blob1,
00755                              AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
00756 {
00757         DATA_BLOB auth = data_blob(NULL,0);
00758         DATA_BLOB auth_reply = data_blob(NULL,0);
00759         DATA_BLOB secblob = data_blob(NULL,0);
00760         NTSTATUS status = NT_STATUS_INVALID_PARAMETER;
00761 
00762         if (!spnego_parse_auth(blob1, &auth)) {
00763 #if 0
00764                 file_save("auth.dat", blob1.data, blob1.length);
00765 #endif
00766                 /* Kill the intermediate vuid */
00767                 invalidate_intermediate_vuid(vuid);
00768 
00769                 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
00770         }
00771 
00772         if (auth.data[0] == ASN1_APPLICATION(0)) {
00773                 /* Might be a second negTokenTarg packet */
00774 
00775                 BOOL got_krb5_mechanism = False;
00776                 status = parse_spnego_mechanisms(auth, &secblob, &got_krb5_mechanism);
00777                 if (NT_STATUS_IS_OK(status)) {
00778                         DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n", (unsigned long)secblob.length));
00779 #ifdef HAVE_KRB5
00780                         if ( got_krb5_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) {
00781                                 BOOL destroy_vuid = True;
00782                                 int ret = reply_spnego_kerberos(conn, inbuf, outbuf, 
00783                                                                 length, bufsize, &secblob, &destroy_vuid);
00784                                 data_blob_free(&secblob);
00785                                 data_blob_free(&auth);
00786                                 if (destroy_vuid) {
00787                                         /* Kill the intermediate vuid */
00788                                         invalidate_intermediate_vuid(vuid);
00789                                 }
00790                                 return ret;
00791                         }
00792 #endif
00793                 }
00794         }
00795 
00796         /* If we get here it wasn't a negTokenTarg auth packet. */
00797         data_blob_free(&secblob);
00798 
00799         if (!*auth_ntlmssp_state) {
00800                 /* Kill the intermediate vuid */
00801                 invalidate_intermediate_vuid(vuid);
00802 
00803                 /* auth before negotiatiate? */
00804                 return ERROR_NT(NT_STATUS_LOGON_FAILURE);
00805         }
00806 
00807         status = auth_ntlmssp_update(*auth_ntlmssp_state,
00808                                         auth, &auth_reply);
00809 
00810         data_blob_free(&auth);
00811 
00812         reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid,
00813                              auth_ntlmssp_state,
00814                              &auth_reply, status, True);
00815 
00816         data_blob_free(&auth_reply);
00817 
00818         /* and tell smbd that we have already replied to this packet */
00819         return -1;
00820 }
00821 
00822 /****************************************************************************
00823  List to store partial SPNEGO auth fragments.
00824 ****************************************************************************/
00825 
00826 static struct pending_auth_data *pd_list;
00827 
00828 /****************************************************************************
00829  Delete an entry on the list.
00830 ****************************************************************************/
00831 
00832 static void delete_partial_auth(struct pending_auth_data *pad)
00833 {
00834         if (!pad) {
00835                 return;
00836         }
00837         DLIST_REMOVE(pd_list, pad);
00838         data_blob_free(&pad->partial_data);
00839         SAFE_FREE(pad);
00840 }
00841 
00842 /****************************************************************************
00843  Search for a partial SPNEGO auth fragment matching an smbpid.
00844 ****************************************************************************/
00845 
00846 static struct pending_auth_data *get_pending_auth_data(uint16 smbpid)
00847 {
00848         struct pending_auth_data *pad;
00849 
00850         for (pad = pd_list; pad; pad = pad->next) {
00851                 if (pad->smbpid == smbpid) {
00852                         break;
00853                 }
00854         }
00855         return pad;
00856 }
00857 
00858 /****************************************************************************
00859  Check the size of an SPNEGO blob. If we need more return NT_STATUS_MORE_PROCESSING_REQUIRED,
00860  else return NT_STATUS_OK. Don't allow the blob to be more than 64k.
00861 ****************************************************************************/
00862 
00863 static NTSTATUS check_spnego_blob_complete(uint16 smbpid, uint16 vuid, DATA_BLOB *pblob)
00864 {
00865         struct pending_auth_data *pad = NULL;
00866         ASN1_DATA data;
00867         size_t needed_len = 0;
00868 
00869         pad = get_pending_auth_data(smbpid);
00870 
00871         /* Ensure we have some data. */
00872         if (pblob->length == 0) {
00873                 /* Caller can cope. */
00874                 DEBUG(2,("check_spnego_blob_complete: zero blob length !\n"));
00875                 delete_partial_auth(pad);
00876                 return NT_STATUS_OK;
00877         }
00878 
00879         /* Were we waiting for more data ? */
00880         if (pad) {
00881                 DATA_BLOB tmp_blob;
00882                 size_t copy_len = MIN(65536, pblob->length);
00883 
00884                 /* Integer wrap paranoia.... */
00885 
00886                 if (pad->partial_data.length + copy_len < pad->partial_data.length ||
00887                     pad->partial_data.length + copy_len < copy_len) {
00888 
00889                         DEBUG(2,("check_spnego_blob_complete: integer wrap "
00890                                 "pad->partial_data.length = %u, "
00891                                 "copy_len = %u\n",
00892                                 (unsigned int)pad->partial_data.length,
00893                                 (unsigned int)copy_len ));
00894 
00895                         delete_partial_auth(pad);
00896                         return NT_STATUS_INVALID_PARAMETER;
00897                 }
00898 
00899                 DEBUG(10,("check_spnego_blob_complete: "
00900                         "pad->partial_data.length = %u, "
00901                         "pad->needed_len = %u, "
00902                         "copy_len = %u, "
00903                         "pblob->length = %u,\n",
00904                         (unsigned int)pad->partial_data.length,
00905                         (unsigned int)pad->needed_len,
00906                         (unsigned int)copy_len,
00907                         (unsigned int)pblob->length ));
00908 
00909                 tmp_blob = data_blob(NULL,
00910                                 pad->partial_data.length + copy_len);
00911 
00912                 /* Concatenate the two (up to copy_len) bytes. */
00913                 memcpy(tmp_blob.data,
00914                         pad->partial_data.data,
00915                         pad->partial_data.length);
00916                 memcpy(tmp_blob.data + pad->partial_data.length,
00917                         pblob->data,
00918                         copy_len);
00919 
00920                 /* Replace the partial data. */
00921                 data_blob_free(&pad->partial_data);
00922                 pad->partial_data = tmp_blob;
00923                 ZERO_STRUCT(tmp_blob);
00924 
00925                 /* Are we done ? */
00926                 if (pblob->length >= pad->needed_len) {
00927                         /* Yes, replace pblob. */
00928                         data_blob_free(pblob);
00929                         *pblob = pad->partial_data;
00930                         ZERO_STRUCT(pad->partial_data);
00931                         delete_partial_auth(pad);
00932                         return NT_STATUS_OK;
00933                 }
00934 
00935                 /* Still need more data. */
00936                 pad->needed_len -= copy_len;
00937                 return NT_STATUS_MORE_PROCESSING_REQUIRED;
00938         }
00939 
00940         if ((pblob->data[0] != ASN1_APPLICATION(0)) &&
00941             (pblob->data[0] != ASN1_CONTEXT(1))) {
00942                 /* Not something we can determine the
00943                  * length of.
00944                  */
00945                 return NT_STATUS_OK;
00946         }
00947 
00948         /* This is a new SPNEGO sessionsetup - see if
00949          * the data given in this blob is enough.
00950          */
00951 
00952         asn1_load(&data, *pblob);
00953         asn1_start_tag(&data, pblob->data[0]);
00954         if (data.has_error || data.nesting == NULL) {
00955                 asn1_free(&data);
00956                 /* Let caller catch. */
00957                 return NT_STATUS_OK;
00958         }
00959 
00960         /* Integer wrap paranoia.... */
00961 
00962         if (data.nesting->taglen + data.nesting->start < data.nesting->taglen ||
00963             data.nesting->taglen + data.nesting->start < data.nesting->start) {
00964 
00965                 DEBUG(2,("check_spnego_blob_complete: integer wrap "
00966                         "data.nesting->taglen = %u, "
00967                         "data.nesting->start = %u\n",
00968                         (unsigned int)data.nesting->taglen,
00969                         (unsigned int)data.nesting->start ));
00970 
00971                 asn1_free(&data);
00972                 return NT_STATUS_INVALID_PARAMETER;
00973         }
00974 
00975         /* Total length of the needed asn1 is the tag length
00976          * plus the current offset. */
00977 
00978         needed_len = data.nesting->taglen + data.nesting->start;
00979         asn1_free(&data);
00980 
00981         DEBUG(10,("check_spnego_blob_complete: needed_len = %u, "
00982                 "pblob->length = %u\n",
00983                 (unsigned int)needed_len,
00984                 (unsigned int)pblob->length ));
00985 
00986         if (needed_len <= pblob->length) {
00987                 /* Nothing to do - blob is complete. */
00988                 return NT_STATUS_OK;
00989         }
00990 
00991         /* Refuse the blob if it's bigger than 64k. */
00992         if (needed_len > 65536) {
00993                 DEBUG(2,("check_spnego_blob_complete: needed_len too large (%u)\n",
00994                         (unsigned int)needed_len ));
00995                 return NT_STATUS_INVALID_PARAMETER;
00996         }
00997 
00998         /* We must store this blob until complete. */
00999         pad = SMB_MALLOC(sizeof(struct pending_auth_data));
01000         if (!pad) {
01001                 return NT_STATUS_NO_MEMORY;
01002         }
01003         pad->needed_len = needed_len - pblob->length;
01004         pad->partial_data = data_blob(pblob->data, pblob->length);
01005         if (pad->partial_data.data == NULL) {
01006                 SAFE_FREE(pad);
01007                 return NT_STATUS_NO_MEMORY;
01008         }
01009         pad->smbpid = smbpid;
01010         pad->vuid = vuid;
01011         DLIST_ADD(pd_list, pad);
01012 
01013         return NT_STATUS_MORE_PROCESSING_REQUIRED;
01014 }
01015 
01016 /****************************************************************************
01017  Reply to a session setup command.
01018  conn POINTER CAN BE NULL HERE !
01019 ****************************************************************************/
01020 
01021 static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
01022                                         char *outbuf,
01023                                         int length,int bufsize)
01024 {
01025         uint8 *p;
01026         DATA_BLOB blob1;
01027         int ret;
01028         size_t bufrem;
01029         fstring native_os, native_lanman, primary_domain;
01030         char *p2;
01031         uint16 data_blob_len = SVAL(inbuf, smb_vwv7);
01032         enum remote_arch_types ra_type = get_remote_arch();
01033         int vuid = SVAL(inbuf,smb_uid);
01034         user_struct *vuser = NULL;
01035         NTSTATUS status = NT_STATUS_OK;
01036         uint16 smbpid = SVAL(inbuf,smb_pid);
01037 
01038         DEBUG(3,("Doing spnego session setup\n"));
01039 
01040         if (global_client_caps == 0) {
01041                 global_client_caps = IVAL(inbuf,smb_vwv10);
01042 
01043                 if (!(global_client_caps & CAP_STATUS32)) {
01044                         remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
01045                 }
01046 
01047         }
01048                 
01049         p = (uint8 *)smb_buf(inbuf);
01050 
01051         if (data_blob_len == 0) {
01052                 /* an invalid request */
01053                 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
01054         }
01055 
01056         bufrem = smb_bufrem(inbuf, p);
01057         /* pull the spnego blob */
01058         blob1 = data_blob(p, MIN(bufrem, data_blob_len));
01059 
01060 #if 0
01061         file_save("negotiate.dat", blob1.data, blob1.length);
01062 #endif
01063 
01064         p2 = inbuf + smb_vwv13 + data_blob_len;
01065         p2 += srvstr_pull_buf(inbuf, native_os, p2, sizeof(native_os), STR_TERMINATE);
01066         p2 += srvstr_pull_buf(inbuf, native_lanman, p2, sizeof(native_lanman), STR_TERMINATE);
01067         p2 += srvstr_pull_buf(inbuf, primary_domain, p2, sizeof(primary_domain), STR_TERMINATE);
01068         DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n", 
01069                 native_os, native_lanman, primary_domain));
01070 
01071         if ( ra_type == RA_WIN2K ) {
01072                 /* Vista sets neither the OS or lanman strings */
01073 
01074                 if ( !strlen(native_os) && !strlen(native_lanman) )
01075                         set_remote_arch(RA_VISTA);
01076                 
01077                 /* Windows 2003 doesn't set the native lanman string, 
01078                    but does set primary domain which is a bug I think */
01079                            
01080                 if ( !strlen(native_lanman) ) {
01081                         ra_lanman_string( primary_domain );
01082                 } else {
01083                         ra_lanman_string( native_lanman );
01084                 }
01085         }
01086                 
01087         vuser = get_partial_auth_user_struct(vuid);
01088         if (!vuser) {
01089                 struct pending_auth_data *pad = get_pending_auth_data(smbpid);
01090                 if (pad) {
01091                         DEBUG(10,("reply_sesssetup_and_X_spnego: found pending vuid %u\n",
01092                                 (unsigned int)pad->vuid ));
01093                         vuid = pad->vuid;
01094                         vuser = get_partial_auth_user_struct(vuid);
01095                 }
01096         }
01097 
01098         if (!vuser) {
01099                 vuid = register_vuid(NULL, data_blob(NULL, 0), data_blob(NULL, 0), NULL);
01100                 if (vuid == UID_FIELD_INVALID ) {
01101                         data_blob_free(&blob1);
01102                         return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
01103                 }
01104         
01105                 vuser = get_partial_auth_user_struct(vuid);
01106         }
01107 
01108         if (!vuser) {
01109                 data_blob_free(&blob1);
01110                 return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
01111         }
01112         
01113         SSVAL(outbuf,smb_uid,vuid);
01114 
01115         /* Large (greater than 4k) SPNEGO blobs are split into multiple
01116          * sessionsetup requests as the Windows limit on the security blob
01117          * field is 4k. Bug #4400. JRA.
01118          */
01119 
01120         status = check_spnego_blob_complete(smbpid, vuid, &blob1);
01121         if (!NT_STATUS_IS_OK(status)) {
01122                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
01123                         /* Real error - kill the intermediate vuid */
01124                         invalidate_intermediate_vuid(vuid);
01125                 }
01126                 data_blob_free(&blob1);
01127                 return ERROR_NT(nt_status_squash(status));
01128         }
01129 
01130         if (blob1.data[0] == ASN1_APPLICATION(0)) {
01131                 /* its a negTokenTarg packet */
01132                 ret = reply_spnego_negotiate(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
01133                                              &vuser->auth_ntlmssp_state);
01134                 data_blob_free(&blob1);
01135                 return ret;
01136         }
01137 
01138         if (blob1.data[0] == ASN1_CONTEXT(1)) {
01139                 /* its a auth packet */
01140                 ret = reply_spnego_auth(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
01141                                         &vuser->auth_ntlmssp_state);
01142                 data_blob_free(&blob1);
01143                 return ret;
01144         }
01145 
01146         if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
01147                 DATA_BLOB chal;
01148                 if (!vuser->auth_ntlmssp_state) {
01149                         status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
01150                         if (!NT_STATUS_IS_OK(status)) {
01151                                 /* Kill the intermediate vuid */
01152                                 invalidate_intermediate_vuid(vuid);
01153                                 data_blob_free(&blob1);
01154                                 return ERROR_NT(nt_status_squash(status));
01155                         }
01156                 }
01157 
01158                 status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
01159                                                 blob1, &chal);
01160                 
01161                 data_blob_free(&blob1);
01162                 
01163                 reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, 
01164                                            &vuser->auth_ntlmssp_state,
01165                                            &chal, status, False);
01166                 data_blob_free(&chal);
01167                 return -1;
01168         }
01169 
01170         /* what sort of packet is this? */
01171         DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));
01172 
01173         data_blob_free(&blob1);
01174 
01175         return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
01176 }
01177 
01178 /****************************************************************************
01179  On new VC == 0, shutdown *all* old connections and users.
01180  It seems that only NT4.x does this. At W2K and above (XP etc.).
01181  a new session setup with VC==0 is ignored.
01182 ****************************************************************************/
01183 
01184 static int shutdown_other_smbds(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf,
01185                                 void *p)
01186 {
01187         struct sessionid sessionid;
01188         const char *ip = (const char *)p;
01189 
01190         SMB_ASSERT(dbuf.dsize == sizeof(sessionid));
01191         memcpy(&sessionid, dbuf.dptr, sizeof(sessionid));
01192 
01193         if (!process_exists(pid_to_procid(sessionid.pid))) {
01194                 return 0;
01195         }
01196 
01197         if (sessionid.pid == sys_getpid()) {
01198                 return 0;
01199         }
01200 
01201         if (strcmp(ip, sessionid.ip_addr) != 0) {
01202                 return 0;
01203         }
01204 
01205         message_send_pid(pid_to_procid(sessionid.pid), MSG_SHUTDOWN,
01206                          NULL, 0, True);
01207         return 0;
01208 }
01209 
01210 static void setup_new_vc_session(void)
01211 {
01212         DEBUG(2,("setup_new_vc_session: New VC == 0, if NT4.x compatible we would close all old resources.\n"));
01213 #if 0
01214         conn_close_all();
01215         invalidate_all_vuids();
01216 #endif
01217         if (lp_reset_on_zero_vc()) {
01218                 session_traverse(shutdown_other_smbds, client_addr());
01219         }
01220 }
01221 
01222 /****************************************************************************
01223  Reply to a session setup command.
01224 ****************************************************************************/
01225 
01226 int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
01227                           int length,int bufsize)
01228 {
01229         int sess_vuid;
01230         int   smb_bufsize;    
01231         DATA_BLOB lm_resp;
01232         DATA_BLOB nt_resp;
01233         DATA_BLOB plaintext_password;
01234         fstring user;
01235         fstring sub_user; /* Sainitised username for substituion */
01236         fstring domain;
01237         fstring native_os;
01238         fstring native_lanman;
01239         fstring primary_domain;
01240         static BOOL done_sesssetup = False;
01241         auth_usersupplied_info *user_info = NULL;
01242         auth_serversupplied_info *server_info = NULL;
01243 
01244         NTSTATUS nt_status;
01245 
01246         BOOL doencrypt = global_encrypted_passwords_negotiated;
01247 
01248         DATA_BLOB session_key;
01249         
01250         START_PROFILE(SMBsesssetupX);
01251 
01252         ZERO_STRUCT(lm_resp);
01253         ZERO_STRUCT(nt_resp);
01254         ZERO_STRUCT(plaintext_password);
01255 
01256         DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
01257 
01258         /* a SPNEGO session setup has 12 command words, whereas a normal
01259            NT1 session setup has 13. See the cifs spec. */
01260         if (CVAL(inbuf, smb_wct) == 12 &&
01261             (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
01262                 if (!global_spnego_negotiated) {
01263                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
01264                         return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
01265                 }
01266 
01267                 if (SVAL(inbuf,smb_vwv4) == 0) {
01268                         setup_new_vc_session();
01269                 }
01270                 return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
01271         }
01272 
01273         smb_bufsize = SVAL(inbuf,smb_vwv2);
01274 
01275         if (Protocol < PROTOCOL_NT1) {
01276                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
01277 
01278                 /* Never do NT status codes with protocols before NT1 as we don't get client caps. */
01279                 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
01280 
01281                 if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) {
01282                         return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
01283                 }
01284 
01285                 if (doencrypt) {
01286                         lm_resp = data_blob(smb_buf(inbuf), passlen1);
01287                 } else {
01288                         plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
01289                         /* Ensure null termination */
01290                         plaintext_password.data[passlen1] = 0;
01291                 }
01292 
01293                 srvstr_pull_buf(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), STR_TERMINATE);
01294                 *domain = 0;
01295 
01296         } else {
01297                 uint16 passlen1 = SVAL(inbuf,smb_vwv7);
01298                 uint16 passlen2 = SVAL(inbuf,smb_vwv8);
01299                 enum remote_arch_types ra_type = get_remote_arch();
01300                 char *p = smb_buf(inbuf);    
01301                 char *save_p = smb_buf(inbuf);
01302                 uint16 byte_count;
01303                         
01304 
01305                 if(global_client_caps == 0) {
01306                         global_client_caps = IVAL(inbuf,smb_vwv11);
01307                 
01308                         if (!(global_client_caps & CAP_STATUS32)) {
01309                                 remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
01310                         }
01311 
01312                         /* client_caps is used as final determination if client is NT or Win95. 
01313                            This is needed to return the correct error codes in some
01314                            circumstances.
01315                         */
01316                 
01317                         if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
01318                                 if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
01319                                         set_remote_arch( RA_WIN95);
01320                                 }
01321                         }
01322                 }
01323 
01324                 if (!doencrypt) {
01325                         /* both Win95 and WinNT stuff up the password lengths for
01326                            non-encrypting systems. Uggh. 
01327                            
01328                            if passlen1==24 its a win95 system, and its setting the
01329                            password length incorrectly. Luckily it still works with the
01330                            default code because Win95 will null terminate the password
01331                            anyway 
01332                            
01333                            if passlen1>0 and passlen2>0 then maybe its a NT box and its
01334                            setting passlen2 to some random value which really stuffs
01335                            things up. we need to fix that one.  */
01336                         
01337                         if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
01338                                 passlen2 = 0;
01339                 }
01340                 
01341                 /* check for nasty tricks */
01342                 if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) {
01343                         return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
01344                 }
01345 
01346                 if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) {
01347                         return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
01348                 }
01349 
01350                 /* Save the lanman2 password and the NT md4 password. */
01351                 
01352                 if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
01353                         doencrypt = False;
01354                 }
01355 
01356                 if (doencrypt) {
01357                         lm_resp = data_blob(p, passlen1);
01358                         nt_resp = data_blob(p+passlen1, passlen2);
01359                 } else {
01360                         pstring pass;
01361                         BOOL unic=SVAL(inbuf, smb_flg2) & FLAGS2_UNICODE_STRINGS;
01362 
01363 #if 0
01364                         /* This was the previous fix. Not sure if it's still valid. JRA. */
01365                         if ((ra_type == RA_WINNT) && (passlen2 == 0) && unic && passlen1) {
01366                                 /* NT4.0 stuffs up plaintext unicode password lengths... */
01367                                 srvstr_pull(inbuf, pass, smb_buf(inbuf) + 1,
01368                                         sizeof(pass), passlen1, STR_TERMINATE);
01369 #endif
01370 
01371                         if (unic && (passlen2 == 0) && passlen1) {
01372                                 /* Only a ascii plaintext password was sent. */
01373                                 srvstr_pull(inbuf, pass, smb_buf(inbuf), sizeof(pass),
01374                                         passlen1, STR_TERMINATE|STR_ASCII);
01375                         } else {
01376                                 srvstr_pull(inbuf, pass, smb_buf(inbuf), 
01377                                         sizeof(pass),  unic ? passlen2 : passlen1, 
01378                                         STR_TERMINATE);
01379                         }
01380                         plaintext_password = data_blob(pass, strlen(pass)+1);
01381                 }
01382                 
01383                 p += passlen1 + passlen2;
01384                 p += srvstr_pull_buf(inbuf, user, p, sizeof(user), STR_TERMINATE);
01385                 p += srvstr_pull_buf(inbuf, domain, p, sizeof(domain), STR_TERMINATE);
01386                 p += srvstr_pull_buf(inbuf, native_os, p, sizeof(native_os), STR_TERMINATE);
01387                 p += srvstr_pull_buf(inbuf, native_lanman, p, sizeof(native_lanman), STR_TERMINATE);
01388 
01389                 /* not documented or decoded by Ethereal but there is one more string 
01390                    in the extra bytes which is the same as the PrimaryDomain when using 
01391                    extended security.  Windows NT 4 and 2003 use this string to store 
01392                    the native lanman string. Windows 9x does not include a string here 
01393                    at all so we have to check if we have any extra bytes left */
01394                 
01395                 byte_count = SVAL(inbuf, smb_vwv13);
01396                 if ( PTR_DIFF(p, save_p) < byte_count)
01397                         p += srvstr_pull_buf(inbuf, primary_domain, p, sizeof(primary_domain), STR_TERMINATE);
01398                 else 
01399                         fstrcpy( primary_domain, "null" );
01400 
01401                 DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n",
01402                          domain, native_os, native_lanman, primary_domain));
01403 
01404                 if ( ra_type == RA_WIN2K ) {
01405                         if ( strlen(native_lanman) == 0 )
01406                                 ra_lanman_string( primary_domain );
01407                         else
01408                                 ra_lanman_string( native_lanman );
01409                 }
01410 
01411         }
01412 
01413         if (SVAL(inbuf,smb_vwv4) == 0) {
01414                 setup_new_vc_session();
01415         }
01416 
01417         DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name()));
01418 
01419         if (*user) {
01420                 if (global_spnego_negotiated) {
01421                         
01422                         /* This has to be here, because this is a perfectly valid behaviour for guest logons :-( */
01423                         
01424                         DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
01425                         return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
01426                 }
01427                 fstrcpy(sub_user, user);
01428         } else {
01429                 fstrcpy(sub_user, lp_guestaccount());
01430         }
01431 
01432         sub_set_smb_name(sub_user);
01433 
01434         reload_services(True);
01435         
01436         if (lp_security() == SEC_SHARE) {
01437                 /* in share level we should ignore any passwords */
01438 
01439                 data_blob_free(&lm_resp);
01440                 data_blob_free(&nt_resp);
01441                 data_blob_clear_free(&plaintext_password);
01442 
01443                 map_username(sub_user);
01444                 add_session_user(sub_user);
01445                 add_session_workgroup(domain);
01446                 /* Then force it to null for the benfit of the code below */
01447                 *user = 0;
01448         }
01449         
01450         if (!*user) {
01451 
01452                 nt_status = check_guest_password(&server_info);
01453 
01454         } else if (doencrypt) {
01455                 if (!negprot_global_auth_context) {
01456                         DEBUG(0, ("reply_sesssetup_and_X:  Attempted encrypted session setup without negprot denied!\n"));
01457                         return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
01458                 }
01459                 nt_status = make_user_info_for_reply_enc(&user_info, user, domain,
01460                                                          lm_resp, nt_resp);
01461                 if (NT_STATUS_IS_OK(nt_status)) {
01462                         nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context, 
01463                                                                                      user_info, 
01464                                                                                      &server_info);
01465                 }
01466         } else {
01467                 struct auth_context *plaintext_auth_context = NULL;
01468                 const uint8 *chal;
01469 
01470                 nt_status = make_auth_context_subsystem(&plaintext_auth_context);
01471 
01472                 if (NT_STATUS_IS_OK(nt_status)) {
01473                         chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
01474                         
01475                         if (!make_user_info_for_reply(&user_info, 
01476                                                       user, domain, chal,
01477                                                       plaintext_password)) {
01478                                 nt_status = NT_STATUS_NO_MEMORY;
01479                         }
01480                 
01481                         if (NT_STATUS_IS_OK(nt_status)) {
01482                                 nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context, 
01483                                                                                         user_info, 
01484                                                                                         &server_info); 
01485                                 
01486                                 (plaintext_auth_context->free)(&plaintext_auth_context);
01487                         }
01488                 }
01489         }
01490 
01491         free_user_info(&user_info);
01492         
01493         if (!NT_STATUS_IS_OK(nt_status)) {
01494                 nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
01495         }
01496         
01497         if (!NT_STATUS_IS_OK(nt_status)) {
01498                 data_blob_free(&nt_resp);
01499                 data_blob_free(&lm_resp);
01500                 data_blob_clear_free(&plaintext_password);
01501                 return ERROR_NT(nt_status_squash(nt_status));
01502         }
01503 
01504         /* Ensure we can't possible take a code path leading to a null defref. */
01505         if (!server_info) {
01506                 return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
01507         }
01508 
01509         if (!server_info->ptok) {
01510                 nt_status = create_local_token(server_info);
01511                 if (!NT_STATUS_IS_OK(nt_status)) {
01512                         DEBUG(10, ("create_local_token failed: %s\n",
01513                                    nt_errstr(nt_status)));
01514                         data_blob_free(&nt_resp);
01515                         data_blob_free(&lm_resp);
01516                         data_blob_clear_free(&plaintext_password);
01517                         return ERROR_NT(nt_status_squash(nt_status));
01518                 }
01519         }
01520 
01521         if (server_info->user_session_key.data) {
01522                 session_key = data_blob(server_info->user_session_key.data, server_info->user_session_key.length);
01523         } else {
01524                 session_key = data_blob(NULL, 0);
01525         }
01526 
01527         data_blob_clear_free(&plaintext_password);
01528         
01529         /* it's ok - setup a reply */
01530         set_message(outbuf,3,0,True);
01531         if (Protocol >= PROTOCOL_NT1) {
01532                 char *p = smb_buf( outbuf );
01533                 p += add_signature( outbuf, p );
01534                 set_message_end( outbuf, p );
01535                 /* perhaps grab OS version here?? */
01536         }
01537         
01538         if (server_info->guest) {
01539                 SSVAL(outbuf,smb_vwv2,1);
01540         }
01541 
01542         /* register the name and uid as being validated, so further connections
01543            to a uid can get through without a password, on the same VC */
01544 
01545         if (lp_security() == SEC_SHARE) {
01546                 sess_vuid = UID_FIELD_INVALID;
01547                 data_blob_free(&session_key);
01548                 TALLOC_FREE(server_info);
01549         } else {
01550                 /* register_vuid keeps the server info */
01551                 sess_vuid = register_vuid(server_info, session_key,
01552                                           nt_resp.data ? nt_resp : lm_resp,
01553                                           sub_user);
01554                 if (sess_vuid == UID_FIELD_INVALID) {
01555                         data_blob_free(&nt_resp);
01556                         data_blob_free(&lm_resp);
01557                         return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
01558                 }
01559 
01560                 /* current_user_info is changed on new vuid */
01561                 reload_services( True );
01562 
01563                 sessionsetup_start_signing_engine(server_info, inbuf);
01564         }
01565 
01566         data_blob_free(&nt_resp);
01567         data_blob_free(&lm_resp);
01568         
01569         SSVAL(outbuf,smb_uid,sess_vuid);
01570         SSVAL(inbuf,smb_uid,sess_vuid);
01571         
01572         if (!done_sesssetup)
01573                 max_send = MIN(max_send,smb_bufsize);
01574         
01575         done_sesssetup = True;
01576         
01577         END_PROFILE(SMBsesssetupX);
01578         return chain_reply(inbuf,outbuf,length,bufsize);
01579 }

Sambaに対してSat Aug 29 21:23:26 2009に生成されました。  doxygen 1.4.7