source: trunk/src/yulectl.c@ 18

Last change on this file since 18 was 1, checked in by katerina, 19 years ago

Initial import

File size: 13.9 KB
Line 
1/* SAMHAIN file system integrity testing */
2/* Copyright (C) 2003 Rainer Wichmann */
3/* */
4/* This program is free software; you can redistribute it */
5/* and/or modify */
6/* it under the terms of the GNU General Public License as */
7/* published by */
8/* the Free Software Foundation; either version 2 of the License, or */
9/* (at your option) any later version. */
10/* */
11/* This program is distributed in the hope that it will be useful, */
12/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
13/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
14/* GNU General Public License for more details. */
15/* */
16/* You should have received a copy of the GNU General Public License */
17/* along with this program; if not, write to the Free Software */
18/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20#include "config_xor.h"
21
22#include <stddef.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <errno.h>
27
28#include <unistd.h>
29#include <fcntl.h>
30
31#include <sys/socket.h>
32#include <sys/un.h>
33
34#include <signal.h>
35#include <pwd.h>
36
37#if !defined(AF_FILE)
38#define AF_FILE AF_UNIX
39#endif
40
41#define SH_MAXMSG 209
42
43static int sock = -1;
44static char * sockname = NULL;
45
46static char password[15] = "";
47
48static int verbose = 0;
49
50#ifdef SH_STEALTH
51char * globber(const char * string);
52#define _(string) globber(string)
53#define N_(string) string
54#else
55#define _(string) string
56#define N_(string) string
57#endif
58
59#ifdef SH_STEALTH
60#ifndef SH_MAX_GLOBS
61#define SH_MAX_GLOBS 32
62#endif
63char * globber(const char * str)
64{
65 register int i, j;
66 static int count = -1;
67 static char glob[SH_MAX_GLOBS][128];
68
69 ++count; if (count > (SH_MAX_GLOBS-1) ) count = 0;
70 j = strlen(str);
71 if (j > 127) j = 127;
72
73 for (i = 0; i < j; ++i)
74 {
75 if (str[i] != '\n' && str[i] != '\t')
76 glob[count][i] = str[i] ^ XOR_CODE;
77 else
78 glob[count][i] = str[i];
79 }
80 glob[count][j] = '\0';
81 return glob[count];
82}
83#endif
84
85#define CLIENT _("yulectl")
86
87
88int
89make_named_socket (char * sockname)
90{
91 int sock;
92
93#if 0
94 struct sockaddr_un name;
95 size_t size;
96#else
97 (void) sockname;
98#endif
99
100 /* Create the socket. */
101
102 sock = socket (PF_UNIX, SOCK_STREAM, 0);
103 if (sock < 0)
104 {
105 perror (_("ERROR: socket"));
106 return -1;
107 }
108
109#if 0
110 /* Bind a name to the socket. */
111 name.sun_family = AF_FILE;
112 strcpy (name.sun_path, sockname);
113
114 /* The size of the address is
115 the offset of the start of the filename,
116 plus its length,
117 plus one for the terminating null byte. */
118 size = (offsetof (struct sockaddr_un, sun_path)
119 + strlen (name.sun_path) + 1);
120
121 if (bind (sock, (struct sockaddr *) &name, size) < 0)
122 {
123 perror (_("ERROR: bind"));
124 return -1;
125 }
126#endif
127
128 return sock;
129}
130
131void
132termination_handler (int signum)
133{
134 /* Clean up. */
135 if (signum != 0)
136 {
137 if (verbose)
138 fprintf(stdout, _("# Terminated on signal %d\n"), signum);
139 }
140#if 0
141 if (sockname != NULL) unlink (sockname);
142#endif
143 if (sock >= 0 ) close (sock);
144
145 return;
146}
147
148
149int send_to_server (char * serversock, char * message)
150{
151 struct sockaddr_un name;
152 /* size_t size; */
153 int size;
154 int nbytes;
155
156 /* Initialize the server socket address.
157 */
158 name.sun_family = AF_UNIX;
159 strncpy (name.sun_path, serversock, sizeof(name.sun_path) - 1);
160 size = (offsetof (struct sockaddr_un, sun_path)
161 + strlen (name.sun_path) + 1);
162
163 nbytes = connect(sock, (struct sockaddr *) & name, size);
164 if (nbytes < 0)
165 {
166 perror (_("ERROR: connect"));
167 return -1;
168 }
169
170 /* Send the datagram.
171 nbytes = sendto (sock, message, strlen (message) + 1, 0,
172 (struct sockaddr *) & name, size);
173 */
174 nbytes = send (sock, message, strlen (message) + 1, 0);
175
176 if (nbytes < 0)
177 {
178 perror (_("ERROR: send"));
179 return -1;
180 }
181 return 0;
182}
183
184static int getline_from_server (int sock, char * buf, int size)
185{
186 int nbytes = 0;
187 int status = 0;
188 char * p = buf;
189
190 do {
191 status = read (sock, p, 1);
192 if (status <= 0)
193 {
194 buf[nbytes] = '\0';
195 return ((status == 0) ? nbytes : status);
196 }
197 else if (*p == '\0')
198 {
199 return nbytes;
200 }
201 ++nbytes; ++p;
202 } while (nbytes < size);
203 buf[size-1] = '\0';
204 return 0;
205}
206
207int recv_from_server (char * message)
208{
209 int nbytes = 0;
210 char recvmsg[SH_MAXMSG];
211 int num = 0;
212 int good = -1;
213 int islist = 0;
214 char * p;
215
216 if (password[0] == '\0')
217 {
218 if (message[0] == 'L' && message[1] == 'I' &&
219 message[2] == 'S' && message[3] == 'T')
220 {
221 islist = 1;
222 }
223 if (message[0] == 'P' && message[1] == 'R' &&
224 message[2] == 'O' && message[3] == 'B' && message[4] == 'E' )
225 {
226 islist = 1;
227 }
228 }
229 else
230 {
231 p = &message[strlen(password)+1];
232 if (p[0] == 'L' && p[1] == 'I' &&
233 p[2] == 'S' && p[3] == 'T')
234 {
235 islist = 1;
236 }
237 if (p[0] == 'P' && p[1] == 'R' &&
238 p[2] == 'O' && p[3] == 'B' && p[4] == 'E' )
239 {
240 islist = 1;
241 }
242 }
243
244 if (islist == 1)
245 {
246 do {
247 /*
248 nbytes = recvfrom (sock, recvmsg, SH_MAXMSG, 0, NULL, 0);
249 */
250 nbytes = getline_from_server (sock, recvmsg, SH_MAXMSG);
251 if (nbytes < 0)
252 {
253 if (errno == EAGAIN)
254 {
255 return 0;
256 }
257 else
258 {
259 perror (_("ERROR: recv"));
260 return -1;
261 }
262 }
263 else if (nbytes == 0)
264 {
265 return 0;
266 }
267 if (recvmsg[0] == 'E' && recvmsg[1] == 'N' && recvmsg[2] == 'D')
268 {
269 if (verbose && (num == 0))
270 fprintf (stdout, _("# There are no pending commands.\n"));
271 return 0;
272 }
273 ++num;
274 fprintf (stdout, _("%03d: %s\n"), num, recvmsg);
275 } while (nbytes >= 0);
276 }
277 else
278 {
279 /*
280 nbytes = recvfrom (sock, recvmsg, SH_MAXMSG, 0, NULL, 0);
281 */
282 nbytes = recv (sock, recvmsg, SH_MAXMSG, 0);
283 if (nbytes < 0)
284 {
285 perror (_("ERROR: recv"));
286 return -1;
287 }
288 }
289
290 /* Print a diagnostic message. */
291 if (password[0] == '\0')
292 {
293 good = strcmp (message, recvmsg);
294 }
295 else
296 {
297 good = strcmp (&message[strlen(password)+1], recvmsg);
298 }
299
300 if (0 != good)
301 {
302 fprintf (stderr, _("ERROR: Bounced message != original message.\n"));
303 return -1;
304 }
305 else
306 {
307 if (verbose)
308 fprintf (stdout, _("# Message received by server.\n"));
309 }
310
311 return 0;
312}
313
314void usage(char * name)
315{
316 printf(_("\nUsage : %s [-v][-s server_socket] -c command <client_hostname>\n\n"),
317 name);
318
319 printf(_("Purpose : send commands to the server via a socket,\n"));
320 printf(_(" in particular commands that the server would\n"));
321 printf(_(" transfer to the client <client_hostname> when\n"));
322 printf(_(" this client connects to deliver a message.\n\n"));
323
324 printf(_("Commands: RELOAD <reload configuration>\n"));
325 printf(_(" STOP <terminate>\n"));
326 printf(_(" CANCEL <cancel previous command>\n"));
327 printf(_(" LIST <list queued commands>\n"));
328 printf(_(" LISTALL <list queued and last sent commands>\n"));
329 printf(_(" PROBE <probe all clients for necessity of reload>\n"));
330 return;
331}
332
333void fixup_message (char * message)
334{
335 char message2[SH_MAXMSG];
336 char home[4096];
337 FILE * fp;
338 struct passwd * pwent;
339
340
341 pwent = getpwuid(geteuid());
342 if ((pwent == 0) || (pwent->pw_dir == NULL))
343 {
344 if (verbose)
345 fprintf (stderr, _("WARNING: no home directory for euid %ld\n"),
346 (long) geteuid());
347 if (NULL != getenv(_("HOME")))
348 {
349 strncpy(home, getenv(_("HOME")), 4096);
350 home[4095] = '\0';
351 }
352 else
353 {
354 fprintf (stderr, _("ERROR: no home directory for euid %ld (tried $HOME and password database).\n"), (long) geteuid());
355 exit(EXIT_FAILURE);
356 }
357 }
358 else
359 {
360 strncpy(home, pwent->pw_dir, 4096);
361 home[4095] = '\0';
362 }
363
364 if ( (strlen(home) + strlen(_("/.yulectl_cred")) + 1) > 4096)
365 {
366 fprintf (stderr, _("ERROR: path for $HOME is too long.\n"));
367 exit(EXIT_FAILURE);
368 }
369 strcat(home, _("/.yulectl_cred"));
370 fp = fopen(home, "r");
371 if (fp == NULL)
372 {
373 if (verbose && (errno == ENOENT))
374 fprintf (stdout,
375 _("# Password file (%s) missing\n"),
376 home);
377 else if (verbose)
378 fprintf (stdout,
379 _("# Password file (%s) not accessible for euid %ld uid %ld\n"),
380 home, (long)geteuid(), (long)getuid());
381 return;
382 }
383 if (NULL == fgets(message2, SH_MAXMSG, fp))
384 {
385 fprintf (stderr,
386 _("ERROR: empty or unreadable password file (%s).\n"),
387 home);
388 exit(EXIT_FAILURE);
389 }
390 if (strlen(message2) > 15)
391 {
392 fprintf (stderr,
393 _("ERROR: Password too long (max. 14 characters).\n"));
394 exit(EXIT_FAILURE);
395 }
396
397 if ( (0 != strlen(message2)) && ('\n' == message2[strlen(message2)-1]))
398 {
399 message2[strlen(message2)-1] = '\0';
400 }
401 strcpy(password, message2);
402 strcat(message2, "@");
403 fclose(fp);
404
405 strncat(message2, message, SH_MAXMSG - strlen(message2) -1);
406 message2[SH_MAXMSG-1] = '\0';
407 strcpy(message, message2);
408 return;
409}
410
411
412int
413main (int argc, char * argv[])
414{
415
416 char message[SH_MAXMSG] = "";
417 char clientcd[1024];
418 char serversock[256];
419 int status, size;
420 int num = 1;
421 int flag = 0;
422
423#ifdef HAVE_VSNPRINTF
424 status = snprintf(serversock, 256, _("%s/%s.sock"),
425 DEFAULT_PIDDIR, SH_INSTALL_NAME);
426#else
427 if ((strlen(DEFAULT_PIDDIR) + strlen(SH_INSTALL_NAME) + 1 + 6) > 256)
428 {
429 status = -1;
430 }
431 else
432 {
433 status = sprintf (serversock, _("%s/%s.sock"),
434 DEFAULT_PIDDIR, SH_INSTALL_NAME);
435 }
436#endif
437
438 if ((status < 0) || (status > 255))
439 {
440 fprintf(stderr, _("ERROR: Path too long (maximum 255): %s/%s.sock\n"),
441 DEFAULT_PIDDIR, SH_INSTALL_NAME);
442 return (EXIT_FAILURE);
443 }
444
445 while (argc > 1 && argv[num][0] == '-')
446 {
447 switch (argv[num][1])
448 {
449 case 'h':
450 usage(argv[0]);
451 return (EXIT_SUCCESS);
452
453 case 'v':
454 ++verbose;
455 break;
456
457 case 's':
458 --argc; ++num;
459 if (argv[num] == NULL || argv[num][0] == '\0') {
460 usage(argv[0]);
461 fprintf(stderr, _("ERROR: -s: argument missing\n"));
462 return (EXIT_FAILURE);
463 } else {
464 if (strlen(argv[num]) > 255)
465 {
466 fprintf(stderr, _("ERROR: Path too long: %s\n"), argv[num]);
467 return (EXIT_FAILURE);
468 }
469 strncpy (serversock, argv[num], 256);
470 serversock[255] = '\0';
471 }
472 break;
473
474 case 'c':
475 --argc; ++num;
476 if (argv[num] == NULL || argv[num][0] == '\0') {
477 usage(argv[0]);
478 fprintf(stderr, _("ERROR: -c: argument missing\n"));
479 return (EXIT_FAILURE);
480 } else {
481 if (strlen(argv[num]) >= SH_MAXMSG)
482 {
483 fprintf(stderr, _("ERROR: Command too long: %s\n"),
484 argv[num]);
485 return (EXIT_FAILURE);
486 }
487 strncpy (message, argv[num], SH_MAXMSG);
488 message[SH_MAXMSG-1] = '\0';
489 strncat(message, ":", SH_MAXMSG-strlen(message)-1);
490 message[SH_MAXMSG-1] = '\0';
491 flag = 1;
492 }
493 break;
494
495 default:
496 usage(argv[0]);
497 fprintf(stderr, _("ERROR: unknown option -%c\n"), argv[num][1]);
498 return (EXIT_FAILURE);
499 }
500 --argc; ++num;
501 }
502
503 if (flag == 0) /* no command given */
504 {
505 usage(argv[0]);
506 return (EXIT_FAILURE);
507 }
508
509 if (argc > 1)
510 {
511 if (strlen(argv[num]) > (SH_MAXMSG - strlen(message) -1))
512 {
513 fprintf(stderr, _("ERROR: Hostname too long: %s\n"), argv[num]);
514 return (EXIT_FAILURE);
515 }
516 strncat (message, argv[num], SH_MAXMSG -strlen(message) - 1);
517 message[SH_MAXMSG-1] = '\0';
518 }
519 else
520 {
521 if (message[0] == 'P' && message[1] == 'R' &&
522 message[2] == 'O' && message[3] == 'B' && message[4] == 'E' )
523 {
524 strncat (message, _("dummy"), SH_MAXMSG -strlen(message) - 1);
525 message[SH_MAXMSG-1] = '\0';
526 }
527 else if (message[0] == 'L' && message[1] == 'I' &&
528 message[2] == 'S' && message[3] == 'T')
529 {
530 strncat (message, _("dummy"), SH_MAXMSG -strlen(message) - 1);
531 message[SH_MAXMSG-1] = '\0';
532 }
533 else
534 {
535 fprintf(stderr, "ERROR: this command requires a hostname\n");
536 usage(argv[0]);
537 return (EXIT_FAILURE);
538 }
539 }
540
541 fixup_message(message);
542
543 /* OpenBSD wants >= 1024
544 */
545 if (NULL == getcwd(clientcd, 1024))
546 {
547 perror(_("ERROR: getcwd"));
548 return (EXIT_FAILURE);
549 }
550 size = strlen(clientcd) + 1 + strlen(CLIENT) + 6;
551 sockname = malloc (size);
552 if (!sockname)
553 {
554 perror(_("ERROR: main: malloc"));
555 return (EXIT_FAILURE);
556 }
557 sprintf(sockname, _("%s/%s.sock"), clientcd, CLIENT);
558
559
560 /* Make the socket.
561 */
562 sock = make_named_socket (sockname);
563 if (sock < 0)
564 {
565 return (EXIT_FAILURE);
566 }
567
568 /* Set up termination handler.
569 */
570 signal (SIGINT, termination_handler);
571 signal (SIGHUP, termination_handler);
572 signal (SIGTERM, termination_handler);
573 signal (SIGQUIT, termination_handler);
574
575 /* Send the datagram.
576 */
577 status = send_to_server (serversock, message);
578 if (status < 0)
579 {
580 fprintf(stderr, _("ERROR: sending command to server failed\n"));
581 (void) termination_handler(0);
582 return (EXIT_FAILURE);
583 }
584
585 /* Wait for a reply.
586 */
587 if (message[0] == 'L' && message[1] == 'I' &&
588 message[2] == 'S' && message[3] == 'T')
589 {
590 if (verbose)
591 fprintf(stdout, _("# Waiting for listing.\n"));
592 }
593 else
594 {
595 if (verbose)
596 fprintf(stdout, _("# Waiting for confirmation.\n"));
597 }
598 status = recv_from_server (message);
599
600 if (status < 0)
601 {
602 fprintf(stderr, _("ERROR: receiving data from server failed.\n"));
603 (void) termination_handler(0);
604 return (EXIT_FAILURE);
605 }
606
607 /* Clean up. */
608 (void) termination_handler(0);
609 return (EXIT_SUCCESS);
610}
611
Note: See TracBrowser for help on using the repository browser.