/* signatured * Daemon to supply random signatures for email front ends with a static part * using a named pipe * * usage: * signatured [-va] [-p named_pipe_name] -i id_file.txt -f signatures.txt * * where * -v is verbose (-vv is more verbose) * -a is 'advertisement', which is appending a line about signatured * -p is the name of the named pipe (e.g. /etc/signature), * default is 'asignature' in the current directory * -i is the text file containing the persistent part displayed first * (mostly this is your name and your company or things like that) * -f is the signature database which is in the form: * * [one or more lines signature] * % <-- this is '%\n' in a line itself * [one or more lines second signature] * .... * * you can use the files of fortune(1) (usual in /usr/share/fortune) as * signature files, if you don't care a fuck about RFC 1855 :) * * FX * $Id: sigd.c,v 1.6 2000/05/17 09:56:50 fx BETA1 fx $ */ #include #include #include #include #include #include #include #include #include #include #include /* syntax definitions */ #define BREAK_LINE "%\n" /* the usual 'plase overflow me' buffer shit */ #define BUF_SIZE 1024 #define DEFAULT_NAME "asignature" #define ADVERT "[signatured, http://www.phenoelit.de/stuff/signatured.c]\n" typedef struct { char *text; void *next; } sigindex_t; /* these have to be global */ sigindex_t *anchor =NULL; unsigned int sigcount =0; char *pipe_name =NULL; /* configuration */ char *base_file_name =NULL; char *id_file_name =NULL; FILE *id_file =NULL; int advertisement; int verbose; void sighandler(int s); char *randomsig(void); void index_basefile(char *name); void usage(char *me) { printf("usage: %s [-va] [-p pipename] -i idfile.txt -f database.txt\n", me); exit (1); } int main(int argc, char **argv) { /* for the named pipe */ FILE *npipe; char *idstr; /* the persistent part */ int pid; /* stuff for command line */ char option; struct stat statbuf; extern char *optarg; /* sleeping data ;) */ struct timespec nanot = {0,100000}; while ((option=getopt(argc,argv,"vap:f:i:"))!=EOF) { switch (option) { case 'a': advertisement++; break; case 'v': verbose++; break; case 'i': if ((id_file_name= (char *)malloc(strlen(optarg)+1))==NULL) { fprintf(stderr,"malloc() failed\n"); exit(1); } memset(id_file_name,0,strlen(optarg)+1); strcpy(id_file_name,optarg); break; case 'f': if (stat(optarg,&statbuf)!=0) { perror("stat()"); fprintf(stderr,"unable to stat() base file\n"); exit (1); } if ((base_file_name=(char*)malloc(strlen(optarg)+1)) ==NULL) { fprintf(stderr,"malloc() failed\n"); exit(1); } memset(base_file_name,0,strlen(optarg)+1); strcpy(base_file_name,optarg); break; case 'p': if ((pipe_name=(char *)malloc(strlen(optarg)+1))==NULL) { fprintf(stderr,"malloc() failed\n"); exit(1); } memset(pipe_name,0,strlen(optarg)+1); strcpy(pipe_name,optarg); break; default: fprintf(stderr,"unknown option\n"); usage(argv[0]); } } /* check for required options */ if (!id_file_name) { fprintf(stderr,"You have to supply an ID file\n"), usage(argv[0]); } if (!base_file_name) { fprintf(stderr,"You have to supply a signatures file\n"), usage(argv[0]); } /* check for optional commandline stuff */ if (!pipe_name) { if ((pipe_name=(char *)malloc(strlen(DEFAULT_NAME)+1))==NULL) { fprintf(stderr,"malloc() failed\n"); exit(1); } memset(pipe_name,0,strlen(DEFAULT_NAME)+1); strcpy(pipe_name,DEFAULT_NAME); } /* read the persistent part */ memset(&statbuf,0,sizeof(statbuf)); stat(id_file_name,&statbuf); if ((idstr=(char *)malloc(statbuf.st_size+1))==NULL) { fprintf(stderr,"malloc() failed for ID\n"); exit (1); } if ((id_file=fopen(id_file_name,"rt"))==NULL) { perror("fopen()"); fprintf(stderr,"unable to open ID file\n"); exit(1); } if (fread(idstr,statbuf.st_size,sizeof(char),id_file)>0) { if (verbose) printf("Persistent signature is:\n%s\n",idstr); } else { if (verbose) printf("Persistent signature is empty\n"); /* make sure we know later that this is empty */ free(idstr); idstr=NULL; } fclose(id_file); /* we index the base file to get a number of available * signatures */ index_basefile(base_file_name); /* set the umask explicitly, you don't know where it's been */ umask(0); /* create named pipe */ if (mkfifo(pipe_name, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) { perror("mkfifo"); exit(-1); } /* make me daemon, baby */ if ((pid=fork())<0) { perror("fork()"); exit (1); } /* the parent terminates here */ if (pid) { if (verbose) printf("Daemon started (PID %d)\n",pid); exit (0); } /* register with syslog(3) */ openlog(argv[0],LOG_PID,LOG_DAEMON); syslog(LOG_NOTICE,"started"); /* assign the signal handler */ signal(SIGINT,&sighandler); signal(SIGTERM,&sighandler); signal(SIGABRT,&sighandler); /* this should be random enough */ srand((unsigned int)time(NULL)); /* main server loop: * opening a named pipe for write is blocking while nobody reads from it */ for (;;) { if ((npipe=fopen(pipe_name,"wt"))==NULL) { perror("fopen"); exit(1); } /* write persitent part if any */ if (idstr) fprintf(npipe,"%s",idstr); /* write random part */ fprintf(npipe,"%s",randomsig()); /* make the ad if desired */ if (advertisement) fprintf(npipe,"%s",ADVERT); fclose(npipe); /* not ALL the CPU power is mine */ nanosleep(&nanot,NULL); if (verbose) syslog(LOG_NOTICE,"served a signature"); } /* not reached but makes gcc happy */ return 0; } void sighandler(int s) { sigindex_t *current =NULL; current=anchor; while(current!=NULL) { anchor=current; current=current->next; if (anchor->text) free(anchor->text); free(anchor); } syslog(LOG_NOTICE,"terminating"); unlink(pipe_name); closelog(); exit(0); } char *randomsig(void) { unsigned int sign=0; int i=0; sigindex_t *current=NULL; /* this is from the rand(3) man page */ sign=(unsigned int)((float)sigcount*rand()/(RAND_MAX+1.0)); if (verbose) syslog(LOG_NOTICE,"Use random number %d",sign); /* search this signature in list */ current=anchor; while (current!=NULL) { if (i==sign) break; current=current->next; i++; } /* check if we are out of range */ if (!current) { syslog(LOG_ERR,"fatal: random number not in list range"); sighandler(0); } return (current->text); } void index_basefile(char *name) { FILE *bf; char *buf; char *onesig =NULL; int linec=0; sigindex_t *current =NULL; #define APPEND_LL if ((current->next=(sigindex_t *)\ malloc(sizeof(sigindex_t)))==NULL) { \ fprintf(stderr,"malloc() failed in LL\n"); \ exit(-1); } else { current=current->next; current->next=NULL; } /* prepare the linked list */ if ((anchor=(sigindex_t *)malloc(sizeof(sigindex_t)))==NULL) { fprintf(stderr,"malloc() failed\n"); exit(1); } current=anchor; current->text=NULL; current->next=NULL; if ((bf=fopen(name,"rt"))==NULL) { perror("fopen()"); fprintf(stderr,"unable to open base file"); exit (1); } if ((buf=(char *)malloc(BUF_SIZE+1))==NULL) { fprintf(stderr,"malloc() failed\n"); exit(1); } memset(buf,0,BUF_SIZE+1); sigcount=0; while (fgets(buf,BUF_SIZE,bf)!=NULL) { if (!strcmp(buf,BREAK_LINE)) { /* make sure the was a signature befor the first seperator */ if (!onesig) continue; sigcount++; /* if the current->text stuff is empty, use this */ if (current->text) APPEND_LL; /* copy the actual onesig buffer to current->text */ if ((current->text=(char *)malloc(strlen(onesig)+1))==NULL) { fprintf(stderr,"malloc() failed!"); sighandler(0); } memset(current->text,0,strlen(onesig)+1); strcpy(current->text,onesig); free(onesig); onesig=NULL; /* seems necessary */ if (verbose) printf("signature %d ends at line %d\n",sigcount,linec+1); if (verbose>1) printf("signature is:\n%s----\n",current->text); } else { if (onesig) { if ((onesig=realloc(onesig,strlen(onesig)+strlen(buf)+1)) ==NULL) { fprintf(stderr,"realloc() failed!"); sighandler(0); } } else { if ((onesig=malloc(strlen(buf)+1))==NULL) { fprintf(stderr,"malloc() failed!"); sighandler(0); } memset(onesig,0,strlen(buf)+1); } strcat(onesig,buf); if (verbose>2) printf("DEBUG: onesig is now:\n%s",onesig); } linec++; memset(buf,0,BUF_SIZE+1); } /* may be someone has not terminted the last signature * let us be nice and add this one too*/ if (onesig) { sigcount++; /* if the current->text stuff is empty, use this */ if (current->text) APPEND_LL; /* copy the actual onesig buffer to current->text */ if ((current->text=(char *)malloc(strlen(onesig)+1))==NULL) { fprintf(stderr,"malloc() failed!"); sighandler(0); } strcpy(current->text,onesig); free(onesig); if (verbose) printf("signature %d ends at line %d\n",sigcount,linec+1); if (verbose>1) printf("signature is:\n%s----\n",current->text); } free(buf); fclose(bf); }