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.37 $
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 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 #include <stdio.h>
41 #include <stdlib.h>
42 /*** solaris' header file doesn't contain the crypt definition...
43 #include <unistd.h> */
44
45 extern char* crypt(const char *, const char *); /* crypt stuff */
46 #include <time.h> /* Time stuff */
47 #include <sys/ioctl.h> /* Terminal control stuff */
48
49 #include "thread.h"
50 #include "constants.h"
51 #include "properties.h"
52 #include <glib.h>
53
54 #include "sk.h"
55 #include "ta.h"
56
57 #include "ut_string.h"
58 #include "memwrap.h"
59
60 #include "pc_commands.h"
61
62 #define PC_IMPL
63 #include "protocol_config.h"
64
65
66 /*++++++++++++++++++++++++++++++++++++++
67
68 Finds a command by name in the array of command function structures.
69
70 int find_command returns the index to the correct row of the array, or -1
71 if the command could not be found.
72
73 char *comm_name name of the command
74
75 Command *comm array of command function structures.
76 ++++++++++++++++++++++++++++++++++++++*/
77 static
78 int find_command(char *comm_name, Command *comm)
/* [<][>][^][v][top][bottom][index][help] */
79 {
80 int i;
81 char *comm_buffer = wr_string(comm_name);
82 char *token, *cursor;
83 int index = -1;
84
85 cursor = comm_buffer;
86 if( (token = strsep(&cursor, " \t")) != NULL) {
87 for (i=0; comm[i].name != NULL; i++) {
88 if ( strcmp(token, comm[i].name) == 0) {
89 index = i;
90 break;
91 }
92 }
93 }
94
95 wr_free(comm_buffer);
96
97 return index; /* returns -1 when command not found */
98 } /* find_command() */
99
100
101 int show_commands(Command *comm, char *comm_name, GString *output)
/* [<][>][^][v][top][bottom][index][help] */
102 {
103 int i = 0;
104
105 g_string_sprintfa(output, "%scommands are:\n\n", comm_name);
106 while (comm[i].name != NULL) {
107 g_string_sprintfa(output, "%s\t%s\n", comm[i].name, comm[i].help);
108 i++;
109 }
110
111 return 1;
112 } /* show_commands() */
113
114
115 /*++++++++++++++++++++++++++++++++++++++
116
117 int command_execute
118 executes a command from the given array, matching
119 given name. Passes input, output and condat to the
120 function found in the array. Command name is
121 removed from the input line so only next words are
122 passed over to the function.
123
124 returns the code of the last command. Code
125 PC_RET_QUIT is reserved to indicate that the connection
126 should be closed.
127
128 Command *comm array of command function structures (defined in
129 protocol_config.h)
130
131 char *comm_name name of the command to be run
132
133 char *input rest of the command line
134
135 GString *output dynamically built output string
136
137 sk_conn_st *condat socket structure for this connection (some commands
138 use it directly instead of storing the output)
139
140 ++++++++++++++++++++++++++++++++++++++*/
141 int command_execute(Command *comm, char *comm_name,
/* [<][>][^][v][top][bottom][index][help] */
142 char *input, GString *output, sk_conn_st *condat)
143 {
144 char *name, *next_word, *tmp_input;
145 int index, result=0;
146
147 /* find the command in the string - first whitespace delimited word */
148 /* make a copy of the input */
149 dieif( (tmp_input = wr_string(input)) == NULL );
150 next_word = tmp_input;
151
152 /* find the first word and set the pointer to the rest of the string */
153 name = strsep(&next_word, " \t");
154
155 if( name != NULL && strlen(name) != 0 ) {
156 index = find_command(name, comm);
157 if( index != -1 ) {
158 if( next_word != NULL ) {
159 /* advance the input pointer to the next word */
160 while( *next_word != '\0'
161 && isspace( *(unsigned char *)next_word) ) {
162 next_word++;
163 }
164 }
165 else {
166 next_word = "";
167 }
168
169 /* run, Forrest, run...*/
170 result = comm[index].function(next_word, output, condat);
171 }
172 else {
173 g_string_sprintfa(output, "invalid %scommand: %s\n", comm_name, name);
174 show_commands(comm, comm_name, output);
175 result = 2;
176 }
177 }
178 else {
179 show_commands(comm, comm_name, output);
180 result = 2;
181 }
182
183 free(tmp_input);
184
185 return result;
186 } /* command_execute() */
187
188
189
190
191
192
193
194 /* proces_input() */
195 /*++++++++++++++++++++++++++++++++++++++
196
197 Process the input. Finds the proper command in the top level command
198 array and invokes the function associated with it with the input and
199 output data as arguments.
200
201 int process_input returns 1 if the connection is to be kept
202 or 0 when it should be finished - that is,
203 when command_execute() returns PC_RET_QUIT.
204
205 char *input input (presumably a command)
206
207 sk_conn_st *condat connection data
208
209 More:
210 +html+ <PRE>
211 Author:
212 ottrey
213 marek - changes and documentation.
214 +html+ </PRE>
215 ++++++++++++++++++++++++++++++++++++++*/
216 static
217 int process_input(char *input, sk_conn_st *condat)
/* [<][>][^][v][top][bottom][index][help] */
218 {
219 int index;
220 int res=0;
221 GString *output = g_string_new("");
222
223 index = find_command(input, command);
224
225 switch (index) {
226 case -1:
227 /* Command not found */
228 command_help(NULL, output, condat);
229 break;
230
231 default:
232 res = command_execute(command, "", input, output, condat);
233 }
234
235 if(res != PC_RET_QUIT) {
236 /*
237 printf("thread output=\n%s\n", output);
238 */
239 if ( CO_get_clear_screen() == 1 ) {
240 SK_cd_puts(condat, CLEAR_SCREEN);
241 }
242 SK_cd_puts(condat, output->str);
243 SK_cd_printf(condat, "\n\n=%d= %s", res, CO_get_prompt());
244
245 }
246
247 g_string_free( output, TRUE );
248
249 /* the return value is the connection state: 1=still open, 0=to be closed
250 */
251
252 return (res != PC_RET_QUIT);
253 } /* process_input() */
254
255
256 /*++++++++++++++++++++++++++++++++++++++
257
258 Authenticates the user - asks for password and checks it. The password is
259 echoed by the tcp stack, to disable that one would have to attach a tty
260 to this connection and switch to raw mode or try the hard way - renegotiate
261 the telnet connection to switch to character mode (and, possibly, back).
262 The latter has the drawback that to do it right it has to be able to check
263 whether there's telnet on the other side - otherwise, if the connection
264 is made by a program just connecting to the socket, garbage will result.
265 However, in such case password checking might be not a good idea.
266
267 sk_conn_st *condat
268
269 More:
270 +html+ <PRE>
271 Author:
272 ottrey
273 marek - slight changes and documentation.
274 +html+ </PRE>
275 ++++++++++++++++++++++++++++++++++++++*/
276 static
277 char *authenticate_user(sk_conn_st *condat)
/* [<][>][^][v][top][bottom][index][help] */
278 {
279 char *user = NULL;
280 const char Salt[2] = "DB";
281 char input[MAX_INPUT_SIZE];
282 int read_result;
283 char *password=NULL;
284 char *user_password=NULL;
285 char user_buf[10];
286
287 SK_cd_puts(condat, LOGIN_PROMPT);
288 read_result = SK_cd_gets(condat, input, MAX_INPUT_SIZE);
289
290 strncpy(user_buf, input, 10);
291
292 SK_cd_puts(condat, PASSWD_PROMPT);
293 /* XXX These aren't working.
294 SK_puts(sock, ECHO_ON);
295 echo_off(sock);
296 */
297 read_result = SK_cd_gets(condat, input, MAX_INPUT_SIZE);
298 /* XXX These aren't working.
299 echo_on(sock);
300 SK_puts(sock, ECHO_OFF);
301 */
302
303 password = crypt(input, Salt);
304
305 user_password = PR_get_property(user_buf, DEFAULT_USER_NAME);
306
307 if (user_password != NULL) {
308 if (strcmp(password, user_password) == 0) {
309 /*user = (char *)calloc(1, strlen(user_buf)+1);*/
310 dieif( wr_malloc((void **)&user, strlen(user_buf)+1) != UT_OK);
311 strcpy(user, user_buf);
312 }
313 }
314
315
316 return user;
317
318 } /* authenticate_user() */
319
320
321
322 /*++++++++++++++++++++++++++++++++++++++
323
324 Main function that talks to the user connected on the given socket.
325 Starts by authenticating the user (if this mode is active)
326 and greeting her with the uptime data. Then it loops reading and executing
327 commands until the "quit" command (or any other command that causes
328 process_input to return 0).
329
330 int sock connected client socket
331
332 ++++++++++++++++++++++++++++++++++++++*/
333 void PC_interact(int sock) {
/* [<][>][^][v][top][bottom][index][help] */
334 char input[MAX_INPUT_SIZE];
335 int connected = 1;
336 char *user=NULL;
337 sk_conn_st condat;
338
339 memset( &condat, 0, sizeof(condat));
340 condat.sock = sock;
341 SK_getpeerip(sock, &(condat.rIP));
342 condat.ip = SK_getpeername(sock); /* XXX *alloc involved */
343
344 /* Welcome the client */
345 SK_cd_puts(&condat, CO_get_welcome());
346
347 /* Authenticate the user */
348 if (CO_get_authenticate() == 1) {
349 user = authenticate_user(&condat);
350
351 if (user == NULL) {
352 ER_inf_va(FAC_PC, ASP_PC_I_SESSION,
353 "unsuccesful login attempt from %s", condat.ip );
354 }
355 }
356 else {
357 user="nobody";
358 }
359
360 if (user != NULL) {
361
362 /* Log admin logging on */
363 ER_inf_va(FAC_PC, ASP_PC_I_SESSION,
364 "user %s from %s logged on", user, condat.ip );
365
366 {
367 show_uptime("", NULL, &condat);
368 }
369
370 SK_cd_printf(&condat, "=0= %s", CO_get_prompt());
371
372 while (condat.rtc==0 && connected) {
373 char *icopy;
374
375 /* Read input. Quit if no input (socket closed) */
376 if( SK_cd_gets(&condat, input, MAX_INPUT_SIZE) <= 0 ) {
377 break;
378 }
379
380 /* filter junk out: leading/trailing/redundant whitespaces */
381 icopy = ut_string_compress( input );
382
383 /* set thread accounting */
384 TA_setactivity(icopy);
385 TA_increment();
386
387 /* if( strlen(icopy) > 0 ) {*/
388 {
389 ER_inf_va(FAC_PC, ASP_PC_I_COMMAND, icopy);
390
391 connected = process_input(icopy, &condat);
392 }
393
394 TA_setactivity("");
395
396 free(icopy);
397 }
398
399 /* Log admin logging off */
400 ER_inf_va(FAC_PC, ASP_PC_I_SESSION,
401 "user %s from %s logged off", user, condat.ip );
402
403 }
404
405 wr_free(condat.ip);
406 } /* PC_interact() */
407