Example #1
0
static int negprot_spnego(char *p)
{
    DATA_BLOB blob;
    nstring dos_name;
    fstring unix_name;
    uint8 guid[17];
    const char *OIDs_krb5[] = {OID_KERBEROS5,
                               OID_KERBEROS5_OLD,
                               OID_NTLMSSP,
                               NULL
                              };
    const char *OIDs_plain[] = {OID_NTLMSSP, NULL};
    char *principal;
    int len;

    global_spnego_negotiated = True;

    ZERO_STRUCT(guid);

    safe_strcpy(unix_name, global_myname(), sizeof(unix_name)-1);
    strlower_m(unix_name);
    push_ascii_nstring(dos_name, unix_name);
    safe_strcpy((char *)guid, dos_name, sizeof(guid)-1);

#ifdef DEVELOPER
    /* valgrind fixer... */
    {
        size_t sl = strlen(guid);
        if (sizeof(guid)-sl)
            memset(&guid[sl], '\0', sizeof(guid)-sl);
    }
#endif

#if 0
    /* strangely enough, NT does not sent the single OID NTLMSSP when
       not a ADS member, it sends no OIDs at all

       we can't do this until we teach our sesssion setup parser to know
       about raw NTLMSSP (clients send no ASN.1 wrapping if we do this)
    */
    if (lp_security() != SEC_ADS) {
        memcpy(p, guid, 16);
        return 16;
    }
#endif
    if (lp_security() != SEC_ADS) {
        blob = spnego_gen_negTokenInit(guid, OIDs_plain, "NONE");
    } else {
        asprintf(&principal, "%s$@%s", guid, lp_realm());
        blob = spnego_gen_negTokenInit(guid, OIDs_krb5, principal);
        free(principal);
    }
    memcpy(p, blob.data, blob.length);
    len = blob.length;
    data_blob_free(&blob);
    return len;
}
Example #2
0
BOOL get_dc_name(const char *domain, const char *realm, fstring srv_name, struct in_addr *ip_out)
{
	struct in_addr dc_ip;
	BOOL ret;
	BOOL our_domain = False;

	zero_ip(&dc_ip);

	ret = False;
	
	if ( strequal(lp_workgroup(), domain) || strequal(lp_realm(), realm) )
		our_domain = True;
	
	/* always try to obey what the admin specified in smb.conf 
	   (for the local domain) */
	
	if ( (our_domain && lp_security()==SEC_ADS) || realm ) {
		ret = ads_dc_name(domain, realm, &dc_ip, srv_name);
	}

	if (!domain) {
		/* if we have only the realm we can't do anything else */
		return False;
	}
	
	if (!ret) {
		/* fall back on rpc methods if the ADS methods fail */
		ret = rpc_dc_name(domain, srv_name, &dc_ip);
	}
		
	*ip_out = dc_ip;

	return ret;
}
Example #3
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 #4
0
WERROR NetGetJoinInformation_l(struct libnetapi_ctx *ctx,
			       struct NetGetJoinInformation *r)
{
	if ((lp_security() == SEC_ADS) && lp_realm()) {
		*r->out.name_buffer = talloc_strdup(ctx, lp_realm());
	} else {
		*r->out.name_buffer = talloc_strdup(ctx, lp_workgroup());
	}
	if (!*r->out.name_buffer) {
		return WERR_NOMEM;
	}

	switch (lp_server_role()) {
		case ROLE_DOMAIN_MEMBER:
		case ROLE_DOMAIN_PDC:
		case ROLE_DOMAIN_BDC:
			*r->out.name_type = NetSetupDomainName;
			break;
		case ROLE_STANDALONE:
		default:
			*r->out.name_type = NetSetupWorkgroupName;
			break;
	}

