1    | /***************************************
2    |   $Revision: 1.7 $
3    | 
4    |   Protocol config module (pc).  This is the protocol that the admin uses to
5    |   talk to the server.
6    | 
7    |   Status: NOT REVUED, NOT TESTED
8    | 
9    |   ******************/ /******************
10   |   Filename            : protocol_config.c
11   |   Author              : ottrey@ripe.net
12   |   OSs Tested          : Solaris
13   |   To Do               : Add a facility to take callbacks instead of
14   |                         hard-coding menu options.
15   |   ******************/ /******************
16   |   Copyright (c) 1999                              RIPE NCC
17   |  
18   |   All Rights Reserved
19   |   
20   |   Permission to use, copy, modify, and distribute this software and its
21   |   documentation for any purpose and without fee is hereby granted,
22   |   provided that the above copyright notice appear in all copies and that
23   |   both that copyright notice and this permission notice appear in
24   |   supporting documentation, and that the name of the author not be
25   |   used in advertising or publicity pertaining to distribution of the
26   |   software without specific, written prior permission.
27   |   
28   |   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
29   |   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
30   |   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
31   |   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
32   |   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
33   |   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
34   |   ***************************************/
35   | #include <stdio.h>
36   | #include <stdlib.h>
37   | #include <unistd.h>
38   | #include <time.h>       /* Time stuff */
39   | #include <sys/ioctl.h>      /* Terminal control stuff */
40   | #include <termio.h>      /* Terminal control stuff */
41   | 
42   | #include "mysql_driver.h"
43   | #include "constants.h"
44   | #include "properties.h"
45   | #include "thread.h"
46   | #include "protocol_config.h"
47   | 
48   | /*+ Each command has a +*/
49   | typedef struct _command {
50   |   const char *name;                          /*+ Name to be invoked. +*/
51   |   char *(*function)(char *);      /*+ Function to be invoked. +*/
52   |   const char *help;                                /*+ Command help. +*/
53   | } Command;
54   | 
55   | /*
56   |  * Forward declarations
57   |  */
58   | static char *command_help(char *input);
59   | static char *command_quit(char *input);
60   | static char *command_show(char *input);
61   | static char *command_repeat(char *input);
62   | static char *show_const(char *input);
63   | static char *show_consts(char *input);
64   | static char *show_props(char *input);
65   | static char *show_thread(char *input);
66   | static char *show_whois(char *input);
67   | static char *command_set(char *input);
68   | static char *set_const(char *input);
69   | static char *set_consts(char *input);
70   | static char *set_props(char *input);
71   | static char *command_sql(char *input);
72   | 
73   | /*+
74   |  * Contains the command definitions
75   | +*/
76   | static struct _command command[] = {
77   |   {"help"   , command_help   , HELP_HELP   },
78   |   {"quit"   , command_quit   , HELP_QUIT   },
79   |   {"show"   , command_show   , HELP_SHOW   },
80   |   {"repeat" , command_repeat , HELP_REPEAT },
81   |   {"set"    , command_set    , HELP_SET    },
82   |   {"sql"    , command_sql    , HELP_SQL    },
83   |   NULL
84   | };
85   | 
86   | /*+
87   |  * Contains the show commands
88   | +*/
89   | static struct _command show[] = {
90   |   {"const"   , show_const   , HELP_SHOW_CONST   },
91   |   {"consts"  , show_consts  , HELP_SHOW_CONSTS  },
92   |   {"props"   , show_props   , HELP_SHOW_PROPS   },
93   |   {"thread"  , show_thread  , HELP_SHOW_THREAD  },
94   |   {"whois"   , show_whois   , HELP_SHOW_WHOIS   },
95   |   NULL
96   | };
97   | 
98   | /*+
99   |  * Contains the set commands
100  | +*/
101  | static struct _command set[] = {
102  |   {"const"  , set_const  , HELP_SET_CONST  },
103  |   {"consts" , set_consts , HELP_SET_CONSTS },
104  |   {"props"  , set_props  , HELP_SET_PROPS  },
105  |   NULL
106  | };
107  | 
108  | static int find_command(char *comm_name, Command *comm) {
109  |   int i, index;
110  |   char comm_buffer[STR_L];
111  | 
112  |   if (comm_name != NULL) {
113  |     strcpy(comm_buffer, comm_name);
114  |     strtok(comm_buffer, " \t");
115  |     for (i=0, index=-1; comm[i].name != NULL; i++) {
116  |       if ( strcmp(comm_buffer, comm[i].name) == 0) {
117  |         index = i;
118  |         break;
119  |       }
120  |     }
121  |   }
122  |   else {
123  |     index = -2;
124  |   }
125  | 
126  |   return index;
127  | } /* find_command() */
128  | 
129  | static char *show_commands(Command *comm) {
130  |   char *str;
131  |   char help_buffer[STR_XL];
132  |   char help_comm[STR_M];
133  |   int i;
134  | 
135  |   sprintf(help_buffer, " commands are:\n\n");
136  |   i = 0;
137  |   while (comm[i].name != NULL) {
138  |     sprintf(help_comm, "%s\t%s\n", comm[i].name, comm[i].help);
139  |     strcat(help_buffer, help_comm);
140  |     i++;
141  |   }
142  | 
143  |   str = (char *)calloc(1, strlen(help_buffer)+1);
144  |   strcpy(str, help_buffer);
145  | 
146  |   return str;
147  | } /* show_commands() */
148  | 
149  | 
150  | /*
151  |  * Command functions
152  |  */
153  | static char *command_help(char *input) {
154  |   char *str;
155  |   char *str1;
156  |   char output_buffer[STR_XXL];
157  |   char *command_name;
158  |   int index;
159  | 
160  |   strcpy(output_buffer, "");
161  | 
162  |   strtok(input, " \t");
163  |   command_name = (char *)strtok(NULL, " \t");
164  | 
165  |   index = find_command(command_name, command);
166  | 
167  |   switch (index) {
168  |     case -2:
169  |       strcat(output_buffer, "Main");
170  |       str1 = show_commands(command);
171  |       strcat(output_buffer, str1);
172  |       free(str1);
173  |       break;
174  | 
175  |     case -1:
176  |       strcat(output_buffer, HELP_ERROR);
177  |       strcat(output_buffer, command_name);
178  |       break;
179  | 
180  |     default: 
181  |       strcat(output_buffer, command[index].help);
182  |   }
183  | 
184  |   /*
185  |   str = (char *)CopyString(output_buffer);
186  |   */
187  |   str = (char *)calloc(1, strlen(output_buffer)+1);
188  |   strcpy(str, output_buffer);
189  | 
190  |   return str;
191  | } /* command_help() */
192  | 
193  | static char *command_quit(char *input) {
194  |     /* Client wishes to quit. */
195  |   return NULL;
196  | } /* command_quit() */
197  | 
198  | static char *show_const(char *input) {
199  |   /* Client wishes to show constants. */
200  |   char *result;
201  |   char *name;
202  |   char *tmp_input;
203  | 
204  |   tmp_input = (char *)calloc(1, strlen(input)+1);
205  |   strcpy(tmp_input, input);
206  | 
207  |   /* The name will be the third token in stuff */
208  |   strtok(tmp_input, " ");
209  |   strtok(NULL, " ");
210  |   name = (char *)strtok(NULL, " ");
211  | 
212  |   result = CO_const_to_string(name);
213  | 
214  |   free(tmp_input);
215  |   return result;
216  | 
217  | } /* show_const() */
218  | 
219  | static char *show_consts(char *input) {
220  |   /* Client wishes to show constants. */
221  |   return CO_to_string();
222  | 
223  | } /* show_consts() */
224  | 
225  | static char *show_props(char *input) {
226  |   /* Client wishes to show properties. */
227  |   return PR_to_string();
228  | 
229  | } /* show_props() */
230  | 
231  | static char *show_thread(char *input) {
232  |   /* Client wishes to show thread information. */
233  |   return TH_to_string();
234  | 
235  | } /* show_thread() */
236  | 
237  | static char *show_whois(char *input) {
238  |   /* Client wishes to show whois query information. */
239  |   return "WQ_to_string();";
240  | 
241  | } /* show_thread() */
242  | 
243  | static char *command_execute(char *input, char *comm_name, Command *comm) {
244  |   char *str;
245  |   char *str1;
246  |   char output_buffer[STR_XXL];
247  |   char tmp[STR_L];
248  |   char *name;
249  |   int index;
250  |   char *tmp_input;
251  | 
252  |   /* Make a copy of the input */
253  |   tmp_input = (char *)calloc(1, strlen(input)+1);
254  |   strcpy(tmp_input, input);
255  | 
256  |   strtok(tmp_input, " \t");
257  |   name = (char *)strtok(NULL, " \t");
258  | 
259  |   index = find_command(name, comm);
260  | 
261  |   switch (index) {
262  |     case -2:
263  |       str1 = show_commands(comm);
264  |       sprintf(output_buffer, "%s%s", comm_name, str1);
265  |       free(str1);
266  |       break;
267  | 
268  |     case -1:
269  |       sprintf(output_buffer, "%s invalid command: %s", comm_name, name);
270  |       break;
271  | 
272  |     default: 
273  |       sprintf(output_buffer, "%s", comm[index].function(input));
274  |   }
275  | 
276  |   /*
277  |   str = (char *)CopyString(output_buffer);
278  |   */
279  |   str = (char *)calloc(1, strlen(output_buffer)+1);
280  |   strcpy(str, output_buffer);
281  | 
282  |   free(tmp_input);
283  | 
284  |   return str;
285  | } /* command_execute() */
286  | 
287  | static char *command_show(char *input) {
288  |   return command_execute(input, "Show", show);
289  | } /* command_show() */
290  | 
291  | static char *command_repeat(char *input) {
292  |   char *command_ptr;
293  | 
294  |   /* Goto the bit after "repeat n " */
295  |   for (command_ptr=input+7; command_ptr[0] != ' ' || (command_ptr[0] >= '0' && command_ptr[0] <= '9'); command_ptr++);
296  | 
297  |   return command_ptr+1;
298  | 
299  | } /* command_show() */
300  | 
301  | static char *set_const(char *input) {
302  |   /* Client wishes to set a constant. */
303  |   char *result;
304  |   char result_buf[STR_M];
305  |   char *tmp_input;
306  |   char *name;
307  |   char *value;
308  |   int value_len;
309  |   char *stuff;
310  |   char *str;
311  | 
312  |   tmp_input = (char *)calloc(1, strlen(input)+1);
313  |   strcpy(tmp_input, input);
314  | 
315  |   stuff = (char *)strtok(tmp_input, "=");
316  | 
317  |   /* The value will be after the '=' */
318  |   value = (char *)strtok(NULL, "=");
319  | 
320  |   /* The name will be the third token in stuff */
321  |   strtok(stuff, " ");
322  |   strtok(NULL, " ");
323  |   name = (char *)strtok(NULL, " ");
324  | 
325  |   /* Remove any quotes */
326  |   if (value[0] == '"') {
327  |     value++;
328  |   }
329  |   value_len=strlen(value);
330  |   if (value[value_len-1] == '"') {
331  |     value[value_len-1]='\0';
332  |   }
333  | 
334  |   printf("set_const name=(%s), value=(%s)\n", name, value);
335  |   if (CO_set_const(name, value) == 0) {
336  |     strcpy(result_buf, "Constant successfully set\n");
337  |   }
338  |   else {
339  |     str = CO_const_to_string(name);
340  |     sprintf(result_buf, "Constant not successfully set\nReverting to:   %s=%s\n", name, str);
341  |     free(str);
342  |   }
343  | 
344  |   result = (char *)calloc(1, strlen(result_buf)+1);
345  |   strcpy(result, result_buf);
346  | 
347  |   free(tmp_input);
348  |   return result;
349  | } /* set_const() */
350  | 
351  | static char *set_consts(char *input) {
352  |   /* Client wishes to set constants. */
353  |   return CO_set();
354  | } /* set_consts() */
355  | 
356  | static char *set_props(char *input) {
357  |   /* Client wishes to set properties. */
358  |   return PR_set();
359  | } /* set_props() */
360  | 
361  | static char *command_set(char *input) {
362  |   return command_execute(input, "Set", set);
363  | } /* command_set() */
364  | 
365  | static char *command_sql(char *input) {
366  |   char *str;
367  |   char output_buffer[STR_XXL];
368  |   char *current_character;
369  |   char *whois_query;
370  |   char *sql_str;
371  | 
372  |   char *res=NULL;
373  | 
374  |   SQ_result_set_t *sql_result=NULL;
375  |   SQ_connection_t *sql_connection;
376  | 
377  |   sql_connection = SQ_get_connection(CO_get_host(), CO_get_database_port(), CO_get_database(), CO_get_user(), CO_get_password() );
378  | 
379  |   if (sql_connection == NULL) {
380  |     printf("/* Check for errors */\n");
381  |   }
382  | 
383  |   /* skip over the "sql" */
384  |   sql_str = input+3;
385  |   /* skip over white space */
386  |   while (sql_str[0] == ' ') {
387  |     sql_str++;
388  |   }
389  | 
390  |   strcpy(output_buffer, "");
391  | 
392  |   if (sql_connection != NULL) {
393  |     if (strcmp(sql_str, "status") == 0) {
394  |       /* Get the status of the database */
395  |       res = SQ_info_to_string(sql_connection);
396  |     }
397  |     else {
398  |       if (strcmp(sql_str, "") == 0) {
399  |         /* Execute the default query (from the properties file) */
400  |         sql_result = SQ_execute_query(sql_connection, CO_get_query());
401  |       }
402  |       else {
403  |         /* Execute an sql query */
404  |         sql_result = SQ_execute_query(sql_connection, sql_str);
405  |       }
406  |       if (sql_result != NULL) {
407  |         res = SQ_result_to_string(sql_result);
408  |       }
409  |       else {
410  |         printf("no results\n");
411  |       }
412  |     }
413  |     if (res != NULL) {
414  |       sprintf(output_buffer, "%s", res);
415  |     }
416  |     else {
417  |       printf("empty results\n");
418  |     }
419  |   }
420  |   else {
421  |     printf("Failed to make connection\n");
422  |   }
423  | 
424  |   /*
425  |   strcat(output_buffer, mysql_info(sql_connection));
426  |   */
427  | 
428  |   strcat(output_buffer, "XXX Results from mysql_info(sql_connection) is meant to go here.  But it's not working!");
429  | 
430  |   /*
431  |   str = (char *)CopyString(output_buffer);
432  |   */
433  |   str = (char *)calloc(1, strlen(output_buffer)+1);
434  |   strcpy(str, output_buffer);
435  | 
436  |   free(res);
437  |   SQ_free_result(sql_result);
438  | 
439  |   SQ_close_connection(sql_connection);
440  | 
441  |   return str;
442  | 
443  | } /* command_sql() */
444  | 
445  | 
446  | /* process_input() */
447  | /*++++++++++++++++++++++++++++++++++++++
448  | 
449  |   Process the input.
450  | 
451  |   int sock  The socket to connect to.
452  | 
453  |   More:
454  |   +html+ <PRE>
455  |   Author:
456  |         ottrey
457  |   +html+ </PRE>
458  |   ++++++++++++++++++++++++++++++++++++++*/
459  | static int process_input(char *input, int sock) {
460  |   int connected = 1;
461  |   char *input_ptr;
462  |   char *output;
463  |   char *command_name;
464  |   int  index;
465  |   int repeat=0;
466  | 
467  |   input_ptr = input;
468  | 
469  |   if (strncmp(input, "repeat", 6) == 0) {
470  |     /* XXX This is a really dodgy call, that hopefully converts
471  |     the string to the value of the first found integer. */
472  |     repeat = atoi(input+7);
473  |     input_ptr= command_repeat(input);
474  |   }
475  | 
476  |   index = find_command(input_ptr, command);
477  | 
478  |   do {
479  |     switch (index) {
480  |       case -1:
481  |         /* Command not found */
482  |         output = command_help(NULL);
483  |         break;
484  | 
485  |       default: 
486  |         output = command[index].function(input_ptr);
487  |     }
488  | 
489  |     if(output == NULL) {
490  |       connected = 0;
491  |     } else {
492  |       /*
493  |       printf("thread output=\n%s\n", output);
494  |       */
495  |       if ( CO_get_clear_screen() == 1 ) {
496  |         SK_puts(sock, CLEAR_SCREEN);
497  |       }
498  |       SK_puts(sock, output);
499  |       SK_puts(sock, "\n");
500  |       SK_puts(sock, CO_get_prompt());
501  |     }
502  | 
503  |     free(output);
504  | 
505  |     if (repeat > 0) {
506  |       repeat--;
507  |       sleep(CO_get_sleep_time());
508  |     }
509  | 
510  |   } while (repeat > 0);
511  | 
512  |   return connected;
513  | 
514  | } /* process_input() */
515  | 
516  | static void log_config(const char *user, const char *status) {
517  |   FILE *logf;
518  |   char *str;
519  |   time_t now;
520  | 
521  |   time(&now);
522  | 
523  |   if (CO_get_config_logging() == 1) {
524  |     
525  |     if (strcmp(CO_get_config_logfile(), "stdout") == 0) {
526  |       printf(LOG_CONFIG, TH_get_id(), user, status, ctime(&now));
527  |     }
528  |     else {
529  |       logf = fopen(CO_get_config_logfile(), "a");
530  |       fprintf(logf, LOG_CONFIG, TH_get_id(), user, status, ctime(&now));
531  |       fclose(logf);
532  |     }
533  |   }
534  | 
535  | } /* log_config() */
536  |  
537  | /* XXX Doh! These only change the server's terminal.  We need some
538  |    tricky escape sequence to send over the socket. */ 
539  | static void echo_off(int sock) {
540  |   struct termio state;
541  | 
542  |   ioctl(0, TIOCGETP, &state);
543  |   state.c_lflag &= ~ECHO;
544  |   ioctl(0, TIOCSETP, &state);
545  | } /* echo_off() */
546  | 
547  | /* XXX Doh! These only change the server's terminal.  We need some
548  |    tricky escape sequence to send over the socket. */ 
549  | static void echo_on(int sock) {
550  |   struct termio state;
551  | 
552  |   ioctl(0, TIOCGETP, &state);
553  |   state.c_lflag |= ECHO;
554  |   ioctl(0, TIOCSETP, &state);
555  | } /* echo_on() */
556  | 
557  | static char *authenticate_user(int sock) {
558  |   char *user = NULL;
559  |   char Salt[2] = "DB";
560  |   char input[MAX_INPUT_SIZE];
561  |   int read_result;
562  |   char *password=NULL;
563  |   char *user_password=NULL;
564  |   char user_buf[10];
565  | 
566  |   SK_puts(sock, LOGIN_PROMPT);
567  |   read_result = SK_gets(sock, input, MAX_INPUT_SIZE);
568  | 
569  |   strncpy(user_buf, input, 10);
570  | 
571  |   SK_puts(sock, PASSWD_PROMPT);
572  |   /* XXX These aren't working.
573  |   SK_puts(sock, ECHO_ON);
574  |   echo_off(sock);
575  |   */
576  |   read_result = SK_gets(sock, input, MAX_INPUT_SIZE);
577  |   /* XXX These aren't working.
578  |   echo_on(sock);
579  |   SK_puts(sock, ECHO_OFF);
580  |   */
581  | 
582  |   password = (char *)crypt(input, Salt);
583  | 
584  |   user_password = PR_get_property(user_buf, DEFAULT_USER_NAME);
585  | 
586  |   if (user_password != NULL) {
587  |     if (strcmp(password, user_password) == 0) {
588  |       user = (char *)calloc(1, strlen(user_buf)+1);
589  |       strcpy(user, user_buf);
590  |     }
591  |   }
592  | 
593  |   if (user == NULL) {
594  |     log_config(user_buf, "unsuccesful login attempt");
595  |   }
596  | 
597  |   return user;
598  | 
599  | } /* authenticate_user() */
600  | 
601  | void PC_interact(int sock) {
602  |   char input[MAX_INPUT_SIZE];
603  |   int connected = 1;
604  |   int read_result;
605  |   char *welcome;
606  |   char *user=NULL;
607  | 
608  |   /* Welcome the client */
609  |   SK_puts(sock, CO_get_welcome());
610  | 
611  |   /* Authenticate the user */
612  |   if (CO_get_authenticate() == 1) {
613  |     user = authenticate_user(sock);
614  |   }
615  |   else {
616  |     user="nobody";
617  |   }
618  | 
619  |   if (user != NULL) {
620  |     /* Log admin logging on */
621  |     log_config(user, "logged on");
622  | 
623  |     SK_puts(sock, CO_get_prompt());
624  | 
625  |     while (connected) {
626  |       /* Read input */
627  |       read_result = SK_gets(sock, input, MAX_INPUT_SIZE);
628  |       if (read_result == -1) {
629  |         connected = 0;
630  |       }
631  |       else if (read_result == -2) {
632  |         printf("Thread received a control-c\n");
633  |         connected = 0;
634  |       }
635  |       connected = process_input(input, sock);
636  |     }
637  | 
638  |     /* Log admin logging off */
639  |     log_config(user, "logged off");
640  |   }
641  | 
642  |   /* Close the socket */
643  |   SK_close(sock);
644  | 
645  | } /* PC_interact() */
646  |