root/source4/smb_server/smb/negprot.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_challenge
  2. reply_corep
  3. reply_coreplus
  4. reply_lanman1
  5. reply_lanman2
  6. reply_nt1_orig
  7. reply_nt1
  8. reply_smb2
  9. smbsrv_reply_negprot

   1 /* 
   2    Unix SMB/CIFS implementation.
   3    negprot reply code
   4    Copyright (C) Andrew Tridgell 1992-1998
   5    
   6    This program is free software; you can redistribute it and/or modify
   7    it under the terms of the GNU General Public License as published by
   8    the Free Software Foundation; either version 3 of the License, or
   9    (at your option) any later version.
  10    
  11    This program is distributed in the hope that it will be useful,
  12    but WITHOUT ANY WARRANTY; without even the implied warranty of
  13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14    GNU General Public License for more details.
  15    
  16    You should have received a copy of the GNU General Public License
  17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18 */
  19 
  20 #include "includes.h"
  21 #include "auth/credentials/credentials.h"
  22 #include "auth/gensec/gensec.h"
  23 #include "auth/auth.h"
  24 #include "smb_server/smb_server.h"
  25 #include "libcli/smb2/smb2.h"
  26 #include "smb_server/smb2/smb2_server.h"
  27 #include "smb_server/service_smb_proto.h"
  28 #include "smbd/service_stream.h"
  29 #include "lib/stream/packet.h"
  30 #include "param/param.h"
  31 
  32 
  33 /* initialise the auth_context for this server and return the cryptkey */
  34 static NTSTATUS get_challenge(struct smbsrv_connection *smb_conn, uint8_t buff[8]) 
     /* [<][>][^][v][top][bottom][index][help] */
  35 {
  36         NTSTATUS nt_status;
  37         const uint8_t *challenge;
  38 
  39         /* muliple negprots are not premitted */
  40         if (smb_conn->negotiate.auth_context) {
  41                 DEBUG(3,("get challenge: is this a secondary negprot?  auth_context is non-NULL!\n"));
  42                 return NT_STATUS_FOOBAR;
  43         }
  44 
  45         DEBUG(10, ("get challenge: creating negprot_global_auth_context\n"));
  46 
  47         nt_status = auth_context_create(smb_conn, 
  48                                         smb_conn->connection->event.ctx,
  49                                         smb_conn->connection->msg_ctx,
  50                                         smb_conn->lp_ctx,
  51                                         &smb_conn->negotiate.auth_context);
  52         if (!NT_STATUS_IS_OK(nt_status)) {
  53                 DEBUG(0, ("auth_context_create() returned %s", nt_errstr(nt_status)));
  54                 return nt_status;
  55         }
  56 
  57         nt_status = auth_get_challenge(smb_conn->negotiate.auth_context, &challenge);
  58         if (!NT_STATUS_IS_OK(nt_status)) {
  59                 DEBUG(0, ("auth_get_challenge() returned %s", nt_errstr(nt_status)));
  60                 return nt_status;
  61         }
  62 
  63         memcpy(buff, challenge, 8);
  64 
  65         return NT_STATUS_OK;
  66 }
  67 
  68 /****************************************************************************
  69  Reply for the core protocol.
  70 ****************************************************************************/
  71 static void reply_corep(struct smbsrv_request *req, uint16_t choice)
     /* [<][>][^][v][top][bottom][index][help] */
  72 {
  73         smbsrv_setup_reply(req, 1, 0);
  74 
  75         SSVAL(req->out.vwv, VWV(0), choice);
  76 
  77         req->smb_conn->negotiate.protocol = PROTOCOL_CORE;
  78 
  79         if (req->smb_conn->signing.mandatory_signing) {
  80                 smbsrv_terminate_connection(req->smb_conn, 
  81                                             "CORE does not support SMB signing, and it is mandatory\n");
  82                 return;
  83         }
  84 
  85         smbsrv_send_reply(req);
  86 }
  87 
  88 /****************************************************************************
  89  Reply for the coreplus protocol.
  90 this is quite incomplete - we only fill in a small part of the reply, but as nobody uses
  91 this any more it probably doesn't matter
  92 ****************************************************************************/
  93 static void reply_coreplus(struct smbsrv_request *req, uint16_t choice)
     /* [<][>][^][v][top][bottom][index][help] */
  94 {
  95         uint16_t raw = (lp_readraw(req->smb_conn->lp_ctx)?1:0) | (lp_writeraw(req->smb_conn->lp_ctx)?2:0);
  96 
  97         smbsrv_setup_reply(req, 13, 0);
  98 
  99         /* Reply, SMBlockread, SMBwritelock supported. */
 100         SCVAL(req->out.hdr,HDR_FLG,
 101               CVAL(req->out.hdr, HDR_FLG) | FLAG_SUPPORT_LOCKREAD);
 102 
 103         SSVAL(req->out.vwv, VWV(0), choice);
 104         SSVAL(req->out.vwv, VWV(1), 0x1); /* user level security, don't encrypt */      
 105 
 106         /* tell redirector we support
 107            readbraw and writebraw (possibly) */
 108         SSVAL(req->out.vwv, VWV(5), raw); 
 109 
 110         req->smb_conn->negotiate.protocol = PROTOCOL_COREPLUS;
 111 
 112         if (req->smb_conn->signing.mandatory_signing) {
 113                 smbsrv_terminate_connection(req->smb_conn, 
 114                                             "COREPLUS does not support SMB signing, and it is mandatory\n");
 115                 return;
 116         }
 117 
 118         smbsrv_send_reply(req);
 119 }
 120 
 121 /****************************************************************************
 122  Reply for the lanman 1.0 protocol.
 123 ****************************************************************************/
 124 static void reply_lanman1(struct smbsrv_request *req, uint16_t choice)
     /* [<][>][^][v][top][bottom][index][help] */
 125 {
 126         int raw = (lp_readraw(req->smb_conn->lp_ctx)?1:0) | (lp_writeraw(req->smb_conn->lp_ctx)?2:0);
 127         int secword=0;
 128         time_t t = req->request_time.tv_sec;
 129 
 130         req->smb_conn->negotiate.encrypted_passwords = lp_encrypted_passwords(req->smb_conn->lp_ctx);
 131 
 132         if (lp_security(req->smb_conn->lp_ctx) != SEC_SHARE)
 133                 secword |= NEGOTIATE_SECURITY_USER_LEVEL;
 134 
 135         if (req->smb_conn->negotiate.encrypted_passwords)
 136                 secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
 137 
 138         req->smb_conn->negotiate.protocol = PROTOCOL_LANMAN1;
 139 
 140         smbsrv_setup_reply(req, 13, req->smb_conn->negotiate.encrypted_passwords ? 8 : 0);
 141 
 142         /* SMBlockread, SMBwritelock supported. */
 143         SCVAL(req->out.hdr,HDR_FLG,
 144               CVAL(req->out.hdr, HDR_FLG) | FLAG_SUPPORT_LOCKREAD);
 145 
 146         SSVAL(req->out.vwv, VWV(0), choice);
 147         SSVAL(req->out.vwv, VWV(1), secword); 
 148         SSVAL(req->out.vwv, VWV(2), req->smb_conn->negotiate.max_recv);
 149         SSVAL(req->out.vwv, VWV(3), lp_maxmux(req->smb_conn->lp_ctx));
 150         SSVAL(req->out.vwv, VWV(4), 1);
 151         SSVAL(req->out.vwv, VWV(5), raw); 
 152         SIVAL(req->out.vwv, VWV(6), req->smb_conn->connection->server_id.id);
 153         srv_push_dos_date(req->smb_conn, req->out.vwv, VWV(8), t);
 154         SSVAL(req->out.vwv, VWV(10), req->smb_conn->negotiate.zone_offset/60);
 155         SIVAL(req->out.vwv, VWV(11), 0); /* reserved */
 156 
 157         /* Create a token value and add it to the outgoing packet. */
 158         if (req->smb_conn->negotiate.encrypted_passwords) {
 159                 NTSTATUS nt_status;
 160 
 161                 SSVAL(req->out.vwv, VWV(11), 8);
 162 
 163                 nt_status = get_challenge(req->smb_conn, req->out.data);
 164                 if (!NT_STATUS_IS_OK(nt_status)) {
 165                         smbsrv_terminate_connection(req->smb_conn, "LANMAN1 get_challenge failed\n");
 166                         return;
 167                 }
 168         }
 169 
 170         if (req->smb_conn->signing.mandatory_signing) {
 171                 smbsrv_terminate_connection(req->smb_conn, 
 172                                             "LANMAN1 does not support SMB signing, and it is mandatory\n");
 173                 return;
 174         }
 175 
 176         smbsrv_send_reply(req); 
 177 }
 178 
 179 /****************************************************************************
 180  Reply for the lanman 2.0 protocol.
 181 ****************************************************************************/
 182 static void reply_lanman2(struct smbsrv_request *req, uint16_t choice)
     /* [<][>][^][v][top][bottom][index][help] */
 183 {
 184         int raw = (lp_readraw(req->smb_conn->lp_ctx)?1:0) | (lp_writeraw(req->smb_conn->lp_ctx)?2:0);
 185         int secword=0;
 186         time_t t = req->request_time.tv_sec;
 187 
 188         req->smb_conn->negotiate.encrypted_passwords = lp_encrypted_passwords(req->smb_conn->lp_ctx);
 189   
 190         if (lp_security(req->smb_conn->lp_ctx) != SEC_SHARE)
 191                 secword |= NEGOTIATE_SECURITY_USER_LEVEL;
 192 
 193         if (req->smb_conn->negotiate.encrypted_passwords)
 194                 secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
 195 
 196         req->smb_conn->negotiate.protocol = PROTOCOL_LANMAN2;
 197 
 198         smbsrv_setup_reply(req, 13, 0);
 199 
 200         SSVAL(req->out.vwv, VWV(0), choice);
 201         SSVAL(req->out.vwv, VWV(1), secword); 
 202         SSVAL(req->out.vwv, VWV(2), req->smb_conn->negotiate.max_recv);
 203         SSVAL(req->out.vwv, VWV(3), lp_maxmux(req->smb_conn->lp_ctx));
 204         SSVAL(req->out.vwv, VWV(4), 1);
 205         SSVAL(req->out.vwv, VWV(5), raw); 
 206         SIVAL(req->out.vwv, VWV(6), req->smb_conn->connection->server_id.id);
 207         srv_push_dos_date(req->smb_conn, req->out.vwv, VWV(8), t);
 208         SSVAL(req->out.vwv, VWV(10), req->smb_conn->negotiate.zone_offset/60);
 209         SIVAL(req->out.vwv, VWV(11), 0);
 210 
 211         /* Create a token value and add it to the outgoing packet. */
 212         if (req->smb_conn->negotiate.encrypted_passwords) {
 213                 SSVAL(req->out.vwv, VWV(11), 8);
 214                 req_grow_data(req, 8);
 215                 get_challenge(req->smb_conn, req->out.data);
 216         }
 217 
 218         req_push_str(req, NULL, lp_workgroup(req->smb_conn->lp_ctx), -1, STR_TERMINATE);
 219 
 220         if (req->smb_conn->signing.mandatory_signing) {
 221                 smbsrv_terminate_connection(req->smb_conn, 
 222                                             "LANMAN2 does not support SMB signing, and it is mandatory\n");
 223                 return;
 224         }
 225 
 226         smbsrv_send_reply(req);
 227 }
 228 
 229 static void reply_nt1_orig(struct smbsrv_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 230 {
 231         /* Create a token value and add it to the outgoing packet. */
 232         if (req->smb_conn->negotiate.encrypted_passwords) {
 233                 req_grow_data(req, 8);
 234                 /* note that we do not send a challenge at all if
 235                    we are using plaintext */
 236                 get_challenge(req->smb_conn, req->out.ptr);
 237                 req->out.ptr += 8;
 238                 SCVAL(req->out.vwv+1, VWV(16), 8);
 239         }
 240         req_push_str(req, NULL, lp_workgroup(req->smb_conn->lp_ctx), -1, STR_UNICODE|STR_TERMINATE|STR_NOALIGN);
 241         req_push_str(req, NULL, lp_netbios_name(req->smb_conn->lp_ctx), -1, STR_UNICODE|STR_TERMINATE|STR_NOALIGN);
 242         DEBUG(3,("not using extended security (SPNEGO or NTLMSSP)\n"));
 243 }
 244 
 245 /****************************************************************************
 246  Reply for the nt protocol.
 247 ****************************************************************************/
 248 static void reply_nt1(struct smbsrv_request *req, uint16_t choice)
     /* [<][>][^][v][top][bottom][index][help] */
 249 {
 250         /* dual names + lock_and_read + nt SMBs + remote API calls */
 251         int capabilities;
 252         int secword=0;
 253         time_t t = req->request_time.tv_sec;
 254         NTTIME nttime;
 255         bool negotiate_spnego = false;
 256         char *large_test_path;
 257 
 258         unix_to_nt_time(&nttime, t);
 259 
 260         capabilities = 
 261                 CAP_NT_FIND | CAP_LOCK_AND_READ | 
 262                 CAP_LEVEL_II_OPLOCKS | CAP_NT_SMBS | CAP_RPC_REMOTE_APIS;
 263 
 264         req->smb_conn->negotiate.encrypted_passwords = lp_encrypted_passwords(req->smb_conn->lp_ctx);
 265 
 266         /* do spnego in user level security if the client
 267            supports it and we can do encrypted passwords */
 268         
 269         if (req->smb_conn->negotiate.encrypted_passwords && 
 270             (lp_security(req->smb_conn->lp_ctx) != SEC_SHARE) &&
 271             lp_use_spnego(req->smb_conn->lp_ctx) &&
 272             (req->flags2 & FLAGS2_EXTENDED_SECURITY)) {
 273                 negotiate_spnego = true; 
 274                 capabilities |= CAP_EXTENDED_SECURITY;
 275         }
 276         
 277         if (lp_unix_extensions(req->smb_conn->lp_ctx)) {
 278                 capabilities |= CAP_UNIX;
 279         }
 280         
 281         if (lp_large_readwrite(req->smb_conn->lp_ctx)) {
 282                 capabilities |= CAP_LARGE_READX | CAP_LARGE_WRITEX | CAP_W2K_SMBS;
 283         }
 284 
 285         large_test_path = lock_path(req, req->smb_conn->lp_ctx, "large_test.dat");
 286         if (large_file_support(large_test_path)) {
 287                 capabilities |= CAP_LARGE_FILES;
 288         }
 289 
 290         if (lp_readraw(req->smb_conn->lp_ctx) && 
 291             lp_writeraw(req->smb_conn->lp_ctx)) {
 292                 capabilities |= CAP_RAW_MODE;
 293         }
 294         
 295         /* allow for disabling unicode */
 296         if (lp_unicode(req->smb_conn->lp_ctx)) {
 297                 capabilities |= CAP_UNICODE;
 298         }
 299 
 300         if (lp_nt_status_support(req->smb_conn->lp_ctx)) {
 301                 capabilities |= CAP_STATUS32;
 302         }
 303         
 304         if (lp_host_msdfs(req->smb_conn->lp_ctx)) {
 305                 capabilities |= CAP_DFS;
 306         }
 307         
 308         if (lp_security(req->smb_conn->lp_ctx) != SEC_SHARE) {
 309                 secword |= NEGOTIATE_SECURITY_USER_LEVEL;
 310         }
 311 
 312         if (req->smb_conn->negotiate.encrypted_passwords) {
 313                 secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
 314         }
 315 
 316         if (req->smb_conn->signing.allow_smb_signing) {
 317                 secword |= NEGOTIATE_SECURITY_SIGNATURES_ENABLED;
 318         }
 319 
 320         if (req->smb_conn->signing.mandatory_signing) {
 321                 secword |= NEGOTIATE_SECURITY_SIGNATURES_REQUIRED;
 322         }
 323         
 324         req->smb_conn->negotiate.protocol = PROTOCOL_NT1;
 325 
 326         smbsrv_setup_reply(req, 17, 0);
 327         
 328         SSVAL(req->out.vwv, VWV(0), choice);
 329         SCVAL(req->out.vwv, VWV(1), secword);
 330 
 331         /* notice the strange +1 on vwv here? That's because
 332            this is the one and only SMB packet that is malformed in
 333            the specification - all the command words after the secword
 334            are offset by 1 byte */
 335         SSVAL(req->out.vwv+1, VWV(1), lp_maxmux(req->smb_conn->lp_ctx));
 336         SSVAL(req->out.vwv+1, VWV(2), 1); /* num vcs */
 337         SIVAL(req->out.vwv+1, VWV(3), req->smb_conn->negotiate.max_recv);
 338         SIVAL(req->out.vwv+1, VWV(5), 0x10000); /* raw size. full 64k */
 339         SIVAL(req->out.vwv+1, VWV(7), req->smb_conn->connection->server_id.id); /* session key */
 340         SIVAL(req->out.vwv+1, VWV(9), capabilities);
 341         push_nttime(req->out.vwv+1, VWV(11), nttime);
 342         SSVALS(req->out.vwv+1,VWV(15), req->smb_conn->negotiate.zone_offset/60);
 343         
 344         if (!negotiate_spnego) {
 345                 reply_nt1_orig(req);
 346         } else {
 347                 struct cli_credentials *server_credentials;
 348                 struct gensec_security *gensec_security;
 349                 DATA_BLOB null_data_blob = data_blob(NULL, 0);
 350                 DATA_BLOB blob;
 351                 const char *oid;
 352                 NTSTATUS nt_status;
 353                 
 354                 server_credentials 
 355                         = cli_credentials_init(req);
 356                 if (!server_credentials) {
 357                         smbsrv_terminate_connection(req->smb_conn, "Failed to init server credentials\n");
 358                         return;
 359                 }
 360                 
 361                 cli_credentials_set_conf(server_credentials, req->smb_conn->lp_ctx);
 362                 nt_status = cli_credentials_set_machine_account(server_credentials, req->smb_conn->lp_ctx);
 363                 if (!NT_STATUS_IS_OK(nt_status)) {
 364                         DEBUG(10, ("Failed to obtain server credentials, perhaps a standalone server?: %s\n", nt_errstr(nt_status)));
 365                         talloc_free(server_credentials);
 366                         server_credentials = NULL;
 367                 }
 368 
 369                 nt_status = samba_server_gensec_start(req,
 370                                                       req->smb_conn->connection->event.ctx,
 371                                                       req->smb_conn->connection->msg_ctx,
 372                                                       req->smb_conn->lp_ctx,
 373                                                       server_credentials,
 374                                                       "cifs",
 375                                                       &gensec_security);
 376 
 377                 if (!NT_STATUS_IS_OK(nt_status)) {
 378                         DEBUG(0, ("Failed to start GENSEC: %s\n", nt_errstr(nt_status)));
 379                         smbsrv_terminate_connection(req->smb_conn, "Failed to start GENSEC\n");
 380                         return;
 381                 }
 382 
 383                 if (req->smb_conn->negotiate.auth_context) {
 384                         smbsrv_terminate_connection(req->smb_conn, "reply_nt1: is this a secondary negprot?  auth_context is non-NULL!\n");
 385                         return;
 386                 }
 387                 req->smb_conn->negotiate.server_credentials = talloc_steal(req->smb_conn, server_credentials);
 388 
 389                 gensec_set_target_service(gensec_security, "cifs");
 390 
 391                 gensec_set_credentials(gensec_security, server_credentials);
 392 
 393                 oid = GENSEC_OID_SPNEGO;
 394                 nt_status = gensec_start_mech_by_oid(gensec_security, oid);
 395                 
 396                 if (NT_STATUS_IS_OK(nt_status)) {
 397                         /* Get and push the proposed OID list into the packets */
 398                         nt_status = gensec_update(gensec_security, req, null_data_blob, &blob);
 399 
 400                         if (!NT_STATUS_IS_OK(nt_status) && !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
 401                                 DEBUG(1, ("Failed to get SPNEGO to give us the first token: %s\n", nt_errstr(nt_status)));
 402                         }
 403                 }
 404 
 405                 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
 406                         DEBUG(3,("using SPNEGO\n"));
 407                 } else {
 408                         DEBUG(5, ("Failed to start SPNEGO, falling back to NTLMSSP only: %s\n", nt_errstr(nt_status)));
 409                         oid = GENSEC_OID_NTLMSSP;
 410                         nt_status = gensec_start_mech_by_oid(gensec_security, oid);
 411                         
 412                         if (!NT_STATUS_IS_OK(nt_status)) {
 413                                 DEBUG(0, ("Failed to start SPNEGO as well as NTLMSSP fallback: %s\n", nt_errstr(nt_status)));
 414                                 reply_nt1_orig(req);
 415                                 return;
 416                         }
 417                         /* NTLMSSP is a client-first exchange */
 418                         blob = data_blob(NULL, 0);
 419                         DEBUG(3,("using raw-NTLMSSP\n"));
 420                 }
 421 
 422                 req->smb_conn->negotiate.oid = oid;
 423         
 424                 req_grow_data(req, blob.length + 16);
 425                 /* a NOT very random guid, perhaps we should get it
 426                  * from the credentials (kitchen sink...) */
 427                 memset(req->out.ptr, '\0', 16);
 428                 req->out.ptr += 16;
 429 
 430                 memcpy(req->out.ptr, blob.data, blob.length);
 431                 SCVAL(req->out.vwv+1, VWV(16), blob.length + 16);
 432                 req->out.ptr += blob.length;
 433         }
 434         
 435         smbsrv_send_reply_nosign(req);  
 436 }
 437 
 438 /****************************************************************************
 439  Reply for the SMB2 2.001 protocol
 440 ****************************************************************************/
 441 static void reply_smb2(struct smbsrv_request *req, uint16_t choice)
     /* [<][>][^][v][top][bottom][index][help] */
 442 {
 443         struct smbsrv_connection *smb_conn = req->smb_conn;
 444         NTSTATUS status;
 445 
 446         talloc_free(smb_conn->sessions.idtree_vuid);
 447         ZERO_STRUCT(smb_conn->sessions);
 448         talloc_free(smb_conn->smb_tcons.idtree_tid);
 449         ZERO_STRUCT(smb_conn->smb_tcons);
 450         ZERO_STRUCT(smb_conn->signing);
 451 
 452         /* reply with a SMB2 packet */
 453         status = smbsrv_init_smb2_connection(smb_conn);
 454         if (!NT_STATUS_IS_OK(status)) {
 455                 smbsrv_terminate_connection(smb_conn, nt_errstr(status));
 456                 talloc_free(req);
 457                 return;
 458         }
 459         packet_set_callback(smb_conn->packet, smbsrv_recv_smb2_request);
 460         smb2srv_reply_smb_negprot(req);
 461         req = NULL;
 462 }
 463 
 464 /* List of supported protocols, most desired first */
 465 static const struct {
 466         const char *proto_name;
 467         const char *short_name;
 468         void (*proto_reply_fn)(struct smbsrv_request *req, uint16_t choice);
 469         int protocol_level;
 470 } supported_protocols[] = {
 471         {"SMB 2.002",                   "SMB2",         reply_smb2,     PROTOCOL_SMB2},
 472         {"SMB 2.001",                   "SMB2",         reply_smb2,     PROTOCOL_SMB2},
 473         {"NT LANMAN 1.0",               "NT1",          reply_nt1,      PROTOCOL_NT1},
 474         {"NT LM 0.12",                  "NT1",          reply_nt1,      PROTOCOL_NT1},
 475         {"LANMAN2.1",                   "LANMAN2",      reply_lanman2,  PROTOCOL_LANMAN2},
 476         {"LM1.2X002",                   "LANMAN2",      reply_lanman2,  PROTOCOL_LANMAN2},
 477         {"Samba",                       "LANMAN2",      reply_lanman2,  PROTOCOL_LANMAN2},
 478         {"DOS LM1.2X002",               "LANMAN2",      reply_lanman2,  PROTOCOL_LANMAN2},
 479         {"Windows for Workgroups 3.1a", "LANMAN1",      reply_lanman1,  PROTOCOL_LANMAN1},
 480         {"LANMAN1.0",                   "LANMAN1",      reply_lanman1,  PROTOCOL_LANMAN1},
 481         {"MICROSOFT NETWORKS 3.0",      "LANMAN1",      reply_lanman1,  PROTOCOL_LANMAN1},
 482         {"MICROSOFT NETWORKS 1.03",     "COREPLUS",     reply_coreplus, PROTOCOL_COREPLUS},
 483         {"PC NETWORK PROGRAM 1.0",      "CORE",         reply_corep,    PROTOCOL_CORE},
 484         {NULL,NULL,NULL,0},
 485 };
 486 
 487 /****************************************************************************
 488  Reply to a negprot.
 489 ****************************************************************************/
 490 
 491 void smbsrv_reply_negprot(struct smbsrv_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 492 {
 493         int protocol;
 494         uint8_t *p;
 495         uint32_t protos_count = 0;
 496         char **protos = NULL;
 497 
 498         if (req->smb_conn->negotiate.done_negprot) {
 499                 smbsrv_terminate_connection(req->smb_conn, "multiple negprot's are not permitted");
 500                 return;
 501         }
 502         req->smb_conn->negotiate.done_negprot = true;
 503 
 504         p = req->in.data;
 505         while (true) {
 506                 size_t len;
 507 
 508                 protos = talloc_realloc(req, protos, char *, protos_count + 1);
 509                 if (!protos) {
 510                         smbsrv_terminate_connection(req->smb_conn, nt_errstr(NT_STATUS_NO_MEMORY));
 511                         return;
 512                 }
 513                 protos[protos_count] = NULL;
 514                 len = req_pull_ascii4(&req->in.bufinfo, (const char **)&protos[protos_count], p, STR_ASCII|STR_TERMINATE);
 515                 p += len;
 516                 if (len == 0 || !protos[protos_count]) break;
 517 
 518                 DEBUG(5,("Requested protocol [%d][%s]\n", protos_count, protos[protos_count]));
 519                 protos_count++;
 520         }
 521 
 522         /* Check for protocols, most desirable first */
 523         for (protocol = 0; supported_protocols[protocol].proto_name; protocol++) {
 524                 int i;
 525 
 526                 if (supported_protocols[protocol].protocol_level > lp_srv_maxprotocol(req->smb_conn->lp_ctx)) 
 527                         continue;
 528                 if (supported_protocols[protocol].protocol_level < lp_srv_minprotocol(req->smb_conn->lp_ctx)) 
 529                         continue;
 530 
 531                 for (i = 0; i < protos_count; i++) {
 532                         if (strcmp(supported_protocols[protocol].proto_name, protos[i]) != 0) continue;
 533 
 534                         supported_protocols[protocol].proto_reply_fn(req, i);
 535                         DEBUG(3,("Selected protocol [%d][%s]\n",
 536                                 i, supported_protocols[protocol].proto_name));
 537                         return;
 538                 }
 539         }
 540 
 541         smbsrv_terminate_connection(req->smb_conn, "No protocol supported !");
 542 }

/* [<][>][^][v][top][bottom][index][help] */