Ejemplo n.º 1
0
Archivo: negprot.c Proyecto: aosm/samba
int reply_negprot(connection_struct *conn, 
		  char *inbuf,char *outbuf, int dum_size, 
		  int dum_buffsize)
{
	int outsize = set_message(outbuf,1,0,True);
	int Index=0;
	int choice= -1;
	int protocol;
	char *p;
	int bcc = SVAL(smb_buf(inbuf),-2);
	int arch = ARCH_ALL;

	static BOOL done_negprot = False;

	START_PROFILE(SMBnegprot);

	if (done_negprot) {
		END_PROFILE(SMBnegprot);
		exit_server_cleanly("multiple negprot's are not permitted");
	}
	done_negprot = True;

	p = smb_buf(inbuf)+1;
	while (p < (smb_buf(inbuf) + bcc)) { 
		Index++;
		DEBUG(3,("Requested protocol [%s]\n",p));
		if (strcsequal(p,"Windows for Workgroups 3.1a"))
			arch &= ( ARCH_WFWG | ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K );
		else if (strcsequal(p,"DOS LM1.2X002"))
			arch &= ( ARCH_WFWG | ARCH_WIN95 );
		else if (strcsequal(p,"DOS LANMAN2.1"))
			arch &= ( ARCH_WFWG | ARCH_WIN95 );
		else if (strcsequal(p,"NT LM 0.12"))
			arch &= ( ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K | ARCH_CIFSFS);
		else if (strcsequal(p,"SMB 2.001"))
			arch = ARCH_VISTA;		
		else if (strcsequal(p,"LANMAN2.1"))
			arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 );
		else if (strcsequal(p,"LM1.2X002"))
			arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 );
		else if (strcsequal(p,"MICROSOFT NETWORKS 1.03"))
			arch &= ARCH_WINNT;
		else if (strcsequal(p,"XENIX CORE"))
			arch &= ( ARCH_WINNT | ARCH_OS2 );
		else if (strcsequal(p,"Samba")) {
			arch = ARCH_SAMBA;
			break;
		} else if (strcsequal(p,"POSIX 2")) {
			arch = ARCH_CIFSFS;
			break;
		}
 
		p += strlen(p) + 2;
	}

	/* CIFSFS can send one arch only, NT LM 0.12. */
	if (Index == 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(SVAL(inbuf,smb_flg2)==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(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 */

	claim_connection(NULL,"",0,True,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++) {
		p = smb_buf(inbuf)+1;
		Index = 0;
		if ((supported_protocols[protocol].protocol_level <= lp_maxprotocol()) &&
				(supported_protocols[protocol].protocol_level >= lp_minprotocol()))
			while (p < (smb_buf(inbuf) + bcc)) { 
				if (strequal(p,supported_protocols[protocol].proto_name))
					choice = Index;
				Index++;
				p += strlen(p) + 2;
			}
		if(choice != -1)
			break;
	}
  
	SSVAL(outbuf,smb_vwv0,choice);
	if(choice != -1) {
		fstrcpy(remote_proto,supported_protocols[protocol].short_name);
		reload_services(True);          
		outsize = supported_protocols[protocol].proto_reply_fn(inbuf, outbuf);
		DEBUG(3,("Selected protocol %s\n",supported_protocols[protocol].proto_name));
	} else {
		DEBUG(0,("No protocol supported !\n"));
	}
	SSVAL(outbuf,smb_vwv0,choice);
  
	DEBUG( 5, ( "negprot index=%d\n", choice ) );

	if ((lp_server_signing() == Required) && (Protocol < PROTOCOL_NT1)) {
		exit_server_cleanly("SMB signing is required and "
			"client negotiated a downlevel protocol");
	}

	END_PROFILE(SMBnegprot);
	return(outsize);
}
Ejemplo n.º 2
0
void reply_negprot(struct smb_request *req)
{
	int choice= -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_ARRAY(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->msg_ctx, sconn->sock, 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(sconn_server_id(sconn),
			  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_maxprotocol()) &&
				(supported_protocols[protocol].protocol_level >= lp_minprotocol()))
			while (i < num_cliprotos) {
				if (strequal(cliprotos[i],supported_protocols[protocol].proto_name))
					choice = i;
				i++;
			}
		if(choice != -1)
			break;
	}

	if(choice != -1) {
		fstrcpy(remote_proto,supported_protocols[protocol].short_name);
		reload_services(sconn->msg_ctx, sconn->sock, 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() == Required) && (get_Protocol() < PROTOCOL_NT1)) {
		exit_server_cleanly("SMB signing is required and "
			"client negotiated a downlevel protocol");
	}

	TALLOC_FREE(cliprotos);

	if (lp_async_smb_echo_handler() && (get_Protocol() < PROTOCOL_SMB2) &&
	    !fork_echo_handler(sconn)) {
		exit_server("Failed to fork echo handler");
	}

	END_PROFILE(SMBnegprot);
	return;
}