source: trunk/src/sh_socket.c@ 278

Last change on this file since 278 was 272, checked in by katerina, 15 years ago

Fixes tickets #190, #191, #192, #193, and #194.

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 int size;
560 int nbytes;
561 int talkfd;
562 int retry = 0;
563
564 char * cmd = NULL;
565 char * clt = NULL;
566
567 int client_uid = -1;
568 char errbuf[SH_ERRBUF_SIZE];
569
570
571 struct msghdr msg;
572 struct iovec iov;
573
574#if defined(NEED_PASSWORD_AUTH)
575 char * eopw = NULL;
576 char * goodpassword = NULL;
577#endif
578
579#if defined(HAVE_GETPEEREID)
580 uid_t peer_uid;
581 gid_t peer_gid;
582#elif defined(SO_PEERCRED)
583 struct ucred cr;
584#ifdef HAVE_SOCKLEN_T
585 socklen_t cl = sizeof(cr);
586#else
587 int cl = sizeof(cr);
588#endif
589
590#elif defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || (defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))
591
592#ifdef HAVE_STRUCT_CMSGCRED
593 typedef struct cmsgcred Cred;
594#define CRED_UID cmcred_uid
595
596#elif HAVE_STRUCT_FCRED
597 typedef struct fcred Cred;
598#define CRED_UID fc_uid
599
600#elif HAVE_STRUCT_SOCKCRED
601 typedef struct sockcred Cred;
602#define CRED_UID sc_uid
603
604#endif
605 Cred *cred;
606
607 /* Compute size without padding */
608 char cmsgmem[ALIGN(sizeof(struct cmsghdr)) + ALIGN(sizeof(Cred))];
609 /* for NetBSD */
610
611 /* Point to start of first structure */
612 struct cmsghdr *cmsg = (struct cmsghdr *) cmsgmem;
613#endif
614
615 if (pf_unix_fd < 0)
616 {
617 return 0;
618 }
619
620 iov.iov_base = (char *) &message;
621 iov.iov_len = sizeof(message);
622
623 memset (&msg, 0, sizeof (msg));
624 msg.msg_iov = &iov;
625 msg.msg_iovlen = 1;
626
627#if !defined(SO_PEERCRED) && !defined(HAVE_GETPEEREID)
628#if defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || (defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))
629 msg.msg_control = (char *) cmsg;
630 msg.msg_controllen = sizeof (cmsgmem);
631 memset (cmsg, 0, sizeof (cmsgmem));
632#endif
633#endif
634
635 /* the socket is non-blocking
636 * 'name' is the address of the sender socket
637 */
638 size = sizeof (name);
639 talkfd = retry_accept(FIL__, __LINE__,
640 pf_unix_fd, (struct sockaddr *) & name, &size);
641 if ((talkfd < 0) && (errno == EAGAIN))
642 {
643 return 0;
644 }
645 else if (talkfd < 0)
646 {
647 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
648 sh_error_message (errno, errbuf, sizeof(errbuf)),
649 _("sh_socket_read: accept"));
650 return -1;
651 }
652
653
654#if defined(LOCAL_CREDS) && !defined(SO_PEERCRED) && !defined(HAVE_GETPEEREID)
655 /* Set the socket to receive credentials on the next message
656 */
657 {
658 int on = 1;
659 if (setsockopt (talkfd, 0, LOCAL_CREDS, &on, sizeof (on)) < 0)
660 {
661 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
662 sh_error_message (errno, errbuf, sizeof(errbuf)),
663 _("sh_socket_read: setsockopt"));
664 sl_close_fd(FIL__, __LINE__, talkfd);
665 return -1;
666 }
667 }
668#endif
669
670 do {
671 nbytes = recvmsg (talkfd, &msg, 0);
672 if ((nbytes < 0) && (errno != EAGAIN))
673 {
674 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
675 sh_error_message (errno, errbuf, sizeof(errbuf)),
676 _("sh_socket_read: recvmsg"));
677 sl_close_fd(FIL__, __LINE__, talkfd);
678 return -1;
679 }
680 else if (nbytes < 0)
681 {
682 ++retry;
683 retry_msleep(0, 1);
684 }
685 } while ((nbytes < 0) && (retry < 3));
686
687#ifdef SH_DEBUG_SOCKET
688 fprintf(stderr, "%d bytes received\n", nbytes);
689#endif
690
691 /* msg.msg_iov.iov_base, filled by recvmsg
692 */
693 message[sizeof(message)-1] = '\0';
694
695 if (nbytes < 0)
696 {
697 if (errno == EAGAIN)
698 {
699 /* no data */
700 sl_close_fd(FIL__, __LINE__, talkfd);
701 return 0;
702 }
703 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
704 sh_error_message (errno, errbuf, sizeof(errbuf)),
705 _("sh_socket_read: recvfrom"));
706 sl_close_fd(FIL__, __LINE__, talkfd);
707 return -1;
708 }
709
710#if defined(HAVE_GETPEEREID)
711 if (0 != getpeereid(talkfd, &peer_uid, &peer_gid))
712 {
713 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
714 sh_error_message (errno, errbuf, sizeof(errbuf)),
715 _("sh_socket_read: getpeereid"));
716 sl_close_fd(FIL__, __LINE__, talkfd);
717 return -1;
718 }
719 client_uid = peer_uid;
720 cmd = message;
721#elif defined(SO_PEERCRED)
722 if (0 != getsockopt(talkfd, SOL_SOCKET, SO_PEERCRED, &cr, &cl))
723 {
724 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
725 sh_error_message (errno, errbuf, sizeof(errbuf)),
726 _("sh_socket_read: getsockopt"));
727 sl_close_fd(FIL__, __LINE__, talkfd);
728 return -1;
729 }
730 client_uid = cr.uid;
731 cmd = message;
732#elif defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || (defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))
733 if (cmsg->cmsg_len < sizeof (cmsgmem) || cmsg->cmsg_type != SCM_CREDS)
734 {
735 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
736 _("Message from recvmsg() was not SCM_CREDS"),
737 _("sh_socket_read"));
738
739 /* Check for file descriptors sent using SCM_RIGHTS, and
740 * close them. If MSG_CTRUNC is set, the buffer was too small,
741 * and no fds are duped.
742 */
743 if (msg.msg_controllen >= sizeof(struct cmsghdr) &&
744 (msg.msg_flags & MSG_CTRUNC) == 0)
745 {
746 unsigned int data_size;
747 unsigned int data_i;
748 int fdcount, fdmax;
749 struct cmsghdr * cmptr;
750 int fdsbuf[1 + (sizeof(cmsgmem)/sizeof(int))];
751
752 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL;
753 cmptr = CMSG_NXTHDR(&msg, cmptr))
754 {
755 if (cmptr->cmsg_len > sizeof (cmsgmem) ||
756 cmptr->cmsg_level != SOL_SOCKET ||
757 cmptr->cmsg_type != SCM_RIGHTS)
758 continue;
759
760 /* Crappy way of finding the data length.
761 * cmptr->cmsg_len includes both header and padding,
762 * how are you supposed to find the data length?
763 * cmptr->cmsg_len - ALIGN(sizeof(struct cmsghdr)) ?
764 */
765 data_size = 0;
766
767 for (data_i = 0; data_i < cmptr->cmsg_len; ++data_i)
768 {
769 if (CMSG_LEN(data_i) == cmptr->cmsg_len)
770 {
771 data_size = data_i;
772 break;
773 }
774 }
775 memcpy(fdsbuf, CMSG_DATA(cmptr), data_size);
776 fdmax = data_size / sizeof(int);
777 for (fdcount = 0; fdcount < fdmax; ++fdcount)
778 (void) sl_close_fd(FIL__, __LINE__, fdsbuf[fdcount]);
779 }
780 }
781
782 sl_close_fd(FIL__, __LINE__, talkfd);
783 return -1;
784 }
785 cred = (Cred *) CMSG_DATA (cmsg);
786 client_uid = cred->CRED_UID;
787 cmd = message;
788#elif defined(NEED_PASSWORD_AUTH)
789 goodpassword = sh_get_sockpass();
790 eopw = strchr(message, '@');
791 if (eopw)
792 *eopw = '\0';
793 /*
794 * message is null-terminated and >> goodpassword
795 */
796 if (0 == strcmp(goodpassword, message) &&
797 strlen(goodpassword) < (sizeof(message)/2))
798 {
799 client_uid = sh_socket_flaguid;
800 cmd = &message[strlen(goodpassword)+1];
801 sh_set_sockpass();
802 }
803 else
804 {
805 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
806 _("Bad password"),
807 _("sh_socket_read"));
808 sh_set_sockpass();
809 sl_close_fd(FIL__, __LINE__, talkfd);
810 return -1;
811 }
812#else
813 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
814 _("Socket credentials not supported on this OS"),
815 _("sh_socket_read"));
816 sl_close_fd(FIL__, __LINE__, talkfd);
817 return -1;
818#endif
819
820#ifdef SH_DEBUG_SOCKET
821 fprintf(stderr, "Peer uid=%d, required=%d\n",
822 client_uid, sh_socket_flaguid);
823#endif
824
825 if (client_uid != sh_socket_flaguid)
826 {
827 sh_error_handle((-1), FIL__, __LINE__, client_uid, MSG_E_SUBGEN,
828 _("client does not have required uid"),
829 _("sh_socket_read: getsockopt"));
830 sl_close_fd(FIL__, __LINE__, talkfd);
831 return -1;
832 }
833
834
835 /* Give a diagnostic message.
836 */
837#ifdef SH_DEBUG_SOCKET
838 fprintf (stderr, "Server: got message: %s\n", cmd);
839#endif
840
841 clt = strchr(cmd, ':');
842 if (clt != NULL)
843 {
844 *clt = '\0'; ++clt;
845 if (sl_strlen(cmd) >= SH_MAXMSGLEN)
846 {
847#ifdef SH_DEBUG_SOCKET
848 fprintf (stderr, "Server: command too long: %s\n", cmd);
849#endif
850 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
851 _("Bad message format: command too long"),
852 _("sh_socket_read"));
853 sl_close_fd(FIL__, __LINE__, talkfd);
854 return -1;
855 }
856 else if (sl_strlen(clt) >= SH_MAXMSGLEN)
857 {
858#ifdef SH_DEBUG_SOCKET
859 fprintf (stderr, "Server: hostname too long: %s\n", clt);
860#endif
861 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
862 _("Bad message format: hostname too long"),
863 _("sh_socket_read"));
864 sl_close_fd(FIL__, __LINE__, talkfd);
865 return -1;
866 }
867 if (cmd[0] == 'L' && cmd[1] == 'I' &&
868 cmd[2] == 'S' && cmd[3] == 'T')
869 {
870#ifdef SH_DEBUG_SOCKET
871 fprintf (stderr, "Server: list %s\n", clt);
872#endif
873 goto list_all;
874 }
875 else if (cmd[0] == 'P' && cmd[1] == 'R' &&
876 cmd[2] == 'O' && cmd[3] == 'B' && cmd[4] == 'E')
877 {
878#ifdef SH_DEBUG_SOCKET
879 fprintf (stderr, "Server: probe start %s\n", clt);
880#endif
881 sh_socket_probe4reload();
882#ifdef SH_DEBUG_SOCKET
883 fprintf (stderr, "Server: probe done %s\n", clt);
884#endif
885 cmd[0] = 'L'; cmd[1] = 'I'; cmd[2] = 'S'; cmd[3] = 'T';cmd[4] = '\0';
886 goto list_all;
887 }
888 sl_strlcpy (srvcmd->cmd, cmd, SH_MAXMSGLEN);
889 sl_strlcpy (srvcmd->clt, clt, SH_MAXMSGLEN);
890 --clt; *clt = ':';
891 }
892 else
893 {
894#ifdef SH_DEBUG_SOCKET
895 fprintf (stderr, "Server: bad message\n");
896#endif
897 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
898 _("Bad message format"),
899 _("sh_socket_read"));
900 sl_close_fd(FIL__, __LINE__, talkfd);
901 return -1;
902 }
903
904 /* Bounce the message back to the sender.
905 * 'name' is the receiver address; it has been been filled
906 * with the sender address in the recvfrom call
907 */
908#ifdef SH_DEBUG_SOCKET
909 fprintf (stderr, "Server: send message: %s to %s\n",
910 cmd, name.sun_path);
911#endif
912 /*
913 nbytes = sendto (pf_unix_fd, message, nbytes, 0,
914 (struct sockaddr *) & name, size);
915 */
916 nbytes = send (talkfd, cmd, strlen(cmd) + 1, 0);
917 sl_close_fd(FIL__, __LINE__, talkfd);
918 if (nbytes < 0)
919 {
920 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
921 sh_error_message (errno, errbuf, sizeof(errbuf)),
922 _("sh_socket_read: send"));
923 return -1;
924 }
925#ifdef SH_DEBUG_SOCKET
926 fprintf (stderr, "Server: message is out\n");
927#endif
928 return nbytes;
929
930 list_all:
931#ifdef SH_DEBUG_SOCKET
932 fprintf (stderr, "Server: list all\n");
933#endif
934 if (cmd[4] == 'A' && cmd[5] == 'L' && cmd[6] == 'L')
935 {
936 list_cmd = runlist;
937 while (list_cmd)
938 {
939 sl_snprintf(message, sizeof(message), _("SENT %8s %32s %s"),
940 list_cmd->cmd, list_cmd->clt, list_cmd->cti);
941 /*
942 sl_strlcpy(message, _("DONE"), SH_MAXMSG);
943 sl_strlcat(message, " ", SH_MAXMSG);
944 sl_strlcat(message, list_cmd->cmd, SH_MAXMSG);
945 sl_strlcat(message, " ", SH_MAXMSG);
946 sl_strlcat(message, list_cmd->clt, SH_MAXMSG);
947 sl_strlcat(message, " ", SH_MAXMSG);
948 sl_strlcat(message, list_cmd->cti, SH_MAXMSG);
949 */
950 nbytes = send (talkfd, message, sl_strlen(message) + 1, 0);
951 if (nbytes < 0)
952 {
953 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
954 sh_error_message (errno, errbuf, sizeof(errbuf)),
955 _("sh_socket_read: sendto"));
956 sl_close_fd(FIL__, __LINE__, talkfd);
957 return -1;
958 }
959 list_cmd = list_cmd->next;
960 }
961 }
962
963 list_cmd = cmdlist;
964 while (list_cmd)
965 {
966 sl_snprintf(message, sizeof(message), _(">>>> %8s %32s %s"),
967 list_cmd->cmd, list_cmd->clt, list_cmd->cti);
968 /*
969 sl_strlcpy(message, _(">>>>"), SH_MAXMSG);
970 sl_strlcat(message, " ", SH_MAXMSG);
971 sl_strlcat(message, list_cmd->cmd, SH_MAXMSG);
972 sl_strlcat(message, " ", SH_MAXMSG);
973 sl_strlcat(message, list_cmd->clt, SH_MAXMSG);
974 sl_strlcat(message, " ", SH_MAXMSG);
975 sl_strlcat(message, list_cmd->cti, SH_MAXMSG);
976 */
977 /*
978 nbytes = sendto (pf_unix_fd, message, sl_strlen(message) + 1, 0,
979 (struct sockaddr *) & name, size);
980 */
981 nbytes = send (talkfd, message, sl_strlen(message) + 1, 0);
982 if (nbytes < 0)
983 {
984 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
985 sh_error_message (errno, errbuf, sizeof(errbuf)),
986 _("sh_socket_read: sendto"));
987 sl_close_fd(FIL__, __LINE__, talkfd);
988 return -1;
989 }
990 list_cmd = list_cmd->next;
991 }
992
993 /*
994 nbytes = sendto (pf_unix_fd, _("END"), 4, 0,
995 (struct sockaddr *) & name, size);
996 */
997 nbytes = send (talkfd, _("END"), 4, 0);
998 sl_close_fd(FIL__, __LINE__, talkfd);
999 return 0;
1000}
1001/* #if !defined(HAVE_CMSGCRED) || !defined(SO_PEERCRED) */
1002/* #endif */
1003
1004static void sh_socket_add2list (struct socket_cmd * in)
1005{
1006 struct socket_cmd * new;
1007
1008 new = SH_ALLOC(sizeof(struct socket_cmd));
1009 sl_strlcpy (new->cmd, in->cmd, sizeof(new->cmd));
1010 sl_strlcpy (new->clt, in->clt, sizeof(new->clt));
1011#ifdef SH_DEBUG_SOCKET
1012 fprintf(stderr, "add2list: time set for %s\n", new->clt);
1013#endif
1014 (void) sh_unix_time(0, new->cti, sizeof(new->cti));
1015 new->next = cmdlist;
1016 cmdlist = new;
1017
1018 return;
1019}
1020
1021static void sh_socket_add2run (struct socket_cmd * in)
1022{
1023 struct socket_cmd * new = runlist;
1024 char * client_name = in->clt;
1025
1026 while (new)
1027 {
1028 if (0 == sl_strcmp(new->clt, client_name))
1029 {
1030 sl_strlcpy (new->cmd, in->cmd, sizeof(new->cmd));
1031 sl_strlcpy (new->clt, in->clt, sizeof(new->clt));
1032#ifdef SH_DEBUG_SOCKET
1033 fprintf(stderr, "add2run: time reset for %s\n", new->clt);
1034#endif
1035 (void) sh_unix_time(0, new->cti, sizeof(new->cti));
1036 return;
1037 }
1038 new = new->next;
1039 }
1040
1041 new = SH_ALLOC(sizeof(struct socket_cmd));
1042 sl_strlcpy (new->cmd, in->cmd, sizeof(new->cmd));
1043 sl_strlcpy (new->clt, in->clt, sizeof(new->clt));
1044#ifdef SH_DEBUG_SOCKET
1045 fprintf(stderr, "add2run: time set for %s\n", new->clt);
1046#endif
1047 (void) sh_unix_time(0, new->cti, sizeof(new->cti));
1048 new->next = runlist;
1049 runlist = new;
1050
1051 return;
1052}
1053
1054
1055
1056static void sh_socket_rm2list (const char * client_name)
1057{
1058 struct socket_cmd * old = cmdlist;
1059 struct socket_cmd * new = cmdlist;
1060
1061 while (new)
1062 {
1063 if (0 == sl_strcmp(new->clt, client_name))
1064 {
1065 if ((new == cmdlist) && (new->next == NULL))
1066 {
1067 cmdlist = NULL;
1068 SH_FREE(new);
1069 return;
1070 }
1071 else if (new == cmdlist)
1072 {
1073 cmdlist = new->next;
1074 SH_FREE(new);
1075 return;
1076 }
1077 else
1078 {
1079 old->next = new->next;
1080 SH_FREE(new);
1081 return;
1082 }
1083 }
1084 old = new;
1085 new = new->next;
1086 }
1087 return;
1088}
1089
1090/* poll the socket to gather input
1091 */
1092int sh_socket_poll()
1093{
1094 struct socket_cmd cmd;
1095 char cancel_cmd[SH_MAXMSGLEN];
1096
1097 /* struct pollfd sh_poll = { pf_unix_fd, POLLIN, 0 }; */
1098
1099 if (pf_unix_fd < 0)
1100 {
1101 return 0;
1102 }
1103
1104 sl_strlcpy(cancel_cmd, _("CANCEL"), sizeof(cancel_cmd));
1105
1106 while (sh_socket_read (&cmd) > 0)
1107 {
1108 if (0 == sl_strcmp(cmd.cmd, cancel_cmd))
1109 {
1110 sh_socket_rm2list (cmd.clt);
1111 }
1112 else
1113 {
1114 sh_socket_rm2list (cmd.clt);
1115 sh_socket_add2list (&cmd);
1116 }
1117 }
1118 return 0;
1119}
1120
1121/* return the command associated with client_name
1122 and remove the corresponding entry
1123 */
1124char * sh_socket_check(const char * client_name)
1125{
1126 struct socket_cmd * old = cmdlist;
1127 struct socket_cmd * new = cmdlist;
1128 static char out[SH_MAXMSGLEN];
1129
1130 while (new)
1131 {
1132 if (0 == sl_strcmp(new->clt, client_name))
1133 {
1134 sl_strlcpy(out, new->cmd, sizeof(out));
1135 sh_socket_add2run (new);
1136 sh_socket_rm2list (client_name);
1137 return out;
1138 }
1139 old = new;
1140 new = new->next;
1141 }
1142 return NULL;
1143}
1144
1145/* #if defined (SH_WITH_SERVER)
1146 */
1147#endif
1148
Note: See TracBrowser for help on using the repository browser.