source: trunk/src/sh_socket.c@ 500

Last change on this file since 500 was 481, checked in by katerina, 9 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.