1 | /*************************************** 2 | $Revision: 1.39 $ 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 | Authors : ottrey@ripe.net - initial design 12 | marek@ripe.net - restructured and rewritten 13 | 14 | To Do : Add a facility to take callbacks instead of 15 | hard-coding menu options. 16 | Add in all the menu support provided by the GLib 17 | libraries. 18 | (Remove strtok if multiple threads are to be used.) 19 | use gnu readline with expansion and history 20 | ******************/ /****************** 21 | Copyright (c) 1999,2000,2001,2002 RIPE NCC 22 | 23 | All Rights Reserved 24 | 25 | Permission to use, copy, modify, and distribute this software and its 26 | documentation for any purpose and without fee is hereby granted, 27 | provided that the above copyright notice appear in all copies and that 28 | both that copyright notice and this permission notice appear in 29 | supporting documentation, and that the name of the author not be 30 | used in advertising or publicity pertaining to distribution of the 31 | software without specific, written prior permission. 32 | 33 | THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 34 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL 35 | AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY 36 | DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 37 | AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 38 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 39 | ***************************************/ 40 | 41 | #define PC_IMPL 42 | #include "rip.h" 43 | 44 | #include <stdio.h> 45 | #include <stdlib.h> 46 | #include <time.h> 47 | #include <sys/ioctl.h> 48 | #include <glib.h> 49 | 50 | /*+ Maximum size of input that can be recieved from the client. +*/ 51 | #define MAX_INPUT_SIZE 1024 52 | 53 | extern char* crypt(const char *, const char *); /* crypt stuff */ 54 | 55 | 56 | /*++++++++++++++++++++++++++++++++++++++ 57 | 58 | Finds a command by name in the array of command function structures. 59 | 60 | int find_command returns the index to the correct row of the array, or -1 61 | if the command could not be found. 62 | 63 | char *comm_name name of the command 64 | 65 | Command *comm array of command function structures. 66 | ++++++++++++++++++++++++++++++++++++++*/ 67 | static 68 | int find_command(char *comm_name, Command *comm) 69 | { 70 | int i; 71 | char *comm_buffer = wr_string(comm_name); 72 | char *token, *cursor; 73 | int index = -1; 74 | 75 | cursor = comm_buffer; 76 | if( (token = strsep(&cursor, " \t")) != NULL) { 77 | for (i=0; comm[i].name != NULL; i++) { 78 | if ( strcmp(token, comm[i].name) == 0) { 79 | index = i; 80 | break; 81 | } 82 | } 83 | } 84 | 85 | UT_free(comm_buffer); 86 | 87 | return index; /* returns -1 when command not found */ 88 | } /* find_command() */ 89 | 90 | 91 | int show_commands(Command *comm, char *comm_name, GString *output) 92 | { 93 | int i = 0; 94 | 95 | g_string_sprintfa(output, "%scommands are:\n\n", comm_name); 96 | while (comm[i].name != NULL) { 97 | g_string_sprintfa(output, "%s\t%s\n", comm[i].name, comm[i].help); 98 | i++; 99 | } 100 | 101 | return 1; 102 | } /* show_commands() */ 103 | 104 | 105 | /*++++++++++++++++++++++++++++++++++++++ 106 | 107 | int command_execute 108 | executes a command from the given array, matching 109 | given name. Passes input, output and condat to the 110 | function found in the array. Command name is 111 | removed from the input line so only next words are 112 | passed over to the function. 113 | 114 | returns the code of the last command. Code 115 | PC_RET_QUIT is reserved to indicate that the connection 116 | should be closed. 117 | 118 | Command *comm array of command function structures (defined in 119 | protocol_config.h) 120 | 121 | char *comm_name name of the command to be run 122 | 123 | char *input rest of the command line 124 | 125 | GString *output dynamically built output string 126 | 127 | sk_conn_st *condat socket structure for this connection (some commands 128 | use it directly instead of storing the output) 129 | 130 | ++++++++++++++++++++++++++++++++++++++*/ 131 | int command_execute(Command *comm, char *comm_name, 132 | char *input, GString *output, sk_conn_st *condat) 133 | { 134 | char *name, *next_word, *tmp_input; 135 | int index, result=0; 136 | 137 | /* find the command in the string - first whitespace delimited word */ 138 | /* make a copy of the input */ 139 | dieif( (tmp_input = wr_string(input)) == NULL ); 140 | next_word = tmp_input; 141 | 142 | /* find the first word and set the pointer to the rest of the string */ 143 | name = strsep(&next_word, " \t"); 144 | 145 | if( name != NULL && strlen(name) != 0 ) { 146 | index = find_command(name, comm); 147 | if( index != -1 ) { 148 | if( next_word != NULL ) { 149 | /* advance the input pointer to the next word */ 150 | while( *next_word != '\0' 151 | && isspace( *(unsigned char *)next_word) ) { 152 | next_word++; 153 | } 154 | } 155 | else { 156 | next_word = ""; 157 | } 158 | 159 | /* run, Forrest, run...*/ 160 | result = comm[index].function(next_word, output, condat); 161 | } 162 | else { 163 | g_string_sprintfa(output, "invalid %scommand: %s\n", comm_name, name); 164 | show_commands(comm, comm_name, output); 165 | result = 2; 166 | } 167 | } 168 | else { 169 | show_commands(comm, comm_name, output); 170 | result = 2; 171 | } 172 | 173 | UT_free(tmp_input); 174 | 175 | return result; 176 | } /* command_execute() */ 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | /* proces_input() */ 185 | /*++++++++++++++++++++++++++++++++++++++ 186 | 187 | Process the input. Finds the proper command in the top level command 188 | array and invokes the function associated with it with the input and 189 | output data as arguments. 190 | 191 | int process_input returns 1 if the connection is to be kept 192 | or 0 when it should be finished - that is, 193 | when command_execute() returns PC_RET_QUIT. 194 | 195 | char *input input (presumably a command) 196 | 197 | sk_conn_st *condat connection data 198 | 199 | More: 200 | +html+ <PRE> 201 | Author: 202 | ottrey 203 | marek - changes and documentation. 204 | +html+ </PRE> 205 | ++++++++++++++++++++++++++++++++++++++*/ 206 | static 207 | int process_input(char *input, sk_conn_st *condat) 208 | { 209 | int index; 210 | int res=0; 211 | GString *output = g_string_new(""); 212 | 213 | index = find_command(input, command); 214 | 215 | switch (index) { 216 | case -1: 217 | /* Command not found */ 218 | command_help(NULL, output, condat); 219 | break; 220 | 221 | default: 222 | res = command_execute(command, "", input, output, condat); 223 | } 224 | 225 | if(res != PC_RET_QUIT) { 226 | /* 227 | printf("thread output=\n%s\n", output); 228 | */ 229 | if ( CO_get_clear_screen() == 1 ) { 230 | SK_cd_puts(condat, CLEAR_SCREEN); 231 | } 232 | SK_cd_puts(condat, output->str); 233 | SK_cd_printf(condat, "\n\n=%d= %s", res, CO_get_prompt()); 234 | 235 | } 236 | 237 | g_string_free( output, TRUE ); 238 | 239 | /* the return value is the connection state: 1=still open, 0=to be closed 240 | */ 241 | 242 | return (res != PC_RET_QUIT); 243 | } /* process_input() */ 244 | 245 | 246 | /*++++++++++++++++++++++++++++++++++++++ 247 | 248 | Authenticates the user - asks for password and checks it. The password is 249 | echoed by the tcp stack, to disable that one would have to attach a tty 250 | to this connection and switch to raw mode or try the hard way - renegotiate 251 | the telnet connection to switch to character mode (and, possibly, back). 252 | The latter has the drawback that to do it right it has to be able to check 253 | whether there's telnet on the other side - otherwise, if the connection 254 | is made by a program just connecting to the socket, garbage will result. 255 | However, in such case password checking might be not a good idea. 256 | 257 | sk_conn_st *condat 258 | 259 | More: 260 | +html+ <PRE> 261 | Author: 262 | ottrey 263 | marek - slight changes and documentation. 264 | +html+ </PRE> 265 | ++++++++++++++++++++++++++++++++++++++*/ 266 | static 267 | char *authenticate_user(sk_conn_st *condat) 268 | { 269 | char *user = NULL; 270 | const char Salt[2] = "DB"; 271 | char input[MAX_INPUT_SIZE]; 272 | int read_result; 273 | char *password=NULL; 274 | char *user_password=NULL; 275 | char user_buf[10]; 276 | 277 | SK_cd_puts(condat, LOGIN_PROMPT); 278 | read_result = SK_cd_gets(condat, input, MAX_INPUT_SIZE); 279 | 280 | strncpy(user_buf, input, 10); 281 | 282 | SK_cd_puts(condat, PASSWD_PROMPT); 283 | /* XXX These aren't working. 284 | SK_puts(sock, ECHO_ON); 285 | echo_off(sock); 286 | */ 287 | read_result = SK_cd_gets(condat, input, MAX_INPUT_SIZE); 288 | /* XXX These aren't working. 289 | echo_on(sock); 290 | SK_puts(sock, ECHO_OFF); 291 | */ 292 | 293 | password = crypt(input, Salt); 294 | 295 | user_password = PR_get_property(user_buf, DEFAULT_USER_NAME); 296 | 297 | if (user_password != NULL) { 298 | if (strcmp(password, user_password) == 0) { 299 | user = UT_strdup(user_buf); 300 | } 301 | } 302 | 303 | 304 | return user; 305 | 306 | } /* authenticate_user() */ 307 | 308 | 309 | 310 | /*++++++++++++++++++++++++++++++++++++++ 311 | 312 | Main function that talks to the user connected on the given socket. 313 | Starts by authenticating the user (if this mode is active) 314 | and greeting her with the uptime data. Then it loops reading and executing 315 | commands until the "quit" command (or any other command that causes 316 | process_input to return 0). 317 | 318 | int sock connected client socket 319 | 320 | ++++++++++++++++++++++++++++++++++++++*/ 321 | void PC_interact(int sock) { 322 | char input[MAX_INPUT_SIZE]; 323 | int connected = 1; 324 | char *user=NULL; 325 | sk_conn_st condat; 326 | 327 | memset( &condat, 0, sizeof(condat)); 328 | condat.sock = sock; 329 | SK_getpeerip(sock, &(condat.rIP)); 330 | condat.ip = SK_getpeername(sock); /* XXX *alloc involved */ 331 | 332 | /* Welcome the client */ 333 | SK_cd_puts(&condat, CO_get_welcome()); 334 | 335 | /* Authenticate the user */ 336 | if (CO_get_authenticate() == 1) { 337 | user = authenticate_user(&condat); 338 | 339 | if (user == NULL) { 340 | ER_inf_va(FAC_PC, ASP_PC_I_SESSION, 341 | "unsuccesful login attempt from %s", condat.ip ); 342 | } 343 | } 344 | else { 345 | user="nobody"; 346 | } 347 | 348 | if (user != NULL) { 349 | 350 | /* Log admin logging on */ 351 | ER_inf_va(FAC_PC, ASP_PC_I_SESSION, 352 | "user %s from %s logged on", user, condat.ip ); 353 | 354 | { 355 | show_uptime("", NULL, &condat); 356 | } 357 | 358 | SK_cd_printf(&condat, "=0= %s", CO_get_prompt()); 359 | 360 | while (condat.rtc==0 && connected) { 361 | char *icopy; 362 | 363 | /* Read input. Quit if no input (socket closed) */ 364 | if( SK_cd_gets(&condat, input, MAX_INPUT_SIZE) <= 0 ) { 365 | break; 366 | } 367 | 368 | /* filter junk out: leading/trailing/redundant whitespaces */ 369 | icopy = ut_string_compress( input ); 370 | 371 | /* set thread accounting */ 372 | TA_setactivity(icopy); 373 | TA_increment(); 374 | 375 | /* if( strlen(icopy) > 0 ) {*/ 376 | { 377 | ER_inf_va(FAC_PC, ASP_PC_I_COMMAND, icopy); 378 | 379 | connected = process_input(icopy, &condat); 380 | } 381 | 382 | TA_setactivity(""); 383 | 384 | UT_free(icopy); 385 | } 386 | 387 | /* Log admin logging off */ 388 | ER_inf_va(FAC_PC, ASP_PC_I_SESSION, 389 | "user %s from %s logged off", user, condat.ip ); 390 | 391 | } 392 | 393 | UT_free(condat.ip); 394 | } /* PC_interact() */ 395 |