Example #1
0
static int reply_spnego_negotiate(connection_struct *conn, 
				  char *inbuf,
				  char *outbuf,
				  uint16 vuid,
				  int length, int bufsize,
				  DATA_BLOB blob1,
				  AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
{
	DATA_BLOB secblob;
	DATA_BLOB chal;
	BOOL got_kerberos_mechanism = False;
	NTSTATUS status;

	status = parse_spnego_mechanisms(blob1, &secblob, &got_kerberos_mechanism);
	if (!NT_STATUS_IS_OK(status)) {
		/* Kill the intermediate vuid */
		invalidate_vuid(vuid);
		return ERROR_NT(nt_status_squash(status));
	}

	DEBUG(3,("reply_spnego_negotiate: Got secblob of size %lu\n", (unsigned long)secblob.length));

#ifdef HAVE_KRB5
	if ( got_kerberos_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) {
		BOOL destroy_vuid = True;
		int ret = reply_spnego_kerberos(conn, inbuf, outbuf, 
						length, bufsize, &secblob, &destroy_vuid);
		data_blob_free(&secblob);
		if (destroy_vuid) {
			/* Kill the intermediate vuid */
			invalidate_vuid(vuid);
		}
		return ret;
	}
#endif

	if (*auth_ntlmssp_state) {
		auth_ntlmssp_end(auth_ntlmssp_state);
	}

	status = auth_ntlmssp_start(auth_ntlmssp_state);
	if (!NT_STATUS_IS_OK(status)) {
		/* Kill the intermediate vuid */
		invalidate_vuid(vuid);
		return ERROR_NT(nt_status_squash(status));
	}

	status = auth_ntlmssp_update(*auth_ntlmssp_state, 
					secblob, &chal);

	data_blob_free(&secblob);

	reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, auth_ntlmssp_state,
			     &chal, status, True);

	data_blob_free(&chal);

	/* already replied */
	return -1;
}
Example #2
0
void invalidate_all_vuids(void)
{
	user_struct *usp, *next=NULL;

	for (usp=validated_users;usp;usp=next) {
		next = usp->next;
		
		invalidate_vuid(usp->vuid);
	}
}
Example #3
0
static int smbd_smb2_session_destructor(struct smbd_smb2_session *session)
{
	if (session->sconn == NULL) {
		return 0;
	}

	/* first free all tcons */
	while (session->tcons.list) {
		talloc_free(session->tcons.list);
	}

	idr_remove(session->sconn->smb2.sessions.idtree, session->vuid);
	DLIST_REMOVE(session->sconn->smb2.sessions.list, session);
	invalidate_vuid(session->sconn, session->vuid);

	session->vuid = 0;
	session->status = NT_STATUS_USER_SESSION_DELETED;
	session->sconn = NULL;

	return 0;
}
Example #4
0
int register_vuid(auth_serversupplied_info *server_info,
		  DATA_BLOB session_key, DATA_BLOB response_blob,
		  const char *smb_name)
{
	user_struct *vuser = NULL;

	/* Paranoia check. */
	if(lp_security() == SEC_SHARE) {
		smb_panic("Tried to register uid in security=share\n");
	}

	/* Limit allowed vuids to 16bits - VUID_OFFSET. */
	if (num_validated_vuids >= 0xFFFF-VUID_OFFSET) {
		data_blob_free(&session_key);
		return UID_FIELD_INVALID;
	}

	if((vuser = SMB_MALLOC_P(user_struct)) == NULL) {
		DEBUG(0,("Failed to malloc users struct!\n"));
		data_blob_free(&session_key);
		return UID_FIELD_INVALID;
	}

	ZERO_STRUCTP(vuser);

	/* Allocate a free vuid. Yes this is a linear search... :-) */
	while( get_valid_user_struct(next_vuid) != NULL ) {
		next_vuid++;
		/* Check for vuid wrap. */
		if (next_vuid == UID_FIELD_INVALID)
			next_vuid = VUID_OFFSET;
	}

	DEBUG(10,("register_vuid: allocated vuid = %u\n",
		  (unsigned int)next_vuid ));

	vuser->vuid = next_vuid;

	if (!server_info) {
		/*
		 * This happens in an unfinished NTLMSSP session setup. We
		 * need to allocate a vuid between the first and second calls
		 * to NTLMSSP.
		 */
		next_vuid++;
		num_validated_vuids++;
		
		vuser->server_info = NULL;
		
		DLIST_ADD(validated_users, vuser);
		
		return vuser->vuid;
	}

	/* the next functions should be done by a SID mapping system (SMS) as
	 * the new real sam db won't have reference to unix uids or gids
	 */
	
	vuser->uid = server_info->uid;
	vuser->gid = server_info->gid;
	
	vuser->n_groups = server_info->n_groups;
	if (vuser->n_groups) {
		if (!(vuser->groups = (gid_t *)memdup(server_info->groups,
						      sizeof(gid_t) *
						      vuser->n_groups))) {
			DEBUG(0,("register_vuid: failed to memdup "
				 "vuser->groups\n"));
			data_blob_free(&session_key);
			free(vuser);
			TALLOC_FREE(server_info);
			return UID_FIELD_INVALID;
		}
	}

	vuser->guest = server_info->guest;
	fstrcpy(vuser->user.unix_name, server_info->unix_name); 

	/* This is a potentially untrusted username */
	alpha_strcpy(vuser->user.smb_name, smb_name, ". _-$",
		     sizeof(vuser->user.smb_name));

	fstrcpy(vuser->user.domain, pdb_get_domain(server_info->sam_account));
	fstrcpy(vuser->user.full_name,
		pdb_get_fullname(server_info->sam_account));

	{
		/* Keep the homedir handy */
		const char *homedir =
			pdb_get_homedir(server_info->sam_account);
		const char *logon_script =
			pdb_get_logon_script(server_info->sam_account);

		if (!IS_SAM_DEFAULT(server_info->sam_account,
				    PDB_UNIXHOMEDIR)) {
			const char *unix_homedir =
				pdb_get_unix_homedir(server_info->sam_account);
			if (unix_homedir) {
				vuser->unix_homedir =
					smb_xstrdup(unix_homedir);
			}
		} else {
			struct passwd *passwd =
				getpwnam_alloc(NULL, vuser->user.unix_name);
			if (passwd) {
				vuser->unix_homedir =
					smb_xstrdup(passwd->pw_dir);
				TALLOC_FREE(passwd);
			}
		}
		
		if (homedir) {
			vuser->homedir = smb_xstrdup(homedir);
		}
		if (logon_script) {
			vuser->logon_script = smb_xstrdup(logon_script);
		}
	}

	vuser->session_key = session_key;

	DEBUG(10,("register_vuid: (%u,%u) %s %s %s guest=%d\n", 
		  (unsigned int)vuser->uid, 
		  (unsigned int)vuser->gid,
		  vuser->user.unix_name, vuser->user.smb_name,
		  vuser->user.domain, vuser->guest ));

	DEBUG(3, ("User name: %s\tReal name: %s\n", vuser->user.unix_name,
		  vuser->user.full_name));	

 	if (server_info->ptok) {
		vuser->nt_user_token = dup_nt_token(NULL, server_info->ptok);
	} else {
		DEBUG(1, ("server_info does not contain a user_token - "
			  "cannot continue\n"));
		TALLOC_FREE(server_info);
		data_blob_free(&session_key);
		SAFE_FREE(vuser->homedir);
		SAFE_FREE(vuser->unix_homedir);
		SAFE_FREE(vuser->logon_script);

		SAFE_FREE(vuser);
		return UID_FIELD_INVALID;
	}

	/* use this to keep tabs on all our info from the authentication */
	vuser->server_info = server_info;

	DEBUG(3,("UNIX uid %d is UNIX user %s, and will be vuid %u\n",
		 (int)vuser->uid,vuser->user.unix_name, vuser->vuid));

	next_vuid++;
	num_validated_vuids++;

	DLIST_ADD(validated_users, vuser);

	if (!session_claim(vuser)) {
		DEBUG(1, ("Failed to claim session for vuid=%d\n",
			  vuser->vuid));
		invalidate_vuid(vuser->vuid);
		return UID_FIELD_INVALID;
	}

	/* Register a home dir service for this user iff
	
	   (a) This is not a guest connection,
	   (b) we have a home directory defined 
	   (c) there s not an existing static share by that name
	   
	   If a share exists by this name (autoloaded or not) reuse it . */

	vuser->homes_snum = -1;

	if ( (!vuser->guest) && vuser->unix_homedir && *(vuser->unix_homedir)) 
	{
		int servicenumber = lp_servicenumber(vuser->user.unix_name);

		if ( servicenumber == -1 ) {
			DEBUG(3, ("Adding homes service for user '%s' using "
				  "home directory: '%s'\n", 
				vuser->user.unix_name, vuser->unix_homedir));
			vuser->homes_snum =
				add_home_service(vuser->user.unix_name, 
						 vuser->user.unix_name,
						 vuser->unix_homedir);
		} else {
			DEBUG(3, ("Using static (or previously created) "
				  "service for user '%s'; path = '%s'\n", 
				  vuser->user.unix_name,
				  lp_pathname(servicenumber) ));
			vuser->homes_snum = servicenumber;
		}
	} 
	
	if (srv_is_signing_negotiated() && !vuser->guest &&
	    !srv_signing_started()) {
		/* Try and turn on server signing on the first non-guest
		 * sessionsetup. */
		srv_set_signing(vuser->session_key, response_blob);
	}
	
	/* fill in the current_user_info struct */
	set_current_user_info( &vuser->user );


	return vuser->vuid;
}
Example #5
0
int register_existing_vuid(uint16 vuid,
			auth_serversupplied_info *server_info,
			DATA_BLOB response_blob,
			const char *smb_name)
{
	fstring tmp;
	user_struct *vuser;

	vuser = get_partial_auth_user_struct(vuid);
	if (!vuser) {
		goto fail;
	}

	/* Use this to keep tabs on all our info from the authentication */
	vuser->server_info = talloc_move(vuser, &server_info);

	/* This is a potentially untrusted username */
	alpha_strcpy(tmp, smb_name, ". _-$", sizeof(tmp));

	vuser->server_info->sanitized_username = talloc_strdup(
		vuser->server_info, tmp);

	DEBUG(10,("register_existing_vuid: (%u,%u) %s %s %s guest=%d\n",
		  (unsigned int)vuser->server_info->utok.uid,
		  (unsigned int)vuser->server_info->utok.gid,
		  vuser->server_info->unix_name,
		  vuser->server_info->sanitized_username,
		  pdb_get_domain(vuser->server_info->sam_account),
		  vuser->server_info->guest ));

	DEBUG(3, ("register_existing_vuid: User name: %s\t"
		  "Real name: %s\n", vuser->server_info->unix_name,
		  pdb_get_fullname(vuser->server_info->sam_account)));

	if (!vuser->server_info->ptok) {
		DEBUG(1, ("register_existing_vuid: server_info does not "
			"contain a user_token - cannot continue\n"));
		goto fail;
	}

	DEBUG(3,("register_existing_vuid: UNIX uid %d is UNIX user %s, "
		"and will be vuid %u\n", (int)vuser->server_info->utok.uid,
		 vuser->server_info->unix_name, vuser->vuid));

	if (!session_claim(vuser)) {
		DEBUG(1, ("register_existing_vuid: Failed to claim session "
			"for vuid=%d\n",
			vuser->vuid));
		goto fail;
	}

	/* Register a home dir service for this user if
	(a) This is not a guest connection,
	(b) we have a home directory defined
	(c) there s not an existing static share by that name
	If a share exists by this name (autoloaded or not) reuse it . */

	vuser->homes_snum = -1;

	if (!vuser->server_info->guest) {
		vuser->homes_snum = register_homes_share(
			vuser->server_info->unix_name);
	}

	if (srv_is_signing_negotiated() && !vuser->server_info->guest &&
			!srv_signing_started()) {
		/* Try and turn on server signing on the first non-guest
		 * sessionsetup. */
		srv_set_signing(vuser->server_info->user_session_key, response_blob);
	}

	/* fill in the current_user_info struct */
	set_current_user_info(
		vuser->server_info->sanitized_username,
		vuser->server_info->unix_name,
		pdb_get_domain(vuser->server_info->sam_account));

	return vuser->vuid;

  fail:

	if (vuser) {
		invalidate_vuid(vuid);
	}
	return UID_FIELD_INVALID;
}
Example #6
0
void invalidate_all_vuids(void)
{
	while (validated_users != NULL) {
		invalidate_vuid(validated_users->vuid);
	}
}
Example #7
0
static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
			     uint16 vuid,
			     int length, int bufsize,
			     DATA_BLOB blob1,
			     AUTH_NTLMSSP_STATE **auth_ntlmssp_state)
{
	DATA_BLOB auth = data_blob(NULL,0);
	DATA_BLOB auth_reply = data_blob(NULL,0);
	DATA_BLOB secblob = data_blob(NULL,0);
	NTSTATUS status = NT_STATUS_INVALID_PARAMETER;

	if (!spnego_parse_auth(blob1, &auth)) {
#if 0
		file_save("auth.dat", blob1.data, blob1.length);
#endif
		/* Kill the intermediate vuid */
		invalidate_vuid(vuid);

		return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
	}

	if (auth.data[0] == ASN1_APPLICATION(0)) {
		/* Might be a second negTokenTarg packet */

		BOOL got_krb5_mechanism = False;
		status = parse_spnego_mechanisms(auth, &secblob, &got_krb5_mechanism);
		if (NT_STATUS_IS_OK(status)) {
			DEBUG(3,("reply_spnego_auth: Got secblob of size %lu\n", (unsigned long)secblob.length));
#ifdef HAVE_KRB5
			if ( got_krb5_mechanism && ((lp_security()==SEC_ADS) || lp_use_kerberos_keytab()) ) {
				BOOL destroy_vuid = True;
				int ret = reply_spnego_kerberos(conn, inbuf, outbuf, 
								length, bufsize, &secblob, &destroy_vuid);
				data_blob_free(&secblob);
				data_blob_free(&auth);
				if (destroy_vuid) {
					/* Kill the intermediate vuid */
					invalidate_vuid(vuid);
				}
				return ret;
			}
#endif
		}
	}

	/* If we get here it wasn't a negTokenTarg auth packet. */
	data_blob_free(&secblob);
	
	if (!*auth_ntlmssp_state) {
		/* Kill the intermediate vuid */
		invalidate_vuid(vuid);

		/* auth before negotiatiate? */
		return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
	}
	
	status = auth_ntlmssp_update(*auth_ntlmssp_state, 
					auth, &auth_reply);

	data_blob_free(&auth);

	reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, 
			     auth_ntlmssp_state,
			     &auth_reply, status, True);
		
	data_blob_free(&auth_reply);

	/* and tell smbd that we have already replied to this packet */
	return -1;
}
Example #8
0
static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *outbuf,
				 uint16 vuid,
				 AUTH_NTLMSSP_STATE **auth_ntlmssp_state,
				 DATA_BLOB *ntlmssp_blob, NTSTATUS nt_status, 
				 BOOL wrap) 
{
	BOOL ret;
	DATA_BLOB response;
	struct auth_serversupplied_info *server_info = NULL;

	if (NT_STATUS_IS_OK(nt_status)) {
		server_info = (*auth_ntlmssp_state)->server_info;
	} else {
		nt_status = do_map_to_guest(nt_status, 
					    &server_info, 
					    (*auth_ntlmssp_state)->ntlmssp_state->user, 
					    (*auth_ntlmssp_state)->ntlmssp_state->domain);
	}

	if (NT_STATUS_IS_OK(nt_status)) {
		int sess_vuid;
		DATA_BLOB nullblob = data_blob(NULL, 0);
		DATA_BLOB session_key = data_blob((*auth_ntlmssp_state)->ntlmssp_state->session_key.data, (*auth_ntlmssp_state)->ntlmssp_state->session_key.length);

		/* register_vuid keeps the server info */
		sess_vuid = register_vuid(server_info, session_key, nullblob, (*auth_ntlmssp_state)->ntlmssp_state->user);
		(*auth_ntlmssp_state)->server_info = NULL;

		if (sess_vuid == UID_FIELD_INVALID ) {
			nt_status = NT_STATUS_LOGON_FAILURE;
		} else {
			
			/* current_user_info is changed on new vuid */
			reload_services( True );

			set_message(outbuf,4,0,True);
			SSVAL(outbuf, smb_vwv3, 0);
			
			if (server_info->guest) {
				SSVAL(outbuf,smb_vwv2,1);
			}
			
			SSVAL(outbuf,smb_uid,sess_vuid);

			sessionsetup_start_signing_engine(server_info, inbuf);
		}
	}

	if (wrap) {
		response = spnego_gen_auth_response(ntlmssp_blob, nt_status, OID_NTLMSSP);
	} else {
		response = *ntlmssp_blob;
	}

	ret = reply_sesssetup_blob(conn, outbuf, response, nt_status);
	if (wrap) {
		data_blob_free(&response);
	}

	/* NT_STATUS_MORE_PROCESSING_REQUIRED from our NTLMSSP code tells us,
	   and the other end, that we are not finished yet. */

	if (!ret || !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
		/* NB. This is *NOT* an error case. JRA */
		auth_ntlmssp_end(auth_ntlmssp_state);
		/* Kill the intermediate vuid */
		invalidate_vuid(vuid);
	}

	return ret;
}
Example #9
0
static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,
					char *outbuf,
					int length,int bufsize)
{
	uint8 *p;
	DATA_BLOB blob1;
	int ret;
	size_t bufrem;
	fstring native_os, native_lanman, primary_domain;
	char *p2;
	uint16 data_blob_len = SVAL(inbuf, smb_vwv7);
	enum remote_arch_types ra_type = get_remote_arch();
	int vuid = SVAL(inbuf,smb_uid);
	user_struct *vuser = NULL;
	NTSTATUS status = NT_STATUS_OK;
	uint16 smbpid = SVAL(inbuf,smb_pid);

	DEBUG(3,("Doing spnego session setup\n"));

	if (global_client_caps == 0) {
		global_client_caps = IVAL(inbuf,smb_vwv10);

		if (!(global_client_caps & CAP_STATUS32)) {
			remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES);
		}

	}
		
	p = (uint8 *)smb_buf(inbuf);

	if (data_blob_len == 0) {
		/* an invalid request */
		return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
	}

	bufrem = smb_bufrem(inbuf, p);
	/* pull the spnego blob */
	blob1 = data_blob(p, MIN(bufrem, data_blob_len));

