merge new-rend-branch

This commit is contained in:
Ron Pedde 2004-01-20 04:41:20 +00:00
parent 41021a3a94
commit 10f7ca1790
12 changed files with 669 additions and 164 deletions

View File

@ -29,7 +29,7 @@ endif
mt_daapd_SOURCES = main.c daapd.h rend.h uici.c uici.h webserver.c \ mt_daapd_SOURCES = main.c daapd.h rend.h uici.c uici.h webserver.c \
webserver.h configfile.c configfile.h err.c err.h restart.c restart.h \ webserver.h configfile.c configfile.h err.c err.h restart.c restart.h \
daap-proto.c daap-proto.h daap.c daap.h db-memory.c db-memory.h \ daap-proto.c daap-proto.h daap.c daap.h db-memory.c db-memory.h \
mp3-scanner.h mp3-scanner.c playlist.c playlist.h \ mp3-scanner.h mp3-scanner.c playlist.c playlist.h rend-unix.c rend-unix.h \
lexer.l parser.y $(RENDSRC) $(STRCASESTR) $(STRSEP) lexer.l parser.y $(RENDSRC) $(STRCASESTR) $(STRSEP)
EXTRA_DIST = mdns/mDNS.c mdns/mDNSClientAPI.h mdns/mDNSDebug.h mdns/mDNSPosix.c \ EXTRA_DIST = mdns/mDNS.c mdns/mDNSClientAPI.h mdns/mDNSDebug.h mdns/mDNSPosix.c \

View File

