Beispiel #1
0
static NTSTATUS remote_op_init_server(struct dcesrv_context *dce_ctx, const struct dcesrv_endpoint_server *ep_server)
{
	unsigned int i;
	char **ifaces = str_list_make(dce_ctx, lpcfg_parm_string(dce_ctx->lp_ctx, NULL, "dcerpc_remote", "interfaces"),NULL);

	if (!ifaces) {
		DEBUG(3,("remote_op_init_server: no interfaces configured\n"));
		return NT_STATUS_OK;
	}

	for (i=0;ifaces[i];i++) {
		NTSTATUS ret;
		struct dcesrv_interface iface;
		
		if (!ep_server->interface_by_name(&iface, ifaces[i])) {
			DEBUG(0,("remote_op_init_server: failed to find interface = '%s'\n", ifaces[i]));
			talloc_free(ifaces);
			return NT_STATUS_UNSUCCESSFUL;
		}

		ret = remote_register_one_iface(dce_ctx, &iface);
		if (!NT_STATUS_IS_OK(ret)) {
			DEBUG(0,("remote_op_init_server: failed to register interface = '%s'\n", ifaces[i]));
			talloc_free(ifaces);
			return ret;
		}
	}

	talloc_free(ifaces);
	return NT_STATUS_OK;
}
Beispiel #2
0
/*
  refresh a WINS name registration
*/
static void nbtd_wins_refresh(struct event_context *ev, struct timed_event *te,
                              struct timeval t, void *private_data)
{
    struct nbtd_iface_name *iname = talloc_get_type(private_data, struct nbtd_iface_name);
    struct nbtd_interface *iface = iname->iface;
    struct nbt_name_refresh_wins io;
    struct composite_context *c;
    TALLOC_CTX *tmp_ctx = talloc_new(iname);

    /* setup a wins name refresh request */
    io.in.name            = iname->name;
    io.in.wins_servers    = str_list_make(tmp_ctx, iname->wins_server, NULL);
    io.in.addresses       = nbtd_address_list(iface, tmp_ctx);
    io.in.nb_flags        = iname->nb_flags;
    io.in.ttl             = iname->ttl;

    if (!io.in.addresses) {
        talloc_free(tmp_ctx);
        return;
    }

    c = nbt_name_refresh_wins_send(wins_socket(iface), &io);
    if (c == NULL) {
        talloc_free(tmp_ctx);
        return;
    }
    talloc_steal(c, io.in.addresses);

    c->async.fn = nbtd_wins_refresh_handler;
    c->async.private_data = iname;

