Esempio n. 1
0
static NTSTATUS check_unix_security(const struct auth_context *auth_context,
                                    void *my_private_data,
                                    TALLOC_CTX *mem_ctx,
                                    const auth_usersupplied_info *user_info,
                                    auth_serversupplied_info **server_info)
{
    NTSTATUS nt_status;
    struct passwd *pass = NULL;

    become_root();
    pass = Get_Pwnam(user_info->internal_username);


    /** @todo This call assumes a ASCII password, no charset transformation is
        done.  We may need to revisit this **/
    nt_status = pass_check(pass,
                           pass ? pass->pw_name : user_info->internal_username,
                           (char *)user_info->plaintext_password.data,
                           user_info->plaintext_password.length-1,
                           lp_update_encrypted() ?
                           update_smbpassword_file : NULL,
                           True);

    unbecome_root();

    if (NT_STATUS_IS_OK(nt_status)) {
        if (pass) {
            /* if a real user check pam account restrictions */
            /* only really perfomed if "obey pam restriction" is true */
            nt_status = smb_pam_accountcheck(pass->pw_name);
            if (  !NT_STATUS_IS_OK(nt_status)) {
                DEBUG(1, ("PAM account restriction prevents user login\n"));
            } else {
                make_server_info_pw(server_info, pass->pw_name, pass);
            }
        } else {
            /* we need to do somthing more useful here */
            nt_status = NT_STATUS_NO_SUCH_USER;
        }
    }

    return nt_status;
}
Esempio n. 2
0
File: auth.c Progetto: sprymak/samba
NTSTATUS auth_check_ntlm_password(const struct auth_context *auth_context,
				  const struct auth_usersupplied_info *user_info, 
				  struct auth_serversupplied_info **server_info)
{
	/* if all the modules say 'not for me' this is reasonable */
	NTSTATUS nt_status = NT_STATUS_NO_SUCH_USER;
	const char *unix_username;
	auth_methods *auth_method;
	TALLOC_CTX *mem_ctx;

	if (!user_info || !auth_context || !server_info)
		return NT_STATUS_LOGON_FAILURE;

	DEBUG(3, ("check_ntlm_password:  Checking password for unmapped user [%s]\\[%s]@[%s] with the new password interface\n", 
		  user_info->client.domain_name, user_info->client.account_name, user_info->workstation_name));

	DEBUG(3, ("check_ntlm_password:  mapped user is: [%s]\\[%s]@[%s]\n", 
		  user_info->mapped.domain_name, user_info->mapped.account_name, user_info->workstation_name));

	if (auth_context->challenge.length != 8) {
		DEBUG(0, ("check_ntlm_password:  Invalid challenge stored for this auth context - cannot continue\n"));
		return NT_STATUS_LOGON_FAILURE;
	}

	if (auth_context->challenge_set_by)
		DEBUG(10, ("check_ntlm_password: auth_context challenge created by %s\n",
					auth_context->challenge_set_by));

	DEBUG(10, ("challenge is: \n"));
	dump_data(5, auth_context->challenge.data, auth_context->challenge.length);

#ifdef DEBUG_PASSWORD
	DEBUG(100, ("user_info has passwords of length %d and %d\n", 
		    (int)user_info->password.response.lanman.length, (int)user_info->password.response.nt.length));
	DEBUG(100, ("lm:\n"));
	dump_data(100, user_info->password.response.lanman.data, user_info->password.response.lanman.length);
	DEBUG(100, ("nt:\n"));
	dump_data(100, user_info->password.response.nt.data, user_info->password.response.nt.length);
#endif

	/* This needs to be sorted:  If it doesn't match, what should we do? */
	if (!check_domain_match(user_info->client.account_name, user_info->mapped.domain_name))
		return NT_STATUS_LOGON_FAILURE;

	for (auth_method = auth_context->auth_method_list;auth_method; auth_method = auth_method->next) {
		NTSTATUS result;

		mem_ctx = talloc_init("%s authentication for user %s\\%s", auth_method->name,
				      user_info->mapped.domain_name, user_info->client.account_name);

		result = auth_method->auth(auth_context, auth_method->private_data, mem_ctx, user_info, server_info);

		/* check if the module did anything */
		if ( NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_NOT_IMPLEMENTED) ) {
			DEBUG(10,("check_ntlm_password: %s had nothing to say\n", auth_method->name));
			talloc_destroy(mem_ctx);
			continue;
		}