	return WERR_OK;
}
Example #5
0
static int net_lookup_pdc(struct net_context *c, int argc, const char **argv)
{
	struct sockaddr_storage ss;
	char *pdc_str = NULL;
	const char *domain;
	char addr[INET6_ADDRSTRLEN];

	if (lp_security() == SEC_ADS) {
		domain = lp_realm();
	} else {
		domain = c->opt_target_workgroup;
	}

	if (argc > 0)
		domain=argv[0];

	/* first get PDC */
	if (!get_pdc_ip(domain, &ss))
		return -1;

	print_sockaddr(addr, sizeof(addr), &ss);
	if (asprintf(&pdc_str, "%s", addr) == -1) {
		return -1;
	}
	d_printf("%s\n", pdc_str);
	SAFE_FREE(pdc_str);
	return 0;
}
Example #6
0
void attempt_machine_password_change(void)
{
	unsigned char trust_passwd_hash[16];
	time_t lct;
	void *lock;

	if (!global_machine_password_needs_changing) {
		return;
	}

	if (lp_security() != SEC_DOMAIN) {
		return;
	}

	/*
	 * We're in domain level security, and the code that
	 * read the machine password flagged that the machine
	 * password needs changing.
	 */

	/*
	 * First, open the machine password file with an exclusive lock.
	 */

	lock = secrets_get_trust_account_lock(NULL, lp_workgroup());

	if (lock == NULL) {
		DEBUG(0,("attempt_machine_password_change: unable to lock "
			"the machine account password for machine %s in "
			"domain %s.\n",
			lp_netbios_name(), lp_workgroup() ));
		return;
	}

	if(!secrets_fetch_trust_account_password(lp_workgroup(),
			trust_passwd_hash, &lct, NULL)) {
		DEBUG(0,("attempt_machine_password_change: unable to read the "
			"machine account password for %s in domain %s.\n",
			lp_netbios_name(), lp_workgroup()));
		TALLOC_FREE(lock);
		return;
	}

	/*
	 * Make sure someone else hasn't already done this.
	 */

	if(time(NULL) < lct + lp_machine_password_timeout()) {
		global_machine_password_needs_changing = false;
		TALLOC_FREE(lock);
		return;
	}

	/* always just contact the PDC here */

	change_trust_account_password( lp_workgroup(), NULL);
	global_machine_password_needs_changing = false;
	TALLOC_FREE(lock);
}
Example #7
0
static int do_global_checks(void)
{
	int ret = 0;
	SMB_STRUCT_STAT st;

	if (lp_security() > SEC_SHARE && lp_revalidate(-1)) {
		printf("WARNING: the 'revalidate' parameter is ignored in all but \
'security=share' mode.\n");
	}
Example #8
0
static void init_sid_name_map (void)
{
	int i = 0;
	
	if (sid_name_map_initialized) return;

	generate_wellknown_sids();

	if ((lp_security() == SEC_USER) && lp_domain_logons()) {
		sid_name_map[i].sid = get_global_sam_sid();
		/* This is not lp_workgroup() for good reason:
		   it must stay around longer than the lp_*() 
		   strings do */
		sid_name_map[i].name = strdup(lp_workgroup());
		sid_name_map[i].known_users = NULL;
		i++;
		sid_name_map[i].sid = get_global_sam_sid();
		sid_name_map[i].name = strdup(global_myname());
		sid_name_map[i].known_users = NULL;
		i++;
	} else {
		sid_name_map[i].sid = get_global_sam_sid();
		sid_name_map[i].name = strdup(global_myname());
		sid_name_map[i].known_users = NULL;
		i++;
	}

	sid_name_map[i].sid = &global_sid_Builtin;
	sid_name_map[i].name = "BUILTIN";
	sid_name_map[i].known_users = &builtin_groups[0];
	i++;
	
	sid_name_map[i].sid = &global_sid_World_Domain;
	sid_name_map[i].name = "";
	sid_name_map[i].known_users = &everyone_users[0];
	i++;

	sid_name_map[i].sid = &global_sid_Creator_Owner_Domain;
	sid_name_map[i].name = "";
	sid_name_map[i].known_users = &creator_owner_users[0];
	i++;
		
	sid_name_map[i].sid = &global_sid_NT_Authority;
	sid_name_map[i].name = "NT Authority";
	sid_name_map[i].known_users = &nt_authority_users[0];
	i++;
		
	/* End of array. */
	sid_name_map[i].sid = NULL;
	sid_name_map[i].name = NULL;
	sid_name_map[i].known_users = NULL;
	
	sid_name_map_initialized = True;
		
	return;
}
Example #9
0
/**************************************************************************
 quick init function
 *************************************************************************/
static void init_sid_name_map (void)
{
	int i = 0;
	
	if (sid_name_map_initialized) return;
	

	if ((lp_security() == SEC_USER) && lp_domain_logons()) {
		sid_name_map[i].sid = &global_sam_sid;
		sid_name_map[i].name = global_myworkgroup;
		sid_name_map[i].known_users = NULL;
		i++;
		sid_name_map[i].sid = &global_sam_sid;
		sid_name_map[i].name = global_myname;
		sid_name_map[i].known_users = NULL;
		i++;
	}
	else {
		sid_name_map[i].sid = &global_sam_sid;
		sid_name_map[i].name = global_myname;
		sid_name_map[i].known_users = NULL;
		i++;
	}

	sid_name_map[i].sid = &global_sid_Builtin;
	sid_name_map[i].name = "BUILTIN";
	sid_name_map[i].known_users = &builtin_groups[0];
	i++;
	
	sid_name_map[i].sid = &global_sid_World_Domain;
	sid_name_map[i].name = "";
	sid_name_map[i].known_users = &everyone_users[0];
	i++;

	sid_name_map[i].sid = &global_sid_Creator_Owner_Domain;
	sid_name_map[i].name = "";
	sid_name_map[i].known_users = &creator_owner_users[0];
	i++;
		
	sid_name_map[i].sid = &global_sid_NT_Authority;
	sid_name_map[i].name = "NT Authority";
	sid_name_map[i].known_users = &nt_authority_users[0];
	i++;
		

	/* end of array */
	sid_name_map[i].sid = NULL;
	sid_name_map[i].name = NULL;
	sid_name_map[i].known_users = NULL;
	
	sid_name_map_initialized = True;
		
	return;

}
Example #10
0
File: uid.c Project: Arkhont/samba
bool change_to_user(connection_struct *conn, uint16_t vuid)
{
	const struct auth_serversupplied_info *session_info = NULL;
	user_struct *vuser;
	int snum = SNUM(conn);

	if (!conn) {
		DEBUG(2,("Connection not open\n"));
		return(False);
	}

	vuser = get_valid_user_struct(conn->sconn, vuid);

	/*
	 * We need a separate check in security=share mode due to vuid
	 * always being UID_FIELD_INVALID. If we don't do this then
	 * in share mode security we are *always* changing uid's between
	 * SMB's - this hurts performance - Badly.
	 */

	if((lp_security() == SEC_SHARE) && (current_user.conn == conn) &&
	   (current_user.ut.uid == conn->session_info->utok.uid)) {
		DEBUG(4,("Skipping user change - already "
			 "user\n"));
		return(True);
	} else if ((current_user.conn == conn) &&
		   (vuser != NULL) && (current_user.vuid == vuid) &&
		   (current_user.ut.uid == vuser->session_info->utok.uid)) {
		DEBUG(4,("Skipping user change - already "
			 "user\n"));
		return(True);
	}

	session_info = vuser ? vuser->session_info : conn->session_info;

	if (session_info == NULL) {
		/* Invalid vuid sent - even with security = share. */
		DEBUG(2,("Invalid vuid %d used on "
			 "share %s.\n", vuid, lp_servicename(snum) ));
		return false;
	}

	/* security = share sets force_user. */
	if (!conn->force_user && vuser == NULL) {
		DEBUG(2,("Invalid vuid used %d in accessing "
			"share %s.\n", vuid, lp_servicename(snum) ));
		return False;
	}

	return change_to_user_internal(conn, session_info, vuid);
}
Example #11
0
static int count_fns(void)
{
	int funcs = sizeof(api_lsa_cmds) / sizeof(struct api_struct);
	
	/*
	 * NOTE: Certain calls can not be enabled if we aren't an ADS DC.  Make sure
	 * these calls are always last and that you decrement by the amount of calls
	 * to disable.
	 */
	if (!(SEC_ADS == lp_security() && ROLE_DOMAIN_PDC == lp_server_role())) {
		funcs -= 1;
	}

	return funcs;
}
Example #12
0
static int do_global_checks(void)
{
	int ret = 0;
	SMB_STRUCT_STAT st;

	if (lp_security() >= SEC_DOMAIN && !lp_encrypted_passwords()) {
		fprintf(stderr, "ERROR: in 'security=domain' mode the 'encrypt passwords' parameter must always be set to 'true'.\n");
		ret = 1;
	}

	if (lp_wins_support() && lp_wins_server_list()) {
		fprintf(stderr, "ERROR: both 'wins support = true' and 'wins server = <server list>' \
cannot be set in the smb.conf file. nmbd will abort with this setting.\n");
		ret = 1;
	}
Example #13
0
/* run kinit to setup our ccache */
int ads_kinit_password(ADS_STRUCT *ads)
{
	char *s;
	int ret;
	const char *account_name;
	fstring acct_name;

	if (ads->auth.flags & ADS_AUTH_USER_CREDS) {
		account_name = ads->auth.user_name;
		goto got_accountname;
	}

	if ( IS_DC ) {
		/* this will end up getting a ticket for [email protected] */
		account_name = lp_workgroup();
	} else {
		/* always use the sAMAccountName for security = domain */
		/* global_myname()[email protected] */
		if ( lp_security() == SEC_DOMAIN ) {
			fstr_sprintf( acct_name, "%s$", global_myname() );
			account_name = acct_name;
		}
		else
			/* This looks like host/global_myname()@REA.LM */
			account_name = ads->auth.user_name;
	}

 got_accountname:
	if (asprintf(&s, "%s@%s", account_name, ads->auth.realm) == -1) {
		return KRB5_CC_NOMEM;
	}

	if (!ads->auth.password) {
		SAFE_FREE(s);
		return KRB5_LIBOS_CANTREADPWD;
	}

	ret = kerberos_kinit_password_ext(s, ads->auth.password, ads->auth.time_offset,
			&ads->auth.tgt_expire, NULL, NULL, False, False, ads->auth.renewable,
			NULL);

	if (ret) {
		DEBUG(0,("kerberos_kinit_password %s failed: %s\n",
			 s, error_message(ret)));
	}
	SAFE_FREE(s);
	return ret;
}
Example #14
0
/* get the winbind_cache structure */
static struct winbind_cache *get_cache(struct winbindd_domain *domain)
{
	struct winbind_cache *ret = wcache;

	if (!domain->backend) {
		extern struct winbindd_methods msrpc_methods;
		switch (lp_security()) {
#ifdef HAVE_ADS
		case SEC_ADS: {
			extern struct winbindd_methods ads_methods;
			/* always obey the lp_security parameter for our domain */
			if (domain->primary) {
				domain->backend = &ads_methods;
				break;
			}

			/* only use ADS for native modes at the momment.
			   The problem is the correct detection of mixed 
			   mode domains from NT4 BDC's    --jerry */
			
			if ( domain->native_mode ) {
				DEBUG(5,("get_cache: Setting ADS methods for domain %s\n",
					domain->name));
				domain->backend = &ads_methods;
				break;
			}

			/* fall through */
		}	
#endif
		default:
			DEBUG(5,("get_cache: Setting MS-RPC methods for domain %s\n",
				domain->name));
			domain->backend = &msrpc_methods;
		}
	}

	if (ret)
		return ret;
	
	ret = smb_xmalloc(sizeof(*ret));
	ZERO_STRUCTP(ret);

	wcache = ret;
	wcache_flush_cache();

	return ret;
}
Example #15
0
static int net_lookup_dc(struct net_context *c, int argc, const char **argv)
{
	struct ip_service *ip_list;
	struct sockaddr_storage ss;
	char *pdc_str = NULL;
	const char *domain = NULL;
	char *sitename = NULL;
	int count, i;
	char addr[INET6_ADDRSTRLEN];
	bool sec_ads = (lp_security() == SEC_ADS);

	if (sec_ads) {
		domain = lp_realm();
	} else {
		domain = c->opt_target_workgroup;
	}

	if (argc > 0)
		domain=argv[0];

	/* first get PDC */
	if (!get_pdc_ip(domain, &ss))
		return -1;

	print_sockaddr(addr, sizeof(addr), &ss);
	if (asprintf(&pdc_str, "%s", addr) == -1) {
		return -1;
	}
	d_printf("%s\n", pdc_str);

	sitename = sitename_fetch(talloc_tos(), domain);
	if (!NT_STATUS_IS_OK(get_sorted_dc_list(domain, sitename,
					&ip_list, &count, sec_ads))) {
		SAFE_FREE(pdc_str);
		TALLOC_FREE(sitename);
		return 0;
	}
	TALLOC_FREE(sitename);
	for (i=0;i<count;i++) {
		print_sockaddr(addr, sizeof(addr), &ip_list[i].ss);
		if (!strequal(pdc_str, addr))
			d_printf("%s\n", addr);
	}
	SAFE_FREE(pdc_str);
	return 0;
}
void set_server_role(void)
{
	server_role = ROLE_STANDALONE;

	switch (lp_security()) {
		case SEC_SHARE:
			if (lp_domain_logons())
				DEBUG(0, ("Server's Role (logon server) conflicts with share-level security\n"));
			break;
		case SEC_SERVER:
			if (lp_domain_logons())
				DEBUG(0, ("Server's Role (logon server) conflicts with server-level security\n"));
			/* this used to be considered ROLE_DOMAIN_MEMBER but that's just wrong */
			server_role = ROLE_STANDALONE;
			break;
		case SEC_DOMAIN:
			if (lp_domain_logons()) {
				DEBUG(1, ("Server's Role (logon server) NOT ADVISED with domain-level security\n"));
				server_role = ROLE_DOMAIN_BDC;
				break;
			}
			server_role = ROLE_DOMAIN_MEMBER;
			break;
		case SEC_ADS:
			if (lp_domain_logons()) {
				server_role = ROLE_DOMAIN_PDC;
				break;
			}
			server_role = ROLE_DOMAIN_MEMBER;
			break;
		case SEC_USER:
			if (lp_domain_logons()) {

				if (lp_domain_master_true_or_auto()) /* auto or yes */
					server_role = ROLE_DOMAIN_PDC;
				else
					server_role = ROLE_DOMAIN_BDC;
			}
			break;
		default:
			DEBUG(0, ("Server's Role undefined due to unknown security mode\n"));
			break;
	}

	DEBUG(10, ("set_server_role: role = %s\n", server_role_str(server_role)));
}
Example #17
0
int register_initial_vuid(void)
{
	user_struct *vuser;

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

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

	if((vuser = talloc_zero(NULL, user_struct)) == NULL) {
		DEBUG(0,("register_initial_vuid: "
				"Failed to talloc users struct!\n"));
		return UID_FIELD_INVALID;
	}

	/* Allocate a free vuid. Yes this is a linear search... */
	while( get_valid_user_struct_internal(next_vuid,
			SERVER_ALLOCATED_REQUIRED_ANY) != NULL ) {
		increment_next_vuid(&next_vuid);
	}

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

	vuser->vuid = next_vuid;

	/*
	 * This happens in an unfinished NTLMSSP session setup. We
	 * need to allocate a vuid between the first and second calls
	 * to NTLMSSP.
	 */
	increment_next_vuid(&next_vuid);
	num_validated_vuids++;

	DLIST_ADD(validated_users, vuser);
	return vuser->vuid;
}
Example #18
0
static void reply_lanman1(struct smb_request *req, uint16 choice)
{
	int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
	int secword=0;
	time_t t = time(NULL);
	struct smbd_server_connection *sconn = req->sconn;

	sconn->smb1.negprot.encrypted_passwords = lp_encrypted_passwords();

	if (lp_security()>=SEC_USER) {
		secword |= NEGOTIATE_SECURITY_USER_LEVEL;
	}
	if (sconn->smb1.negprot.encrypted_passwords) {
		secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
	}

	reply_outbuf(req, 13, sconn->smb1.negprot.encrypted_passwords?8:0);

	SSVAL(req->outbuf,smb_vwv0,choice);
	SSVAL(req->outbuf,smb_vwv1,secword);
	/* Create a token value and add it to the outgoing packet. */
	if (sconn->smb1.negprot.encrypted_passwords) {
		get_challenge(sconn, (uint8 *)smb_buf(req->outbuf));
		SSVAL(req->outbuf,smb_vwv11, 8);
	}

	set_Protocol(PROTOCOL_LANMAN1);

	/* Reply, SMBlockread, SMBwritelock supported. */
	SCVAL(req->outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
	SSVAL(req->outbuf,smb_vwv2,sconn->smb1.negprot.max_recv);
	SSVAL(req->outbuf,smb_vwv3,lp_maxmux()); /* maxmux */
	SSVAL(req->outbuf,smb_vwv4,1);
	SSVAL(req->outbuf,smb_vwv5,raw); /* tell redirector we support
		readbraw writebraw (possibly) */
	SIVAL(req->outbuf,smb_vwv6,sys_getpid());
	SSVAL(req->outbuf,smb_vwv10, set_server_zone_offset(t)/60);

	srv_put_dos_date((char *)req->outbuf,smb_vwv8,t);

	return;
}
Example #19
0
static bool fillup_pw_field(const char *lp_template,
                            const char *username,
                            const char *domname,
                            uid_t uid,
                            gid_t gid,
                            const char *in,
                            fstring out)
{
    char *templ;

    if (out == NULL)
        return False;

    /* The substitution of %U and %D in the 'template
       homedir' is done by talloc_sub_specified() below.
       If we have an in string (which means the value has already
       been set in the nss_info backend), then use that.
       Otherwise use the template value passed in. */

    if ( in && !strequal(in,"") && lp_security() == SEC_ADS ) {
        templ = talloc_sub_specified(NULL, in,
                                     username, domname,
                                     uid, gid);
    } else {
        templ = talloc_sub_specified(NULL, lp_template,
                                     username, domname,
                                     uid, gid);
    }

    if (!templ)
        return False;

    safe_strcpy(out, templ, sizeof(fstring) - 1);
    TALLOC_FREE(templ);

    return True;

}
Example #20
0
File: negprot.c Project: aosm/samba
static int reply_lanman1(char *inbuf, char *outbuf)
{
	int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
	int secword=0;
	time_t t = time(NULL);

	global_encrypted_passwords_negotiated = lp_encrypted_passwords();

	if (lp_security()>=SEC_USER)
		secword |= NEGOTIATE_SECURITY_USER_LEVEL;
	if (global_encrypted_passwords_negotiated)
		secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;

	set_message(outbuf,13,global_encrypted_passwords_negotiated?8:0,True);
	SSVAL(outbuf,smb_vwv1,secword); 
	/* Create a token value and add it to the outgoing packet. */
	if (global_encrypted_passwords_negotiated) {
		get_challenge(smb_buf(outbuf));
		SSVAL(outbuf,smb_vwv11, 8);
	}

	Protocol = PROTOCOL_LANMAN1;

	/* Reply, SMBlockread, SMBwritelock supported. */
	SCVAL(outbuf,smb_flg,FLAG_REPLY|FLAG_SUPPORT_LOCKREAD);
	SSVAL(outbuf,smb_vwv2,max_recv);
	SSVAL(outbuf,smb_vwv3,lp_maxmux()); /* maxmux */
	SSVAL(outbuf,smb_vwv4,1);
	SSVAL(outbuf,smb_vwv5,raw); /* tell redirector we support
		readbraw writebraw (possibly) */
	SIVAL(outbuf,smb_vwv6,sys_getpid());
	SSVAL(outbuf,smb_vwv10, set_server_zone_offset(t)/60);

	srv_put_dos_date(outbuf,smb_vwv8,t);

	return (smb_len(outbuf)+4);
}
Example #21
0
File: negprot.c Project: aosm/samba
static int reply_nt1(char *inbuf, char *outbuf)
{
	/* dual names + lock_and_read + nt SMBs + remote API calls */
	int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ|
		CAP_LEVEL_II_OPLOCKS;

	int secword=0;
	char *p, *q;
	BOOL negotiate_spnego = False;
	time_t t = time(NULL);

	global_encrypted_passwords_negotiated = lp_encrypted_passwords();

	/* Check the flags field to see if this is Vista.
	   WinXP sets it and Vista does not. But we have to 
	   distinguish from NT which doesn't set it either. */

	if ( (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY) &&
		((SVAL(inbuf, smb_flg2) & FLAGS2_UNKNOWN_BIT4) == 0) ) 
	{
	    	/* Don't override the SAMBA or CIFSFS arch */
		if ((get_remote_arch() != RA_SAMBA) && (get_remote_arch() != RA_CIFSFS)) {
			set_remote_arch( RA_VISTA );
		}
	}

	/* do spnego in user level security if the client
	   supports it and we can do encrypted passwords */
	
	if (global_encrypted_passwords_negotiated && 
	    (lp_security() != SEC_SHARE) &&
	    lp_use_spnego() &&
	    (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
		negotiate_spnego = True;
		capabilities |= CAP_EXTENDED_SECURITY;
		add_to_common_flags2(FLAGS2_EXTENDED_SECURITY);
		/* Ensure FLAGS2_EXTENDED_SECURITY gets set in this reply (already
			partially constructed. */
		SSVAL(outbuf,smb_flg2, SVAL(outbuf,smb_flg2) | FLAGS2_EXTENDED_SECURITY);
	}
	
	capabilities |= CAP_NT_SMBS|CAP_RPC_REMOTE_APIS|CAP_UNICODE;

	if (lp_unix_extensions()) {
		capabilities |= CAP_UNIX;
	}
	
	if (lp_large_readwrite() && (SMB_OFF_T_BITS == 64))
		capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_W2K_SMBS;
	
	if (SMB_OFF_T_BITS == 64)
		capabilities |= CAP_LARGE_FILES;

	if (lp_readraw() && lp_writeraw())
		capabilities |= CAP_RAW_MODE;
	
	if (lp_nt_status_support())
		capabilities |= CAP_STATUS32;
	
	if (lp_host_msdfs())
		capabilities |= CAP_DFS;
	
	if (lp_security() >= SEC_USER)
		secword |= NEGOTIATE_SECURITY_USER_LEVEL;
	if (global_encrypted_passwords_negotiated)
		secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
	
	if (lp_server_signing()) {
	       	if (lp_security() >= SEC_USER) {
			secword |= NEGOTIATE_SECURITY_SIGNATURES_ENABLED;
			/* No raw mode with smb signing. */
			capabilities &= ~CAP_RAW_MODE;
			if (lp_server_signing() == Required)
				secword |=NEGOTIATE_SECURITY_SIGNATURES_REQUIRED;
			srv_set_signing_negotiated();
		} else {
			DEBUG(0,("reply_nt1: smb signing is incompatible with share level security !\n"));
			if (lp_server_signing() == Required) {
				exit_server_cleanly("reply_nt1: smb signing required and share level security selected.");
			}
		}
	}

	set_message(outbuf,17,0,True);
	
	SCVAL(outbuf,smb_vwv1,secword);
	
	Protocol = PROTOCOL_NT1;
	
	SSVAL(outbuf,smb_vwv1+1,lp_maxmux()); /* maxmpx */
	SSVAL(outbuf,smb_vwv2+1,1); /* num vcs */
	SIVAL(outbuf,smb_vwv3+1,max_recv); /* max buffer. LOTS! */
	SIVAL(outbuf,smb_vwv5+1,0x10000); /* raw size. full 64k */
	SIVAL(outbuf,smb_vwv7+1,sys_getpid()); /* session key */
	SIVAL(outbuf,smb_vwv9+1,capabilities); /* capabilities */
	put_long_date(outbuf+smb_vwv11+1,t);
	SSVALS(outbuf,smb_vwv15+1,set_server_zone_offset(t)/60);
	
	p = q = smb_buf(outbuf);
	if (!negotiate_spnego) {
		/* Create a token value and add it to the outgoing packet. */
		if (global_encrypted_passwords_negotiated) {
			/* note that we do not send a challenge at all if
			   we are using plaintext */
			get_challenge(p);
			SCVAL(outbuf,smb_vwv16+1,8);
			p += 8;
		}
		p += srvstr_push(outbuf, p, lp_workgroup(), BUFFER_SIZE - (p-outbuf), 
				 STR_UNICODE|STR_TERMINATE|STR_NOALIGN);
		DEBUG(3,("not using SPNEGO\n"));
	} else {
		DATA_BLOB spnego_blob = negprot_spnego();

		if (spnego_blob.data == NULL) {
			return ERROR_NT(NT_STATUS_NO_MEMORY);
		}

		memcpy(p, spnego_blob.data, spnego_blob.length);
		p += spnego_blob.length;
		data_blob_free(&spnego_blob);

		SCVAL(outbuf,smb_vwv16+1, 0);
		DEBUG(3,("using SPNEGO\n"));
	}
	
	SSVAL(outbuf,smb_vwv17, p - q); /* length of challenge+domain strings */
	set_message_end(outbuf, p);
	
	return (smb_len(outbuf)+4);
}
Example #22
0
File: negprot.c Project: aosm/samba
static DATA_BLOB negprot_spnego(void)
{
	DATA_BLOB blob;
	nstring dos_name;
	fstring unix_name;
#ifdef DEVELOPER
	size_t slen;
#endif
	char guid[17];
	const char *OIDs_krb5[] = {OID_KERBEROS5,
				   OID_KERBEROS5_OLD,
				   OID_NTLMSSP,
				   NULL};
	const char *OIDs_plain[] = {OID_NTLMSSP, NULL};

	global_spnego_negotiated = True;

	memset(guid, '\0', sizeof(guid));

	safe_strcpy(unix_name, global_myname(), sizeof(unix_name)-1);
	strlower_m(unix_name);
	push_ascii_nstring(dos_name, unix_name);
	safe_strcpy(guid, dos_name, sizeof(guid)-1);

#ifdef DEVELOPER
	/* Fix valgrind 'uninitialized bytes' issue. */
	slen = strlen(dos_name);
	if (slen < sizeof(guid)) {
		memset(guid+slen, '\0', sizeof(guid) - slen);
	}
#endif

	/* strangely enough, NT does not sent the single OID NTLMSSP when
	   not a ADS member, it sends no OIDs at all

	   OLD COMMENT : "we can't do this until we teach our sesssion setup parser to know
		   about raw NTLMSSP (clients send no ASN.1 wrapping if we do this)"

	   Our sessionsetup code now handles raw NTLMSSP connects, so we can go
	   back to doing what W2K3 does here. This is needed to make PocketPC 2003
	   CIFS connections work with SPNEGO. See bugzilla bugs #1828 and #3133
	   for details. JRA.

	*/

	if (lp_security() != SEC_ADS && !lp_use_kerberos_keytab()) {
#if 0
		/* Code for PocketPC client */
		blob = data_blob(guid, 16);
#else
		/* Code for standalone WXP client */
		blob = spnego_gen_negTokenInit(guid, OIDs_plain, "NONE");
#endif
	} else {
		fstring myname;
		char *host_princ_s = NULL;

		const char * lkdc_realm =
			lp_parm_talloc_string(GLOBAL_SECTION_SNUM,
				"com.apple", "lkdc realm", NULL);

		myname[0] = '\0';
		get_mydnsfullname(myname);
		strlower_m(myname);

		/* If we have a LKDC, use it unless there is a managed realm
		 * also configured. The managed realm should have precedence.
		 */
		if (lkdc_realm && (*lp_realm() == '\0' ||
				strcmp(lkdc_realm, lp_realm()) == 0)) {
			asprintf(&host_princ_s,
				"cifs/%s@%s", lkdc_realm, lkdc_realm);
		} else {
			asprintf(&host_princ_s, "cifs/%s@%s",
					myname, lp_realm());
		}

		blob = spnego_gen_negTokenInit(guid, OIDs_krb5, host_princ_s);

		SAFE_FREE(host_princ_s);
		TALLOC_FREE(lkdc_realm);
	}

	return blob;
}
Example #23
0
connection_struct *make_connection_snum(struct smbd_server_connection *sconn,
					int snum, user_struct *vuser,
					DATA_BLOB password,
					const char *pdev,
					NTSTATUS *pstatus)
{
	connection_struct *conn;
	struct smb_filename *smb_fname_cpath = NULL;
	fstring dev;
	int ret;
	char addr[INET6_ADDRSTRLEN];
	bool on_err_call_dis_hook = false;
	NTSTATUS status;

	fstrcpy(dev, pdev);

	if (NT_STATUS_IS_ERR(*pstatus = share_sanity_checks(snum, dev))) {
		return NULL;
	}	

	conn = conn_new(sconn);
	if (!conn) {
		DEBUG(0,("Couldn't find free connection.\n"));
		*pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
		return NULL;
	}

	conn->params->service = snum;

	status = create_connection_server_info(sconn,
		conn, snum, vuser ? vuser->server_info : NULL, password,
		&conn->server_info);

	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("create_connection_server_info failed: %s\n",
			  nt_errstr(status)));
		*pstatus = status;
		conn_free(conn);
		return NULL;
	}

	if ((lp_guest_only(snum)) || (lp_security() == SEC_SHARE)) {
		conn->force_user = true;
	}

	add_session_user(sconn, conn->server_info->unix_name);

	safe_strcpy(conn->client_address,
			client_addr(get_client_fd(),addr,sizeof(addr)), 
			sizeof(conn->client_address)-1);
	conn->num_files_open = 0;
	conn->lastused = conn->lastused_count = time(NULL);
	conn->used = True;
	conn->printer = (strncmp(dev,"LPT",3) == 0);
	conn->ipc = ( (strncmp(dev,"IPC",3) == 0) ||
		      ( lp_enable_asu_support() && strequal(dev,"ADMIN$")) );

	/* Case options for the share. */
	if (lp_casesensitive(snum) == Auto) {
		/* We will be setting this per packet. Set to be case
		 * insensitive for now. */
		conn->case_sensitive = False;
	} else {
		conn->case_sensitive = (bool)lp_casesensitive(snum);
	}

	conn->case_preserve = lp_preservecase(snum);
	conn->short_case_preserve = lp_shortpreservecase(snum);

	conn->encrypt_level = lp_smb_encrypt(snum);

	conn->veto_list = NULL;
	conn->hide_list = NULL;
	conn->veto_oplock_list = NULL;
	conn->aio_write_behind_list = NULL;

	conn->read_only = lp_readonly(SNUM(conn));
	conn->admin_user = False;

	if (*lp_force_user(snum)) {

		/*
		 * Replace conn->server_info with a completely faked up one
		 * from the username we are forced into :-)
		 */

		char *fuser;
		struct auth_serversupplied_info *forced_serverinfo;

		fuser = talloc_string_sub(conn, lp_force_user(snum), "%S",
					  lp_servicename(snum));
		if (fuser == NULL) {
			conn_free(conn);
			*pstatus = NT_STATUS_NO_MEMORY;
			return NULL;
		}

		status = make_serverinfo_from_username(
			conn, fuser, conn->server_info->guest,
			&forced_serverinfo);
		if (!NT_STATUS_IS_OK(status)) {
			conn_free(conn);
			*pstatus = status;
			return NULL;
		}

		TALLOC_FREE(conn->server_info);
		conn->server_info = forced_serverinfo;

		conn->force_user = True;
		DEBUG(3,("Forced user %s\n", fuser));
	}

	/*
	 * If force group is true, then override
	 * any groupid stored for the connecting user.
	 */

	if (*lp_force_group(snum)) {

		status = find_forced_group(
			conn->force_user, snum, conn->server_info->unix_name,
			&conn->server_info->ptok->user_sids[1],
			&conn->server_info->utok.gid);

		if (!NT_STATUS_IS_OK(status)) {
			conn_free(conn);
			*pstatus = status;
			return NULL;
		}

		/*
		 * We need to cache this gid, to use within
 		 * change_to_user() separately from the conn->server_info
 		 * struct. We only use conn->server_info directly if
 		 * "force_user" was set.
 		 */
		conn->force_group_gid = conn->server_info->utok.gid;
	}

	conn->vuid = (vuser != NULL) ? vuser->vuid : UID_FIELD_INVALID;

	{
		char *s = talloc_sub_advanced(talloc_tos(),
					lp_servicename(SNUM(conn)),
					conn->server_info->unix_name,
					conn->connectpath,
					conn->server_info->utok.gid,
					conn->server_info->sanitized_username,
					pdb_get_domain(conn->server_info->sam_account),
					lp_pathname(snum));
		if (!s) {
			conn_free(conn);
			*pstatus = NT_STATUS_NO_MEMORY;
			return NULL;
		}

		if (!set_conn_connectpath(conn,s)) {
			TALLOC_FREE(s);
			conn_free(conn);
			*pstatus = NT_STATUS_NO_MEMORY;
			return NULL;
		}
		DEBUG(3,("Connect path is '%s' for service [%s]\n",s,
			 lp_servicename(snum)));
		TALLOC_FREE(s);
	}

	/*
	 * New code to check if there's a share security descripter
	 * added from NT server manager. This is done after the
	 * smb.conf checks are done as we need a uid and token. JRA.
	 *
	 */

	{
		bool can_write = False;

		can_write = share_access_check(conn->server_info->ptok,
					       lp_servicename(snum),
					       FILE_WRITE_DATA);

		if (!can_write) {
			if (!share_access_check(conn->server_info->ptok,
						lp_servicename(snum),
						FILE_READ_DATA)) {
				/* No access, read or write. */
				DEBUG(0,("make_connection: connection to %s "
					 "denied due to security "
					 "descriptor.\n",
					  lp_servicename(snum)));
				conn_free(conn);
				*pstatus = NT_STATUS_ACCESS_DENIED;
				return NULL;
			} else {
				conn->read_only = True;
			}
		}
	}
	/* Initialise VFS function pointers */

	if (!smbd_vfs_init(conn)) {
		DEBUG(0, ("vfs_init failed for service %s\n",
			  lp_servicename(snum)));
		conn_free(conn);
		*pstatus = NT_STATUS_BAD_NETWORK_NAME;
		return NULL;
	}

	/*
	 * If widelinks are disallowed we need to canonicalise the connect
	 * path here to ensure we don't have any symlinks in the
	 * connectpath. We will be checking all paths on this connection are
	 * below this directory. We must do this after the VFS init as we
	 * depend on the realpath() pointer in the vfs table. JRA.
	 */
	if (!lp_widelinks(snum)) {
		if (!canonicalize_connect_path(conn)) {
			DEBUG(0, ("canonicalize_connect_path failed "
			"for service %s, path %s\n",
				lp_servicename(snum),
				conn->connectpath));
			conn_free(conn);
			*pstatus = NT_STATUS_BAD_NETWORK_NAME;
			return NULL;
		}
	}

	if ((!conn->printer) && (!conn->ipc)) {
		conn->notify_ctx = notify_init(conn, server_id_self(),
					       smbd_messaging_context(),
					       smbd_event_context(),
					       conn);
	}

/* ROOT Activities: */	
	/*
	 * Enforce the max connections parameter.
	 */

	if ((lp_max_connections(snum) > 0)
	    && (count_current_connections(lp_servicename(SNUM(conn)), True) >=
		lp_max_connections(snum))) {

		DEBUG(1, ("Max connections (%d) exceeded for %s\n",
			  lp_max_connections(snum), lp_servicename(snum)));
		conn_free(conn);
		*pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
		return NULL;
	}  

	/*
	 * Get us an entry in the connections db
	 */
	if (!claim_connection(conn, lp_servicename(snum), 0)) {
		DEBUG(1, ("Could not store connections entry\n"));
		conn_free(conn);
		*pstatus = NT_STATUS_INTERNAL_DB_ERROR;
		return NULL;
	}  

	/* Preexecs are done here as they might make the dir we are to ChDir
	 * to below */
	/* execute any "root preexec = " line */
	if (*lp_rootpreexec(snum)) {
		char *cmd = talloc_sub_advanced(talloc_tos(),
					lp_servicename(SNUM(conn)),
					conn->server_info->unix_name,
					conn->connectpath,
					conn->server_info->utok.gid,
					conn->server_info->sanitized_username,
					pdb_get_domain(conn->server_info->sam_account),
					lp_rootpreexec(snum));
		DEBUG(5,("cmd=%s\n",cmd));
		ret = smbrun(cmd,NULL);
		TALLOC_FREE(cmd);
		if (ret != 0 && lp_rootpreexec_close(snum)) {
			DEBUG(1,("root preexec gave %d - failing "
				 "connection\n", ret));
			yield_connection(conn, lp_servicename(snum));
			conn_free(conn);
			*pstatus = NT_STATUS_ACCESS_DENIED;
			return NULL;
		}
	}

/* USER Activites: */
	if (!change_to_user(conn, conn->vuid)) {
		/* No point continuing if they fail the basic checks */
		DEBUG(0,("Can't become connected user!\n"));
		yield_connection(conn, lp_servicename(snum));
		conn_free(conn);
		*pstatus = NT_STATUS_LOGON_FAILURE;
		return NULL;
	}

	/* Remember that a different vuid can connect later without these
	 * checks... */
	
	/* Preexecs are done here as they might make the dir we are to ChDir
	 * to below */

	/* execute any "preexec = " line */
	if (*lp_preexec(snum)) {
		char *cmd = talloc_sub_advanced(talloc_tos(),
					lp_servicename(SNUM(conn)),
					conn->server_info->unix_name,
					conn->connectpath,
					conn->server_info->utok.gid,
					conn->server_info->sanitized_username,
					pdb_get_domain(conn->server_info->sam_account),
					lp_preexec(snum));
		ret = smbrun(cmd,NULL);
		TALLOC_FREE(cmd);
		if (ret != 0 && lp_preexec_close(snum)) {
			DEBUG(1,("preexec gave %d - failing connection\n",
				 ret));
			*pstatus = NT_STATUS_ACCESS_DENIED;
			goto err_root_exit;
		}
	}

#ifdef WITH_FAKE_KASERVER
	if (lp_afs_share(snum)) {
		afs_login(conn);
	}
#endif
	
	/* Add veto/hide lists */
	if (!IS_IPC(conn) && !IS_PRINT(conn)) {
		set_namearray( &conn->veto_list, lp_veto_files(snum));
		set_namearray( &conn->hide_list, lp_hide_files(snum));
		set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(snum));
		set_namearray( &conn->aio_write_behind_list,
				lp_aio_write_behind(snum));
	}
	
	/* Invoke VFS make connection hook - do this before the VFS_STAT call
	   to allow any filesystems needing user credentials to initialize
	   themselves. */

	if (SMB_VFS_CONNECT(conn, lp_servicename(snum),
			    conn->server_info->unix_name) < 0) {
		DEBUG(0,("make_connection: VFS make connection failed!\n"));
		*pstatus = NT_STATUS_UNSUCCESSFUL;
		goto err_root_exit;
	}

	/* Any error exit after here needs to call the disconnect hook. */
	on_err_call_dis_hook = true;

	status = create_synthetic_smb_fname(talloc_tos(), conn->connectpath,
					    NULL, NULL, &smb_fname_cpath);
	if (!NT_STATUS_IS_OK(status)) {
		*pstatus = status;
		goto err_root_exit;
	}

	/* win2000 does not check the permissions on the directory
	   during the tree connect, instead relying on permission
	   check during individual operations. To match this behaviour
	   I have disabled this chdir check (tridge) */
	/* the alternative is just to check the directory exists */
	if ((ret = SMB_VFS_STAT(conn, smb_fname_cpath)) != 0 ||
	    !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
		if (ret == 0 && !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
			DEBUG(0,("'%s' is not a directory, when connecting to "
				 "[%s]\n", conn->connectpath,
				 lp_servicename(snum)));
		} else {
			DEBUG(0,("'%s' does not exist or permission denied "
				 "when connecting to [%s] Error was %s\n",
				 conn->connectpath, lp_servicename(snum),
				 strerror(errno) ));
		}
		*pstatus = NT_STATUS_BAD_NETWORK_NAME;
		goto err_root_exit;
	}

	string_set(&conn->origpath,conn->connectpath);

#if SOFTLINK_OPTIMISATION
	/* resolve any soft links early if possible */
	if (vfs_ChDir(conn,conn->connectpath) == 0) {
		TALLOC_CTX *ctx = talloc_tos();
		char *s = vfs_GetWd(ctx,s);
		if (!s) {
			*status = map_nt_error_from_unix(errno);
			goto err_root_exit;
		}
		if (!set_conn_connectpath(conn,s)) {
			*status = NT_STATUS_NO_MEMORY;
			goto err_root_exit;
		}
		vfs_ChDir(conn,conn->connectpath);
	}
#endif

	if (lp_unix_extensions() && lp_widelinks(snum)) {
		DEBUG(0,("Share '%s' has wide links and unix extensions enabled. "
			"These parameters are incompatible. "
			"Disabling wide links for this share.\n",
			lp_servicename(snum) ));
		lp_do_parameter(snum, "wide links", "False");
	}

	/* Figure out the characteristics of the underlying filesystem. This
	 * assumes that all the filesystem mounted withing a share path have
	 * the same characteristics, which is likely but not guaranteed.
	 */

	conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);

	/*
	 * Print out the 'connected as' stuff here as we need
	 * to know the effective uid and gid we will be using
	 * (at least initially).
	 */

	if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
		dbgtext( "%s (%s) ", get_remote_machine_name(),
			 conn->client_address );
		dbgtext( "%s", srv_is_signing_active(smbd_server_conn) ? "signed " : "");
		dbgtext( "connect to service %s ", lp_servicename(snum) );
		dbgtext( "initially as user %s ",
			 conn->server_info->unix_name );
		dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
		dbgtext( "(pid %d)\n", (int)sys_getpid() );
	}

	/* we've finished with the user stuff - go back to root */
	change_to_root_user();
	return(conn);

  err_root_exit:
	TALLOC_FREE(smb_fname_cpath);
	change_to_root_user();
	if (on_err_call_dis_hook) {
		/* Call VFS disconnect hook */
		SMB_VFS_DISCONNECT(conn);
	}
	yield_connection(conn, lp_servicename(snum));
	conn_free(conn);
	return NULL;
}
Example #24
0
static NTSTATUS create_connection_server_info(struct smbd_server_connection *sconn,
					      TALLOC_CTX *mem_ctx, int snum,
                                              struct auth_serversupplied_info *vuid_serverinfo,
					      DATA_BLOB password,
                                              struct auth_serversupplied_info **presult)
{
        if (lp_guest_only(snum)) {
                return make_server_info_guest(mem_ctx, presult);
        }

