Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 13 Apr 2009 20:39:17 -0400
From:      "Mikhail T." <mi+thun@aldan.algebra.com>
To:        Maksim Yevmenkin <maksim.yevmenkin@gmail.com>
Cc:        "freebsd-bluetooth@freebsd.org" <freebsd-bluetooth@freebsd.org>
Subject:   Re: RFC: obexapp - virtual root folder for each device
Message-ID:  <49E3DB35.4030601@aldan.algebra.com>
In-Reply-To: <bb4a86c70904131640n7cf471c0o7a56a43d722a90e1@mail.gmail.com>
References:  <bb4a86c70904131640n7cf471c0o7a56a43d722a90e1@mail.gmail.com>

next in thread | previous in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.
--------------000404000405070103000206
Content-Type: text/plain; charset=KOI8-R
Content-Transfer-Encoding: 8bit

Maksim Yevmenkin ΞΑΠΙΣΑΧ(ΜΑ):
> possible setup
>
> - create 'obex' user and 'obex' group
> - create '/var/spool/obex' (or whatever you want for default root)
> owned by 'obex' user/group
> - user 'foo' creates ~/private directory under his home directory with
> 0700 permissions
> - admin setups 'obex' directory under foo's ~/private/ directory with
> 0770 permissions, this directory is owned by 'obex' user. group is set
> to foo's group
> - admin setups symlink in /var/spool/obex/ called 'foo_cell' that
> points to ~foo/private/obex
> - admin adds entry in the /etc/bluetooth/hosts file to assign
> 'foo_cell' foo's cell phone bd_addr
> - admin run obexapp server as 'obexapp -s -r /var/spool/obex -R -u obex -C 1'
>
> every time foo's uses cell phone to send data to the obex server, the
> data will end up in foo's ~/private/obex directory.
>
> please give it a try and let me know it works.
>   
I think, Maksim's proposal is suboptimal, because the uploaded files end
up owned by the new user obex, rather than the actual user (foo in the
above example), which will make file-manipulations on the system itself
more difficult (obex-owned will they not have 600 permissions?). It also
necessitates creation of a new UID without the security benefit of
having the daemon run under that UID permanently (but only switching
after accepting each connection)...

My proposal -- discussed with Maksim at length -- would *derive the
user-ID from the ownership of the link*. The sample set up would then be
as follows. Suppose, user named wallaby has a device with BD_ADDR
01:02:03:04:05:06. The user would create a subdirectory for their
bluetooth files (or use something existing, like ~/Desktop/):

    wallaby@tasmania (11) mkdir ~/bluetooth

root will then -- on wallaby's request -- tell obexapp about it:

    root@tasmania (111) ln -s ~wallaby/bluetooth
    /var/spool/obex/01:02:03:04:05:06
    root@tasmania (112) chown -h wallaby ~wallaby/bluetooth
    /var/spool/obex/01:02:03:04:05:06

The second of the above root's lines is what will -- under my proposal
-- tell obexapp-daemon, who shall own any files uploaded by the device.
If started as root, instead of becoming 'obex', obexapp will become
'wallaby'...

