#ifndef LINT static char *rcsid="$Id: serv_common.c,v 1.17 2001/09/20 05:56:39 crosser Exp $"; #endif /* $Log: serv_common.c,v $ Revision 1.17 2001/09/20 05:56:39 crosser chroot() for whosond Revision 1.16 1999/10/06 15:54:03 crosser fix for kluge about initializing private fields Initialization for global parameters Revision 1.15 1999/10/03 21:18:03 crosser First (probably) working version with new run time config parser. Also added listenq parameter (backlog size for listen()) and renamed wtest to whoson (and with man page). Release 2.00beta1. Revision 1.14 1999/10/02 21:29:30 crosser work in progress on rtconfig Revision 1.13 1999/07/27 17:17:18 crosser remove include version.h Revision 1.12 1998/07/26 20:17:39 crosser LIST command Revision 1.11 1998/07/26 14:06:40 crosser stupid change made by mistake Revision 1.10 1998/07/12 16:43:57 crosser Change protocol: responce now is terminated with empty line Revision 1.9 1998/07/05 00:26:18 crosser Change copyright Revision 1.8 1998/07/05 00:01:27 crosser add user and group global parms Revision 1.7 1998/07/02 18:17:12 crosser make expiry work again Revision 1.6 1998/07/02 18:01:15 crosser change API Revision 1.5 1998/07/02 15:37:07 crosser make right responce if req invalid Revision 1.4 1998/07/01 20:01:05 crosser fix chain corruption when replacing Revision 1.3 1998/07/01 08:04:58 crosser Use lhash, make global pseudo-server Revision 1.2 1998/07/01 05:18:09 crosser minor warnings fix Revision 1.1 1998/07/01 05:01:22 crosser Initial revision Revision 1.3 1998/05/05 19:08:16 crosser allow multiline entry (and ignore) Revision 1.2 1998/04/29 10:02:21 crosser fix TODO list Revision 1.1 1998/04/28 18:37:21 crosser Initial revision */ /* WHAT IS IT: Implementation of experimental "whoson" protocol AUTHOR: Eugene G. Crosser COPYRIGHT: Public domain */ #include "config.h" #include #include #include #include #include #include #include #include #include #include "lhash.h" #include "whosond.h" #include "serv_common.h" #include "rtconfig.h" #include "report.h" #include "rtc_begin.h" #include "serv_common_cfg.h" #include "rtc_middle.h" #include "serv_common_cfg.h" #include "rtc_end.h" #define MAXREQL 1024 #define MAXADDR 32 #define MAXNAME 128 #define CACHESIZE 999999999L #define TTL 300 /* ttl is 5 min by default; may set in global section */ char *newroot=NULL; uid_t runuid=0; gid_t rungid=0; unsigned long cachesize; unsigned long incache=0L,maxcache=0L; time_t starttime; struct timeval oldtime; double intvl1=0L,intvl2=0L,intvl3=0L; unsigned long requests=0L; static int ttl; typedef struct _crec { struct _crec *next; struct _crec *prev; time_t ttl; char addr[MAXADDR]; char name[MAXNAME]; } crec_t; static crec_t *first=NULL,*last=NULL; static time_t now; static LHASH *chash=(LHASH*)0; static unsigned long ch_hash(crec_t *entry1) { return lh_strhash(entry1->addr); } static int ch_cmp(crec_t *entry1,crec_t *entry2) { return strcmp(entry1->addr,entry2->addr); } static char *do_login(char *arg1,char *arg2) { crec_t *newrec,*tmp; if (!*arg1) return "*LOGIN addr-spec required"; if (incache >= cachesize) return "-LOGIN Too many entries"; if ((newrec=(crec_t*)malloc(sizeof(crec_t))) == NULL) return "-LOGIN no memory for the new entry"; strncpy(newrec->addr,arg1,MAXADDR); strncpy(newrec->name,arg2,MAXNAME); if ((tmp=(crec_t*)lh_insert(chash,(char*)newrec))) { incache--; DPRINT(("replacing \"%s\" -> \"%s\" with \"%s\" -> \"%s\"\n", tmp->addr,tmp->name,newrec->addr,newrec->name)) if (tmp->next) tmp->next->prev=tmp->prev; else last=tmp->prev; if (tmp->prev) tmp->prev->next=tmp->next; else first=tmp->next; free(tmp); } incache++; if (incache > maxcache) maxcache=incache; newrec->next=NULL; newrec->prev=last; newrec->ttl=now+ttl; if (last) { last->next=newrec; last=newrec; } else { first=last=newrec; } return "+LOGIN OK"; } static char *do_logout(char *arg1,char *arg2) { crec_t *tmp,dummy_entry; if (!*arg1) return "*LOGOUT addr-spec required"; strncpy(dummy_entry.addr,arg1,sizeof(dummy_entry.addr)-1); dummy_entry.addr[sizeof(dummy_entry.addr)-1]='\0'; tmp=(crec_t*)lh_delete(chash,(char*)&dummy_entry); if (tmp) { incache--; if (tmp->next) tmp->next->prev=tmp->prev; else last=tmp->prev; if (tmp->prev) tmp->prev->next=tmp->next; else first=tmp->next; free(tmp); return "+LOGOUT record deleted"; } return "+LOGOUT no such record, nothing done"; } static char *do_query(char *arg1,char *arg2) { crec_t *tmp,dummy_entry; static char buf[MAXNAME+4]; if (!(*arg1)) return "*QUERY addr-spec required"; if (*arg2) return "*QUERY only one argument allowed"; strncpy(dummy_entry.addr,arg1,sizeof(dummy_entry.addr)-1); dummy_entry.addr[sizeof(dummy_entry.addr)-1]='\0'; tmp=(crec_t*)lh_retrieve(chash,(char*)&dummy_entry); if (tmp) { buf[0]='+'; strncpy(buf+1,tmp->name,MAXNAME); buf[MAXNAME+1]='\0'; return buf; } return "-Not logged in"; } static char *do_cmd(char *verb,char *arg1,char *arg2) { static char buf[512]; sprintf(buf," version %s build %s\r\n",VERSION,__DATE__); sprintf(buf+strlen(buf)," running from %s total %lu requests, cache now %lu, max %lu\r\n", asctime(localtime(&starttime)), requests, incache, maxcache); sprintf(buf+strlen(buf)," load %10.3f %10.3f %10.3f %10.3f", 1.0e+6/intvl1, 1.0e+6/intvl2, 1.0e+6/intvl3, (double)requests/(now-starttime)); return buf; } static void do_cleanup(void) { crec_t *prev; while (first) { if (first->ttl > now) break; DPRINT(("expiring \"%s\" -> \"%s\"\n", first->addr,first->name)) prev=first; first=first->next; if (first) first->prev=NULL; (void)lh_delete(chash,(char*)prev); free(prev); incache--; } if (!first) last=NULL; } void do_request(char *req,char *retbuf,int retsize) { char buf[MAXREQL]; char *p,*endb,*verb,*arg1,*arg2,*rc; struct timeval cmdtime; unsigned long intvl; gettimeofday(&cmdtime,NULL); (void)time(&now); intvl=(cmdtime.tv_sec-oldtime.tv_sec)*1000000+ (cmdtime.tv_sec-oldtime.tv_sec); intvl1=intvl*100.0e-3+intvl1*900.0e-3; intvl2=intvl*010.0e-3+intvl2*990.0e-3; intvl3=intvl*001.0e-3+intvl3*999.0e-3; oldtime=cmdtime; requests++; strncpy(buf,req,sizeof(buf)-1); buf[sizeof(buf)-1]='\0'; if ((endb=strchr(buf,'\n'))) *endb='\0'; if ((endb=strchr(buf,'\r'))) *endb='\0'; if (endb) while (isspace(*(endb-1))) *(--endb)='\0'; else endb=buf+sizeof(buf)-1; DPRINT(("Got: \"%s\"\n",buf)) p=buf; while (pttl; if (ttl == 0) ttl=TTL; cachesize=rec->cachesize; if (cachesize == 0) cachesize=CACHESIZE; if (rec->chroot) newroot=rec->chroot; if ((rec->user) && ((pw=getpwnam(rec->user)))) { runuid=pw->pw_uid; if (!rungid) rungid=pw->pw_gid; } else { ERRLOG((LOG_ERR,"bad user name \"%s\"", rec->user?rec->user:"(null)")) } if ((rec->group) && ((gr=getgrnam(rec->group)))) { rungid=gr->gr_gid; } else { ERRLOG((LOG_ERR,"bad group name \"%s\"", rec->group?rec->group:"(null)")) } chash=lh_new(ch_hash,ch_cmp); (void)time(&starttime); gettimeofday(&oldtime,NULL); memset(&evdesc,0,sizeof(struct _evdesc)); evdesc.fd=-1; return evdesc; }