/* XMMS InfoPipe plugin Distributed under GNU GPL. See the COPYING file for details. Written by Weyfour WWWWolf (Urpo Lankinen), 2000-12-09 and onward threaded handler and #include cleanup by Da Fox $Id: infopipe.c,v 1.38 2006/05/09 18:54:33 Da Fox Exp $ */ #include #include #include #include #include "infopipe.h" #include "../config.h" #include "infopipe_config.h" /***********************************************************/ int thread_count; /* Some strings - these are initialized in the init function and g_free()d in the finalization function. infopipe_ver should be gchar *, but for some reason, it wants a "constant" and pointer-passing gives Weird Results... */ /* Name and version */ #define VERSTRLEN 40 char infopipe_ver[VERSTRLEN]; /* FIFO file name. */ //gchar *fifo_file = NULL; char *fifo_file; // this becomes a hardcoded version of 'FIFO_FILE_PFX'-XXXXXX // someone please fixme :) /* Current user's name. */ //gchar *user_name; /* The data structure that holds the information about this plugin... */ GeneralPlugin infopipe_gp = { NULL, /* Handle (Filled by XMMS) */ NULL, /* Filename (Filled by XMMS) */ 0, /* Session ID */ infopipe_ver, /* Description */ init_plugin, /* Init function */ show_about, /* About box */ NULL, /* Configure */ finalize_plugin /* Cleanup */ }; /***********************************************************/ /* XMMS hookup function. This routine is called by XMMS after it dlopen()s this library, and it's supposed to return a pointer to GeneralPlugin struct. */ GeneralPlugin *get_gplugin_info(void) { strncpy(infopipe_ver, "InfoPipe ", VERSTRLEN); strncat(infopipe_ver, VERSION, VERSTRLEN); return &infopipe_gp; } /* Pipe handling thread. */ pthread_t requesthandler; pthread_t blasterhandler; pthread_attr_t attr; /* The function that's called when the plugin is initialized, as specified in infopipe_gp structure... This will create the pipe special file, then start a thread to handle pipe requests. */ void init_plugin(void) { struct passwd *user_info; /* Load configuration. */ load_config(); /* Handle multiple session names. (Changed by WWWWolf - snprintf vs. sprintf, eliminated Yet Another Possible Buffer Overflow Sploit =) */ /* Create the thread that handles pipe stuff. */ fifo_file=malloc(22); if(fifo_file==NULL) { perror("xmms-infopipe: unable to allocate memory for filename"); } pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); if(pthread_create(&requesthandler, &attr , (void *) &request_handler_thread, NULL) != 0) { perror("xmms-infopipe: Unable the create new thread (ie, no InfoPipe for you!)"); xmms_quit(); } return; } /* The function that's called when XMMS quits. It will get rid of the thread and the special file. NOTE: Do we need xmms_remote_quit()s here? After all, we're probably *already* quitting! */ void finalize_plugin(void) { // Only executed on xmms_unload(disable)_plugin /* Wait for it to finish... even thought it never does that. */ if(pthread_cancel(requesthandler) != 0) { perror("xmms-infopipe: Thread cancel failed"); xmms_quit(); } /* ...remove the pipe ... even when we never do this either... */ if(unlink(fifo_file)!=0) { perror("xmms-infopipe: Unable to remove the pipe in the cleanup phase"); xmms_quit(); } /* remove the symlink */ if(param.delete_symlinks) { if(unlink(FIFO_FILE_PFX)!=0) { perror("xmms-infopipe: Unable to remove the symlink in the cleanup phase"); xmms_quit(); } } /* Unallocate strings */ //g_free(user_name); /* g_free(infopipe_ver); */ //g_free(fifo_file); free(fifo_file);fifo_file=NULL; return; } /* This is the thread that runs in background, waiting for reader at the InfoPipe and then sending information. In 1.1, we use fcntl() instead of waiting 'round, because this seems to be the Right Way and apparently more cooler anyway if you get millions of hits... */ void clear_tmp_fifo(char fifo_file[]) { /* closes the stream pointed to by p, then removes the temporary file fifo_file */ /* See if the file exists... */ if(access(fifo_file,F_OK)==0) { /* Let's nuke the old pipe that we found. */ if(unlink(fifo_file)!=0) { perror("xmms-infopipe: Unable to remove pipe."); xmms_quit(); return; } } return; } void create_tmp_fifo(char fifo_file[]) { /* opens a tmpname-fifo, and symlinks, then opens it for writing and */ /* returns a pointer to the stream */ mktemp(fifo_file); /* Create the pipe. */ if(mkfifo(fifo_file,0644) != 0) { perror("xmms-infopipe: Unable to create a pipe"); xmms_quit(); } /* Chown the pipe if so desired. */ if(param.do_chown) { if(chown(fifo_file, param.chowntouid, param.chowntogid) != 0) { perror("xmms-infopipe: Couldn't chown(), but continuing anyway"); } } /* Remove old symlink if it exists, and create a new symlink */ if(param.create_symlinks) { if(unlink(FIFO_FILE_PFX)!=0 && (errno != ENOENT && errno != EPERM && errno != EACCES) ) { /* Oops, we did something wrong. */ perror("xmms-infopipe: Unable to reasonably remove the symbolic link"); xmms_quit(); return; } else { /* We succeeded. Let's try to create the link. */ if(symlink(fifo_file,FIFO_FILE_PFX)!=0) { perror("xmms-infopipe: Unable to create symbolic link"); xmms_quit(); return; } } } } void info_blaster_thread(char fifo_file[]) { int f; FILE *p; f = open(fifo_file, O_WRONLY); if(f != -1) { errno=0; p = fdopen(f, "w"); //This will generate a Illegal Seek if(errno==ESPIPE) { errno=0 ; //as expected blast_info(p); if(fclose(p)!=0) { perror("xmms-infopipe: Unexpected failure in fclose()"); } } else { perror("xmms-infopipe: Unexpected failure in fdopen()"); } } else { printf("xmms-infopipe: Failed to open %s as requested.\n", fifo_file); perror("open()"); } free(fifo_file); fifo_file=NULL; thread_count--; pthread_exit(NULL); //does not return return; } void request_handler_thread(void) { FILE *i; /* input pipe */ FILE *o; /* output pipe */ int ifd; /* File descriptor for input pipe, and its flags. */ fifo_file[ 0]='/'; fifo_file[ 1]='t'; fifo_file[ 2]='m'; fifo_file[ 3]='p'; fifo_file[ 4]='/'; fifo_file[ 5]='x'; fifo_file[ 6]='m'; fifo_file[ 7]='m'; fifo_file[ 8]='s'; fifo_file[ 9]='-'; fifo_file[10]='i'; fifo_file[11]='n'; fifo_file[12]='f'; fifo_file[13]='o'; fifo_file[14]='-'; fifo_file[21]= 0 ; fifo_file[15]='X'; fifo_file[16]='X'; fifo_file[17]='X'; fifo_file[18]='X'; fifo_file[19]='X'; fifo_file[20]='X'; create_tmp_fifo(fifo_file); //this creates the tmp file and symlink int status=1; ifd = open(fifo_file, O_RDWR ); //this blocks until at least one writer also opens the fifo #define MinBufSize 256 int bufsize=MinBufSize; char *b=malloc(bufsize); if(b==NULL) { perror("Unable to malloc() a buffer"); } char *index=b; int spaceleft=bufsize-1; int inputlen=0; b[bufsize-1]=0; //we keep this as an eos marker while(status!=0) { while(strchr(b,'\n')==NULL) { //until (at least one) command is present int r=read(ifd,index,spaceleft); if(r<=0) { // Read failed // perror("xmms-infopipe: error while reading from fifo"); xmms_quit(); } if(spaceleft-r==0){ //enlarge buffer when neccesary b=(char *)realloc(b,bufsize<<1); if(b==NULL) { fprintf(stderr,"xmms-infopipe: Bufferoverflow exploits won't work here buddy :)\n"); perror("malloc()"); break; } bufsize=bufsize<<1; } inputlen=inputlen+r; spaceleft=bufsize-1-inputlen; index=b+inputlen; } b[inputlen]=0; /* I hereby formally assert that this assignment is safe and willnot overwrite valuable data */ /* b either is NULL or is a valid buffer containing a newline and terminated with an \0*/ if(b!=NULL) { int f,l; char *old=b; char *newline=strchr(b,'\n'); while(newline!=NULL) { if(newline-b > 2 && b[0]=='0' && b[1]==':') { char *q=malloc(newline-b-1); if(q==NULL) { perror("xmms-infopipe: char *q=malloc(newline-b-1)"); xmms_quit; } *newline=0; memcpy(q,b+2,newline-b-1); if(thread_count < 127) { thread_count++; if(pthread_create(&blasterhandler, &attr , (void *)&info_blaster_thread, q) != 0) { // Recycles blaster, is this ok? perror("xmms-infopipe: While starting info_blaster_thread"); free(q); q=NULL; } } else { printf("xmms-infopipe: WARNING: to many pending requests\n"); free(q) ; q=NULL; } } if((newline-b==1 ) && b[0]=='1') { printf("xmms-infopipe: There are currently %i requests pending.\n",thread_count); } newline++; b=newline; newline=strchr(b,'\n'); } /* Clean up buffer as far as we've used it */ int left=inputlen-(b-old); int x=1; while(x<=left){ x=x<<1; } if(x