    talloc_free(tmp_ctx);
}
Beispiel #3
0
/**
 Set user socket options.
**/
_PUBLIC_ void set_socket_options(int fd, const char *options)
{
	const char **options_list = (const char **)str_list_make(NULL, options, " \t,");
	int j;

	if (!options_list)
		return;

	for (j = 0; options_list[j]; j++) {
		const char *tok = options_list[j];
		int ret=0,i;
		int value = 1;
		char *p;
		bool got_value = false;

		if ((p = strchr(tok,'='))) {
			*p = 0;
			value = atoi(p+1);
			got_value = true;
		}

		for (i=0;socket_options[i].name;i++)
			if (strequal(socket_options[i].name,tok))
				break;

		if (!socket_options[i].name) {
			DEBUG(0,("Unknown socket option %s\n",tok));
			continue;
		}

		switch (socket_options[i].opttype) {
		case OPT_BOOL:
		case OPT_INT:
			ret = setsockopt(fd,socket_options[i].level,
						socket_options[i].option,(char *)&value,sizeof(int));
			break;

		case OPT_ON:
			if (got_value)
				DEBUG(0,("syntax error - %s does not take a value\n",tok));

			{
				int on = socket_options[i].value;
				ret = setsockopt(fd,socket_options[i].level,
							socket_options[i].option,(char *)&on,sizeof(int));
			}
			break;	  
		}
      
		if (ret != 0)
			DEBUG(0,("Failed to set socket option %s (Error %s)\n",tok, strerror(errno) ));
	}

	talloc_free(options_list);
}
Beispiel #4
0
void web_set_lang(const char *lang_string)
{
	char **lang_list, **count;
	struct pri_list *pl;
	int lang_num, i;

	/* build the lang list */
	lang_list = str_list_make(lang_string, ", \t\r\n");
	if (!lang_list) return;
	
	/* sort the list by priority */
	lang_num = 0;
	count = lang_list;
	while (*count && **count) {
		count++;
		lang_num++;
	}
	pl = SMB_MALLOC_ARRAY(struct pri_list, lang_num);
	if (!pl) {
		return;
	}

	for (i = 0; i < lang_num; i++) {
		char *pri_code;
		if ((pri_code=strstr(lang_list[i], ";q="))) {
			*pri_code = '\0';
			pri_code += 3;
			sscanf(pri_code, "%f", &(pl[i].pri));
		} else {
			pl[i].pri = 1;
		}
		pl[i].string = SMB_STRDUP(lang_list[i]);
	}
	str_list_free(&lang_list);

	qsort(pl, lang_num, sizeof(struct pri_list), &qsort_cmp_list);

	/* it's not an error to not initialise - we just fall back to 
	   the default */

	for (i = 0; i < lang_num; i++) {
		if (lang_tdb_init(pl[i].string)) break;
	}

	for (i = 0; i < lang_num; i++) {
		SAFE_FREE(pl[i].string);
	}
	SAFE_FREE(pl);

	return;
}
Beispiel #5
0
static BOOL user_ok(const char *user, int snum)
{
	char **valid, **invalid;
	BOOL ret;

	valid = invalid = NULL;
	ret = True;

	if (lp_invalid_users(snum)) {
		str_list_copy(&invalid, lp_invalid_users(snum));
		if (invalid &&
		    str_list_substitute(invalid, "%S", lp_servicename(snum))) {
			if ( invalid &&
			     str_list_sub_basic(invalid,
						current_user_info.smb_name) ) {
				ret = !user_in_list(user,
						    (const char **)invalid);
			}
		}
	}
	if (invalid)
		str_list_free (&invalid);

	if (ret && lp_valid_users(snum)) {
		str_list_copy(&valid, lp_valid_users(snum));
		if ( valid &&
		     str_list_substitute(valid, "%S", lp_servicename(snum)) ) {
			if ( valid &&
			     str_list_sub_basic(valid,
						current_user_info.smb_name) ) {
				ret = user_in_list(user, (const char **)valid);
			}
		}
	}
	if (valid)
		str_list_free (&valid);

	if (ret && lp_onlyuser(snum)) {
		char **user_list = str_list_make (lp_username(snum), NULL);
		if (user_list &&
		    str_list_substitute(user_list, "%S",
					lp_servicename(snum))) {
			ret = user_in_list(user, (const char **)user_list);
		}
		if (user_list) str_list_free (&user_list);
	}

	return(ret);
}
Beispiel #6
0
bool ads_parse_gp_ext(TALLOC_CTX *mem_ctx,
		      const char *extension_raw,
		      struct GP_EXT **gp_ext)
{
	bool ret = false;
	struct GP_EXT *ext = NULL;
	char **ext_list = NULL;
	char **ext_strings = NULL;
	int i;

	if (!extension_raw) {
		goto parse_error;
	}

	DEBUG(20,("ads_parse_gp_ext: %s\n", extension_raw));

	ext = talloc_zero(mem_ctx, struct GP_EXT);
	if (!ext) {
		goto parse_error;
	}

	ext_list = str_list_make(mem_ctx, extension_raw, "]");
	if (!ext_list) {
		goto parse_error;
	}

	for (i = 0; ext_list[i] != NULL; i++) {
		/* no op */
	}

	ext->num_exts = i;