        if (vuid_serverinfo != NULL) {

		struct auth_serversupplied_info *result;

                /*
                 * This is the normal security != share case where we have a
                 * valid vuid from the session setup.                 */

                if (vuid_serverinfo->guest) {
                        if (!lp_guest_ok(snum)) {
                                DEBUG(2, ("guest user (from session setup) "
                                          "not permitted to access this share "
                                          "(%s)\n", lp_servicename(snum)));
                                return NT_STATUS_ACCESS_DENIED;
                        }
                } else {
                        if (!user_ok_token(vuid_serverinfo->unix_name,
					   pdb_get_domain(vuid_serverinfo->sam_account),
                                           vuid_serverinfo->ptok, snum)) {
                                DEBUG(2, ("user '%s' (from session setup) not "
                                          "permitted to access this share "
                                          "(%s)\n",
                                          vuid_serverinfo->unix_name,
                                          lp_servicename(snum)));
                                return NT_STATUS_ACCESS_DENIED;
                        }
                }

                result = copy_serverinfo(mem_ctx, vuid_serverinfo);
		if (result == NULL) {
			return NT_STATUS_NO_MEMORY;
		}

		*presult = result;
		return NT_STATUS_OK;
        }

        if (lp_security() == SEC_SHARE) {

                fstring user;
		bool guest;

                /* add the sharename as a possible user name if we
                   are in share mode security */

                add_session_user(sconn, lp_servicename(snum));

                /* shall we let them in? */

                if (!authorise_login(sconn, snum,user,password,&guest)) {
                        DEBUG( 2, ( "Invalid username/password for [%s]\n",
                                    lp_servicename(snum)) );
			return NT_STATUS_WRONG_PASSWORD;
                }

		return make_serverinfo_from_username(mem_ctx, user, guest,
						     presult);
        }

