/*
GGSD (Generic Graphical Server Daemon) (C) Patrick Lambert <drow@darkelf.net>
*/
#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 <drow@darkelf.net> http://devplanet.fastethernet.net\n", VERSION);
printf("ggsd -script <filename> -uid <uid> -port <port> -log <filename|syslog> -allow <list of hostnames> -deny <list of hostnames> [-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(i<starting_at)
{
return (char *)"";
}
while(tokens[starting_at] != NULL)
{
strncat(out_string,tokens[starting_at],1024);
strcat(out_string, " ");
starting_at++;
}
strncpy(global_var,out_string,511);
return (char *)global_var;
}
#ifdef USE_GUI
void gui_exit(GtkWidget *w, GtkWidget *e)
{
fprintf(stderr, "ggsd: Aborted.\n");
exit(1);
}
void gui_cb1(GtkWidget *w, GtkWidget *e)
{
nofork = GTK_TOGGLE_BUTTON(w)->active;
}
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
syntax highlighted by Code2HTML, v. 0.9.1