source: trunk/src/sh_socket.c @ 421

Last change on this file since 421 was 421, checked in by katerina, 9 years ago

Fix for ticket #325 (samhainctl probe command).

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