Upon accepting a connection, the server will do the same lookups as
Maksim's version is doing, cd/chroot into the subdirectory, and setuid
to the proper UID (such as wallaby's in this example).

The attached patch can be dropped into /usr/ports/comms/obexapp/files/ .
The only functionality still missing from it compared to Maksim's is the
bt_gethostbyaddr(3) lookup -- only the numeric BD_ADDR is currently
considered. This is not a significant difference between proposals,
though...

My proposal has other, not so significant differences -- it allows the
BD_ADDR-entries in /var/spool/obex to be non-directories (files, broken
links a'la /etc/make.conf, even sockets). Even if a chdir into such an
entry fails, the ID of the entry's owner will still be used to
determine, which user shall own any uploaded files, etc. even though all
such files will end up in the same directory (as they do with the
current version of obexapp).

Maksim thought, offering such flexibility would be too confusing...

I agree, that chroot-ing (rather than merely chdir-ing) into such a
"virtual root" directory makes sense. The only material difference
between our proposals is my deriving the desired UID from the ownership
of the found BD_ADDR entry vs. Maksim's always using the user specified
on command-line (such as 'obex').

Yours,

    -mi


--------------000404000405070103000206
Content-Type: text/plain;
 name="patch-uid"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="patch-uid"

--- obexapp.1	2007-05-21 11:55:35.000000000 -0400
+++ obexapp.1	2009-04-09 22:15:22.000000000 -0400
@@ -217,4 +217,30 @@
 This only works if server was started as root.
 .El
+.Sh Per-user configurations
+When accepting connections in server mode, 
+.Nm
+will check, if there is an entry named after the connecting device's
+BD_ADDR in the root-path (default or specified by the
+.Fl r
+option). If found, the entry will be used as follows:
+.Bl -enum -offset indent -compact
+.It
+The group ID will be changed to that, which owns the entry.
+.It
+If
+.Nm
+is running as root, it will change to the user, that owns the entry.
+.It
+If the entry is itself a directory and chdir into it succeeds, it will
+be used as the top-level.
+.El
+This allows the same system to intelligently distinguish different Bluetooth devices 
+as belonging to different users. An administrator can set up the subdirectories for
+known devices under
+.Pa /var/spool/obex
+(or wherever, see
+.Fl r
+option) for each user, or even as symlinks to each user's home directory
+(or a subdirectory thereof).
 .Sh LOCALE SUPPORT
 The
@@ -326,4 +352,11 @@
 address and RFCOMM channel
 .Li 1 .
+.It ln -s Ar /home/wallaby Ar /var/spool/obex/00:01:02:03:04:05
+.It chown -h wallaby Ar /var/spool/obex/00:01:02:03:04:05
+Whenever the device with BD_ADDR of 00:01:02:03:04:05 connects,
+.Nm
+running in server mode will switch to user ID
+.Ar wallaby
+and use their home directory as the top-level for the connection. 
 .El
 .Ss Level 1 Information Access
--- transport.c	2007-05-21 11:55:35.000000000 -0400
+++ transport.c	2009-04-09 20:53:27.000000000 -0400
@@ -271,4 +272,7 @@
 				addr.rfcomm_channel, getpid());
 
+			memcpy(&context->raddr, &addr.rfcomm_bdaddr,
+                                        sizeof(context->raddr));
+
 			if (daemon(1, 0) < 0) {
 				log_err("%s(): Could not daemon. %s (%d)",
--- work/obexapp/server.c	2009-04-10 12:29:53.000000000 -0400
+++ work/obexapp/server.c	2009-04-13 20:33:16.000000000 -0400
@@ -110,5 +110,4 @@
  * OBEX server
  */
-
 int
 obexapp_server(obex_t *handle)
@@ -118,4 +117,8 @@
 	int			 error = -1;
 	struct sockaddr_rfcomm	 addr;
+	struct stat	 	 sb;
+	const char		*subdir = bt_ntoa(&context->raddr, NULL);
+	uid_t			 uid = 0;
+	gid_t			 gid = getgid();
 
 	context->ss = sdp_open_local(NULL);
@@ -143,4 +146,6 @@
 			goto done;
 		}
+		uid = pw->pw_uid;
+		gid = pw->pw_gid;
 	}
 
@@ -171,4 +176,36 @@
 	}
 
+	if (chdir(context->root) < 0) {
+		log_err("%s(): Could not chdir(%s). %s (%d)",
+			__func__, context->root, strerror(errno), errno);
+		goto done;
+	}
+
+	log_debug("%s(): checking for %s/%s subdirectory", __func__,
+	    context->root, subdir);
+	if (lstat(subdir, &sb) == 0) {
+		log_debug("%s(): %s/%s exists and belongs to uid %d",
+		    __func__, context->root, subdir, sb.st_uid);
+		uid = sb.st_uid;
+		gid = sb.st_gid;
+		if (chdir(subdir))
+			log_debug("%s(): chdir to %s failed: %s. Will remain "
+			    "on top (uid %ld).", __func__, subdir, strerror(errno),
+			    (long)uid);
+		else
+			getwd(context->root);
+		
+		log_debug("%s(): using %s", __func__, context->root);
+	} else switch (errno) {
+	case ENOENT:
+		log_debug("%s(): %s/%s not found", __func__,
+		    context->root, subdir);
+		break;
+	default:
+		log_err("%s(): %s/%s: %s", __func__, context->root, subdir,
+		    strerror(errno));
+		goto done;
+	}
+
 	if (getuid() == 0) {
 		if (context->secure) {
@@ -183,25 +220,19 @@
 		}
 
-		if (pw != NULL) {
-			if (setgid(pw->pw_gid) < 0) {
-				log_err("%s(): Could not setgid(%d). %s (%d)",
-					__func__, pw->pw_gid, strerror(errno),
-					errno);
-				goto done;
-			}
-
-			if (setuid(pw->pw_uid) < 0) {
+		if (uid) {
+			if (setuid(uid) < 0) {
 				log_err("%s(): Could not setuid(%d). %s (%d)",
-					__func__, pw->pw_uid, strerror(errno),
+					__func__, uid, strerror(errno),
 					errno);
 				goto done;
 			}
 		}
-	}
 
-	if (chdir(context->root) < 0) {
-		log_err("%s(): Could not chdir(%s). %s (%d)",
-			__func__, context->root, strerror(errno), errno);
-		goto done;
+		if (gid != getgid() && setgid(gid) < 0) {
+			log_err("%s(): Could not setgid(%d). %s (%d)",
+				__func__, gid, strerror(errno),
+				errno);
+			goto done;
+		}
 	}
 

--------------000404000405070103000206--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?49E3DB35.4030601>