Esempio n. 1
0
AuthInfo*
passLogin(char *user, char *secret)
{
	AuthInfo *ai;
	Chalstate *cs;
	uint8_t digest[MD5dlen];
	char response[2*MD5dlen+1];
	int i;

	if((cs = auth_challenge("proto=cram role=server")) == nil)
		return nil;

	hmac_md5((uint8_t*)cs->chal, strlen(cs->chal),
		(uint8_t*)secret, strlen(secret), digest,
		nil);
	for(i = 0; i < MD5dlen; i++)
		snprint(response + 2*i, sizeof(response) - 2*i, "%2.2ux", digest[i]);

	cs->user = user;
	cs->resp = response;
	cs->nresp = strlen(response);
	ai = auth_response(cs);
	auth_freechal(cs);
	return ai;
}
Esempio n. 2
0
File: auth.c Progetto: bhanug/harvey
int
vncsrvauth(Vnc *v)
{
	Chalstate *c;
	AuthInfo *ai;

	if((c = auth_challenge("proto=vnc role=server user=%q", getuser()))==nil)
		sysfatal("vncchal: %r");
	if(c->nchal != VncChalLen)
		sysfatal("vncchal got %d bytes wanted %d", c->nchal, VncChalLen);
	vncwrlong(v, AVncAuth);
	vncwrbytes(v, c->chal, VncChalLen);
	vncflush(v);

	vncrdbytes(v, c->chal, VncChalLen);
	c->resp = c->chal;
	c->nresp = VncChalLen;
	ai = auth_response(c);
	auth_freechal(c);
	if(ai == nil){
		fprint(2, "vnc auth failed: server factotum: %r\n");
		vncwrlong(v, VncAuthFailed);
		vncflush(v);
		return -1;
	}
	auth_freeAI(ai);
	vncwrlong(v, VncAuthOK);
	vncflush(v);

	return 0;
}
Esempio n. 3
0
File: cpu.c Progetto: 99years/plan9
static int
netkeysrvauth(int fd, char *user)
{
	char response[32];
	Chalstate *ch;
	int tries;
	AuthInfo *ai;

	if(readstr(fd, user, 32) < 0)
		return -1;

	ai = nil;
	ch = nil;
	for(tries = 0; tries < 10; tries++){
		if((ch = auth_challenge("proto=p9cr role=server user=%q", user)) == nil)
			return -1;
		writestr(fd, ch->chal, "challenge", 1);
		if(readstr(fd, response, sizeof response) < 0)
			return -1;
		ch->resp = response;
		ch->nresp = strlen(response);
		if((ai = auth_response(ch)) != nil)
			break;
	}
	auth_freechal(ch);
	if(ai == nil)
		return -1;
	writestr(fd, "", "challenge", 1);
	if(auth_chuid(ai, 0) < 0)
		fatal(1, "newns");
	auth_freeAI(ai);
	return fd;
}
Esempio n. 4
0
AuthInfo*
auth_userpasswd(char *user, char *passwd)
{
	char key[DESKEYLEN], resp[16];
	AuthInfo *ai;
	Chalstate *ch;

	/*
	 * Probably we should have a factotum protocol
	 * to check a raw password.  For now, we use
	 * p9cr, which is simplest to speak.
	 */
	if((ch = auth_challenge("user=%q proto=p9cr role=server", user)) == nil)
		return nil;

	passtokey(key, passwd);
	netresp(key, atol(ch->chal), resp);
	memset(key, 0, sizeof key);

	ch->resp = resp;
	ch->nresp = strlen(resp);
	ai = auth_response(ch);
	auth_freechal(ch);
	return ai;
}
Esempio n. 5
0
void
main(int argc, char **argv)
{
	char buf[128], bufu[128];
	int afd, n;
	AuthInfo *ai;
	AuthRpc *rpc;
	Chalstate *c;

	ARGBEGIN{
	default:
		usage();
	}ARGEND

	if(argc != 1)
		usage();

	if((afd = open("/mnt/factotum/rpc", ORDWR)) < 0)
		sysfatal("open /mnt/factotum/rpc: %r");

	rpc = auth_allocrpc(afd);
	if(rpc == nil)
		sysfatal("auth_allocrpc: %r");

	if((c = auth_challenge("%s", argv[0])) == nil)
		sysfatal("auth_challenge: %r");

	print("challenge: %s\n", c->chal);
	print("user:"******"response: ");
	n = read(0, buf, sizeof buf);
	if(n < 0)
		sysfatal("read: %r");
	if(n == 0)
		exits(nil);
	c->nresp = n-1;
	c->resp = buf;
	if((ai = auth_response(c)) == nil)
		sysfatal("auth_response: %r");

	print("%s %s\n", ai->cuid, ai->suid);
}
Esempio n. 6
0
static AuthInfo*
responselogin(char *user, char *resp)
{
	Chalstate *c;
	AuthInfo *ai;

	if((c = auth_challenge("proto=p9cr user=%q role=server", user)) == nil){
		sshlog("auth_challenge failed for %s", user);
		return nil;
	}
	c->resp = resp;
	c->nresp = strlen(resp);
	ai = auth_response(c);
	auth_freechal(c);
	return ai;
}
Esempio n. 7
0
File: pop3.c Progetto: npe9/harvey
static int
dologin(char *response)
{
	AuthInfo *ai;
	static int tries;
	static uint32_t delaysecs = 5;

	chs->user = user;
	chs->resp = response;
	chs->nresp = strlen(response);
	if((ai = auth_response(chs)) == nil){
		if(tries >= 20){
			senderr("authentication failed: %r; server exiting");
			exits(nil);
		}
		if(++tries == 3)
			syslog(0, "pop3", "likely password guesser from %s",
				peeraddr);
		delaysecs *= 2;
		if (delaysecs > 30*60)
			delaysecs = 30*60;		/* half-hour max. */
		sleep(delaysecs * 1000); /* prevent beating on our auth server */
		return senderr("authentication failed");
	}

	if(auth_chuid(ai, nil) < 0){
		senderr("chuid failed: %r; server exiting");
		exits(nil);
	}
	auth_freeAI(ai);
	auth_freechal(chs);
	chs = nil;

	loggedin = 1;
	if(newns(user, 0) < 0){
		senderr("newns failed: %r; server exiting");
		exits(nil);
	}
	syslog(0, "pop3", "user %s logged in", user);
	enableaddr();
	if(readmbox(box) < 0)
		exits(nil);
	return sendok("mailbox is %s", box);
}
Esempio n. 8
0
/*
 * rfc 2195 cram-md5 authentication
 */