	if (ext->num_exts) {
		ext->extensions 	= talloc_zero_array(mem_ctx, char *,
							    ext->num_exts);
		ext->extensions_guid	= talloc_zero_array(mem_ctx, char *,
							    ext->num_exts);
		ext->snapins		= talloc_zero_array(mem_ctx, char *,
							    ext->num_exts);
		ext->snapins_guid	= talloc_zero_array(mem_ctx, char *,
							    ext->num_exts);
	}
Beispiel #7
0
/****************************************************************************
parse the debug levels from smb.conf. Example debug level string:
  3 tdb:5 printdrivers:7
Note: the 1st param has no "name:" preceeding it.
****************************************************************************/
BOOL debug_parse_levels(const char *params_str)
{
    char **params;

    /* Just in case */
    debug_init();

    if (AllowDebugChange == False)
        return True;

    params = str_list_make(params_str, NULL);

    if (debug_parse_params(params))
    {
        debug_dump_status(5);
        str_list_free(&params);
        return True;
    } else {
        str_list_free(&params);
        return False;
    }
}
Beispiel #8
0
NTSTATUS make_auth_context_subsystem(struct auth_context **auth_context) 
{
	char **auth_method_list = NULL; 
	NTSTATUS nt_status;

	if (lp_auth_methods() && !str_list_copy(&auth_method_list, 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("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("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("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("guest sam", NULL);
				}
			} else {
				DEBUG(5,("Making default auth method list for security=user, encrypt passwords = no\n"));
				auth_method_list = str_list_make("guest unix", NULL);
			}
			break;
		case SEC_SHARE:
			if (lp_encrypted_passwords()) {
				DEBUG(5,("Making default auth method list for security=share, encrypt passwords = yes\n"));
				auth_method_list = str_list_make("guest sam", NULL);
			} else {
				DEBUG(5,("Making default auth method list for security=share, encrypt passwords = no\n"));
				auth_method_list = str_list_make("guest unix", NULL);
			}
			break;
		case SEC_ADS:
			DEBUG(5,("Making default auth method list for security=ADS\n"));
			auth_method_list = str_list_make("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"));
	}
	
	if (!NT_STATUS_IS_OK(nt_status = make_auth_context_text_list(auth_context, auth_method_list))) {
		str_list_free(&auth_method_list);
		return nt_status;
	}
	
	str_list_free(&auth_method_list);
	return nt_status;
}
Beispiel #9
0
/*
  test operations against a WINS server
*/
static bool nbt_test_wins_name(struct torture_context *tctx, const char *address,
			       struct nbt_name *name, uint16_t nb_flags,
			       bool try_low_port)
{
	struct nbt_name_register_wins io;
	struct nbt_name_register name_register;
	struct nbt_name_query query;
	struct nbt_name_refresh_wins refresh;
	struct nbt_name_release release;
	struct nbt_name_request *req;
	NTSTATUS status;
	struct nbt_name_socket *nbtsock = torture_init_nbt_socket(tctx);
	const char *myaddress;
	struct socket_address *socket_address;
	struct interface *ifaces;
	bool low_port = try_low_port;

	load_interfaces(tctx, lp_interfaces(tctx->lp_ctx), &ifaces);

	myaddress = talloc_strdup(tctx, iface_best_ip(ifaces, address));

	socket_address = socket_address_from_strings(tctx, 
						     nbtsock->sock->backend_name,
						     myaddress, lp_nbt_port(tctx->lp_ctx));
	torture_assert(tctx, socket_address != NULL, 
				   "Error getting address");

	/* we do the listen here to ensure the WINS server receives the packets from
	   the right IP */
	status = socket_listen(nbtsock->sock, socket_address, 0, 0);
	talloc_free(socket_address);
	if (!NT_STATUS_IS_OK(status)) {
		low_port = false;
		socket_address = socket_address_from_strings(tctx,
							     nbtsock->sock->backend_name,
							     myaddress, 0);
		torture_assert(tctx, socket_address != NULL,
			       "Error getting address");

		status = socket_listen(nbtsock->sock, socket_address, 0, 0);
		talloc_free(socket_address);
		torture_assert_ntstatus_ok(tctx, status,
					   "socket_listen for WINS failed");
	}

	torture_comment(tctx, "Testing name registration to WINS with name %s at %s nb_flags=0x%x\n", 
	       nbt_name_string(tctx, name), myaddress, nb_flags);

	torture_comment(tctx, "release the name\n");
	release.in.name = *name;
	release.in.dest_port = lp_nbt_port(tctx->lp_ctx);
	release.in.dest_addr = address;
	release.in.address = myaddress;
	release.in.nb_flags = nb_flags;
	release.in.broadcast = false;
	release.in.timeout = 3;
	release.in.retries = 0;

	status = nbt_name_release(nbtsock, tctx, &release);
	torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name query", address));
	CHECK_VALUE(tctx, release.out.rcode, 0);

	if (nb_flags & NBT_NM_GROUP) {
		/* ignore this for group names */
	} else if (!low_port) {
		torture_comment(tctx, "no low port - skip: register the name with a wrong address\n");
	} else {
		torture_comment(tctx, "register the name with a wrong address (makes the next request slow!)\n");
		io.in.name = *name;
		io.in.wins_port = lp_nbt_port(tctx->lp_ctx);
		io.in.wins_servers = str_list_make(tctx, address, NULL);
		io.in.addresses = str_list_make(tctx, "127.64.64.1", NULL);
		io.in.nb_flags = nb_flags;
		io.in.ttl = 300000;

		status = nbt_name_register_wins(nbtsock, tctx, &io);
		if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
			torture_assert_ntstatus_ok(tctx, status,
				talloc_asprintf(tctx, "No response from %s for name register\n",
						address));
		}
		torture_assert_ntstatus_ok(tctx, status,
			talloc_asprintf(tctx, "Bad response from %s for name register\n",
					address));

		CHECK_STRING(tctx, io.out.wins_server, address);
		CHECK_VALUE(tctx, io.out.rcode, 0);

		torture_comment(tctx, "register the name correct address\n");
		name_register.in.name		= *name;
		name_register.in.dest_port	= lp_nbt_port(tctx->lp_ctx);
		name_register.in.dest_addr	= address;
		name_register.in.address	= myaddress;
		name_register.in.nb_flags	= nb_flags;
		name_register.in.register_demand= false;
		name_register.in.broadcast	= false;
		name_register.in.multi_homed	= true;
		name_register.in.ttl		= 300000;
		name_register.in.timeout	= 3;
		name_register.in.retries	= 2;

		/*
		 * test if the server ignores resent requests
		 */
		req = nbt_name_register_send(nbtsock, &name_register);
		while (true) {
			event_loop_once(nbtsock->event_ctx);
			if (req->state != NBT_REQUEST_WAIT) {
				break;
			}
			if (req->received_wack) {
				/*
				 * if we received the wack response
				 * we resend the request and the
				 * server should ignore that
				 * and not handle it as new request
				 */
				req->state = NBT_REQUEST_SEND;
				DLIST_ADD_END(nbtsock->send_queue, req,
					      struct nbt_name_request *);
				EVENT_FD_WRITEABLE(nbtsock->fde);
				break;
			}
		}

		status = nbt_name_register_recv(req, tctx, &name_register);
		if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
			torture_assert_ntstatus_ok(tctx, status,
				talloc_asprintf(tctx, "No response from %s for name register\n",
						address));
		}
		torture_assert_ntstatus_ok(tctx, status,
			talloc_asprintf(tctx, "Bad response from %s for name register\n",
					address));

