/* GGSD (Generic Graphical Server Daemon) (C) Patrick Lambert */ #include "ggsd.h" /* check args and start the thing */ int main(int argc, char *argv[]) { int i; for(i = 1; argv[i] != NULL; i++) { /* user id under which to run */ if(!strcasecmp(argv[i], "-uid")) { i++; if(argv[i] == NULL || *argv[i]=='-') ggsd_report("You didn't specify a UID !", GGSD_EXIT_ERROR, GGSD_PARAM); if(getpwnam(argv[i]) == NULL) uid = atoi(argv[i]); else uid = getpwnam(argv[i])->pw_uid; } /* version */ else if(!strcasecmp(argv[i], "-version")) { usage(); exit(0); } /* log file to use, or "syslog" */ else if(!strcasecmp(argv[i], "-log")) { i++; if(argv[i] == NULL || *argv[i]=='-') ggsd_report("You didn't specify a log file !", GGSD_EXIT_ERROR, GGSD_PARAM); if(!strcasecmp(argv[i], "syslog")) { GGSD_LOG_SYSLOG = 1; strcpy(logfile, "syslog"); } else { if(strlen(argv[i]) > 98) ggsd_report("Log file name too long", GGSD_EXIT_ERROR, GGSD_PARAM); strcpy(logfile, argv[i]); } } /* port num */ else if(!strcasecmp(argv[i], "-port")) { i++; if(argv[i] == NULL || *argv[i]=='-') ggsd_report("You didn't specify a port number !", GGSD_EXIT_ERROR, GGSD_PARAM); if(atoi(argv[i]) < 1 || atoi(argv[i]) > 65500) ggsd_report("Invalid port", GGSD_EXIT_ERROR, GGSD_PARAM); portnum = atoi(argv[i]); } /* allow list, hostnames separated by spaces */ else if(!strcasecmp(argv[i], "-allow")) { i++; if(argv[i] == NULL || *argv[i]=='-') ggsd_report("You didn't specify an access list !", GGSD_EXIT_ERROR, GGSD_PARAM); if(strlen(argv[i]) > 1000) ggsd_report("Access list too long (>1000 chars)", GGSD_EXIT_ERROR, GGSD_PARAM); strcpy(allow_list, argv[i]); } /* script to use */ else if(!strcasecmp(argv[i], "-script")) { i++; if(argv[i] == NULL || *argv[i]=='-') ggsd_report("You didn't specify a script !", GGSD_EXIT_ERROR, GGSD_PARAM); if(strlen(argv[i]) > 100) ggsd_report("Script file name too long", GGSD_EXIT_ERROR, GGSD_PARAM); strcpy(script, argv[i]); } /* don't fork */ else if(!strcasecmp(argv[i], "-fg")) { nofork = 1; } /* use allow list first */ else if(!strcasecmp(argv[i], "-allow-first")) { allow_first = 1; } /* don't display config */ else if(!strcasecmp(argv[i], "-nogui")) { nogui = 1; } /* deny list, hostnames separated by spaces */ else if(!strcasecmp(argv[i], "-deny")) { i++; if(argv[i] == NULL || *argv[i]=='-') ggsd_report("You didn't specify an access list !", GGSD_EXIT_ERROR, GGSD_PARAM); if(strlen(argv[i]) > 1000) ggsd_report("Access list too long (>1000 chars)", GGSD_EXIT_ERROR, GGSD_PARAM); strcpy(deny_list, argv[i]); } /* unknown args */ else { sprintf(temp, "Unknown argument: %s", argv[i]); ggsd_report(temp, GGSD_EXIT_ERROR, GGSD_PARAM); } } #ifdef USE_GUI if(!nogui) { gtk_init(&argc, &argv); make_gui(); } #endif print_status(); if(!nofork) { if((pid=fork())) { exit(0); } } start_server(); return 0; } /* print variables */ void print_status() { printf("ggsd: Starting server [UID=%d PORT=%d LOG=%s]\n", uid, portnum, logfile); printf("ggsd: Allowing hosts: %s\n", allow_list); printf("ggsd: Denying hosts: %s\n", deny_list); } /* main net function */ void start_server() { char remotehost[1024]; struct hostent *hp; struct sockaddr_in from; sockfd2 = socket(AF_INET, SOCK_STREAM, 0); if(sockfd2<1) ggsd_report("Can't open a socket", GGSD_EXIT_ERROR, GGSD_RUN); listen_addr.sin_family = AF_INET; listen_addr.sin_addr.s_addr = htonl(INADDR_ANY); listen_addr.sin_port = htons(portnum); listen_len = sizeof(listen_addr); if(geteuid()==0) setsockopt(sockfd2, SOL_SOCKET, SO_REUSEADDR, (char *) &opt, sizeof(int)); if(bind(sockfd2, (struct sockaddr *)&listen_addr, listen_len)) ggsd_report("Can't bind address (an other ggsd running on that port?)", GGSD_EXIT_ERROR, GGSD_BIND); setuid(uid); /* we need to bind as root */ listen(sockfd2, 5); for(;;) { if(sockfd!=(int)NULL) close(sockfd); sockfd = accept(sockfd2, (struct sockaddr *)&address, &len); if((pid=fork())) break; } from_len=sizeof(from_addr); memset(&from_addr, 0, sizeof(from_addr)); if(getpeername(sockfd, (struct sockaddr *)&from_addr,&from_len) < 0) { ggsd_report("Connection from unknown host. Refusing", GGSD_EXIT_ERROR, GGSD_RUN); output("Sorry. Can't find your IP\n"); close(sockfd); exit(0); } else { from.sin_family = AF_INET; from.sin_addr.s_addr = inet_addr(inet_ntoa(from_addr.sin_addr)); hp=gethostbyaddr((char *)&from.sin_addr, sizeof(struct in_addr),from.sin_family); if(hp==NULL) strncpy(remotehost,"unknown", 1000); else strncpy(remotehost,(char *)hp->h_name, 1000); if(strlen(inet_ntoa(from_addr.sin_addr))>50) exit(1); sprintf(temp, "Connection from %s[%s] [pid=%d]\n", remotehost, inet_ntoa(from_addr.sin_addr), pid); ggsd_report(temp, 0, GGSD_RUN); } if(check_address(remotehost) == -1) { close(sockfd); sprintf(temp, "Refusing connection [pid=%d]", pid); ggsd_report(temp, GGSD_EXIT_OK, GGSD_RUN); } get_report(); sprintf(temp, "Closing connection [pid=%d]", pid); ggsd_report(temp, 0, GGSD_RUN); close(sockfd); exit(0); } /* check the host with the lists */ int check_address(char *ip) { int i; if(allow_first) for(i = 0; lindex(allow_list, i)!=NULL; i++) { if(!match(lindex(allow_list, i), ip)) return 1; } for(i = 0; lindex(deny_list, i)!=NULL; i++) { if(!match(lindex(deny_list, i), ip)) return -1; } if(!allow_first) for(i = 0; lindex(allow_list, i)!=NULL; i++) { if(!match(lindex(allow_list, i), ip)) return 1; } return 1; } /* connection is done, we do whatever we need to do here */ void get_report() { FILE *fd, *fd2; fd = fopen(script, "r"); if(fd==NULL) ggsd_report("Script not found", GGSD_EXIT_ERROR, GGSD_RUN); while(fgets(line, 500, fd)!=NULL) { if(lindex(line,0)!=NULL) { line[strlen(line)-1]=' '; if(!strcasecmp(lindex(line,0),"run:")) system(lrange(line,1)); if(!strcasecmp(lindex(line,0),"cat:")) { fd2 = fopen(lindex(line,1), "r"); if(fd2!=NULL) { bzero(line, 512); while(fgets(line, 500, fd2)!=NULL) { output(line); } fclose(fd2); } else { sprintf(temp, "Could not open file for cat command: %s", line); ggsd_report(temp, 0, GGSD_RUN); } } /* cat */ if(!strcasecmp(lindex(line,0),"output:")) output(lrange(line,1)); if(!strcasecmp(lindex(line,0),"deny:")) { fd2 = fopen(lindex(line,1), "r"); if(fd2==NULL) { sprintf(temp, "Could not open file for require command: %s", line); ggsd_report(temp, 0, GGSD_RUN); } bzero(temp, 512); fgets(temp, 500, fd2); temp[strlen(temp)-1]=' '; fclose(fd2); sprintf(line, "*%s*", lindex(line,2)); if(!match(line, temp)) { close(sockfd); return; } } if(!strcasecmp(lindex(line,0),"require:")) { fd2 = fopen(lindex(line,1), "r"); if(fd2==NULL) { sprintf(temp, "Could not open file for require command: %s", line); ggsd_report(temp, 0, GGSD_RUN); } bzero(temp, 512); fgets(temp, 500, fd2); temp[strlen(temp)-1]=' '; fclose(fd2); sprintf(line, "*%s*", lindex(line,2)); if(match(line,temp)) { close(sockfd); return; } } if(!strcasecmp(lindex(line,0),"input:")) { fd2 = fopen(lindex(line,1), "w"); if(fd2!=NULL) { bzero(line, 512); read(sockfd, line, 500); line[strlen(line)-2]=' '; fputs(line, fd2); fclose(fd2); fd2=NULL; } else { sprintf(temp, "Could not open file for input command: %s", line); ggsd_report(temp, 0, GGSD_RUN); } } /* input */ if(!strcasecmp(lindex(line,0),"tail:")) { fd2 = fopen(lindex(line,1), "r"); if(fd2!=NULL) { bzero(line, 512); fseek(fd2, 0, SEEK_END); fgets(line, 500, fd); while(1) { if(fgets(line, 500, fd2) != (char*)EOF && strcmp(line, temp)) output(line); strcpy(temp, line); sleep(1); } fclose(fd2); } else { sprintf(temp, "Could not open file for tail command: %s", line); ggsd_report(temp, 0, GGSD_RUN); } } /* tail */ } } /* while */ fclose(fd); close(sockfd); ggsd_report("Connection closed", GGSD_EXIT_OK, GGSD_RUN); } /* output on the socket */ void output(char *msg) { write(sockfd, msg, strlen(msg)); } /* an event occured */ void ggsd_report(char *msg, int type, int when) { if(GGSD_LOG_SYSLOG && (when != GGSD_PARAM)) { openlog("ggsd",LOG_PID,LOG_USER); syslog(LOG_DAEMON | LOG_NOTICE, msg); closelog(); } else { if(when == GGSD_PARAM || when == GGSD_BIND) fprintf(stderr, "ggsd: %s\n", msg); print_log(msg); } if(when == GGSD_PARAM) usage(); if(type == GGSD_EXIT_ERROR) exit(1); if(type == GGSD_EXIT_OK) exit(0); return; } /* print to a log file */ void print_log(char *msg) { FILE *fd; fd = fopen(logfile, "a"); if(fd == NULL) return; fputs(msg, fd); fputs("\n", fd); fclose(fd); return; } /* print usage info */ void usage() { printf("GGSD v%s (C) 1999 Patrick Lambert http://devplanet.fastethernet.net\n", VERSION); printf("ggsd -script -uid -port -log -allow -deny [-version] [-nogui] [-fg] [-allow-first]\n"); return; } /* matching function */ int match(char *ip1, char *ip2) { while(*ip1 == '*' || *ip1==*ip2 || *ip1 == '?') if(*ip1 == '*') if(*++ip1) { while(*ip2) if(!match(ip1,ip2++)) return 0; return 1; } else return 0; else if (!*ip1) return 0; else if (!*ip2) return 1; else { ++ip1; ++ip2; } return 1; } /* lindex */ char *lindex(char *input_string, int word_number) { char *tokens[1024]; static char tmpstring[1024]; int i; strncpy(tmpstring,input_string,1024); (char *)tokens[i=0] = (char *)strtok(tmpstring, " "); while (((char *)tokens[++i] = (char *)strtok(NULL, " "))); tokens[i] = NULL; return(tokens[word_number]); } /* lrange */ char *lrange(char *input_string, int starting_at) { char *tokens[1024]; static char tmpstring[1024]=""; int i; char out_string[1024]=""; strcpy(out_string,""); if(input_string==NULL) { strcpy(out_string," "); strcat(out_string,NULL); strcpy(global_var,out_string); return (char *)global_var; } strncpy(tmpstring,input_string,1024); tokens[i=0] = strtok(tmpstring, " "); while((tokens[++i] = strtok(NULL, " "))); tokens[i] = NULL; i++; if(iactive; } void gui_cb2(GtkWidget *w, GtkWidget *e) { allow_first = GTK_TOGGLE_BUTTON(w)->active; } void gui_ok(GtkWidget *w, GtkWidget *e) { strncpy(allow_list, gtk_entry_get_text(GTK_ENTRY(eb1)), 1000); strncpy(deny_list, gtk_entry_get_text(GTK_ENTRY(eb2)), 1000); strncpy(logfile, gtk_entry_get_text(GTK_ENTRY(eb3)), 100); strncpy(script, gtk_entry_get_text(GTK_ENTRY(eb6)), 100); if(!strcasecmp(gtk_entry_get_text(GTK_ENTRY(eb3)), "syslog")) GGSD_LOG_SYSLOG = 1; if(getpwnam(gtk_entry_get_text(GTK_ENTRY(eb4))) == NULL) uid = atoi(gtk_entry_get_text(GTK_ENTRY(eb4))); else uid = getpwnam(gtk_entry_get_text(GTK_ENTRY(eb4)))->pw_uid; portnum = atoi(gtk_entry_get_text(GTK_ENTRY(eb5))); if(portnum < 1 || portnum > 65500) { ggsd_report("Invalid port", GGSD_EXIT_ERROR, GGSD_PARAM); exit(1); } gtk_widget_destroy(window); gtk_main_quit(); if(allow_first) printf("ggsd: *** Note: To start a server with these settings on system bootup you should use this line in one of your startup files, ie. /etc/rc.d/rc.local:\n/sbin/ggsd -nogui -allow-first -allow \"%s\" -deny \"%s\" -port %d -uid %d -log %s -script %s\n", allow_list, deny_list, portnum, uid, logfile, script); else printf("ggsd: *** Note: To start a server with these settings on system bootup you should use this line in one of your startup files, ie. /etc/rc.d/rc.local:\n/sbin/ggsd -nogui -allow \"%s\" -deny \"%s\" -port %d -uid %d -log %s -script %s\n", allow_list, deny_list, portnum, uid, logfile, script); } void make_gui() { window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_signal_connect(GTK_OBJECT(window), "delete_event", GTK_SIGNAL_FUNC(gui_exit), &window); gtk_container_border_width(GTK_CONTAINER(window), 5); gtk_window_set_title(GTK_WINDOW(window), "GGSD Control Panel"); gtk_widget_set_uposition (window, 200, 200); gtk_widget_set_usize (window, 300, 350); vbox = gtk_vbox_new (FALSE, 0); gtk_container_add (GTK_CONTAINER (window), vbox); gtk_widget_show (vbox); cb1 = gtk_check_button_new_with_label("Don't go to background"); gtk_signal_connect (GTK_OBJECT(cb1), "toggled", GTK_SIGNAL_FUNC(gui_cb1), cb1); gtk_box_pack_start (GTK_BOX (vbox), cb1, TRUE, TRUE, 0); if(nofork) gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(cb1), TRUE); gtk_widget_show (cb1); cb2 = gtk_check_button_new_with_label("Use allow list before deny"); gtk_signal_connect (GTK_OBJECT(cb2), "toggled", GTK_SIGNAL_FUNC(gui_cb2), cb2); gtk_box_pack_start (GTK_BOX (vbox), cb2, TRUE, TRUE, 0); if(allow_first) gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(cb2), TRUE); gtk_widget_show (cb2); label = gtk_label_new ("Hostnames allowed in:"); gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0); gtk_widget_show (label); eb1 = gtk_entry_new (); gtk_editable_select_region (GTK_EDITABLE (eb1), 0, -1); gtk_box_pack_start (GTK_BOX (vbox), eb1, TRUE, TRUE, 0); if(strcmp(allow_list,"")) gtk_entry_set_text (GTK_ENTRY (eb1), allow_list); else gtk_entry_set_text (GTK_ENTRY (eb1), "*"); gtk_widget_show (eb1); label = gtk_label_new ("Hostnames denied:"); gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0); gtk_widget_show (label); eb2 = gtk_entry_new (); gtk_editable_select_region (GTK_EDITABLE (eb2), 0, -1); gtk_box_pack_start (GTK_BOX (vbox), eb2, TRUE, TRUE, 0); if(strcmp(deny_list,"")) gtk_entry_set_text (GTK_ENTRY (eb2), deny_list); else gtk_entry_set_text (GTK_ENTRY (eb2), "unknown localhost 192.168.* 10.* 127.*"); gtk_widget_show (eb2); label = gtk_label_new ("Log file name:"); gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0); gtk_widget_show (label); eb3 = gtk_entry_new (); gtk_editable_select_region (GTK_EDITABLE (eb3), 0, -1); gtk_box_pack_start (GTK_BOX (vbox), eb3, TRUE, TRUE, 0); gtk_entry_set_text (GTK_ENTRY (eb3), logfile); gtk_widget_show (eb3); label = gtk_label_new ("User ID:"); gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0); gtk_widget_show (label); eb4 = gtk_entry_new (); gtk_editable_select_region (GTK_EDITABLE (eb4), 0, -1); gtk_box_pack_start (GTK_BOX (vbox), eb4, TRUE, TRUE, 0); if(uid != -1) { sprintf(temp, "%d", uid); gtk_entry_set_text (GTK_ENTRY (eb4), temp); } else gtk_entry_set_text (GTK_ENTRY (eb4), "nobody"); gtk_widget_show (eb4); label = gtk_label_new ("Port number:"); gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0); gtk_widget_show (label); eb5 = gtk_entry_new (); gtk_editable_select_region (GTK_EDITABLE (eb5), 0, -1); gtk_box_pack_start (GTK_BOX (vbox), eb5, TRUE, TRUE, 0); sprintf(temp, "%d", portnum); gtk_entry_set_text (GTK_ENTRY (eb5), temp); gtk_widget_show (eb5); label = gtk_label_new ("GGSD script to use:"); gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0); gtk_widget_show (label); eb6 = gtk_entry_new (); gtk_editable_select_region (GTK_EDITABLE (eb6), 0, -1); gtk_box_pack_start (GTK_BOX (vbox), eb6, TRUE, TRUE, 0); gtk_entry_set_text (GTK_ENTRY (eb6), script); gtk_widget_show (eb6); hbox = gtk_hbutton_box_new(); gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END); gtk_button_box_set_spacing(GTK_BUTTON_BOX(hbox), 5); gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); gtk_widget_show (hbox); button = gtk_button_new_with_label ("Start server"); gtk_signal_connect_object (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC(gui_ok), GTK_OBJECT (window)); gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0); gtk_widget_show (button); button = gtk_button_new_with_label ("Cancel"); gtk_signal_connect_object (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC(gui_exit), GTK_OBJECT (window)); gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0); gtk_widget_show (button); gtk_widget_show (window); gtk_main(); } #endif