source: trunk/src/sh_socket.c @ 481

Last change on this file since 481 was 481, checked in by katerina, 6 years ago

Enhancements and fixes for tickets #374, #375, #376, #377, #378, and #379.

File size: 33.9 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 */
[270]25
[177]26#if defined(SH_WITH_SERVER) && defined(__linux__)
27#define _GNU_SOURCE
28#endif
[1]29
30#include <stdio.h>
31#include <stdlib.h>
32#include <stddef.h>
33#include <string.h>
34
[481]35#if TIME_WITH_SYS_TIME
36#include <sys/time.h>
37#include <time.h>
38#else
39#if HAVE_SYS_TIME_H
40#include <sys/time.h>
41#else
42#include <time.h>
43#endif
44#endif
45
[1]46#include "samhain.h"
47#include "sh_socket.h"
48#include "sh_error.h"
49#include "sh_unix.h"
50#include "sh_calls.h"
[481]51#include "sh_guid.h"
52#include "sh_fifo.h"
53#include "sh_utils.h"
[1]54
55#undef  FIL__
56#define FIL__  _("sh_socket.c")
57
58#if defined (SH_WITH_CLIENT)
59
60#include <signal.h>
61
[481]62typedef struct delta_tofetch {
63  char            uuid[SH_UUID_BUF];
64  time_t          last_time;
65  unsigned int    count;
66} SH_DELTA_DB;
67
68static SH_DELTA_DB * parse_entry(SH_DELTA_DB * db, const char * str)
69{
70  long last_time;
71  unsigned int count;
72  char buf[SH_UUID_BUF];
73  int res = sscanf(str, _("%u:%ld:%36s"), &count, &last_time, buf);
74  if (res == 3)
75    {
76      db->count = count;
77      db->last_time  = (time_t) last_time;
78      sl_strlcpy(db->uuid, buf, SH_UUID_BUF);
79      return db;
80    }
81  return NULL;
82}
83
84static char * unparse_entry(const SH_DELTA_DB * db, char * str, size_t len)
85{
86  int nbytes = sl_snprintf(str, len, _("%u:%ld:%s"), 
87                           db->count, (long) db->last_time, db->uuid);
88  if (nbytes < 0 || nbytes >= (int) len)
89    return NULL;
90  return str;
91}
92
93static SH_FIFO xfifo = SH_FIFO_INITIALIZER;
94
95int sh_socket_store_uuid(const char * cmd)
96{
97  char * p = sh_util_strdup(cmd);
98  char * q = strchr(cmd, ':');
99  char   entry[SH_BUFSIZE];
100  SH_DELTA_DB db;
101
102  if (!q) { SH_FREE(p); return -1; }
103
104  ++q;
105
106  if (0 != sh_uuid_check(q)) { SH_FREE(p); return -1; }
107
108  db.count = 0;
109  db.last_time = (time_t) 0;
110  sl_strlcpy(db.uuid, q, SH_UUID_BUF);
111  SH_FREE(p);
112
113  if (NULL != unparse_entry(&db, entry, sizeof(entry)))
114    {
115      sh_fifo_push(&xfifo, entry);
116      return 0;
117    }
118  return -1;
119}
120
121static unsigned int try_interval = 60;
122static unsigned int try_max = 2;
123
124int set_delta_retry_interval(const char * str)
125{
126  long val = strtol (str, (char **)NULL, 10);
127
128  if (val < 0 || val > INT_MAX)
129    return -1;
130  try_interval = (unsigned int) val;
131  return 0;
132}
133int set_delta_retry_count(const char * str)
134{
135  long val = strtol (str, (char **)NULL, 10);
136
137  if (val < 0 || val > INT_MAX)
138    return -1;
139  try_max = (unsigned int) val;
140  return 0;
141}
142
143char * sh_socket_get_uuid(int * errflag, unsigned int * count, time_t * last)
144{
145  char * entry = sh_fifo_pop(&xfifo);
146  char * uuid = NULL;
147
148  if (entry)
149    {
150      SH_DELTA_DB db;
151      time_t      now;
152     
153      if (NULL == parse_entry(&db, entry))
154        {
155          SH_FREE(entry);
156          sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, 0, MSG_E_SUBGEN,
157                          _("Bad entry in fifo"), 
158                          _("sh_socket_get_uuid"));
159          *errflag = -1;
160          return NULL;
161        }
162
163      now = time(NULL);
164
165      if ( (db.count > 0) && ((unsigned long)(now - db.last_time) < try_interval) )
166        {
167          sh_fifo_push_tail(&xfifo, entry);
168          SH_FREE(entry);
169          *errflag = -1;
170          return NULL;
171        }
172
173      SH_FREE(entry);
174      uuid   = sh_util_strdup(db.uuid);
175      *count = db.count;
176      *last  = db.last_time;
177    }
178
179  *errflag = 0;
180  return uuid;
181}
182
183int sh_socket_return_uuid (const char * uuid, unsigned int count, time_t last)
184{
185  (void) last;
186
187  if (count < try_max)
188    {
189      char   entry[SH_BUFSIZE];
190      SH_DELTA_DB db;
191      time_t now = time(NULL);
192
193      db.count     = count + 1;
194      db.last_time = now;
195      sl_strlcpy(db.uuid, uuid, SH_UUID_BUF);
196
197      if (NULL != unparse_entry(&db, entry, sizeof(entry)))
198        return sh_fifo_push_tail(&xfifo, entry); /* >0 for success */
199    }
200  return -1;
201}
202
[1]203void sh_socket_server_cmd(const char * srvcmd)
204{
205  SL_ENTER(_("sh_tools_server_cmd"));
206
207  if ((srvcmd == NULL) || (srvcmd[0] == '\0') || (sl_strlen(srvcmd) < 4))
208    {
209      SL_RET0(_("sh_socket_server_cmd"));
210    }
[481]211
212  if (0 == strncmp(srvcmd, _("STOP"), 4))
[1]213    {
214      TPT((0, FIL__, __LINE__, _("msg=<stop command from server>\n")));
215#ifdef SIGQUIT
216      raise(SIGQUIT);
217#else
[200]218      sig_terminate       = 1;
219      ++sig_raised;
[1]220#endif
221    } 
[481]222
223  else if (0 == strncmp(srvcmd, _("RELOAD"), 6))
[1]224    {
225      TPT((0, FIL__, __LINE__, _("msg=<reload command from server>\n")));
226#ifdef SIGHUP
227      raise(SIGHUP);
228#else
[200]229      sig_config_read_again = 1;
230      ++sig_raised;
[1]231#endif
232    }
[481]233
234  else if (0 == strncmp(srvcmd, _("DELTA:"), 6))
[200]235    {
[481]236      TPT((0, FIL__, __LINE__, _("msg=<delta load command from server>\n")));
237
238      if (sh_socket_store_uuid(srvcmd) == 0)
239        {
240          ++sh_load_delta_flag;
241          ++sig_raised;
242        }
243    }
244
245  else if (0 == strncmp(srvcmd, _("SCAN"), 4))
246    {
[200]247      TPT((0, FIL__, __LINE__, _("msg=<scan command from server>\n")));
[481]248      if (sh.flag.isdaemon == S_TRUE) 
[200]249        { 
250#ifdef SIGTTOU
251          raise(SIGTTOU);
252#else
253          sig_force_check = 1;
254          ++sig_raised;
255#endif
256        } 
257      else 
258        {
259          sig_force_check = 1;
260          ++sig_raised;
261        }
262    }
[481]263
264  /* Unknown command
265   */
[1]266  else
267    {
[481]268      sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, 0, MSG_E_SUBGEN,
[1]269                      srvcmd, 
270                      _("sh_socket_server_cmd"));
271    }
272  SL_RET0(_("sh_socket_server_cmd"));
273}
[481]274#endif  /* #if defined (SH_WITH_CLIENT) */
[1]275
276#if defined(SH_WITH_SERVER)
277#include <errno.h>
278
279#include <sys/types.h>
280#include <sys/stat.h>
281
282#include <unistd.h>
283#include <fcntl.h>
284
285#include <time.h>
286
287#include <sys/socket.h>
288#include <sys/un.h>
289
290
291#ifdef HAVE_SYS_UIO_H
292#include <sys/uio.h>
293#endif
294#if !defined(HAVE_GETPEEREID) && !defined(SO_PEERCRED)
295#if defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || defined(HAVE_STRUCT_SOCKCRED)
296#include <sys/param.h>
297#include <sys/ucred.h>
298#endif
299#endif
300
301
302int    pf_unix_fd  = -1;
303static char * sh_sockname = NULL;
[40]304static char   sh_sockpass_real[SOCKPASS_MAX+1];
[1]305
306struct socket_cmd {
307  char cmd[SH_MAXMSGLEN];
308  char clt[SH_MAXMSGLEN];
309  char cti[81];
310  struct socket_cmd * next;
311};
312
313#if !defined(O_NONBLOCK)
314#if defined(O_NDELAY)
315#define O_NONBLOCK  O_NDELAY
316#else
317#define O_NONBLOCK  0
318#endif
319#endif
320
321#if !defined(AF_FILE)
322#define AF_FILE AF_UNIX
323#endif
324
325static struct socket_cmd * cmdlist    = NULL;
326static struct socket_cmd * runlist    = NULL;
327
328static int    sh_socket_flaguse = S_FALSE;
329static int    sh_socket_flaguid = 0;
330
331#include "sh_utils.h"
332
[421]333/* The reload list stores information about
334 * reloads confirmed by clients (startup and/or
335 * runtime cinfiguration reloaded).
336 */
[1]337struct reload_cmd {
338  char          clt[SH_MAXMSGLEN];
339  time_t        cti;
340  struct reload_cmd * next;
341};
342static struct reload_cmd * reloadlist = NULL;
343
344void sh_socket_add2reload (const char * clt)
345{
346  struct reload_cmd  * new = reloadlist;
347
348  while (new)
349    {
350      if (0 == sl_strcmp(new->clt, clt))
351        {
[270]352#ifdef SH_DEBUG_SOCKET
353          fprintf(stderr, "add2reload: time reset for %s\n", clt);
354#endif
[1]355          sl_strlcpy (new->clt, clt, SH_MAXMSGLEN);
356          new->cti = time(NULL);
357          return;
358        }
359      new = new->next;
360    }
361
362  new = SH_ALLOC(sizeof(struct reload_cmd));
[270]363#ifdef SH_DEBUG_SOCKET
364  fprintf(stderr, "add2reload: time set for %s\n", clt);
365#endif
[1]366  sl_strlcpy (new->clt, clt, SH_MAXMSGLEN);
367  new->cti = time(NULL);
368
369  new->next    = reloadlist;
370  reloadlist   = new;
371
372  return;
373}
374
375#include "zAVLTree.h"
376#include "sh_html.h"
377#include "sh_tools.h"
378static void sh_socket_add2list (struct socket_cmd * in);
379
[272]380static void sh_socket_probe4reload (void)
[1]381{
382  struct reload_cmd  * new;
383  struct socket_cmd    cmd;
384
385  zAVLCursor avlcursor;
386  client_t * item;
387  extern zAVLTree * all_clients;
388
389  char     * file;
390  unsigned long dummy;
391  struct stat buf;
392
393  for (item = (client_t *) zAVLFirst(&avlcursor, all_clients); item;
394       item = (client_t *) zAVLNext(&avlcursor))
395    {
396      if (item->status_now != CLT_INACTIVE)
397        {
[421]398          int flag = 0;
399
[1]400          file = get_client_conf_file (item->hostname, &dummy);
401
402          if (0 == stat (file, &buf))
403            {
404              new = reloadlist;
405              while (new)
406                {
407                  if (0 == sl_strcmp(new->clt, item->hostname))
408                    {
[421]409                      flag = 1; /* Client is in list already */
410
[1]411                      if (buf.st_mtime > new->cti)
412                        {
413                          /* reload */
414                          sl_strlcpy(cmd.cmd, _("RELOAD"),    SH_MAXMSGLEN);
415                          sl_strlcpy(cmd.clt, item->hostname, SH_MAXMSGLEN);
416                          sh_socket_add2list (&cmd);
417                        }
418                      break;
419                    }
420                  new = new->next;
421                }
[421]422
423              if (flag == 0)
424                {
425                  /* client is active, but start message has been missed; reload
426                   */
427                  sl_strlcpy(cmd.cmd, _("RELOAD"),    SH_MAXMSGLEN);
428                  sl_strlcpy(cmd.clt, item->hostname, SH_MAXMSGLEN);
429                  sh_socket_add2list (&cmd);
430
431                  /* Add the client to the reload list and set
432                   * time to 0, since we don't know the startup time.
433                   */
434                  sh_socket_add2reload (item->hostname);
435                  new = reloadlist;
436                  while (new)
437                    {
438                      if (0 == sl_strcmp(new->clt, item->hostname))
439                        {
440                          new->cti = 0;
441                          break;
442                        }
443                      new = new->next;
444                    }
445                }
446            } /* if stat(file).. */
447        } /* if !CLT_INACTIVE */
448    } /* loop over clients */
[1]449  return;
450}
451
[170]452char * sh_get_sockpass (void)
[1]453{
[50]454  size_t j = 0;
455
[40]456  while (skey->sh_sockpass[2*j] != '\0' && j < sizeof(sh_sockpass_real))
[1]457    {
458      sh_sockpass_real[j] = skey->sh_sockpass[2*j];
459      ++j;
460    }
461  sh_sockpass_real[j] = '\0';
[50]462
[1]463  return sh_sockpass_real;
464}
465
[170]466void sh_set_sockpass (void)
[1]467{
468  int j;
469  for (j = 0; j < 15; ++j)
470    {
471      sh_sockpass_real[j] = '\0';
472    }
473}
474
[22]475int sh_socket_use (const char * c)
[1]476{
477  return sh_util_flagval(c, &sh_socket_flaguse);
478}
479
480int sh_socket_remove ()
481{
482  int retval = 0;
483#ifdef S_ISSOCK
484  struct stat sbuf;
485#endif
486
487  SL_ENTER(_("sh_socket_remove"));
488
489  if (NULL == sh_sockname)
490    {
491      SL_RETURN((retval),_("sh_socket_remove"));
492    }
493
494  if (0 != tf_trust_check (DEFAULT_PIDDIR, SL_YESPRIV))
495    {
496      SL_RETURN((-1),_("sh_socket_remove"));
497    }
498
499  if ( (retry_lstat(FIL__, __LINE__, sh_sockname, &sbuf) == 0) && 
500       (sbuf.st_uid == getuid()))
501    {
502#ifdef S_ISSOCK
503      if (S_ISSOCK (sbuf.st_mode))
504        {
505          retval = retry_aud_unlink (FIL__, __LINE__, sh_sockname);
506        }
507#else
508      retval = retry_aud_unlink (FIL__, __LINE__, sh_sockname);
509#endif
510    }
511  SL_RETURN((retval),_("sh_socket_remove"));
512}
513
514#if !defined(HAVE_GETPEEREID) && !defined(SO_PEERCRED) && !defined(HAVE_STRUCT_CMSGCRED) && !defined(HAVE_STRUCT_FCRED) && !(defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))
515
516#define NEED_PASSWORD_AUTH
517#endif
518
[22]519int sh_socket_uid (const char * c)
[1]520{
521  uid_t val = (uid_t) strtol (c, (char **)NULL, 10);
522  sh_socket_flaguid = val;
523#if defined(NEED_PASSWORD_AUTH)
524  sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, errno, MSG_E_SUBGEN,
525                  _("Config option SetSocketAllowUID not supported, use SetSocketPassword"), 
526                  _("sh_socket_uid"));
527#endif
528  return 0;
529}
530
[22]531int sh_socket_password (const char * c)
[1]532{
533#if defined(NEED_PASSWORD_AUTH)
534  int j, i;
535 
536#define LCG(n) ((69069 * n) & 0xffffffffUL)
537
538  i = sl_strlen(c);
[40]539  if (i > SOCKPASS_MAX) {
[1]540    return -1;
541  }
[40]542  for (j = 0; j < (2*SOCKPASS_MAX+1); ++j)
[1]543    {
544      skey->sh_sockpass[j] = '\0';
545    }
546  for (j = 0; j < i; ++j)
547    {
548      skey->sh_sockpass[2*j]     = c[j];
549      skey->sh_sockpass[(2*j)+1] = (LCG(c[j]) % 256);
550    }
551  return 0;
552#else
553  sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, errno, MSG_E_SUBGEN,
554                  _("Config option SetSocketPassword not supported, use SetSocketAllowUID"), 
555                  _("sh_socket_password"));
556  (void) c;
557  return 0;
558#endif
559}
560
561
562int sh_socket_open_int ()
563{
564  struct sockaddr_un name;
565  size_t size;
566  int    flags;
567#if defined(SO_PASSCRED)
568  socklen_t    optval = 1;
569#endif
570  struct stat buf;
[132]571  char errbuf[SH_ERRBUF_SIZE];
[1]572 
573  SL_ENTER(_("sh_socket_open_int"));
574
575  if (sh_socket_flaguse == S_FALSE)
576    {
577      SL_RETURN(0, _("sh_socket_open_int"));
578    }
579
580  if (sh_sockname == NULL)
581    {
582      size = sl_strlen(DEFAULT_PIDDIR) + 1 + sl_strlen(SH_INSTALL_NAME) + 6;
[34]583      sh_sockname = SH_ALLOC(size); /* compile-time constant */
[1]584      sl_strlcpy(sh_sockname, DEFAULT_PIDDIR, size);
585      sl_strlcat(sh_sockname, "/", size);
586      sl_strlcat(sh_sockname, SH_INSTALL_NAME, size);
587      sl_strlcat(sh_sockname, _(".sock"), size);
588    }
589
[265]590  if (0 != sh_unix_check_piddir (sh_sockname))
591    {
592      SH_FREE(sh_sockname);
593      SL_RETURN((-1),_("sh_socket_open_int"));
594    }
[264]595
[1]596  pf_unix_fd = socket (PF_UNIX, SOCK_STREAM, 0);
597  if ((pf_unix_fd) < 0)
598    {
599      sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]600                       sh_error_message (errno, errbuf, sizeof(errbuf)), 
[1]601                       _("sh_socket_open_int: socket"));
602      SL_RETURN( (-1), _("sh_socket_open_int"));
603    }
604
605  if (sizeof(name.sun_path) < (1 + sl_strlen(sh_sockname)))
606    {
[252]607      sl_close_fd(FIL__, __LINE__, pf_unix_fd); pf_unix_fd = -1;
[1]608      sh_error_handle ((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
609                       _("PID dir path too long"), 
610                       _("sh_socket_open_int"));
611      SL_RETURN( (-1), _("sh_socket_open_int"));
612    }
613
614  name.sun_family = AF_FILE;
[22]615  sl_strlcpy (name.sun_path, sh_sockname, sizeof(name.sun_path));
[1]616
617  size = (offsetof (struct sockaddr_un, sun_path)
618          + strlen (name.sun_path) + 1);
619
620  flags = retry_lstat (FIL__, __LINE__, sh_sockname, &buf);
621
622  if (flags == 0)
623    {
624      sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, -1, MSG_E_SUBGEN,
625                      _("Socket exists, trying to unlink it"), 
626                      _("sh_socket_open_int"));
627      if (sh_socket_remove() < 0) 
628        {
[252]629          sl_close_fd(FIL__, __LINE__, pf_unix_fd); pf_unix_fd = -1;
[1]630          sh_error_handle ((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
631                           _("Unlink of socket failed, maybe path not trusted"), 
632                           _("sh_socket_open_int"));
633          SL_RETURN( (-1), _("sh_socket_open_int"));
634        }
635    }
636
637  if (bind ((pf_unix_fd), (struct sockaddr *) &name, size) < 0)
638    {
[252]639      sl_close_fd(FIL__, __LINE__, pf_unix_fd); pf_unix_fd = -1;
[1]640      sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]641                       sh_error_message (errno, errbuf, sizeof(errbuf)), 
[1]642                       _("sh_socket_open_int: bind"));
643      SL_RETURN( (-1), _("sh_socket_open_int"));
644    }
645
646#ifdef SO_PASSCRED
647  if (0 != setsockopt(pf_unix_fd, SOL_SOCKET, SO_PASSCRED, 
648                      &optval, sizeof(optval)))
649    {
[252]650      sl_close_fd(FIL__, __LINE__, pf_unix_fd); pf_unix_fd = -1;
[1]651      sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]652                       sh_error_message (errno, errbuf, sizeof(errbuf)), 
[1]653                       _("sh_socket_open_int: setsockopt"));
654      SL_RETURN( (-1), _("sh_socket_open_int"));
655    }
656#endif
657
658  flags = fcntl((pf_unix_fd), F_GETFL);
659  if (flags < 0)
660    {
[252]661      sl_close_fd(FIL__, __LINE__, pf_unix_fd); pf_unix_fd = -1;
[1]662      sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]663                       sh_error_message (errno, errbuf, sizeof(errbuf)), 
[1]664                       _("sh_socket_open_int: fcntl1"));
665      SL_RETURN( (-1), _("sh_socket_open_int"));
666    }
667
668  flags = fcntl((pf_unix_fd), F_SETFL, flags|O_NONBLOCK);
669  if (flags < 0)
670    {
[252]671      sl_close_fd(FIL__, __LINE__, pf_unix_fd); pf_unix_fd = -1;
[1]672      sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]673                      sh_error_message (errno, errbuf, sizeof(errbuf)), 
[1]674                      _("sh_socket_open_int: fcntl2"));
675      SL_RETURN( (-1), _("sh_socket_open_int"));
676    }
677
678  if (0 != listen(pf_unix_fd, 5))
679    {
[252]680      sl_close_fd(FIL__, __LINE__, pf_unix_fd); pf_unix_fd = -1;
[1]681      sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]682                       sh_error_message (errno, errbuf, sizeof(errbuf)), 
[1]683                       _("sh_socket_open_int: listen"));
684      SL_RETURN( (-1), _("sh_socket_open_int"));
685    }
686  SL_RETURN( (0), _("sh_socket_open_int"));
687}
688
689
690/*
691 * Parts of the socket authentication code is copied from PostgreSQL:
692 *
693 * PostgreSQL Database Management System
694 * (formerly known as Postgres, then as Postgres95)
695 *
696 * Portions Copyright (c) 1996-2001, The PostgreSQL Global Development Group
697 *
698 * Portions Copyright (c) 1994, The Regents of the University of California
699 *
700 * Permission to use, copy, modify, and distribute this software and its
701 * documentation for any purpose, without fee, and without a written agreement
702 * is hereby granted, provided that the above copyright notice and this
703 * paragraph and the following two paragraphs appear in all copies.
704 *
705 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
706 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
707 * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
708 * DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
709 * POSSIBILITY OF SUCH DAMAGE.
710 *
711 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
712 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
713 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
714 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO
715 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
716 */
[481]717
718static int receive_message(int talkfd, struct msghdr * msg, size_t message_size)
[1]719{
[481]720  unsigned int retry = 0;
[1]721  int nbytes;
[481]722  char * message = msg->msg_iov->iov_base;
[132]723  char errbuf[SH_ERRBUF_SIZE];
[1]724
[295]725  do {
[481]726    nbytes = recvmsg (talkfd, msg, 0);
[1]727    if ((nbytes < 0) && (errno != EAGAIN))
728      {
729        sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]730                        sh_error_message (errno, errbuf, sizeof(errbuf)),
[1]731                        _("sh_socket_read: recvmsg"));
[252]732        sl_close_fd(FIL__, __LINE__, talkfd);   
[1]733        return -1;
734      }
735    else if (nbytes < 0)
736      {
737        ++retry;
[315]738        retry_msleep(0, 10);
[1]739      }
740  } while ((nbytes < 0) && (retry < 3));
741
[40]742  /* msg.msg_iov.iov_base, filled by recvmsg
743   */
[481]744  message[message_size-1] = '\0';
[1]745
746  if (nbytes < 0)
747    {
748      if (errno == EAGAIN)
749        {
750          /* no data */
[481]751          sh_error_handle(SH_ERR_ALL, FIL__, __LINE__, errno, MSG_E_SUBGEN,
752                          sh_error_message (errno, errbuf, sizeof(errbuf)), 
753                          _("sh_socket_read: recvfrom"));
[252]754          sl_close_fd(FIL__, __LINE__, talkfd);
[1]755          return 0;
756        }
757      sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]758                      sh_error_message (errno, errbuf, sizeof(errbuf)), 
[1]759                      _("sh_socket_read: recvfrom"));
[252]760      sl_close_fd(FIL__, __LINE__, talkfd);
[1]761      return -1;
762    }
[481]763  return 0;
764}
[1]765
766#if defined(HAVE_GETPEEREID)
[481]767
768static int get_peer_uid(int talkfd)
769{
770  uid_t peer_uid;
771  gid_t peer_gid;
772  char errbuf[SH_ERRBUF_SIZE];
773
[1]774  if (0 != getpeereid(talkfd, &peer_uid, &peer_gid))
775    {
776      sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]777                      sh_error_message (errno, errbuf, sizeof(errbuf)), 
[1]778                      _("sh_socket_read: getpeereid"));
[252]779      sl_close_fd(FIL__, __LINE__, talkfd);
[1]780      return -1;
781    }
[481]782  return peer_uid;
783}
784
785#elif defined(SO_PEERCRED)
786
787static int get_peer_uid(int talkfd)
788{
789  char errbuf[SH_ERRBUF_SIZE];
790  struct ucred cr;
791#ifdef HAVE_SOCKLEN_T
792  socklen_t cl = sizeof(cr);
793#else
794  int       cl = sizeof(cr);
795#endif
796
[1]797  if (0 != getsockopt(talkfd, SOL_SOCKET, SO_PEERCRED, &cr, &cl))
798    {
799      sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]800                      sh_error_message (errno, errbuf, sizeof(errbuf)), 
[1]801                      _("sh_socket_read: getsockopt"));
[252]802      sl_close_fd(FIL__, __LINE__, talkfd);
[1]803      return -1;
804    }
[481]805  return cr.uid;
806}
[118]807
[481]808#endif
[118]809
[481]810#if defined(NEED_PASSWORD_AUTH)
811char * check_password(char * message, int * client_uid, int talkfd)
812{
813  char * cmd = NULL;
814  char * eopw = NULL;
815  char * goodpassword = NULL;
[118]816
[1]817  goodpassword = sh_get_sockpass();
818  eopw = strchr(message, '@');
819  if (eopw) 
820    *eopw = '\0';
[40]821  /*
822   * message is null-terminated and >> goodpassword
823   */
824  if (0 == strcmp(goodpassword, message) &&
825      strlen(goodpassword) < (sizeof(message)/2))
[1]826    {
[481]827      *client_uid = sh_socket_flaguid;
[1]828      cmd = &message[strlen(goodpassword)+1];
829      sh_set_sockpass();
830    }
831  else
832    {
833      sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
834                      _("Bad password"), 
835                      _("sh_socket_read"));
836      sh_set_sockpass();
[252]837      sl_close_fd(FIL__, __LINE__, talkfd);
[481]838      return NULL;
839    }
840  return cmd;
841}
842#endif
843
844static int list_all (int talkfd, char * cmd);
845static int process_message(int talkfd, char * cmd, struct socket_cmd * srvcmd);
846
847static 
848int sh_socket_read (struct socket_cmd * srvcmd)
849{
850  char message[SH_MAXMSG];
851  struct sockaddr_un name;
852  ACCEPT_TYPE_ARG3 size = sizeof(name);
853  int talkfd;
854  char * cmd = NULL;
855  int  client_uid = -1;
856  char errbuf[SH_ERRBUF_SIZE];
857  struct msghdr msg;
858  struct iovec iov;
859  int status;
860
861  if (pf_unix_fd  < 0)
862    return 0;
863
864  iov.iov_base = (char *) &message;
865  iov.iov_len  = sizeof(message);
866
867  memset (&msg, 0, sizeof (msg));
868  msg.msg_iov = &iov;
869  msg.msg_iovlen = 1;
870
871  /* the socket is non-blocking
872   * 'name' is the address of the sender socket
873   */
874  do {
875    talkfd = accept(pf_unix_fd, (struct sockaddr *) &name, &size);
876  } while (talkfd < 0 && errno == EINTR);
877
878  if ((talkfd < 0) && (errno == EAGAIN))
879    {
880      return 0;
881    }
882  else if (talkfd < 0)
883    {
884      sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
885                      sh_error_message (errno, errbuf, sizeof(errbuf)), 
886                      _("sh_socket_read: accept"));
[1]887      return -1;
888    }
[481]889
890  if (receive_message(talkfd, &msg, sizeof(message)) < 0)
891    return -1;
892
893  /* Authenticate request by peer uid or password.
894   */
895#if defined(HAVE_GETPEEREID)
896  client_uid = get_peer_uid(talkfd);
897  cmd = message;
898
899#elif defined(SO_PEERCRED)
900  client_uid = get_peer_uid(talkfd);
901  cmd = message;
902
903#elif defined(NEED_PASSWORD_AUTH)
904  cmd = check_password(message, &client_uid, talkfd);
905
[1]906#else
907  sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
908                  _("Socket credentials not supported on this OS"), 
909                  _("sh_socket_read"));
[252]910  sl_close_fd(FIL__, __LINE__, talkfd);
[1]911  return -1;
912#endif
913
914  if (client_uid != sh_socket_flaguid)
915    {
916      sh_error_handle((-1), FIL__, __LINE__, client_uid, MSG_E_SUBGEN,
917                      _("client does not have required uid"), 
918                      _("sh_socket_read: getsockopt"));
[252]919      sl_close_fd(FIL__, __LINE__, talkfd);
[1]920      return -1;
921    }
922
[481]923  status = process_message(talkfd, cmd, srvcmd);
[1]924
[481]925  sl_close_fd(FIL__, __LINE__, talkfd);
926  return status;
927}
[1]928
[481]929static int check_valid_command(const char * str)
930{
931  unsigned int i = 0;
932  char * commands[] = { N_("DELTA"),  N_("RELOAD"),  N_("STOP"), N_("SCAN"),
933                        N_("CANCEL"), N_("LISTALL"), N_("LIST"), N_("PROBE"), NULL };
934
935  while (commands[i])
936    {
937      if (0 == strcmp(_(commands[i]), str))
938        {
939          return 0;
940        }
941      ++i;
942    }
943  return -1;
944}
945
946static int send_reply (int fd, char * msg)
947{
948  int nbytes = send (fd, msg, strlen(msg) + 1, 0);
949
950  if (nbytes < 0)
951    {
952      char errbuf[SH_ERRBUF_SIZE];
953      sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
954                      sh_error_message (errno, errbuf, sizeof(errbuf)), 
955                      _("send_reply"));
956      return -1;
957    }
958
959  return nbytes;
960}
961
962static int process_message(int talkfd, char * cmd, struct socket_cmd * srvcmd)
963{
964  int nbytes;
965  char error_type[SH_ERRBUF_SIZE] = { '\0' };
966  char * clt  = (cmd) ? strchr(cmd, ':') : NULL;
967
968  if (clt && 0 == strncmp(cmd, _("DELTA:"), 6))
969    {
970      /* DELTA:uuid:hostname
971       */
972      char * uuid = clt;
973     
974      *uuid = '\0'; ++uuid;
975      clt = strchr(uuid, ':');
976      if (clt) { *clt = '\0'; ++clt; }
977     
978      if (sh_uuid_check(uuid) < 0)
979        {
980          sl_strlcpy(error_type, _("!E:uuid-format:"), sizeof(error_type));
981          sl_strlcat(error_type, uuid, sizeof(error_type));
982          clt = NULL;
983        }
984     
985      --uuid; *uuid = ':';
986    }
987  else if (clt && *clt == ':')
988    { 
989      *clt = '\0'; ++clt; 
990      if (check_valid_command(cmd) < 0)
991        {
992          sl_strlcpy(error_type, _("!E:cmd-invalid:"), sizeof(error_type));
993          sl_strlcat(error_type, cmd, sizeof(error_type));
994          clt = NULL;
995        }
996    }
997   
[1]998  if (clt != NULL) 
999    {
1000      if (sl_strlen(cmd) >= SH_MAXMSGLEN)
1001        {
1002          sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
1003                          _("Bad message format: command too long"), 
1004                          _("sh_socket_read"));
[481]1005          sl_strlcpy(error_type, _("!E:cmd-toolong"), sizeof(error_type));
1006          send_reply(talkfd, error_type);
[1]1007          return -1;
1008        }
1009      else if (sl_strlen(clt) >= SH_MAXMSGLEN)
1010        {
1011          sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
1012                          _("Bad message format: hostname too long"), 
1013                          _("sh_socket_read"));
[481]1014          sl_strlcpy(error_type, _("!E:hostname-toolong"), sizeof(error_type));
1015          send_reply(talkfd, error_type);
[1]1016          return -1;
1017        }
[481]1018
1019      if (0 == strncmp(cmd, _("LIST"), 4))
1020        return list_all(talkfd, cmd);
1021      else if (0 == strncmp(cmd, _("PROBE"), 4))
[1]1022        {
1023          sh_socket_probe4reload();
[481]1024          sl_strlcpy(cmd, _("LIST"), 5);
1025          return list_all(talkfd, cmd);
[1]1026        }
[481]1027
[1]1028      sl_strlcpy (srvcmd->cmd, cmd, SH_MAXMSGLEN);
1029      sl_strlcpy (srvcmd->clt, clt, SH_MAXMSGLEN);
1030      --clt; *clt = ':';
1031    }
1032  else
1033    {
1034      sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
1035                      _("Bad message format"), 
1036                      _("sh_socket_read"));
[481]1037      if (error_type[0] == '\0')
1038        sl_strlcpy(error_type, _("!E:message-format"), sizeof(error_type));
1039      send_reply(talkfd, error_type);
[1]1040      return -1;
1041    }
1042
1043  /* Bounce the message back to the sender.
1044   */
[481]1045  nbytes = send_reply(talkfd, cmd);
1046
[1]1047  return nbytes;
[481]1048}
[1]1049
[481]1050static int list_all (int talkfd, char * cmd)
1051{
1052  int nbytes;
1053  struct socket_cmd * list_cmd;
1054  char message[SH_MAXMSG];
1055  char errbuf[SH_ERRBUF_SIZE];
1056
1057  if (0 == strncmp(cmd, _("LISTALL"), 7))
[1]1058    {
1059      list_cmd = runlist;
1060      while (list_cmd)
1061        {
[481]1062          sl_snprintf(message, sizeof(message), _("SENT  %42s  %32s  %s"),
[1]1063                      list_cmd->cmd, list_cmd->clt, list_cmd->cti);
[481]1064
[1]1065          nbytes = send (talkfd, message, sl_strlen(message) + 1, 0);
1066          if (nbytes < 0)
1067            {
1068              sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]1069                              sh_error_message (errno, errbuf, sizeof(errbuf)), 
[1]1070                              _("sh_socket_read: sendto"));
1071              return -1;
1072            }
1073          list_cmd = list_cmd->next;
1074        }
1075    }
1076
1077  list_cmd = cmdlist;
1078  while (list_cmd)
1079    {
[481]1080      sl_snprintf(message, sizeof(message), _(">>>>  %42s  %32s  %s"),
[1]1081                  list_cmd->cmd, list_cmd->clt, list_cmd->cti);
[481]1082
[1]1083      nbytes = send (talkfd, message, sl_strlen(message) + 1, 0);
1084      if (nbytes < 0)
1085        {
1086          sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
[132]1087                          sh_error_message (errno, errbuf, sizeof(errbuf)), 
[1]1088                          _("sh_socket_read: sendto"));
1089          return -1;
1090        }
1091      list_cmd = list_cmd->next;
1092    }
1093
[481]1094  send (talkfd, _("END"), 4, 0);
[1]1095  return 0;
1096}
1097
1098static void sh_socket_add2list (struct socket_cmd * in)
1099{
[481]1100  struct socket_cmd  * new  = cmdlist;
1101  struct socket_cmd  * last = cmdlist;
[1]1102
[481]1103  while (new)
1104    {
1105      /* Only skip identical commands.
1106       */
1107      if (0 == sl_strcmp(new->clt,  in->clt) &&
1108          0 == sl_strcmp(new->cmd,  in->cmd))
1109        {
1110          (void) sh_unix_time(0, new->cti, sizeof(new->cti));
1111          return;
1112        }
1113      new = new->next;
1114    }
1115
[1]1116  new = SH_ALLOC(sizeof(struct socket_cmd));
[481]1117  sl_strlcpy (new->cmd,  in->cmd,  sizeof(new->cmd));
1118  sl_strlcpy (new->clt,  in->clt,  sizeof(new->clt));
[132]1119  (void) sh_unix_time(0, new->cti, sizeof(new->cti));
[481]1120  new->next  = NULL;
[1]1121
[481]1122  if (last)
1123    {
1124      while (last->next) { last = last->next; }
1125      last->next = new;
1126    }
1127  else
1128    {
1129      cmdlist = new;
1130    }
[1]1131  return;
1132}
1133
1134static void sh_socket_add2run (struct socket_cmd * in)
1135{
[481]1136  struct socket_cmd  * new  = runlist;
1137  struct socket_cmd  * last = runlist;
[1]1138
1139  while (new)
1140    {
[481]1141      /* Only skip identical commands. First 5 will
1142       * make all 'DELTA' identical.
1143       */
1144      if (0 == sl_strcmp(new->clt,  in->clt) &&
1145          0 == sl_strncmp(new->cmd,  in->cmd, 5))
[1]1146        {
[481]1147          sl_strlcpy (new->cmd,  in->cmd,  sizeof(new->cmd));
[132]1148          (void) sh_unix_time(0, new->cti, sizeof(new->cti));
[1]1149          return;
1150        }
1151      new = new->next;
1152    }
1153
1154  new = SH_ALLOC(sizeof(struct socket_cmd));
[481]1155  sl_strlcpy (new->cmd,  in->cmd,  sizeof(new->cmd));
1156  sl_strlcpy (new->clt,  in->clt,  sizeof(new->clt));
[270]1157#ifdef SH_DEBUG_SOCKET
1158  fprintf(stderr, "add2run: time set for %s\n", new->clt);
1159#endif
[132]1160  (void) sh_unix_time(0, new->cti, sizeof(new->cti));
[481]1161  new->next  = NULL;
[1]1162
[481]1163  if (last)
1164    {
1165      while (last->next) { last = last->next; }
1166      last->next = new;
1167    }
1168  else
1169    {
1170      runlist = new;
1171    }
[1]1172  return;
1173}
1174
1175
1176
[481]1177static void sh_socket_rm2list (const char * client_name, int remove_all)
[1]1178{
1179  struct socket_cmd * old = cmdlist;
1180  struct socket_cmd * new = cmdlist;
1181 
1182  while (new)
1183    {
1184      if (0 == sl_strcmp(new->clt, client_name))
1185        {
1186          if ((new == cmdlist) && (new->next == NULL))
1187            {
[481]1188              /* There is only one entry */
[1]1189              cmdlist = NULL;
1190              SH_FREE(new);
1191              return;
1192            }
1193          else if (new == cmdlist)
1194            {
[481]1195              /* first entry: new = old = cmdlist */
[1]1196              cmdlist = new->next;
1197              SH_FREE(new);
[481]1198              if (remove_all == S_FALSE)
1199                return;
1200              old = cmdlist;
1201              new = cmdlist;
1202              continue;
[1]1203            }
1204          else
1205            {
1206              old->next = new->next;
1207              SH_FREE(new);
[481]1208              if (remove_all == S_FALSE)
1209                return;
1210              new = old;
[1]1211            }
1212        }
1213      old = new;
1214      new = new->next;
1215    }
1216  return;
1217}
1218
1219/* poll the socket to gather input
1220 */
1221int sh_socket_poll()
1222{
1223  struct socket_cmd   cmd;
1224  char   cancel_cmd[SH_MAXMSGLEN];
1225 
1226  /* struct pollfd sh_poll = { pf_unix_fd, POLLIN, 0 }; */
1227
1228  if (pf_unix_fd  < 0)
[481]1229    return 0;
[1]1230
[40]1231  sl_strlcpy(cancel_cmd, _("CANCEL"), sizeof(cancel_cmd)); 
[1]1232
1233  while (sh_socket_read (&cmd) > 0)
1234    {
1235      if (0 == sl_strcmp(cmd.cmd, cancel_cmd))
[481]1236        sh_socket_rm2list  (cmd.clt, S_TRUE);
[1]1237      else
[481]1238        sh_socket_add2list (&cmd);
[1]1239    }
1240  return 0;
1241}
1242
1243/* return the command associated with client_name
1244   and remove the corresponding entry
1245 */
1246char * sh_socket_check(const char * client_name)
1247{
1248  struct socket_cmd * new = cmdlist;
1249  static char         out[SH_MAXMSGLEN];
1250
1251  while (new)
1252    {
1253      if (0 == sl_strcmp(new->clt, client_name))
1254        {
[481]1255          sl_strlcpy(out,  new->cmd,  sizeof(out));
[1]1256          sh_socket_add2run (new);
[481]1257          sh_socket_rm2list (client_name, S_FALSE);
[1]1258          return out;
1259        }
1260      new = new->next;
1261    }
1262  return NULL;
1263}
1264/* #if defined (SH_WITH_SERVER)
1265 */
1266#endif
1267
[481]1268
1269#ifdef SH_CUTEST
1270#include "CuTest.h"
1271
1272void Test_cmdlist (CuTest *tc) {
1273
1274#if defined (SH_WITH_SERVER)
1275  struct socket_cmd cmd;
1276  char * p;
1277
1278  sl_strlcpy(cmd.clt, "one", sizeof(cmd.clt));
1279  sl_strlcpy(cmd.cmd, "RELOAD", sizeof(cmd.cmd));
1280
1281  sh_socket_add2list (&cmd);
1282  p = sh_socket_check("one");
1283  CuAssertPtrNotNull(tc, p);
1284  CuAssertStrEquals(tc, "RELOAD", p);
1285
1286  p = sh_socket_check("one");
1287  CuAssertPtrEquals(tc, NULL, p);
1288
1289  sh_socket_add2list (&cmd);
1290  sl_strlcpy(cmd.cmd, "STOP",   sizeof(cmd.cmd));
1291  sh_socket_add2list (&cmd);
1292
1293  sl_strlcpy(cmd.clt, "two", sizeof(cmd.clt));
1294  sl_strlcpy(cmd.cmd, "STOP", sizeof(cmd.cmd));
1295  sh_socket_add2list (&cmd);
1296  sl_strlcpy(cmd.clt, "three", sizeof(cmd.clt));
1297  sl_strlcpy(cmd.cmd, "STOP", sizeof(cmd.cmd));
1298  sh_socket_add2list (&cmd);
1299
1300  sl_strlcpy(cmd.clt, "one", sizeof(cmd.clt));
1301  sl_strlcpy(cmd.cmd, "DELTA",   sizeof(cmd.cmd));
1302  sh_socket_add2list (&cmd);
1303
1304  p = sh_socket_check("one");
1305  CuAssertPtrNotNull(tc, p);
1306  CuAssertStrEquals(tc, "RELOAD", p);
1307
1308  sl_strlcpy(cmd.clt, "two", sizeof(cmd.clt));
1309  sl_strlcpy(cmd.cmd, "RELOAD", sizeof(cmd.cmd));
1310  sh_socket_add2list (&cmd);
1311  sl_strlcpy(cmd.clt, "three", sizeof(cmd.clt));
1312  sl_strlcpy(cmd.cmd, "RELOAD", sizeof(cmd.cmd));
1313  sh_socket_add2list (&cmd);
1314
1315  p = sh_socket_check("one");
1316  CuAssertPtrNotNull(tc, p);
1317  CuAssertStrEquals(tc, "STOP", p);
1318  p = sh_socket_check("one");
1319  CuAssertPtrNotNull(tc, p);
1320  CuAssertStrEquals(tc, "DELTA", p);
1321  p = sh_socket_check("one");
1322  CuAssertPtrEquals(tc, NULL, p);
1323
1324  /* Test removal in correct order */
1325  sl_strlcpy(cmd.clt, "one", sizeof(cmd.clt));
1326  sl_strlcpy(cmd.cmd, "RELOAD", sizeof(cmd.cmd));
1327  sh_socket_add2list (&cmd);
1328  sl_strlcpy(cmd.cmd, "STOP",   sizeof(cmd.cmd));
1329  sh_socket_add2list (&cmd);
1330  sl_strlcpy(cmd.cmd, "DELTA",  sizeof(cmd.cmd));
1331  sh_socket_add2list (&cmd);
1332  sl_strlcpy(cmd.cmd, "FOOBAR", sizeof(cmd.cmd));
1333  sh_socket_add2list (&cmd);
1334 
1335  sh_socket_rm2list ("one", S_FALSE);
1336
1337  p = sh_socket_check("one");
1338  CuAssertPtrNotNull(tc, p);
1339  CuAssertStrEquals(tc, "STOP", p);
1340
1341  sh_socket_rm2list ("one", S_FALSE);
1342 
1343  p = sh_socket_check("one");
1344  CuAssertPtrNotNull(tc, p);
1345  CuAssertStrEquals(tc, "FOOBAR", p);
1346
1347  p = sh_socket_check("one");
1348  CuAssertPtrEquals(tc, NULL, p);
1349
1350  sl_strlcpy(cmd.clt, "one", sizeof(cmd.clt));
1351  sl_strlcpy(cmd.cmd, "RELOAD", sizeof(cmd.cmd));
1352  sh_socket_add2list (&cmd);
1353  sl_strlcpy(cmd.cmd, "STOP",   sizeof(cmd.cmd));
1354  sh_socket_add2list (&cmd);
1355
1356  sl_strlcpy(cmd.clt, "two", sizeof(cmd.clt));
1357  sl_strlcpy(cmd.cmd, "RELOAD", sizeof(cmd.cmd));
1358  sh_socket_add2list (&cmd);
1359  sl_strlcpy(cmd.clt, "three", sizeof(cmd.clt));
1360  sl_strlcpy(cmd.cmd, "RELOAD", sizeof(cmd.cmd));
1361  sh_socket_add2list (&cmd);
1362
1363  sl_strlcpy(cmd.clt, "one", sizeof(cmd.clt));
1364  sl_strlcpy(cmd.cmd, "DELTA",  sizeof(cmd.cmd));
1365  sh_socket_add2list (&cmd);
1366  sl_strlcpy(cmd.cmd, "FOOBAR", sizeof(cmd.cmd));
1367  sh_socket_add2list (&cmd);
1368
1369  sh_socket_rm2list ("one", S_TRUE);
1370  p = sh_socket_check("one");
1371  CuAssertPtrEquals(tc, NULL, p);
1372
1373  p = sh_socket_check("two");
1374  CuAssertPtrNotNull(tc, p);
1375  CuAssertStrEquals(tc, "STOP", p);
1376  p = sh_socket_check("two");
1377  CuAssertPtrNotNull(tc, p);
1378  CuAssertStrEquals(tc, "RELOAD", p);
1379  p = sh_socket_check("two");
1380  CuAssertPtrEquals(tc, NULL, p);
1381
1382  p = sh_socket_check("three");
1383  CuAssertPtrNotNull(tc, p);
1384  CuAssertStrEquals(tc, "STOP", p);
1385  p = sh_socket_check("three");
1386  CuAssertPtrNotNull(tc, p);
1387  CuAssertStrEquals(tc, "RELOAD", p);
1388  p = sh_socket_check("three");
1389  CuAssertPtrEquals(tc, NULL, p);
1390
1391  p = sh_socket_check("four");
1392  CuAssertPtrEquals(tc, NULL, p);
1393#else
1394  (void) tc;
1395#endif
1396}
1397
1398#endif  /* #ifdef SH_CUTEST */
1399
1400
1401
Note: See TracBrowser for help on using the repository browser.