	DEBUG(0, ("invalid VUID (vuser) but not in security=share\n"));
	return NT_STATUS_ACCESS_DENIED;
}
Example #25
0
connection_struct *make_connection(struct smbd_server_connection *sconn,
				   const char *service_in, DATA_BLOB password,
				   const char *pdev, uint16 vuid,
				   NTSTATUS *status)
{
	uid_t euid;
	user_struct *vuser = NULL;
	fstring service;
	fstring dev;
	int snum = -1;
	char addr[INET6_ADDRSTRLEN];

	fstrcpy(dev, pdev);

	/* This must ONLY BE CALLED AS ROOT. As it exits this function as
	 * root. */
	if (!non_root_mode() && (euid = geteuid()) != 0) {
		DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot "
			 "(%u)\n", (unsigned int)euid ));
		smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
	}

	if (conn_num_open(sconn) > 2047) {
		*status = NT_STATUS_INSUFF_SERVER_RESOURCES;
		return NULL;
	}

	if(lp_security() != SEC_SHARE) {
		vuser = get_valid_user_struct(sconn, vuid);
		if (!vuser) {
			DEBUG(1,("make_connection: refusing to connect with "
				 "no session setup\n"));
			*status = NT_STATUS_ACCESS_DENIED;
			return NULL;
		}
	}

	/* Logic to try and connect to the correct [homes] share, preferably
	   without too many getpwnam() lookups.  This is particulary nasty for
	   winbind usernames, where the share name isn't the same as unix
	   username.

	   The snum of the homes share is stored on the vuser at session setup
	   time.
	*/

	if (strequal(service_in,HOMES_NAME)) {
		if(lp_security() != SEC_SHARE) {
			DATA_BLOB no_pw = data_blob_null;
			if (vuser->homes_snum == -1) {
				DEBUG(2, ("[homes] share not available for "
					  "this user because it was not found "
					  "or created at session setup "
					  "time\n"));
				*status = NT_STATUS_BAD_NETWORK_NAME;
				return NULL;
			}
			DEBUG(5, ("making a connection to [homes] service "
				  "created at session setup time\n"));
			return make_connection_snum(sconn,
						    vuser->homes_snum,
						    vuser, no_pw, 
						    dev, status);
		} else {
			/* Security = share. Try with
			 * current_user_info.smb_name as the username.  */
			if (*current_user_info.smb_name) {
				fstring unix_username;
				fstrcpy(unix_username,
					current_user_info.smb_name);
				map_username(sconn, unix_username);
				snum = find_service(unix_username);
			} 
			if (snum != -1) {
				DEBUG(5, ("making a connection to 'homes' "
					  "service %s based on "
					  "security=share\n", service_in));
				return make_connection_snum(sconn,
							    snum, NULL,
							    password,
							    dev, status);
			}
		}
	} else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
		   && strequal(service_in,
			       lp_servicename(vuser->homes_snum))) {
		DATA_BLOB no_pw = data_blob_null;
		DEBUG(5, ("making a connection to 'homes' service [%s] "
			  "created at session setup time\n", service_in));
		return make_connection_snum(sconn,
					    vuser->homes_snum,
					    vuser, no_pw, 
					    dev, status);
	}
	
	fstrcpy(service, service_in);

	strlower_m(service);

	snum = find_service(service);

	if (snum < 0) {
		if (strequal(service,"IPC$") ||
		    (lp_enable_asu_support() && strequal(service,"ADMIN$"))) {
			DEBUG(3,("refusing IPC connection to %s\n", service));
			*status = NT_STATUS_ACCESS_DENIED;
			return NULL;
		}

		DEBUG(3,("%s (%s) couldn't find service %s\n",
			get_remote_machine_name(),
			client_addr(get_client_fd(),addr,sizeof(addr)),
			service));
		*status = NT_STATUS_BAD_NETWORK_NAME;
		return NULL;
	}

	/* Handle non-Dfs clients attempting connections to msdfs proxy */
	if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0'))  {
		DEBUG(3, ("refusing connection to dfs proxy share '%s' "
			  "(pointing to %s)\n", 
			service, lp_msdfs_proxy(snum)));
		*status = NT_STATUS_BAD_NETWORK_NAME;
		return NULL;
	}

	DEBUG(5, ("making a connection to 'normal' service %s\n", service));

	return make_connection_snum(sconn, snum, vuser,
				    password,
				    dev, status);
}
Example #26
0
 int main(int argc, char *argv[])
{
	int c;
	int profile_only = 0;
	bool show_processes, show_locks, show_shares;
	poptContext pc;
	struct poptOption long_options[] = {
		POPT_AUTOHELP
		{"processes",	'p', POPT_ARG_NONE,	NULL, 'p', "Show processes only" },
		{"verbose",	'v', POPT_ARG_NONE, 	NULL, 'v', "Be verbose" },
		{"locks",	'L', POPT_ARG_NONE,	NULL, 'L', "Show locks only" },
		{"shares",	'S', POPT_ARG_NONE,	NULL, 'S', "Show shares only" },
		{"user", 	'u', POPT_ARG_STRING,	&username, 'u', "Switch to user" },
		{"brief",	'b', POPT_ARG_NONE, 	NULL, 'b', "Be brief" },
		{"profile",     'P', POPT_ARG_NONE, NULL, 'P', "Do profiling" },
		{"profile-rates", 'R', POPT_ARG_NONE, NULL, 'R', "Show call rates" },
		{"byterange",	'B', POPT_ARG_NONE,	NULL, 'B', "Include byte range locks"},
		{"numeric",	'n', POPT_ARG_NONE,	NULL, 'n', "Numeric uid/gid"},
		POPT_COMMON_SAMBA
		POPT_TABLEEND
	};
	TALLOC_CTX *frame = talloc_stackframe();
	int ret = 0;
	struct messaging_context *msg_ctx;

	sec_init();
	load_case_tables();

	setup_logging(argv[0], DEBUG_STDERR);

	if (getuid() != geteuid()) {
		d_printf("smbstatus should not be run setuid\n");
		ret = 1;
		goto done;
	}

	pc = poptGetContext(NULL, argc, (const char **) argv, long_options, 
			    POPT_CONTEXT_KEEP_FIRST);

	while ((c = poptGetNextOpt(pc)) != -1) {
		switch (c) {
		case 'p':
			processes_only = true;
			break;
		case 'v':
			verbose = true;
			break;
		case 'L':
			locks_only = true;
			break;
		case 'S':
			shares_only = true;
			break;
		case 'b':
			brief = true;
			break;
		case 'u':
			Ucrit_addUid(nametouid(poptGetOptArg(pc)));
			break;
		case 'P':
		case 'R':
			profile_only = c;
			break;
		case 'B':
			show_brl = true;
			break;
		case 'n':
			numeric_only = true;
			break;
		}
	}

	/* setup the flags based on the possible combincations */

	show_processes = !(shares_only || locks_only || profile_only) || processes_only;
	show_locks     = !(shares_only || processes_only || profile_only) || locks_only;
	show_shares    = !(processes_only || locks_only || profile_only) || shares_only;

	if ( username )
		Ucrit_addUid( nametouid(username) );

	if (verbose) {
		d_printf("using configfile = %s\n", get_dyn_CONFIGFILE());
	}

	if (!lp_load_initial_only(get_dyn_CONFIGFILE())) {
		fprintf(stderr, "Can't load %s - run testparm to debug it\n",
			get_dyn_CONFIGFILE());
		ret = -1;
		goto done;
	}


	if (lp_clustering()) {
		/*
		 * This implicitly initializes the global ctdbd
		 * connection, usable by the db_open() calls further
		 * down.
		 */
		msg_ctx = messaging_init(NULL, event_context_init(NULL));
		if (msg_ctx == NULL) {
			fprintf(stderr, "messaging_init failed\n");
			ret = -1;
			goto done;
		}
	}

	if (!lp_load_global(get_dyn_CONFIGFILE())) {
		fprintf(stderr, "Can't load %s - run testparm to debug it\n",
			get_dyn_CONFIGFILE());
		ret = -1;
		goto done;
	}

	switch (profile_only) {
		case 'P':
			/* Dump profile data */
			return status_profile_dump(verbose);
		case 'R':
			/* Continuously display rate-converted data */
			return status_profile_rates(verbose);
		default:
			break;
	}

	if ( show_processes ) {
		d_printf("\nSamba version %s\n",samba_version_string());
		d_printf("PID     Username      Group         Machine                        \n");
		d_printf("-------------------------------------------------------------------\n");
		if (lp_security() == SEC_SHARE) {
			d_printf(" <processes do not show up in "
				 "anonymous mode>\n");
		}

		sessionid_traverse_read(traverse_sessionid, NULL);

		if (processes_only) {
			goto done;
		}
	}

	if ( show_shares ) {
		if (verbose) {
			d_printf("Opened %s\n", lock_path("connections.tdb"));
		}

		if (brief) {
			goto done;
		}

		d_printf("\nService      pid     machine       Connected at\n");
		d_printf("-------------------------------------------------------\n");

		connections_forall_read(traverse_fn1, NULL);

		d_printf("\n");

		if ( shares_only ) {
			goto done;
		}
	}

	if ( show_locks ) {
		int result;
		struct db_context *db;
		db = db_open(NULL, lock_path("locking.tdb"), 0,
			     TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH, O_RDONLY, 0,
			     DBWRAP_LOCK_ORDER_1);

		if (!db) {
			d_printf("%s not initialised\n",
				 lock_path("locking.tdb"));
			d_printf("This is normal if an SMB client has never "
				 "connected to your server.\n");
			exit(0);
		} else {
			TALLOC_FREE(db);
		}

		if (!locking_init_readonly()) {
			d_printf("Can't initialise locking module - exiting\n");
			ret = 1;
			goto done;
		}

		result = share_mode_forall(print_share_mode, NULL);

		if (result == 0) {
			d_printf("No locked files\n");
		} else if (result < 0) {
			d_printf("locked file list truncated\n");
		}

		d_printf("\n");

		if (show_brl) {
			brl_forall(print_brl, NULL);
		}

		locking_end();
	}

done:
	TALLOC_FREE(frame);
	return ret;
}
Example #27
0
File: auth.c Project: sprymak/samba
NTSTATUS make_auth_context_subsystem(TALLOC_CTX *mem_ctx,
				     struct auth_context **auth_context)
{
	char **auth_method_list = NULL; 
	NTSTATUS nt_status;