		nt_status = result;

		if (NT_STATUS_IS_OK(nt_status)) {
			DEBUG(3, ("check_ntlm_password: %s authentication for user [%s] succeeded\n", 
				  auth_method->name, user_info->client.account_name));
		} else {
			DEBUG(5, ("check_ntlm_password: %s authentication for user [%s] FAILED with error %s\n", 
				  auth_method->name, user_info->client.account_name, nt_errstr(nt_status)));
		}

		talloc_destroy(mem_ctx);

		if ( NT_STATUS_IS_OK(nt_status))
		{
				break;			
		}
	}

	/* successful authentication */

	if (NT_STATUS_IS_OK(nt_status)) {
		unix_username = (*server_info)->unix_name;
		if (!(*server_info)->guest) {
			const char *rhost;

			if (tsocket_address_is_inet(user_info->remote_host, "ip")) {
				rhost = tsocket_address_inet_addr_string(user_info->remote_host,
									 talloc_tos());
				if (rhost == NULL) {
					return NT_STATUS_NO_MEMORY;
				}
			} else {
				rhost = "127.0.0.1";
			}

			/* We might not be root if we are an RPC call */
			become_root();
			nt_status = smb_pam_accountcheck(unix_username,
							 rhost);
			unbecome_root();

			if (NT_STATUS_IS_OK(nt_status)) {
				DEBUG(5, ("check_ntlm_password:  PAM Account for user [%s] succeeded\n", 
					  unix_username));
			} else {
				DEBUG(3, ("check_ntlm_password:  PAM Account for user [%s] FAILED with error %s\n", 
					  unix_username, nt_errstr(nt_status)));
			} 
		}

		if (NT_STATUS_IS_OK(nt_status)) {
			DEBUG((*server_info)->guest ? 5 : 2, 
			      ("check_ntlm_password:  %sauthentication for user [%s] -> [%s] -> [%s] succeeded\n",
			       (*server_info)->guest ? "guest " : "",
			       user_info->client.account_name,
			       user_info->mapped.account_name,
			       unix_username));
		}

		return nt_status;
	}

	/* failed authentication; check for guest lapping */

	DEBUG(2, ("check_ntlm_password:  Authentication for user [%s] -> [%s] FAILED with error %s\n",
		  user_info->client.account_name, user_info->mapped.account_name,
		  nt_errstr(nt_status)));
	ZERO_STRUCTP(server_info);

	return nt_status;
}
Esempio n. 3
0
File: auth.c Progetto: encukou/samba
/**
 * Check a user's Plaintext, LM or NTLM password.
 *
 * Check a user's password, as given in the user_info struct and return various
 * interesting details in the server_info struct.
 *
 * This function does NOT need to be in a become_root()/unbecome_root() pair
 * as it makes the calls itself when needed.
 *
 * The return value takes precedence over the contents of the server_info 
 * struct.  When the return is other than NT_STATUS_OK the contents 
 * of that structure is undefined.
 *
 * @param user_info Contains the user supplied components, including the passwords.
 *                  Must be created with make_user_info() or one of its wrappers.
 *
 * @param auth_context Supplies the challenges and some other data. 
 *                  Must be created with make_auth_context(), and the challenges should be 
 *                  filled in, either at creation or by calling the challenge geneation 
 *                  function auth_get_challenge().  
 *
 * @param pserver_info If successful, contains information about the authentication,
 *                     including a struct samu struct describing the user.
 *
 * @param pauthoritative Indicates if the result should be treated as final
 *                       result.
 *
 * @return An NTSTATUS with NT_STATUS_OK or an appropriate error.
 *
 **/