char*
cramauth(void)
{
	AuthInfo *ai;
	Chalstate *cs;
	char *s, *t;
	int n;

	if((cs = auth_challenge("proto=cram role=server")) == nil)
		return "couldn't get cram challenge";

	n = cs->nchal;
	s = binalloc(&parseBin, n * 2, 0);
	n = enc64(s, n * 2, (uint8_t*)cs->chal, n);
	Bprint(&bout, "+ ");
	Bwrite(&bout, s, n);
	Bprint(&bout, "\r\n");
	if(Bflush(&bout) < 0)
		writeErr();

	s = authresp();
	if(s == nil)
		return "client cancelled authentication";

	t = strchr(s, ' ');
	if(t == nil)
		bye("bad auth response");
	*t++ = '\0';
	strncpy(username, s, UserNameLen);
	username[UserNameLen-1] = '\0';

	cs->user = username;
	cs->resp = t;
	cs->nresp = strlen(t);
	if((ai = auth_response(cs)) == nil)
		return "login failed";
	auth_freechal(cs);
	setupuser(ai);
	return nil;
}
Esempio n. 9
0
void
auth(String *mech, String *resp)
{
	char *user, *pass, *scratch = nil;
	AuthInfo *ai = nil;
	Chalstate *chs = nil;
	String *s_resp1_64 = nil, *s_resp2_64 = nil, *s_resp1 = nil;
	String *s_resp2 = nil;

	if (rejectcheck())
		goto bomb_out;

	syslog(0, "smtpd", "auth(%s, %s) from %s", s_to_c(mech),
		"(protected)", him);

	if (authenticated) {
	bad_sequence:
		rejectcount++;
		reply("503 5.5.2 Bad sequence of commands\r\n");
		goto bomb_out;
	}
	if (cistrcmp(s_to_c(mech), "plain") == 0) {
		if (!passwordinclear) {
			rejectcount++;
			reply("538 5.7.1 Encryption required for requested "
				"authentication mechanism\r\n");
			goto bomb_out;
		}
		s_resp1_64 = resp;
		if (s_resp1_64 == nil) {
			reply("334 \r\n");
			s_resp1_64 = s_new();
			if (getcrnl(s_resp1_64, &bin) <= 0)
				goto bad_sequence;
		}
		s_resp1 = s_dec64(s_resp1_64);
		if (s_resp1 == nil) {
			rejectcount++;
			reply("501 5.5.4 Cannot decode base64\r\n");
			goto bomb_out;
		}
		memset(s_to_c(s_resp1_64), 'X', s_len(s_resp1_64));
		user = s_to_c(s_resp1) + strlen(s_to_c(s_resp1)) + 1;
		pass = user + strlen(user) + 1;
		ai = auth_userpasswd(user, pass);
		authenticated = ai != nil;
		memset(pass, 'X', strlen(pass));
		goto windup;
	}
	else if (cistrcmp(s_to_c(mech), "login") == 0) {
		if (!passwordinclear) {
			rejectcount++;
			reply("538 5.7.1 Encryption required for requested "
				"authentication mechanism\r\n");
			goto bomb_out;
		}
		if (resp == nil) {
			reply("334 VXNlcm5hbWU6\r\n");
			s_resp1_64 = s_new();
			if (getcrnl(s_resp1_64, &bin) <= 0)
				goto bad_sequence;
		}
		reply("334 UGFzc3dvcmQ6\r\n");
		s_resp2_64 = s_new();
		if (getcrnl(s_resp2_64, &bin) <= 0)
			goto bad_sequence;
		s_resp1 = s_dec64(s_resp1_64);
		s_resp2 = s_dec64(s_resp2_64);
		memset(s_to_c(s_resp2_64), 'X', s_len(s_resp2_64));
		if (s_resp1 == nil || s_resp2 == nil) {
			rejectcount++;
			reply("501 5.5.4 Cannot decode base64\r\n");
			goto bomb_out;
		}
		ai = auth_userpasswd(s_to_c(s_resp1), s_to_c(s_resp2));
		authenticated = ai != nil;
		memset(s_to_c(s_resp2), 'X', s_len(s_resp2));
windup:
		if (authenticated) {
			/* if you authenticated, we trust you despite your IP */
			trusted = 1;
			reply("235 2.0.0 Authentication successful\r\n");
		} else {
			rejectcount++;
			reply("535 5.7.1 Authentication failed\r\n");
			syslog(0, "smtpd", "authentication failed: %r");
		}
		goto bomb_out;
	}
	else if (cistrcmp(s_to_c(mech), "cram-md5") == 0) {
		int chal64n;
		char *resp, *t;

		chs = auth_challenge("proto=cram role=server");
		if (chs == nil) {
			rejectcount++;
			reply("501 5.7.5 Couldn't get CRAM-MD5 challenge\r\n");
			goto bomb_out;
		}
		scratch = malloc(chs->nchal * 2 + 1);
		chal64n = enc64(scratch, chs->nchal * 2, (uchar *)chs->chal,
			chs->nchal);
		scratch[chal64n] = 0;
		reply("334 %s\r\n", scratch);
		s_resp1_64 = s_new();
		if (getcrnl(s_resp1_64, &bin) <= 0)
			goto bad_sequence;
		s_resp1 = s_dec64(s_resp1_64);
		if (s_resp1 == nil) {
			rejectcount++;
			reply("501 5.5.4 Cannot decode base64\r\n");
			goto bomb_out;
		}
		/* should be of form <user><space><response> */
		resp = s_to_c(s_resp1);
		t = strchr(resp, ' ');
		if (t == nil) {
			rejectcount++;
			reply("501 5.5.4 Poorly formed CRAM-MD5 response\r\n");
			goto bomb_out;
		}
		*t++ = 0;
		chs->user = resp;
		chs->resp = t;
		chs->nresp = strlen(t);
		ai = auth_response(chs);
		authenticated = ai != nil;
		goto windup;
	}
	rejectcount++;
	reply("501 5.5.1 Unrecognised authentication type %s\r\n", s_to_c(mech));
bomb_out:
	if (ai)
		auth_freeAI(ai);
	if (chs)
		auth_freechal(chs);
	if (scratch)
		free(scratch);
	if (s_resp1)
		s_free(s_resp1);
	if (s_resp2)
		s_free(s_resp2);
	if (s_resp1_64)
		s_free(s_resp1_64);
	if (s_resp2_64)
		s_free(s_resp2_64);
}
Esempio n. 10
0
/*
 *	mschap_authenticate() - authenticate user based on given
 *	attributes and configuration.
 *	We will try to find out password in configuration
 *	or in configured passwd file.
 *	If one is found we will check paraneters given by NAS.
 *
 *	If PW_SMB_ACCOUNT_CTRL is not set to ACB_PWNOTREQ we must have
 *	one of:
 *		PAP:      PW_USER_PASSWORD or
 *		MS-CHAP:  PW_MSCHAP_CHALLENGE and PW_MSCHAP_RESPONSE or
 *		MS-CHAP2: PW_MSCHAP_CHALLENGE and PW_MSCHAP2_RESPONSE
 *	In case of password mismatch or locked account we MAY return
 *	PW_MSCHAP_ERROR for MS-CHAP or MS-CHAP v2
 *	If MS-CHAP2 succeeds we MUST return
 *	PW_MSCHAP2_SUCCESS
 */