		CHECK_VALUE(tctx, name_register.out.rcode, 0);
		CHECK_STRING(tctx, name_register.out.reply_addr, myaddress);
	}
Beispiel #10
0
			torture_assert_ntstatus_ok(tctx, status,
				talloc_asprintf(tctx, "No response from %s for name register\n",
						address));
		}
		torture_assert_ntstatus_ok(tctx, status,
			talloc_asprintf(tctx, "Bad response from %s for name register\n",
					address));

		CHECK_VALUE(tctx, name_register.out.rcode, 0);
		CHECK_STRING(tctx, name_register.out.reply_addr, myaddress);
	}

	torture_comment(tctx, "register the name correct address\n");
	io.in.name = *name;
	io.in.wins_port = lp_nbt_port(tctx->lp_ctx);
	io.in.wins_servers = (const char **)str_list_make(tctx, address, NULL);
	io.in.addresses = (const char **)str_list_make(tctx, myaddress, NULL);
	io.in.nb_flags = nb_flags;
	io.in.ttl = 300000;
	
	status = nbt_name_register_wins(nbtsock, tctx, &io);
	torture_assert_ntstatus_ok(tctx, status, talloc_asprintf(tctx, "Bad response from %s for name register", address));
	
	CHECK_STRING(tctx, io.out.wins_server, address);
	CHECK_VALUE(tctx, io.out.rcode, 0);

	if (name->type != NBT_NAME_MASTER &&
	    name->type != NBT_NAME_LOGON && 
	    name->type != NBT_NAME_BROWSER && 
	    (nb_flags & NBT_NM_GROUP)) {
		torture_comment(tctx, "Try to register as non-group\n");
Beispiel #11
0
/****************************************************************************
 Do a specific test for a SAM_ACCOUNT being valid for this connection
 (ie not disabled, expired and the like).
****************************************************************************/
_PUBLIC_ NTSTATUS authsam_account_ok(TALLOC_CTX *mem_ctx,
				     struct ldb_context *sam_ctx,
				     uint32_t logon_parameters,
				     struct ldb_dn *domain_dn,
				     struct ldb_message *msg,
				     const char *logon_workstation,
				     const char *name_for_logs,
				     bool allow_domain_trust,
				     bool password_change)
{
	uint16_t acct_flags;
	const char *workstation_list;
	NTTIME acct_expiry;
	NTTIME must_change_time;

	NTTIME now;
	DEBUG(4,("authsam_account_ok: Checking SMB password for user %s\n", name_for_logs));

	acct_flags = samdb_result_acct_flags(sam_ctx, mem_ctx, msg, domain_dn);
	
	acct_expiry = samdb_result_account_expires(msg);

	/* Check for when we must change this password, taking the
	 * userAccountControl flags into account */
	must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx, 
							      domain_dn, msg);

	workstation_list = ldb_msg_find_attr_as_string(msg, "userWorkstations", NULL);

	/* Quit if the account was disabled. */
	if (acct_flags & ACB_DISABLED) {
		DEBUG(2,("authsam_account_ok: Account for user '%s' was disabled.\n", name_for_logs));
		return NT_STATUS_ACCOUNT_DISABLED;
	}

	/* Quit if the account was locked out. */
	if (acct_flags & ACB_AUTOLOCK) {
		DEBUG(2,("authsam_account_ok: Account for user %s was locked out.\n", name_for_logs));
		return NT_STATUS_ACCOUNT_LOCKED_OUT;
	}

	/* Test account expire time */
	unix_to_nt_time(&now, time(NULL));
	if (now > acct_expiry) {
		DEBUG(2,("authsam_account_ok: Account for user '%s' has expired.\n", name_for_logs));
		DEBUG(3,("authsam_account_ok: Account expired at '%s'.\n", 
			 nt_time_string(mem_ctx, acct_expiry)));
		return NT_STATUS_ACCOUNT_EXPIRED;
	}

	/* check for immediate expiry "must change at next logon" (but not if this is a password change request) */
	if ((must_change_time == 0) && !password_change) {
		DEBUG(2,("sam_account_ok: Account for user '%s' password must change!.\n",
			 name_for_logs));
		return NT_STATUS_PASSWORD_MUST_CHANGE;
	}

	/* check for expired password (but not if this is a password change request) */
	if ((must_change_time < now) && !password_change) {
		DEBUG(2,("sam_account_ok: Account for user '%s' password expired!.\n",
			 name_for_logs));
		DEBUG(2,("sam_account_ok: Password expired at '%s' unix time.\n",
			 nt_time_string(mem_ctx, must_change_time)));
		return NT_STATUS_PASSWORD_EXPIRED;
	}

	/* Test workstation. Workstation list is comma separated. */
	if (logon_workstation && workstation_list && *workstation_list) {
		bool invalid_ws = true;
		int i;
		const char **workstations = (const char **)str_list_make(mem_ctx, workstation_list, ",");
		
		for (i = 0; workstations && workstations[i]; i++) {
			DEBUG(10,("sam_account_ok: checking for workstation match '%s' and '%s'\n",
				  workstations[i], logon_workstation));

			if (strequal(workstations[i], logon_workstation)) {
				invalid_ws = false;
				break;
			}
		}

		talloc_free(workstations);

		if (invalid_ws) {
			return NT_STATUS_INVALID_WORKSTATION;
		}
	}
	
	if (!logon_hours_ok(msg, name_for_logs)) {
		return NT_STATUS_INVALID_LOGON_HOURS;
	}
	
	if (!allow_domain_trust) {
		if (acct_flags & ACB_DOMTRUST) {
			DEBUG(2,("sam_account_ok: Domain trust account %s denied by server\n", name_for_logs));
			return NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT;
		}
	}
	if (!(logon_parameters & MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT)) {
		if (acct_flags & ACB_SVRTRUST) {
			DEBUG(2,("sam_account_ok: Server trust account %s denied by server\n", name_for_logs));
			return NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT;
		}
	}
	if (!(logon_parameters & MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT)) {
		/* TODO: this fails with current solaris client. We
		   need to work with Gordon to work out why */
		if (acct_flags & ACB_WSTRUST) {
			DEBUG(4,("sam_account_ok: Wksta trust account %s denied by server\n", name_for_logs));
			return NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
		}
	}

	return NT_STATUS_OK;
}
Beispiel #12
0
/*
 * Hook to allow handling of NTLM authentication for AD operation
 * without directly linking the s4 auth stack
 *
 * This ensures we use the source4 authentication stack, as well as
 * the authorization stack to create the user's token.  This ensures
 * consistency between NTLM logins and NTLMSSP logins, as NTLMSSP is
 * handled by the hook above.
 */
