Page 1 of 1

How to authenticate client using libmpdclient?

Posted: February 13th, 2021, 7:06 am
by wangledorf
Hello! I'm writing a simple TUI mpd client as a side project and I'm running into a problem I'm not sure how to solve. (I know there are a bunch of existing TUI clients but this is just for fun/learning purposes).

I would like to be able to add a song to the playlist that resides outside of the configured music_directory.

The problem I'm running into is that when I call mpd_run_add(conn, "/path/to/song.mp3"), I see an "Access denied" error.

I dug into why this error occurs in the MPD codebase. In handle_add(), the function that processes the add command, one of the first things we do is locate the URI of the file. As part of locating the URI, if we determine the file is not relative to the MPD database, we ensure that the client is authenticated by checking the UID (In Client::AllowFile()):

Code: Select all

if (uid < 0)
    /* unauthenticated client */
    throw ProtocolError(ACK_ERROR_PERMISSION, "Access denied");
There are a couple other cases that cause "Access denied" but I've run this through GDB to ensure this is the one I'm hitting.

So I continued digging into how the uid field gets set and it comes from the file descriptor of the socket MPD is using to communicate with the client. From ServerSocket.cxx:

Code: Select all

static int
get_remote_uid(int fd)
	struct ucred cred;
	socklen_t len = sizeof (cred);

	if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len) < 0)
		return -1;

	return cred.uid;
When this runs, cred.uid is -1 which is why I'm seeing the error.

I think I've read through all of the relevant docs for libmpdclient and I've looked through code as well but I'm struggling to understand how to get it to set up the file descriptor such that the MPD server gets the correct UID from it. Does anyone know what I might be doing wrong or misunderstanding? I'm connecting via mpd_connection_new("", 6600, 0);

Re: How to authenticate client using libmpdclient?

Posted: February 13th, 2021, 3:40 pm
by max
You need to connect via local socket.
If you develop a client, never hard-code "" and 6600. Just pass NULL and 0. This way, libmpdclient uses proper defaults and users can override them by setting the environment variables MPD_HOST and MPD_PORT.

Re: How to authenticate client using libmpdclient?

Posted: February 13th, 2021, 5:02 pm
by wangledorf
Thanks, that works! And I appreciate the explanation; that makes perfect sense.

I changed my mpd config to remove bind_to_address "" so that it will automatically bind to $XDG_RUNTIME_DIR/mpd/socket.

Then I updated the client to connect via mpd_connection_new(NULL, 0, 0) and set MPD_HOST="$XDG_RUNTIME_DIR/mpd/socket" and now the socket is a unix domain socket and has the uid. :)