#if 0
	file_save("negotiate.dat", blob1.data, blob1.length);
#endif

	p2 = inbuf + smb_vwv13 + data_blob_len;
	p2 += srvstr_pull_buf(inbuf, native_os, p2, sizeof(native_os), STR_TERMINATE);
	p2 += srvstr_pull_buf(inbuf, native_lanman, p2, sizeof(native_lanman), STR_TERMINATE);
	p2 += srvstr_pull_buf(inbuf, primary_domain, p2, sizeof(primary_domain), STR_TERMINATE);
	DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n", 
		native_os, native_lanman, primary_domain));

	if ( ra_type == RA_WIN2K ) {
		/* Vista sets neither the OS or lanman strings */

		if ( !strlen(native_os) && !strlen(native_lanman) )
			set_remote_arch(RA_VISTA);
		
		/* Windows 2003 doesn't set the native lanman string, 
		   but does set primary domain which is a bug I think */
			   
		if ( !strlen(native_lanman) ) {
			ra_lanman_string( primary_domain );
		} else {
			ra_lanman_string( native_lanman );
		}
	}
		
	vuser = get_partial_auth_user_struct(vuid);
	if (!vuser) {
		struct pending_auth_data *pad = get_pending_auth_data(smbpid);
		if (pad) {
			DEBUG(10,("reply_sesssetup_and_X_spnego: found pending vuid %u\n",
				(unsigned int)pad->vuid ));
			vuid = pad->vuid;
			vuser = get_partial_auth_user_struct(vuid);
		}
	}

	if (!vuser) {
		vuid = register_vuid(NULL, data_blob(NULL, 0), data_blob(NULL, 0), NULL);
		if (vuid == UID_FIELD_INVALID ) {
			data_blob_free(&blob1);
			return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
		}
	
		vuser = get_partial_auth_user_struct(vuid);
	}

	if (!vuser) {
		data_blob_free(&blob1);
		return ERROR_NT(nt_status_squash(NT_STATUS_INVALID_PARAMETER));
	}
	
	SSVAL(outbuf,smb_uid,vuid);

	/* Large (greater than 4k) SPNEGO blobs are split into multiple
	 * sessionsetup requests as the Windows limit on the security blob
	 * field is 4k. Bug #4400. JRA.
	 */

	status = check_spnego_blob_complete(smbpid, vuid, &blob1);
	if (!NT_STATUS_IS_OK(status)) {
		if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
			/* Real error - kill the intermediate vuid */
			invalidate_vuid(vuid);
		}
		data_blob_free(&blob1);
		return ERROR_NT(nt_status_squash(status));
	}

	if (blob1.data[0] == ASN1_APPLICATION(0)) {
		/* its a negTokenTarg packet */
		ret = reply_spnego_negotiate(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
					     &vuser->auth_ntlmssp_state);
		data_blob_free(&blob1);
		return ret;
	}

	if (blob1.data[0] == ASN1_CONTEXT(1)) {
		/* its a auth packet */
		ret = reply_spnego_auth(conn, inbuf, outbuf, vuid, length, bufsize, blob1,
					&vuser->auth_ntlmssp_state);
		data_blob_free(&blob1);
		return ret;
	}

	if (strncmp((char *)(blob1.data), "NTLMSSP", 7) == 0) {
		DATA_BLOB chal;
		if (!vuser->auth_ntlmssp_state) {
			status = auth_ntlmssp_start(&vuser->auth_ntlmssp_state);
			if (!NT_STATUS_IS_OK(status)) {
				/* Kill the intermediate vuid */
				invalidate_vuid(vuid);
				data_blob_free(&blob1);
				return ERROR_NT(nt_status_squash(status));
			}
		}

		status = auth_ntlmssp_update(vuser->auth_ntlmssp_state,
						blob1, &chal);
		
		data_blob_free(&blob1);
		
		reply_spnego_ntlmssp(conn, inbuf, outbuf, vuid, 
					   &vuser->auth_ntlmssp_state,
					   &chal, status, False);
		data_blob_free(&chal);
		return -1;
	}

	/* what sort of packet is this? */
	DEBUG(1,("Unknown packet in reply_sesssetup_and_X_spnego\n"));

	data_blob_free(&blob1);

	return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
}