/* area manager for gtic, experimental, 17 March 1998 updated 27 May 1998 accepts standard rfc message via stdin should be sgid to somegroup for writing to areas_file and users_file [also read INSTALL file please] usually called by MTA from /etc/aliases: filefix: "|/path/gtic -m" */ #include #include #include "config.h" void swap_uid_gid(); void area_manager(void) { node_t addr; char *from=NULL,*subj=NULL,*ftn,*ro_ftn,*tmp,*p,*real_address=NULL; user_t *user; int i; list_t *ltmp; area_t *atmp; int strtonode_res; FILE *resp_fp,*help_fp; char buff[BUFSIZE]; /* find From and Subject */ while(1) { if(fgets(buff,sizeof(buff)-1,stdin)==NULL) break; delcrlf(buff); /* accept correct RFC message - \n at end of headers */ if(buff[0]==0) break; if(!strncmp(buff,"From: ",6)) { if(!from) { if(strchr(buff,'<') && strchr(buff,'>')) { from=xstrcpy(strchr(buff,'<')+1); if(strchr(from,'>')) strchr(from,'>')[0]=0; } else { from=xstrcpy(buff+6); } } } else if(!strncmp(buff,"Subject: ",9)) { subj=xstrcpy(buff+9); subj=xstrcpy(strtok(buff+9," \t")); /* xstrcpy return NULL when parameter is NULL -> all ok */ real_address=xstrcpy(strtok(NULL," \t")); /* TODO: work with non-RFC address here! */ /* break; don't break here */ } } if(from==NULL) { l_printf("no From in area_manager"); return; } if(subj==NULL) { l_printf("no Subject in area_manager (From=%s)",from); /* TODO: write response about "no subject" here */ return; } /* determine rfc-ftn-address and convert it to ftn-address */ if(strchr(from,'@')==NULL && strchr(from,'!')==NULL) { /* TODO: work with $HOSTNAME here */ l_printf("incorrect address in area_manager (From=%s)",from); return; } if(real_address==NULL) { if(strchr(from,'@')) real_address=strchr(from,'@')+1; else real_address=strchr(from,'!')+1; } if((strtonode_res=strtonode(&addr,real_address,NULL))!=0) { l_printf("parse error in address \"%s\" (%d)\n", from,strtonode_res); /* return; */ } /*printf("DBG: %d:%d/%d.%d\n",addr.zone,addr.net,addr.node,addr.point); */ ftn=xstrcpy(nodetoftn(NULL,&addr)); ro_ftn=xstrcat("!",xstrcpy(ftn)); if(response_exec) { tmp=xstrcpy(response_exec); tmp=xstrcat(tmp," \""); tmp=xstrcat(tmp,from); tmp=xstrcat(tmp,"\""); /*printf("DBG: tmp=%s\n",tmp); */ swap_uid_gid(); resp_fp=popen(tmp,"w"); swap_uid_gid(); if(resp_fp==NULL) { /* TODO: maybe process query with resp_fp == NULL */ e_printf("unable to popen(%s)",tmp); return; } } fprintf(resp_fp,"Subject: gtic response\n\n"); l_printf("area_manager: processing %s (%s)",ftn,from); if(resp_fp) fprintf(resp_fp,"gtic response for \"%s\" (%s)\n\n",from,ftn); user=list_find_entry(users,ftn); if(user==NULL) { if(resp_fp) fprintf(resp_fp,"sorry, you absent in our users list\n"); l_printf("link absent in users_file"); } else if(!strcmp(user->passwd,"*")) { if(resp_fp) fprintf(resp_fp,"sorry, but you rejected from area manager\n"); l_printf("link has \"*\" password - rejected"); } else if(strcasecmp(user->passwd,subj)) { if(resp_fp) fprintf(resp_fp,"sorry, your password is incorrect\n"); l_printf("link give incorrect password"); } else { if(resp_fp) { fprintf(resp_fp,"Your current status is: "); write_flag_tab_to_FILE(resp_fp,user->flags, (struct flag_tab*)&user_flag_tab); fprintf(resp_fp,"\n\n"); } while(1) { if(fgets(buff,sizeof(buff)-1,stdin)==NULL) break; delcrlf(buff); if(buff[0]==0) continue; if(strncmp(buff,"--",strlen("--"))==0) break; /* FIXME ? ;-) */ /* skip Message-ID: and X-FTN-* and some ... FIXME (fixed ;-) if(strncmp(buff,"Message-ID: ",strlen("Message-ID: "))==0) continue; if(strncmp(buff,"X-FTN-",strlen("X-FTN-"))==0) continue; if(strncmp(buff,"In-Reply-To:",strlen("In-Reply-To:"))==0) continue; */ /* HELP */ if(strcasecmp(buff,"%HELP")==0) { if(resp_fp) fprintf(resp_fp,"> %%HELP\n"); if(help_file==NULL) { l_printf("%%HELP - help_file not defined in config"); if(resp_fp) fprintf(resp_fp,"sorry, help file not available on server\n"); } else { l_printf("%%HELP"); if(resp_fp) { help_fp=fopen(help_file,"rb"); if(help_fp==NULL) { l_printf("%%HELP - unable to open help_file"); fprintf(resp_fp,"sorry, unable to open help file on server\n"); } else { /* yes, we can use buff here */ while(fgets(buff,sizeof(buff)-1,help_fp)!=NULL) { /* help_fp may contain text in DOS format, need to convert to * UNIX format. */ delcrlf(buff); fprintf(resp_fp,"%s\n",buff); } fclose(help_fp); } } } } /* PAUSE */ else if(strcasecmp(buff,"%PAUSE")==0) { l_printf("%%PAUSE"); if(resp_fp) fprintf(resp_fp,"> %%PAUSE\nok\n"); user->flags|=USER_PAUSE; } /* RESUME */ else if(strcasecmp(buff,"%RESUME")==0) { l_printf("%%RESUME"); if(resp_fp) fprintf(resp_fp,"> %%RESUME\nok\n"); user->flags&=~USER_PAUSE; } /* PASSWD */ else if(strncasecmp(buff,"%PASSWD",7)==0) { l_printf("%%PASSWD"); if(resp_fp) fprintf(resp_fp,"> %%PASSWD\n"); p=strschr(buff," \t"); if(p) { if(user->passwd) xfree(user->passwd); user->passwd=xstrcpy(p); if(resp_fp) fprintf(resp_fp,"ok\n"); } else { l_printf("EMPTY %%PASSWD string"); if(resp_fp) fprintf(resp_fp,"failed, empty password not allowed\n"); } } /* LINKED */ else if(strcasecmp(buff,"%LINKED")==0) { l_printf("%%LINKED"); if(resp_fp) fprintf(resp_fp,"> %%LINKED\n"); if(resp_fp) fprintf(resp_fp,"%-20s %-6s %-10s %s\n", "AREA","WRITE","GROUP","DESCRIPTION"); if(resp_fp) fprintf(resp_fp,"%-20s %-6s %-10s %s\n", "----","-----","-----","-----------"); for(i=0;iusers; ass(ltmp!=NULL); if(list_find(ltmp,ftn)) { l_printf("[%s]",atmp->name); if(resp_fp) { fprintf(resp_fp,"%-20s %-6s %-10s %s\n", atmp->name,"yes",atmp->group?atmp->group:"", atmp->desc?atmp->desc:""); } } else if(list_find(ltmp,ro_ftn)) { l_printf("[%s]",atmp->name); if(resp_fp) { fprintf(resp_fp,"%-20s %-6s %-10s %s\n",atmp->name, "",atmp->group?atmp->group:"",atmp->desc?atmp->desc:""); } } } } /* LIST and UNLINKED */ else if(strcasecmp(buff,"%LIST")==0 || strcasecmp(buff,"%UNLINKED")==0) { int fulllist,linked_mode; linked_mode=0; /* 0 - unlinked, 1 - readonly, 2 - readwrite */ fulllist=strcasecmp(buff,"%LIST")?0:1; l_printf("%s",fulllist?"%LIST":"%UNLINKED"); if(resp_fp) fprintf(resp_fp,"> %s\n",fulllist?"%LIST":"%UNLINKED"); if(resp_fp) fprintf(resp_fp,"%-20s %-6s %-10s %s\n", "AREA","WRITE","GROUP","DESCRIPTION"); if(resp_fp) fprintf(resp_fp,"%-20s %-6s %-10s %s\n", "----","-----","-----","-----------"); for(i=0;iusers; ass(ltmp!=NULL); linked_mode=list_find(ltmp,ro_ftn)?1:0; if(linked_mode==0) linked_mode=list_find(ltmp,ftn)?2:0; if(fulllist==0 && linked_mode!=0) continue; if(validate_group(atmp,user)==FALSE) continue; l_printf("[%s]",atmp->name); if(resp_fp) { fprintf(resp_fp,"%-20s %-6s %-10s %s\n", atmp->name,linked_mode==2?"yes":linked_mode==1?"": atmp->flags&AREA_READONLY?"":"yes",atmp->group?atmp->group:"", atmp->desc?atmp->desc:""); } } } /* unlink from area */ else if(buff[0]=='-') { l_printf("%s",buff); if(resp_fp) fprintf(resp_fp,"> %s\n",buff); atmp=list_find_entry(areas,buff+1); if(atmp==NULL) { l_printf("not found",buff); if(resp_fp) fprintf(resp_fp,"area not found\n"); continue; } ltmp=atmp->users; ass(ltmp!=NULL); if(list_find(ltmp,ftn) || list_find(ltmp,ro_ftn)) { if(list_find(ltmp,ftn)) list_remove(ltmp,ftn); else if(list_find(ltmp,ro_ftn)) list_remove(ltmp,ro_ftn); if(resp_fp) fprintf(resp_fp,"unlinked\n"); } else { l_printf("don't connected"); if(resp_fp) fprintf(resp_fp,"you don't connected to this area\n"); } } else /* link to area */ { l_printf("%s",buff); if(resp_fp) fprintf(resp_fp,"> %s\n",buff); atmp=list_find_entry(areas,buff[0]=='+'?buff+1:buff); if(atmp==NULL) { l_printf("not found",buff); if(resp_fp) fprintf(resp_fp,"area not found\n"); continue; } if(validate_group(atmp,user)==FALSE) { l_printf("invalid group",buff); if(resp_fp) fprintf(resp_fp,"access violation\n"); continue; } ltmp=atmp->users; ass(ltmp!=NULL); if(list_find(ltmp,ftn) || list_find(ltmp,ro_ftn)) { l_printf("already connected",buff); if(resp_fp) fprintf(resp_fp,"already connected\n"); continue; } if(atmp->flags & AREA_READONLY) { /* link readonly */ list_add(ltmp,ro_ftn,user); l_printf("(readonly)"); if(resp_fp) fprintf(resp_fp,"connected in readonly mode\n"); } else { /* link read-write */ list_add(ltmp,ftn,user); l_printf("(read-write)"); if(resp_fp) fprintf(resp_fp,"connected in read-write mode\n"); } } } } if(resp_fp) pclose(resp_fp); }