source: trunk/src/sh_socket.c@ 229

Last change on this file since 229 was 200, checked in by katerina, 16 years ago

Implement server->client SCAN command to run file check on demand.

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