source: trunk/src/sh_socket.c@ 592

Last change on this file since 592 was 592, checked in by katerina, 7 days ago

Fixes for compiler warnings.

File size: 33.8 KB
Line 
1/* SAMHAIN file system integrity testing */
2/* Copyright (C) 2003,2005 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/* define if you want debug info
23 * #define SH_DEBUG_SOCKET
24 */
25
26#if defined(SH_WITH_SERVER) && defined(__linux__)
27#define _GNU_SOURCE
28#endif
29
30#include <stdio.h>
31#include <stdlib.h>
32#include <stddef.h>
33#include <string.h>
34
35#if HAVE_SYS_TIME_H
36#include <sys/time.h>
37#endif
38#include <time.h>
39
40#include "samhain.h"
41#include "sh_socket.h"
42#include "sh_error.h"
43#include "sh_unix.h"
44#include "sh_calls.h"
45#include "sh_guid.h"
46#include "sh_fifo.h"
47#include "sh_utils.h"
48
49#undef FIL__
50#define FIL__ _("sh_socket.c")
51
52#if defined (SH_WITH_CLIENT)
53
54#include <signal.h>
55
56typedef struct delta_tofetch {
57 char uuid[SH_UUID_BUF];
58 time_t last_time;
59 unsigned int count;
60} SH_DELTA_DB;
61
62static SH_DELTA_DB * parse_entry(SH_DELTA_DB * db, const char * str)
63{
64 long last_time;
65 unsigned int count;
66 char buf[SH_UUID_BUF];
67 int res = sscanf(str, _("%u:%ld:%36s"), &count, &last_time, buf);
68 if (res == 3)
69 {
70 db->count = count;
71 db->last_time = (time_t) last_time;
72 sl_strlcpy(db->uuid, buf, SH_UUID_BUF);
73 return db;
74 }
75 return NULL;
76}
77
78static char * unparse_entry(const SH_DELTA_DB * db, char * str, size_t len)
79{
80 int nbytes = sl_snprintf(str, len, _("%u:%ld:%s"),
81 db->count, (long) db->last_time, db->uuid);
82 if (nbytes < 0 || nbytes >= (int) len)
83 return NULL;
84 return str;
85}
86
87static SH_FIFO xfifo = SH_FIFO_INITIALIZER;
88
89int sh_socket_store_uuid(const char * cmd)
90{
91 const char * q = strchr(cmd, ':');
92 char entry[SH_BUFSIZE];
93 SH_DELTA_DB db;
94
95 if (!q) { return -1; }
96
97 ++q;
98
99 if (0 != sh_uuid_check(q)) { return -1; }
100
101 db.count = 0;
102 db.last_time = (time_t) 0;
103 sl_strlcpy(db.uuid, q, SH_UUID_BUF);
104
105 if (NULL != unparse_entry(&db, entry, sizeof(entry)))
106 {
107 sh_fifo_push(&xfifo, entry);
108 return 0;
109 }
110 return -1;
111}
112
113static unsigned int try_interval = 60;
114static unsigned int try_max = 2;
115
116int set_delta_retry_interval(const char * str)
117{
118 long val = strtol (str, (char **)NULL, 10);
119
120 if (val < 0 || val > INT_MAX)
121 return -1;
122 try_interval = (unsigned int) val;
123 return 0;
124}
125int set_delta_retry_count(const char * str)
126{
127 long val = strtol (str, (char **)NULL, 10);
128
129 if (val < 0 || val > INT_MAX)
130 return -1;
131 try_max = (unsigned int) val;
132 return 0;
133}
134
135char * sh_socket_get_uuid(int * errflag, unsigned int * count, time_t * last)
136{
137 char * entry = sh_fifo_pop(&xfifo);
138 char * uuid = NULL;
139
140 if (entry)
141 {
142 SH_DELTA_DB db;
143 time_t now;
144
145 if (NULL == parse_entry(&db, entry))
146 {
147 SH_FREE(entry);
148 sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, 0, MSG_E_SUBGEN,
149 _("Bad entry in fifo"),
150 _("sh_socket_get_uuid"));
151 *errflag = -1;
152 return NULL;
153 }
154
155 now = time(NULL);
156
157 if ( (db.count > 0) && ((unsigned long)(now - db.last_time) < try_interval) )
158 {
159 sh_fifo_push_tail(&xfifo, entry);
160 SH_FREE(entry);
161 *errflag = -1;
162 return NULL;
163 }
164
165 SH_FREE(entry);
166 uuid = sh_util_strdup(db.uuid);
167 *count = db.count;
168 *last = db.last_time;
169 }
170
171 *errflag = 0;
172 return uuid;
173}
174
175int sh_socket_return_uuid (const char * uuid, unsigned int count, time_t last)
176{
177 (void) last;
178
179 if (count < try_max)
180 {
181 char entry[SH_BUFSIZE];
182 SH_DELTA_DB db;
183 time_t now = time(NULL);
184
185 db.count = count + 1;
186 db.last_time = now;
187 sl_strlcpy(db.uuid, uuid, SH_UUID_BUF);
188
189 if (NULL != unparse_entry(&db, entry, sizeof(entry)))
190 return sh_fifo_push_tail(&xfifo, entry); /* >0 for success */
191 }
192 return -1;
193}
194
195void sh_socket_server_cmd(const char * srvcmd)
196{
197 SL_ENTER(_("sh_tools_server_cmd"));
198
199 if ((srvcmd == NULL) || (srvcmd[0] == '\0') || (sl_strlen(srvcmd) < 4))
200 {
201 SL_RET0(_("sh_socket_server_cmd"));
202 }
203
204 if (0 == strncmp(srvcmd, _("STOP"), 4))
205 {
206 TPT((0, FIL__, __LINE__, _("msg=<stop command from server>\n")));
207#ifdef SIGQUIT
208 raise(SIGQUIT);
209#else
210 sig_terminate = 1;
211 ++sig_raised;
212#endif
213 }
214
215 else if (0 == strncmp(srvcmd, _("RELOAD"), 6))
216 {
217 TPT((0, FIL__, __LINE__, _("msg=<reload command from server>\n")));
218#ifdef SIGHUP
219 raise(SIGHUP);
220#else
221 sig_config_read_again = 1;
222 ++sig_raised;
223#endif
224 }
225
226 else if (0 == strncmp(srvcmd, _("DELTA:"), 6))
227 {
228 TPT((0, FIL__, __LINE__, _("msg=<delta load command from server>\n")));
229
230 if (sh_socket_store_uuid(srvcmd) == 0)
231 {
232 ++sh_load_delta_flag;
233 ++sig_raised;
234 }
235 }
236
237 else if (0 == strncmp(srvcmd, _("SCAN"), 4))
238 {
239 TPT((0, FIL__, __LINE__, _("msg=<scan command from server>\n")));
240 if (sh.flag.isdaemon == S_TRUE)
241 {
242#ifdef SIGTTOU
243 raise(SIGTTOU);
244#else
245 sig_force_check = 1;
246 ++sig_raised;
247#endif
248 }
249 else
250 {
251 sig_force_check = 1;
252 ++sig_raised;
253 }
254 }
255
256 /* Unknown command
257 */
258 else
259 {
260 sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, 0, MSG_E_SUBGEN,
261 srvcmd,
262 _("sh_socket_server_cmd"));
263 }
264 SL_RET0(_("sh_socket_server_cmd"));
265}
266#endif /* #if defined (SH_WITH_CLIENT) */
267
268#if defined(SH_WITH_SERVER)
269#include <errno.h>
270
271#include <sys/types.h>
272#include <sys/stat.h>
273
274#include <unistd.h>
275#include <fcntl.h>
276
277#include <time.h>
278
279#include <sys/socket.h>
280#include <sys/un.h>
281
282
283#ifdef HAVE_SYS_UIO_H
284#include <sys/uio.h>
285#endif
286#if !defined(HAVE_GETPEEREID) && !defined(SO_PEERCRED)
287#if defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || defined(HAVE_STRUCT_SOCKCRED)
288#include <sys/param.h>
289#include <sys/ucred.h>
290#endif
291#endif
292
293
294int pf_unix_fd = -1;
295static char * sh_sockname = NULL;
296static char sh_sockpass_real[SOCKPASS_MAX+1];
297
298struct socket_cmd {
299 char cmd[SH_MAXMSGLEN];
300 char clt[SH_MAXMSGLEN];
301 char cti[81];
302 struct socket_cmd * next;
303};
304
305#if !defined(O_NONBLOCK)
306#if defined(O_NDELAY)
307#define O_NONBLOCK O_NDELAY
308#else
309#define O_NONBLOCK 0
310#endif
311#endif
312
313#if !defined(AF_FILE)
314#define AF_FILE AF_UNIX
315#endif
316
317static struct socket_cmd * cmdlist = NULL;
318static struct socket_cmd * runlist = NULL;
319
320static int sh_socket_flaguse = S_FALSE;
321static int sh_socket_flaguid = 0;
322
323#include "sh_utils.h"
324
325/* The reload list stores information about
326 * reloads confirmed by clients (startup and/or
327 * runtime cinfiguration reloaded).
328 */
329struct reload_cmd {
330 char clt[SH_MAXMSGLEN];
331 time_t cti;
332 struct reload_cmd * next;
333};
334static struct reload_cmd * reloadlist = NULL;
335
336void sh_socket_add2reload (const char * clt)
337{
338 struct reload_cmd * new = reloadlist;
339
340 while (new)
341 {
342 if (0 == sl_strcmp(new->clt, clt))
343 {
344#ifdef SH_DEBUG_SOCKET
345 fprintf(stderr, "add2reload: time reset for %s\n", clt);
346#endif
347 sl_strlcpy (new->clt, clt, SH_MAXMSGLEN);
348 new->cti = time(NULL);
349 return;
350 }
351 new = new->next;
352 }
353
354 new = SH_ALLOC(sizeof(struct reload_cmd));
355#ifdef SH_DEBUG_SOCKET
356 fprintf(stderr, "add2reload: time set for %s\n", clt);
357#endif
358 sl_strlcpy (new->clt, clt, SH_MAXMSGLEN);
359 new->cti = time(NULL);
360
361 new->next = reloadlist;
362 reloadlist = new;
363
364 return;
365}
366
367#include "zAVLTree.h"
368#include "sh_html.h"
369#include "sh_tools.h"
370static void sh_socket_add2list (struct socket_cmd * in);
371
372static void sh_socket_probe4reload (void)
373{
374 struct reload_cmd * new;
375 struct socket_cmd cmd;
376
377 zAVLCursor avlcursor;
378 client_t * item;
379 extern zAVLTree * all_clients;
380
381 char * file;
382 unsigned long dummy;
383 struct stat buf;
384
385 for (item = (client_t *) zAVLFirst(&avlcursor, all_clients); item;
386 item = (client_t *) zAVLNext(&avlcursor))
387 {
388 if (item->status_now != CLT_INACTIVE)
389 {
390 int flag = 0;
391
392 file = get_client_conf_file (item->hostname, &dummy);
393
394 if (0 == stat (file, &buf))
395 {
396 new = reloadlist;
397 while (new)
398 {
399 if (0 == sl_strcmp(new->clt, item->hostname))
400 {
401 flag = 1; /* Client is in list already */
402
403 if (buf.st_mtime > new->cti)
404 {
405 /* reload */
406 sl_strlcpy(cmd.cmd, _("RELOAD"), SH_MAXMSGLEN);
407 sl_strlcpy(cmd.clt, item->hostname, SH_MAXMSGLEN);
408 sh_socket_add2list (&cmd);
409 }
410 break;
411 }
412 new = new->next;
413 }
414
415 if (flag == 0)
416 {
417 /* client is active, but start message has been missed; reload
418 */
419 sl_strlcpy(cmd.cmd, _("RELOAD"), SH_MAXMSGLEN);
420 sl_strlcpy(cmd.clt, item->hostname, SH_MAXMSGLEN);
421 sh_socket_add2list (&cmd);
422
423 /* Add the client to the reload list and set
424 * time to 0, since we don't know the startup time.
425 */
426 sh_socket_add2reload (item->hostname);
427 new = reloadlist;
428 while (new)
429 {
430 if (0 == sl_strcmp(new->clt, item->hostname))
431 {
432 new->cti = 0;
433 break;
434 }
435 new = new->next;
436 }
437 }
438 } /* if stat(file).. */
439 } /* if !CLT_INACTIVE */
440 } /* loop over clients */
441 return;
442}
443
444char * sh_get_sockpass (void)
445{
446 size_t j = 0;
447
448 while (skey->sh_sockpass[2*j] != '\0' && j < sizeof(sh_sockpass_real))
449 {
450 sh_sockpass_real[j] = skey->sh_sockpass[2*j];
451 ++j;
452 }
453 sh_sockpass_real[j] = '\0';
454
455 return sh_sockpass_real;
456}
457
458void sh_set_sockpass (void)
459{
460 int j;
461 for (j = 0; j < 15; ++j)
462 {
463 sh_sockpass_real[j] = '\0';
464 }
465}
466
467int sh_socket_use (const char * c)
468{
469 return sh_util_flagval(c, &sh_socket_flaguse);
470}
471
472int sh_socket_remove ()
473{
474 int retval = 0;
475#ifdef S_ISSOCK
476 struct stat sbuf;
477#endif
478
479 SL_ENTER(_("sh_socket_remove"));
480
481 if (NULL == sh_sockname)
482 {
483 SL_RETURN((retval),_("sh_socket_remove"));
484 }
485
486 if (0 != tf_trust_check (DEFAULT_PIDDIR, SL_YESPRIV))
487 {
488 SL_RETURN((-1),_("sh_socket_remove"));
489 }
490
491 if ( (retry_lstat(FIL__, __LINE__, sh_sockname, &sbuf) == 0) &&
492 (sbuf.st_uid == getuid()))
493 {
494#ifdef S_ISSOCK
495 /* cppcheck-suppress syntaxError */
496 if (S_ISSOCK(sbuf.st_mode))
497 {
498 retval = retry_aud_unlink (FIL__, __LINE__, sh_sockname);
499 }
500#else
501 retval = retry_aud_unlink (FIL__, __LINE__, sh_sockname);
502#endif
503 }
504 SL_RETURN((retval),_("sh_socket_remove"));
505}
506
507#if !defined(HAVE_GETPEEREID) && !defined(SO_PEERCRED) && !defined(HAVE_STRUCT_CMSGCRED) && !defined(HAVE_STRUCT_FCRED) && !(defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))
508
509#define NEED_PASSWORD_AUTH
510#endif
511
512int sh_socket_uid (const char * c)
513{
514 uid_t val = (uid_t) strtol (c, (char **)NULL, 10);
515 sh_socket_flaguid = val;
516#if defined(NEED_PASSWORD_AUTH)
517 sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, errno, MSG_E_SUBGEN,
518 _("Config option SetSocketAllowUID not supported, use SetSocketPassword"),
519 _("sh_socket_uid"));
520#endif
521 return 0;
522}
523
524int sh_socket_password (const char * c)
525{
526#if defined(NEED_PASSWORD_AUTH)
527 int j, i;
528
529#define LCG(n) ((69069 * n) & 0xffffffffUL)
530
531 i = sl_strlen(c);
532 if (i > SOCKPASS_MAX) {
533 return -1;
534 }
535 for (j = 0; j < (2*SOCKPASS_MAX+1); ++j)
536 {
537 skey->sh_sockpass[j] = '\0';
538 }
539 for (j = 0; j < i; ++j)
540 {
541 skey->sh_sockpass[2*j] = c[j];
542 skey->sh_sockpass[(2*j)+1] = (LCG(c[j]) % 256);
543 }
544 return 0;
545#else
546 sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, errno, MSG_E_SUBGEN,
547 _("Config option SetSocketPassword not supported, use SetSocketAllowUID"),
548 _("sh_socket_password"));
549 (void) c;
550 return 0;
551#endif
552}
553
554
555int sh_socket_open_int ()
556{
557 struct sockaddr_un name;
558 size_t size;
559 int flags;
560#if defined(SO_PASSCRED)
561 socklen_t optval = 1;
562#endif
563 struct stat buf;
564 char errbuf[SH_ERRBUF_SIZE];
565
566 SL_ENTER(_("sh_socket_open_int"));
567
568 if (sh_socket_flaguse == S_FALSE)
569 {
570 SL_RETURN(0, _("sh_socket_open_int"));
571 }
572
573 if (sh_sockname == NULL)
574 {
575 size = sl_strlen(DEFAULT_PIDDIR) + 1 + sl_strlen(SH_INSTALL_NAME) + 6;
576 sh_sockname = SH_ALLOC(size); /* compile-time constant */
577 sl_strlcpy(sh_sockname, DEFAULT_PIDDIR, size);
578 sl_strlcat(sh_sockname, "/", size);
579 sl_strlcat(sh_sockname, SH_INSTALL_NAME, size);
580 sl_strlcat(sh_sockname, _(".sock"), size);
581 }
582
583 if (0 != sh_unix_check_piddir (sh_sockname))
584 {
585 SH_FREE(sh_sockname);
586 SL_RETURN((-1),_("sh_socket_open_int"));
587 }
588
589 pf_unix_fd = socket (PF_UNIX, SOCK_STREAM, 0);
590 if ((pf_unix_fd) < 0)
591 {
592 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
593 sh_error_message (errno, errbuf, sizeof(errbuf)),
594 _("sh_socket_open_int: socket"));
595 SL_RETURN( (-1), _("sh_socket_open_int"));
596 }
597
598 if (sizeof(name.sun_path) < (1 + sl_strlen(sh_sockname)))
599 {
600 sl_close_fd(FIL__, __LINE__, pf_unix_fd); pf_unix_fd = -1;
601 sh_error_handle ((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
602 _("PID dir path too long"),
603 _("sh_socket_open_int"));
604 SL_RETURN( (-1), _("sh_socket_open_int"));
605 }
606
607 name.sun_family = AF_FILE;
608 sl_strlcpy (name.sun_path, sh_sockname, sizeof(name.sun_path));
609
610 size = (offsetof (struct sockaddr_un, sun_path)
611 + strlen (name.sun_path) + 1);
612
613 flags = retry_lstat (FIL__, __LINE__, sh_sockname, &buf);
614
615 if (flags == 0)
616 {
617 sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, -1, MSG_E_SUBGEN,
618 _("Socket exists, trying to unlink it"),
619 _("sh_socket_open_int"));
620 if (sh_socket_remove() < 0)
621 {
622 sl_close_fd(FIL__, __LINE__, pf_unix_fd); pf_unix_fd = -1;
623 sh_error_handle ((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
624 _("Unlink of socket failed, maybe path not trusted"),
625 _("sh_socket_open_int"));
626 SL_RETURN( (-1), _("sh_socket_open_int"));
627 }
628 }
629
630 if (bind ((pf_unix_fd), (struct sockaddr *) &name, size) < 0)
631 {
632 sl_close_fd(FIL__, __LINE__, pf_unix_fd); pf_unix_fd = -1;
633 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
634 sh_error_message (errno, errbuf, sizeof(errbuf)),
635 _("sh_socket_open_int: bind"));
636 SL_RETURN( (-1), _("sh_socket_open_int"));
637 }
638
639#ifdef SO_PASSCRED
640 if (0 != setsockopt(pf_unix_fd, SOL_SOCKET, SO_PASSCRED,
641 &optval, sizeof(optval)))
642 {
643 sl_close_fd(FIL__, __LINE__, pf_unix_fd); pf_unix_fd = -1;
644 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
645 sh_error_message (errno, errbuf, sizeof(errbuf)),
646 _("sh_socket_open_int: setsockopt"));
647 SL_RETURN( (-1), _("sh_socket_open_int"));
648 }
649#endif
650
651 flags = fcntl((pf_unix_fd), F_GETFL);
652 if (flags < 0)
653 {
654 sl_close_fd(FIL__, __LINE__, pf_unix_fd); pf_unix_fd = -1;
655 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
656 sh_error_message (errno, errbuf, sizeof(errbuf)),
657 _("sh_socket_open_int: fcntl1"));
658 SL_RETURN( (-1), _("sh_socket_open_int"));
659 }
660
661 flags = fcntl((pf_unix_fd), F_SETFL, flags|O_NONBLOCK);
662 if (flags < 0)
663 {
664 sl_close_fd(FIL__, __LINE__, pf_unix_fd); pf_unix_fd = -1;
665 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
666 sh_error_message (errno, errbuf, sizeof(errbuf)),
667 _("sh_socket_open_int: fcntl2"));
668 SL_RETURN( (-1), _("sh_socket_open_int"));
669 }
670
671 if (0 != listen(pf_unix_fd, 5))
672 {
673 sl_close_fd(FIL__, __LINE__, pf_unix_fd); pf_unix_fd = -1;
674 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
675 sh_error_message (errno, errbuf, sizeof(errbuf)),
676 _("sh_socket_open_int: listen"));
677 SL_RETURN( (-1), _("sh_socket_open_int"));
678 }
679 SL_RETURN( (0), _("sh_socket_open_int"));
680}
681
682
683/*
684 * Parts of the socket authentication code is copied from PostgreSQL:
685 *
686 * PostgreSQL Database Management System
687 * (formerly known as Postgres, then as Postgres95)
688 *
689 * Portions Copyright (c) 1996-2001, The PostgreSQL Global Development Group
690 *
691 * Portions Copyright (c) 1994, The Regents of the University of California
692 *
693 * Permission to use, copy, modify, and distribute this software and its
694 * documentation for any purpose, without fee, and without a written agreement
695 * is hereby granted, provided that the above copyright notice and this
696 * paragraph and the following two paragraphs appear in all copies.
697 *
698 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
699 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
700 * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
701 * DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
702 * POSSIBILITY OF SUCH DAMAGE.
703 *
704 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
705 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
706 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
707 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO
708 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
709 */
710
711static int receive_message(int talkfd, struct msghdr * msg, size_t message_size)
712{
713 unsigned int retry = 0;
714 int nbytes;
715 char * message = msg->msg_iov->iov_base;
716 char errbuf[SH_ERRBUF_SIZE];
717
718 do {
719 nbytes = recvmsg (talkfd, msg, 0);
720 if ((nbytes < 0) && (errno != EAGAIN))
721 {
722 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
723 sh_error_message (errno, errbuf, sizeof(errbuf)),
724 _("sh_socket_read: recvmsg"));
725 sl_close_fd(FIL__, __LINE__, talkfd);
726 return -1;
727 }
728 else if (nbytes < 0)
729 {
730 ++retry;
731 retry_msleep(0, 10);
732 }
733 } while ((nbytes < 0) && (retry < 3));
734
735 /* msg.msg_iov.iov_base, filled by recvmsg
736 */
737 message[message_size-1] = '\0';
738
739 if (nbytes < 0)
740 {
741 if (errno == EAGAIN)
742 {
743 /* no data */
744 sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, errno, MSG_E_SUBGEN,
745 sh_error_message (errno, errbuf, sizeof(errbuf)),
746 _("sh_socket_read: recvfrom"));
747 sl_close_fd(FIL__, __LINE__, talkfd);
748 return 0;
749 }
750 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
751 sh_error_message (errno, errbuf, sizeof(errbuf)),
752 _("sh_socket_read: recvfrom"));
753 sl_close_fd(FIL__, __LINE__, talkfd);
754 return -1;
755 }
756 return 0;
757}
758
759#if defined(HAVE_GETPEEREID)
760
761static int get_peer_uid(int talkfd)
762{
763 uid_t peer_uid;
764 gid_t peer_gid;
765 char errbuf[SH_ERRBUF_SIZE];
766
767 if (0 != getpeereid(talkfd, &peer_uid, &peer_gid))
768 {
769 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
770 sh_error_message (errno, errbuf, sizeof(errbuf)),
771 _("sh_socket_read: getpeereid"));
772 sl_close_fd(FIL__, __LINE__, talkfd);
773 return -1;
774 }
775 return peer_uid;
776}
777
778#elif defined(SO_PEERCRED)
779
780static int get_peer_uid(int talkfd)
781{
782 char errbuf[SH_ERRBUF_SIZE];
783 struct ucred cr;
784#ifdef HAVE_SOCKLEN_T
785 socklen_t cl = sizeof(cr);
786#else
787 int cl = sizeof(cr);
788#endif
789
790 if (0 != getsockopt(talkfd, SOL_SOCKET, SO_PEERCRED, &cr, &cl))
791 {
792 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
793 sh_error_message (errno, errbuf, sizeof(errbuf)),
794 _("sh_socket_read: getsockopt"));
795 sl_close_fd(FIL__, __LINE__, talkfd);
796 return -1;
797 }
798 return cr.uid;
799}
800
801#endif
802
803#if defined(NEED_PASSWORD_AUTH)
804char * check_password(char * message, size_t msglen, int * client_uid, int talkfd)
805{
806 char * cmd = NULL;
807 char * eopw = NULL;
808 char * goodpassword = NULL;
809
810 goodpassword = sh_get_sockpass();
811 eopw = strchr(message, '@');
812 if (eopw)
813 *eopw = '\0';
814 /*
815 * message is null-terminated and >> goodpassword
816 */
817 if (0 == strcmp(goodpassword, message) &&
818 strlen(goodpassword) < (msglen/2))
819 {
820 *client_uid = sh_socket_flaguid;
821 cmd = &message[strlen(goodpassword)+1];
822 sh_set_sockpass();
823 }
824 else
825 {
826 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
827 _("Bad password"),
828 _("sh_socket_read"));
829 sh_set_sockpass();
830 sl_close_fd(FIL__, __LINE__, talkfd);
831 return NULL;
832 }
833 return cmd;
834}
835#endif
836
837static int list_all (int talkfd, char * cmd);
838static int process_message(int talkfd, char * cmd, struct socket_cmd * srvcmd);
839
840static
841int sh_socket_read (struct socket_cmd * srvcmd)
842{
843 char message[SH_MAXMSG];
844 struct sockaddr_un name;
845 ACCEPT_TYPE_ARG3 size = sizeof(name);
846 int talkfd;
847 char * cmd = NULL;
848 int client_uid = -1;
849 char errbuf[SH_ERRBUF_SIZE];
850 struct msghdr msg;
851 struct iovec iov;
852 int status;
853
854 if (pf_unix_fd < 0)
855 return 0;
856
857 iov.iov_base = (char *) &message;
858 iov.iov_len = sizeof(message);
859
860 memset (&msg, 0, sizeof (msg));
861 msg.msg_iov = &iov;
862 msg.msg_iovlen = 1;
863
864 /* the socket is non-blocking
865 * 'name' is the address of the sender socket
866 */
867 do {
868 talkfd = accept(pf_unix_fd, (struct sockaddr *) &name, &size);
869 } while (talkfd < 0 && errno == EINTR);
870
871 if ((talkfd < 0) && (errno == EAGAIN))
872 {
873 return 0;
874 }
875 else if (talkfd < 0)
876 {
877 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
878 sh_error_message (errno, errbuf, sizeof(errbuf)),
879 _("sh_socket_read: accept"));
880 return -1;
881 }
882
883 if (receive_message(talkfd, &msg, sizeof(message)) < 0)
884 return -1;
885
886 /* Authenticate request by peer uid or password.
887 */
888#if defined(HAVE_GETPEEREID)
889 client_uid = get_peer_uid(talkfd);
890 cmd = message;
891
892#elif defined(SO_PEERCRED)
893 client_uid = get_peer_uid(talkfd);
894 cmd = message;
895
896#elif defined(NEED_PASSWORD_AUTH)
897 cmd = check_password(message, sizeof(message), &client_uid, talkfd);
898
899#else
900 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
901 _("Socket credentials not supported on this OS"),
902 _("sh_socket_read"));
903 sl_close_fd(FIL__, __LINE__, talkfd);
904 return -1;
905#endif
906
907 if (client_uid != sh_socket_flaguid)
908 {
909 sh_error_handle((-1), FIL__, __LINE__, client_uid, MSG_E_SUBGEN,
910 _("client does not have required uid"),
911 _("sh_socket_read: getsockopt"));
912 sl_close_fd(FIL__, __LINE__, talkfd);
913 return -1;
914 }
915
916 status = process_message(talkfd, cmd, srvcmd);
917
918 sl_close_fd(FIL__, __LINE__, talkfd);
919 return status;
920}
921
922static int check_valid_command(const char * str)
923{
924 unsigned int i = 0;
925 char * commands[] = { N_("DELTA"), N_("RELOAD"), N_("STOP"), N_("SCAN"),
926 N_("CANCEL"), N_("LISTALL"), N_("LIST"), N_("PROBE"), NULL };
927
928 while (commands[i])
929 {
930 if (0 == strcmp(_(commands[i]), str))
931 {
932 return 0;
933 }
934 ++i;
935 }
936 return -1;
937}
938
939static int send_reply (int fd, char * msg)
940{
941 int nbytes = send (fd, msg, strlen(msg) + 1, 0);
942
943 if (nbytes < 0)
944 {
945 char errbuf[SH_ERRBUF_SIZE];
946 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
947 sh_error_message (errno, errbuf, sizeof(errbuf)),
948 _("send_reply"));
949 return -1;
950 }
951
952 return nbytes;
953}
954
955static int process_message(int talkfd, char * cmd, struct socket_cmd * srvcmd)
956{
957 int nbytes;
958 char error_type[SH_ERRBUF_SIZE] = { '\0' };
959 char * clt = (cmd) ? strchr(cmd, ':') : NULL;
960
961 if (clt && 0 == strncmp(cmd, _("DELTA:"), 6))
962 {
963 /* DELTA:uuid:hostname
964 */
965 char * uuid = clt;
966
967 *uuid = '\0'; ++uuid;
968 clt = strchr(uuid, ':');
969 if (clt) { *clt = '\0'; ++clt; }
970
971 if (sh_uuid_check(uuid) < 0)
972 {
973 sl_strlcpy(error_type, _("!E:uuid-format:"), sizeof(error_type));
974 sl_strlcat(error_type, uuid, sizeof(error_type));
975 clt = NULL;
976 }
977
978 --uuid; *uuid = ':';
979 }
980 else if (clt && *clt == ':')
981 {
982 *clt = '\0'; ++clt;
983 if (check_valid_command(cmd) < 0)
984 {
985 sl_strlcpy(error_type, _("!E:cmd-invalid:"), sizeof(error_type));
986 sl_strlcat(error_type, cmd, sizeof(error_type));
987 clt = NULL;
988 }
989 }
990
991 if (clt != NULL)
992 {
993 if (sl_strlen(cmd) >= SH_MAXMSGLEN)
994 {
995 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
996 _("Bad message format: command too long"),
997 _("sh_socket_read"));
998 sl_strlcpy(error_type, _("!E:cmd-toolong"), sizeof(error_type));
999 send_reply(talkfd, error_type);
1000 return -1;
1001 }
1002 else if (sl_strlen(clt) >= SH_MAXMSGLEN)
1003 {
1004 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
1005 _("Bad message format: hostname too long"),
1006 _("sh_socket_read"));
1007 sl_strlcpy(error_type, _("!E:hostname-toolong"), sizeof(error_type));
1008 send_reply(talkfd, error_type);
1009 return -1;
1010 }
1011
1012 if (0 == strncmp(cmd, _("LIST"), 4))
1013 return list_all(talkfd, cmd);
1014 else if (0 == strncmp(cmd, _("PROBE"), 4))
1015 {
1016 sh_socket_probe4reload();
1017 sl_strlcpy(cmd, _("LIST"), 5);
1018 return list_all(talkfd, cmd);
1019 }
1020
1021 sl_strlcpy (srvcmd->cmd, cmd, SH_MAXMSGLEN);
1022 sl_strlcpy (srvcmd->clt, clt, SH_MAXMSGLEN);
1023 --clt; *clt = ':';
1024 }
1025 else
1026 {
1027 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
1028 _("Bad message format"),
1029 _("sh_socket_read"));
1030 if (error_type[0] == '\0')
1031 sl_strlcpy(error_type, _("!E:message-format"), sizeof(error_type));
1032 send_reply(talkfd, error_type);
1033 return -1;
1034 }
1035
1036 /* Bounce the message back to the sender.
1037 */
1038 nbytes = send_reply(talkfd, cmd);
1039
1040 return nbytes;
1041}
1042
1043static int list_all (int talkfd, char * cmd)
1044{
1045 int nbytes;
1046 struct socket_cmd * list_cmd;
1047 char message[SH_MAXMSG];
1048 char errbuf[SH_ERRBUF_SIZE];
1049
1050 if (0 == strncmp(cmd, _("LISTALL"), 7))
1051 {
1052 list_cmd = runlist;
1053 while (list_cmd)
1054 {
1055 sl_snprintf(message, sizeof(message), _("SENT %42s %32s %s"),
1056 list_cmd->cmd, list_cmd->clt, list_cmd->cti);
1057
1058 nbytes = send (talkfd, message, sl_strlen(message) + 1, 0);
1059 if (nbytes < 0)
1060 {
1061 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
1062 sh_error_message (errno, errbuf, sizeof(errbuf)),
1063 _("sh_socket_read: sendto"));
1064 return -1;
1065 }
1066 list_cmd = list_cmd->next;
1067 }
1068 }
1069
1070 list_cmd = cmdlist;
1071 while (list_cmd)
1072 {
1073 sl_snprintf(message, sizeof(message), _(">>>> %42s %32s %s"),
1074 list_cmd->cmd, list_cmd->clt, list_cmd->cti);
1075
1076 nbytes = send (talkfd, message, sl_strlen(message) + 1, 0);
1077 if (nbytes < 0)
1078 {
1079 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
1080 sh_error_message (errno, errbuf, sizeof(errbuf)),
1081 _("sh_socket_read: sendto"));
1082 return -1;
1083 }
1084 list_cmd = list_cmd->next;
1085 }
1086
1087 send (talkfd, _("END"), 4, 0);
1088 return 0;
1089}
1090
1091static void sh_socket_add2list (struct socket_cmd * in)
1092{
1093 struct socket_cmd * new = cmdlist;
1094 struct socket_cmd * last = cmdlist;
1095
1096 while (new)
1097 {
1098 /* Only skip identical commands.
1099 */
1100 if (0 == sl_strcmp(new->clt, in->clt) &&
1101 0 == sl_strcmp(new->cmd, in->cmd))
1102 {
1103 (void) sh_unix_time(0, new->cti, sizeof(new->cti));
1104 return;
1105 }
1106 new = new->next;
1107 }
1108
1109 new = SH_ALLOC(sizeof(struct socket_cmd));
1110 sl_strlcpy (new->cmd, in->cmd, sizeof(new->cmd));
1111 sl_strlcpy (new->clt, in->clt, sizeof(new->clt));
1112 (void) sh_unix_time(0, new->cti, sizeof(new->cti));
1113 new->next = NULL;
1114
1115 if (last)
1116 {
1117 while (last->next) { last = last->next; }
1118 last->next = new;
1119 }
1120 else
1121 {
1122 cmdlist = new;
1123 }
1124 return;
1125}
1126
1127static void sh_socket_add2run (struct socket_cmd * in)
1128{
1129 struct socket_cmd * new = runlist;
1130 struct socket_cmd * last = runlist;
1131
1132 while (new)
1133 {
1134 /* Only skip identical commands. First 5 will
1135 * make all 'DELTA' identical.
1136 */
1137 if (0 == sl_strcmp(new->clt, in->clt) &&
1138 0 == sl_strncmp(new->cmd, in->cmd, 5))
1139 {
1140 sl_strlcpy (new->cmd, in->cmd, sizeof(new->cmd));
1141 (void) sh_unix_time(0, new->cti, sizeof(new->cti));
1142 return;
1143 }
1144 new = new->next;
1145 }
1146
1147 new = SH_ALLOC(sizeof(struct socket_cmd));
1148 sl_strlcpy (new->cmd, in->cmd, sizeof(new->cmd));
1149 sl_strlcpy (new->clt, in->clt, sizeof(new->clt));
1150#ifdef SH_DEBUG_SOCKET
1151 fprintf(stderr, "add2run: time set for %s\n", new->clt);
1152#endif
1153 (void) sh_unix_time(0, new->cti, sizeof(new->cti));
1154 new->next = NULL;
1155
1156 if (last)
1157 {
1158 while (last->next) { last = last->next; }
1159 last->next = new;
1160 }
1161 else
1162 {
1163 runlist = new;
1164 }
1165 return;
1166}
1167
1168
1169
1170static void sh_socket_rm2list (const char * client_name, int remove_all)
1171{
1172 struct socket_cmd * old = cmdlist;
1173 struct socket_cmd * new = cmdlist;
1174
1175 while (new)
1176 {
1177 if (0 == sl_strcmp(new->clt, client_name))
1178 {
1179 if ((new == cmdlist) && (new->next == NULL))
1180 {
1181 /* There is only one entry */
1182 cmdlist = NULL;
1183 SH_FREE(new);
1184 return;
1185 }
1186 else if (new == cmdlist)
1187 {
1188 /* first entry: new = old = cmdlist */
1189 cmdlist = new->next;
1190 SH_FREE(new);
1191 if (remove_all == S_FALSE)
1192 return;
1193 old = cmdlist;
1194 new = cmdlist;
1195 continue;
1196 }
1197 else
1198 {
1199 old->next = new->next;
1200 SH_FREE(new);
1201 if (remove_all == S_FALSE)
1202 return;
1203 new = old;
1204 }
1205 }
1206 old = new;
1207 new = new->next;
1208 }
1209 return;
1210}
1211
1212/* poll the socket to gather input
1213 */
1214int sh_socket_poll()
1215{
1216 struct socket_cmd cmd;
1217 char cancel_cmd[SH_MAXMSGLEN];
1218
1219 /* struct pollfd sh_poll = { pf_unix_fd, POLLIN, 0 }; */
1220
1221 if (pf_unix_fd < 0)
1222 return 0;
1223
1224 sl_strlcpy(cancel_cmd, _("CANCEL"), sizeof(cancel_cmd));
1225
1226 while (sh_socket_read (&cmd) > 0)
1227 {
1228 if (0 == sl_strcmp(cmd.cmd, cancel_cmd))
1229 sh_socket_rm2list (cmd.clt, S_TRUE);
1230 else
1231 sh_socket_add2list (&cmd);
1232 }
1233 return 0;
1234}
1235
1236/* return the command associated with client_name
1237 and remove the corresponding entry
1238 */
1239char * sh_socket_check(const char * client_name)
1240{
1241 struct socket_cmd * new = cmdlist;
1242 static char out[SH_MAXMSGLEN];
1243
1244 while (new)
1245 {
1246 if (0 == sl_strcmp(new->clt, client_name))
1247 {
1248 sl_strlcpy(out, new->cmd, sizeof(out));
1249 sh_socket_add2run (new);
1250 sh_socket_rm2list (client_name, S_FALSE);
1251 return out;
1252 }
1253 new = new->next;
1254 }
1255 return NULL;
1256}
1257/* #if defined (SH_WITH_SERVER)
1258 */
1259#endif
1260
1261
1262#ifdef SH_CUTEST
1263#include "CuTest.h"
1264
1265void Test_cmdlist (CuTest *tc) {
1266
1267#if defined (SH_WITH_SERVER)
1268 struct socket_cmd cmd;
1269 char * p;
1270
1271 sl_strlcpy(cmd.clt, "one", sizeof(cmd.clt));
1272 sl_strlcpy(cmd.cmd, "RELOAD", sizeof(cmd.cmd));
1273
1274 sh_socket_add2list (&cmd);
1275 p = sh_socket_check("one");
1276 CuAssertPtrNotNull(tc, p);
1277 CuAssertStrEquals(tc, "RELOAD", p);
1278
1279 p = sh_socket_check("one");
1280 CuAssertPtrEquals(tc, NULL, p);
1281
1282 sh_socket_add2list (&cmd);
1283 sl_strlcpy(cmd.cmd, "STOP", sizeof(cmd.cmd));
1284 sh_socket_add2list (&cmd);
1285
1286 sl_strlcpy(cmd.clt, "two", sizeof(cmd.clt));
1287 sl_strlcpy(cmd.cmd, "STOP", sizeof(cmd.cmd));
1288 sh_socket_add2list (&cmd);
1289 sl_strlcpy(cmd.clt, "three", sizeof(cmd.clt));
1290 sl_strlcpy(cmd.cmd, "STOP", sizeof(cmd.cmd));
1291 sh_socket_add2list (&cmd);
1292
1293 sl_strlcpy(cmd.clt, "one", sizeof(cmd.clt));
1294 sl_strlcpy(cmd.cmd, "DELTA", sizeof(cmd.cmd));
1295 sh_socket_add2list (&cmd);
1296
1297 p = sh_socket_check("one");
1298 CuAssertPtrNotNull(tc, p);
1299 CuAssertStrEquals(tc, "RELOAD", p);
1300
1301 sl_strlcpy(cmd.clt, "two", sizeof(cmd.clt));
1302 sl_strlcpy(cmd.cmd, "RELOAD", sizeof(cmd.cmd));
1303 sh_socket_add2list (&cmd);
1304 sl_strlcpy(cmd.clt, "three", sizeof(cmd.clt));
1305 sl_strlcpy(cmd.cmd, "RELOAD", sizeof(cmd.cmd));
1306 sh_socket_add2list (&cmd);
1307
1308 p = sh_socket_check("one");
1309 CuAssertPtrNotNull(tc, p);
1310 CuAssertStrEquals(tc, "STOP", p);
1311 p = sh_socket_check("one");
1312 CuAssertPtrNotNull(tc, p);
1313 CuAssertStrEquals(tc, "DELTA", p);
1314 p = sh_socket_check("one");
1315 CuAssertPtrEquals(tc, NULL, p);
1316
1317 /* Test removal in correct order */
1318 sl_strlcpy(cmd.clt, "one", sizeof(cmd.clt));
1319 sl_strlcpy(cmd.cmd, "RELOAD", sizeof(cmd.cmd));
1320 sh_socket_add2list (&cmd);
1321 sl_strlcpy(cmd.cmd, "STOP", sizeof(cmd.cmd));
1322 sh_socket_add2list (&cmd);
1323 sl_strlcpy(cmd.cmd, "DELTA", sizeof(cmd.cmd));
1324 sh_socket_add2list (&cmd);
1325 sl_strlcpy(cmd.cmd, "FOOBAR", sizeof(cmd.cmd));
1326 sh_socket_add2list (&cmd);
1327
1328 sh_socket_rm2list ("one", S_FALSE);
1329
1330 p = sh_socket_check("one");
1331 CuAssertPtrNotNull(tc, p);
1332 CuAssertStrEquals(tc, "STOP", p);
1333
1334 sh_socket_rm2list ("one", S_FALSE);
1335
1336 p = sh_socket_check("one");
1337 CuAssertPtrNotNull(tc, p);
1338 CuAssertStrEquals(tc, "FOOBAR", p);
1339
1340 p = sh_socket_check("one");
1341 CuAssertPtrEquals(tc, NULL, p);
1342
1343 sl_strlcpy(cmd.clt, "one", sizeof(cmd.clt));
1344 sl_strlcpy(cmd.cmd, "RELOAD", sizeof(cmd.cmd));
1345 sh_socket_add2list (&cmd);
1346 sl_strlcpy(cmd.cmd, "STOP", sizeof(cmd.cmd));
1347 sh_socket_add2list (&cmd);
1348
1349 sl_strlcpy(cmd.clt, "two", sizeof(cmd.clt));
1350 sl_strlcpy(cmd.cmd, "RELOAD", sizeof(cmd.cmd));
1351 sh_socket_add2list (&cmd);
1352 sl_strlcpy(cmd.clt, "three", sizeof(cmd.clt));
1353 sl_strlcpy(cmd.cmd, "RELOAD", sizeof(cmd.cmd));
1354 sh_socket_add2list (&cmd);
1355
1356 sl_strlcpy(cmd.clt, "one", sizeof(cmd.clt));
1357 sl_strlcpy(cmd.cmd, "DELTA", sizeof(cmd.cmd));
1358 sh_socket_add2list (&cmd);
1359 sl_strlcpy(cmd.cmd, "FOOBAR", sizeof(cmd.cmd));
1360 sh_socket_add2list (&cmd);
1361
1362 sh_socket_rm2list ("one", S_TRUE);
1363 p = sh_socket_check("one");
1364 CuAssertPtrEquals(tc, NULL, p);
1365
1366 p = sh_socket_check("two");
1367 CuAssertPtrNotNull(tc, p);
1368 CuAssertStrEquals(tc, "STOP", p);
1369 p = sh_socket_check("two");
1370 CuAssertPtrNotNull(tc, p);
1371 CuAssertStrEquals(tc, "RELOAD", p);
1372 p = sh_socket_check("two");
1373 CuAssertPtrEquals(tc, NULL, p);
1374
1375 p = sh_socket_check("three");
1376 CuAssertPtrNotNull(tc, p);
1377 CuAssertStrEquals(tc, "STOP", p);
1378 p = sh_socket_check("three");
1379 CuAssertPtrNotNull(tc, p);
1380 CuAssertStrEquals(tc, "RELOAD", p);
1381 p = sh_socket_check("three");
1382 CuAssertPtrEquals(tc, NULL, p);
1383
1384 p = sh_socket_check("four");
1385 CuAssertPtrEquals(tc, NULL, p);
1386#else
1387 (void) tc;
1388#endif
1389}
1390
1391#endif /* #ifdef SH_CUTEST */
1392
1393
1394
Note: See TracBrowser for help on using the repository browser.