source: trunk/src/sh_socket.c@ 113

Last change on this file since 113 was 50, checked in by rainer, 18 years ago

Fix for the fix in revision 48. Released as 2.2.1c

File size: 25.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#include <stdio.h>
27#include <stdlib.h>
28#include <stddef.h>
29#include <string.h>
30
31#include "samhain.h"
32#include "sh_socket.h"
33#include "sh_error.h"
34#include "sh_unix.h"
35#include "sh_calls.h"
36
37#undef FIL__
38#define FIL__ _("sh_socket.c")
39
40#if defined (SH_WITH_CLIENT)
41
42#include <signal.h>
43
44void sh_socket_server_cmd(const char * srvcmd)
45{
46 SL_ENTER(_("sh_tools_server_cmd"));
47
48 if ((srvcmd == NULL) || (srvcmd[0] == '\0') || (sl_strlen(srvcmd) < 4))
49 {
50 SL_RET0(_("sh_socket_server_cmd"));
51 }
52 if ((srvcmd[0] == 'S') || (srvcmd[1] == 'T') ||
53 (srvcmd[2] == 'O') || (srvcmd[3] == 'P'))
54 {
55 TPT((0, FIL__, __LINE__, _("msg=<stop command from server>\n")));
56#ifdef SIGQUIT
57 raise(SIGQUIT);
58#else
59 TPT((0, FIL__, __LINE__, _("msg=<sigquit not defined>\n")));
60#endif
61 }
62 else if ((srvcmd[0] == 'R') || (srvcmd[1] == 'E') ||
63 (srvcmd[2] == 'L') || (srvcmd[3] == 'O') ||
64 (srvcmd[4] == 'A') || (srvcmd[5] == 'D'))
65 {
66 TPT((0, FIL__, __LINE__, _("msg=<reload command from server>\n")));
67#ifdef SIGHUP
68 raise(SIGHUP);
69#else
70 TPT((0, FIL__, __LINE__, _("msg=<sighup not defined>\n")));
71#endif
72 }
73 else
74 {
75 sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, 0, MSG_E_SUBGEN,
76 srvcmd,
77 _("sh_socket_server_cmd"));
78 }
79 SL_RET0(_("sh_socket_server_cmd"));
80}
81/* #if defined (SH_WITH_CLIENT)
82 */
83#endif
84
85#if defined(SH_WITH_SERVER)
86#include <errno.h>
87
88#include <sys/types.h>
89#include <sys/stat.h>
90
91#include <unistd.h>
92#include <fcntl.h>
93
94#include <time.h>
95
96#include <sys/socket.h>
97#include <sys/un.h>
98
99
100#ifdef HAVE_SYS_UIO_H
101#include <sys/uio.h>
102#endif
103#if !defined(HAVE_GETPEEREID) && !defined(SO_PEERCRED)
104#if defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || defined(HAVE_STRUCT_SOCKCRED)
105#include <sys/param.h>
106#include <sys/ucred.h>
107#endif
108#endif
109
110
111int pf_unix_fd = -1;
112static char * sh_sockname = NULL;
113static char sh_sockpass_real[SOCKPASS_MAX+1];
114
115struct socket_cmd {
116 char cmd[SH_MAXMSGLEN];
117 char clt[SH_MAXMSGLEN];
118 char cti[81];
119 struct socket_cmd * next;
120};
121
122#if !defined(O_NONBLOCK)
123#if defined(O_NDELAY)
124#define O_NONBLOCK O_NDELAY
125#else
126#define O_NONBLOCK 0
127#endif
128#endif
129
130#if !defined(AF_FILE)
131#define AF_FILE AF_UNIX
132#endif
133
134static struct socket_cmd * cmdlist = NULL;
135static struct socket_cmd * runlist = NULL;
136
137static int sh_socket_flaguse = S_FALSE;
138static int sh_socket_flaguid = 0;
139
140#include "sh_utils.h"
141
142
143struct reload_cmd {
144 char clt[SH_MAXMSGLEN];
145 time_t cti;
146 struct reload_cmd * next;
147};
148static struct reload_cmd * reloadlist = NULL;
149
150void sh_socket_add2reload (const char * clt)
151{
152 struct reload_cmd * new = reloadlist;
153
154 while (new)
155 {
156 if (0 == sl_strcmp(new->clt, clt))
157 {
158 sl_strlcpy (new->clt, clt, SH_MAXMSGLEN);
159 new->cti = time(NULL);
160 return;
161 }
162 new = new->next;
163 }
164
165 new = SH_ALLOC(sizeof(struct reload_cmd));
166 sl_strlcpy (new->clt, clt, SH_MAXMSGLEN);
167 new->cti = time(NULL);
168
169 new->next = reloadlist;
170 reloadlist = new;
171
172 return;
173}
174
175#include "zAVLTree.h"
176#include "sh_html.h"
177#include "sh_tools.h"
178static void sh_socket_add2list (struct socket_cmd * in);
179
180static void sh_socket_probe4reload ()
181{
182 struct reload_cmd * new;
183 struct socket_cmd cmd;
184
185 zAVLCursor avlcursor;
186 client_t * item;
187 extern zAVLTree * all_clients;
188
189 char * file;
190 unsigned long dummy;
191 struct stat buf;
192
193 for (item = (client_t *) zAVLFirst(&avlcursor, all_clients); item;
194 item = (client_t *) zAVLNext(&avlcursor))
195 {
196 if (item->status_now != CLT_INACTIVE)
197 {
198 file = get_client_conf_file (item->hostname, &dummy);
199
200 if (0 == stat (file, &buf))
201 {
202 new = reloadlist;
203 while (new)
204 {
205 if (0 == sl_strcmp(new->clt, item->hostname))
206 {
207 if (buf.st_mtime > new->cti)
208 {
209 /* reload */
210 sl_strlcpy(cmd.cmd, _("RELOAD"), SH_MAXMSGLEN);
211 sl_strlcpy(cmd.clt, item->hostname, SH_MAXMSGLEN);
212 sh_socket_add2list (&cmd);
213 }
214 break;
215 }
216 new = new->next;
217 }
218 }
219 }
220 }
221 return;
222}
223
224char * sh_get_sockpass ()
225{
226 size_t j = 0;
227
228 while (skey->sh_sockpass[2*j] != '\0' && j < sizeof(sh_sockpass_real))
229 {
230 sh_sockpass_real[j] = skey->sh_sockpass[2*j];
231 ++j;
232 }
233 sh_sockpass_real[j] = '\0';
234
235 return sh_sockpass_real;
236}
237
238void sh_set_sockpass ()
239{
240 int j;
241 for (j = 0; j < 15; ++j)
242 {
243 sh_sockpass_real[j] = '\0';
244 }
245}
246
247int sh_socket_use (const char * c)
248{
249 return sh_util_flagval(c, &sh_socket_flaguse);
250}
251
252int sh_socket_remove ()
253{
254 int retval = 0;
255#ifdef S_ISSOCK
256 struct stat sbuf;
257#endif
258
259 SL_ENTER(_("sh_socket_remove"));
260
261 if (NULL == sh_sockname)
262 {
263 SL_RETURN((retval),_("sh_socket_remove"));
264 }
265
266 if (0 != tf_trust_check (DEFAULT_PIDDIR, SL_YESPRIV))
267 {
268 SL_RETURN((-1),_("sh_socket_remove"));
269 }
270
271 if ( (retry_lstat(FIL__, __LINE__, sh_sockname, &sbuf) == 0) &&
272 (sbuf.st_uid == getuid()))
273 {
274#ifdef S_ISSOCK
275 if (S_ISSOCK (sbuf.st_mode))
276 {
277 retval = retry_aud_unlink (FIL__, __LINE__, sh_sockname);
278 }
279#else
280 retval = retry_aud_unlink (FIL__, __LINE__, sh_sockname);
281#endif
282 }
283 SL_RETURN((retval),_("sh_socket_remove"));
284}
285
286#if !defined(HAVE_GETPEEREID) && !defined(SO_PEERCRED) && !defined(HAVE_STRUCT_CMSGCRED) && !defined(HAVE_STRUCT_FCRED) && !(defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))
287
288#define NEED_PASSWORD_AUTH
289
290#endif
291
292int sh_socket_uid (const char * c)
293{
294 uid_t val = (uid_t) strtol (c, (char **)NULL, 10);
295 sh_socket_flaguid = val;
296#if defined(NEED_PASSWORD_AUTH)
297 sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, errno, MSG_E_SUBGEN,
298 _("Config option SetSocketAllowUID not supported, use SetSocketPassword"),
299 _("sh_socket_uid"));
300#endif
301 return 0;
302}
303
304int sh_socket_password (const char * c)
305{
306#if defined(NEED_PASSWORD_AUTH)
307 int j, i;
308
309#define LCG(n) ((69069 * n) & 0xffffffffUL)
310
311 i = sl_strlen(c);
312 if (i > SOCKPASS_MAX) {
313 return -1;
314 }
315 for (j = 0; j < (2*SOCKPASS_MAX+1); ++j)
316 {
317 skey->sh_sockpass[j] = '\0';
318 }
319 for (j = 0; j < i; ++j)
320 {
321 skey->sh_sockpass[2*j] = c[j];
322 skey->sh_sockpass[(2*j)+1] = (LCG(c[j]) % 256);
323 }
324 return 0;
325#else
326 sh_error_handle(SH_ERR_WARN, FIL__, __LINE__, errno, MSG_E_SUBGEN,
327 _("Config option SetSocketPassword not supported, use SetSocketAllowUID"),
328 _("sh_socket_password"));
329 (void) c;
330 return 0;
331#endif
332}
333
334
335int sh_socket_open_int ()
336{
337 struct sockaddr_un name;
338 size_t size;
339 int flags;
340#if defined(SO_PASSCRED)
341 socklen_t optval = 1;
342#endif
343 struct stat buf;
344
345 SL_ENTER(_("sh_socket_open_int"));
346
347 if (sh_socket_flaguse == S_FALSE)
348 {
349 SL_RETURN(0, _("sh_socket_open_int"));
350 }
351
352 if (sh_sockname == NULL)
353 {
354 size = sl_strlen(DEFAULT_PIDDIR) + 1 + sl_strlen(SH_INSTALL_NAME) + 6;
355 sh_sockname = SH_ALLOC(size); /* compile-time constant */
356 sl_strlcpy(sh_sockname, DEFAULT_PIDDIR, size);
357 sl_strlcat(sh_sockname, "/", size);
358 sl_strlcat(sh_sockname, SH_INSTALL_NAME, size);
359 sl_strlcat(sh_sockname, _(".sock"), size);
360 }
361
362 pf_unix_fd = socket (PF_UNIX, SOCK_STREAM, 0);
363 if ((pf_unix_fd) < 0)
364 {
365 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
366 sh_error_message (errno),
367 _("sh_socket_open_int: socket"));
368 SL_RETURN( (-1), _("sh_socket_open_int"));
369 }
370
371 if (sizeof(name.sun_path) < (1 + sl_strlen(sh_sockname)))
372 {
373 close(pf_unix_fd); pf_unix_fd = -1;
374 sh_error_handle ((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
375 _("PID dir path too long"),
376 _("sh_socket_open_int"));
377 SL_RETURN( (-1), _("sh_socket_open_int"));
378 }
379
380 name.sun_family = AF_FILE;
381 sl_strlcpy (name.sun_path, sh_sockname, sizeof(name.sun_path));
382
383 size = (offsetof (struct sockaddr_un, sun_path)
384 + strlen (name.sun_path) + 1);
385
386 flags = retry_lstat (FIL__, __LINE__, sh_sockname, &buf);
387
388 if (flags == 0)
389 {
390 sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, -1, MSG_E_SUBGEN,
391 _("Socket exists, trying to unlink it"),
392 _("sh_socket_open_int"));
393 if (sh_socket_remove() < 0)
394 {
395 close(pf_unix_fd); pf_unix_fd = -1;
396 sh_error_handle ((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
397 _("Unlink of socket failed, maybe path not trusted"),
398 _("sh_socket_open_int"));
399 SL_RETURN( (-1), _("sh_socket_open_int"));
400 }
401 }
402
403 if (bind ((pf_unix_fd), (struct sockaddr *) &name, size) < 0)
404 {
405 close(pf_unix_fd); pf_unix_fd = -1;
406 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
407 sh_error_message (errno),
408 _("sh_socket_open_int: bind"));
409 SL_RETURN( (-1), _("sh_socket_open_int"));
410 }
411
412#ifdef SO_PASSCRED
413 if (0 != setsockopt(pf_unix_fd, SOL_SOCKET, SO_PASSCRED,
414 &optval, sizeof(optval)))
415 {
416 close(pf_unix_fd); pf_unix_fd = -1;
417 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
418 sh_error_message (errno),
419 _("sh_socket_open_int: setsockopt"));
420 SL_RETURN( (-1), _("sh_socket_open_int"));
421 }
422#endif
423
424 flags = fcntl((pf_unix_fd), F_GETFL);
425 if (flags < 0)
426 {
427 close(pf_unix_fd); pf_unix_fd = -1;
428 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
429 sh_error_message (errno),
430 _("sh_socket_open_int: fcntl1"));
431 SL_RETURN( (-1), _("sh_socket_open_int"));
432 }
433
434 flags = fcntl((pf_unix_fd), F_SETFL, flags|O_NONBLOCK);
435 if (flags < 0)
436 {
437 close(pf_unix_fd); pf_unix_fd = -1;
438 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
439 sh_error_message (errno),
440 _("sh_socket_open_int: fcntl2"));
441 SL_RETURN( (-1), _("sh_socket_open_int"));
442 }
443
444 if (0 != listen(pf_unix_fd, 5))
445 {
446 close(pf_unix_fd); pf_unix_fd = -1;
447 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
448 sh_error_message (errno),
449 _("sh_socket_open_int: listen"));
450 SL_RETURN( (-1), _("sh_socket_open_int"));
451 }
452 SL_RETURN( (0), _("sh_socket_open_int"));
453}
454/* #if !defined(HAVE_CMSGCRED) || !defined(SO_PEERCRED) */
455/* #endif */
456
457/*
458#if !defined(HAVE_GETPEEREID) && !defined(SO_PEERCRED) && !defined(HAVE_STRUCT_CMSGCRED) && !defined(HAVE_STRUCT_FCRED) && !(defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))
459static
460int sh_socket_read (struct socket_cmd * srvcmd)
461{
462 srvcmd->cmd[0] = '\0';
463 srvcmd->clt[0] = '\0';
464 return 0;
465}
466#else
467*/
468
469/*
470 * Parts of the socket authentication code is copied from PostgreSQL:
471 *
472 * PostgreSQL Database Management System
473 * (formerly known as Postgres, then as Postgres95)
474 *
475 * Portions Copyright (c) 1996-2001, The PostgreSQL Global Development Group
476 *
477 * Portions Copyright (c) 1994, The Regents of the University of California
478 *
479 * Permission to use, copy, modify, and distribute this software and its
480 * documentation for any purpose, without fee, and without a written agreement
481 * is hereby granted, provided that the above copyright notice and this
482 * paragraph and the following two paragraphs appear in all copies.
483 *
484 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
485 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
486 * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
487 * DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
488 * POSSIBILITY OF SUCH DAMAGE.
489 *
490 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
491 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
492 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
493 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO
494 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
495 */
496static
497int sh_socket_read (struct socket_cmd * srvcmd)
498{
499 struct socket_cmd * list_cmd;
500 char message[SH_MAXMSG];
501 struct sockaddr_un name;
502 int size;
503 int nbytes;
504 int talkfd;
505 int retry = 0;
506
507 char * cmd = NULL;
508 char * clt = NULL;
509
510 int client_uid = -1;
511
512
513 struct msghdr msg;
514 struct iovec iov;
515
516#if defined(NEED_PASSWORD_AUTH)
517 char * eopw = NULL;
518 char * goodpassword = NULL;
519#endif
520
521#if defined(HAVE_GETPEEREID)
522 uid_t peer_uid;
523 gid_t peer_gid;
524#elif defined(SO_PEERCRED)
525 struct ucred cr;
526#ifdef HAVE_SOCKLEN_T
527 socklen_t cl = sizeof(cr);
528#else
529 int cl = sizeof(cr);
530#endif
531
532#elif defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || (defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))
533
534#ifdef HAVE_STRUCT_CMSGCRED
535 typedef struct cmsgcred Cred;
536#define CRED_UID cmcred_uid
537
538#elif HAVE_STRUCT_FCRED
539 typedef struct fcred Cred;
540#define CRED_UID fc_uid
541
542#elif HAVE_STRUCT_SOCKCRED
543 typedef struct sockcred Cred;
544#define CRED_UID sc_uid
545
546#endif
547 Cred *cred;
548
549 /* Compute size without padding */
550 char cmsgmem[ALIGN(sizeof(struct cmsghdr)) + ALIGN(sizeof(Cred))];
551 /* for NetBSD */
552
553 /* Point to start of first structure */
554 struct cmsghdr *cmsg = (struct cmsghdr *) cmsgmem;
555#endif
556
557 if (pf_unix_fd < 0)
558 {
559 return 0;
560 }
561
562 iov.iov_base = (char *) &message;
563 iov.iov_len = sizeof(message);
564
565 memset (&msg, 0, sizeof (msg));
566 msg.msg_iov = &iov;
567 msg.msg_iovlen = 1;
568
569#if !defined(SO_PEERCRED) && !defined(HAVE_GETPEEREID)
570#if defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || (defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))
571 msg.msg_control = (char *) cmsg;
572 msg.msg_controllen = sizeof (cmsgmem);
573 memset (cmsg, 0, sizeof (cmsgmem));
574#endif
575#endif
576
577 /* the socket is non-blocking
578 * 'name' is the address of the sender socket
579 */
580 size = sizeof (name);
581 talkfd = retry_accept(FIL__, __LINE__,
582 pf_unix_fd, (struct sockaddr *) & name, &size);
583 if ((talkfd < 0) && (errno == EAGAIN))
584 {
585 return 0;
586 }
587 else if (talkfd < 0)
588 {
589 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
590 sh_error_message (errno),
591 _("sh_socket_read: accept"));
592 return -1;
593 }
594
595
596#if defined(LOCAL_CREDS) && !defined(SO_PEERCRED) && !defined(HAVE_GETPEEREID)
597 /* Set the socket to receive credentials on the next message
598 */
599 {
600 int on = 1;
601 if (setsockopt (talkfd, 0, LOCAL_CREDS, &on, sizeof (on)) < 0)
602 {
603 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
604 sh_error_message (errno),
605 _("sh_socket_read: setsockopt"));
606 close(talkfd);
607 return -1;
608 }
609 }
610#endif
611
612 do {
613 nbytes = recvmsg (talkfd, &msg, 0);
614 if ((nbytes < 0) && (errno != EAGAIN))
615 {
616 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
617 sh_error_message (errno),
618 _("sh_socket_read: recvmsg"));
619 close(talkfd);
620 return -1;
621 }
622 else if (nbytes < 0)
623 {
624 ++retry;
625 retry_msleep(0, 1);
626 }
627 } while ((nbytes < 0) && (retry < 3));
628
629#ifdef SH_DEBUG_SOCKET
630 fprintf(stderr, "%d bytes received\n", nbytes);
631#endif
632
633 /* msg.msg_iov.iov_base, filled by recvmsg
634 */
635 message[sizeof(message)-1] = '\0';
636
637 if (nbytes < 0)
638 {
639 if (errno == EAGAIN)
640 {
641 /* no data */
642 close(talkfd);
643 return 0;
644 }
645 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
646 sh_error_message (errno),
647 _("sh_socket_read: recvfrom"));
648 close(talkfd);
649 return -1;
650 }
651
652#if defined(HAVE_GETPEEREID)
653 if (0 != getpeereid(talkfd, &peer_uid, &peer_gid))
654 {
655 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
656 sh_error_message (errno),
657 _("sh_socket_read: getpeereid"));
658 close(talkfd);
659 return -1;
660 }
661 client_uid = peer_uid;
662 cmd = message;
663#elif defined(SO_PEERCRED)
664 if (0 != getsockopt(talkfd, SOL_SOCKET, SO_PEERCRED, &cr, &cl))
665 {
666 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
667 sh_error_message (errno),
668 _("sh_socket_read: getsockopt"));
669 close(talkfd);
670 return -1;
671 }
672 client_uid = cr.uid;
673 cmd = message;
674#elif defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || (defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))
675 if (cmsg->cmsg_len < sizeof (cmsgmem) || cmsg->cmsg_type != SCM_CREDS)
676 {
677 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
678 _("Message from recvmsg() was not SCM_CREDS"),
679 _("sh_socket_read"));
680 close(talkfd);
681 return -1;
682 }
683 cred = (Cred *) CMSG_DATA (cmsg);
684 client_uid = cred->CRED_UID;
685 cmd = message;
686#elif defined(NEED_PASSWORD_AUTH)
687 goodpassword = sh_get_sockpass();
688 eopw = strchr(message, '@');
689 if (eopw)
690 *eopw = '\0';
691 /*
692 * message is null-terminated and >> goodpassword
693 */
694 if (0 == strcmp(goodpassword, message) &&
695 strlen(goodpassword) < (sizeof(message)/2))
696 {
697 client_uid = sh_socket_flaguid;
698 cmd = &message[strlen(goodpassword)+1];
699 sh_set_sockpass();
700 }
701 else
702 {
703 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
704 _("Bad password"),
705 _("sh_socket_read"));
706 sh_set_sockpass();
707 close(talkfd);
708 return -1;
709 }
710#else
711 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
712 _("Socket credentials not supported on this OS"),
713 _("sh_socket_read"));
714 close(talkfd);
715 return -1;
716#endif
717
718#ifdef SH_DEBUG_SOCKET
719 fprintf(stderr, "Peer uid=%d, required=%d\n",
720 client_uid, sh_socket_flaguid);
721#endif
722
723 if (client_uid != sh_socket_flaguid)
724 {
725 sh_error_handle((-1), FIL__, __LINE__, client_uid, MSG_E_SUBGEN,
726 _("client does not have required uid"),
727 _("sh_socket_read: getsockopt"));
728 close(talkfd);
729 return -1;
730 }
731
732
733 /* Give a diagnostic message.
734 */
735#ifdef SH_DEBUG_SOCKET
736 fprintf (stderr, "Server: got message: %s\n", cmd);
737#endif
738
739 clt = strchr(cmd, ':');
740 if (clt != NULL)
741 {
742 *clt = '\0'; ++clt;
743 if (sl_strlen(cmd) >= SH_MAXMSGLEN)
744 {
745 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
746 _("Bad message format: command too long"),
747 _("sh_socket_read"));
748 close(talkfd);
749 return -1;
750 }
751 else if (sl_strlen(clt) >= SH_MAXMSGLEN)
752 {
753 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
754 _("Bad message format: hostname too long"),
755 _("sh_socket_read"));
756 close(talkfd);
757 return -1;
758 }
759 if (cmd[0] == 'L' && cmd[1] == 'I' &&
760 cmd[2] == 'S' && cmd[3] == 'T')
761 {
762 goto list_all;
763 }
764 else if (cmd[0] == 'P' && cmd[1] == 'R' &&
765 cmd[2] == 'O' && cmd[3] == 'B' && cmd[4] == 'E')
766 {
767 sh_socket_probe4reload();
768 cmd[0] = 'L'; cmd[1] = 'I'; cmd[2] = 'S'; cmd[3] = 'T';cmd[4] = '\0';
769 goto list_all;
770 }
771 sl_strlcpy (srvcmd->cmd, cmd, SH_MAXMSGLEN);
772 sl_strlcpy (srvcmd->clt, clt, SH_MAXMSGLEN);
773 --clt; *clt = ':';
774 }
775 else
776 {
777 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
778 _("Bad message format"),
779 _("sh_socket_read"));
780 close(talkfd);
781 return -1;
782 }
783
784 /* Bounce the message back to the sender.
785 * 'name' is the receiver address; it has been been filled
786 * with the sender address in the recvfrom call
787 */
788#ifdef SH_DEBUG_SOCKET
789 fprintf (stderr, "Server: send message: %s to %s\n",
790 cmd, name.sun_path);
791#endif
792 /*
793 nbytes = sendto (pf_unix_fd, message, nbytes, 0,
794 (struct sockaddr *) & name, size);
795 */
796 nbytes = send (talkfd, cmd, strlen(cmd) + 1, 0);
797 close(talkfd);
798 if (nbytes < 0)
799 {
800 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
801 sh_error_message (errno),
802 _("sh_socket_read: send"));
803 return -1;
804 }
805#ifdef SH_DEBUG_SOCKET
806 fprintf (stderr, "Server: message is out\n");
807#endif
808 return nbytes;
809
810 list_all:
811#ifdef SH_DEBUG_SOCKET
812 fprintf (stderr, "Server: list all\n");
813#endif
814 if (cmd[4] == 'A' && cmd[5] == 'L' && cmd[6] == 'L')
815 {
816 list_cmd = runlist;
817 while (list_cmd)
818 {
819 sl_snprintf(message, sizeof(message), _("SENT %8s %32s %s"),
820 list_cmd->cmd, list_cmd->clt, list_cmd->cti);
821 /*
822 sl_strlcpy(message, _("DONE"), SH_MAXMSG);
823 sl_strlcat(message, " ", SH_MAXMSG);
824 sl_strlcat(message, list_cmd->cmd, SH_MAXMSG);
825 sl_strlcat(message, " ", SH_MAXMSG);
826 sl_strlcat(message, list_cmd->clt, SH_MAXMSG);
827 sl_strlcat(message, " ", SH_MAXMSG);
828 sl_strlcat(message, list_cmd->cti, SH_MAXMSG);
829 */
830 nbytes = send (talkfd, message, sl_strlen(message) + 1, 0);
831 if (nbytes < 0)
832 {
833 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
834 sh_error_message (errno),
835 _("sh_socket_read: sendto"));
836 close(talkfd);
837 return -1;
838 }
839 list_cmd = list_cmd->next;
840 }
841 }
842
843 list_cmd = cmdlist;
844 while (list_cmd)
845 {
846 sl_snprintf(message, sizeof(message), _(">>>> %8s %32s %s"),
847 list_cmd->cmd, list_cmd->clt, list_cmd->cti);
848 /*
849 sl_strlcpy(message, _(">>>>"), SH_MAXMSG);
850 sl_strlcat(message, " ", SH_MAXMSG);
851 sl_strlcat(message, list_cmd->cmd, SH_MAXMSG);
852 sl_strlcat(message, " ", SH_MAXMSG);
853 sl_strlcat(message, list_cmd->clt, SH_MAXMSG);
854 sl_strlcat(message, " ", SH_MAXMSG);
855 sl_strlcat(message, list_cmd->cti, SH_MAXMSG);
856 */
857 /*
858 nbytes = sendto (pf_unix_fd, message, sl_strlen(message) + 1, 0,
859 (struct sockaddr *) & name, size);
860 */
861 nbytes = send (talkfd, message, sl_strlen(message) + 1, 0);
862 if (nbytes < 0)
863 {
864 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
865 sh_error_message (errno),
866 _("sh_socket_read: sendto"));
867 close(talkfd);
868 return -1;
869 }
870 list_cmd = list_cmd->next;
871 }
872
873 /*
874 nbytes = sendto (pf_unix_fd, _("END"), 4, 0,
875 (struct sockaddr *) & name, size);
876 */
877 nbytes = send (talkfd, _("END"), 4, 0);
878 close(talkfd);
879 return 0;
880}
881/* #if !defined(HAVE_CMSGCRED) || !defined(SO_PEERCRED) */
882/* #endif */
883
884static void sh_socket_add2list (struct socket_cmd * in)
885{
886 struct socket_cmd * new;
887
888 new = SH_ALLOC(sizeof(struct socket_cmd));
889 sl_strlcpy (new->cmd, in->cmd, sizeof(new->cmd));
890 sl_strlcpy (new->clt, in->clt, sizeof(new->clt));
891 sl_strlcpy (new->cti, sh_unix_time(0), sizeof(new->cti));
892 new->next = cmdlist;
893 cmdlist = new;
894
895 return;
896}
897
898static void sh_socket_add2run (struct socket_cmd * in)
899{
900 struct socket_cmd * new = runlist;
901 char * client_name = in->clt;
902
903 while (new)
904 {
905 if (0 == sl_strcmp(new->clt, client_name))
906 {
907 sl_strlcpy (new->cmd, in->cmd, sizeof(new->cmd));
908 sl_strlcpy (new->clt, in->clt, sizeof(new->clt));
909 sl_strlcpy (new->cti, sh_unix_time(0), sizeof(new->cti));
910 return;
911 }
912 new = new->next;
913 }
914
915 new = SH_ALLOC(sizeof(struct socket_cmd));
916 sl_strlcpy (new->cmd, in->cmd, sizeof(new->cmd));
917 sl_strlcpy (new->clt, in->clt, sizeof(new->clt));
918 sl_strlcpy (new->cti, sh_unix_time(0), sizeof(new->cti));
919 new->next = runlist;
920 runlist = new;
921
922 return;
923}
924
925
926
927static void sh_socket_rm2list (const char * client_name)
928{
929 struct socket_cmd * old = cmdlist;
930 struct socket_cmd * new = cmdlist;
931
932 while (new)
933 {
934 if (0 == sl_strcmp(new->clt, client_name))
935 {
936 if ((new == cmdlist) && (new->next == NULL))
937 {
938 cmdlist = NULL;
939 SH_FREE(new);
940 return;
941 }
942 else if (new == cmdlist)
943 {
944 cmdlist = new->next;
945 SH_FREE(new);
946 return;
947 }
948 else
949 {
950 old->next = new->next;
951 SH_FREE(new);
952 return;
953 }
954 }
955 old = new;
956 new = new->next;
957 }
958 return;
959}
960
961/* poll the socket to gather input
962 */
963int sh_socket_poll()
964{
965 struct socket_cmd cmd;
966 char cancel_cmd[SH_MAXMSGLEN];
967
968 /* struct pollfd sh_poll = { pf_unix_fd, POLLIN, 0 }; */
969
970 if (pf_unix_fd < 0)
971 {
972 return 0;
973 }
974
975 sl_strlcpy(cancel_cmd, _("CANCEL"), sizeof(cancel_cmd));
976
977 while (sh_socket_read (&cmd) > 0)
978 {
979 if (0 == sl_strcmp(cmd.cmd, cancel_cmd))
980 {
981 sh_socket_rm2list (cmd.clt);
982 }
983 else
984 {
985 sh_socket_rm2list (cmd.clt);
986 sh_socket_add2list (&cmd);
987 }
988 }
989 return 0;
990}
991
992/* return the command associated with client_name
993 and remove the corresponding entry
994 */
995char * sh_socket_check(const char * client_name)
996{
997 struct socket_cmd * old = cmdlist;
998 struct socket_cmd * new = cmdlist;
999 static char out[SH_MAXMSGLEN];
1000
1001 while (new)
1002 {
1003 if (0 == sl_strcmp(new->clt, client_name))
1004 {
1005 sl_strlcpy(out, new->cmd, sizeof(out));
1006 sh_socket_add2run (new);
1007 sh_socket_rm2list (client_name);
1008 return out;
1009 }
1010 old = new;
1011 new = new->next;
1012 }
1013 return NULL;
1014}
1015
1016/* #if defined (SH_WITH_SERVER)
1017 */
1018#endif
1019
Note: See TracBrowser for help on using the repository browser.