source: trunk/src/sh_socket.c@ 318

Last change on this file since 318 was 315, checked in by katerina, 14 years ago

Fix for ticket #236 (blocking on NFS mounts).

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