NTSTATUS auth_check_ntlm_password(TALLOC_CTX *mem_ctx,
				  const struct auth_context *auth_context,
				  const struct auth_usersupplied_info *user_info,
				  struct auth_serversupplied_info **pserver_info,
				  uint8_t *pauthoritative)
{
	TALLOC_CTX *frame;
	const char *auth_method_name = "";
	/* if all the modules say 'not for me' this is reasonable */
	NTSTATUS nt_status = NT_STATUS_NOT_IMPLEMENTED;
	const char *unix_username;
	auth_methods *auth_method;
	struct auth_serversupplied_info *server_info = NULL;
	struct dom_sid sid = {0};

	if (user_info == NULL || auth_context == NULL || pserver_info == NULL) {
		return NT_STATUS_LOGON_FAILURE;
	}

	frame = talloc_stackframe();

	*pauthoritative = 1;

	DEBUG(3, ("check_ntlm_password:  Checking password for unmapped user [%s]\\[%s]@[%s] with the new password interface\n", 
		  user_info->client.domain_name, user_info->client.account_name, user_info->workstation_name));

	DEBUG(3, ("check_ntlm_password:  mapped user is: [%s]\\[%s]@[%s]\n", 
		  user_info->mapped.domain_name, user_info->mapped.account_name, user_info->workstation_name));

	if (auth_context->challenge.length != 8) {
		DEBUG(0, ("check_ntlm_password:  Invalid challenge stored for this auth context - cannot continue\n"));
		nt_status = NT_STATUS_LOGON_FAILURE;
		goto fail;
	}

	if (auth_context->challenge_set_by)
		DEBUG(10, ("check_ntlm_password: auth_context challenge created by %s\n",
					auth_context->challenge_set_by));

	DEBUG(10, ("challenge is: \n"));
	dump_data(5, auth_context->challenge.data, auth_context->challenge.length);

#ifdef DEBUG_PASSWORD
	DEBUG(100, ("user_info has passwords of length %d and %d\n", 
		    (int)user_info->password.response.lanman.length, (int)user_info->password.response.nt.length));
	DEBUG(100, ("lm:\n"));
	dump_data(100, user_info->password.response.lanman.data, user_info->password.response.lanman.length);
	DEBUG(100, ("nt:\n"));
	dump_data(100, user_info->password.response.nt.data, user_info->password.response.nt.length);
#endif

	/* This needs to be sorted:  If it doesn't match, what should we do? */
	if (!check_domain_match(user_info->client.account_name,
				user_info->mapped.domain_name)) {
		nt_status = NT_STATUS_LOGON_FAILURE;
		goto fail;
	}

	for (auth_method = auth_context->auth_method_list;auth_method; auth_method = auth_method->next) {

		auth_method_name = auth_method->name;

		nt_status = auth_method->auth(auth_context,
					      auth_method->private_data,
					      talloc_tos(),
					      user_info,
					      &server_info);

		if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) {
			break;
		}

		DBG_DEBUG("%s had nothing to say\n", auth_method->name);
	}

	if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NOT_IMPLEMENTED)) {
		*pauthoritative = 0;
		nt_status = NT_STATUS_NO_SUCH_USER;
	}

	if (!NT_STATUS_IS_OK(nt_status)) {
		DBG_INFO("%s authentication for user [%s] FAILED with "
			 "error %s, authoritative=%u\n",
			 auth_method_name,
			 user_info->client.account_name,
			 nt_errstr(nt_status),
			 *pauthoritative);
		goto fail;
	}

	DBG_NOTICE("%s authentication for user [%s] succeeded\n",
		   auth_method_name, user_info->client.account_name);

	unix_username = server_info->unix_name;

	/* We skip doing this step if the caller asked us not to */
	if (!(user_info->flags & USER_INFO_INFO3_AND_NO_AUTHZ)
	    && !(server_info->guest)) {
		const char *rhost;

		if (tsocket_address_is_inet(user_info->remote_host, "ip")) {
			rhost = tsocket_address_inet_addr_string(
				user_info->remote_host, talloc_tos());
			if (rhost == NULL) {
				nt_status = NT_STATUS_NO_MEMORY;
				goto fail;
			}
		} else {
			rhost = "127.0.0.1";
		}

		/* We might not be root if we are an RPC call */
		become_root();
		nt_status = smb_pam_accountcheck(unix_username, rhost);
		unbecome_root();

		if (NT_STATUS_IS_OK(nt_status)) {
			DEBUG(5, ("check_ntlm_password:  PAM Account for user [%s] "
				  "succeeded\n", unix_username));
		} else {
			DEBUG(3, ("check_ntlm_password:  PAM Account for user [%s] "
				  "FAILED with error %s\n",
				  unix_username, nt_errstr(nt_status)));
		}
	}

	if (!NT_STATUS_IS_OK(nt_status)) {
		goto fail;
	}

	nt_status = get_user_sid_info3_and_extra(server_info->info3,
						 &server_info->extra,
						 &sid);
	if (!NT_STATUS_IS_OK(nt_status)) {
		sid = (struct dom_sid) {0};
	}

	log_authentication_event(NULL, NULL,
				 user_info, nt_status,
				 server_info->info3->base.logon_domain.string,
				 server_info->info3->base.account_name.string,
				 unix_username, &sid);

	DEBUG(server_info->guest ? 5 : 2,
	      ("check_ntlm_password:  %sauthentication for user "
	       "[%s] -> [%s] -> [%s] succeeded\n",
	       server_info->guest ? "guest " : "",
	       user_info->client.account_name,
	       user_info->mapped.account_name,
	       unix_username));

	*pserver_info = talloc_move(mem_ctx, &server_info);

	TALLOC_FREE(frame);
	return NT_STATUS_OK;

