changeset 21402:60e796757b53

10992 SMB logon should tolerate idmap problems Reviewed by: Matt Barden <matt.barden@nexenta.com> Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com> Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com> Approved by: Richard Lowe <richlowe@richlowe.net>
author Gordon Ross <gwr@nexenta.com>
date Tue, 10 Jul 2018 13:05:19 -0400
parents ebeeffcb370f
children da3a5bcef56c
files usr/src/lib/smbsrv/libfksmbsrv/common/fksmb_idmap.c usr/src/lib/smbsrv/libmlsvc/common/smb_logon.c usr/src/lib/smbsrv/libsmb/common/smb_idmap.c usr/src/uts/common/fs/smbsrv/smb_idmap.c usr/src/uts/common/smbsrv/smb_idmap.h
diffstat 5 files changed, 162 insertions(+), 60 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/lib/smbsrv/libfksmbsrv/common/fksmb_idmap.c	Wed May 29 17:34:03 2019 +0000
+++ b/usr/src/lib/smbsrv/libfksmbsrv/common/fksmb_idmap.c	Tue Jul 10 13:05:19 2018 -0400
@@ -20,17 +20,17 @@
  */
 /*
  * 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.
  */
 
 /*
  * SMB server interface to idmap
  * (smb_idmap_get..., smb_idmap_batch_...)
  *
- * There are three implementations of this interface:
- *	uts/common/fs/smbsrv/smb_idmap.c (smbsrv kmod)
- *	lib/smbsrv/libfksmbsrv/common/fksmb_idmap.c (libfksmbsrv)
- *	lib/smbsrv/libsmb/common/smb_idmap.c (libsmb)
+ * There are three implementations of this interface.
+ * This is the "fake kernel" version of these routines.  See also:
+ * $SRC/lib/smbsrv/libsmb/common/smb_idmap.c
+ * $SRC/uts/common/fs/smbsrv/smb_idmap.c
  *
  * There are enough differences (relative to the code size)
  * that it's more trouble than it's worth to merge them.
@@ -39,6 +39,7 @@
  *	calls idmap interfaces (libidmap)
  *	uses kmem_... interfaces (libfakekernel)
  *	uses cmn_err instead of syslog, etc.
+ * The code in this variant looks a lot like the one in libsmb.
  */
 
 #include <sys/param.h>