@ -32,6 +32,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/wait.h> #include <sys/wait.h>
@ -51,7 +52,9 @@ void config_emit_ispage(WS_CONNINFO *pwsc, void *value, char *arg);
void config_emit_session_count(WS_CONNINFO *pwsc, void *value, char *arg); void config_emit_session_count(WS_CONNINFO *pwsc, void *value, char *arg);
void config_emit_service_status(WS_CONNINFO *pwsc, void *value, char *arg); void config_emit_service_status(WS_CONNINFO *pwsc, void *value, char *arg);
void config_emit_user(WS_CONNINFO *pwsc, void *value, char *arg); void config_emit_user(WS_CONNINFO *pwsc, void *value, char *arg);
void config_emit_readonly(WS_CONNINFO *pwsc, void *value, char *arg);
void config_subst_stream(WS_CONNINFO *pwsc, int fd_src); void config_subst_stream(WS_CONNINFO *pwsc, int fd_src);
int config_file_is_readonly(void);
int config_mutex_lock(void); int config_mutex_lock(void);
int config_mutex_unlock(void); int config_mutex_unlock(void);
@ -89,6 +92,7 @@ CONFIGELEMENT config_elements[] = {
{ 0,0,0,CONFIG_TYPE_SPECIAL,"session-count",(void*)NULL,config_emit_session_count }, { 0,0,0,CONFIG_TYPE_SPECIAL,"session-count",(void*)NULL,config_emit_session_count },
{ 0,0,0,CONFIG_TYPE_SPECIAL,"service-status",(void*)NULL,config_emit_service_status }, { 0,0,0,CONFIG_TYPE_SPECIAL,"service-status",(void*)NULL,config_emit_service_status },
{ 0,0,0,CONFIG_TYPE_SPECIAL,"user",(void*)NULL,config_emit_user }, { 0,0,0,CONFIG_TYPE_SPECIAL,"user",(void*)NULL,config_emit_user },
{ 0,0,0,CONFIG_TYPE_SPECIAL,"readonly",(void*)NULL,config_emit_readonly },
{ -1,1,0,CONFIG_TYPE_STRING,NULL,NULL,NULL } { -1,1,0,CONFIG_TYPE_STRING,NULL,NULL,NULL }
}; };
@ -240,7 +244,7 @@ void config_close(void) {
pce=config_elements; pce=config_elements;
err=0; err=0;
while((pce->config_element != -1)) { while((pce->config_element != -1)) {
if((pce->config_element) && (pce->type == CONFIG_TYPE_STRING)) if((pce->config_element) && (pce->type == CONFIG_TYPE_STRING) && (*((char**)pce->var)))
free(*((char**)pce->var)); free(*((char**)pce->var));
pce++; pce++;
} }
@ -250,7 +254,32 @@ void config_close(void) {
* config_write * config_write
* *
*/ */
int config_write(CONFIG *pconfig) { int config_write(WS_CONNINFO *pwsc) {
FILE *configfile;
char ctime_buf[27];
time_t now;
configfile=fopen(config.configfile,"w");
if(!configfile)
return -1;
now=time(NULL);
ctime_r(&now,ctime_buf);
fprintf(configfile,"#\n# mt-daapd.conf\n#\n");
fprintf(configfile,"# Edited: %s",ctime_buf);
fprintf(configfile,"# By: %s\n",ws_getvar(pwsc,"HTTP_USER"));
fprintf(configfile,"#\n");
fprintf(configfile,"web_root\t%s\n",ws_getvar(pwsc,"web_root"));
fprintf(configfile,"port\t\t%s\n",ws_getvar(pwsc,"port"));
fprintf(configfile,"admin_pw\t%s\n",ws_getvar(pwsc,"admin_pw"));
fprintf(configfile,"mp3_dir\t\t%s\n",ws_getvar(pwsc,"mp3_dir"));
fprintf(configfile,"servername\t%s\n",ws_getvar(pwsc,"servername"));
fprintf(configfile,"runas\t\t%s\n",ws_getvar(pwsc,"runas"));
fprintf(configfile,"playlist\t%s\n",ws_getvar(pwsc,"playlist"));
fprintf(configfile,"password\t%s\n",ws_getvar(pwsc,"password"));
fclose(configfile);
return 0; return 0;
} }
@ -377,22 +406,30 @@ void config_handler(WS_CONNINFO *pwsc) {
if(strcasecmp(pwsc->uri,"/config-update.html")==0) { if(strcasecmp(pwsc->uri,"/config-update.html")==0) {
/* we need to update stuff */ /* we need to update stuff */
pw=ws_getvar(pwsc,"adminpw"); pw=ws_getvar(pwsc,"admin_pw");
if(pw) { if(pw) {
if(config.adminpassword) if(config.adminpassword)
free(config.adminpassword); free(config.adminpassword);
config.adminpassword=strdup(pw); config.adminpassword=strdup(pw);
} }
pw=ws_getvar(pwsc,"password");
if(pw) {
if(config.readpassword)
free(config.readpassword);
config.readpassword=strdup(pw);
}
if(!config_file_is_readonly()) {
DPRINTF(ERR_INFO,"Updating config file\n");
config_write(pwsc);
}
pw=ws_getvar(pwsc,"action"); pw=ws_getvar(pwsc,"action");
if(pw) { if(pw) {
if(strcasecmp(pw,"stopmdns")==0) { /* ignore stopmdns and startmdns */
DPRINTF(ERR_INFO,"Stopping rendezvous daemon\n"); if (strcasecmp(pw,"stopdaap")==0) {
kill(config.rend_pid,SIGINT);
wait(&status);
} else if (strcasecmp(pw,"startmdns")==0) {
rend_init(&config.rend_pid,config.servername, config.port);
} else if (strcasecmp(pw,"stopdaap")==0) {
config.stop=1; config.stop=1;
} }
} }
@ -426,7 +463,8 @@ int config_auth(char *user, char *password) {
* write a simple string value to the connection * write a simple string value to the connection
*/ */
void config_emit_string(WS_CONNINFO *pwsc, void *value, char *arg) { void config_emit_string(WS_CONNINFO *pwsc, void *value, char *arg) {
ws_writefd(pwsc,"%s",*((char**)value)); if(*((char**)value))
ws_writefd(pwsc,"%s",*((char**)value));
} }
/* /*
@ -464,10 +502,8 @@ void config_emit_service_status(WS_CONNINFO *pwsc, void *value, char *arg) {
ws_writefd(pwsc,"<TR><TD>Rendezvous</TD>"); ws_writefd(pwsc,"<TR><TD>Rendezvous</TD>");
if(config.use_mdns) { if(config.use_mdns) {
mdns_running=1; mdns_running=!rend_running();
err=waitpid(config.rend_pid,&status,WNOHANG);
if(err == -1)
mdns_running=0;
if(mdns_running) { if(mdns_running) {
html="<a href=\"config-update.html?action=stopmdns\">Stop MDNS responder</a>"; html="<a href=\"config-update.html?action=stopmdns\">Stop MDNS responder</a>";
} else { } else {
@ -622,6 +658,33 @@ void config_emit_user(WS_CONNINFO *pwsc, void *value, char *arg) {
return; return;
} }
/*
* config_file_is_readonly
*
* See if the configfile is writable or not
*/
int config_file_is_readonly(void) {
FILE *fin;
fin=fopen(config.configfile,"r+");
if(!fin) {
return 1;
}
fclose(fin);
return 0;
}
/*
* config_emit_readonly
*
*/
void config_emit_readonly(WS_CONNINFO *pwsc, void *value, char *arg) {
if(config_file_is_readonly()) {
ws_writefd(pwsc,"READONLY");
}
}
/* /*
* config_emit_include * config_emit_include
* *

View File

@ -26,7 +26,7 @@
#include "webserver.h" #include "webserver.h"
extern int config_read(char *file); extern int config_read(char *file);
extern int config_write(CONFIG *pconfig); extern int config_write(WS_CONNINFO *pwsc);
extern int config_auth(char *user, char *password); extern int config_auth(char *user, char *password);
extern void config_handler(WS_CONNINFO *pwsc); extern void config_handler(WS_CONNINFO *pwsc);
extern void config_set_status(WS_CONNINFO *pwsc, int session, char *fmt, ...); extern void config_set_status(WS_CONNINFO *pwsc, int session, char *fmt, ...);

View File

@ -30,7 +30,6 @@ typedef struct tag_songentry {
} SONGENTRY; } SONGENTRY;
typedef struct tag_config { typedef struct tag_config {
pid_t rend_pid;
int use_mdns; int use_mdns;
int stop; int stop;
char *configfile; char *configfile;
@ -48,4 +47,7 @@ typedef struct tag_config {
extern CONFIG config; extern CONFIG config;
/* Forwards */
extern drop_privs(char *user);
#endif /* _DAAPD_H_ */ #endif /* _DAAPD_H_ */

View File

@ -373,6 +373,39 @@ void usage(char *program) {
printf("\n\n"); printf("\n\n");
} }
/*
* drop_privs
*
* drop privs to a specific user
*/
int drop_privs(char *user) {
int err;
struct passwd *pw=NULL;
/* drop privs */
if(getuid() == (uid_t)0) {
pw=getpwnam(config.runas);
if(pw) {
if(initgroups(user,pw->pw_gid) != 0 ||
setgid(pw->pw_gid) != 0 ||
setuid(pw->pw_uid) != 0) {
err=errno;
fprintf(stderr,"Couldn't change to %s, gid=%d, uid=%d\n",
user,pw->pw_gid, pw->pw_uid);
errno=err;
return -1;
}
} else {
err=errno;
fprintf(stderr,"Couldn't lookup user %s\n",user);
errno=err;
return -1;
}
}
return 0;
}
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
int option; int option;
char *configfile=DEFAULT_CONFIGFILE; char *configfile=DEFAULT_CONFIGFILE;
@ -384,7 +417,6 @@ int main(int argc, char *argv[]) {
int parseonly=0; int parseonly=0;
int foreground=0; int foreground=0;
config.use_mdns=1; config.use_mdns=1;
struct passwd *pw=NULL;
#ifdef DEBUG #ifdef DEBUG
char *optval="d:c:mpf"; char *optval="d:c:mpf";
@ -443,26 +475,18 @@ int main(int argc, char *argv[]) {
if((config.use_mdns) && (!parseonly)) { if((config.use_mdns) && (!parseonly)) {
fprintf(stderr,"Starting rendezvous daemon\n"); fprintf(stderr,"Starting rendezvous daemon\n");
rend_init(&config.rend_pid,config.servername, config.port, config.runas); if(rend_init(config.runas)) {
} perror("rend_init");
/* drop privs */
if(getuid() == (uid_t)0) {
pw=getpwnam(config.runas);
if(pw) {
if(initgroups(config.runas,pw->pw_gid) != 0 ||
setgid(pw->pw_gid) != 0 ||
setuid(pw->pw_uid) != 0) {
fprintf(stderr,"Couldn't change to %s, gid=%d, uid=%d\n",
config.runas,pw->pw_gid, pw->pw_uid);
exit(EXIT_FAILURE);
}
} else {
fprintf(stderr,"Couldn't lookup user %s\n",config.runas);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }
// Drop privs here
if(drop_privs(config.runas)) {
perror("drop_privs");
exit(EXIT_FAILURE);
}
DPRINTF(ERR_DEBUG,"Initializing database\n"); DPRINTF(ERR_DEBUG,"Initializing database\n");
/* Initialize the database before starting */ /* Initialize the database before starting */
@ -512,6 +536,12 @@ int main(int argc, char *argv[]) {
ws_registerhandler(server,"^/logout$",daap_handler,daap_auth,0); ws_registerhandler(server,"^/logout$",daap_handler,daap_auth,0);
ws_registerhandler(server,"^/databases/.*",daap_handler,daap_auth,0); ws_registerhandler(server,"^/databases/.*",daap_handler,daap_auth,0);
if(config.use_mdns) { /* register services */
DPRINTF(ERR_DEBUG,"Registering rendezvous names\n");
rend_register(config.servername,"_daap._tcp",config.port);
rend_register(config.servername,"_http._tcp",config.port);
}
config.stop=0; config.stop=0;
while(!config.stop) while(!config.stop)
@ -519,8 +549,7 @@ int main(int argc, char *argv[]) {
if(config.use_mdns) { if(config.use_mdns) {
if(foreground) fprintf(stderr,"Killing rendezvous daemon\n"); if(foreground) fprintf(stderr,"Killing rendezvous daemon\n");
kill(config.rend_pid,SIGINT); rend_stop();
wait(&status);
} }
if(foreground) fprintf(stderr,"Stopping webserver\n"); if(foreground) fprintf(stderr,"Stopping webserver\n");

View File

@ -261,7 +261,7 @@ int scan_init(char *path) {
int scan_foreground(char *path) { int scan_foreground(char *path) {
MP3FILE mp3file; MP3FILE mp3file;
DIR *current_dir; DIR *current_dir;
struct dirent de; char de[sizeof(struct dirent) + MAXNAMLEN + 1]; /* overcommit for solaris */
struct dirent *pde; struct dirent *pde;
int err; int err;
char mp3_path[PATH_MAX]; char mp3_path[PATH_MAX];
@ -276,9 +276,9 @@ int scan_foreground(char *path) {
} }
while(1) { while(1) {
pde=&de; pde=(struct dirent *)&de;
err=readdir_r(current_dir,&de,&pde); err=readdir_r(current_dir,(struct dirent *)de,&pde);
if(err == -1) { if(err == -1) {
DPRINTF(ERR_DEBUG,"Error on readdir_r: %s\n",strerror(errno)); DPRINTF(ERR_DEBUG,"Error on readdir_r: %s\n",strerror(errno));
err=errno; err=errno;
@ -290,28 +290,28 @@ int scan_foreground(char *path) {
if(!pde) if(!pde)
break; break;
if(de.d_name[0] == '.') /* skip hidden and directories */ if(pde->d_name[0] == '.') /* skip hidden and directories */
continue; continue;
sprintf(mp3_path,"%s/%s",path,de.d_name); sprintf(mp3_path,"%s/%s",path,pde->d_name);
DPRINTF(ERR_DEBUG,"Found %s\n",mp3_path); DPRINTF(ERR_DEBUG,"Found %s\n",mp3_path);
if(stat(mp3_path,&sb)) { if(stat(mp3_path,&sb)) {
DPRINTF(ERR_WARN,"Error statting: %s\n",strerror(errno)); DPRINTF(ERR_WARN,"Error statting: %s\n",strerror(errno));
} }
if(sb.st_mode & S_IFDIR) { /* dir -- recurse */ if(sb.st_mode & S_IFDIR) { /* dir -- recurse */
DPRINTF(ERR_DEBUG,"Found dir %s... recursing\n",de.d_name); DPRINTF(ERR_DEBUG,"Found dir %s... recursing\n",pde->d_name);
scan_foreground(mp3_path); scan_foreground(mp3_path);
} else { } else {
DPRINTF(ERR_DEBUG,"Processing file\n"); DPRINTF(ERR_DEBUG,"Processing file\n");
/* process the file */ /* process the file */
if(strlen(de.d_name) > 4) { if(strlen(pde->d_name) > 4) {
if(strcasecmp(".m3u",(char*)&de.d_name[strlen(de.d_name) - 4]) == 0) { if(strcasecmp(".m3u",(char*)&pde->d_name[strlen(pde->d_name) - 4]) == 0) {
/* we found an m3u file */ /* we found an m3u file */
DPRINTF(ERR_DEBUG,"Found m3u: %s\n",de.d_name); DPRINTF(ERR_DEBUG,"Found m3u: %s\n",pde->d_name);
strcpy(m3u_path,de.d_name); strcpy(m3u_path,pde->d_name);
m3u_path[strlen(de.d_name) - 4] = '\0'; m3u_path[strlen(pde->d_name) - 4] = '\0';
playlistid=sb.st_ino; playlistid=sb.st_ino;
fd=open(mp3_path,O_RDONLY); fd=open(mp3_path,O_RDONLY);
if(fd != -1) { if(fd != -1) {
@ -344,13 +344,13 @@ int scan_foreground(char *path) {
} }
close(fd); close(fd);
} }
} else if(strcasecmp(".mp3",(char*)&de.d_name[strlen(de.d_name) - 4]) == 0) { } else if(strcasecmp(".mp3",(char*)&pde->d_name[strlen(pde->d_name) - 4]) == 0) {
/* we found an mp3 file */ /* we found an mp3 file */
DPRINTF(ERR_DEBUG,"Found mp3: %s\n",de.d_name); DPRINTF(ERR_DEBUG,"Found mp3: %s\n",pde->d_name);
memset((void*)&mp3file,0,sizeof(mp3file)); memset((void*)&mp3file,0,sizeof(mp3file));
mp3file.path=mp3_path; mp3file.path=mp3_path;
mp3file.fname=de.d_name; mp3file.fname=pde->d_name;
#ifdef MAC /* wtf is this about? */ #ifdef MAC /* wtf is this about? */
mp3file.mtime=sb.st_mtimespec.tv_sec; mp3file.mtime=sb.st_mtimespec.tv_sec;
@ -371,7 +371,7 @@ int scan_foreground(char *path) {
db_add(&mp3file); db_add(&mp3file);
pl_eval(&mp3file); pl_eval(&mp3file);
} else { } else {
DPRINTF(ERR_INFO,"Skipping %s\n",de.d_name); DPRINTF(ERR_INFO,"Skipping %s\n",pde->d_name);
} }
scan_freetags(&mp3file); scan_freetags(&mp3file);

View File

@ -26,9 +26,17 @@
#include <sys/types.h> #include <sys/types.h>
#include <rendezvous/rendezvous.h> #include <rendezvous/rendezvous.h>
#include <salt/log.h> #include <salt/log.h>
#include <pthread.h>
#include "err.h" #include "err.h"
#include "rend-unix.h"
pthread_t rend_tid;
sw_rendezvous rend_handle;
/* Forwards */
void *rend_pipe_monitor(void* arg);
void rend_callback(void);
/* /*
* rend_howl_reply * rend_howl_reply
@ -53,57 +61,113 @@ static sw_result rend_howl_reply(sw_rendezvous_publish_handler handler,
/* /*
* public interface * rend_private_init
*
* Initialize howl and start runloop
*/ */
int rend_init(pid_t *pid, char *name, int port, char *user) { int rend_private_init(char *user) {
sw_rendezvous rendezvous;
sw_result result; sw_result result;
sw_rendezvous_publish_id daap_id;
sw_rendezvous_publish_id http_id;
struct passwd *pw=NULL;
/* drop privs */
if(getuid() == (uid_t)0) {
pw=getpwnam(user);
if(pw) {
if(initgroups(user,pw->pw_gid) != 0 ||
setgid(pw->pw_gid) != 0 ||
setuid(pw->pw_uid) != 0) {
fprintf(stderr,"Couldn't change to %s, gid=%d, uid=%d\n",
user,pw->pw_gid, pw->pw_uid);
exit(EXIT_FAILURE);
}
} else {
fprintf(stderr,"Couldn't lookup user %s\n",user);
exit(EXIT_FAILURE);
}
}
if(sw_rendezvous_init(&rendezvous) != SW_OKAY) { DPRINTF(ERR_DEBUG,"Starting rendezvous services\n");
if(sw_rendezvous_init(&rend_handle) != SW_OKAY) {
DPRINTF(ERR_WARN,"Error initializing rendezvous\n"); DPRINTF(ERR_WARN,"Error initializing rendezvous\n");
errno=EINVAL; errno=EINVAL;
return -1; return -1;
} }
if((result=sw_rendezvous_publish(rendezvous,name,"_daap._tcp",NULL,NULL,port,NULL,NULL, if(drop_privs(user))
rend_howl_reply,NULL,&daap_id)) != SW_OKAY) {
DPRINTF(ERR_WARN,"Error registering DAAP server via mDNS: %d\n",result);
return -1; return -1;
}
if((result=sw_rendezvous_publish(rendezvous,name,"_http._tcp",NULL,NULL,port,NULL,NULL, DPRINTF(ERR_DEBUG,"Starting polling thread\n");
rend_howl_reply,NULL,&http_id)) != SW_OKAY) {
DPRINTF(ERR_WARN,"Error registering HTTP server via mDNS: %d\n",result);
return -1;
}
*pid=fork(); if(pthread_create(&rend_tid,NULL,rend_pipe_monitor,NULL)) {
if(*pid) { DPRINTF(ERR_FATAL,"Could not start thread. Terminating\n");
return 0; /* should kill parent, too */
exit(EXIT_FAILURE);
} }
DPRINTF(ERR_DEBUG,"Registered rendezvous services\n"); DPRINTF(ERR_DEBUG,"Entering runloop\n");
sw_rendezvous_run(rendezvous);
sw_rendezvous_run(rend_handle);
DPRINTF(ERR_DEBUG,"Exiting runloop\n");
return 0; return 0;
} }
/*
* rend_pipe_monitor
*/
void *rend_pipe_monitor(void* arg) {
fd_set rset;
struct timeval tv;
int result;
while(1) {
DPRINTF(ERR_DEBUG,"Waiting for data\n");
FD_ZERO(&rset);
FD_SET(rend_pipe_to[RD_SIDE],&rset);
/* sit in a select spin until there is data on the to fd */
while(((result=select(rend_pipe_to[RD_SIDE] + 1,&rset,NULL,NULL,NULL)) != -1) &&
errno != EINTR) {
if(FD_ISSET(rend_pipe_to[RD_SIDE],&rset)) {
DPRINTF(ERR_DEBUG,"Received a message from daap server\n");
rend_callback();
}
}
DPRINTF(ERR_DEBUG,"Select error!\n");
/* should really bail here */
}
}
/*
* rend_callback
*
* This gets called from the main thread when there is a
* message waiting to be processed.
*/
void rend_callback(void) {
REND_MESSAGE msg;
sw_rendezvous_publish_id rend_id;
sw_result result;
/* here, we've seen the message, now we have to process it */
if(rend_read_message(&msg) != sizeof(msg)) {
DPRINTF(ERR_FATAL,"Error reading rendezvous message\n");
exit(EXIT_FAILURE);
}
switch(msg.cmd) {
case REND_MSG_TYPE_REGISTER:
DPRINTF(ERR_DEBUG,"Registering %s.%s (%d)\n",msg.type,msg.name,msg.port);
if((result=sw_rendezvous_publish(rend_handle,msg.name,msg.type,NULL,NULL,msg.port,NULL,0,
NULL,rend_howl_reply,NULL,&rend_id)) != SW_OKAY) {
DPRINTF(ERR_WARN,"Error registering name\n");
rend_send_response(-1);
} else {
rend_send_response(0); /* success */
}
break;
case REND_MSG_TYPE_UNREGISTER:
DPRINTF(ERR_WARN,"Unsupported function: UNREGISTER\n");
rend_send_response(-1); /* error */
break;
case REND_MSG_TYPE_STOP:
DPRINTF(ERR_DEBUG,"Stopping mDNS\n");
rend_send_response(0);
//sw_rendezvous_stop_publish(rend_handle);
sw_rendezvous_fina(rend_handle);
break;
case REND_MSG_TYPE_STATUS:
DPRINTF(ERR_DEBUG,"Status inquiry -- returning 0\n");
rend_send_response(0); /* success */
break;
default:
break;
}
}

View File

@ -28,24 +28,42 @@
#include <CoreFoundation/CoreFoundation.h> #include <CoreFoundation/CoreFoundation.h>
#include <DNSServiceDiscovery/DNSServiceDiscovery.h> #include <DNSServiceDiscovery/DNSServiceDiscovery.h>
#include "daapd.h"
#include "err.h" #include "err.h"
#include "rend-unix.h"
CFRunLoopRef rend_runloop; CFRunLoopRef rend_runloop;
CFRunLoopSourceRef rend_rls;
pthread_t rend_tid;
/* Forwards */
void *rend_pipe_monitor(void* arg);
/*
* rend_stoprunloop
*/
static void rend_stoprunloop(void) { static void rend_stoprunloop(void) {
CFRunLoopStop(rend_runloop); CFRunLoopStop(rend_runloop);
} }
/*
* rend_sigint
*/
static void rend_sigint(int sigraised) { static void rend_sigint(int sigraised) {
DPRINTF(ERR_INFO,"SIGINT\n"); DPRINTF(ERR_INFO,"SIGINT\n");
rend_stoprunloop(); rend_stoprunloop();
} }
/*
* rend_handler
*/
static void rend_handler(CFMachPortRef port, void *msg, CFIndex size, void *info) { static void rend_handler(CFMachPortRef port, void *msg, CFIndex size, void *info) {
DNSServiceDiscovery_handleReply(msg); DNSServiceDiscovery_handleReply(msg);
} }
/*
* rend_addtorunloop
*/
static int rend_addtorunloop(dns_service_discovery_ref client) { static int rend_addtorunloop(dns_service_discovery_ref client) {
mach_port_t port=DNSServiceDiscoveryMachPort(client); mach_port_t port=DNSServiceDiscoveryMachPort(client);
@ -66,6 +84,9 @@ static int rend_addtorunloop(dns_service_discovery_ref client) {
} }
} }
/*
* rend_reply
*/
static void rend_reply(DNSServiceRegistrationReplyErrorType errorCode, void *context) { static void rend_reply(DNSServiceRegistrationReplyErrorType errorCode, void *context) {
switch(errorCode) { switch(errorCode) {
case kDNSServiceDiscoveryNoError: case kDNSServiceDiscoveryNoError:
@ -81,62 +102,123 @@ static void rend_reply(DNSServiceRegistrationReplyErrorType errorCode, void *con
} }
/* /*
* public interface * rend_pipe_monitor
*/ */
int rend_init(pid_t *pid, char *name, int port, char *user) { void *rend_pipe_monitor(void* arg) {
dns_service_discovery_ref daap_ref=NULL; fd_set rset;
dns_service_discovery_ref http_ref=NULL; struct timeval tv;
unsigned short usPort=port; int result;
struct passwd *pw=NULL;
*pid=fork();
if(*pid) {
return 0;
}
/* drop privs */ while(1) {
if(getuid() == (uid_t)0) { DPRINTF(ERR_DEBUG,"Waiting for data\n");
pw=getpwnam(user); FD_ZERO(&rset);
if(pw) { FD_SET(rend_pipe_to[RD_SIDE],&rset);
if(initgroups(user,pw->pw_gid) != 0 ||
setgid(pw->pw_gid) != 0 || /* sit in a select spin until there is data on the to fd */
setuid(pw->pw_uid) != 0) { while(((result=select(rend_pipe_to[RD_SIDE] + 1,&rset,NULL,NULL,NULL)) != -1) &&
fprintf(stderr,"Couldn't change to %s, gid=%d, uid=%d\n", errno != EINTR) {
user,pw->pw_gid, pw->pw_uid); if(FD_ISSET(rend_pipe_to[RD_SIDE],&rset)) {
exit(EXIT_FAILURE); DPRINTF(ERR_DEBUG,"Received a message from daap server\n");
CFRunLoopSourceSignal(rend_rls);
CFRunLoopWakeUp(rend_runloop);
sleep(1); /* force a reschedule, hopefully */
} }
} else {
fprintf(stderr,"Couldn't lookup user %s\n",user);
exit(EXIT_FAILURE);
} }
DPRINTF(ERR_DEBUG,"Select error!\n");
/* should really bail here */
}
}
/*
* rend_callback
*
* This gets called from the main thread when there is a
* message waiting to be processed.
*/
void rend_callback(void *info) {
REND_MESSAGE msg;
unsigned short usPort;
dns_service_discovery_ref dns_ref=NULL;
/* here, we've seen the message, now we have to process it */
if(rend_read_message(&msg) != sizeof(msg)) {
DPRINTF(ERR_FATAL,"Error reading rendezvous message\n");
exit(EXIT_FAILURE);
} }
switch(msg.cmd) {
case REND_MSG_TYPE_REGISTER:
DPRINTF(ERR_DEBUG,"Registering %s.%s (%d)\n",msg.type,msg.name,msg.port);
usPort=msg.port;
dns_ref=DNSServiceRegistrationCreate(msg.name,msg.type,"",usPort,"",rend_reply,nil);
if(rend_addtorunloop(dns_ref)) {
DPRINTF(ERR_WARN,"Add to runloop failed\n");
rend_send_response(-1);
} else {
rend_send_response(0); /* success */
}
break;
case REND_MSG_TYPE_UNREGISTER:
DPRINTF(ERR_WARN,"Unsupported function: UNREGISTER\n");
rend_send_response(-1); /* error */
break;
case REND_MSG_TYPE_STOP:
DPRINTF(ERR_DEBUG,"Stopping mDNS\n");
rend_send_response(0);
rend_stoprunloop();
break;
case REND_MSG_TYPE_STATUS:
DPRINTF(ERR_DEBUG,"Status inquiry -- returning 0\n");
rend_send_response(0); /* success */
break;
default:
break;
}
}
signal(SIGINT, rend_sigint); // SIGINT is what you get for a Ctrl-C /*
* rend_private_init
*
* start up the rendezvous services
*/
int rend_private_init(char *user) {
CFRunLoopSourceContext context;
if(drop_privs(user)) /* shouldn't be running as root anyway */
DPRINTF(ERR_DEBUG,"Registering services\n");
daap_ref=DNSServiceRegistrationCreate(name,"_daap._tcp","",usPort,"",rend_reply,nil);
http_ref=DNSServiceRegistrationCreate(name,"_http._tcp","",port,"",rend_reply,nil);
if(rend_addtorunloop(daap_ref)|| rend_addtorunloop(http_ref)) {
DPRINTF(ERR_WARN,"Add to runloop failed\n");
return -1; return -1;
}
/* need a sigint handler */
DPRINTF(ERR_DEBUG,"Starting rendezvous services\n");
memset((void*)&context,0,sizeof(context));
context.perform = rend_callback;
rend_runloop = CFRunLoopGetCurrent(); rend_runloop = CFRunLoopGetCurrent();
rend_rls = CFRunLoopSourceCreate(NULL,0,&context);
CFRunLoopAddSource(CFRunLoopGetCurrent(),rend_rls,kCFRunLoopDefaultMode);
DPRINTF(ERR_DEBUG,"Starting polling thread\n");
if(pthread_create(&rend_tid,NULL,rend_pipe_monitor,NULL)) {
DPRINTF(ERR_FATAL,"Could not start thread. Terminating\n");
/* should kill parent, too */
exit(EXIT_FAILURE);
}
DPRINTF(ERR_DEBUG,"Registered rendezvous services\n"); DPRINTF(ERR_DEBUG,"Starting runloop\n");
CFRunLoopRun(); CFRunLoopRun();
DPRINTF(ERR_DEBUG,"Exiting runloop\n"); DPRINTF(ERR_DEBUG,"Exiting runloop\n");
DNSServiceDiscoveryDeallocate(daap_ref); CFRelease(rend_rls);
DNSServiceDiscoveryDeallocate(http_ref); pthread_cancel(rend_tid);
close(rend_pipe_to[RD_SIDE]);
exit(0); close(rend_pipe_from[WR_SIDE]);
return 0;
} }

View File

@ -89,6 +89,12 @@
Change History (most recent first): Change History (most recent first):
$Log$ $Log$
Revision 1.10 2004/01/20 04:41:20 rpedde
merge new-rend-branch
Revision 1.9.2.1 2004/01/16 20:51:01 rpedde
Convert rend-posix to message-based system
Revision 1.9 2004/01/04 05:02:23 rpedde Revision 1.9 2004/01/04 05:02:23 rpedde
fix segfault on dropping privs fix segfault on dropping privs
@ -143,6 +149,8 @@
#define __IN_ERR__ #define __IN_ERR__
#include "err.h" #include "err.h"
#include "rend.h"
#include "rend-unix.h"
#pragma mark ***** Globals #pragma mark ***** Globals
@ -549,55 +557,73 @@ static void DeregisterOurServices(void)
} }
} }
#pragma mark **** Main /*
* rend_callback
*
* This is borrowed from the OSX rend client
*/
void rend_callback(void) {
REND_MESSAGE msg;
int result;
int rend_init(pid_t *pid,char *name, int port, char *user) { DPRINTF(ERR_DEBUG,"Processing rendezvous message\n");
/* here, we've seen the message, now we have to process it */
if((result=rend_read_message(&msg)) != sizeof(msg)) {
DPRINTF(ERR_DEBUG,"Expected %d, got %d\n",sizeof(msg),result);
DPRINTF(ERR_FATAL,"Error reading rendezvous message: %s\n",
strerror(errno));
exit(1);
}
switch(msg.cmd) {
case REND_MSG_TYPE_REGISTER:
DPRINTF(ERR_DEBUG,"Registering %s.%s (%d)\n",msg.type,msg.name,msg.port);
RegisterOneService(msg.name,msg.type,NULL,0,msg.port);
rend_send_response(0); /* success */
break;
case REND_MSG_TYPE_UNREGISTER:
rend_send_response(1); /* error */
break;
case REND_MSG_TYPE_STOP:
DPRINTF(ERR_INFO,"Stopping mDNS\n");
gStopNow = mDNStrue;
rend_send_response(0);
break;
case REND_MSG_TYPE_STATUS:
rend_send_response(1);
break;
default:
break;
}
}
#pragma mark **** rend_private_init
int rend_private_init(char *user) {
mStatus status; mStatus status;
mDNSBool result; mDNSBool result;
struct passwd *pw=NULL;
status = mDNS_Init(&mDNSStorage, &PlatformStorage, status = mDNS_Init(&mDNSStorage, &PlatformStorage,
mDNS_Init_NoCache, mDNS_Init_ZeroCacheSize, mDNS_Init_NoCache, mDNS_Init_ZeroCacheSize,
mDNS_Init_AdvertiseLocalAddresses, mDNS_Init_AdvertiseLocalAddresses,
mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext); mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
if (status != mStatus_NoError) { if (status != mStatus_NoError) {
DPRINTF(ERR_FATAL,"mDNS Error %d\n",status); DPRINTF(ERR_FATAL,"mDNS Error %d\n",status);
return(-1); return(-1);
} }
*pid=fork(); if(drop_privs(user))
if(*pid) { return -1;
return 0;
}
/* drop privs */
if(getuid() == (uid_t)0) {
pw=getpwnam(user);
if(pw) {
if(initgroups(user,pw->pw_gid) != 0 ||
setgid(pw->pw_gid) != 0 ||
setuid(pw->pw_uid) != 0) {
fprintf(stderr,"Couldn't change to %s, gid=%d, uid=%d\n",
user,pw->pw_gid, pw->pw_uid);
exit(EXIT_FAILURE);
}
} else {
fprintf(stderr,"Couldn't lookup user %s\n",user);
exit(EXIT_FAILURE);
}
}
DPRINTF(ERR_DEBUG,"Registering tcp service\n");
RegisterOneService(name,"_http._tcp",NULL,0,port);
RegisterOneService(name,"_daap._tcp",NULL,0,port);
signal(SIGINT, HandleSigInt); // SIGINT is what you get for a Ctrl-C signal(SIGINT, HandleSigInt); // SIGINT is what you get for a Ctrl-C
signal(SIGQUIT, HandleSigQuit); // SIGQUIT is what you get for a Ctrl-\ (indeed) signal(SIGQUIT, HandleSigQuit); // SIGQUIT is what you get for a Ctrl-\ (indeed)
while (!gStopNow) { while (!gStopNow) {
int nfds = 0; int nfds = 1;
fd_set readfds; fd_set readfds;
struct timeval timeout; struct timeval timeout;
int result; int result;
@ -606,6 +632,7 @@ int rend_init(pid_t *pid,char *name, int port, char *user) {
// This example client has no file descriptors of its own, // This example client has no file descriptors of its own,
// but a real application would call FD_SET to add them to the set here // but a real application would call FD_SET to add them to the set here
FD_ZERO(&readfds); FD_ZERO(&readfds);
FD_SET(rend_pipe_to[RD_SIDE],&readfds);
// 2. Set up the timeout. // 2. Set up the timeout.
// This example client has no other work it needs to be doing, // This example client has no other work it needs to be doing,
@ -632,6 +659,9 @@ int rend_init(pid_t *pid,char *name, int port, char *user) {
// 6. This example client has no other work it needs to be doing, // 6. This example client has no other work it needs to be doing,
// but a real client would do its work here // but a real client would do its work here
// ... (do work) ... // ... (do work) ...
if(FD_ISSET(rend_pipe_to[RD_SIDE],&readfds)) {
rend_callback();
}
} }
} }
@ -651,3 +681,4 @@ int rend_init(pid_t *pid,char *name, int port, char *user) {
exit(result); exit(result);
} }

179
src/rend-unix.c Normal file
View File

@ -0,0 +1,179 @@
/*
* $Id$
* General unix rendezvous routines
*
* Copyright (C) 2003 Ron Pedde (ron@pedde.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include "daapd.h"
#include "err.h"
#include "rend-unix.h"
int rend_pipe_to[2];
int rend_pipe_from[2];
int rend_pid;
#define RD_SIDE 0
#define WR_SIDE 1
/*
* rend_init
*
* Fork and set up message passing system
*/
int rend_init(char *user) {
int err;
if(pipe((int*)&rend_pipe_to) == -1)
return -1;
if(pipe((int*)&rend_pipe_from) == -1) {
err=errno;
close(rend_pipe_to[RD_SIDE]);
close(rend_pipe_to[WR_SIDE]);
errno=err;
return -1;
}
rend_pid=fork();
if(rend_pid==-1) {
err=errno;
close(rend_pipe_to[RD_SIDE]);
close(rend_pipe_to[WR_SIDE]);
close(rend_pipe_from[RD_SIDE]);
close(rend_pipe_from[WR_SIDE]);
errno=err;
return -1;
}
if(rend_pid) { /* parent */
close(rend_pipe_to[RD_SIDE]);
close(rend_pipe_from[WR_SIDE]);
return 0;
}
/* child */
close(rend_pipe_to[WR_SIDE]);
close(rend_pipe_from[RD_SIDE]);
/* something bad here... should really signal the parent, rather
* than just zombieizing
*/
rend_private_init(user); /* should only return when terminated */
exit(0);
}
/*
* rend_running
*
* See if the rendezvous daemon is runnig
*/
int rend_running(void) {
REND_MESSAGE msg;
int result;
DPRINTF(ERR_DEBUG,"Status inquiry\n");
msg.cmd=REND_MSG_TYPE_STATUS;
result=rend_send_message(&msg);
DPRINTF(ERR_DEBUG,"Returning status %d\n",result);
return result;
}
/*
*rend_stop
*
* Stop the rendezvous server
*/
int rend_stop(void) {
REND_MESSAGE msg;
msg.cmd=REND_MSG_TYPE_STOP;
return rend_send_message(&msg);
}
/*
* rend_register
*
* register a rendezvous name
*/
int rend_register(char *name, char *type, int port) {
REND_MESSAGE msg;
if((strlen(name)+1 > MAX_NAME_LEN) || (strlen(type)+1 > MAX_NAME_LEN)) {
DPRINTF(ERR_FATAL,"Registration failed: name or type too long\n");
return -1;
}
msg.cmd=REND_MSG_TYPE_REGISTER;
strcpy(msg.name,name);
strcpy(msg.type,type);
msg.port=port;
return rend_send_message(&msg);
}
/*
* rend_unregister
*
* Stop advertising a rendezvous name
*/
int rend_unregister(char *name, char *type, int port) {
return -1; /* not implemented */
}
/*
* rend_send_message
*
* Send a rendezvous message
*/
int rend_send_message(REND_MESSAGE *pmsg) {
int retval;
if(r_write(rend_pipe_to[WR_SIDE],pmsg,sizeof(REND_MESSAGE)) == -1)
return -1;
if((retval=r_read(rend_pipe_from[RD_SIDE],&retval,sizeof(int)) == -1))
return -1;
return retval;
}
/*
* rend_read_message
*
* read the message passed to the rend daemon
*/
int rend_read_message(REND_MESSAGE *pmsg) {
return r_read(rend_pipe_to[RD_SIDE],pmsg,sizeof(REND_MESSAGE));
}
/*
* rend_send_response
*
* Let the rendezvous daemon return a result
*/
int rend_send_response(int value) {
return r_write(rend_pipe_from[WR_SIDE],&value,sizeof(int));
}

51
src/rend-unix.h Normal file
View File

@ -0,0 +1,51 @@
/*
* $Id$
* General unix rendezvous routines
*
* Copyright (C) 2003 Ron Pedde (ron@pedde.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _REND_UNIX_H_
#define _REND_UNIX_H_
#define MAX_NAME_LEN 256
typedef struct tag_rend_message {
int cmd;
int port;
char name[MAX_NAME_LEN];
char type[MAX_NAME_LEN];
} REND_MESSAGE;
#define REND_MSG_TYPE_REGISTER 0
#define REND_MSG_TYPE_UNREGISTER 1
#define REND_MSG_TYPE_STOP 2
#define REND_MSG_TYPE_STATUS 3
#define RD_SIDE 0
#define WR_SIDE 1
extern int rend_pipe_to[2];
extern int rend_pipe_from[2];
extern int rend_send_message(REND_MESSAGE *pmsg);
extern int rend_send_response(int value);
extern int rend_private_init(char *user);
extern int rend_read_message(REND_MESSAGE *pmsg);
#endif /* _REND_UNIX_H_ */

View File

@ -22,6 +22,10 @@
#ifndef _REND_H_ #ifndef _REND_H_
#define _REND_H_ #define _REND_H_
int rend_init(pid_t *pid, char *name, int port, char *user); extern int rend_init(char *user);
extern int rend_running(void);
extern int rend_stop(void);
extern int rend_register(char *name, char *type, int port);
extern int rend_unregister(char *name, char *type, int port);
#endif /* _REND_H_ */ #endif /* _REND_H_ */