allow-home-share-as-usershare   [plain text]


Index: samba/source/utils/net_usershare.c
===================================================================
--- samba/source/utils/net_usershare.c.orig
+++ samba/source/utils/net_usershare.c
@@ -518,6 +518,33 @@ static int count_num_usershares(void)
  Add a single userlevel share.
 ***************************************************************************/
 
+static BOOL usershare_name_is_valid(const char *sharename)
+{
+	struct passwd *pwent;
+	uid_t uid;
+
+	if (!validate_net_name(sharename, INVALID_SHARENAME_CHARS, strlen(sharename))) {
+		d_fprintf(stderr, "net usershare add: share name %s contains "
+                        "invalid characters (any of %s)\n",
+                        sharename, INVALID_SHARENAME_CHARS);
+		return False;
+	}
+
+	/* Disallow shares the same as users unless the share is being added by
+	 * root or by the user themselves.
+	 */
+	uid = getuid();
+	if (uid != 0 &&
+	    (pwent = getpwnam(sharename)) &&
+	    pwent->pw_uid != uid) {
+		d_fprintf(stderr, "net usershare add: share name %s is "
+			"already a valid system user name\n", sharename );
+		return False;
+	}
+
+	return True;
+}
+
 static int net_usershare_add(int argc, const char **argv)
 {
 	TALLOC_CTX *ctx = NULL;
@@ -598,18 +625,7 @@ static int net_usershare_add(int argc, c
 		return -1;
 	}
 
-	if (!validate_net_name(sharename, INVALID_SHARENAME_CHARS, strlen(sharename))) {
-		d_fprintf(stderr, "net usershare add: share name %s contains "
-                        "invalid characters (any of %s)\n",
-                        sharename, INVALID_SHARENAME_CHARS);
-		SAFE_FREE(sharename);
-		return -1;
-	}
-
-	/* Disallow shares the same as users. */
-	if (getpwnam(sharename)) {
-		d_fprintf(stderr, "net usershare add: share name %s is already a valid system user name\n",
-			sharename );
+	if (!usershare_name_is_valid(sharename)) {
 		SAFE_FREE(sharename);
 		return -1;
 	}
Index: samba/source/param/loadparm.c
===================================================================
--- samba/source/param/loadparm.c.orig
+++ samba/source/param/loadparm.c
@@ -4363,8 +4363,11 @@ static void set_allowed_client_auth(void
  get their sorry ass fired.
 ***************************************************************************/
 
-static BOOL check_usershare_stat(const char *fname, SMB_STRUCT_STAT *psbuf)
+static BOOL check_usershare_stat(const char *service_name,
+		const char *fname, SMB_STRUCT_STAT *psbuf)
 {
+	struct passwd *pwent;
+
 	if (!S_ISREG(psbuf->st_mode)) {
 		DEBUG(0,("check_usershare_stat: file %s owned by uid %u is "
 			"not a regular file\n",
@@ -4389,6 +4392,22 @@ static BOOL check_usershare_stat(const c
 		return False;
 	}
 
+	/* Only root and the user themselves are allowed to create a user share
+	 * named after a user. This prevents users clobbering each others'
+	 * auto-home shares.
+	 *
+	 * NOTE: this check will not be 100% because getpwnam is case-sensitive
+	 * on some systems.
+	 */
+	if ((pwent = sys_getpwnam(service_name))) {
+		if (psbuf->st_uid != 0 && psbuf->st_uid != pwent->pw_uid) {
+			DEBUG(0, ("check_usershare_stat: file %s is a home "
+			    "share for %s, but is owned by uid %u.\n",
+			    fname, service_name, (unsigned int)psbuf->st_uid));
+			return False;
+		}
+	}
+
 	return True;
 }
 
@@ -4599,15 +4618,17 @@ static int process_usershare_file(const 
 		return -1;
 	}
 
+	canonicalize_servicename(service_name);
+
 	/* This must be a regular file, not a symlink, directory or
 	   other strange filetype. */
-	if (!check_usershare_stat(fname, &lsbuf)) {
+	if (!check_usershare_stat(service_name, fname, &lsbuf)) {
 		return -1;
 	}
 
 	/* See if there is already a servicenum for this name. */
 	/* tdb_fetch_int32 returns -1 if not found. */
-	iService = (int)tdb_fetch_int32(ServiceHash, canonicalize_servicename(service_name) );
+	iService = (int)tdb_fetch_int32(ServiceHash, service_name);
 
 	if (iService != -1 && ServicePtrs[iService]->usershare_last_mod == lsbuf.st_mtime) {
 		/* Nothing changed - Mark valid and return. */
@@ -4648,7 +4669,7 @@ static int process_usershare_file(const 
 
 	/* This must be a regular file, not a symlink, directory or
 	   other strange filetype. */
-	if (!check_usershare_stat(fname, &sbuf)) {
+	if (!check_usershare_stat(service_name, fname, &sbuf)) {
 		return -1;
 	}
 
Index: samba/source/smbd/service.c
===================================================================
--- samba/source/smbd/service.c.orig
+++ samba/source/smbd/service.c
@@ -269,6 +269,15 @@ int find_service(fstring service)
 
 	iService = lp_servicenumber(service);
 
+	/* Is it a usershare service ? Usershares are statically configured
+	 * services, so they get priority over any implicitly created services.
+	 */
+	if (iService < 0 && *lp_usershare_path()) {
+		/* Ensure the name is canonicalized. */
+		strlower_m(service);
+		iService = load_usershare_service(service);
+	}
+
 	/* now handle the special case of a home directory */
 	if (iService < 0) {
 		char *phome_dir = get_user_home_dir(service);
@@ -312,13 +321,6 @@ int find_service(fstring service)
 	if (iService < 0) {
 	}
 
-	/* Is it a usershare service ? */
-	if (iService < 0 && *lp_usershare_path()) {
-		/* Ensure the name is canonicalized. */
-		strlower_m(service);
-		iService = load_usershare_service(service);
-	}
-
 	/* just possibly it's a default service? */
 	if (iService < 0) {
 		char *pdefservice = lp_defaultservice();