source: trunk/src/sh_socket.c@ 478

Last change on this file since 478 was 421, checked in by katerina, 12 years ago

Fix for ticket #325 (samhainctl probe command).

File size: 30.4 KB
RevLine 
[1]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 */
[270]25
[177]26#if defined(SH_WITH_SERVER) && defined(__linux__)
27#define _GNU_SOURCE
28#endif
[1]29
30#include <stdio.h>
31#include <stdlib.h>
32#include <stddef.h>
33#include <string.h>
34
35#include "samhain.h"
36#include "sh_socket.h"
37#include "sh_error.h"
38#include "sh_unix.h"
39#include "sh_calls.h"
40
41#undef FIL__
42#define FIL__ _("sh_socket.c")
43
44#if defined (SH_WITH_CLIENT)
45
46#include <signal.h>
47
48void sh_socket_server_cmd(const char * srvcmd)
49{
50 SL_ENTER(_("sh_tools_server_cmd"));
51
52 if ((srvcmd == NULL) || (srvcmd[0] == '\0') || (sl_strlen(srvcmd) < 4))
53 {
54 SL_RET0(_("sh_socket_server_cmd"));
55 }
[200]56 if ((srvcmd[0] == 'S') && (srvcmd[1] == 'T') &&
57 (srvcmd[2] == 'O') && (srvcmd[3] == 'P'))
[1]58 {
59 TPT((0, FIL__, __LINE__, _("msg=<stop command from server>\n")));
60#ifdef SIGQUIT
61 raise(SIGQUIT);
62#else
[200]63 sig_terminate = 1;
64 ++sig_raised;
[1]65#endif
66 }
[200]67 else if ((srvcmd[0] == 'R') && (srvcmd[1] == 'E') &&
68 (srvcmd[2] == 'L') && (srvcmd[3] == 'O') &&
69 (srvcmd[4] == 'A') && (srvcmd[5] == 'D'))
[1]70 {
71 TPT((0, FIL__, __LINE__, _("msg=<reload command from server>\n")));
72#ifdef SIGHUP
73 raise(SIGHUP);
74#else
[200]75 sig_config_read_again = 1;
76 ++sig_raised;
[1]77#endif
78 }
[200]79 else if ((srvcmd[0] == 'S') && (srvcmd[1] == 'C') &&
80 (srvcmd[2] == 'A') && (srvcmd[3] == 'N'))
81 {
82 TPT((0, FIL__, __LINE__, _("msg=<scan command from server>\n")));
83 if (sh.flag.isdaemon == ON)
84 {
85#ifdef SIGTTOU
86 raise(SIGTTOU);
87#else
88 sig_force_check = 1;
89 ++sig_raised;
90#endif
91 }
92 else
93 {
94 sig_force_check = 1;
95 ++sig_raised;
96 }
97 }
[1]98 else
99 {
100 sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, 0, MSG_E_SUBGEN,
101 srvcmd,
102 _("sh_socket_server_cmd"));
103 }
104 SL_RET0(_("sh_socket_server_cmd"));
105}
106/* #if defined (SH_WITH_CLIENT)
107 */
108#endif
109
110#if defined(SH_WITH_SERVER)
111#include <errno.h>
112
113#include <sys/types.h>
114#include <sys/stat.h>
115
116#include <unistd.h>
117#include <fcntl.h>
118
119#include <time.h>
120
121#include <sys/socket.h>
122#include <sys/un.h>
123
124
125#ifdef HAVE_SYS_UIO_H
126#include <sys/uio.h>
127#endif
128#if !defined(HAVE_GETPEEREID) && !defined(SO_PEERCRED)
129#if defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || defined(HAVE_STRUCT_SOCKCRED)
130#include <sys/param.h>
131#include <sys/ucred.h>
132#endif
133#endif
134
135
136int pf_unix_fd = -1;
137static char * sh_sockname = NULL;
[40]138static char sh_sockpass_real[SOCKPASS_MAX+1];
[1]139
140struct socket_cmd {
141 char cmd[SH_MAXMSGLEN];
142 char clt[SH_MAXMSGLEN];
143 char cti[81];
144 struct socket_cmd * next;
145};
146
147#if !defined(O_NONBLOCK)
148#if defined(O_NDELAY)
149#define O_NONBLOCK O_NDELAY
150#else
151#define O_NONBLOCK 0
152#endif
153#endif
154
155#if !defined(AF_FILE)
156#define AF_FILE AF_UNIX
157#endif
158
159static struct socket_cmd * cmdlist = NULL;
160static struct socket_cmd * runlist = NULL;
161
162static int sh_socket_flaguse = S_FALSE;
163static int sh_socket_flaguid = 0;
164
165#include "sh_utils.h"
166
[421]167/* The reload list stores information about
168 * reloads confirmed by clients (startup and/or
169 * runtime cinfiguration reloaded).
170 */
[1]171struct reload_cmd {
172 char clt[SH_MAXMSGLEN];
173 time_t cti;
174 struct reload_cmd * next;
175};
176static struct reload_cmd * reloadlist = NULL;
177
178void sh_socket_add2reload (const char * clt)
179{
180 struct reload_cmd * new = reloadlist;
181
182 while (new)
183 {
184 if (0 == sl_strcmp(new->clt, clt))
185 {
[270]186#ifdef SH_DEBUG_SOCKET
187 fprintf(stderr, "add2reload: time reset for %s\n", clt);
188#endif
[1]189 sl_strlcpy (new->clt, clt, SH_MAXMSGLEN);
190 new->cti = time(NULL);
191 return;
192 }
193 new = new->next;
194 }
195
196 new = SH_ALLOC(sizeof(struct reload_cmd));
[270]197#ifdef SH_DEBUG_SOCKET
198 fprintf(stderr, "add2reload: time set for %s\n", clt);
199#endif
[1]200 sl_strlcpy (new->clt, clt, SH_MAXMSGLEN);
201 new->cti = time(NULL);
202
203 new->next = reloadlist;
204 reloadlist = new;
205
206 return;
207}
208
209#include "zAVLTree.h"
210#include "sh_html.h"
211#include "sh_tools.h"
212static void sh_socket_add2list (struct socket_cmd * in);
213
[272]214static void sh_socket_probe4reload (void)
[1]215{
216 struct reload_cmd * new;
217 struct socket_cmd cmd;
218
219 zAVLCursor avlcursor;
220 client_t * item;
221 extern zAVLTree * all_clients;
222
223 char * file;
224 unsigned long dummy;
225 struct stat buf;
226
[270]227#ifdef SH_DEBUG_SOCKET
228 fprintf(stderr, "PROBE\n");
229#endif
230
[1]231 for (item = (client_t *) zAVLFirst(&avlcursor, all_clients); item;
232 item = (client_t *) zAVLNext(&avlcursor))
233 {
[270]234#ifdef SH_DEBUG_SOCKET
235 fprintf(stderr, "%s %d\n", item->hostname, (int)item->status_now);
236#endif
237
[1]238 if (item->status_now != CLT_INACTIVE)
239 {
[421]240 int flag = 0;
241
[1]242 file = get_client_conf_file (item->hostname, &dummy);
243
[270]244#ifdef SH_DEBUG_SOCKET
245 fprintf(stderr, "%s\n", file);
246#endif
[1]247 if (0 == stat (file, &buf))
248 {
249 new = reloadlist;
250 while (new)
251 {
[270]252#ifdef SH_DEBUG_SOCKET
253 fprintf(stderr, "%s <> %s\n", new->clt, item->hostname);
254#endif
[1]255 if (0 == sl_strcmp(new->clt, item->hostname))
256 {
[421]257 flag = 1; /* Client is in list already */
258
[270]259#ifdef SH_DEBUG_SOCKET
260 fprintf(stderr, "%lu <> %lu\n",
261 (unsigned long) buf.st_mtime,
262 (unsigned long)new->cti);
263#endif
[1]264 if (buf.st_mtime > new->cti)
265 {
266 /* reload */
267 sl_strlcpy(cmd.cmd, _("RELOAD"), SH_MAXMSGLEN);
268 sl_strlcpy(cmd.clt, item->hostname, SH_MAXMSGLEN);
269 sh_socket_add2list (&cmd);
270 }
271 break;
272 }
273 new = new->next;
274 }
[421]275
276 if (flag == 0)
277 {
278 /* client is active, but start message has been missed; reload
279 */
280 sl_strlcpy(cmd.cmd, _("RELOAD"), SH_MAXMSGLEN);
281 sl_strlcpy(cmd.clt, item->hostname, SH_MAXMSGLEN);
282 sh_socket_add2list (&cmd);
283
284 /* Add the client to the reload list and set
285 * time to 0, since we don't know the startup time.
286 */
287 sh_socket_add2reload (item->hostname);
288 new = reloadlist;
289 while (new)
290 {
291 if (0 == sl_strcmp(new->clt, item->hostname))
292 {
293 new->cti = 0;
294 break;
295 }
296 new = new->next;
297 }
298 }
299 } /* if stat(file).. */
300 } /* if !CLT_INACTIVE */
301 } /* loop over clients */
[1]302 return;
303}
304
[170]305char * sh_get_sockpass (void)
[1]306{
[50]307 size_t j = 0;
308
[40]309 while (skey->sh_sockpass[2*j] != '\0' && j < sizeof(sh_sockpass_real))
[1]310 {
311 sh_sockpass_real[j] = skey->sh_sockpass[2*j];
312 ++j;
313 }
314 sh_sockpass_real[j] = '\0';
[50]315
[1]316 return sh_sockpass_real;
317}
318
[170]319void sh_set_sockpass (void)
[1]320{
321 int j;
322 for (j = 0; j < 15; ++j)
323 {
324 sh_sockpass_real[j] = '\0';
325 }
326}
327
[22]328int sh_socket_use (const char * c)
[1]329{
330 return sh_util_flagval(c, &sh_socket_flaguse);
331}
332
333int sh_socket_remove ()
334{
335 int retval = 0;
336#ifdef S_ISSOCK
337 struct stat sbuf;
338#endif
339
340 SL_ENTER(_("sh_socket_remove"));
341
342 if (NULL == sh_sockname)
343 {
344 SL_RETURN((retval),_("sh_socket_remove"));
345 }
346
347 if (0 != tf_trust_check (DEFAULT_PIDDIR, SL_YESPRIV))
348 {
349 SL_RETURN((-1),_("sh_socket_remove"));
350 }
351
352 if ( (retry_lstat(FIL__, __LINE__, sh_sockname, &sbuf) == 0) &&
353 (sbuf.st_uid == getuid()))
354 {
355#ifdef S_ISSOCK
356 if (S_ISSOCK (sbuf.st_mode))
357 {
358 retval = retry_aud_unlink (FIL__, __LINE__, sh_sockname);
359 }
360#else
361 retval = retry_aud_unlink (FIL__, __LINE__, sh_sockname);
362#endif
363 }
364 SL_RETURN((retval),_("sh_socket_remove"));
365}
366
367#if !defined(HAVE_GETPEEREID) && !defined(SO_PEERCRED) && !defined(HAVE_STRUCT_CMSGCRED) && !defined(HAVE_STRUCT_FCRED) && !(defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))
368
369#define NEED_PASSWORD_AUTH
370
371#endif
372
[22]373int sh_socket_uid (const char * c)
[1]374{
375 uid_t val = (uid_t) strtol (c, (char **)NULL, 10);
376 sh_socket_flaguid = val;
377#if defined(NEED_PASSWORD_AUTH)
378 sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, errno, MSG_E_SUBGEN,
379 _("Config option SetSocketAllowUID not supported, use SetSocketPassword"),
380 _("sh_socket_uid"));
381#endif
382 return 0;
383}
384
[22]385int sh_socket_password (const char * c)
[1]386{
387#if defined(NEED_PASSWORD_AUTH)
388 int j, i;
389
390#define LCG(n) ((69069 * n) & 0xffffffffUL)
391
392 i = sl_strlen(c);
[40]393 if (i > SOCKPASS_MAX) {
[1]394 return -1;
395 }
[40]396 for (j = 0; j < (2*SOCKPASS_MAX+1); ++j)
[1]397 {
398 skey->sh_sockpass[j] = '\0';
399 }
400 for (j = 0; j < i; ++j)
401 {
402 skey->sh_sockpass[2*j] = c[j];
403 skey->sh_sockpass[(2*j)+1] = (LCG(c[j]) % 256);
404 }
405 return 0;
406#else
407 sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, errno, MSG_E_SUBGEN,
408 _("Config option SetSocketPassword not supported, use SetSocketAllowUID"),
409 _("sh_socket_password"));
410 (void) c;
411 return 0;
412#endif
413}
414
415
416int sh_socket_open_int ()
417{
418 struct sockaddr_un name;
419 size_t size;
420 int flags;
421#if defined(SO_PASSCRED)
422 socklen_t optval = 1;
423#endif
424 struct stat buf;
[132]425 char errbuf[SH_ERRBUF_SIZE];
[1]426
427 SL_ENTER(_("sh_socket_open_int"));
428
429 if (sh_socket_flaguse == S_FALSE)
430 {
431 SL_RETURN(0, _("sh_socket_open_int"));
432 }
433
434 if (sh_sockname == NULL)
435 {
436 size = sl_strlen(DEFAULT_PIDDIR) + 1 + sl_strlen(SH_INSTALL_NAME) + 6;
[34]437 sh_sockname = SH_ALLOC(size); /* compile-time constant */
[1]438 sl_strlcpy(sh_sockname, DEFAULT_PIDDIR, size);
439 sl_strlcat(sh_sockname, "/", size);
440 sl_strlcat(sh_sockname, SH_INSTALL_NAME, size);
441 sl_strlcat(sh_sockname, _(".sock"), size);
442 }
443
[265]444 if (0 != sh_unix_check_piddir (sh_sockname))
445 {
446 SH_FREE(sh_sockname);
447 SL_RETURN((-1),_("sh_socket_open_int"));
448 }
[264]449
[1]450 pf_unix_fd = socket (PF_UNIX, SOCK_STREAM, 0);
451 if ((pf_unix_fd) < 0)
452 {
453 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]454 sh_error_message (errno, errbuf, sizeof(errbuf)),
[1]455 _("sh_socket_open_int: socket"));
456 SL_RETURN( (-1), _("sh_socket_open_int"));
457 }
458
459 if (sizeof(name.sun_path) < (1 + sl_strlen(sh_sockname)))
460 {
[252]461 sl_close_fd(FIL__, __LINE__, pf_unix_fd); pf_unix_fd = -1;
[1]462 sh_error_handle ((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
463 _("PID dir path too long"),
464 _("sh_socket_open_int"));
465 SL_RETURN( (-1), _("sh_socket_open_int"));
466 }
467
468 name.sun_family = AF_FILE;
[22]469 sl_strlcpy (name.sun_path, sh_sockname, sizeof(name.sun_path));
[1]470
471 size = (offsetof (struct sockaddr_un, sun_path)
472 + strlen (name.sun_path) + 1);
473
474 flags = retry_lstat (FIL__, __LINE__, sh_sockname, &buf);
475
476 if (flags == 0)
477 {
478 sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, -1, MSG_E_SUBGEN,
479 _("Socket exists, trying to unlink it"),
480 _("sh_socket_open_int"));
481 if (sh_socket_remove() < 0)
482 {
[252]483 sl_close_fd(FIL__, __LINE__, pf_unix_fd); pf_unix_fd = -1;
[1]484 sh_error_handle ((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
485 _("Unlink of socket failed, maybe path not trusted"),
486 _("sh_socket_open_int"));
487 SL_RETURN( (-1), _("sh_socket_open_int"));
488 }
489 }
490
491 if (bind ((pf_unix_fd), (struct sockaddr *) &name, size) < 0)
492 {
[252]493 sl_close_fd(FIL__, __LINE__, pf_unix_fd); pf_unix_fd = -1;
[1]494 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]495 sh_error_message (errno, errbuf, sizeof(errbuf)),
[1]496 _("sh_socket_open_int: bind"));
497 SL_RETURN( (-1), _("sh_socket_open_int"));
498 }
499
500#ifdef SO_PASSCRED
501 if (0 != setsockopt(pf_unix_fd, SOL_SOCKET, SO_PASSCRED,
502 &optval, sizeof(optval)))
503 {
[252]504 sl_close_fd(FIL__, __LINE__, pf_unix_fd); pf_unix_fd = -1;
[1]505 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]506 sh_error_message (errno, errbuf, sizeof(errbuf)),
[1]507 _("sh_socket_open_int: setsockopt"));
508 SL_RETURN( (-1), _("sh_socket_open_int"));
509 }
510#endif
511
512 flags = fcntl((pf_unix_fd), F_GETFL);
513 if (flags < 0)
514 {
[252]515 sl_close_fd(FIL__, __LINE__, pf_unix_fd); pf_unix_fd = -1;
[1]516 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]517 sh_error_message (errno, errbuf, sizeof(errbuf)),
[1]518 _("sh_socket_open_int: fcntl1"));
519 SL_RETURN( (-1), _("sh_socket_open_int"));
520 }
521
522 flags = fcntl((pf_unix_fd), F_SETFL, flags|O_NONBLOCK);
523 if (flags < 0)
524 {
[252]525 sl_close_fd(FIL__, __LINE__, pf_unix_fd); pf_unix_fd = -1;
[1]526 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]527 sh_error_message (errno, errbuf, sizeof(errbuf)),
[1]528 _("sh_socket_open_int: fcntl2"));
529 SL_RETURN( (-1), _("sh_socket_open_int"));
530 }
531
532 if (0 != listen(pf_unix_fd, 5))
533 {
[252]534 sl_close_fd(FIL__, __LINE__, pf_unix_fd); pf_unix_fd = -1;
[1]535 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]536 sh_error_message (errno, errbuf, sizeof(errbuf)),
[1]537 _("sh_socket_open_int: listen"));
538 SL_RETURN( (-1), _("sh_socket_open_int"));
539 }
540 SL_RETURN( (0), _("sh_socket_open_int"));
541}
542/* #if !defined(HAVE_CMSGCRED) || !defined(SO_PEERCRED) */
543/* #endif */
544
545/*
546#if !defined(HAVE_GETPEEREID) && !defined(SO_PEERCRED) && !defined(HAVE_STRUCT_CMSGCRED) && !defined(HAVE_STRUCT_FCRED) && !(defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))
547static
548int sh_socket_read (struct socket_cmd * srvcmd)
549{
550 srvcmd->cmd[0] = '\0';
551 srvcmd->clt[0] = '\0';
552 return 0;
553}
554#else
555*/
556
557/*
558 * Parts of the socket authentication code is copied from PostgreSQL:
559 *
560 * PostgreSQL Database Management System
561 * (formerly known as Postgres, then as Postgres95)
562 *
563 * Portions Copyright (c) 1996-2001, The PostgreSQL Global Development Group
564 *
565 * Portions Copyright (c) 1994, The Regents of the University of California
566 *
567 * Permission to use, copy, modify, and distribute this software and its
568 * documentation for any purpose, without fee, and without a written agreement
569 * is hereby granted, provided that the above copyright notice and this
570 * paragraph and the following two paragraphs appear in all copies.
571 *
572 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
573 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
574 * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
575 * DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
576 * POSSIBILITY OF SUCH DAMAGE.
577 *
578 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
579 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
580 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
581 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO
582 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
583 */
584static
585int sh_socket_read (struct socket_cmd * srvcmd)
586{
587 struct socket_cmd * list_cmd;
588 char message[SH_MAXMSG];
589 struct sockaddr_un name;
[295]590 ACCEPT_TYPE_ARG3 size = sizeof(name);
591
[1]592 int nbytes;
593 int talkfd;
594 int retry = 0;
595
596 char * cmd = NULL;
597 char * clt = NULL;
598
599 int client_uid = -1;
[132]600 char errbuf[SH_ERRBUF_SIZE];
[1]601
602
603 struct msghdr msg;
604 struct iovec iov;
605
606#if defined(NEED_PASSWORD_AUTH)
607 char * eopw = NULL;
608 char * goodpassword = NULL;
609#endif
610
611#if defined(HAVE_GETPEEREID)
612 uid_t peer_uid;
613 gid_t peer_gid;
614#elif defined(SO_PEERCRED)
615 struct ucred cr;
[46]616#ifdef HAVE_SOCKLEN_T
617 socklen_t cl = sizeof(cr);
618#else
619 int cl = sizeof(cr);
620#endif
[1]621
622#elif defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || (defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))
623
624#ifdef HAVE_STRUCT_CMSGCRED
625 typedef struct cmsgcred Cred;
626#define CRED_UID cmcred_uid
627
628#elif HAVE_STRUCT_FCRED
629 typedef struct fcred Cred;
630#define CRED_UID fc_uid
631
632#elif HAVE_STRUCT_SOCKCRED
633 typedef struct sockcred Cred;
634#define CRED_UID sc_uid
635
636#endif
637 Cred *cred;
638
639 /* Compute size without padding */
640 char cmsgmem[ALIGN(sizeof(struct cmsghdr)) + ALIGN(sizeof(Cred))];
641 /* for NetBSD */
642
643 /* Point to start of first structure */
644 struct cmsghdr *cmsg = (struct cmsghdr *) cmsgmem;
645#endif
646
647 if (pf_unix_fd < 0)
648 {
649 return 0;
650 }
651
652 iov.iov_base = (char *) &message;
[40]653 iov.iov_len = sizeof(message);
[1]654
655 memset (&msg, 0, sizeof (msg));
656 msg.msg_iov = &iov;
657 msg.msg_iovlen = 1;
658
659#if !defined(SO_PEERCRED) && !defined(HAVE_GETPEEREID)
660#if defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || (defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))
661 msg.msg_control = (char *) cmsg;
662 msg.msg_controllen = sizeof (cmsgmem);
663 memset (cmsg, 0, sizeof (cmsgmem));
664#endif
665#endif
666
667 /* the socket is non-blocking
668 * 'name' is the address of the sender socket
669 */
[295]670 do {
671 talkfd = accept(pf_unix_fd, (struct sockaddr *) &name, &size);
672 } while (talkfd < 0 && errno == EINTR);
673
[1]674 if ((talkfd < 0) && (errno == EAGAIN))
675 {
676 return 0;
677 }
678 else if (talkfd < 0)
679 {
680 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]681 sh_error_message (errno, errbuf, sizeof(errbuf)),
[1]682 _("sh_socket_read: accept"));
683 return -1;
684 }
685
686
687#if defined(LOCAL_CREDS) && !defined(SO_PEERCRED) && !defined(HAVE_GETPEEREID)
688 /* Set the socket to receive credentials on the next message
689 */
690 {
691 int on = 1;
692 if (setsockopt (talkfd, 0, LOCAL_CREDS, &on, sizeof (on)) < 0)
693 {
694 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]695 sh_error_message (errno, errbuf, sizeof(errbuf)),
[1]696 _("sh_socket_read: setsockopt"));
[252]697 sl_close_fd(FIL__, __LINE__, talkfd);
[1]698 return -1;
699 }
700 }
701#endif
702
703 do {
704 nbytes = recvmsg (talkfd, &msg, 0);
705 if ((nbytes < 0) && (errno != EAGAIN))
706 {
707 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]708 sh_error_message (errno, errbuf, sizeof(errbuf)),
[1]709 _("sh_socket_read: recvmsg"));
[252]710 sl_close_fd(FIL__, __LINE__, talkfd);
[1]711 return -1;
712 }
713 else if (nbytes < 0)
714 {
715 ++retry;
[315]716 retry_msleep(0, 10);
[1]717 }
718 } while ((nbytes < 0) && (retry < 3));
719
720#ifdef SH_DEBUG_SOCKET
721 fprintf(stderr, "%d bytes received\n", nbytes);
722#endif
723
[40]724 /* msg.msg_iov.iov_base, filled by recvmsg
725 */
726 message[sizeof(message)-1] = '\0';
[1]727
728 if (nbytes < 0)
729 {
730 if (errno == EAGAIN)
731 {
732 /* no data */
[252]733 sl_close_fd(FIL__, __LINE__, talkfd);
[1]734 return 0;
735 }
736 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]737 sh_error_message (errno, errbuf, sizeof(errbuf)),
[1]738 _("sh_socket_read: recvfrom"));
[252]739 sl_close_fd(FIL__, __LINE__, talkfd);
[1]740 return -1;
741 }
742
743#if defined(HAVE_GETPEEREID)
744 if (0 != getpeereid(talkfd, &peer_uid, &peer_gid))
745 {
746 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]747 sh_error_message (errno, errbuf, sizeof(errbuf)),
[1]748 _("sh_socket_read: getpeereid"));
[252]749 sl_close_fd(FIL__, __LINE__, talkfd);
[1]750 return -1;
751 }
752 client_uid = peer_uid;
753 cmd = message;
754#elif defined(SO_PEERCRED)
755 if (0 != getsockopt(talkfd, SOL_SOCKET, SO_PEERCRED, &cr, &cl))
756 {
757 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]758 sh_error_message (errno, errbuf, sizeof(errbuf)),
[1]759 _("sh_socket_read: getsockopt"));
[252]760 sl_close_fd(FIL__, __LINE__, talkfd);
[1]761 return -1;
762 }
763 client_uid = cr.uid;
764 cmd = message;
765#elif defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || (defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))
766 if (cmsg->cmsg_len < sizeof (cmsgmem) || cmsg->cmsg_type != SCM_CREDS)
767 {
768 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
769 _("Message from recvmsg() was not SCM_CREDS"),
770 _("sh_socket_read"));
[118]771
772 /* Check for file descriptors sent using SCM_RIGHTS, and
773 * close them. If MSG_CTRUNC is set, the buffer was too small,
774 * and no fds are duped.
775 */
776 if (msg.msg_controllen >= sizeof(struct cmsghdr) &&
777 (msg.msg_flags & MSG_CTRUNC) == 0)
778 {
779 unsigned int data_size;
780 unsigned int data_i;
781 int fdcount, fdmax;
782 struct cmsghdr * cmptr;
783 int fdsbuf[1 + (sizeof(cmsgmem)/sizeof(int))];
784
785 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL;
786 cmptr = CMSG_NXTHDR(&msg, cmptr))
787 {
788 if (cmptr->cmsg_len > sizeof (cmsgmem) ||
789 cmptr->cmsg_level != SOL_SOCKET ||
790 cmptr->cmsg_type != SCM_RIGHTS)
791 continue;
792
793 /* Crappy way of finding the data length.
794 * cmptr->cmsg_len includes both header and padding,
795 * how are you supposed to find the data length?
796 * cmptr->cmsg_len - ALIGN(sizeof(struct cmsghdr)) ?
797 */
798 data_size = 0;
799
800 for (data_i = 0; data_i < cmptr->cmsg_len; ++data_i)
801 {
802 if (CMSG_LEN(data_i) == cmptr->cmsg_len)
803 {
804 data_size = data_i;
805 break;
806 }
807 }
808 memcpy(fdsbuf, CMSG_DATA(cmptr), data_size);
809 fdmax = data_size / sizeof(int);
810 for (fdcount = 0; fdcount < fdmax; ++fdcount)
[252]811 (void) sl_close_fd(FIL__, __LINE__, fdsbuf[fdcount]);
[118]812 }
813 }
814
[252]815 sl_close_fd(FIL__, __LINE__, talkfd);
[1]816 return -1;
817 }
818 cred = (Cred *) CMSG_DATA (cmsg);
819 client_uid = cred->CRED_UID;
820 cmd = message;
821#elif defined(NEED_PASSWORD_AUTH)
822 goodpassword = sh_get_sockpass();
823 eopw = strchr(message, '@');
824 if (eopw)
825 *eopw = '\0';
[40]826 /*
827 * message is null-terminated and >> goodpassword
828 */
829 if (0 == strcmp(goodpassword, message) &&
830 strlen(goodpassword) < (sizeof(message)/2))
[1]831 {
832 client_uid = sh_socket_flaguid;
833 cmd = &message[strlen(goodpassword)+1];
834 sh_set_sockpass();
835 }
836 else
837 {
838 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
839 _("Bad password"),
840 _("sh_socket_read"));
841 sh_set_sockpass();
[252]842 sl_close_fd(FIL__, __LINE__, talkfd);
[1]843 return -1;
844 }
845#else
846 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
847 _("Socket credentials not supported on this OS"),
848 _("sh_socket_read"));
[252]849 sl_close_fd(FIL__, __LINE__, talkfd);
[1]850 return -1;
851#endif
852
853#ifdef SH_DEBUG_SOCKET
854 fprintf(stderr, "Peer uid=%d, required=%d\n",
855 client_uid, sh_socket_flaguid);
856#endif
857
858 if (client_uid != sh_socket_flaguid)
859 {
860 sh_error_handle((-1), FIL__, __LINE__, client_uid, MSG_E_SUBGEN,
861 _("client does not have required uid"),
862 _("sh_socket_read: getsockopt"));
[252]863 sl_close_fd(FIL__, __LINE__, talkfd);
[1]864 return -1;
865 }
866
867
868 /* Give a diagnostic message.
869 */
870#ifdef SH_DEBUG_SOCKET
871 fprintf (stderr, "Server: got message: %s\n", cmd);
872#endif
873
874 clt = strchr(cmd, ':');
875 if (clt != NULL)
876 {
877 *clt = '\0'; ++clt;
878 if (sl_strlen(cmd) >= SH_MAXMSGLEN)
879 {
[270]880#ifdef SH_DEBUG_SOCKET
881 fprintf (stderr, "Server: command too long: %s\n", cmd);
882#endif
[1]883 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
884 _("Bad message format: command too long"),
885 _("sh_socket_read"));
[252]886 sl_close_fd(FIL__, __LINE__, talkfd);
[1]887 return -1;
888 }
889 else if (sl_strlen(clt) >= SH_MAXMSGLEN)
890 {
[270]891#ifdef SH_DEBUG_SOCKET
892 fprintf (stderr, "Server: hostname too long: %s\n", clt);
893#endif
[1]894 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
895 _("Bad message format: hostname too long"),
896 _("sh_socket_read"));
[252]897 sl_close_fd(FIL__, __LINE__, talkfd);
[1]898 return -1;
899 }
900 if (cmd[0] == 'L' && cmd[1] == 'I' &&
901 cmd[2] == 'S' && cmd[3] == 'T')
902 {
[270]903#ifdef SH_DEBUG_SOCKET
904 fprintf (stderr, "Server: list %s\n", clt);
905#endif
[1]906 goto list_all;
907 }
908 else if (cmd[0] == 'P' && cmd[1] == 'R' &&
909 cmd[2] == 'O' && cmd[3] == 'B' && cmd[4] == 'E')
910 {
[270]911#ifdef SH_DEBUG_SOCKET
912 fprintf (stderr, "Server: probe start %s\n", clt);
913#endif
[1]914 sh_socket_probe4reload();
[270]915#ifdef SH_DEBUG_SOCKET
916 fprintf (stderr, "Server: probe done %s\n", clt);
917#endif
[1]918 cmd[0] = 'L'; cmd[1] = 'I'; cmd[2] = 'S'; cmd[3] = 'T';cmd[4] = '\0';
919 goto list_all;
920 }
921 sl_strlcpy (srvcmd->cmd, cmd, SH_MAXMSGLEN);
922 sl_strlcpy (srvcmd->clt, clt, SH_MAXMSGLEN);
923 --clt; *clt = ':';
924 }
925 else
926 {
[270]927#ifdef SH_DEBUG_SOCKET
928 fprintf (stderr, "Server: bad message\n");
929#endif
[1]930 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
931 _("Bad message format"),
932 _("sh_socket_read"));
[252]933 sl_close_fd(FIL__, __LINE__, talkfd);
[1]934 return -1;
935 }
936
937 /* Bounce the message back to the sender.
938 * 'name' is the receiver address; it has been been filled
939 * with the sender address in the recvfrom call
940 */
941#ifdef SH_DEBUG_SOCKET
942 fprintf (stderr, "Server: send message: %s to %s\n",
943 cmd, name.sun_path);
944#endif
945 /*
946 nbytes = sendto (pf_unix_fd, message, nbytes, 0,
947 (struct sockaddr *) & name, size);
948 */
949 nbytes = send (talkfd, cmd, strlen(cmd) + 1, 0);
[252]950 sl_close_fd(FIL__, __LINE__, talkfd);
[1]951 if (nbytes < 0)
952 {
953 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]954 sh_error_message (errno, errbuf, sizeof(errbuf)),
[1]955 _("sh_socket_read: send"));
956 return -1;
957 }
958#ifdef SH_DEBUG_SOCKET
959 fprintf (stderr, "Server: message is out\n");
960#endif
961 return nbytes;
962
963 list_all:
964#ifdef SH_DEBUG_SOCKET
965 fprintf (stderr, "Server: list all\n");
966#endif
967 if (cmd[4] == 'A' && cmd[5] == 'L' && cmd[6] == 'L')
968 {
969 list_cmd = runlist;
970 while (list_cmd)
971 {
[40]972 sl_snprintf(message, sizeof(message), _("SENT %8s %32s %s"),
[1]973 list_cmd->cmd, list_cmd->clt, list_cmd->cti);
974 /*
975 sl_strlcpy(message, _("DONE"), SH_MAXMSG);
976 sl_strlcat(message, " ", SH_MAXMSG);
977 sl_strlcat(message, list_cmd->cmd, SH_MAXMSG);
978 sl_strlcat(message, " ", SH_MAXMSG);
979 sl_strlcat(message, list_cmd->clt, SH_MAXMSG);
980 sl_strlcat(message, " ", SH_MAXMSG);
981 sl_strlcat(message, list_cmd->cti, SH_MAXMSG);
982 */
983 nbytes = send (talkfd, message, sl_strlen(message) + 1, 0);
984 if (nbytes < 0)
985 {
986 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]987 sh_error_message (errno, errbuf, sizeof(errbuf)),
[1]988 _("sh_socket_read: sendto"));
[252]989 sl_close_fd(FIL__, __LINE__, talkfd);
[1]990 return -1;
991 }
992 list_cmd = list_cmd->next;
993 }
994 }
995
996 list_cmd = cmdlist;
997 while (list_cmd)
998 {
[40]999 sl_snprintf(message, sizeof(message), _(">>>> %8s %32s %s"),
[1]1000 list_cmd->cmd, list_cmd->clt, list_cmd->cti);
1001 /*
1002 sl_strlcpy(message, _(">>>>"), SH_MAXMSG);
1003 sl_strlcat(message, " ", SH_MAXMSG);
1004 sl_strlcat(message, list_cmd->cmd, SH_MAXMSG);
1005 sl_strlcat(message, " ", SH_MAXMSG);
1006 sl_strlcat(message, list_cmd->clt, SH_MAXMSG);
1007 sl_strlcat(message, " ", SH_MAXMSG);
1008 sl_strlcat(message, list_cmd->cti, SH_MAXMSG);
1009 */
1010 /*
1011 nbytes = sendto (pf_unix_fd, message, sl_strlen(message) + 1, 0,
1012 (struct sockaddr *) & name, size);
1013 */
1014 nbytes = send (talkfd, message, sl_strlen(message) + 1, 0);
1015 if (nbytes < 0)
1016 {
1017 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]1018 sh_error_message (errno, errbuf, sizeof(errbuf)),
[1]1019 _("sh_socket_read: sendto"));
[252]1020 sl_close_fd(FIL__, __LINE__, talkfd);
[1]1021 return -1;
1022 }
1023 list_cmd = list_cmd->next;
1024 }
1025
1026 /*
1027 nbytes = sendto (pf_unix_fd, _("END"), 4, 0,
1028 (struct sockaddr *) & name, size);
1029 */
[383]1030 /* nbytes = *//* never read */ send (talkfd, _("END"), 4, 0);
[252]1031 sl_close_fd(FIL__, __LINE__, talkfd);
[1]1032 return 0;
1033}
1034/* #if !defined(HAVE_CMSGCRED) || !defined(SO_PEERCRED) */
1035/* #endif */
1036
1037static void sh_socket_add2list (struct socket_cmd * in)
1038{
1039 struct socket_cmd * new;
1040
1041 new = SH_ALLOC(sizeof(struct socket_cmd));
[22]1042 sl_strlcpy (new->cmd, in->cmd, sizeof(new->cmd));
1043 sl_strlcpy (new->clt, in->clt, sizeof(new->clt));
[270]1044#ifdef SH_DEBUG_SOCKET
1045 fprintf(stderr, "add2list: time set for %s\n", new->clt);
1046#endif
[132]1047 (void) sh_unix_time(0, new->cti, sizeof(new->cti));
[1]1048 new->next = cmdlist;
1049 cmdlist = new;
1050
1051 return;
1052}
1053
1054static void sh_socket_add2run (struct socket_cmd * in)
1055{
1056 struct socket_cmd * new = runlist;
1057 char * client_name = in->clt;
1058
1059 while (new)
1060 {
1061 if (0 == sl_strcmp(new->clt, client_name))
1062 {
[22]1063 sl_strlcpy (new->cmd, in->cmd, sizeof(new->cmd));
1064 sl_strlcpy (new->clt, in->clt, sizeof(new->clt));
[270]1065#ifdef SH_DEBUG_SOCKET
1066 fprintf(stderr, "add2run: time reset for %s\n", new->clt);
1067#endif
[132]1068 (void) sh_unix_time(0, new->cti, sizeof(new->cti));
[1]1069 return;
1070 }
1071 new = new->next;
1072 }
1073
1074 new = SH_ALLOC(sizeof(struct socket_cmd));
[22]1075 sl_strlcpy (new->cmd, in->cmd, sizeof(new->cmd));
1076 sl_strlcpy (new->clt, in->clt, sizeof(new->clt));
[270]1077#ifdef SH_DEBUG_SOCKET
1078 fprintf(stderr, "add2run: time set for %s\n", new->clt);
1079#endif
[132]1080 (void) sh_unix_time(0, new->cti, sizeof(new->cti));
[1]1081 new->next = runlist;
1082 runlist = new;
1083
1084 return;
1085}
1086
1087
1088
1089static void sh_socket_rm2list (const char * client_name)
1090{
1091 struct socket_cmd * old = cmdlist;
1092 struct socket_cmd * new = cmdlist;
1093
1094 while (new)
1095 {
1096 if (0 == sl_strcmp(new->clt, client_name))
1097 {
1098 if ((new == cmdlist) && (new->next == NULL))
1099 {
1100 cmdlist = NULL;
1101 SH_FREE(new);
1102 return;
1103 }
1104 else if (new == cmdlist)
1105 {
1106 cmdlist = new->next;
1107 SH_FREE(new);
1108 return;
1109 }
1110 else
1111 {
1112 old->next = new->next;
1113 SH_FREE(new);
1114 return;
1115 }
1116 }
1117 old = new;
1118 new = new->next;
1119 }
1120 return;
1121}
1122
1123/* poll the socket to gather input
1124 */
1125int sh_socket_poll()
1126{
1127 struct socket_cmd cmd;
1128 char cancel_cmd[SH_MAXMSGLEN];
1129
1130 /* struct pollfd sh_poll = { pf_unix_fd, POLLIN, 0 }; */
1131
1132 if (pf_unix_fd < 0)
1133 {
1134 return 0;
1135 }
1136
[40]1137 sl_strlcpy(cancel_cmd, _("CANCEL"), sizeof(cancel_cmd));
[1]1138
1139 while (sh_socket_read (&cmd) > 0)
1140 {
1141 if (0 == sl_strcmp(cmd.cmd, cancel_cmd))
1142 {
1143 sh_socket_rm2list (cmd.clt);
1144 }
1145 else
1146 {
1147 sh_socket_rm2list (cmd.clt);
1148 sh_socket_add2list (&cmd);
1149 }
1150 }
1151 return 0;
1152}
1153
1154/* return the command associated with client_name
1155 and remove the corresponding entry
1156 */
1157char * sh_socket_check(const char * client_name)
1158{
1159 struct socket_cmd * new = cmdlist;
1160 static char out[SH_MAXMSGLEN];
1161
1162 while (new)
1163 {
1164 if (0 == sl_strcmp(new->clt, client_name))
1165 {
[40]1166 sl_strlcpy(out, new->cmd, sizeof(out));
[1]1167 sh_socket_add2run (new);
1168 sh_socket_rm2list (client_name);
1169 return out;
1170 }
1171 new = new->next;
1172 }
1173 return NULL;
1174}
1175
1176/* #if defined (SH_WITH_SERVER)
1177 */
1178#endif
1179
Note: See TracBrowser for help on using the repository browser.