	if (lp_auth_methods()
	    && !(auth_method_list = str_list_copy(talloc_tos(), 
			      lp_auth_methods()))) {
		return NT_STATUS_NO_MEMORY;
	}

	if (auth_method_list == NULL) {
		switch (lp_security()) 
		{
		case SEC_DOMAIN:
			DEBUG(5,("Making default auth method list for security=domain\n"));
			auth_method_list = str_list_make_v3(
				talloc_tos(), "guest sam winbind:ntdomain",
				NULL);
			break;
		case SEC_SERVER:
			DEBUG(5,("Making default auth method list for security=server\n"));
			auth_method_list = str_list_make_v3(
				talloc_tos(), "guest sam smbserver",
				NULL);
			break;
		case SEC_USER:
			if (lp_encrypted_passwords()) {	
				if ((lp_server_role() == ROLE_DOMAIN_PDC) || (lp_server_role() == ROLE_DOMAIN_BDC)) {
					DEBUG(5,("Making default auth method list for DC, security=user, encrypt passwords = yes\n"));
					auth_method_list = str_list_make_v3(
						talloc_tos(),
						"guest sam winbind:trustdomain",
						NULL);
				} else {
					DEBUG(5,("Making default auth method list for standalone security=user, encrypt passwords = yes\n"));
					auth_method_list = str_list_make_v3(
						talloc_tos(), "guest sam",
						NULL);
				}
			} else {
				DEBUG(5,("Making default auth method list for security=user, encrypt passwords = no\n"));
				auth_method_list = str_list_make_v3(
					talloc_tos(), "guest unix", NULL);
			}
			break;
		case SEC_ADS:
			DEBUG(5,("Making default auth method list for security=ADS\n"));
			auth_method_list = str_list_make_v3(
				talloc_tos(), "guest sam winbind:ntdomain",
				NULL);
			break;
		default:
			DEBUG(5,("Unknown auth method!\n"));
			return NT_STATUS_UNSUCCESSFUL;
		}
	} else {
		DEBUG(5,("Using specified auth order\n"));
	}

