--- old/usr/src/cmd/smbsrv/smbd/smbd_logon.c	Mon Aug  5 17:15:31 2019
+++ new/usr/src/cmd/smbsrv/smbd/smbd_logon.c	Mon Aug  5 17:15:31 2019
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  */
 
 #include <sys/types.h>
@@ -76,32 +76,31 @@
 
 /*
  * Invoked at user logon due to SmbSessionSetupX.  Authenticate the
- * user, start an audit session and audit the event.
+ * user.
+ *
+ * On error, returns NULL, and status in user_info->lg_status
  */
 smb_token_t *
 smbd_user_auth_logon(smb_logon_t *user_info)
 {
 	smb_token_t *token;
-	smb_audit_t *entry;
-	adt_session_data_t *ah;
-	adt_event_data_t *event;
 	smb_logon_t tmp_user;
-	au_tid_addr_t termid;
-	char sidbuf[SMB_SID_STRSZ];
-	char *username;
-	char *domain;
-	uid_t uid;
-	gid_t gid;
-	char *sid;
-	int status;
-	int retval;
+	char *p;
+	char *buf = NULL;
 
 	if (user_info->lg_username == NULL ||
 	    user_info->lg_domain == NULL ||
 	    user_info->lg_workstation == NULL) {
+		user_info->lg_status = NT_STATUS_INVALID_PARAMETER;
 		return (NULL);
 	}
 
+	/*
+	 * Avoid modifying the caller-provided struct because it
+	 * may or may not point to allocated strings etc.
+	 * Copy to tmp_user, auth, then copy the (out) lg_status
+	 * member back to the caller-provided struct.
+	 */
 	tmp_user = *user_info;
 	if (tmp_user.lg_username[0] == '\0') {
 		tmp_user.lg_flags |= SMB_ATF_ANON;
@@ -109,14 +108,73 @@
 	} else {
 		tmp_user.lg_e_username = tmp_user.lg_username;
 	}
-	tmp_user.lg_e_domain = tmp_user.lg_domain;
 
-	if ((token = smb_logon(&tmp_user)) == NULL) {
+	/* Handle user@domain format. */
+	if (tmp_user.lg_domain[0] == '\0' &&
+	    (p = strchr(tmp_user.lg_e_username, '@')) != NULL) {
+		buf = strdup(tmp_user.lg_e_username);
+		p = buf + (p - tmp_user.lg_e_username);
+		*p = '\0';
+		tmp_user.lg_e_domain = p + 1;
+		tmp_user.lg_e_username = buf;
+	} else {
+		tmp_user.lg_e_domain = tmp_user.lg_domain;
+	}
+
+	token = smb_logon(&tmp_user);
+	user_info->lg_status = tmp_user.lg_status;
+
+	if (token == NULL) {
+		if (user_info->lg_status == 0) /* should not happen */
+			user_info->lg_status = NT_STATUS_INTERNAL_ERROR;
+	}
+
+	if (!smbd_logon_audit(token, &user_info->lg_clnt_ipaddr,
+	    tmp_user.lg_e_username, tmp_user.lg_e_domain)) {
+		user_info->lg_status = NT_STATUS_AUDIT_FAILED;
+		goto errout;
+	}
+
+	if (token) {
+		smb_autohome_add(token);
+	}
+
+	if (buf != NULL)
+		free(buf);
+
+	return (token);
+
+errout:
+	if (buf != NULL)
+		free(buf);
+	smb_token_destroy(token);
+	return (NULL);
+}
+
+/* Start an audit session and audit the event. */
+boolean_t
+smbd_logon_audit(smb_token_t *token, smb_inaddr_t *ipaddr, char *username,
+    char *domain)
+{
+	smb_audit_t *entry;
+	adt_session_data_t *ah = NULL;
+	adt_event_data_t *event;
+	au_tid_addr_t termid;
+	char sidbuf[SMB_SID_STRSZ];
+	uid_t uid;
+	gid_t gid;
+	char *sid;
+	int status;
+	int retval;
+
+	if (username == NULL)
+		username = "";
+
+	if (token == NULL) {
 		uid = ADT_NO_ATTRIB;
 		gid = ADT_NO_ATTRIB;
 		sid = NT_NULL_SIDSTR;
-		username = tmp_user.lg_e_username;
-		domain = tmp_user.lg_e_domain;
+		/* use the 'default' username and domain we were given */
 		status = ADT_FAILURE;
 		retval = ADT_FAIL_VALUE_AUTH;
 	} else {
@@ -132,26 +190,23 @@
 
 	if (adt_start_session(&ah, NULL, 0)) {
 		syslog(LOG_AUTH | LOG_ALERT, "adt_start_session: %m");
-		smb_token_destroy(token);
-		return (NULL);
+		goto errout;
 	}
 
 	if ((event = adt_alloc_event(ah, ADT_smbd_session)) == NULL) {
 		syslog(LOG_AUTH | LOG_ALERT,
 		    "adt_alloc_event(ADT_smbd_session): %m");
-		(void) adt_end_session(ah);
-		smb_token_destroy(token);
-		return (NULL);
+		goto errout;
 	}
 
 	(void) memset(&termid, 0, sizeof (au_tid_addr_t));
-	termid.at_port = user_info->lg_local_port;
+	termid.at_port = 445;
 
-	if (user_info->lg_clnt_ipaddr.a_family == AF_INET) {
-		termid.at_addr[0] = user_info->lg_clnt_ipaddr.a_ipv4;
+	if (ipaddr->a_family == AF_INET) {
+		termid.at_addr[0] = ipaddr->a_ipv4;
 		termid.at_type = AU_IPv4;
 	} else {
-		bcopy(&user_info->lg_clnt_ipaddr.a_ip, termid.at_addr,
+		bcopy(&ipaddr->a_ip, termid.at_addr,
 		    sizeof (in6_addr_t));
 		termid.at_type = AU_IPv6;
 	}
@@ -160,9 +215,7 @@
 	if (adt_set_user(ah, uid, gid, uid, gid, NULL, ADT_NEW)) {
 		syslog(LOG_AUTH | LOG_ALERT, "adt_set_user: %m");
 		adt_free_event(event);
-		(void) adt_end_session(ah);
-		smb_token_destroy(token);
-		return (NULL);
+		goto errout;
 	}
 
 	event->adt_smbd_session.domain = domain;
@@ -177,9 +230,7 @@
 	if (token) {
 		if ((entry = malloc(sizeof (smb_audit_t))) == NULL) {
 			syslog(LOG_ERR, "smbd_user_auth_logon: %m");
-			(void) adt_end_session(ah);
-			smb_token_destroy(token);
-			return (NULL);
+			goto errout;
 		}
 
 		entry->sa_handle = ah;
@@ -188,12 +239,19 @@
 		entry->sa_username = strdup(username);
 		entry->sa_domain = strdup(domain);
 
-		smb_autohome_add(token);
 		smbd_audit_link(entry);
 		token->tkn_audit_sid = entry->sa_audit_sid;
+		adt_get_auid(ah, &token->tkn_auid);
+		adt_get_mask(ah, &token->tkn_amask);
+		adt_get_asid(ah, &token->tkn_asid);
 	}
 
-	return (token);
+	return (B_TRUE);
+errout:
+	if (ah != NULL)
+		(void) adt_end_session(ah);
+
+	return (B_FALSE);
 }
 
 /*