@@ -148,8 +149,7 @@
 {
 	idmap_stat	stat;
 
-	if (!sib)
-		return (IDMAP_ERR_ARG);
+	ASSERT(sib != NULL);
 
 	bzero(sib, sizeof (smb_idmap_batch_t));
 	stat = idmap_get_create(&sib->sib_idmaph);
@@ -175,19 +175,17 @@
 void
 smb_idmap_batch_destroy(smb_idmap_batch_t *sib)
 {
+	char *domsid;
 	int i;
 
-	if (sib == NULL)
-		return;
+	ASSERT(sib != NULL);
+	ASSERT(sib->sib_maps != NULL);
 
 	if (sib->sib_idmaph) {
 		idmap_get_destroy(sib->sib_idmaph);
 		sib->sib_idmaph = NULL;
 	}
 
-	if (sib->sib_maps == NULL)
-		return;
-
 	if (sib->sib_flags & SMB_IDMAP_ID2SID) {
 		/*
 		 * SIDs are allocated only when mapping
@@ -198,6 +196,16 @@
 			/* from strdup() in libidmap */
 			free(sib->sib_maps[i].sim_domsid);
 		}
+	} else if (sib->sib_flags & SMB_IDMAP_SID2ID) {
+		/*
+		 * SID prefixes are allocated only when mapping
+		 * SIDs to UID/GID
+		 */
+		for (i = 0; i < sib->sib_nmap; i++) {
+			domsid = sib->sib_maps[i].sim_domsid;
+			if (domsid)
+				smb_mem_free(domsid);
+		}
 	}
 
 	if (sib->sib_size && sib->sib_maps) {
@@ -225,13 +233,15 @@
 	idmap_stat stat;
 	int flag = 0;
 
-	if (idmaph == NULL || sim == NULL || sid == NULL)
-		return (IDMAP_ERR_ARG);
+	ASSERT(idmaph != NULL);
+	ASSERT(sim != NULL);
+	ASSERT(sid != NULL);
 
 	smb_sid_tostr(sid, sidstr);
 	if (smb_sid_splitstr(sidstr, &sim->sim_rid) != 0)
 		return (IDMAP_ERR_SID);
-	sim->sim_domsid = sidstr;
+	/* Note: Free sim_domsid in smb_idmap_batch_destroy */
+	sim->sim_domsid = smb_mem_strdup(sidstr);
 	sim->sim_idtype = idtype;
 
 	switch (idtype) {
@@ -259,9 +269,6 @@
 		break;
 	}
 
-	/* This was copied by idmap_get_Xbysid. */
-	sim->sim_domsid = NULL;
-
 	return (stat);
 }
 
@@ -272,6 +279,8 @@
  *
  * sim->sim_domsid and sim->sim_rid will contain the mapping
  * result upon successful process of the batched request.
+ * Stash the type for error reporting (caller saves the ID).
+ *
  * NB: sim_domsid allocated by strdup, here or in libidmap
  */
 idmap_stat
@@ -284,6 +293,7 @@
 	if (!idmaph || !sim)
 		return (IDMAP_ERR_ARG);
 
+	sim->sim_idtype = idtype;
 	switch (idtype) {
 	case SMB_IDMAP_USER:
 		stat = idmap_get_sidbyuid(idmaph, id, flag,
@@ -322,12 +332,35 @@
 		break;
 
 	default:
+		ASSERT(0);
 		return (IDMAP_ERR_ARG);
 	}
 
 	return (stat);
 }
 
+static void
+smb_idmap_bgm_report(smb_idmap_batch_t *sib, smb_idmap_t *sim)
+{
+
+	if ((sib->sib_flags & SMB_IDMAP_ID2SID) != 0) {
+		/*
+		 * Note: The ID and type we asked idmap to map
+		 * were saved in *sim_id and sim_idtype.
+		 */
+		uint_t id = (sim->sim_id == NULL) ?
+		    0 : (uint_t)*sim->sim_id;
+		cmn_err(CE_WARN, "Can't get SID for "
+		    "ID=%u type=%d, status=%d",
+		    id, sim->sim_idtype, sim->sim_stat);
+	}
+
+	if ((sib->sib_flags & SMB_IDMAP_SID2ID) != 0) {
+		cmn_err(CE_WARN, "Can't get ID for SID %s-%u, status=%d",
+		    sim->sim_domsid, sim->sim_rid, sim->sim_stat);
+	}
+}
+
 /*
  * smb_idmap_batch_getmappings
  *
@@ -353,13 +386,10 @@
 	 */
 	for (i = 0, sim = sib->sib_maps; i < sib->sib_nmap; i++, sim++) {
 		if (sim->sim_stat != IDMAP_SUCCESS) {
-			if (sib->sib_flags == SMB_IDMAP_SID2ID) {
-				cmn_err(CE_NOTE, "[%d] %d (%d)",
-				    sim->sim_idtype,
-				    sim->sim_rid,
-				    sim->sim_stat);
+			smb_idmap_bgm_report(sib, sim);
+			if ((sib->sib_flags & SMB_IDMAP_SKIP_ERRS) == 0) {
+				return (sim->sim_stat);
 			}
-			return (sim->sim_stat);
 		}
 	}
 
@@ -389,6 +419,7 @@
 
 	sim = sib->sib_maps;
 	for (i = 0; i < sib->sib_nmap; sim++, i++) {
+		ASSERT(sim->sim_domsid != NULL);
 		if (sim->sim_domsid == NULL)
 			return (-1);
 
--- a/usr/src/lib/smbsrv/libmlsvc/common/smb_logon.c	Wed May 29 17:34:03 2019 +0000
+++ b/usr/src/lib/smbsrv/libmlsvc/common/smb_logon.c	Tue Jul 10 13:05:19 2018 -0400
@@ -21,7 +21,7 @@
 /*
  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2016 by Delphix. All rights reserved.
- * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  */
 
 #include <unistd.h>
@@ -129,6 +129,10 @@
  * smb_token_sids2ids
  *
  * This will map all the SIDs of the access token to UIDs/GIDs.
+ * However, if there are some SIDs we can't map to UIDs/GIDs,
+ * we don't want to fail the logon, and instead just log the
+ * SIDs we could not map and continue as best we can.
+ * The flag SMB_IDMAP_SKIP_ERRS below does that.
  *
  * Returns 0 upon success.  Otherwise, returns -1.
  */
@@ -148,7 +152,8 @@
 	else
 		nmaps = token->tkn_win_grps.i_cnt + 3;
 
-	stat = smb_idmap_batch_create(&sib, nmaps, SMB_IDMAP_SID2ID);
+	stat = smb_idmap_batch_create(&sib, nmaps,
+	    SMB_IDMAP_SID2ID | SMB_IDMAP_SKIP_ERRS);
 	if (stat != IDMAP_SUCCESS)
 		return (-1);
 
--- a/usr/src/lib/smbsrv/libsmb/common/smb_idmap.c	Wed May 29 17:34:03 2019 +0000
+++ b/usr/src/lib/smbsrv/libsmb/common/smb_idmap.c	Tue Jul 10 13:05:19 2018 -0400
@@ -20,17 +20,17 @@
  */
 /*
  * 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.
  */
 
 /*
  * SMB server interface to idmap
  * (smb_idmap_get..., smb_idmap_batch_...)
  *
- * There are three implementations of this interface:
- *	uts/common/fs/smbsrv/smb_idmap.c (smbsrv kmod)
- *	lib/smbsrv/libfksmbsrv/common/fksmb_idmap.c (libfksmbsrv)
- *	lib/smbsrv/libsmb/common/smb_idmap.c (libsmb)
+ * There are three implementations of this interface.
+ * This is the libsmb version of these routines.  See also:
+ * $SRC/uts/common/fs/smbsrv/smb_idmap.c
+ * $SRC/lib/smbsrv/libfksmbsrv/common/fksmb_idmap.c
  *
  * There are enough differences (relative to the code size)
  * that it's more trouble than it's worth to merge them.
@@ -197,6 +197,14 @@
 			smb_sid_free(sib->sib_maps[i].sim_sid);
 			free(sib->sib_maps[i].sim_domsid);
 		}
+	} else if (sib->sib_flags & SMB_IDMAP_SID2ID) {
+		/*
+		 * SID prefixes are allocated only when mapping
+		 * SIDs to UID/GID
+		 */
+		for (i = 0; i < sib->sib_nmap; i++) {
+			free(sib->sib_maps[i].sim_domsid);
+		}
 	}
 
 	if (sib->sib_size && sib->sib_maps) {
@@ -230,7 +238,8 @@
 	smb_sid_tostr(sid, sidstr);
 	if (smb_sid_splitstr(sidstr, &sim->sim_rid) != 0)
 		return (IDMAP_ERR_SID);
-	sim->sim_domsid = sidstr;
+	/* Note: Free sim_domsid in smb_idmap_batch_destroy */
+	sim->sim_domsid = strdup(sidstr);
 	sim->sim_idtype = idtype;
 
 	switch (idtype) {
@@ -258,9 +267,6 @@
 		break;
 	}
 
-	/* This was copied by idmap_get_Xbysid. */
-	sim->sim_domsid = NULL;
-
 	return (stat);
 }
 
@@ -271,6 +277,8 @@
  *
  * sim->sim_domsid and sim->sim_rid will contain the mapping
  * result upon successful process of the batched request.
+ * Stash the type for error reporting (caller saves the ID).
+ *
  * NB: sim_domsid allocated by strdup, here or in libidmap
  */
 idmap_stat
@@ -283,6 +291,7 @@
 	if (!idmaph || !sim)
 		return (IDMAP_ERR_ARG);
 
+	sim->sim_idtype = idtype;
 	switch (idtype) {
 	case SMB_IDMAP_USER:
 		stat = idmap_get_sidbyuid(idmaph, id, flag,
@@ -327,6 +336,28 @@
 	return (stat);
 }
 
+static void
+smb_idmap_bgm_report(smb_idmap_batch_t *sib, smb_idmap_t *sim)
+{
+
+	if ((sib->sib_flags & SMB_IDMAP_ID2SID) != 0) {
+		/*
+		 * Note: The ID and type we asked idmap to map
+		 * were saved in *sim_id and sim_idtype.
+		 */
+		uint_t id = (sim->sim_id == NULL) ?
+		    0 : (uint_t)*sim->sim_id;
+		syslog(LOG_ERR, "Can't get SID for "
+		    "ID=%u type=%d, status=%d",
+		    id, sim->sim_idtype, sim->sim_stat);
+	}
+
+	if ((sib->sib_flags & SMB_IDMAP_SID2ID) != 0) {
+		syslog(LOG_ERR, "Can't get ID for SID %s-%u, status=%d",
+		    sim->sim_domsid, sim->sim_rid, sim->sim_stat);
+	}
+}
+
 /*
  * smb_idmap_batch_getmappings
  *
@@ -352,11 +383,10 @@
 	 */
 	for (i = 0, sim = sib->sib_maps; i < sib->sib_nmap; i++, sim++) {
 		if (sim->sim_stat != IDMAP_SUCCESS) {
-			if (sib->sib_flags == SMB_IDMAP_SID2ID) {
-				smb_tracef("[%d] %d (%d)", sim->sim_idtype,
-				    sim->sim_rid, sim->sim_stat);
+			smb_idmap_bgm_report(sib, sim);
+			if ((sib->sib_flags & SMB_IDMAP_SKIP_ERRS) == 0) {
+				return (sim->sim_stat);
 			}
-			return (sim->sim_stat);
 		}
 	}
 
--- a/usr/src/uts/common/fs/smbsrv/smb_idmap.c	Wed May 29 17:34:03 2019 +0000
+++ b/usr/src/uts/common/fs/smbsrv/smb_idmap.c	Tue Jul 10 13:05:19 2018 -0400
@@ -20,24 +20,24 @@
  */
 /*
  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  */
 
 /*
  * SMB server interface to idmap
  * (smb_idmap_get..., smb_idmap_batch_...)
  *
- * There are three implementations of this interface:
- *	uts/common/fs/smbsrv/smb_idmap.c (smbsrv kmod)
- *	lib/smbsrv/libfksmbsrv/common/fksmb_idmap.c (libfksmbsrv)
- *	lib/smbsrv/libsmb/common/smb_idmap.c (libsmb)
+ * There are three implementations of this interface.
+ * This is the kernel version of these routines.  See also:
+ * $SRC/lib/smbsrv/libfksmbsrv/common/fksmb_idmap.c
+ * $SRC/lib/smbsrv/libsmb/common/smb_idmap.c
  *
  * There are enough differences (relative to the code size)
  * that it's more trouble than it's worth to merge them.
  *
  * This one differs from the others in that it:
  *	calls kernel (kidmap_...) interfaces
- *	domain SIDs are shared, not strdup'ed
+ *	returned domain SIDs are shared, not strdup'ed
  */
 
 /*
@@ -174,7 +174,7 @@
 idmap_stat
 smb_idmap_batch_create(smb_idmap_batch_t *sib, uint16_t nmap, int flags)
 {
-	ASSERT(sib);
+	ASSERT(sib != NULL);
 
 	bzero(sib, sizeof (smb_idmap_batch_t));
 
@@ -201,11 +201,13 @@
 	char *domsid;
 	int i;
 
-	ASSERT(sib);
-	ASSERT(sib->sib_maps);
+	ASSERT(sib != NULL);
+	ASSERT(sib->sib_maps != NULL);
 
-	if (sib->sib_idmaph)
+	if (sib->sib_idmaph) {
 		kidmap_get_destroy(sib->sib_idmaph);
+		sib->sib_idmaph = NULL;
+	}
 
 	if (sib->sib_flags & SMB_IDMAP_ID2SID) {
 		/*
@@ -226,8 +228,10 @@
 		}
 	}
 
-	if (sib->sib_size && sib->sib_maps)
+	if (sib->sib_size && sib->sib_maps) {
 		kmem_free(sib->sib_maps, sib->sib_size);
+		sib->sib_maps = NULL;
+	}
 }
 
 /*
@@ -249,14 +253,16 @@
 	char strsid[SMB_SID_STRSZ];
 	idmap_stat idm_stat;
 
-	ASSERT(idmaph);
-	ASSERT(sim);
-	ASSERT(sid);
+	ASSERT(idmaph != NULL);
+	ASSERT(sim != NULL);
+	ASSERT(sid != NULL);
 
 	smb_sid_tostr(sid, strsid);
 	if (smb_sid_splitstr(strsid, &sim->sim_rid) != 0)
 		return (IDMAP_ERR_SID);
+	/* Note: Free sim_domsid in smb_idmap_batch_destroy */
 	sim->sim_domsid = smb_mem_strdup(strsid);
+	sim->sim_idtype = idtype;
 
 	switch (idtype) {
 	case SMB_IDMAP_USER:
@@ -290,6 +296,7 @@
  *
  * sim->sim_domsid and sim->sim_rid will contain the mapping
  * result upon successful process of the batched request.
+ * Stash the type for error reporting (caller saves the ID).
  */
 idmap_stat
 smb_idmap_batch_getsid(idmap_get_handle_t *idmaph, smb_idmap_t *sim,
@@ -297,6 +304,7 @@
 {
 	idmap_stat idm_stat;
 
+	sim->sim_idtype = idtype;
 	switch (idtype) {
 	case SMB_IDMAP_USER:
 		idm_stat = kidmap_batch_getsidbyuid(idmaph, id,
@@ -342,6 +350,28 @@
 	return (idm_stat);
 }
 
+static void
+smb_idmap_bgm_report(smb_idmap_batch_t *sib, smb_idmap_t *sim)
+{
+
+	if ((sib->sib_flags & SMB_IDMAP_ID2SID) != 0) {
+		/*
+		 * Note: The ID and type we asked idmap to map
+		 * were saved in *sim_id and sim_idtype.
+		 */
+		uint_t id = (sim->sim_id == NULL) ?
+		    0 : (uint_t)*sim->sim_id;
+		cmn_err(CE_WARN, "Can't get SID for "
+		    "ID=%u type=%d, status=%d",
+		    id, sim->sim_idtype, sim->sim_stat);
+	}
+
+	if ((sib->sib_flags & SMB_IDMAP_SID2ID) != 0) {
+		cmn_err(CE_WARN, "Can't get ID for SID %s-%u, status=%d",
+		    sim->sim_domsid, sim->sim_rid, sim->sim_stat);
+	}
+}
+
 /*
  * smb_idmap_batch_getmappings
  *
@@ -356,6 +386,7 @@
 smb_idmap_batch_getmappings(smb_idmap_batch_t *sib)
 {
 	idmap_stat idm_stat = IDMAP_SUCCESS;
+	smb_idmap_t *sim;
 	int i;
 
 	idm_stat = kidmap_get_mappings(sib->sib_idmaph);
@@ -365,9 +396,13 @@
 	/*
 	 * Check the status for all the queued requests
 	 */
-	for (i = 0; i < sib->sib_nmap; i++) {
-		if (sib->sib_maps[i].sim_stat != IDMAP_SUCCESS)
-			return (sib->sib_maps[i].sim_stat);
+	for (i = 0, sim = sib->sib_maps; i < sib->sib_nmap; i++, sim++) {
+		if (sim->sim_stat != IDMAP_SUCCESS) {
+			smb_idmap_bgm_report(sib, sim);
+			if ((sib->sib_flags & SMB_IDMAP_SKIP_ERRS) == 0) {
+				return (sim->sim_stat);
+			}
+		}
 	}
 
 	if (smb_idmap_batch_binsid(sib) != 0)
@@ -396,7 +431,7 @@
 
 	sim = sib->sib_maps;
 	for (i = 0; i < sib->sib_nmap; sim++, i++) {
-		ASSERT(sim->sim_domsid);
+		ASSERT(sim->sim_domsid != NULL);
 		if (sim->sim_domsid == NULL)
 			return (1);
 
--- a/usr/src/uts/common/smbsrv/smb_idmap.h	Wed May 29 17:34:03 2019 +0000
+++ b/usr/src/uts/common/smbsrv/smb_idmap.h	Tue Jul 10 13:05:19 2018 -0400
@@ -22,7 +22,7 @@
  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  *
- * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
+ * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  */
 
 #ifndef _SMB_IDMAP_H
@@ -59,6 +59,7 @@
 
 #define	SMB_IDMAP_SID2ID	0x0001
 #define	SMB_IDMAP_ID2SID	0x0002
+#define	SMB_IDMAP_SKIP_ERRS	0x0004
 
 /*
  * smb_idmap_t
@@ -79,8 +80,8 @@
 	uint16_t		sib_nmap;
 	uint32_t		sib_flags;
 	uint32_t		sib_size;
-	smb_idmap_t 		*sib_maps;
-	idmap_get_handle_t 	*sib_idmaph;
+	smb_idmap_t		*sib_maps;
+	idmap_get_handle_t	*sib_idmaph;
 } smb_idmap_batch_t;
 
 idmap_stat smb_idmap_getsid(uid_t, int, smb_sid_t **);