source: trunk/src/sh_socket.c@ 127

Last change on this file since 127 was 118, checked in by rainer, 17 years ago

Fix for ticket #74 (local DoS attack on yule on BSD systems lacking the getpeereid() call).

File size: 26.7 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
681 /* Check for file descriptors sent using SCM_RIGHTS, and
682 * close them. If MSG_CTRUNC is set, the buffer was too small,
683 * and no fds are duped.
684 */
685 if (msg.msg_controllen >= sizeof(struct cmsghdr) &&
686 (msg.msg_flags & MSG_CTRUNC) == 0)
687 {
688 unsigned int data_size;
689 unsigned int data_i;
690 int fdcount, fdmax;
691 struct cmsghdr * cmptr;
692 int fdsbuf[1 + (sizeof(cmsgmem)/sizeof(int))];
693
694 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL;
695 cmptr = CMSG_NXTHDR(&msg, cmptr))
696 {
697 if (cmptr->cmsg_len > sizeof (cmsgmem) ||
698 cmptr->cmsg_level != SOL_SOCKET ||
699 cmptr->cmsg_type != SCM_RIGHTS)
700 continue;
701
702 /* Crappy way of finding the data length.
703 * cmptr->cmsg_len includes both header and padding,
704 * how are you supposed to find the data length?
705 * cmptr->cmsg_len - ALIGN(sizeof(struct cmsghdr)) ?
706 */
707 data_size = 0;
708
709 for (data_i = 0; data_i < cmptr->cmsg_len; ++data_i)
710 {
711 if (CMSG_LEN(data_i) == cmptr->cmsg_len)
712 {
713 data_size = data_i;
714 break;
715 }
716 }
717 memcpy(fdsbuf, CMSG_DATA(cmptr), data_size);
718 fdmax = data_size / sizeof(int);
719 for (fdcount = 0; fdcount < fdmax; ++fdcount)
720 (void) close(fdsbuf[fdcount]);
721 }
722 }
723
724 close(talkfd);
725 return -1;
726 }
727 cred = (Cred *) CMSG_DATA (cmsg);
728 client_uid = cred->CRED_UID;
729 cmd = message;
730#elif defined(NEED_PASSWORD_AUTH)
731 goodpassword = sh_get_sockpass();
732 eopw = strchr(message, '@');
733 if (eopw)
734 *eopw = '\0';
735 /*
736 * message is null-terminated and >> goodpassword
737 */
738 if (0 == strcmp(goodpassword, message) &&
739 strlen(goodpassword) < (sizeof(message)/2))
740 {
741 client_uid = sh_socket_flaguid;
742 cmd = &message[strlen(goodpassword)+1];
743 sh_set_sockpass();
744 }
745 else
746 {
747 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
748 _("Bad password"),
749 _("sh_socket_read"));
750 sh_set_sockpass();
751 close(talkfd);
752 return -1;
753 }
754#else
755 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
756 _("Socket credentials not supported on this OS"),
757 _("sh_socket_read"));
758 close(talkfd);
759 return -1;
760#endif
761
762#ifdef SH_DEBUG_SOCKET
763 fprintf(stderr, "Peer uid=%d, required=%d\n",
764 client_uid, sh_socket_flaguid);
765#endif
766
767 if (client_uid != sh_socket_flaguid)
768 {
769 sh_error_handle((-1), FIL__, __LINE__, client_uid, MSG_E_SUBGEN,
770 _("client does not have required uid"),
771 _("sh_socket_read: getsockopt"));
772 close(talkfd);
773 return -1;
774 }
775
776
777 /* Give a diagnostic message.
778 */
779#ifdef SH_DEBUG_SOCKET
780 fprintf (stderr, "Server: got message: %s\n", cmd);
781#endif
782
783 clt = strchr(cmd, ':');
784 if (clt != NULL)
785 {
786 *clt = '\0'; ++clt;
787 if (sl_strlen(cmd) >= SH_MAXMSGLEN)
788 {
789 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
790 _("Bad message format: command too long"),
791 _("sh_socket_read"));
792 close(talkfd);
793 return -1;
794 }
795 else if (sl_strlen(clt) >= SH_MAXMSGLEN)
796 {
797 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
798 _("Bad message format: hostname too long"),
799 _("sh_socket_read"));
800 close(talkfd);
801 return -1;
802 }
803 if (cmd[0] == 'L' && cmd[1] == 'I' &&
804 cmd[2] == 'S' && cmd[3] == 'T')
805 {
806 goto list_all;
807 }
808 else if (cmd[0] == 'P' && cmd[1] == 'R' &&
809 cmd[2] == 'O' && cmd[3] == 'B' && cmd[4] == 'E')
810 {
811 sh_socket_probe4reload();
812 cmd[0] = 'L'; cmd[1] = 'I'; cmd[2] = 'S'; cmd[3] = 'T';cmd[4] = '\0';
813 goto list_all;
814 }
815 sl_strlcpy (srvcmd->cmd, cmd, SH_MAXMSGLEN);
816 sl_strlcpy (srvcmd->clt, clt, SH_MAXMSGLEN);
817 --clt; *clt = ':';
818 }
819 else
820 {
821 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
822 _("Bad message format"),
823 _("sh_socket_read"));
824 close(talkfd);
825 return -1;
826 }
827
828 /* Bounce the message back to the sender.
829 * 'name' is the receiver address; it has been been filled
830 * with the sender address in the recvfrom call
831 */
832#ifdef SH_DEBUG_SOCKET
833 fprintf (stderr, "Server: send message: %s to %s\n",
834 cmd, name.sun_path);
835#endif
836 /*
837 nbytes = sendto (pf_unix_fd, message, nbytes, 0,
838 (struct sockaddr *) & name, size);
839 */
840 nbytes = send (talkfd, cmd, strlen(cmd) + 1, 0);
841 close(talkfd);
842 if (nbytes < 0)
843 {
844 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
845 sh_error_message (errno),
846 _("sh_socket_read: send"));
847 return -1;
848 }
849#ifdef SH_DEBUG_SOCKET
850 fprintf (stderr, "Server: message is out\n");
851#endif
852 return nbytes;
853
854 list_all:
855#ifdef SH_DEBUG_SOCKET
856 fprintf (stderr, "Server: list all\n");
857#endif
858 if (cmd[4] == 'A' && cmd[5] == 'L' && cmd[6] == 'L')
859 {
860 list_cmd = runlist;
861 while (list_cmd)
862 {
863 sl_snprintf(message, sizeof(message), _("SENT %8s %32s %s"),
864 list_cmd->cmd, list_cmd->clt, list_cmd->cti);
865 /*
866 sl_strlcpy(message, _("DONE"), SH_MAXMSG);
867 sl_strlcat(message, " ", SH_MAXMSG);
868 sl_strlcat(message, list_cmd->cmd, SH_MAXMSG);
869 sl_strlcat(message, " ", SH_MAXMSG);
870 sl_strlcat(message, list_cmd->clt, SH_MAXMSG);
871 sl_strlcat(message, " ", SH_MAXMSG);
872 sl_strlcat(message, list_cmd->cti, SH_MAXMSG);
873 */
874 nbytes = send (talkfd, message, sl_strlen(message) + 1, 0);
875 if (nbytes < 0)
876 {
877 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
878 sh_error_message (errno),
879 _("sh_socket_read: sendto"));
880 close(talkfd);
881 return -1;
882 }
883 list_cmd = list_cmd->next;
884 }
885 }
886
887 list_cmd = cmdlist;
888 while (list_cmd)
889 {
890 sl_snprintf(message, sizeof(message), _(">>>> %8s %32s %s"),
891 list_cmd->cmd, list_cmd->clt, list_cmd->cti);
892 /*
893 sl_strlcpy(message, _(">>>>"), SH_MAXMSG);
894 sl_strlcat(message, " ", SH_MAXMSG);
895 sl_strlcat(message, list_cmd->cmd, SH_MAXMSG);
896 sl_strlcat(message, " ", SH_MAXMSG);
897 sl_strlcat(message, list_cmd->clt, SH_MAXMSG);
898 sl_strlcat(message, " ", SH_MAXMSG);
899 sl_strlcat(message, list_cmd->cti, SH_MAXMSG);
900 */
901 /*
902 nbytes = sendto (pf_unix_fd, message, sl_strlen(message) + 1, 0,
903 (struct sockaddr *) & name, size);
904 */
905 nbytes = send (talkfd, message, sl_strlen(message) + 1, 0);
906 if (nbytes < 0)
907 {
908 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
909 sh_error_message (errno),
910 _("sh_socket_read: sendto"));
911 close(talkfd);
912 return -1;
913 }
914 list_cmd = list_cmd->next;
915 }
916
917 /*
918 nbytes = sendto (pf_unix_fd, _("END"), 4, 0,
919 (struct sockaddr *) & name, size);
920 */
921 nbytes = send (talkfd, _("END"), 4, 0);
922 close(talkfd);
923 return 0;
924}
925/* #if !defined(HAVE_CMSGCRED) || !defined(SO_PEERCRED) */
926/* #endif */
927
928static void sh_socket_add2list (struct socket_cmd * in)
929{
930 struct socket_cmd * new;
931
932 new = SH_ALLOC(sizeof(struct socket_cmd));
933 sl_strlcpy (new->cmd, in->cmd, sizeof(new->cmd));
934 sl_strlcpy (new->clt, in->clt, sizeof(new->clt));
935 sl_strlcpy (new->cti, sh_unix_time(0), sizeof(new->cti));
936 new->next = cmdlist;
937 cmdlist = new;
938
939 return;
940}
941
942static void sh_socket_add2run (struct socket_cmd * in)
943{
944 struct socket_cmd * new = runlist;
945 char * client_name = in->clt;
946
947 while (new)
948 {
949 if (0 == sl_strcmp(new->clt, client_name))
950 {
951 sl_strlcpy (new->cmd, in->cmd, sizeof(new->cmd));
952 sl_strlcpy (new->clt, in->clt, sizeof(new->clt));
953 sl_strlcpy (new->cti, sh_unix_time(0), sizeof(new->cti));
954 return;
955 }
956 new = new->next;
957 }
958
959 new = SH_ALLOC(sizeof(struct socket_cmd));
960 sl_strlcpy (new->cmd, in->cmd, sizeof(new->cmd));
961 sl_strlcpy (new->clt, in->clt, sizeof(new->clt));
962 sl_strlcpy (new->cti, sh_unix_time(0), sizeof(new->cti));
963 new->next = runlist;
964 runlist = new;
965
966 return;
967}
968
969
970
971static void sh_socket_rm2list (const char * client_name)
972{
973 struct socket_cmd * old = cmdlist;
974 struct socket_cmd * new = cmdlist;
975
976 while (new)
977 {
978 if (0 == sl_strcmp(new->clt, client_name))
979 {
980 if ((new == cmdlist) && (new->next == NULL))
981 {
982 cmdlist = NULL;
983 SH_FREE(new);
984 return;
985 }
986 else if (new == cmdlist)
987 {
988 cmdlist = new->next;
989 SH_FREE(new);
990 return;
991 }
992 else
993 {
994 old->next = new->next;
995 SH_FREE(new);
996 return;
997 }
998 }
999 old = new;
1000 new = new->next;
1001 }
1002 return;
1003}
1004
1005/* poll the socket to gather input
1006 */
1007int sh_socket_poll()
1008{
1009 struct socket_cmd cmd;
1010 char cancel_cmd[SH_MAXMSGLEN];
1011
1012 /* struct pollfd sh_poll = { pf_unix_fd, POLLIN, 0 }; */
1013
1014 if (pf_unix_fd < 0)
1015 {
1016 return 0;
1017 }
1018
1019 sl_strlcpy(cancel_cmd, _("CANCEL"), sizeof(cancel_cmd));
1020
1021 while (sh_socket_read (&cmd) > 0)
1022 {
1023 if (0 == sl_strcmp(cmd.cmd, cancel_cmd))
1024 {
1025 sh_socket_rm2list (cmd.clt);
1026 }
1027 else
1028 {
1029 sh_socket_rm2list (cmd.clt);
1030 sh_socket_add2list (&cmd);
1031 }
1032 }
1033 return 0;
1034}
1035
1036/* return the command associated with client_name
1037 and remove the corresponding entry
1038 */
1039char * sh_socket_check(const char * client_name)
1040{
1041 struct socket_cmd * old = cmdlist;
1042 struct socket_cmd * new = cmdlist;
1043 static char out[SH_MAXMSGLEN];
1044
1045 while (new)
1046 {
1047 if (0 == sl_strcmp(new->clt, client_name))
1048 {
1049 sl_strlcpy(out, new->cmd, sizeof(out));
1050 sh_socket_add2run (new);
1051 sh_socket_rm2list (client_name);
1052 return out;
1053 }
1054 old = new;
1055 new = new->next;
1056 }
1057 return NULL;
1058}
1059
1060/* #if defined (SH_WITH_SERVER)
1061 */
1062#endif
1063
Note: See TracBrowser for help on using the repository browser.