source: trunk/src/sh_socket.c@ 264

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

Fix for ticket #182 (too many UID/GID lookups).

File size: 28.1 KB
RevLine 
[1]1/* SAMHAIN file system integrity testing */
2/* Copyright (C) 2003,2005 Rainer Wichmann */
3/* */
4/* This program is free software; you can redistribute it */
5/* and/or modify */
6/* it under the terms of the GNU General Public License as */
7/* published by */
8/* the Free Software Foundation; either version 2 of the License, or */
9/* (at your option) any later version. */
10/* */
11/* This program is distributed in the hope that it will be useful, */
12/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
13/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
14/* GNU General Public License for more details. */
15/* */
16/* You should have received a copy of the GNU General Public License */
17/* along with this program; if not, write to the Free Software */
18/* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20#include "config_xor.h"
21
22/* define if you want debug info
23 * #define SH_DEBUG_SOCKET
24 */
[177]25#if defined(SH_WITH_SERVER) && defined(__linux__)
26#define _GNU_SOURCE
27#endif
[1]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 }
[200]55 if ((srvcmd[0] == 'S') && (srvcmd[1] == 'T') &&
56 (srvcmd[2] == 'O') && (srvcmd[3] == 'P'))
[1]57 {
58 TPT((0, FIL__, __LINE__, _("msg=<stop command from server>\n")));
59#ifdef SIGQUIT
60 raise(SIGQUIT);
61#else
[200]62 sig_terminate = 1;
63 ++sig_raised;
[1]64#endif
65 }
[200]66 else if ((srvcmd[0] == 'R') && (srvcmd[1] == 'E') &&
67 (srvcmd[2] == 'L') && (srvcmd[3] == 'O') &&
68 (srvcmd[4] == 'A') && (srvcmd[5] == 'D'))
[1]69 {
70 TPT((0, FIL__, __LINE__, _("msg=<reload command from server>\n")));
71#ifdef SIGHUP
72 raise(SIGHUP);
73#else
[200]74 sig_config_read_again = 1;
75 ++sig_raised;
[1]76#endif
77 }
[200]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 }
[1]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;
[40]137static char sh_sockpass_real[SOCKPASS_MAX+1];
[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
[170]204static void sh_socket_probe4reload (void)
[1]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
[170]248char * sh_get_sockpass (void)
[1]249{
[50]250 size_t j = 0;
251
[40]252 while (skey->sh_sockpass[2*j] != '\0' && j < sizeof(sh_sockpass_real))
[1]253 {
254 sh_sockpass_real[j] = skey->sh_sockpass[2*j];
255 ++j;
256 }
257 sh_sockpass_real[j] = '\0';
[50]258
[1]259 return sh_sockpass_real;
260}
261
[170]262void sh_set_sockpass (void)
[1]263{
264 int j;
265 for (j = 0; j < 15; ++j)
266 {
267 sh_sockpass_real[j] = '\0';
268 }
269}
270
[22]271int sh_socket_use (const char * c)
[1]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
[22]316int sh_socket_uid (const char * c)
[1]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
[22]328int sh_socket_password (const char * c)
[1]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);
[40]336 if (i > SOCKPASS_MAX) {
[1]337 return -1;
338 }
[40]339 for (j = 0; j < (2*SOCKPASS_MAX+1); ++j)
[1]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;
[132]368 char errbuf[SH_ERRBUF_SIZE];
[1]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;
[34]380 sh_sockname = SH_ALLOC(size); /* compile-time constant */
[1]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
[264]387
[1]388 pf_unix_fd = socket (PF_UNIX, SOCK_STREAM, 0);
389 if ((pf_unix_fd) < 0)
390 {
391 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]392 sh_error_message (errno, errbuf, sizeof(errbuf)),
[1]393 _("sh_socket_open_int: socket"));
394 SL_RETURN( (-1), _("sh_socket_open_int"));
395 }
396
397 if (sizeof(name.sun_path) < (1 + sl_strlen(sh_sockname)))
398 {
[252]399 sl_close_fd(FIL__, __LINE__, pf_unix_fd); pf_unix_fd = -1;
[1]400 sh_error_handle ((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
401 _("PID dir path too long"),
402 _("sh_socket_open_int"));
403 SL_RETURN( (-1), _("sh_socket_open_int"));
404 }
405
406 name.sun_family = AF_FILE;
[22]407 sl_strlcpy (name.sun_path, sh_sockname, sizeof(name.sun_path));
[1]408
409 size = (offsetof (struct sockaddr_un, sun_path)
410 + strlen (name.sun_path) + 1);
411
412 flags = retry_lstat (FIL__, __LINE__, sh_sockname, &buf);
413
414 if (flags == 0)
415 {
416 sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, -1, MSG_E_SUBGEN,
417 _("Socket exists, trying to unlink it"),
418 _("sh_socket_open_int"));
419 if (sh_socket_remove() < 0)
420 {
[252]421 sl_close_fd(FIL__, __LINE__, pf_unix_fd); pf_unix_fd = -1;
[1]422 sh_error_handle ((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
423 _("Unlink of socket failed, maybe path not trusted"),
424 _("sh_socket_open_int"));
425 SL_RETURN( (-1), _("sh_socket_open_int"));
426 }
427 }
428
429 if (bind ((pf_unix_fd), (struct sockaddr *) &name, size) < 0)
430 {
[252]431 sl_close_fd(FIL__, __LINE__, pf_unix_fd); pf_unix_fd = -1;
[1]432 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]433 sh_error_message (errno, errbuf, sizeof(errbuf)),
[1]434 _("sh_socket_open_int: bind"));
435 SL_RETURN( (-1), _("sh_socket_open_int"));
436 }
437
438#ifdef SO_PASSCRED
439 if (0 != setsockopt(pf_unix_fd, SOL_SOCKET, SO_PASSCRED,
440 &optval, sizeof(optval)))
441 {
[252]442 sl_close_fd(FIL__, __LINE__, pf_unix_fd); pf_unix_fd = -1;
[1]443 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]444 sh_error_message (errno, errbuf, sizeof(errbuf)),
[1]445 _("sh_socket_open_int: setsockopt"));
446 SL_RETURN( (-1), _("sh_socket_open_int"));
447 }
448#endif
449
450 flags = fcntl((pf_unix_fd), F_GETFL);
451 if (flags < 0)
452 {
[252]453 sl_close_fd(FIL__, __LINE__, pf_unix_fd); pf_unix_fd = -1;
[1]454 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]455 sh_error_message (errno, errbuf, sizeof(errbuf)),
[1]456 _("sh_socket_open_int: fcntl1"));
457 SL_RETURN( (-1), _("sh_socket_open_int"));
458 }
459
460 flags = fcntl((pf_unix_fd), F_SETFL, flags|O_NONBLOCK);
461 if (flags < 0)
462 {
[252]463 sl_close_fd(FIL__, __LINE__, pf_unix_fd); pf_unix_fd = -1;
[1]464 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]465 sh_error_message (errno, errbuf, sizeof(errbuf)),
[1]466 _("sh_socket_open_int: fcntl2"));
467 SL_RETURN( (-1), _("sh_socket_open_int"));
468 }
469
470 if (0 != listen(pf_unix_fd, 5))
471 {
[252]472 sl_close_fd(FIL__, __LINE__, pf_unix_fd); pf_unix_fd = -1;
[1]473 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]474 sh_error_message (errno, errbuf, sizeof(errbuf)),
[1]475 _("sh_socket_open_int: listen"));
476 SL_RETURN( (-1), _("sh_socket_open_int"));
477 }
478 SL_RETURN( (0), _("sh_socket_open_int"));
479}
480/* #if !defined(HAVE_CMSGCRED) || !defined(SO_PEERCRED) */
481/* #endif */
482
483/*
484#if !defined(HAVE_GETPEEREID) && !defined(SO_PEERCRED) && !defined(HAVE_STRUCT_CMSGCRED) && !defined(HAVE_STRUCT_FCRED) && !(defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))
485static
486int sh_socket_read (struct socket_cmd * srvcmd)
487{
488 srvcmd->cmd[0] = '\0';
489 srvcmd->clt[0] = '\0';
490 return 0;
491}
492#else
493*/
494
495/*
496 * Parts of the socket authentication code is copied from PostgreSQL:
497 *
498 * PostgreSQL Database Management System
499 * (formerly known as Postgres, then as Postgres95)
500 *
501 * Portions Copyright (c) 1996-2001, The PostgreSQL Global Development Group
502 *
503 * Portions Copyright (c) 1994, The Regents of the University of California
504 *
505 * Permission to use, copy, modify, and distribute this software and its
506 * documentation for any purpose, without fee, and without a written agreement
507 * is hereby granted, provided that the above copyright notice and this
508 * paragraph and the following two paragraphs appear in all copies.
509 *
510 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
511 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
512 * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
513 * DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
514 * POSSIBILITY OF SUCH DAMAGE.
515 *
516 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
517 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
518 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
519 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO
520 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
521 */
522static
523int sh_socket_read (struct socket_cmd * srvcmd)
524{
525 struct socket_cmd * list_cmd;
526 char message[SH_MAXMSG];
527 struct sockaddr_un name;
528 int size;
529 int nbytes;
530 int talkfd;
531 int retry = 0;
532
533 char * cmd = NULL;
534 char * clt = NULL;
535
536 int client_uid = -1;
[132]537 char errbuf[SH_ERRBUF_SIZE];
[1]538
539
540 struct msghdr msg;
541 struct iovec iov;
542
543#if defined(NEED_PASSWORD_AUTH)
544 char * eopw = NULL;
545 char * goodpassword = NULL;
546#endif
547
548#if defined(HAVE_GETPEEREID)
549 uid_t peer_uid;
550 gid_t peer_gid;
551#elif defined(SO_PEERCRED)
552 struct ucred cr;
[46]553#ifdef HAVE_SOCKLEN_T
554 socklen_t cl = sizeof(cr);
555#else
556 int cl = sizeof(cr);
557#endif
[1]558
559#elif defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || (defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))
560
561#ifdef HAVE_STRUCT_CMSGCRED
562 typedef struct cmsgcred Cred;
563#define CRED_UID cmcred_uid
564
565#elif HAVE_STRUCT_FCRED
566 typedef struct fcred Cred;
567#define CRED_UID fc_uid
568
569#elif HAVE_STRUCT_SOCKCRED
570 typedef struct sockcred Cred;
571#define CRED_UID sc_uid
572
573#endif
574 Cred *cred;
575
576 /* Compute size without padding */
577 char cmsgmem[ALIGN(sizeof(struct cmsghdr)) + ALIGN(sizeof(Cred))];
578 /* for NetBSD */
579
580 /* Point to start of first structure */
581 struct cmsghdr *cmsg = (struct cmsghdr *) cmsgmem;
582#endif
583
584 if (pf_unix_fd < 0)
585 {
586 return 0;
587 }
588
589 iov.iov_base = (char *) &message;
[40]590 iov.iov_len = sizeof(message);
[1]591
592 memset (&msg, 0, sizeof (msg));
593 msg.msg_iov = &iov;
594 msg.msg_iovlen = 1;
595
596#if !defined(SO_PEERCRED) && !defined(HAVE_GETPEEREID)
597#if defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || (defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))
598 msg.msg_control = (char *) cmsg;
599 msg.msg_controllen = sizeof (cmsgmem);
600 memset (cmsg, 0, sizeof (cmsgmem));
601#endif
602#endif
603
604 /* the socket is non-blocking
605 * 'name' is the address of the sender socket
606 */
607 size = sizeof (name);
608 talkfd = retry_accept(FIL__, __LINE__,
609 pf_unix_fd, (struct sockaddr *) & name, &size);
610 if ((talkfd < 0) && (errno == EAGAIN))
611 {
612 return 0;
613 }
614 else if (talkfd < 0)
615 {
616 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]617 sh_error_message (errno, errbuf, sizeof(errbuf)),
[1]618 _("sh_socket_read: accept"));
619 return -1;
620 }
621
622
623#if defined(LOCAL_CREDS) && !defined(SO_PEERCRED) && !defined(HAVE_GETPEEREID)
624 /* Set the socket to receive credentials on the next message
625 */
626 {
627 int on = 1;
628 if (setsockopt (talkfd, 0, LOCAL_CREDS, &on, sizeof (on)) < 0)
629 {
630 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]631 sh_error_message (errno, errbuf, sizeof(errbuf)),
[1]632 _("sh_socket_read: setsockopt"));
[252]633 sl_close_fd(FIL__, __LINE__, talkfd);
[1]634 return -1;
635 }
636 }
637#endif
638
639 do {
640 nbytes = recvmsg (talkfd, &msg, 0);
641 if ((nbytes < 0) && (errno != EAGAIN))
642 {
643 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]644 sh_error_message (errno, errbuf, sizeof(errbuf)),
[1]645 _("sh_socket_read: recvmsg"));
[252]646 sl_close_fd(FIL__, __LINE__, talkfd);
[1]647 return -1;
648 }
649 else if (nbytes < 0)
650 {
651 ++retry;
652 retry_msleep(0, 1);
653 }
654 } while ((nbytes < 0) && (retry < 3));
655
656#ifdef SH_DEBUG_SOCKET
657 fprintf(stderr, "%d bytes received\n", nbytes);
658#endif
659
[40]660 /* msg.msg_iov.iov_base, filled by recvmsg
661 */
662 message[sizeof(message)-1] = '\0';
[1]663
664 if (nbytes < 0)
665 {
666 if (errno == EAGAIN)
667 {
668 /* no data */
[252]669 sl_close_fd(FIL__, __LINE__, talkfd);
[1]670 return 0;
671 }
672 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]673 sh_error_message (errno, errbuf, sizeof(errbuf)),
[1]674 _("sh_socket_read: recvfrom"));
[252]675 sl_close_fd(FIL__, __LINE__, talkfd);
[1]676 return -1;
677 }
678
679#if defined(HAVE_GETPEEREID)
680 if (0 != getpeereid(talkfd, &peer_uid, &peer_gid))
681 {
682 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]683 sh_error_message (errno, errbuf, sizeof(errbuf)),
[1]684 _("sh_socket_read: getpeereid"));
[252]685 sl_close_fd(FIL__, __LINE__, talkfd);
[1]686 return -1;
687 }
688 client_uid = peer_uid;
689 cmd = message;
690#elif defined(SO_PEERCRED)
691 if (0 != getsockopt(talkfd, SOL_SOCKET, SO_PEERCRED, &cr, &cl))
692 {
693 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]694 sh_error_message (errno, errbuf, sizeof(errbuf)),
[1]695 _("sh_socket_read: getsockopt"));
[252]696 sl_close_fd(FIL__, __LINE__, talkfd);
[1]697 return -1;
698 }
699 client_uid = cr.uid;
700 cmd = message;
701#elif defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || (defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))
702 if (cmsg->cmsg_len < sizeof (cmsgmem) || cmsg->cmsg_type != SCM_CREDS)
703 {
704 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
705 _("Message from recvmsg() was not SCM_CREDS"),
706 _("sh_socket_read"));
[118]707
708 /* Check for file descriptors sent using SCM_RIGHTS, and
709 * close them. If MSG_CTRUNC is set, the buffer was too small,
710 * and no fds are duped.
711 */
712 if (msg.msg_controllen >= sizeof(struct cmsghdr) &&
713 (msg.msg_flags & MSG_CTRUNC) == 0)
714 {
715 unsigned int data_size;
716 unsigned int data_i;
717 int fdcount, fdmax;
718 struct cmsghdr * cmptr;
719 int fdsbuf[1 + (sizeof(cmsgmem)/sizeof(int))];
720
721 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL;
722 cmptr = CMSG_NXTHDR(&msg, cmptr))
723 {
724 if (cmptr->cmsg_len > sizeof (cmsgmem) ||
725 cmptr->cmsg_level != SOL_SOCKET ||
726 cmptr->cmsg_type != SCM_RIGHTS)
727 continue;
728
729 /* Crappy way of finding the data length.
730 * cmptr->cmsg_len includes both header and padding,
731 * how are you supposed to find the data length?
732 * cmptr->cmsg_len - ALIGN(sizeof(struct cmsghdr)) ?
733 */
734 data_size = 0;
735
736 for (data_i = 0; data_i < cmptr->cmsg_len; ++data_i)
737 {
738 if (CMSG_LEN(data_i) == cmptr->cmsg_len)
739 {
740 data_size = data_i;
741 break;
742 }
743 }
744 memcpy(fdsbuf, CMSG_DATA(cmptr), data_size);
745 fdmax = data_size / sizeof(int);
746 for (fdcount = 0; fdcount < fdmax; ++fdcount)
[252]747 (void) sl_close_fd(FIL__, __LINE__, fdsbuf[fdcount]);
[118]748 }
749 }
750
[252]751 sl_close_fd(FIL__, __LINE__, talkfd);
[1]752 return -1;
753 }
754 cred = (Cred *) CMSG_DATA (cmsg);
755 client_uid = cred->CRED_UID;
756 cmd = message;
757#elif defined(NEED_PASSWORD_AUTH)
758 goodpassword = sh_get_sockpass();
759 eopw = strchr(message, '@');
760 if (eopw)
761 *eopw = '\0';
[40]762 /*
763 * message is null-terminated and >> goodpassword
764 */
765 if (0 == strcmp(goodpassword, message) &&
766 strlen(goodpassword) < (sizeof(message)/2))
[1]767 {
768 client_uid = sh_socket_flaguid;
769 cmd = &message[strlen(goodpassword)+1];
770 sh_set_sockpass();
771 }
772 else
773 {
774 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
775 _("Bad password"),
776 _("sh_socket_read"));
777 sh_set_sockpass();
[252]778 sl_close_fd(FIL__, __LINE__, talkfd);
[1]779 return -1;
780 }
781#else
782 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
783 _("Socket credentials not supported on this OS"),
784 _("sh_socket_read"));
[252]785 sl_close_fd(FIL__, __LINE__, talkfd);
[1]786 return -1;
787#endif
788
789#ifdef SH_DEBUG_SOCKET
790 fprintf(stderr, "Peer uid=%d, required=%d\n",
791 client_uid, sh_socket_flaguid);
792#endif
793
794 if (client_uid != sh_socket_flaguid)
795 {
796 sh_error_handle((-1), FIL__, __LINE__, client_uid, MSG_E_SUBGEN,
797 _("client does not have required uid"),
798 _("sh_socket_read: getsockopt"));
[252]799 sl_close_fd(FIL__, __LINE__, talkfd);
[1]800 return -1;
801 }
802
803
804 /* Give a diagnostic message.
805 */
806#ifdef SH_DEBUG_SOCKET
807 fprintf (stderr, "Server: got message: %s\n", cmd);
808#endif
809
810 clt = strchr(cmd, ':');
811 if (clt != NULL)
812 {
813 *clt = '\0'; ++clt;
814 if (sl_strlen(cmd) >= SH_MAXMSGLEN)
815 {
816 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
817 _("Bad message format: command too long"),
818 _("sh_socket_read"));
[252]819 sl_close_fd(FIL__, __LINE__, talkfd);
[1]820 return -1;
821 }
822 else if (sl_strlen(clt) >= SH_MAXMSGLEN)
823 {
824 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
825 _("Bad message format: hostname too long"),
826 _("sh_socket_read"));
[252]827 sl_close_fd(FIL__, __LINE__, talkfd);
[1]828 return -1;
829 }
830 if (cmd[0] == 'L' && cmd[1] == 'I' &&
831 cmd[2] == 'S' && cmd[3] == 'T')
832 {
833 goto list_all;
834 }
835 else if (cmd[0] == 'P' && cmd[1] == 'R' &&
836 cmd[2] == 'O' && cmd[3] == 'B' && cmd[4] == 'E')
837 {
838 sh_socket_probe4reload();
839 cmd[0] = 'L'; cmd[1] = 'I'; cmd[2] = 'S'; cmd[3] = 'T';cmd[4] = '\0';
840 goto list_all;
841 }
842 sl_strlcpy (srvcmd->cmd, cmd, SH_MAXMSGLEN);
843 sl_strlcpy (srvcmd->clt, clt, SH_MAXMSGLEN);
844 --clt; *clt = ':';
845 }
846 else
847 {
848 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
849 _("Bad message format"),
850 _("sh_socket_read"));
[252]851 sl_close_fd(FIL__, __LINE__, talkfd);
[1]852 return -1;
853 }
854
855 /* Bounce the message back to the sender.
856 * 'name' is the receiver address; it has been been filled
857 * with the sender address in the recvfrom call
858 */
859#ifdef SH_DEBUG_SOCKET
860 fprintf (stderr, "Server: send message: %s to %s\n",
861 cmd, name.sun_path);
862#endif
863 /*
864 nbytes = sendto (pf_unix_fd, message, nbytes, 0,
865 (struct sockaddr *) & name, size);
866 */
867 nbytes = send (talkfd, cmd, strlen(cmd) + 1, 0);
[252]868 sl_close_fd(FIL__, __LINE__, talkfd);
[1]869 if (nbytes < 0)
870 {
871 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]872 sh_error_message (errno, errbuf, sizeof(errbuf)),
[1]873 _("sh_socket_read: send"));
874 return -1;
875 }
876#ifdef SH_DEBUG_SOCKET
877 fprintf (stderr, "Server: message is out\n");
878#endif
879 return nbytes;
880
881 list_all:
882#ifdef SH_DEBUG_SOCKET
883 fprintf (stderr, "Server: list all\n");
884#endif
885 if (cmd[4] == 'A' && cmd[5] == 'L' && cmd[6] == 'L')
886 {
887 list_cmd = runlist;
888 while (list_cmd)
889 {
[40]890 sl_snprintf(message, sizeof(message), _("SENT %8s %32s %s"),
[1]891 list_cmd->cmd, list_cmd->clt, list_cmd->cti);
892 /*
893 sl_strlcpy(message, _("DONE"), SH_MAXMSG);
894 sl_strlcat(message, " ", SH_MAXMSG);
895 sl_strlcat(message, list_cmd->cmd, SH_MAXMSG);
896 sl_strlcat(message, " ", SH_MAXMSG);
897 sl_strlcat(message, list_cmd->clt, SH_MAXMSG);
898 sl_strlcat(message, " ", SH_MAXMSG);
899 sl_strlcat(message, list_cmd->cti, SH_MAXMSG);
900 */
901 nbytes = send (talkfd, message, sl_strlen(message) + 1, 0);
902 if (nbytes < 0)
903 {
904 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]905 sh_error_message (errno, errbuf, sizeof(errbuf)),
[1]906 _("sh_socket_read: sendto"));
[252]907 sl_close_fd(FIL__, __LINE__, talkfd);
[1]908 return -1;
909 }
910 list_cmd = list_cmd->next;
911 }
912 }
913
914 list_cmd = cmdlist;
915 while (list_cmd)
916 {
[40]917 sl_snprintf(message, sizeof(message), _(">>>> %8s %32s %s"),
[1]918 list_cmd->cmd, list_cmd->clt, list_cmd->cti);
919 /*
920 sl_strlcpy(message, _(">>>>"), SH_MAXMSG);
921 sl_strlcat(message, " ", SH_MAXMSG);
922 sl_strlcat(message, list_cmd->cmd, SH_MAXMSG);
923 sl_strlcat(message, " ", SH_MAXMSG);
924 sl_strlcat(message, list_cmd->clt, SH_MAXMSG);
925 sl_strlcat(message, " ", SH_MAXMSG);
926 sl_strlcat(message, list_cmd->cti, SH_MAXMSG);
927 */
928 /*
929 nbytes = sendto (pf_unix_fd, message, sl_strlen(message) + 1, 0,
930 (struct sockaddr *) & name, size);
931 */
932 nbytes = send (talkfd, message, sl_strlen(message) + 1, 0);
933 if (nbytes < 0)
934 {
935 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]936 sh_error_message (errno, errbuf, sizeof(errbuf)),
[1]937 _("sh_socket_read: sendto"));
[252]938 sl_close_fd(FIL__, __LINE__, talkfd);
[1]939 return -1;
940 }
941 list_cmd = list_cmd->next;
942 }
943
944 /*
945 nbytes = sendto (pf_unix_fd, _("END"), 4, 0,
946 (struct sockaddr *) & name, size);
947 */
948 nbytes = send (talkfd, _("END"), 4, 0);
[252]949 sl_close_fd(FIL__, __LINE__, talkfd);
[1]950 return 0;
951}
952/* #if !defined(HAVE_CMSGCRED) || !defined(SO_PEERCRED) */
953/* #endif */
954
955static void sh_socket_add2list (struct socket_cmd * in)
956{
957 struct socket_cmd * new;
958
959 new = SH_ALLOC(sizeof(struct socket_cmd));
[22]960 sl_strlcpy (new->cmd, in->cmd, sizeof(new->cmd));
961 sl_strlcpy (new->clt, in->clt, sizeof(new->clt));
[132]962 (void) sh_unix_time(0, new->cti, sizeof(new->cti));
[1]963 new->next = cmdlist;
964 cmdlist = new;
965
966 return;
967}
968
969static void sh_socket_add2run (struct socket_cmd * in)
970{
971 struct socket_cmd * new = runlist;
972 char * client_name = in->clt;
973
974 while (new)
975 {
976 if (0 == sl_strcmp(new->clt, client_name))
977 {
[22]978 sl_strlcpy (new->cmd, in->cmd, sizeof(new->cmd));
979 sl_strlcpy (new->clt, in->clt, sizeof(new->clt));
[132]980 (void) sh_unix_time(0, new->cti, sizeof(new->cti));
[1]981 return;
982 }
983 new = new->next;
984 }
985
986 new = SH_ALLOC(sizeof(struct socket_cmd));
[22]987 sl_strlcpy (new->cmd, in->cmd, sizeof(new->cmd));
988 sl_strlcpy (new->clt, in->clt, sizeof(new->clt));
[132]989 (void) sh_unix_time(0, new->cti, sizeof(new->cti));
[1]990 new->next = runlist;
991 runlist = new;
992
993 return;
994}
995
996
997
998static void sh_socket_rm2list (const char * client_name)
999{
1000 struct socket_cmd * old = cmdlist;
1001 struct socket_cmd * new = cmdlist;
1002
1003 while (new)
1004 {
1005 if (0 == sl_strcmp(new->clt, client_name))
1006 {
1007 if ((new == cmdlist) && (new->next == NULL))
1008 {
1009 cmdlist = NULL;
1010 SH_FREE(new);
1011 return;
1012 }
1013 else if (new == cmdlist)
1014 {
1015 cmdlist = new->next;
1016 SH_FREE(new);
1017 return;
1018 }
1019 else
1020 {
1021 old->next = new->next;
1022 SH_FREE(new);
1023 return;
1024 }
1025 }
1026 old = new;
1027 new = new->next;
1028 }
1029 return;
1030}
1031
1032/* poll the socket to gather input
1033 */
1034int sh_socket_poll()
1035{
1036 struct socket_cmd cmd;
1037 char cancel_cmd[SH_MAXMSGLEN];
1038
1039 /* struct pollfd sh_poll = { pf_unix_fd, POLLIN, 0 }; */
1040
1041 if (pf_unix_fd < 0)
1042 {
1043 return 0;
1044 }
1045
[40]1046 sl_strlcpy(cancel_cmd, _("CANCEL"), sizeof(cancel_cmd));
[1]1047
1048 while (sh_socket_read (&cmd) > 0)
1049 {
1050 if (0 == sl_strcmp(cmd.cmd, cancel_cmd))
1051 {
1052 sh_socket_rm2list (cmd.clt);
1053 }
1054 else
1055 {
1056 sh_socket_rm2list (cmd.clt);
1057 sh_socket_add2list (&cmd);
1058 }
1059 }
1060 return 0;
1061}
1062
1063/* return the command associated with client_name
1064 and remove the corresponding entry
1065 */
1066char * sh_socket_check(const char * client_name)
1067{
1068 struct socket_cmd * old = cmdlist;
1069 struct socket_cmd * new = cmdlist;
1070 static char out[SH_MAXMSGLEN];
1071
1072 while (new)
1073 {
1074 if (0 == sl_strcmp(new->clt, client_name))
1075 {
[40]1076 sl_strlcpy(out, new->cmd, sizeof(out));
[1]1077 sh_socket_add2run (new);
1078 sh_socket_rm2list (client_name);
1079 return out;
1080 }
1081 old = new;
1082 new = new->next;
1083 }
1084 return NULL;
1085}
1086
1087/* #if defined (SH_WITH_SERVER)
1088 */
1089#endif
1090
Note: See TracBrowser for help on using the repository browser.