enum protocol_types smbd_smb2_protocol_dialect_match(const uint8_t *indyn, const int dialect_count, uint16_t *dialect) { struct { enum protocol_types proto; uint16_t dialect; } pd[] = { { PROTOCOL_SMB3_11, SMB3_DIALECT_REVISION_311 }, { PROTOCOL_SMB3_10, SMB3_DIALECT_REVISION_310 }, { PROTOCOL_SMB3_02, SMB3_DIALECT_REVISION_302 }, { PROTOCOL_SMB3_00, SMB3_DIALECT_REVISION_300 }, { PROTOCOL_SMB2_24, SMB2_DIALECT_REVISION_224 }, { PROTOCOL_SMB2_22, SMB2_DIALECT_REVISION_222 }, { PROTOCOL_SMB2_10, SMB2_DIALECT_REVISION_210 }, { PROTOCOL_SMB2_02, SMB2_DIALECT_REVISION_202 }, }; size_t i; for (i = 0; i < ARRAY_SIZE(pd); i ++) { size_t c = 0; if (lp_server_max_protocol() < pd[i].proto) { continue; } if (lp_server_min_protocol() > pd[i].proto) { continue; } for (c = 0; c < dialect_count; c++) { *dialect = SVAL(indyn, c*2); if (*dialect == pd[i].dialect) { return pd[i].proto; } } } return PROTOCOL_NONE; }
void reply_negprot(struct smb_request *req) { int choice= -1; int chosen_level = -1; int protocol; const char *p; int arch = ARCH_ALL; int num_cliprotos; char **cliprotos; int i; size_t converted_size; struct smbd_server_connection *sconn = req->sconn; START_PROFILE(SMBnegprot); if (sconn->smb1.negprot.done) { END_PROFILE(SMBnegprot); exit_server_cleanly("multiple negprot's are not permitted"); } sconn->smb1.negprot.done = true; if (req->buflen == 0) { DEBUG(0, ("negprot got no protocols\n")); reply_nterror(req, NT_STATUS_INVALID_PARAMETER); END_PROFILE(SMBnegprot); return; } if (req->buf[req->buflen-1] != '\0') { DEBUG(0, ("negprot protocols not 0-terminated\n")); reply_nterror(req, NT_STATUS_INVALID_PARAMETER); END_PROFILE(SMBnegprot); return; } p = (const char *)req->buf + 1; num_cliprotos = 0; cliprotos = NULL; while (smbreq_bufrem(req, p) > 0) { char **tmp; tmp = talloc_realloc(talloc_tos(), cliprotos, char *, num_cliprotos+1); if (tmp == NULL) { DEBUG(0, ("talloc failed\n")); TALLOC_FREE(cliprotos); reply_nterror(req, NT_STATUS_NO_MEMORY); END_PROFILE(SMBnegprot); return; } cliprotos = tmp; if (!pull_ascii_talloc(cliprotos, &cliprotos[num_cliprotos], p, &converted_size)) { DEBUG(0, ("pull_ascii_talloc failed\n")); TALLOC_FREE(cliprotos); reply_nterror(req, NT_STATUS_NO_MEMORY); END_PROFILE(SMBnegprot); return; } DEBUG(3, ("Requested protocol [%s]\n", cliprotos[num_cliprotos])); num_cliprotos += 1; p += strlen(p) + 2; } for (i=0; i<num_cliprotos; i++) { if (strcsequal(cliprotos[i], "Windows for Workgroups 3.1a")) arch &= ( ARCH_WFWG | ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K ); else if (strcsequal(cliprotos[i], "DOS LM1.2X002")) arch &= ( ARCH_WFWG | ARCH_WIN95 ); else if (strcsequal(cliprotos[i], "DOS LANMAN2.1")) arch &= ( ARCH_WFWG | ARCH_WIN95 ); else if (strcsequal(cliprotos[i], "NT LM 0.12")) arch &= ( ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K | ARCH_CIFSFS); else if (strcsequal(cliprotos[i], "SMB 2.001")) arch = ARCH_VISTA; else if (strcsequal(cliprotos[i], "LANMAN2.1")) arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 ); else if (strcsequal(cliprotos[i], "LM1.2X002")) arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 ); else if (strcsequal(cliprotos[i], "MICROSOFT NETWORKS 1.03")) arch &= ARCH_WINNT; else if (strcsequal(cliprotos[i], "XENIX CORE")) arch &= ( ARCH_WINNT | ARCH_OS2 ); else if (strcsequal(cliprotos[i], "Samba")) { arch = ARCH_SAMBA; break; } else if (strcsequal(cliprotos[i], "POSIX 2")) { arch = ARCH_CIFSFS; break; } } /* CIFSFS can send one arch only, NT LM 0.12. */ if (i == 1 && (arch & ARCH_CIFSFS)) { arch = ARCH_CIFSFS; } switch ( arch ) { case ARCH_CIFSFS: set_remote_arch(RA_CIFSFS); break; case ARCH_SAMBA: set_remote_arch(RA_SAMBA); break; case ARCH_WFWG: set_remote_arch(RA_WFWG); break; case ARCH_WIN95: set_remote_arch(RA_WIN95); break; case ARCH_WINNT: if(req->flags2 == FLAGS2_WIN2K_SIGNATURE) set_remote_arch(RA_WIN2K); else set_remote_arch(RA_WINNT); break; case ARCH_WIN2K: /* Vista may have been set in the negprot so don't override it here */ if ( get_remote_arch() != RA_VISTA ) set_remote_arch(RA_WIN2K); break; case ARCH_VISTA: set_remote_arch(RA_VISTA); break; case ARCH_OS2: set_remote_arch(RA_OS2); break; default: set_remote_arch(RA_UNKNOWN); break; } /* possibly reload - change of architecture */ reload_services(sconn, conn_snum_used, true); /* moved from the netbios session setup code since we don't have that when the client connects to port 445. Of course there is a small window where we are listening to messages -- jerry */ serverid_register(messaging_server_id(sconn->msg_ctx), FLAG_MSG_GENERAL|FLAG_MSG_SMBD |FLAG_MSG_PRINT_GENERAL); /* Check for protocols, most desirable first */ for (protocol = 0; supported_protocols[protocol].proto_name; protocol++) { i = 0; if ((supported_protocols[protocol].protocol_level <= lp_server_max_protocol()) && (supported_protocols[protocol].protocol_level >= lp_server_min_protocol())) while (i < num_cliprotos) { if (strequal(cliprotos[i],supported_protocols[protocol].proto_name)) { choice = i; chosen_level = supported_protocols[protocol].protocol_level; } i++; } if(choice != -1) break; } if(choice != -1) { fstrcpy(remote_proto,supported_protocols[protocol].short_name); reload_services(sconn, conn_snum_used, true); supported_protocols[protocol].proto_reply_fn(req, choice); DEBUG(3,("Selected protocol %s\n",supported_protocols[protocol].proto_name)); } else { DEBUG(0,("No protocol supported !\n")); reply_outbuf(req, 1, 0); SSVAL(req->outbuf, smb_vwv0, choice); } DEBUG( 5, ( "negprot index=%d\n", choice ) ); if ((lp_server_signing() == SMB_SIGNING_REQUIRED) && (chosen_level < PROTOCOL_NT1)) { exit_server_cleanly("SMB signing is required and " "client negotiated a downlevel protocol"); } TALLOC_FREE(cliprotos); if (lp_async_smb_echo_handler() && (chosen_level < PROTOCOL_SMB2_02) && !fork_echo_handler(sconn)) { exit_server("Failed to fork echo handler"); } END_PROFILE(SMBnegprot); return; }