source: trunk/src/sh_socket.c@ 257

Last change on this file since 257 was 252, checked in by katerina, 15 years ago

Add code to check for stale file records on close() and fclose(), fix sl_close() to handle open stream (ticket #163).

File size: 28.1 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 sl_close_fd(FIL__, __LINE__, 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 sl_close_fd(FIL__, __LINE__, 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 sl_close_fd(FIL__, __LINE__, 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 sl_close_fd(FIL__, __LINE__, 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 sl_close_fd(FIL__, __LINE__, 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 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: fcntl2"));
466 SL_RETURN( (-1), _("sh_socket_open_int"));
467 }
468
469 if (0 != listen(pf_unix_fd, 5))
470 {
471 sl_close_fd(FIL__, __LINE__, 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 sl_close_fd(FIL__, __LINE__, 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 sl_close_fd(FIL__, __LINE__, 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 sl_close_fd(FIL__, __LINE__, 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 sl_close_fd(FIL__, __LINE__, 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 sl_close_fd(FIL__, __LINE__, 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 sl_close_fd(FIL__, __LINE__, 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) sl_close_fd(FIL__, __LINE__, fdsbuf[fdcount]);
747 }
748 }
749
750 sl_close_fd(FIL__, __LINE__, 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 sl_close_fd(FIL__, __LINE__, 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 sl_close_fd(FIL__, __LINE__, 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 sl_close_fd(FIL__, __LINE__, 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 sl_close_fd(FIL__, __LINE__, 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 sl_close_fd(FIL__, __LINE__, 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 sl_close_fd(FIL__, __LINE__, 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 sl_close_fd(FIL__, __LINE__, 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 sl_close_fd(FIL__, __LINE__, 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 sl_close_fd(FIL__, __LINE__, 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 sl_close_fd(FIL__, __LINE__, 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.