	nt_status = make_auth_context_text_list(mem_ctx, auth_context,
						auth_method_list);

	TALLOC_FREE(auth_method_list);
	return nt_status;
}
Example #28
0
static NTSTATUS _idmap_adex_init(struct idmap_domain *dom)
{
	ADS_STRUCT *ads = NULL;
	ADS_STATUS status;
	static NTSTATUS init_status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
	struct dom_sid domain_sid;
	fstring dcname;
	struct sockaddr_storage ip;
	struct likewise_cell *lwcell;

	if (NT_STATUS_IS_OK(init_status))
		return NT_STATUS_OK;

	/* Silently fail if we are not a member server in security = ads */

	if ((lp_server_role() != ROLE_DOMAIN_MEMBER) ||
	    (lp_security() != SEC_ADS)) {
		init_status = NT_STATUS_INVALID_SERVER_STATE;
		BAIL_ON_NTSTATUS_ERROR(init_status);
	}

	/* fetch our domain SID first */

	if (!secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) {
		init_status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
		BAIL_ON_NTSTATUS_ERROR(init_status);
	}

	/* reuse the same ticket cache as winbindd */

	setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1);

	/* Establish a connection to a DC */

	if ((ads = ads_init(lp_realm(), lp_workgroup(), NULL)) == NULL) {
		init_status = NT_STATUS_NO_MEMORY;
		BAIL_ON_NTSTATUS_ERROR(init_status);
	}

	ads->auth.password =
	    secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
	ads->auth.realm = SMB_STRDUP(lp_realm());

	/* get the DC name here to setup the server affinity cache and
	   local krb5.conf */

	get_dc_name(lp_workgroup(), lp_realm(), dcname, &ip);

	status = ads_connect(ads);
	if (!ADS_ERR_OK(status)) {
		DEBUG(0, ("_idmap_adex_init: ads_connect() failed! (%s)\n",
			  ads_errstr(status)));
	}
	init_status = ads_ntstatus(status);
	BAIL_ON_NTSTATUS_ERROR(init_status);


	/* Find out cell membership */

	init_status = cell_locate_membership(ads);
	if (!NT_STATUS_IS_OK(init_status)) {
		DEBUG(0,("LWI: Fail to locate cell membership (%s).",
			 nt_errstr(init_status)));
		goto done;
	}

	/* Fill in the cell information */

	lwcell = cell_list_head();

	init_status = cell_lookup_settings(lwcell);
	BAIL_ON_NTSTATUS_ERROR(init_status);

	/* Miscellaneous setup.  E.g. set up the list of GC
	   servers and domain list for our forest (does not actually
	   connect). */

	init_status = gc_init_list();
	BAIL_ON_NTSTATUS_ERROR(init_status);

	init_status = domain_init_list();
	BAIL_ON_NTSTATUS_ERROR(init_status);