static int mschap_authenticate(void * instance, REQUEST *request)
{
#define inst ((rlm_mschap_t *)instance)
	VALUE_PAIR *challenge = NULL;
	VALUE_PAIR *response = NULL;
	VALUE_PAIR *password = NULL;
	VALUE_PAIR *lm_password, *nt_password, *smb_ctrl;
	VALUE_PAIR *username;
	uint8_t nthashhash[16];
	char msch2resp[42];
	char *username_string;
	int chap = 0;
	int		do_ntlm_auth;

	/*
	 *	If we have ntlm_auth configured, use it unless told
	 *	otherwise
	 */
	do_ntlm_auth = (inst->ntlm_auth != NULL);

	/*
	 *	If we have an ntlm_auth configuration, then we may
	 *	want to suppress it.
	 */
	if (do_ntlm_auth) {
		VALUE_PAIR *vp = pairfind(request->config_items,
					  PW_MS_CHAP_USE_NTLM_AUTH);
		if (vp) do_ntlm_auth = vp->vp_integer;
	}

	/*
	 *	Find the SMB-Account-Ctrl attribute, or the
	 *	SMB-Account-Ctrl-Text attribute.
	 */
	smb_ctrl = pairfind(request->config_items, PW_SMB_ACCOUNT_CTRL);
	if (!smb_ctrl) {
		password = pairfind(request->config_items,
				    PW_SMB_ACCOUNT_CTRL_TEXT);
		if (password) {
			smb_ctrl = radius_pairmake(request,
						   &request->config_items,
						   "SMB-Account-CTRL", "0",
						   T_OP_SET);
			if (smb_ctrl) {
				smb_ctrl->vp_integer = pdb_decode_acct_ctrl(password->vp_strvalue);
			}
		}
	}

	/*
	 *	We're configured to do MS-CHAP authentication.
	 *	and account control information exists.  Enforce it.
	 */
	if (smb_ctrl) {
		/*
		 *	Password is not required.
		 */
		if ((smb_ctrl->vp_integer & ACB_PWNOTREQ) != 0) {
			RDEBUG2("SMB-Account-Ctrl says no password is required.");
			return RLM_MODULE_OK;
		}
	}

	/*
	 *	Decide how to get the passwords.
	 */
	password = pairfind(request->config_items, PW_CLEARTEXT_PASSWORD);

	/*
	 *	We need an LM-Password.
	 */
	lm_password = pairfind(request->config_items, PW_LM_PASSWORD);
	if (lm_password) {
		/*
		 *	Allow raw octets.
		 */
		if ((lm_password->length == 16) ||
		    ((lm_password->length == 32) &&
		     (fr_hex2bin(lm_password->vp_strvalue,
				 lm_password->vp_octets, 16) == 16))) {
			RDEBUG2("Found LM-Password");
			lm_password->length = 16;

		} else {
			radlog_request(L_ERR, 0, request, "Invalid LM-Password");
			lm_password = NULL;
		}

	} else if (!password) {
		if (!do_ntlm_auth) RDEBUG2("No Cleartext-Password configured.  Cannot create LM-Password.");

	} else {		/* there is a configured Cleartext-Password */
		lm_password = radius_pairmake(request, &request->config_items,
					      "LM-Password", "", T_OP_EQ);
		if (!lm_password) {
			radlog_request(L_ERR, 0, request, "No memory");
		} else {
			smbdes_lmpwdhash(password->vp_strvalue,
					 lm_password->vp_octets);
			lm_password->length = 16;
		}
	}

	/*
	 *	We need an NT-Password.
	 */
	nt_password = pairfind(request->config_items, PW_NT_PASSWORD);
	if (nt_password) {
		if ((nt_password->length == 16) ||
		    ((nt_password->length == 32) &&
		     (fr_hex2bin(nt_password->vp_strvalue,
				 nt_password->vp_octets, 16) == 16))) {
			RDEBUG2("Found NT-Password");
			nt_password->length = 16;

                } else {
			radlog_request(L_ERR, 0, request, "Invalid NT-Password");
			nt_password = NULL;
		}
	} else if (!password) {
		if (!do_ntlm_auth) RDEBUG2("No Cleartext-Password configured.  Cannot create NT-Password.");

	} else {		/* there is a configured Cleartext-Password */
		nt_password = radius_pairmake(request, &request->config_items,
					      "NT-Password", "", T_OP_EQ);
		if (!nt_password) {
			radlog_request(L_ERR, 0, request, "No memory");
			return RLM_MODULE_FAIL;
		} else {
			ntpwdhash(nt_password->vp_octets,
				  password->vp_strvalue);
			nt_password->length = 16;
		}
	}

	challenge = pairfind(request->packet->vps, PW_MSCHAP_CHALLENGE);
	if (!challenge) {
		RDEBUG2("No MS-CHAP-Challenge in the request");
		return RLM_MODULE_REJECT;
	}

	/*
	 *	We also require an MS-CHAP-Response.
	 */
	response = pairfind(request->packet->vps, PW_MSCHAP_RESPONSE);

	/*
	 *	MS-CHAP-Response, means MS-CHAPv1
	 */
	if (response) {
		int offset;

		/*
		 *	MS-CHAPv1 challenges are 8 octets.
		 */
		if (challenge->length < 8) {
			radlog_request(L_AUTH, 0, request, "MS-CHAP-Challenge has the wrong format.");
			return RLM_MODULE_INVALID;
		}

		/*
		 *	Responses are 50 octets.
		 */
		if (response->length < 50) {
			radlog_request(L_AUTH, 0, request, "MS-CHAP-Response has the wrong format.");
			return RLM_MODULE_INVALID;
		}

		/*
		 *	We are doing MS-CHAP.  Calculate the MS-CHAP
		 *	response
		 */
		if (response->vp_octets[1] & 0x01) {
			RDEBUG2("Told to do MS-CHAPv1 with NT-Password");
			password = nt_password;
			offset = 26;
		} else {
			RDEBUG2("Told to do MS-CHAPv1 with LM-Password");
			password = lm_password;
			offset = 2;
		}

		/*
		 *	Do the MS-CHAP authentication.
		 */
		if (do_mschap(inst, request, password, challenge->vp_octets,
			      response->vp_octets + offset, nthashhash,
			      do_ntlm_auth) < 0) {
			RDEBUG2("MS-CHAP-Response is incorrect.");
			mschap_add_reply(request, &request->reply->vps,
					 *response->vp_octets,
					 "MS-CHAP-Error", "E=691 R=1", 9);
			return RLM_MODULE_REJECT;
		}

		chap = 1;

	} else if ((response = pairfind(request->packet->vps, PW_MSCHAP2_RESPONSE)) != NULL) {
		uint8_t	mschapv1_challenge[16];

		/*
		 *	MS-CHAPv2 challenges are 16 octets.
		 */
		if (challenge->length < 16) {
			radlog_request(L_AUTH, 0, request, "MS-CHAP-Challenge has the wrong format.");
			return RLM_MODULE_INVALID;
		}

		/*
		 *	Responses are 50 octets.
		 */
		if (response->length < 50) {
			radlog_request(L_AUTH, 0, request, "MS-CHAP-Response has the wrong format.");
			return RLM_MODULE_INVALID;
		}

		/*
		 *	We also require a User-Name
		 */
		username = pairfind(request->packet->vps, PW_USER_NAME);
		if (!username) {
			radlog_request(L_AUTH, 0, request, "We require a User-Name for MS-CHAPv2");
			return RLM_MODULE_INVALID;
		}


		/*
		 *	with_ntdomain_hack moved here
		 */
		if ((username_string = strchr(username->vp_strvalue, '\\')) != NULL) {
		        if (inst->with_ntdomain_hack) {
			        username_string++;
			} else {
				RDEBUG2("  NT Domain delimeter found, should we have enabled with_ntdomain_hack?");
				username_string = username->vp_strvalue;
			}
		} else {
		        username_string = username->vp_strvalue;
		}

#ifdef __APPLE__
		/*
		 *  No "known good" NT-Password attribute.  Try to do
		 *  OpenDirectory authentication.
		 *
		 *  If OD determines the user is an AD user it will return noop, which
		 *  indicates the auth process should continue directly to AD.
		 *  Otherwise OD will determine auth success/fail.
		 */
		if (!nt_password && inst->open_directory) {
			RDEBUG2("No NT-Password configured. Trying OpenDirectory Authentication.");
			int odStatus = od_mschap_auth(request, challenge, username);
			if (odStatus != RLM_MODULE_NOOP) {
				return odStatus;
			}
		}
#endif
		/*
		 *	The old "mschapv2" function has been moved to
		 *	here.
		 *
		 *	MS-CHAPv2 takes some additional data to create an
		 *	MS-CHAPv1 challenge, and then does MS-CHAPv1.
		 */
		challenge_hash(response->vp_octets + 2, /* peer challenge */
			       challenge->vp_octets, /* our challenge */
			       username_string,	/* user name */
			       mschapv1_challenge); /* resulting challenge */

		RDEBUG2("Told to do MS-CHAPv2 for %s with NT-Password",
		       username_string);

		if (do_mschap(inst, request, nt_password, mschapv1_challenge,
			      response->vp_octets + 26, nthashhash,
			      do_ntlm_auth) < 0) {
			RDEBUG2("FAILED: MS-CHAP2-Response is incorrect");
			mschap_add_reply(request, &request->reply->vps,
					 *response->vp_octets,
					 "MS-CHAP-Error", "E=691 R=1", 9);
			return RLM_MODULE_REJECT;
		}

		/*
		 *	Get the NT-hash-hash, if necessary
		 */
		if (nt_password) {
		}

		auth_response(username_string, /* without the domain */
			      nthashhash, /* nt-hash-hash */
			      response->vp_octets + 26, /* peer response */
			      response->vp_octets + 2, /* peer challenge */
			      challenge->vp_octets, /* our challenge */
			      msch2resp); /* calculated MPPE key */
		mschap_add_reply(request, &request->reply->vps, *response->vp_octets,
				 "MS-CHAP2-Success", msch2resp, 42);
		chap = 2;

	} else {		/* Neither CHAPv1 or CHAPv2 response: die */
		radlog_request(L_AUTH, 0, request, "No MS-CHAP response found");
		return RLM_MODULE_INVALID;
	}

	/*
	 *	We have a CHAP response, but the account may be
	 *	disabled.  Reject the user with the same error code
	 *	we use when their password is invalid.
	 */
	if (smb_ctrl) {
		/*
		 *	Account is disabled.
		 *
		 *	They're found, but they don't exist, so we
		 *	return 'not found'.
		 */
		if (((smb_ctrl->vp_integer & ACB_DISABLED) != 0) ||
		    ((smb_ctrl->vp_integer & ACB_NORMAL) == 0)) {
			RDEBUG2("SMB-Account-Ctrl says that the account is disabled, or is not a normal account.");
			mschap_add_reply(request, &request->reply->vps,
					  *response->vp_octets,
					  "MS-CHAP-Error", "E=691 R=1", 9);
			return RLM_MODULE_NOTFOUND;
		}

		/*
		 *	User is locked out.
		 */
		if ((smb_ctrl->vp_integer & ACB_AUTOLOCK) != 0) {
			RDEBUG2("SMB-Account-Ctrl says that the account is locked out.");
			mschap_add_reply(request, &request->reply->vps,
					  *response->vp_octets,
					  "MS-CHAP-Error", "E=647 R=0", 9);
			return RLM_MODULE_USERLOCK;
		}
	}

	/* now create MPPE attributes */
	if (inst->use_mppe) {
		uint8_t mppe_sendkey[34];
		uint8_t mppe_recvkey[34];

		if (chap == 1){
			RDEBUG2("adding MS-CHAPv1 MPPE keys");
			memset(mppe_sendkey, 0, 32);
			if (lm_password) {
				memcpy(mppe_sendkey, lm_password->vp_octets, 8);
			}

			/*
			 *	According to RFC 2548 we
			 *	should send NT hash.  But in
			 *	practice it doesn't work.
			 *	Instead, we should send nthashhash
			 *
			 *	This is an error on RFC 2548.
			 */
			/*
			 *	do_mschap cares to zero nthashhash if NT hash
			 *	is not available.
			 */
			memcpy(mppe_sendkey + 8,
			       nthashhash, 16);
			mppe_add_reply(request,
				       "MS-CHAP-MPPE-Keys",
				       mppe_sendkey, 32);
		} else if (chap == 2) {
			RDEBUG2("adding MS-CHAPv2 MPPE keys");
			mppe_chap2_gen_keys128(nthashhash,
					       response->vp_octets + 26,
					       mppe_sendkey, mppe_recvkey);

			mppe_add_reply(request,
				       "MS-MPPE-Recv-Key",
				       mppe_recvkey, 16);
			mppe_add_reply(request,
				       "MS-MPPE-Send-Key",
				       mppe_sendkey, 16);

		}
		radius_pairmake(request, &request->reply->vps,
				"MS-MPPE-Encryption-Policy",
				(inst->require_encryption)? "0x00000002":"0x00000001",
				T_OP_EQ);
		radius_pairmake(request, &request->reply->vps,
				"MS-MPPE-Encryption-Types",
				(inst->require_strong)? "0x00000004":"0x00000006",
				T_OP_EQ);
	} /* else we weren't asked to use MPPE */

	return RLM_MODULE_OK;
#undef inst
}
SmbProcessResult
smbcomsessionsetupandx(SmbSession *s, SmbHeader *h, uchar *pdata, SmbBuffer *b)
{
	uchar andxcommand;
	ushort andxoffset;
	ulong andxfixupoffset;
	ushort vcnumber;
	ulong sessionkey;
	ushort caseinsensitivepasswordlength;
	ushort casesensitivepasswordlength;
	ushort bytecountfixup, offset;
	uchar *mschapreply;
	AuthInfo *ai;
	char *sp;
	SmbProcessResult pr;
	char *accountname = nil;
	char *primarydomain = nil;
	char *nativeos = nil;
	char *nativelanman = nil;

	if (!smbcheckwordcount("comsessionsetupandx", h, 13)) {
	fmtfail:
		pr = SmbProcessResultFormat;
		goto done;
	}

	andxcommand = *pdata++;
	switch (andxcommand) {
	case SMB_COM_TREE_CONNECT_ANDX:
	case SMB_COM_OPEN_ANDX:
	case SMB_COM_CREATE_NEW:
	case SMB_COM_DELETE:
	case SMB_COM_FIND:
	case SMB_COM_COPY:
	case SMB_COM_NT_RENAME:
	case SMB_COM_QUERY_INFORMATION:
	case SMB_COM_NO_ANDX_COMMAND:
	case SMB_COM_OPEN:
	case SMB_COM_CREATE:
	case SMB_COM_CREATE_DIRECTORY:
	case SMB_COM_DELETE_DIRECTORY:
	case SMB_COM_FIND_UNIQUE:
	case SMB_COM_RENAME:
	case SMB_COM_CHECK_DIRECTORY:
	case SMB_COM_SET_INFORMATION:
	case SMB_COM_OPEN_PRINT_FILE:
		break;
	default:
		smblogprint(h->command, "smbcomsessionsetupandx: invalid andxcommand %s (0x%.2ux)\n",
			smboptable[andxcommand].name, andxcommand);
		goto fmtfail;
	}
	pdata++;
	andxoffset = smbnhgets(pdata); pdata += 2;
	s->peerinfo.maxlen = smbnhgets(pdata); pdata += 2;
	smbresponseinit(s, s->peerinfo.maxlen);
	s->client.maxmpxcount = smbnhgets(pdata); pdata += 2;
	vcnumber = smbnhgets(pdata); pdata += 2;
	sessionkey = smbnhgetl(pdata); pdata += 4;
	caseinsensitivepasswordlength = smbnhgets(pdata); pdata += 2;
	casesensitivepasswordlength = smbnhgets(pdata); pdata += 2;
	pdata += 4;
	s->peerinfo.capabilities = smbnhgetl(pdata); /*pdata += 4;*/
smbloglock();
smblogprint(h->command, "andxcommand: %s offset %ud\n", smboptable[andxcommand].name, andxoffset);
smblogprint(h->command, "client.maxbuffersize: %ud\n", s->peerinfo.maxlen);
smblogprint(h->command, "client.maxmpxcount: %ud\n", s->client.maxmpxcount);
smblogprint(h->command, "vcnumber: %ud\n", vcnumber);
smblogprint(h->command, "sessionkey: 0x%.8lux\n", sessionkey);
smblogprint(h->command, "caseinsensitivepasswordlength: %ud\n", caseinsensitivepasswordlength);
smblogprint(h->command, "casesensitivepasswordlength: %ud\n", casesensitivepasswordlength);
smblogprint(h->command, "clientcapabilities: 0x%.8lux\n", s->peerinfo.capabilities);
smblogunlock();

	mschapreply = smbbufferreadpointer(b);

	if (!smbbuffergetbytes(b, nil, caseinsensitivepasswordlength + casesensitivepasswordlength)) {
		smblogprint(h->command, "smbcomsessionsetupandx: not enough bdata for passwords\n");
		goto fmtfail;
	}
	if (!smbbuffergetstring(b, h, 0, &accountname)
		|| !smbbuffergetstring(b, h, 0, &primarydomain)
		|| !smbbuffergetstring(b, h, 0, &nativeos)
		|| !smbbuffergetstring(b, h, 0, &nativelanman)) {
		smblogprint(h->command, "smbcomsessionsetupandx: not enough bytes for strings\n");
		goto fmtfail;
	}

	for (sp = accountname; *sp; sp++)
		*sp = tolower(*sp);

smblogprint(h->command, "account: %s\n", accountname);
smblogprint(h->command, "primarydomain: %s\n", primarydomain);
smblogprint(h->command, "nativeos: %s\n", nativeos);
smblogprint(h->command, "nativelanman: %s\n", nativelanman);

	if (s->client.accountname && accountname[0] && strcmp(s->client.accountname, accountname) != 0) {
		smblogprint(h->command, "smbcomsessionsetupandx: more than one user on VC (before %s, now %s)\n",
			s->client.accountname, accountname);
		smbseterror(s, ERRSRV, ERRtoomanyuids);
	errordone:
		pr = SmbProcessResultError;
		goto done;
	}

	if (s->client.accountname == nil) {
		/* first time */
		if (accountname[0] == 0) {
			smbseterror(s, ERRSRV, ERRbaduid);
			goto errordone;
		}
		if ((casesensitivepasswordlength != 24 || caseinsensitivepasswordlength != 24)) {
			smblogprint(h->command,
				"smbcomsessionsetupandx: case sensitive/insensitive password length not 24\n");
			smbseterror(s, ERRSRV, ERRbadpw);
			goto errordone;
		}
		memcpy(&s->client.mschapreply, mschapreply, sizeof(s->client.mschapreply));
		if(s->cs == nil){
			smbseterror(s, ERRSRV, ERRerror);
			goto errordone;
		}
		s->cs->user = accountname;
		s->cs->resp = &s->client.mschapreply;
		s->cs->nresp = sizeof(MSchapreply);
		ai = auth_response(s->cs);
		if (ai == nil) {
			smblogprint(h->command, "authentication failed\n");
			smbseterror(s, ERRSRV, ERRbadpw);
			goto errordone;
		}
		smblogprint(h->command, "authentication succeeded\n");
		if (auth_chuid(ai, nil) < 0) {
			smblogprint(h->command, "smbcomsessionsetupandx: chuid failed: %r\n");
			auth_freeAI(ai);
		miscerror:
			pr = SmbProcessResultMisc;
			goto done;
		}
		auth_freeAI(ai);
		h->uid = 1;
		s->client.accountname = accountname;
		s->client.primarydomain = primarydomain;
		s->client.nativeos = nativeos;
		s->client.nativelanman = nativelanman;
		accountname = nil;
		primarydomain = nil;
		nativeos = nil;
		nativelanman = nil;
	}
	else {
		if (caseinsensitivepasswordlength == 24 && casesensitivepasswordlength == 24
			&& memcmp(&s->client.mschapreply, mschapreply, sizeof(MSchapreply)) != 0) {
			smblogprint(h->command, "second time authentication failed\n");
			smbseterror(s, ERRSRV, ERRbadpw);
			goto errordone;
		}
	}

	/* CIFS says 4 with or without extended security, samba/ms says 3 without */
	h->wordcount = 3;
	if (!smbresponseputandxheader(s, h, andxcommand, &andxfixupoffset))
		goto miscerror;
	if (!smbresponseputs(s, 0))
		goto miscerror;
	bytecountfixup = smbresponseoffset(s);
	if (!smbresponseputs(s, 0))
		goto miscerror;
	if (!smbresponseputstring(s, 1, smbglobals.nativeos)
		|| !smbresponseputstring(s, 1, smbglobals.serverinfo.nativelanman)
		|| !smbresponseputstring(s, 1, smbglobals.primarydomain))
		goto miscerror;
	offset = smbresponseoffset(s);
	smbresponseoffsetputs(s, bytecountfixup, offset - bytecountfixup - 2);
	s->state = SmbSessionEstablished;
	if (andxcommand != SMB_COM_NO_ANDX_COMMAND)
		pr = smbchaincommand(s, h, andxfixupoffset, andxcommand, andxoffset, b);
	else
		pr = SmbProcessResultReply;
done:
	free(accountname);
	free(primarydomain);
	free(nativeos);
	free(nativelanman);
	return pr;
}