modules/pc/protocol_config.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- find_command
- show_commands
- command_execute
- process_input
- authenticate_user
- PC_interact
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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,
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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) {
/* [<][>][^][v][top][bottom][index][help] */
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