done:
	if (!NT_STATUS_IS_OK(init_status)) {
		DEBUG(1,("Likewise initialization failed (%s)\n",
			 nt_errstr(init_status)));
	}

	/* cleanup */

	if (!NT_STATUS_IS_OK(init_status)) {
		cell_list_destroy();

		/* init_status stores the failure reason but we need to
		   return success or else idmap_init() will drop us from the
		   backend list */
		return NT_STATUS_OK;
	}

	init_status = NT_STATUS_OK;

	return init_status;
}
Example #29
0
/**
 * confirm that a domain join is still valid
 *
 * @return A shell status integer (0 for success)
 *
 **/
NTSTATUS net_rpc_join_ok(struct net_context *c, const char *domain,
			 const char *server, struct sockaddr_storage *pss)
{
	enum security_types sec;
	unsigned int conn_flags = NET_FLAGS_PDC;
	uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS;
	struct cli_state *cli = NULL;
	struct rpc_pipe_client *pipe_hnd = NULL;
	struct rpc_pipe_client *netlogon_pipe = NULL;
	NTSTATUS ntret = NT_STATUS_UNSUCCESSFUL;

	sec = (enum security_types)lp_security();

	if (sec == SEC_ADS) {
		/* Connect to IPC$ using machine account's credentials. We don't use anonymous
		   connection here, as it may be denied by server's local policy. */
		net_use_machine_account(c);

	} else {
		/* some servers (e.g. WinNT) don't accept machine-authenticated
		   smb connections */
		conn_flags |= NET_FLAGS_ANONYMOUS;
	}

	/* Connect to remote machine */
	ntret = net_make_ipc_connection_ex(c, domain, server, pss, conn_flags,
					   &cli);
	if (!NT_STATUS_IS_OK(ntret)) {
		return ntret;
	}

	/* Setup the creds as though we're going to do schannel... */
	ntret = get_schannel_session_key(cli, domain, &neg_flags,
					 &netlogon_pipe);

	/* We return NT_STATUS_INVALID_NETWORK_RESPONSE if the server is refusing
	   to negotiate schannel, but the creds were set up ok. That'll have to do. */

        if (!NT_STATUS_IS_OK(ntret)) {
		if (NT_STATUS_EQUAL(ntret, NT_STATUS_INVALID_NETWORK_RESPONSE)) {
			cli_shutdown(cli);
			return NT_STATUS_OK;
		} else {
			DEBUG(0,("net_rpc_join_ok: failed to get schannel session "
					"key from server %s for domain %s. Error was %s\n",
				cli->desthost, domain, nt_errstr(ntret) ));
			cli_shutdown(cli);
			return ntret;
		}
	}

	/* Only do the rest of the schannel test if the client is allowed to do this. */
	if (!lp_client_schannel()) {
		cli_shutdown(cli);
		/* We're good... */
		return ntret;
	}

	ntret = cli_rpc_pipe_open_schannel_with_key(
		cli, &ndr_table_netlogon.syntax_id, NCACN_NP,
		DCERPC_AUTH_LEVEL_PRIVACY,
		domain, &netlogon_pipe->dc, &pipe_hnd);

	if (!NT_STATUS_IS_OK(ntret)) {
		DEBUG(0,("net_rpc_join_ok: failed to open schannel session "
				"on netlogon pipe to server %s for domain %s. Error was %s\n",
			cli->desthost, domain, nt_errstr(ntret) ));
		/*
		 * Note: here, we have:
		 * (pipe_hnd != NULL) if and only if NT_STATUS_IS_OK(ntret)
		 */
	}

	cli_shutdown(cli);
	return ntret;
}
Example #30
0
NTSTATUS auth_generic_prepare(TALLOC_CTX *mem_ctx,
			      const struct tsocket_address *remote_address,
			      struct gensec_security **gensec_security_out)
{
	struct gensec_security *gensec_security;
	struct auth_context *auth_context;
	NTSTATUS nt_status;

	TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
	NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);

	nt_status = make_auth_context_subsystem(tmp_ctx, &auth_context);
	if (!NT_STATUS_IS_OK(nt_status)) {
		TALLOC_FREE(tmp_ctx);
		return nt_status;
	}

	if (auth_context->prepare_gensec) {
		nt_status = auth_context->prepare_gensec(auth_context, tmp_ctx,
							 &gensec_security);
		if (!NT_STATUS_IS_OK(nt_status)) {
			TALLOC_FREE(tmp_ctx);
			return nt_status;
		}
	} else {
		const struct gensec_security_ops **backends = NULL;
		struct gensec_settings *gensec_settings;
		struct loadparm_context *lp_ctx;
		size_t idx = 0;
		struct cli_credentials *server_credentials;
		const char *dns_name;
		const char *dns_domain;
		struct auth4_context *auth4_context = make_auth4_context_s3(tmp_ctx, auth_context);
		if (auth4_context == NULL) {
			TALLOC_FREE(tmp_ctx);
			return NT_STATUS_NO_MEMORY;
		}

		lp_ctx = loadparm_init_s3(tmp_ctx, loadparm_s3_helpers());
		if (lp_ctx == NULL) {
			DEBUG(10, ("loadparm_init_s3 failed\n"));
			TALLOC_FREE(tmp_ctx);
			return NT_STATUS_INVALID_SERVER_STATE;
		}

		gensec_settings = lpcfg_gensec_settings(tmp_ctx, lp_ctx);
		if (lp_ctx == NULL) {
			DEBUG(10, ("lpcfg_gensec_settings failed\n"));
			TALLOC_FREE(tmp_ctx);
			return NT_STATUS_NO_MEMORY;
		}

		/*
		 * This should be a 'netbios domain -> DNS domain'
		 * mapping, and can currently validly return NULL on
		 * poorly configured systems.
		 *
		 * This is used for the NTLMSSP server
		 *
		 */
		dns_name = get_mydnsfullname();
		if (dns_name == NULL) {
			dns_name = "";
		}

		dns_domain = get_mydnsdomname(tmp_ctx);
		if (dns_domain == NULL) {
			dns_domain = "";
		}

		gensec_settings->server_dns_name = strlower_talloc(gensec_settings, dns_name);
		if (gensec_settings->server_dns_name == NULL) {
			TALLOC_FREE(tmp_ctx);
			return NT_STATUS_NO_MEMORY;
		}

		gensec_settings->server_dns_domain = strlower_talloc(gensec_settings, dns_domain);
		if (gensec_settings->server_dns_domain == NULL) {
			TALLOC_FREE(tmp_ctx);
			return NT_STATUS_NO_MEMORY;
		}

		backends = talloc_zero_array(gensec_settings,
					     const struct gensec_security_ops *, 6);
		if (backends == NULL) {
			TALLOC_FREE(tmp_ctx);
			return NT_STATUS_NO_MEMORY;
		}
		gensec_settings->backends = backends;

		gensec_init();

		/* These need to be in priority order, krb5 before NTLMSSP */
#if defined(HAVE_KRB5)
		backends[idx++] = &gensec_gse_krb5_security_ops;
#endif

		backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_NTLMSSP);

		backends[idx++] = gensec_security_by_oid(NULL, GENSEC_OID_SPNEGO);

		backends[idx++] = gensec_security_by_auth_type(NULL, DCERPC_AUTH_TYPE_SCHANNEL);

		backends[idx++] = gensec_security_by_auth_type(NULL, DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM);

		/*
		 * This is anonymous for now, because we just use it
		 * to set the kerberos state at the moment
		 */
		server_credentials = cli_credentials_init_anon(tmp_ctx);
		if (!server_credentials) {
			DEBUG(0, ("auth_generic_prepare: Failed to init server credentials\n"));
			return NT_STATUS_NO_MEMORY;
		}

		cli_credentials_set_conf(server_credentials, lp_ctx);

		if (lp_security() == SEC_ADS || USE_KERBEROS_KEYTAB) {
			cli_credentials_set_kerberos_state(server_credentials, CRED_AUTO_USE_KERBEROS);
		} else {
			cli_credentials_set_kerberos_state(server_credentials, CRED_DONT_USE_KERBEROS);
		}

		nt_status = gensec_server_start(tmp_ctx, gensec_settings,
						auth4_context, &gensec_security);

		if (!NT_STATUS_IS_OK(nt_status)) {
			TALLOC_FREE(tmp_ctx);
			return nt_status;
		}

		gensec_set_credentials(gensec_security, server_credentials);

		talloc_unlink(tmp_ctx, lp_ctx);
		talloc_unlink(tmp_ctx, server_credentials);
		talloc_unlink(tmp_ctx, gensec_settings);
		talloc_unlink(tmp_ctx, auth4_context);
	}

	nt_status = gensec_set_remote_address(gensec_security,
					      remote_address);
	if (!NT_STATUS_IS_OK(nt_status)) {
		TALLOC_FREE(tmp_ctx);
		return nt_status;
	}

	*gensec_security_out = talloc_steal(mem_ctx, gensec_security);
	TALLOC_FREE(tmp_ctx);
	return NT_STATUS_OK;
}