/* vi: set ts=4 sw=4 ai: */ /* * boots.c * * Lotos v1.2.3 : (c) 1999-2003 Pavol Hluchy (Lopo) * last update : 30.1.2003 * email : lotos@losys.sk * homepage : lotos.losys.sk */ #ifndef __BOOTS_C__ #define __BOOTS_C__ 1 #include <stdlib.h> #include <stdio.h> #include <sys/stat.h> #include <sys/utsname.h> #include <time.h> #include <fcntl.h> #include <netinet/in.h> #include <sys/socket.h> #include <signal.h> #include <dirent.h> #include <string.h> #include <ctype.h> #include <unistd.h> #include "define.h" #include "obj_ur.h" #include "obj_rm.h" #include "obj_tr.h" #ifdef NETLINKS #include "obj_nl.h" #endif #include "obj_sys.h" #include "obj_pl.h" #include "obj_mc.h" #include "obj_syspp.h" #include "prototypes.h" #include "boots.h" #ifndef NUM_LEVELS #define NUM_LEVELS SIZEOF(user_level) #endif /*** Construct system object and reset some global variables ***/ void create_system(void) { int i; struct utsname uts; set_crash(); if ((amsys=(SYS_OBJECT)malloc(sizeof(struct system_struct)))==NULL) { fprintf(stderr,"Lotos: Failed to create system object in create_system().\n"); boot_exit(21); } amsys->auto_connect=1; amsys->max_users=50; amsys->max_clones=1; amsys->ban_swearing=0; amsys->heartbeat=2; amsys->keepalive_interval=60; /* DO NOT TOUCH!!! */ amsys->net_idle_time=300; /* Must be > than the above */ amsys->login_idle_time=180; amsys->user_idle_time=300; amsys->time_out_afks=0; amsys->wizport_level=WIZ; amsys->minlogin_level=-1; amsys->mesg_life=1; amsys->num_of_logins=0; amsys->logging=BIT_SET(amsys->logging,SYSLOG); amsys->logging=BIT_SET(amsys->logging,REQLOG); #ifdef NETLOG amsys->logging=BIT_SET(amsys->logging,NETLOG); #endif #ifdef DEBUG amsys->logging=BIT_SET(amsys->logging,DEBLOG); #endif amsys->logging=BIT_SET(amsys->logging,ERRLOG); amsys->password_echo=0; amsys->ignore_sigterm=0; amsys->crash_action=2; amsys->prompt_def=1; amsys->colour_def=1; amsys->charecho_def=0; amsys->time_out_maxlevel=USER; amsys->mesg_check_hour=0; amsys->mesg_check_min=0; amsys->rs_countdown=0; amsys->rs_announce=0; amsys->rs_which=-1; amsys->rs_user=NULL; amsys->gatecrash_level=GOD+1; /* minimum user level which can enter private rooms */ amsys->min_private_users=2; /* minimum num. of users in room before can set to priv */ amsys->ignore_mp_level=GOD; /* User level which can ignore the above var. */ amsys->rem_user_maxlevel=USER; amsys->rem_user_deflevel=USER; amsys->logons_old=0; amsys->logons_new=0; amsys->purge_count=0; amsys->purge_skip=0; amsys->users_purged=0; amsys->purge_date=1; amsys->suggestion_count=0; amsys->forwarding=1; amsys->auto_purge=0; amsys->user_count=0; amsys->auto_promote=1; amsys->personal_rooms=1; amsys->startup_room_parse=1; amsys->motd1_cnt=0; amsys->motd2_cnt=0; amsys->random_motds=1; amsys->last_cmd_cnt=0; amsys->resolve_ip=1; /* auto resolve ip */ amsys->flood_protect=1; amsys->pid=(unsigned int)getpid(); time(&amsys->boot_time); if ((uname(&uts))<0) { strcpy(amsys->sysname,"[undetermined]"); strcpy(amsys->sysmachine,"[undetermined]"); strcpy(amsys->sysrelease,"[undetermined]"); strcpy(amsys->sysversion,"[undetermined]"); strcpy(amsys->sysnodename,"[undetermined]"); } else { strncpy(amsys->sysname,uts.sysname,63); strncpy(amsys->sysmachine,uts.machine,63); strncpy(amsys->sysrelease,uts.release,63); strncpy(amsys->sysversion,uts.version,63); strncpy(amsys->sysnodename,uts.nodename,63); } user_first=NULL; user_last=NULL; room_first=NULL; room_last=NULL; /* This variable isn't used yet */ transport_first=NULL; transport_last=NULL; first_dir_entry=NULL; first_command=NULL; first_wiz_entry=NULL; last_wiz_entry=NULL; force_listen=0; no_prompt=0; logon_flag=0; for (i=0;i<port_total;i++) { port[i]=0; listen_sock[i]=0; } for (i=0;i<LASTLOGON_NUM;i++) { last_login_info[i].name[0]='\0'; last_login_info[i].time[0]='\0'; last_login_info[i].on=0; } for (i=0;i<16;i++) cmd_history[i][0]='\0'; clear_words(); #ifdef NETLINKS verification[0]='\0'; nl_first=NULL; nl_last=NULL; #endif strcpy(susers_restrict, RESTRICT_MASK); } /*** Initialise the signal traps etc ***/ void init_signals(void) { set_crash(); SIGNAL(SIGTERM,sig_handler); SIGNAL(SIGSEGV,sig_handler); SIGNAL(SIGBUS,sig_handler); SIGNAL(SIGILL,SIG_IGN); SIGNAL(SIGTRAP,SIG_IGN); SIGNAL(SIGIOT,SIG_IGN); SIGNAL(SIGTSTP,SIG_IGN); SIGNAL(SIGCONT,SIG_IGN); SIGNAL(SIGHUP,sig_handler); SIGNAL(SIGINT,SIG_IGN); SIGNAL(SIGQUIT,SIG_IGN); SIGNAL(SIGABRT,SIG_IGN); SIGNAL(SIGFPE,SIG_IGN); SIGNAL(SIGPIPE,SIG_IGN); SIGNAL(SIGTTIN,SIG_IGN); SIGNAL(SIGTTOU,SIG_IGN); } /****************************************************************************** The loading up and parsing of the configuration file *****************************************************************************/ void load_and_parse_config(void) { FILE *fp; char line[256+1]; /* Should be long enough */ char fname[FNAME_LEN], c; int i,section_in=0,got_init=0,got_rooms=0,got_topics=0, got_transport=0; RM_OBJECT rm1,rm2; #ifdef NETLINKS NL_OBJECT nl; #endif set_crash(); printf("Parsing config file \"%s\"...\n", confile); if (!(fp=fopen(confile,"r"))) { perror("Lotos: Can't open config file\n"); boot_exit(1); } /* Main reading loop */ config_line=0; fgets(line,81,fp); while (!feof(fp)) { config_line++; for(i=0;i<8;++i) wrd[i][0]='\0'; sscanf(line,"%s %s %s %s %s %s %s %s",wrd[0],wrd[1],wrd[2],wrd[3],wrd[4],wrd[5],wrd[6],wrd[7]); if (wrd[0][0]=='#' || wrd[0][0]=='\0') { fgets(line,81,fp); continue; } /* See if new section */ if (wrd[0][strlen(wrd[0])-1]==':') { if (!strcmp(wrd[0],"INIT:")) section_in=1; else if (!strcmp(wrd[0],"ROOMS:")) section_in=2; else if (!strcmp(wrd[0],"TOPICS:")) section_in=3; else if (!strcmp(wrd[0],"SITES:")) section_in=4; else if (!strcmp(wrd[0],"TRANSPORTS:")) section_in=5; else { fprintf(stderr, "Lotos: Unknown section header on line %d.\n",config_line); fclose(fp); boot_exit(1); } } switch (section_in) { case 1: parse_init_section(); got_init=1; break; case 2: parse_rooms_section(); got_rooms=1; break; case 3: parse_topics_section(remove_first(line)); got_topics=1; break; case 4: #ifdef NETLINKS parse_sites_section(); break; #else break; #endif case 5: parse_transports_section(); got_transport=1; break; default: fprintf(stderr,"Lotos: Section header expected on line %d.\n",config_line); fclose(fp); boot_exit(1); } fgets(line,81,fp); } fclose(fp); /* See if required sections were present (SITES and TOPICS is optional) and if required parameters were set. */ if (!got_init) { fprintf(stderr,"Lotos: INIT section missing from config file.\n"); boot_exit(1); } if (got_topics && !got_rooms) { fprintf(stderr,"Lotos: TOPICS section must come after ROOMS section in the config file.\n"); boot_exit(1); } if (got_transport && !got_rooms) { fprintf(stderr,"Lotos: TRANSPORTS section must come after ROOMS section in the config file.\n"); boot_exit(1); } if (got_topics && !got_transport) { fprintf(stderr,"Lotos: TOPICS section must come after TRANSPORTS section in the config file.\n"); boot_exit(1); } if (!got_rooms) { fprintf(stderr,"Lotos: ROOMS section missing from config file.\n"); boot_exit(1); } if (!got_transport) { fprintf(stderr,"Lotos: TRANSPORTS section missing from config file.\n"); boot_exit(1); } if (!port[0]) { fprintf(stderr,"Lotos: Main port number not set in config file.\n"); boot_exit(1); } if (!port[1]) { fprintf(stderr,"Lotos: Wiz port number not set in config file.\n"); boot_exit(1); } #ifdef NETLINKS if (!port[2]) { fprintf(stderr,"Lotos: Link port number not set in config file.\n"); boot_exit(1); } if (!verification[0]) { fprintf(stderr,"Lotos: Verification not set in config file.\n"); boot_exit(1); } if (port[0]==port[1] || port[1]==port[2] || port[0]==port[2] ) { #else if (port[0]==port[1]) { #endif fprintf(stderr,"Lotos: Port numbers must be unique.\n"); boot_exit(1); } if (room_first==NULL) { fprintf(stderr,"Lotos: No rooms configured in config file.\n"); boot_exit(1); } if (!syspp->auto_save) { fprintf(stderr,"Lotos: autosave period not set in config file.\n"); boot_exit(1); } if (syspp->auto_afk && syspp->auto_afk_time>=(amsys->user_idle_time-60)) { fprintf(stderr, "Lotos: Auto_afk_time musi byt vacsie ako user_idle_time-60.\n"); exit(1); } /* Parsing done, now check data is valid. Check room stuff first. */ for (rm1=room_first; rm1!=NULL; rm1=rm1->next) { if (rm1->transp!=NULL && rm1->link_label[1]=='\0') { fprintf(stderr, "Rooma %s je transport, preto musi mat minimalne 2 linky\n", rm1->name); boot_exit(1); } for (i=0;i<MAX_LINKS;++i) { if (!rm1->link_label[i][0]) break; if ((!strcmp(rm1->link_label[i], no_leave)) && (rm1->transp==NULL)) break; if ((!strcmp(rm1->link_label[i], no_leave)) && rm1->transp!=NULL) { fprintf(stderr,"Lotos: Rooma %s je transport, preto nemoze byt bez linkov\n", rm1->name); boot_exit(1); } for (rm2=room_first;rm2!=NULL;rm2=rm2->next) { if (rm1==rm2) continue; if (!strcmp(rm1->link_label[i],rm2->label)) { if (rm2->transp!=NULL) { fprintf(stderr,"Rooma %s nemoze byt nalinkovana na iny transport\n", rm1->name); boot_exit(1); } rm1->link[i]=rm2; break; } } if (rm1->link[i]==NULL) { fprintf(stderr,"Lotos: Room %s has undefined link label '%s'.\n",rm1->name,rm1->link_label[i]); boot_exit(1); } } } #ifdef NETLINKS /* Check external links */ for (rm1=room_first;rm1!=NULL;rm1=rm1->next) { if (rm1->netlink_name[0] && rm1->transp!=NULL) { fprintf(stderr, "Rooma %s je nadefinovana ako transport a preto nemoze mat netlink\n", rm1->name); boot_exit(1); } for (nl=nl_first;nl!=NULL;nl=nl->next) { if (!strcmp(nl->service,rm1->name)) { fprintf(stderr,"Lotos: Service name %s is also the name of a room.\n",nl->service); boot_exit(1); } if (rm1->netlink_name[0] && !strcmp(rm1->netlink_name,nl->service)) { rm1->netlink=nl; break; } } if (rm1->netlink_name[0] && rm1->netlink==NULL) { fprintf(stderr,"Lotos: Service name %s not defined for room %s.\n",rm1->netlink_name,rm1->name); boot_exit(1); } } #endif /* Load room descriptions */ for (rm1=room_first;rm1!=NULL;rm1=rm1->next) { if (rm1->transp!=NULL) sprintf(fname,"%s/%s.R", TRFILES, rm1->name); else sprintf(fname,"%s/%s.R", ROOMFILES, rm1->name); if (!(fp=fopen(fname,"r"))) { fprintf(stderr,"Lotos: Can't open description file for room %s.\n",rm1->name); write_syslog(ERRLOG,1,"Couldn't open description file for room %s.\n",rm1->name); continue; } i=0; c=getc(fp); while (!feof(fp)) { if (i==ROOM_DESC_LEN) { fprintf(stderr,"Lotos: Description too long for room %s.\n",rm1->name); write_syslog(ERRLOG,1,"Description too long for room %s.\n",rm1->name); break; } rm1->desc[i]=c; c=getc(fp); ++i; } rm1->desc[i]='\0'; fclose(fp); } } /*** Parse the user rooms ***/ void parse_user_rooms(void) { DIR *dirp; struct dirent *dp; char name[USER_NAME_LEN]; RM_OBJECT rm; if (!(dirp=opendir(USERROOMS))) { fprintf(stderr,"Lotos: Directory open failure in parse_user_rooms().\n"); boot_exit(19); } /* parse the names of the files but don't include . and .. */ while ((dp=readdir(dirp))!=NULL) { if (!strcmp(dp->d_name,".") || !strcmp(dp->d_name,"..")) continue; if (strstr(dp->d_name,".R")) { strcpy(name,dp->d_name); name[strlen(name)-2]='\0'; rm=create_room(); if (!(personal_room_store(name,0,rm))) { write_syslog(ERRLOG,1,"Could not read personal room attributes. Using standard config.\n"); } strtolower(name); sprintf(rm->name,"(%s)",name); } } closedir(dirp); } /*** Check to see if the directory structure in USERFILES is correct, ie, there is one directory for each of the level names given in *user_level[] Also, check if level names are unique. ***/ void check_directories(void) { struct stat stbuf; int levels,found,i,j; levels=found=0; /* Check for unique directory names */ for (i=0; i<NUM_LEVELS; ++i) { for (j=i+1; j<NUM_LEVELS; ++j) { if (!strcmp(user_level[i].name,user_level[j].name)) { fprintf(stderr,"Lotos: Level names are not unique.\n"); boot_exit(14); } } } i=0; /* check the directories needed exist */ if (stat(USERFILES, &stbuf)==-1) { fprintf(stderr,"Lotos: Directory stat failure in check_directories().\n"); boot_exit(15); } if ((stbuf.st_mode & S_IFMT)!=S_IFDIR) goto SKIP; if (stat(USERMAILS, &stbuf)==-1) { fprintf(stderr,"Lotos: Directory stat failure in check_directories().\n"); boot_exit(15); } if ((stbuf.st_mode & S_IFMT)!=S_IFDIR) goto SKIP; if (stat(USERPROFILES,&stbuf)==-1) { fprintf(stderr,"Lotos: Directory stat failure in check_directories().\n"); boot_exit(15); } if ((stbuf.st_mode & S_IFMT)!=S_IFDIR) goto SKIP; if (stat(USERFRIENDS,&stbuf)==-1) { fprintf(stderr,"Lotos: Directory stat failure in check_directories().\n"); boot_exit(15); } if ((stbuf.st_mode & S_IFMT)!=S_IFDIR) goto SKIP; if (stat(USERHISTORYS,&stbuf)==-1) { fprintf(stderr,"Lotos: Directory stat failure in check_directories().\n"); boot_exit(15); } if ((stbuf.st_mode & S_IFMT)!=S_IFDIR) goto SKIP; if (stat(USERCOMMANDS,&stbuf)==-1) { fprintf(stderr,"Lotos: Directory stat failure in check_directories().\n"); boot_exit(15); } if ((stbuf.st_mode & S_IFMT)!=S_IFDIR) goto SKIP; if (stat(USERMACROS,&stbuf)==-1) { fprintf(stderr,"Lotos: Directory stat failure in check_directories().\n"); boot_exit(15); } if ((stbuf.st_mode & S_IFMT)!=S_IFDIR) goto SKIP; if (stat(USERROOMS,&stbuf)==-1) { fprintf(stderr,"Lotos: Directory stat failure in check_directories().\n"); boot_exit(15); } if ((stbuf.st_mode & S_IFMT)!=S_IFDIR) goto SKIP; return; SKIP: fprintf(stderr,"Lotos: Directory structure is incorrect.\n"); boot_exit(16); } /*** Get all users from the user directories and add them to the user lists. If verbose mode is on, then attempt to get date string as well ***/ void process_users(void) { char name[USER_NAME_LEN+3]; DIR *dirp; struct dirent *dp; UR_OBJECT u; set_crash(); /* open the directory file up */ dirp=opendir(USERFILES); if (dirp==NULL) { fprintf(stderr,"Lotos: Directory open failure in process_users().\n"); boot_exit(12); } if ((u=create_user())==NULL) { fprintf(stderr,"Lotos: Create user failure in process_users().\n"); (void) closedir(dirp); boot_exit(17); } /* count up how many files in the directory - this include . and .. */ while((dp=readdir(dirp))!=NULL) { if (!strcmp(dp->d_name,".") || !strcmp(dp->d_name,"..")) continue; if (strstr(dp->d_name,".D")) { strcpy(name,dp->d_name); name[strlen(name)-2]='\0'; strcpy(u->name,name); if (load_user_details(u)) { add_user_node(u->name,u->level); if (u->level>=WIZ) add_wiz_node(u->name,u->level); add_user_date_node(u->name,u->date); } /* end if */ else { fprintf(stderr,"Lotos: Could not load userfile for '%s' in process_users().\n",name); (void) closedir(dirp); boot_exit(18); } } /* end if */ reset_user(u); } /* end while */ destruct_user(u); closedir(dirp); } /* Put commands in an ordered linked list for viewing with .help */ void parse_commands(void) { int cnt=0; set_crash(); while (command_table[cnt].name[0]!='*') { if (!(add_command(cnt))) { fprintf(stderr,"Lotos: Memory allocation failure in parse_commands().\n"); boot_exit(13); } ++cnt; } return; } /* needs only doing once when booting */ void count_suggestions(void) { char line[82],id[20]; FILE *fp; int valid=1; set_crash(); if (!(fp=fopen(SUGBOARD, "r"))) return; fgets(line,82,fp); while (!feof(fp)) { if (line[0]=='\n') valid=1; sscanf(line,"%s",id); if (valid && strstr(id,"From:")) { ++amsys->suggestion_count; valid=0; } fgets(line,82,fp); } fclose(fp); } /*** Initialise sockets on ports ***/ void init_sockets(void) { struct sockaddr_in bind_addr; int i,on,size; #ifdef NETLINKS printf("Initialising sockets on ports: %d, %d, %d\n",port[0],port[1],port[2]); #else printf("Initialising sockets on ports: %d, %d\n",port[0],port[1]); #endif on=1; size=sizeof(struct sockaddr_in); bind_addr.sin_family=AF_INET; bind_addr.sin_addr.s_addr=INADDR_ANY; for (i=0; i<port_total; ++i) { /* create sockets */ if ((listen_sock[i]=socket(AF_INET,SOCK_STREAM,0))==-1) boot_exit(i+2); /* allow reboots on port even with TIME_WAITS */ setsockopt(listen_sock[i],SOL_SOCKET,SO_REUSEADDR,(char *)&on,sizeof(on)); /* bind sockets and set up listen queues */ bind_addr.sin_port=htons(port[i]); if (bind(listen_sock[i],(struct sockaddr *)&bind_addr,size)==-1) boot_exit(i+5); if (listen(listen_sock[i],10)==-1) boot_exit(i+8); /* Set to non-blocking */ fcntl(listen_sock[i],F_SETFL,O_NDELAY); } } /*** Return level value based on level name ***/ int get_level(char *name) { int i; set_crash(); for (i=0; i<NUM_LEVELS; i++) { if (!strcasecmp(user_level[i].name, name)) return i; } return -1; } /*** Parse init section ***/ void parse_init_section(void) { static int in_section=0; int op,val,tmp; char *options[]={ "mainport","wizport","linkport","system_logging","minlogin_level","mesg_life", "wizport_level","prompt_def","gatecrash_level","min_private","ignore_mp_level", "rem_user_maxlevel","rem_user_deflevel","verification","mesg_check_time", "max_users","heartbeat","login_idle_time","user_idle_time","password_echo", "ignore_sigterm","auto_connect","max_clones","ban_swearing","crash_action", "colour_def","time_out_afks","charecho_def","time_out_maxlevel","auto_purge", "auto_promote","personal_rooms","random_motds","startup_room_parse", "resolve_ip","flood_protect", "pueblo_enh", "auto_save", "susers_restrict", "auto_afk", "use_hosts_file", "*" }; if (!strcmp(wrd[0],"INIT:")) { if (++in_section>1) { fprintf(stderr,"Lotos: Unexpected INIT section header on line %d.\n",config_line); boot_exit(1); } return; } op=0; tmp=0; while(strcmp(options[op],wrd[0])) { if (options[op][0]=='*') { fprintf(stderr,"Lotos: Unknown INIT option on line %d.\n",config_line); boot_exit(1); } ++op; } if (!wrd[1][0]) { fprintf(stderr,"Lotos: Required parameter missing on line %d.\n",config_line); boot_exit(1); } if (wrd[2][0] && wrd[2][0]!='#') { fprintf(stderr,"Lotos: Unexpected word following init parameter on line %d.\n",config_line); boot_exit(1); } val=atoi(wrd[1]); switch (op) { case 0: /* main port */ case 1: /* wiz */ #ifdef NETLINKS case 2: /* link */ #endif if ((port[op]=val)<1 || val>65535) { fprintf(stderr,"Lotos: Illegal port number on line %d.\n",config_line); boot_exit(1); } return; case 3: if ((tmp=onoff_check(wrd[1]))==-1) { fprintf(stderr,"Lotos: System_logging must be ON or OFF on line %d.\n",config_line); boot_exit(1); } /* set the bits correctly */ if (tmp) { amsys->logging=BIT_SET(amsys->logging,SYSLOG); amsys->logging=BIT_SET(amsys->logging,REQLOG); #ifdef NETLINKS amsys->logging=BIT_SET(amsys->logging,NETLOG); #endif #ifdef DEBUG amsys->logging=BIT_SET(amsys->logging,DEBLOG); #endif amsys->logging=BIT_SET(amsys->logging,ERRLOG); } else amsys->logging=0; return; case 4: if ((amsys->minlogin_level=get_level(wrd[1]))==-1) { if (strcmp(wrd[1],"NONE")) { fprintf(stderr,"Lotos: Unknown level specifier for minlogin_level on line %d.\n",config_line); boot_exit(1); } amsys->minlogin_level=-1; } return; case 5: /* message lifetime */ if ((amsys->mesg_life=val)<1) { fprintf(stderr,"Lotos: Illegal message lifetime on line %d.\n",config_line); boot_exit(1); } return; case 6: /* wizport_level */ if ((amsys->wizport_level=get_level(wrd[1]))==-1) { fprintf(stderr,"Lotos: Unknown level specifier for wizport_level on line %d.\n",config_line); boot_exit(1); } return; case 7: /* prompt defaults */ if ((amsys->prompt_def=onoff_check(wrd[1]))==-1) { fprintf(stderr,"Lotos: Prompt_def must be ON or OFF on line %d.\n",config_line); boot_exit(1); } return; case 8: /* gatecrash level */ if ((amsys->gatecrash_level=get_level(wrd[1]))==-1) { fprintf(stderr,"Lotos: Unknown level specifier for gatecrash_level on line %d.\n",config_line); boot_exit(1); } return; case 9: if (val<1) { fprintf(stderr,"Lotos: Number too low for min_private_users on line %d.\n",config_line); boot_exit(1); } amsys->min_private_users=val; return; case 10: if ((amsys->ignore_mp_level=get_level(wrd[1]))==-1) { fprintf(stderr,"Lotos: Unknown level specifier for ignore_mp_level on line %d.\n",config_line); boot_exit(1); } return; case 11: /* Max level a remote user can remotely log in if he doesn't have a local account. ie if level set to WIZ a GOD can only be a WIZ if logging in from another server unless he has a local account of level GOD */ if ((amsys->rem_user_maxlevel=get_level(wrd[1]))==-1) { fprintf(stderr,"Lotos: Unknown level specifier for rem_user_maxlevel on line %d.\n",config_line); boot_exit(1); } return; case 12: /* Default level of remote user who does not have an account on site and connection is from a server of version 3.3.0 or lower. */ if ((amsys->rem_user_deflevel=get_level(wrd[1]))==-1) { fprintf(stderr,"Lotos: Unknown level specifier for rem_user_deflevel on line %d.\n",config_line); boot_exit(1); } return; case 13: #ifdef NETLINKS if (strlen(wrd[1])>VERIFY_LEN) { fprintf(stderr,"Lotos: Verification too long on line %d.\n",config_line); boot_exit(1); } strcpy(verification,wrd[1]); #endif return; case 14: /* mesg_check_time */ if (wrd[1][2]!=':' || strlen(wrd[1])>5 || !isdigit(wrd[1][0]) || !isdigit(wrd[1][1]) || !isdigit(wrd[1][3]) || !isdigit(wrd[1][4])) { fprintf(stderr,"Lotos: Invalid message check time on line %d.\n",config_line); boot_exit(1); } sscanf(wrd[1],"%d:%d",&amsys->mesg_check_hour,&amsys->mesg_check_min); if (amsys->mesg_check_hour>23 || amsys->mesg_check_min>59) { fprintf(stderr,"Lotos: Invalid message check time on line %d.\n",config_line); boot_exit(1); } return; case 15: if ((amsys->max_users=val)<1) { fprintf(stderr,"Lotos: Invalid value for max_users on line %d.\n",config_line); boot_exit(1); } return; case 16: if ((amsys->heartbeat=val)<1) { fprintf(stderr,"Lotos: Invalid value for heartbeat on line %d.\n",config_line); boot_exit(1); } return; case 17: if ((amsys->login_idle_time=val)<10) { fprintf(stderr,"Lotos: Invalid value for login_idle_time on line %d.\n",config_line); boot_exit(1); } return; case 18: if ((amsys->user_idle_time=val)<10) { fprintf(stderr,"Lotos: Invalid value for user_idle_time on line %d.\n",config_line); boot_exit(1); } return; case 19: if ((amsys->password_echo=yn_check(wrd[1]))==-1) { fprintf(stderr,"Lotos: Password_echo must be YES or NO on line %d.\n",config_line); boot_exit(1); } return; case 20: if ((amsys->ignore_sigterm=yn_check(wrd[1]))==-1) { fprintf(stderr,"Lotos: Ignore_sigterm must be YES or NO on line %d.\n",config_line); boot_exit(1); } return; case 21: if ((amsys->auto_connect=yn_check(wrd[1]))==-1) { fprintf(stderr,"Lotos: Auto_connect must be YES or NO on line %d.\n",config_line); boot_exit(1); } return; case 22: if ((amsys->max_clones=val)<0) { fprintf(stderr,"Lotos: Invalid value for max_clones on line %d.\n",config_line); boot_exit(1); } return; case 23: if ((amsys->ban_swearing=minmax_check(wrd[1]))==-1) { fprintf(stderr,"Lotos: Ban_swearing must be OFF, MIN or MAX on line %d.\n",config_line); boot_exit(1); } return; case 24: if (!strcmp(wrd[1],"NONE")) amsys->crash_action=0; else if (!strcmp(wrd[1],"IGNORE")) amsys->crash_action=1; else if (!strcmp(wrd[1],"REBOOT")) amsys->crash_action=2; else if (!strcmp(wrd[1],"RESTART")) amsys->crash_action=3; else if (!strcmp(wrd[1],"SHUTDOWN")) amsys->crash_action=4; else { fprintf(stderr,"Lotos: Crash_action must be NONE, IGNORE, REBOOT, RESTART or SHUTDOWN on line %d.\n",config_line); boot_exit(1); } return; case 25: if ((amsys->colour_def=onoff_check(wrd[1]))==-1) { fprintf(stderr,"Lotos: Colour_def must be ON or OFF on line %d.\n",config_line); boot_exit(1); } return; case 26: if ((amsys->time_out_afks=yn_check(wrd[1]))==-1) { fprintf(stderr,"Lotos: Time_out_afks must be YES or NO on line %d.\n",config_line); boot_exit(1); } return; case 27: if ((amsys->charecho_def=onoff_check(wrd[1]))==-1) { fprintf(stderr,"Lotos: Charecho_def must be ON or OFF on line %d.\n",config_line); boot_exit(1); } return; case 28: if ((amsys->time_out_maxlevel=get_level(wrd[1]))==-1) { fprintf(stderr,"Lotos: Unknown level specifier for time_out_maxlevel on line %d.\n",config_line); boot_exit(1); } return; case 29: /* auto purge on boot up */ if ((amsys->auto_purge=yn_check(wrd[1]))==-1) { fprintf(stderr,"Lotos: Auto_purge must be YES or NO on line %d.\n",config_line); boot_exit(1); } return; case 30: /* define whether auto promotes are on or off */ if ((amsys->auto_promote=yn_check(wrd[1]))==-1) { fprintf(stderr,"Lotos: auto_promote must be YES or NO on line %d.\n",config_line); boot_exit(1); } return; case 31: if ((amsys->personal_rooms=yn_check(wrd[1]))==-1) { fprintf(stderr,"Lotos: Personal_rooms must be YES or NO on line %d.\n",config_line); boot_exit(1); } return; case 32: if ((amsys->random_motds=yn_check(wrd[1]))==-1) { fprintf(stderr,"Lotos: Random_motds must be YES or NO on line %d.\n",config_line); boot_exit(1); } return; case 33: if ((amsys->startup_room_parse=yn_check(wrd[1]))==-1) { fprintf(stderr,"Lotos: Startup_room_parse must be YES or NO on line %d.\n",config_line); boot_exit(1); } return; case 34: if ((amsys->resolve_ip=resolve_check(wrd[1]))==-1) { fprintf(stderr,"Lotos: Resolve_ip must be OFF, AUTO or MANUAL on line %d.\n",config_line); boot_exit(1); } return; case 35: /* turns flood protection and auto-baning on and off */ if ((amsys->flood_protect=onoff_check(wrd[1]))==-1) { fprintf(stderr,"Lotos: Flood_protect must be ON or OFF on line %d.\n",config_line); boot_exit(1); } return; case 36: /* povoli rozsirenie pre Pueblo */ #ifdef PUEBLO if ((syspp->pueblo_enh=onoff_check(wrd[1]))==-1) { fprintf(stderr, "Lotos: Pueblo_enh musi byt ON alebo OFF na riadku %d.\n", config_line); boot_exit(1); } #endif return; case 37: /* perioda ukladania userfajlov v minutach */ if (!is_inumber(wrd[1])) { fprintf(stderr, "Lotos: Auto_save na riadku %d musi byt cele kladne cislo alebo -1.\n", config_line); boot_exit(1); } syspp->auto_save=atoi(wrd[1]); if (syspp->auto_save==0 || syspp->auto_save<(-1)) { fprintf(stderr, "Lotos: Auto_save na riadku %d ma chybny parameter.\n", config_line); boot_exit(1); } return; case 38: /* default restrictions mask for superior users */ strcpy(susers_restrict, wrd[1]); return; case 39: /* auto_afk */ if (!is_number(wrd[1])) { fprintf(stderr, "Lotos: Auto_afk na riadku %d musi byt cele kladne cislo\n", config_line); boot_exit(1); } syspp->auto_afk_time=atoi(wrd[1]); if (syspp->auto_afk_time>0) syspp->auto_afk=1; else syspp->auto_afk=0; return; case 40: /* use_hosts_file */ if ((use_hostsfile=yn_check(wrd[1]))==-1) { fprintf(stderr, "Lotos: use_hosts_file musi byt YES alebo NO na riadku %d.\n", config_line); boot_exit(1); } return; } /* end switch */ } /*** Parse rooms section ***/ void parse_rooms_section(void) { static int in_section=0; int i; char *ptr1,*ptr2,c; RM_OBJECT room; if (!strcmp(wrd[0],"ROOMS:")) { if (++in_section>1) { fprintf(stderr,"Lotos: Unexpected ROOMS section header on line %d.\n",config_line); boot_exit(1); } return; } if (!wrd[3][0]) { fprintf(stderr,"Lotos: Required parameter(s) missing on line %d.\n",config_line); boot_exit(1); } if (strlen(wrd[0])>ROOM_NAME_LEN) { fprintf(stderr,"Lotos: Room map name too long on line %d.\n",config_line); boot_exit(1); } if (strlen(wrd[1])>ROOM_LABEL_LEN) { fprintf(stderr,"Lotos: Room label too long on line %d.\n",config_line); boot_exit(1); } if (strlen(wrd[2])>ROOM_NAME_LEN) { fprintf(stderr,"Lotos: Room name too long on line %d.\n",config_line); boot_exit(1); } /* Check for duplicate label or name */ for(room=room_first;room!=NULL;room=room->next) { if (!strcmp(room->label,wrd[1])) { fprintf(stderr,"Lotos: Duplicate room label on line %d.\n",config_line); boot_exit(1); } if (!strcmp(room->name,wrd[2])) { fprintf(stderr,"Lotos: Duplicate room name on line %d.\n",config_line); boot_exit(1); } } room=create_room(); strcpy(room->map,wrd[0]); strcpy(room->label,wrd[1]); strcpy(room->name,wrd[2]); /* Parse internal links bit ie hl,gd,of etc. MUST NOT be any spaces between the commas */ i=0; ptr1=wrd[3]; ptr2=wrd[3]; while (1) { while (*ptr2!=',' && *ptr2!='\0') ++ptr2; if (*ptr2==',' && *(ptr2+1)=='\0') { fprintf(stderr,"Lotos: Missing link label on line %d.\n",config_line); boot_exit(1); } c=*ptr2; *ptr2='\0'; if (!strcmp(ptr1,room->label)) { fprintf(stderr,"Lotos: Room has a link to itself on line %d.\n",config_line); boot_exit(1); } strcpy(room->link_label[i],ptr1); if (c=='\0') break; if (++i>=MAX_LINKS) { fprintf(stderr,"Lotos: Too many links on line %d.\n",config_line); boot_exit(1); } *ptr2=c; ptr1=++ptr2; } /* Parse access privs */ if (wrd[4][0]=='#') { room->access=PUBLIC; return; } if (!wrd[4][0] || !strcmp(wrd[4],"BOTH")) room->access=PUBLIC; else if (!strcmp(wrd[4],"PUB")) room->access=FIXED_PUBLIC; else if (!strcmp(wrd[4],"PRIV")) room->access=FIXED_PRIVATE; else if (!strcmp(wrd[4],"RTC")) room->access=ROOT_CONSOLE; else { fprintf(stderr,"Lotos: Unknown room access type on line %d.\n",config_line); boot_exit(1); } /* Parse external link stuff */ #ifdef NETLINKS if (!wrd[5][0] || wrd[5][0]=='#') return; if (!strcmp(wrd[5],"ACCEPT")) { if (wrd[6][0] && wrd[6][0]!='#') { fprintf(stderr,"Lotos: Unexpected word following ACCEPT keyword on line %d.\n",config_line); boot_exit(1); } room->inlink=1; return; } if (!strcmp(wrd[5],"CONNECT")) { if (!wrd[6][0]) { fprintf(stderr,"Lotos: External link name missing on line %d.\n",config_line); boot_exit(1); } if (wrd[7][0] && wrd[7][0]!='#') { fprintf(stderr,"Lotos: Unexpected word following external link name on line %d.\n",config_line); boot_exit(1); } strcpy(room->netlink_name,wrd[6]); return; } fprintf(stderr,"Lotos: Unknown connection option on line %d.\n",config_line); boot_exit(1); #else return; #endif } /*** Parse rooms desc (topic) section ***/ void parse_topics_section(char *topic) { static int in_section=0; int exists; RM_OBJECT room; if (!strcmp(wrd[0],"TOPICS:")) { if (++in_section>1) { fprintf(stderr,"Lotos: Unexpected TOPICS section header on line %d.\n",config_line); boot_exit(1); } return; } if (!wrd[1][0]) { fprintf(stderr,"Lotos: Required parameter(s) missing on line %d.\n",config_line); boot_exit(1); } /* Check to see if room exists */ exists=0; for (room=room_first;room!=NULL;room=room->next) if (!strcmp(room->name,wrd[0])) { ++exists; break; } if (!exists) { fprintf(stderr,"Lotos: Room does not exist on line %d.\n",config_line); boot_exit(1); } if (topic[strlen(topic)-1]=='\n') topic[strlen(topic)-1]='\0'; strncpy(room->topic,topic,TOPIC_LEN); } #ifdef NETLINKS /*** Parse sites section ***/ void parse_sites_section(void) { NL_OBJECT nl; static int in_section=0; if (!strcmp(wrd[0],"SITES:")) { if (++in_section>1) { fprintf(stderr,"Lotos: Unexpected SITES section header on line %d.\n",config_line); boot_exit(1); } return; } if (!wrd[3][0]) { fprintf(stderr,"Lotos: Required parameter(s) missing on line %d.\n",config_line); boot_exit(1); } if (strlen(wrd[0])>SERV_NAME_LEN) { fprintf(stderr,"Lotos: Link name length too long on line %d.\n",config_line); boot_exit(1); } if (strlen(wrd[3])>VERIFY_LEN) { fprintf(stderr,"Lotos: Verification too long on line %d.\n",config_line); boot_exit(1); } if ((nl=create_netlink())==NULL) { fprintf(stderr,"Lotos: Memory allocation failure creating netlink on line %d.\n",config_line); boot_exit(1); } if (!wrd[4][0] || wrd[4][0]=='#' || !strcmp(wrd[4],"ALL")) nl->allow=ALL; else if (!strcmp(wrd[4],"IN")) nl->allow=IN; else if (!strcmp(wrd[4],"OUT")) nl->allow=OUT; else { fprintf(stderr,"Lotos: Unknown netlink access type on line %d.\n",config_line); boot_exit(1); } if ((nl->port=atoi(wrd[2]))<1 || nl->port>65535) { fprintf(stderr,"Lotos: Illegal port number on line %d.\n",config_line); boot_exit(1); } strcpy(nl->service,wrd[0]); strtolower(wrd[1]); strcpy(nl->site,wrd[1]); strcpy(nl->verification,wrd[3]); } #endif /*** Parse transports section ***/ void parse_transports_section(void) { static int in_section=0; int i; char *ptr1,*ptr2,c; RM_OBJECT room; if (!strcmp(wrd[0],"TRANSPORTS:")) { if (++in_section>1) { fprintf(stderr,"Lotos: Unexpected TRANSPORTS section header on line %d.\n",config_line); boot_exit(1); } return; } if (!wrd[5][0]) { fprintf(stderr,"Lotos: Required parameter(s) missing on line %d.\n",config_line); boot_exit(1); } if (strlen(wrd[0])>ROOM_NAME_LEN) { fprintf(stderr,"Lotos: Room map name too long on line %d.\n",config_line); boot_exit(1); } if (strlen(wrd[1])>ROOM_LABEL_LEN) { fprintf(stderr,"Lotos: Room label too long on line %d.\n",config_line); boot_exit(1); } if (strlen(wrd[2])>ROOM_NAME_LEN) { fprintf(stderr,"Lotos: Room name too long on line %d.\n",config_line); boot_exit(1); } /* Check for duplicate label or name */ for(room=room_first;room!=NULL;room=room->next) { if (!strcmp(room->label,wrd[1])) { fprintf(stderr,"Lotos: Duplicate room label on line %d.\n",config_line); boot_exit(1); } if (!strcmp(room->name,wrd[2])) { fprintf(stderr,"Lotos: Duplicate room name on line %d.\n",config_line); boot_exit(1); } } room=create_room(); room->transp=create_transport(); room->transp->room=room; strcpy(room->map,wrd[0]); strcpy(room->label,wrd[1]); strcpy(room->name,wrd[2]); room->transp->place=atoi(wrd[4]); room->transp->route=atoi(wrd[5]); room->transp->smer=1; room->access=FIXED_PUBLIC; /* Parse internal links bit ie hl,gd,of etc. MUST NOT be any spaces between the commas */ i=0; ptr1=wrd[3]; ptr2=wrd[3]; while (1) { while (*ptr2!=',' && *ptr2!='\0') ++ptr2; if (*ptr2==',' && *(ptr2+1)=='\0') { fprintf(stderr,"Lotos: Missing link label on line %d.\n",config_line); boot_exit(1); } c=*ptr2; *ptr2='\0'; if (!strcmp(ptr1,room->label)) { fprintf(stderr,"Lotos: Room has a link to itself on line %d.\n",config_line); boot_exit(1); } strcpy(room->link_label[i],ptr1); if (c=='\0') break; if (++i>=MAX_LINKS) { fprintf(stderr,"Lotos: Too many links on line %d.\n",config_line); boot_exit(1); } *ptr2=c; ptr1=++ptr2; } } void clear_temps(void) { char fname[FNAME_LEN]; DIR *dirp; struct dirent *dp; set_crash(); printf("Removing temp files ... "); if (!(dirp=opendir(TEMPFILES))) { printf("Nemozem otvorit TEMPFILES adresar\n"); return; } while ((dp=readdir(dirp))!=NULL) { if (!strcmp(dp->d_name,".") || !strcmp(dp->d_name,"..")) continue; sprintf(fname, "%s/%s", TEMPFILES, dp->d_name); unlink(fname); } closedir(dirp); printf(" done\n"); } void write_pid(void) { FILE *fp; set_crash(); if ((fp=fopen(PIDFILE, "rb+"))==NULL) return; fprintf(fp, "%d", getpid()); fclose(fp); return; } void create_kill_file(void) { FILE *fp; int i=0; set_crash(); if ((fp=fopen(KILLFILE, "wb"))==NULL) { write_syslog(ERRLOG, 1, "nemozem vytvorit KILLFILE v create_kill_file()\n"); return; } sprintf(text, "kill -9 %d\n", getpid()); while (text[i]) { fwrite(text+i, 1, sizeof(char), fp); i++; } fclose(fp); sprintf(text, "chmod 700 %s", KILLFILE); system(text); } #endif /* __BOOTS_C__ */