From 1de4ef8bc17bbba02ccbf334f83154c3ed061fc5 Mon Sep 17 00:00:00 2001 From: Justin Maggard Date: Wed, 18 Jul 2012 18:58:26 +0000 Subject: [PATCH] * Add configuration option to specify the user to run as. --- NEWS | 15 ++++++- daemonize.c | 35 ---------------- daemonize.h | 5 --- minidlna.c | 105 +++++++++++++++++++++++++++++++++++++++++++++-- minidlna.conf | 3 ++ minissdp.c | 7 +--- minissdp.h | 16 -------- options.c | 3 +- options.h | 3 +- upnpglobalvars.c | 2 +- 10 files changed, 125 insertions(+), 69 deletions(-) diff --git a/NEWS b/NEWS index 45ae6d4..59de635 100644 --- a/NEWS +++ b/NEWS @@ -1,7 +1,20 @@ 1.1.0 - Released 00-Month-0000 -------------------------------- - Add support for other operating systems. -- Switch to autoconf from our little genconfig.sh. +- Switch to autoconf from our handcrafted genconfig.sh. +- Add configuration option for UUID. +- Add configuration option to specify the user to run as. + +1.0.25 - Released 13-July-2012 +-------------------------------- +- Fix a couple crash bugs on malformed WAV files. +- Forcibly tweak the model number for Xbox360 clients, or they might ignore us. +- Enable all network interfaces by default if none were specified. +- Add flag to force downscaled thumbnails rather than using embedded ones. +- Add DirecTV client detection, and fix image resolution issue. +- Add support for the latest ffmpeg/libav library versions. +- Fix a potential crash on requests for a resize of a non-existent image. +- Make DeviceID checking more permissive for Sagem Radio. 1.0.24 - Released 14-Feb-2012 -------------------------------- diff --git a/daemonize.c b/daemonize.c index 7873d32..1fddf80 100644 --- a/daemonize.c +++ b/daemonize.c @@ -86,41 +86,6 @@ daemonize(void) return pid; } -int -writepidfile(const char * fname, int pid) -{ - char pidstring[16]; - int pidstringlen; - int pidfile; - - if(!fname || *fname == '\0') - return -1; - - if( (pidfile = open(fname, O_WRONLY|O_CREAT, 0644)) < 0) - { - DPRINTF(E_ERROR, L_GENERAL, "Unable to open pidfile for writing %s: %s\n", fname, strerror(errno)); - return -1; - } - - pidstringlen = snprintf(pidstring, sizeof(pidstring), "%d\n", pid); - if(pidstringlen <= 0) - { - DPRINTF(E_ERROR, L_GENERAL, - "Unable to write to pidfile %s: snprintf(): FAILED\n", fname); - close(pidfile); - return -1; - } - else - { - if(write(pidfile, pidstring, pidstringlen) < 0) - DPRINTF(E_ERROR, L_GENERAL, "Unable to write to pidfile %s: %s\n", fname, strerror(errno)); - } - - close(pidfile); - - return 0; -} - int checkforrunning(const char * fname) { diff --git a/daemonize.h b/daemonize.h index 7a05d6c..ec8732a 100644 --- a/daemonize.h +++ b/daemonize.h @@ -37,11 +37,6 @@ int daemonize(void); -/* writepidfile() - * write the pid to a file */ -int -writepidfile(const char * fname, int pid); - /* checkforrunning() * check for another instance running * returns: 0 only instance diff --git a/minidlna.c b/minidlna.c index 255e5cf..01c8231 100644 --- a/minidlna.c +++ b/minidlna.c @@ -65,6 +65,7 @@ #include #include #include +#include #include #include "config.h" @@ -409,6 +410,71 @@ check_db(sqlite3 *db, int new_db, pid_t *scanner_pid) } } +static int +writepidfile(const char *fname, int pid, uid_t uid) +{ + FILE *pidfile; + struct stat st; + char path[PATH_MAX], *dir; + int ret = 0; + + if(!fname || *fname == '\0') + return -1; + + /* Create parent directory if it doesn't already exist */ + strncpyt(path, fname, sizeof(path)); + dir = dirname(path); + if (stat(dir, &st) == 0) + { + if (!S_ISDIR(st.st_mode)) + { + DPRINTF(E_ERROR, L_GENERAL, "Pidfile path is not a directory: %s\n", + fname); + return -1; + } + } + else + { + if (make_dir(dir, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) != 0) + { + DPRINTF(E_ERROR, L_GENERAL, "Unable to create pidfile directory: %s\n", + fname); + return -1; + } + if (uid >= 0) + { + if (chown(dir, uid, -1) != 0) + DPRINTF(E_WARN, L_GENERAL, "Unable to change pidfile ownership: %s\n", + dir, strerror(errno)); + } + } + + pidfile = fopen(fname, "w"); + if (!pidfile) + { + DPRINTF(E_ERROR, L_GENERAL, "Unable to open pidfile for writing %s: %s\n", + fname, strerror(errno)); + return -1; + } + + if (fprintf(pidfile, "%d\n", pid) <= 0) + { + DPRINTF(E_ERROR, L_GENERAL, + "Unable to write to pidfile %s: %s\n", fname); + ret = -1; + } + if (uid >= 0) + { + if (fchown(fileno(pidfile), uid, -1) != 0) + DPRINTF(E_WARN, L_GENERAL, "Unable to change pidfile ownership: %s\n", + pidfile, strerror(errno)); + } + + fclose(pidfile); + + return ret; +} + /* init phase : * 1) read configuration file * 2) read command line arguments @@ -429,13 +495,14 @@ init(int argc, char * * argv) const char * presurl = NULL; const char * optionsfile = "/etc/minidlna.conf"; char mac_str[13]; - char * string, * word; + char *string, *word; enum media_types type; - char * path; + char *path; char buf[PATH_MAX]; char ip_addr[INET_ADDRSTRLEN + 3] = {'\0'}; char log_str[75] = "general,artwork,database,inotify,scanner,metadata,http,ssdp,tivo=warn"; char *log_level = NULL; + uid_t uid = -1; /* first check if "-f" option is used */ for(i=2; ipw_uid; + } + break; default: DPRINTF(E_ERROR, L_GENERAL, "Unknown option in file %s\n", optionsfile); @@ -828,6 +905,21 @@ init(int argc, char * * argv) if( system(buf) != 0 ) DPRINTF(E_FATAL, L_GENERAL, "Failed to clean old file cache. EXITING\n"); break; + case 'u': + if(i+1 == argc) + DPRINTF(E_FATAL, L_GENERAL, "Option -%c takes one argument.\n", argv[i][1]); + else { + i++; + uid = strtol(argv[i], &string, 0); + if (*string) { + /* Symbolic username given, not UID. */ + struct passwd *entry = getpwnam(argv[i]); + if (!entry) + DPRINTF(E_FATAL, L_GENERAL, "Bad user '%s'.\n", argv[i]); + uid = entry->pw_uid; + } + } + break; case 'V': printf("Version " MINIDLNA_VERSION "\n"); exit(0); @@ -859,6 +951,7 @@ init(int argc, char * * argv) /*"[-l logfile] " not functionnal */ "\t\t[-s serial] [-m model_number] \n" "\t\t[-t notify_interval] [-P pid_filename]\n" + "\t\t[-u uid_to_run_as]\n" "\t\t[-w url] [-R] [-V] [-h]\n" "\nNotes:\n\tNotify interval is in seconds. Default is 895 seconds.\n" "\tDefault pid file is %s.\n" @@ -926,9 +1019,13 @@ init(int argc, char * * argv) if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) DPRINTF(E_FATAL, L_GENERAL, "Failed to set %s handler. EXITING.\n", SIGPIPE); - if (writepidfile(pidfilename, pid) != 0) + if (writepidfile(pidfilename, pid, uid) != 0) pidfilename = NULL; + if (uid != -1 && setuid(uid) == -1) + DPRINTF(E_FATAL, L_GENERAL, "Failed to switch to uid '%d'. [%s] EXITING.\n", + uid, strerror(errno)); + return 0; } @@ -1000,7 +1097,7 @@ main(int argc, char * * argv) } } #endif - sudp = OpenAndConfSSDPReceiveSocket(n_lan_addr, lan_addr); + sudp = OpenAndConfSSDPReceiveSocket(); if(sudp < 0) { DPRINTF(E_INFO, L_GENERAL, "Failed to open socket for receiving SSDP. Trying to use MiniSSDPd\n"); diff --git a/minidlna.conf b/minidlna.conf index 798d303..089f421 100644 --- a/minidlna.conf +++ b/minidlna.conf @@ -4,6 +4,9 @@ port=8200 # network interfaces to serve, comma delimited #network_interface=eth0 +# specify the user account name or uid to run as +#user=jmaggard + # set this to the directory you want scanned. # * if have multiple directories, you can have multiple media_dir= lines # * if you want to restrict a media_dir to a specific content type, you diff --git a/minissdp.c b/minissdp.c index e923667..0ccccc8 100644 --- a/minissdp.c +++ b/minissdp.c @@ -63,8 +63,7 @@ AddMulticastMembership(int s, in_addr_t ifaddr) /* setting up imr structure */ imr.imr_multiaddr.s_addr = inet_addr(SSDP_MCAST_ADDR); - /*imr.imr_interface.s_addr = htonl(INADDR_ANY);*/ - imr.imr_interface.s_addr = ifaddr; /*inet_addr(ifaddr);*/ + imr.imr_interface.s_addr = ifaddr; if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (void *)&imr, sizeof(struct ip_mreq)) < 0) { @@ -78,7 +77,7 @@ AddMulticastMembership(int s, in_addr_t ifaddr) /* Open and configure the socket listening for * SSDP udp packets sent on 239.255.255.250 port 1900 */ int -OpenAndConfSSDPReceiveSocket() +OpenAndConfSSDPReceiveSocket(void) { int s; int i = 1; @@ -99,9 +98,7 @@ OpenAndConfSSDPReceiveSocket() sockname.sin_family = AF_INET; sockname.sin_port = htons(SSDP_PORT); /* NOTE : it seems it doesnt work when binding on the specific address */ - /*sockname.sin_addr.s_addr = inet_addr(UPNP_MCAST_ADDR);*/ sockname.sin_addr.s_addr = htonl(INADDR_ANY); - /*sockname.sin_addr.s_addr = inet_addr(ifaddr);*/ if(bind(s, (struct sockaddr *)&sockname, sizeof(struct sockaddr_in)) < 0) { diff --git a/minissdp.h b/minissdp.h index bcc7ff4..38f67dc 100644 --- a/minissdp.h +++ b/minissdp.h @@ -29,35 +29,19 @@ #ifndef __MINISSDP_H__ #define __MINISSDP_H__ -/*#include "minidlnatypes.h"*/ - int OpenAndConfSSDPReceiveSocket(); -/* OpenAndConfSSDPReceiveSocket(int n_lan_addr, struct lan_addr_s * lan_addr);*/ - -/*int -OpenAndConfSSDPNotifySocket(const char * addr);*/ int OpenAndConfSSDPNotifySockets(int * sockets); -/*OpenAndConfSSDPNotifySockets(int * sockets, - struct lan_addr_s * lan_addr, int n_lan_addr);*/ -/*void -SendSSDPNotifies(int s, const char * host, unsigned short port, - unsigned int lifetime);*/ void SendSSDPNotifies2(int * sockets, unsigned short port, unsigned int lifetime); -/*SendSSDPNotifies2(int * sockets, struct lan_addr_s * lan_addr, int n_lan_addr, - unsigned short port, - unsigned int lifetime);*/ void ProcessSSDPRequest(int s, unsigned short port); -/*ProcessSSDPRequest(int s, struct lan_addr_s * lan_addr, int n_lan_addr, - unsigned short port);*/ int SendSSDPGoodbye(int * sockets, int n); diff --git a/options.c b/options.c index 894095d..ac96c29 100644 --- a/options.c +++ b/options.c @@ -61,7 +61,8 @@ static const struct { { UPNPMINISSDPDSOCKET, "minissdpdsocket"}, { ENABLE_TIVO, "enable_tivo" }, { ENABLE_DLNA_STRICT, "strict_dlna" }, - { ROOT_CONTAINER, "root_container" } + { ROOT_CONTAINER, "root_container" }, + { USER_ACCOUNT, "user" } }; int diff --git a/options.h b/options.h index 29f6cae..609b5db 100644 --- a/options.h +++ b/options.h @@ -54,7 +54,8 @@ enum upnpconfigoptions { UPNPMINISSDPDSOCKET, /* minissdpdsocket */ ENABLE_TIVO, /* enable support for streaming images and music to TiVo */ ENABLE_DLNA_STRICT, /* strictly adhere to DLNA specs */ - ROOT_CONTAINER /* root ObjectID (instead of "0") */ + ROOT_CONTAINER, /* root ObjectID (instead of "0") */ + USER_ACCOUNT /* user account to run as */ }; /* readoptionsfile() diff --git a/upnpglobalvars.c b/upnpglobalvars.c index bd7bcfc..3d40700 100644 --- a/upnpglobalvars.c +++ b/upnpglobalvars.c @@ -62,7 +62,7 @@ time_t startup_time = 0; struct runtime_vars_s runtime_vars; uint32_t runtime_flags = INOTIFY_MASK; -const char * pidfilename = "/var/run/minidlna.pid"; +const char * pidfilename = "/var/run/minidlna/minidlna.pid"; char uuidvalue[] = "uuid:00000000-0000-0000-0000-000000000000"; char modelname[MODELNAME_MAX_LEN] = ROOTDEV_MODELNAME;