fail:

	/* failed authentication; check for guest lapping */

	/*
	 * Please try not to change this string, it is probably in use
	 * in audit logging tools
	 */
	DEBUG(2, ("check_ntlm_password:  Authentication for user "
		  "[%s] -> [%s] FAILED with error %s, authoritative=%u\n",
		  user_info->client.account_name, user_info->mapped.account_name,
		  nt_errstr(nt_status), *pauthoritative));

	log_authentication_event(NULL, NULL, user_info, nt_status, NULL, NULL, NULL, NULL);

	ZERO_STRUCTP(pserver_info);

	TALLOC_FREE(frame);

	return nt_status;
}
Esempio n. 4
0
NTSTATUS get_user_from_kerberos_info(TALLOC_CTX *mem_ctx,
				     const char *cli_name,
				     const char *princ_name,
				     struct PAC_LOGON_INFO *logon_info,
				     bool *is_mapped,
				     bool *mapped_to_guest,
				     char **ntuser,
				     char **ntdomain,
				     char **username,
				     struct passwd **_pw)
{
	NTSTATUS status;
	char *domain = NULL;
	char *realm = NULL;
	char *user = NULL;
	char *p;
	char *fuser = NULL;
	char *unixuser = NULL;
	struct passwd *pw = NULL;

	DEBUG(3, ("Kerberos ticket principal name is [%s]\n", princ_name));

	p = strchr_m(princ_name, '@');
	if (!p) {
		DEBUG(3, ("[%s] Doesn't look like a valid principal\n",
			  princ_name));
		return NT_STATUS_LOGON_FAILURE;
	}

	user = talloc_strndup(mem_ctx, princ_name, p - princ_name);
	if (!user) {
		return NT_STATUS_NO_MEMORY;
	}

	realm = talloc_strdup(talloc_tos(), p + 1);
	if (!realm) {
		return NT_STATUS_NO_MEMORY;
	}

	if (!strequal(realm, lp_realm())) {
		DEBUG(3, ("Ticket for foreign realm %s@%s\n", user, realm));
		if (!lp_allow_trusted_domains()) {
			return NT_STATUS_LOGON_FAILURE;
		}
	}

	if (logon_info && logon_info->info3.base.domain.string) {
		domain = talloc_strdup(mem_ctx,
					logon_info->info3.base.domain.string);
		if (!domain) {
			return NT_STATUS_NO_MEMORY;
		}
		DEBUG(10, ("Domain is [%s] (using PAC)\n", domain));
	} else {

		/* If we have winbind running, we can (and must) shorten the
		   username by using the short netbios name. Otherwise we will
		   have inconsistent user names. With Kerberos, we get the
		   fully qualified realm, with ntlmssp we get the short
		   name. And even w2k3 does use ntlmssp if you for example
		   connect to an ip address. */

		wbcErr wbc_status;
		struct wbcDomainInfo *info = NULL;

		DEBUG(10, ("Mapping [%s] to short name using winbindd\n",
			   realm));

		wbc_status = wbcDomainInfo(realm, &info);

		if (WBC_ERROR_IS_OK(wbc_status)) {
			domain = talloc_strdup(mem_ctx,
						info->short_name);
			wbcFreeMemory(info);
		} else {
			DEBUG(3, ("Could not find short name: %s\n",
				  wbcErrorString(wbc_status)));
			domain = talloc_strdup(mem_ctx, realm);
		}
		if (!domain) {
			return NT_STATUS_NO_MEMORY;
		}
		DEBUG(10, ("Domain is [%s] (using Winbind)\n", domain));
	}