static NTSTATUS make_auth4_context_s4(const struct auth_context *auth_context,
				      TALLOC_CTX *mem_ctx,
				      struct auth4_context **auth4_context)
{
	NTSTATUS status;
	struct loadparm_context *lp_ctx;
	struct tevent_context *event_ctx;
	TALLOC_CTX *frame = talloc_stackframe();
	struct imessaging_context *msg_ctx;
	struct server_id *server_id;

	lp_ctx = loadparm_init_s3(frame, loadparm_s3_helpers());
	if (lp_ctx == NULL) {
		DEBUG(1, ("loadparm_init_s3 failed\n"));
		TALLOC_FREE(frame);
		return NT_STATUS_INVALID_SERVER_STATE;
	}
	event_ctx = s4_event_context_init(frame);
	if (event_ctx == NULL) {
		DEBUG(1, ("s4_event_context_init failed\n"));
		TALLOC_FREE(frame);
		return NT_STATUS_INVALID_SERVER_STATE;
	}

	server_id = new_server_id_task(frame);
	if (server_id == NULL) {
		DEBUG(1, ("new_server_id_task failed\n"));
		TALLOC_FREE(frame);
		return NT_STATUS_INVALID_SERVER_STATE;
	}

	msg_ctx = imessaging_init(frame,
				  lp_ctx,
				  *server_id,
				  event_ctx, true);
	if (msg_ctx == NULL) {
		DEBUG(1, ("imessaging_init failed\n"));
		TALLOC_FREE(frame);
		return NT_STATUS_INVALID_SERVER_STATE;
	}
	talloc_reparent(frame, msg_ctx, server_id);

	/* Allow forcing a specific auth4 module */
	if (!auth_context->forced_samba4_methods) {
		status = auth_context_create(mem_ctx,
					     event_ctx,
					     msg_ctx,
					     lp_ctx,
					     auth4_context);
	} else {
		const char * const *forced_auth_methods = (const char * const *)str_list_make(mem_ctx, auth_context->forced_samba4_methods, NULL);
		status = auth_context_create_methods(mem_ctx, forced_auth_methods, event_ctx, msg_ctx, lp_ctx, NULL, auth4_context);
	}
	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("Failed to start auth server code: %s\n", nt_errstr(status)));
		TALLOC_FREE(frame);
		return status;
	}

	talloc_reparent(frame, *auth4_context, msg_ctx);
	talloc_reparent(frame, *auth4_context, event_ctx);
	talloc_reparent(frame, *auth4_context, lp_ctx);

	TALLOC_FREE(frame);
	return status;
}