	fuser = talloc_asprintf(mem_ctx,
				"%s%c%s",
				domain,
				*lp_winbind_separator(),
				user);
	if (!fuser) {
		return NT_STATUS_NO_MEMORY;
	}

	*is_mapped = map_username(mem_ctx, fuser, &fuser);
	if (!fuser) {
		return NT_STATUS_NO_MEMORY;
	}

	pw = smb_getpwnam(mem_ctx, fuser, &unixuser, true);
	if (pw) {
		if (!unixuser) {
			return NT_STATUS_NO_MEMORY;
		}
		/* if a real user check pam account restrictions */
		/* only really perfomed if "obey pam restriction" is true */
		/* do this before an eventual mapping to guest occurs */
		status = smb_pam_accountcheck(pw->pw_name, cli_name);
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(1, ("PAM account restrictions prevent user "
				  "[%s] login\n", unixuser));
			return status;
		}
	}
	if (!pw) {

		/* this was originally the behavior of Samba 2.2, if a user
		   did not have a local uid but has been authenticated, then
		   map them to a guest account */

		if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID) {
			*mapped_to_guest = true;
			fuser = talloc_strdup(mem_ctx, lp_guestaccount());
			if (!fuser) {
				return NT_STATUS_NO_MEMORY;
			}
			pw = smb_getpwnam(mem_ctx, fuser, &unixuser, true);
		}

		/* extra sanity check that the guest account is valid */
		if (!pw) {
			DEBUG(1, ("Username %s is invalid on this system\n",
				  fuser));
			return NT_STATUS_LOGON_FAILURE;
		}
	}

	if (!unixuser) {
		return NT_STATUS_NO_MEMORY;
	}

	*username = talloc_strdup(mem_ctx, unixuser);
	if (!*username) {
		return NT_STATUS_NO_MEMORY;
	}
	*ntuser = user;
	*ntdomain = domain;
	*_pw = pw;

	return NT_STATUS_OK;
}
Esempio n. 5
0
static int reply_spnego_kerberos(connection_struct *conn, 
				 char *inbuf, char *outbuf,
				 int length, int bufsize,
				 DATA_BLOB *secblob,
				 BOOL *p_invalidate_vuid)
{
	TALLOC_CTX *mem_ctx;
	DATA_BLOB ticket;
	char *client, *p, *domain;
	fstring netbios_domain_name;
	struct passwd *pw;
	fstring user;
	int sess_vuid;
	NTSTATUS ret;
	PAC_DATA *pac_data;
	DATA_BLOB ap_rep, ap_rep_wrapped, response;
	auth_serversupplied_info *server_info = NULL;
	DATA_BLOB session_key = data_blob(NULL, 0);
	uint8 tok_id[2];
	DATA_BLOB nullblob = data_blob(NULL, 0);
	fstring real_username;
	BOOL map_domainuser_to_guest = False;
	BOOL username_was_mapped;
	PAC_LOGON_INFO *logon_info = NULL;

	ZERO_STRUCT(ticket);
	ZERO_STRUCT(pac_data);
	ZERO_STRUCT(ap_rep);
	ZERO_STRUCT(ap_rep_wrapped);
	ZERO_STRUCT(response);

	/* Normally we will always invalidate the intermediate vuid. */
	*p_invalidate_vuid = True;

	mem_ctx = talloc_init("reply_spnego_kerberos");
	if (mem_ctx == NULL) {
		return ERROR_NT(nt_status_squash(NT_STATUS_NO_MEMORY));
	}

	if (!spnego_parse_krb5_wrap(*secblob, &ticket, tok_id)) {
		talloc_destroy(mem_ctx);
		return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
	}

	ret = ads_verify_ticket(mem_ctx, lp_realm(), 0, &ticket, &client, &pac_data, &ap_rep, &session_key);

	data_blob_free(&ticket);

	if (!NT_STATUS_IS_OK(ret)) {
#if 0
		/* Experiment that failed. See "only happens with a KDC" comment below. */

		if (NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {

			/*
			 * Windows in this case returns NT_STATUS_MORE_PROCESSING_REQUIRED
			 * with a negTokenTarg blob containing an krb5_error struct ASN1 encoded
			 * containing KRB5KRB_AP_ERR_SKEW. The client then fixes its
			 * clock and continues rather than giving an error. JRA.
			 * -- Looks like this only happens with a KDC. JRA.
			 */

			BOOL ok = make_krb5_skew_error(&ap_rep);
			if (!ok) {
				talloc_destroy(mem_ctx);
				return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
			}
			ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_ERROR);
			response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
			reply_sesssetup_blob(conn, outbuf, response, NT_STATUS_MORE_PROCESSING_REQUIRED);

			/*
			 * In this one case we don't invalidate the intermediate vuid.
			 * as we're expecting the client to re-use it for the next
			 * sessionsetupX packet. JRA.
			 */

			*p_invalidate_vuid = False;

			data_blob_free(&ap_rep);
			data_blob_free(&ap_rep_wrapped);
			data_blob_free(&response);
			talloc_destroy(mem_ctx);
			return -1; /* already replied */
		}
#else
		if (!NT_STATUS_EQUAL(ret, NT_STATUS_TIME_DIFFERENCE_AT_DC)) {
			ret = NT_STATUS_LOGON_FAILURE;
		}
#endif
		DEBUG(1,("Failed to verify incoming ticket with error %s!\n", nt_errstr(ret)));	
		talloc_destroy(mem_ctx);
		return ERROR_NT(nt_status_squash(ret));
	}

	DEBUG(3,("Ticket name is [%s]\n", client));

	p = strchr_m(client, '@');
	if (!p) {
		DEBUG(3,("Doesn't look like a valid principal\n"));
		data_blob_free(&ap_rep);
		data_blob_free(&session_key);
		SAFE_FREE(client);
		talloc_destroy(mem_ctx);
		return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
	}

	*p = 0;

	/* save the PAC data if we have it */

	if (pac_data) {
		logon_info = get_logon_info_from_pac(pac_data);
		if (logon_info) {
			netsamlogon_cache_store( client, &logon_info->info3 );
		}
	}

	if (!strequal(p+1, lp_realm())) {
		DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
		if (!lp_allow_trusted_domains()) {
			data_blob_free(&ap_rep);
			data_blob_free(&session_key);
			SAFE_FREE(client);
			talloc_destroy(mem_ctx);
			return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
		}
	}

	/* this gives a fully qualified user name (ie. with full realm).
	   that leads to very long usernames, but what else can we do? */

	domain = p+1;

	if (logon_info && logon_info->info3.hdr_logon_dom.uni_str_len) {

		unistr2_to_ascii(netbios_domain_name, &logon_info->info3.uni_logon_dom, -1);
		domain = netbios_domain_name;
		DEBUG(10, ("Mapped to [%s] (using PAC)\n", domain));

	} else {

		/* If we have winbind running, we can (and must) shorten the
		   username by using the short netbios name. Otherwise we will
		   have inconsistent user names. With Kerberos, we get the
		   fully qualified realm, with ntlmssp we get the short
		   name. And even w2k3 does use ntlmssp if you for example
		   connect to an ip address. */

		struct winbindd_request wb_request;
		struct winbindd_response wb_response;
		NSS_STATUS wb_result;

		ZERO_STRUCT(wb_request);
		ZERO_STRUCT(wb_response);

		DEBUG(10, ("Mapping [%s] to short name\n", domain));

		fstrcpy(wb_request.domain_name, domain);

		wb_result = winbindd_request_response(WINBINDD_DOMAIN_INFO,
					     &wb_request, &wb_response);

		if (wb_result == NSS_STATUS_SUCCESS) {

			fstrcpy(netbios_domain_name,
				wb_response.data.domain_info.name);
			domain = netbios_domain_name;

			DEBUG(10, ("Mapped to [%s] (using Winbind)\n", domain));
		} else {
			DEBUG(3, ("Could not find short name -- winbind "
				  "not running?\n"));
		}
	}

	fstr_sprintf(user, "%s%c%s", domain, *lp_winbind_separator(), client);
	
	/* lookup the passwd struct, create a new user if necessary */

	username_was_mapped = map_username( user );

	pw = smb_getpwnam( mem_ctx, user, real_username, True );

	if (pw) {
		/* if a real user check pam account restrictions */
		/* only really perfomed if "obey pam restriction" is true */
		/* do this before an eventual mappign to guest occurs */
		ret = smb_pam_accountcheck(pw->pw_name);
		if (  !NT_STATUS_IS_OK(ret)) {
			DEBUG(1, ("PAM account restriction prevents user login\n"));
			data_blob_free(&ap_rep);
			data_blob_free(&session_key);
			TALLOC_FREE(mem_ctx);
			return ERROR_NT(nt_status_squash(ret));
		}
	}

	if (!pw) {

		/* this was originally the behavior of Samba 2.2, if a user
		   did not have a local uid but has been authenticated, then 
		   map them to a guest account */

		if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_UID){ 
			map_domainuser_to_guest = True;
			fstrcpy(user,lp_guestaccount());
			pw = smb_getpwnam( mem_ctx, user, real_username, True );
		} 

		/* extra sanity check that the guest account is valid */

		if ( !pw ) {
			DEBUG(1,("Username %s is invalid on this system\n", user));
			SAFE_FREE(client);
			data_blob_free(&ap_rep);
			data_blob_free(&session_key);
			TALLOC_FREE(mem_ctx);
			return ERROR_NT(nt_status_squash(NT_STATUS_LOGON_FAILURE));
		}
	}

	/* setup the string used by %U */
	
	sub_set_smb_name( real_username );
	reload_services(True);

	if ( map_domainuser_to_guest ) {
		make_server_info_guest(&server_info);
	} else if (logon_info) {
		/* pass the unmapped username here since map_username() 
		   will be called again from inside make_server_info_info3() */
		
		ret = make_server_info_info3(mem_ctx, client, domain, 
					     &server_info, &logon_info->info3);
		if ( !NT_STATUS_IS_OK(ret) ) {
			DEBUG(1,("make_server_info_info3 failed: %s!\n",
				 nt_errstr(ret)));
			SAFE_FREE(client);
			data_blob_free(&ap_rep);
			data_blob_free(&session_key);
			TALLOC_FREE(mem_ctx);
			return ERROR_NT(nt_status_squash(ret));
		}

	} else {
		ret = make_server_info_pw(&server_info, real_username, pw);

		if ( !NT_STATUS_IS_OK(ret) ) {
			DEBUG(1,("make_server_info_pw failed: %s!\n",
				 nt_errstr(ret)));
			SAFE_FREE(client);
			data_blob_free(&ap_rep);
			data_blob_free(&session_key);
			TALLOC_FREE(mem_ctx);
			return ERROR_NT(nt_status_squash(ret));
		}

	        /* make_server_info_pw does not set the domain. Without this
		 * we end up with the local netbios name in substitutions for
		 * %D. */

		if (server_info->sam_account != NULL) {
			pdb_set_domain(server_info->sam_account, domain, PDB_SET);
		}
	}

	server_info->was_mapped |= username_was_mapped;
	
	/* we need to build the token for the user. make_server_info_guest()
	   already does this */
	
	if ( !server_info->ptok ) {
		ret = create_local_token( server_info );
		if ( !NT_STATUS_IS_OK(ret) ) {
			SAFE_FREE(client);
			data_blob_free(&ap_rep);
			data_blob_free(&session_key);
			TALLOC_FREE( mem_ctx );
			TALLOC_FREE( server_info );
			return ERROR_NT(nt_status_squash(ret));
		}
	}

	/* register_vuid keeps the server info */
	/* register_vuid takes ownership of session_key, no need to free after this.
 	   A better interface would copy it.... */
	sess_vuid = register_vuid(server_info, session_key, nullblob, client);

	SAFE_FREE(client);

	if (sess_vuid == UID_FIELD_INVALID ) {
		ret = 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);
	}

        /* wrap that up in a nice GSS-API wrapping */
	if (NT_STATUS_IS_OK(ret)) {
		ap_rep_wrapped = spnego_gen_krb5_wrap(ap_rep, TOK_ID_KRB_AP_REP);
	} else {
		ap_rep_wrapped = data_blob(NULL, 0);
	}
	response = spnego_gen_auth_response(&ap_rep_wrapped, ret, OID_KERBEROS5_OLD);
	reply_sesssetup_blob(conn, outbuf, response, ret);

	data_blob_free(&ap_rep);
	data_blob_free(&ap_rep_wrapped);
	data_blob_free(&response);
	TALLOC_FREE(mem_ctx);

	return -1; /* already replied */
}