source: trunk/src/sh_socket.c@ 136

Last change on this file since 136 was 132, checked in by rainer, 17 years ago

Make utility functions thread-safe.

File size: 27.1 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 char errbuf[SH_ERRBUF_SIZE];
345
346 SL_ENTER(_("sh_socket_open_int"));
347
348 if (sh_socket_flaguse == S_FALSE)
349 {
350 SL_RETURN(0, _("sh_socket_open_int"));
351 }
352
353 if (sh_sockname == NULL)
354 {
355 size = sl_strlen(DEFAULT_PIDDIR) + 1 + sl_strlen(SH_INSTALL_NAME) + 6;
356 sh_sockname = SH_ALLOC(size); /* compile-time constant */
357 sl_strlcpy(sh_sockname, DEFAULT_PIDDIR, size);
358 sl_strlcat(sh_sockname, "/", size);
359 sl_strlcat(sh_sockname, SH_INSTALL_NAME, size);
360 sl_strlcat(sh_sockname, _(".sock"), size);
361 }
362
363 pf_unix_fd = socket (PF_UNIX, SOCK_STREAM, 0);
364 if ((pf_unix_fd) < 0)
365 {
366 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
367 sh_error_message (errno, errbuf, sizeof(errbuf)),
368 _("sh_socket_open_int: socket"));
369 SL_RETURN( (-1), _("sh_socket_open_int"));
370 }
371
372 if (sizeof(name.sun_path) < (1 + sl_strlen(sh_sockname)))
373 {
374 close(pf_unix_fd); pf_unix_fd = -1;
375 sh_error_handle ((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
376 _("PID dir path too long"),
377 _("sh_socket_open_int"));
378 SL_RETURN( (-1), _("sh_socket_open_int"));
379 }
380
381 name.sun_family = AF_FILE;
382 sl_strlcpy (name.sun_path, sh_sockname, sizeof(name.sun_path));
383
384 size = (offsetof (struct sockaddr_un, sun_path)
385 + strlen (name.sun_path) + 1);
386
387 flags = retry_lstat (FIL__, __LINE__, sh_sockname, &buf);
388
389 if (flags == 0)
390 {
391 sh_error_handle(SH_ERR_INFO, FIL__, __LINE__, -1, MSG_E_SUBGEN,
392 _("Socket exists, trying to unlink it"),
393 _("sh_socket_open_int"));
394 if (sh_socket_remove() < 0)
395 {
396 close(pf_unix_fd); pf_unix_fd = -1;
397 sh_error_handle ((-1), FIL__, __LINE__, -1, MSG_E_SUBGEN,
398 _("Unlink of socket failed, maybe path not trusted"),
399 _("sh_socket_open_int"));
400 SL_RETURN( (-1), _("sh_socket_open_int"));
401 }
402 }
403
404 if (bind ((pf_unix_fd), (struct sockaddr *) &name, size) < 0)
405 {
406 close(pf_unix_fd); pf_unix_fd = -1;
407 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
408 sh_error_message (errno, errbuf, sizeof(errbuf)),
409 _("sh_socket_open_int: bind"));
410 SL_RETURN( (-1), _("sh_socket_open_int"));
411 }
412
413#ifdef SO_PASSCRED
414 if (0 != setsockopt(pf_unix_fd, SOL_SOCKET, SO_PASSCRED,
415 &optval, sizeof(optval)))
416 {
417 close(pf_unix_fd); pf_unix_fd = -1;
418 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
419 sh_error_message (errno, errbuf, sizeof(errbuf)),
420 _("sh_socket_open_int: setsockopt"));
421 SL_RETURN( (-1), _("sh_socket_open_int"));
422 }
423#endif
424
425 flags = fcntl((pf_unix_fd), F_GETFL);
426 if (flags < 0)
427 {
428 close(pf_unix_fd); pf_unix_fd = -1;
429 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
430 sh_error_message (errno, errbuf, sizeof(errbuf)),
431 _("sh_socket_open_int: fcntl1"));
432 SL_RETURN( (-1), _("sh_socket_open_int"));
433 }
434
435 flags = fcntl((pf_unix_fd), F_SETFL, flags|O_NONBLOCK);
436 if (flags < 0)
437 {
438 close(pf_unix_fd); pf_unix_fd = -1;
439 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
440 sh_error_message (errno, errbuf, sizeof(errbuf)),
441 _("sh_socket_open_int: fcntl2"));
442 SL_RETURN( (-1), _("sh_socket_open_int"));
443 }
444
445 if (0 != listen(pf_unix_fd, 5))
446 {
447 close(pf_unix_fd); pf_unix_fd = -1;
448 sh_error_handle ((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
449 sh_error_message (errno, errbuf, sizeof(errbuf)),
450 _("sh_socket_open_int: listen"));
451 SL_RETURN( (-1), _("sh_socket_open_int"));
452 }
453 SL_RETURN( (0), _("sh_socket_open_int"));
454}
455/* #if !defined(HAVE_CMSGCRED) || !defined(SO_PEERCRED) */
456/* #endif */
457
458/*
459#if !defined(HAVE_GETPEEREID) && !defined(SO_PEERCRED) && !defined(HAVE_STRUCT_CMSGCRED) && !defined(HAVE_STRUCT_FCRED) && !(defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))
460static
461int sh_socket_read (struct socket_cmd * srvcmd)
462{
463 srvcmd->cmd[0] = '\0';
464 srvcmd->clt[0] = '\0';
465 return 0;
466}
467#else
468*/
469
470/*
471 * Parts of the socket authentication code is copied from PostgreSQL:
472 *
473 * PostgreSQL Database Management System
474 * (formerly known as Postgres, then as Postgres95)
475 *
476 * Portions Copyright (c) 1996-2001, The PostgreSQL Global Development Group
477 *
478 * Portions Copyright (c) 1994, The Regents of the University of California
479 *
480 * Permission to use, copy, modify, and distribute this software and its
481 * documentation for any purpose, without fee, and without a written agreement
482 * is hereby granted, provided that the above copyright notice and this
483 * paragraph and the following two paragraphs appear in all copies.
484 *
485 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
486 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
487 * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
488 * DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
489 * POSSIBILITY OF SUCH DAMAGE.
490 *
491 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
492 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
493 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
494 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO
495 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
496 */
497static
498int sh_socket_read (struct socket_cmd * srvcmd)
499{
500 struct socket_cmd * list_cmd;
501 char message[SH_MAXMSG];
502 struct sockaddr_un name;
503 int size;
504 int nbytes;
505 int talkfd;
506 int retry = 0;
507
508 char * cmd = NULL;
509 char * clt = NULL;
510
511 int client_uid = -1;
512 char errbuf[SH_ERRBUF_SIZE];
513
514
515 struct msghdr msg;
516 struct iovec iov;
517
518#if defined(NEED_PASSWORD_AUTH)
519 char * eopw = NULL;
520 char * goodpassword = NULL;
521#endif
522
523#if defined(HAVE_GETPEEREID)
524 uid_t peer_uid;
525 gid_t peer_gid;
526#elif defined(SO_PEERCRED)
527 struct ucred cr;
528#ifdef HAVE_SOCKLEN_T
529 socklen_t cl = sizeof(cr);
530#else
531 int cl = sizeof(cr);
532#endif
533
534#elif defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || (defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))
535
536#ifdef HAVE_STRUCT_CMSGCRED
537 typedef struct cmsgcred Cred;
538#define CRED_UID cmcred_uid
539
540#elif HAVE_STRUCT_FCRED
541 typedef struct fcred Cred;
542#define CRED_UID fc_uid
543
544#elif HAVE_STRUCT_SOCKCRED
545 typedef struct sockcred Cred;
546#define CRED_UID sc_uid
547
548#endif
549 Cred *cred;
550
551 /* Compute size without padding */
552 char cmsgmem[ALIGN(sizeof(struct cmsghdr)) + ALIGN(sizeof(Cred))];
553 /* for NetBSD */
554
555 /* Point to start of first structure */
556 struct cmsghdr *cmsg = (struct cmsghdr *) cmsgmem;
557#endif
558
559 if (pf_unix_fd < 0)
560 {
561 return 0;
562 }
563
564 iov.iov_base = (char *) &message;
565 iov.iov_len = sizeof(message);
566
567 memset (&msg, 0, sizeof (msg));
568 msg.msg_iov = &iov;
569 msg.msg_iovlen = 1;
570
571#if !defined(SO_PEERCRED) && !defined(HAVE_GETPEEREID)
572#if defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || (defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))
573 msg.msg_control = (char *) cmsg;
574 msg.msg_controllen = sizeof (cmsgmem);
575 memset (cmsg, 0, sizeof (cmsgmem));
576#endif
577#endif
578
579 /* the socket is non-blocking
580 * 'name' is the address of the sender socket
581 */
582 size = sizeof (name);
583 talkfd = retry_accept(FIL__, __LINE__,
584 pf_unix_fd, (struct sockaddr *) & name, &size);
585 if ((talkfd < 0) && (errno == EAGAIN))
586 {
587 return 0;
588 }
589 else if (talkfd < 0)
590 {
591 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
592 sh_error_message (errno, errbuf, sizeof(errbuf)),
593 _("sh_socket_read: accept"));
594 return -1;
595 }
596
597
598#if defined(LOCAL_CREDS) && !defined(SO_PEERCRED) && !defined(HAVE_GETPEEREID)
599 /* Set the socket to receive credentials on the next message
600 */
601 {
602 int on = 1;
603 if (setsockopt (talkfd, 0, LOCAL_CREDS, &on, sizeof (on)) < 0)
604 {
605 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
606 sh_error_message (errno, errbuf, sizeof(errbuf)),
607 _("sh_socket_read: setsockopt"));
608 close(talkfd);
609 return -1;
610 }
611 }
612#endif
613
614 do {
615 nbytes = recvmsg (talkfd, &msg, 0);
616 if ((nbytes < 0) && (errno != EAGAIN))
617 {
618 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
619 sh_error_message (errno, errbuf, sizeof(errbuf)),
620 _("sh_socket_read: recvmsg"));
621 close(talkfd);
622 return -1;
623 }
624 else if (nbytes < 0)
625 {
626 ++retry;
627 retry_msleep(0, 1);
628 }
629 } while ((nbytes < 0) && (retry < 3));
630
631#ifdef SH_DEBUG_SOCKET
632 fprintf(stderr, "%d bytes received\n", nbytes);
633#endif
634
635 /* msg.msg_iov.iov_base, filled by recvmsg
636 */
637 message[sizeof(message)-1] = '\0';
638
639 if (nbytes < 0)
640 {
641 if (errno == EAGAIN)
642 {
643 /* no data */
644 close(talkfd);
645 return 0;
646 }
647 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
648 sh_error_message (errno, errbuf, sizeof(errbuf)),
649 _("sh_socket_read: recvfrom"));
650 close(talkfd);
651 return -1;
652 }
653
654#if defined(HAVE_GETPEEREID)
655 if (0 != getpeereid(talkfd, &peer_uid, &peer_gid))
656 {
657 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
658 sh_error_message (errno, errbuf, sizeof(errbuf)),
659 _("sh_socket_read: getpeereid"));
660 close(talkfd);
661 return -1;
662 }
663 client_uid = peer_uid;
664 cmd = message;
665#elif defined(SO_PEERCRED)
666 if (0 != getsockopt(talkfd, SOL_SOCKET, SO_PEERCRED, &cr, &cl))
667 {
668 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
669 sh_error_message (errno, errbuf, sizeof(errbuf)),
670 _("sh_socket_read: getsockopt"));
671 close(talkfd);
672 return -1;
673 }
674 client_uid = cr.uid;
675 cmd = message;
676#elif defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || (defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))
677 if (cmsg->cmsg_len < sizeof (cmsgmem) || cmsg->cmsg_type != SCM_CREDS)
678 {
679 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
680 _("Message from recvmsg() was not SCM_CREDS"),
681 _("sh_socket_read"));
682
683 /* Check for file descriptors sent using SCM_RIGHTS, and
684 * close them. If MSG_CTRUNC is set, the buffer was too small,
685 * and no fds are duped.
686 */
687 if (msg.msg_controllen >= sizeof(struct cmsghdr) &&
688 (msg.msg_flags & MSG_CTRUNC) == 0)
689 {
690 unsigned int data_size;
691 unsigned int data_i;
692 int fdcount, fdmax;
693 struct cmsghdr * cmptr;
694 int fdsbuf[1 + (sizeof(cmsgmem)/sizeof(int))];
695
696 for (cmptr = CMSG_FIRSTHDR(&msg); cmptr != NULL;
697 cmptr = CMSG_NXTHDR(&msg, cmptr))
698 {
699 if (cmptr->cmsg_len > sizeof (cmsgmem) ||
700 cmptr->cmsg_level != SOL_SOCKET ||
701 cmptr->cmsg_type != SCM_RIGHTS)
702 continue;
703
704 /* Crappy way of finding the data length.
705 * cmptr->cmsg_len includes both header and padding,
706 * how are you supposed to find the data length?
707 * cmptr->cmsg_len - ALIGN(sizeof(struct cmsghdr)) ?
708 */
709 data_size = 0;
710
711 for (data_i = 0; data_i < cmptr->cmsg_len; ++data_i)
712 {
713 if (CMSG_LEN(data_i) == cmptr->cmsg_len)
714 {
715 data_size = data_i;
716 break;
717 }
718 }
719 memcpy(fdsbuf, CMSG_DATA(cmptr), data_size);
720 fdmax = data_size / sizeof(int);
721 for (fdcount = 0; fdcount < fdmax; ++fdcount)
722 (void) close(fdsbuf[fdcount]);
723 }
724 }
725
726 close(talkfd);
727 return -1;
728 }
729 cred = (Cred *) CMSG_DATA (cmsg);
730 client_uid = cred->CRED_UID;
731 cmd = message;
732#elif defined(NEED_PASSWORD_AUTH)
733 goodpassword = sh_get_sockpass();
734 eopw = strchr(message, '@');
735 if (eopw)
736 *eopw = '\0';
737 /*
738 * message is null-terminated and >> goodpassword
739 */
740 if (0 == strcmp(goodpassword, message) &&
741 strlen(goodpassword) < (sizeof(message)/2))
742 {
743 client_uid = sh_socket_flaguid;
744 cmd = &message[strlen(goodpassword)+1];
745 sh_set_sockpass();
746 }
747 else
748 {
749 sh_error_handle((-1), FIL__, __LINE__, 0, MSG_E_SUBGEN,
750 _("Bad password"),
751 _("sh_socket_read"));
752 sh_set_sockpass();
753 close(talkfd);
754 return -1;
755 }
756#else
757 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
758 _("Socket credentials not supported on this OS"),
759 _("sh_socket_read"));
760 close(talkfd);
761 return -1;
762#endif
763
764#ifdef SH_DEBUG_SOCKET
765 fprintf(stderr, "Peer uid=%d, required=%d\n",
766 client_uid, sh_socket_flaguid);
767#endif
768
769 if (client_uid != sh_socket_flaguid)
770 {
771 sh_error_handle((-1), FIL__, __LINE__, client_uid, MSG_E_SUBGEN,
772 _("client does not have required uid"),
773 _("sh_socket_read: getsockopt"));
774 close(talkfd);
775 return -1;
776 }
777
778
779 /* Give a diagnostic message.
780 */
781#ifdef SH_DEBUG_SOCKET
782 fprintf (stderr, "Server: got message: %s\n", cmd);
783#endif
784
785 clt = strchr(cmd, ':');
786 if (clt != NULL)
787 {
788 *clt = '\0'; ++clt;
789 if (sl_strlen(cmd) >= SH_MAXMSGLEN)
790 {
791 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
792 _("Bad message format: command too long"),
793 _("sh_socket_read"));
794 close(talkfd);
795 return -1;
796 }
797 else if (sl_strlen(clt) >= SH_MAXMSGLEN)
798 {
799 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
800 _("Bad message format: hostname too long"),
801 _("sh_socket_read"));
802 close(talkfd);
803 return -1;
804 }
805 if (cmd[0] == 'L' && cmd[1] == 'I' &&
806 cmd[2] == 'S' && cmd[3] == 'T')
807 {
808 goto list_all;
809 }
810 else if (cmd[0] == 'P' && cmd[1] == 'R' &&
811 cmd[2] == 'O' && cmd[3] == 'B' && cmd[4] == 'E')
812 {
813 sh_socket_probe4reload();
814 cmd[0] = 'L'; cmd[1] = 'I'; cmd[2] = 'S'; cmd[3] = 'T';cmd[4] = '\0';
815 goto list_all;
816 }
817 sl_strlcpy (srvcmd->cmd, cmd, SH_MAXMSGLEN);
818 sl_strlcpy (srvcmd->clt, clt, SH_MAXMSGLEN);
819 --clt; *clt = ':';
820 }
821 else
822 {
823 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
824 _("Bad message format"),
825 _("sh_socket_read"));
826 close(talkfd);
827 return -1;
828 }
829
830 /* Bounce the message back to the sender.
831 * 'name' is the receiver address; it has been been filled
832 * with the sender address in the recvfrom call
833 */
834#ifdef SH_DEBUG_SOCKET
835 fprintf (stderr, "Server: send message: %s to %s\n",
836 cmd, name.sun_path);
837#endif
838 /*
839 nbytes = sendto (pf_unix_fd, message, nbytes, 0,
840 (struct sockaddr *) & name, size);
841 */
842 nbytes = send (talkfd, cmd, strlen(cmd) + 1, 0);
843 close(talkfd);
844 if (nbytes < 0)
845 {
846 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
847 sh_error_message (errno, errbuf, sizeof(errbuf)),
848 _("sh_socket_read: send"));
849 return -1;
850 }
851#ifdef SH_DEBUG_SOCKET
852 fprintf (stderr, "Server: message is out\n");
853#endif
854 return nbytes;
855
856 list_all:
857#ifdef SH_DEBUG_SOCKET
858 fprintf (stderr, "Server: list all\n");
859#endif
860 if (cmd[4] == 'A' && cmd[5] == 'L' && cmd[6] == 'L')
861 {
862 list_cmd = runlist;
863 while (list_cmd)
864 {
865 sl_snprintf(message, sizeof(message), _("SENT %8s %32s %s"),
866 list_cmd->cmd, list_cmd->clt, list_cmd->cti);
867 /*
868 sl_strlcpy(message, _("DONE"), SH_MAXMSG);
869 sl_strlcat(message, " ", SH_MAXMSG);
870 sl_strlcat(message, list_cmd->cmd, SH_MAXMSG);
871 sl_strlcat(message, " ", SH_MAXMSG);
872 sl_strlcat(message, list_cmd->clt, SH_MAXMSG);
873 sl_strlcat(message, " ", SH_MAXMSG);
874 sl_strlcat(message, list_cmd->cti, SH_MAXMSG);
875 */
876 nbytes = send (talkfd, message, sl_strlen(message) + 1, 0);
877 if (nbytes < 0)
878 {
879 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
880 sh_error_message (errno, errbuf, sizeof(errbuf)),
881 _("sh_socket_read: sendto"));
882 close(talkfd);
883 return -1;
884 }
885 list_cmd = list_cmd->next;
886 }
887 }
888
889 list_cmd = cmdlist;
890 while (list_cmd)
891 {
892 sl_snprintf(message, sizeof(message), _(">>>> %8s %32s %s"),
893 list_cmd->cmd, list_cmd->clt, list_cmd->cti);
894 /*
895 sl_strlcpy(message, _(">>>>"), SH_MAXMSG);
896 sl_strlcat(message, " ", SH_MAXMSG);
897 sl_strlcat(message, list_cmd->cmd, SH_MAXMSG);
898 sl_strlcat(message, " ", SH_MAXMSG);
899 sl_strlcat(message, list_cmd->clt, SH_MAXMSG);
900 sl_strlcat(message, " ", SH_MAXMSG);
901 sl_strlcat(message, list_cmd->cti, SH_MAXMSG);
902 */
903 /*
904 nbytes = sendto (pf_unix_fd, message, sl_strlen(message) + 1, 0,
905 (struct sockaddr *) & name, size);
906 */
907 nbytes = send (talkfd, message, sl_strlen(message) + 1, 0);
908 if (nbytes < 0)
909 {
910 sh_error_handle((-1), FIL__, __LINE__, errno, MSG_E_SUBGEN,
911 sh_error_message (errno, errbuf, sizeof(errbuf)),
912 _("sh_socket_read: sendto"));
913 close(talkfd);
914 return -1;
915 }
916 list_cmd = list_cmd->next;
917 }
918
919 /*
920 nbytes = sendto (pf_unix_fd, _("END"), 4, 0,
921 (struct sockaddr *) & name, size);
922 */
923 nbytes = send (talkfd, _("END"), 4, 0);
924 close(talkfd);
925 return 0;
926}
927/* #if !defined(HAVE_CMSGCRED) || !defined(SO_PEERCRED) */
928/* #endif */
929
930static void sh_socket_add2list (struct socket_cmd * in)
931{
932 struct socket_cmd * new;
933
934 new = SH_ALLOC(sizeof(struct socket_cmd));
935 sl_strlcpy (new->cmd, in->cmd, sizeof(new->cmd));
936 sl_strlcpy (new->clt, in->clt, sizeof(new->clt));
937 (void) sh_unix_time(0, new->cti, sizeof(new->cti));
938 new->next = cmdlist;
939 cmdlist = new;
940
941 return;
942}
943
944static void sh_socket_add2run (struct socket_cmd * in)
945{
946 struct socket_cmd * new = runlist;
947 char * client_name = in->clt;
948
949 while (new)
950 {
951 if (0 == sl_strcmp(new->clt, client_name))
952 {
953 sl_strlcpy (new->cmd, in->cmd, sizeof(new->cmd));
954 sl_strlcpy (new->clt, in->clt, sizeof(new->clt));
955 (void) sh_unix_time(0, new->cti, sizeof(new->cti));
956 return;
957 }
958 new = new->next;
959 }
960
961 new = SH_ALLOC(sizeof(struct socket_cmd));
962 sl_strlcpy (new->cmd, in->cmd, sizeof(new->cmd));
963 sl_strlcpy (new->clt, in->clt, sizeof(new->clt));
964 (void) sh_unix_time(0, new->cti, sizeof(new->cti));
965 new->next = runlist;
966 runlist = new;
967
968 return;
969}
970
971
972
973static void sh_socket_rm2list (const char * client_name)
974{
975 struct socket_cmd * old = cmdlist;
976 struct socket_cmd * new = cmdlist;
977
978 while (new)
979 {
980 if (0 == sl_strcmp(new->clt, client_name))
981 {
982 if ((new == cmdlist) && (new->next == NULL))
983 {
984 cmdlist = NULL;
985 SH_FREE(new);
986 return;
987 }
988 else if (new == cmdlist)
989 {
990 cmdlist = new->next;
991 SH_FREE(new);
992 return;
993 }
994 else
995 {
996 old->next = new->next;
997 SH_FREE(new);
998 return;
999 }
1000 }
1001 old = new;
1002 new = new->next;
1003 }
1004 return;
1005}
1006
1007/* poll the socket to gather input
1008 */
1009int sh_socket_poll()
1010{
1011 struct socket_cmd cmd;
1012 char cancel_cmd[SH_MAXMSGLEN];
1013
1014 /* struct pollfd sh_poll = { pf_unix_fd, POLLIN, 0 }; */
1015
1016 if (pf_unix_fd < 0)
1017 {
1018 return 0;
1019 }
1020
1021 sl_strlcpy(cancel_cmd, _("CANCEL"), sizeof(cancel_cmd));
1022
1023 while (sh_socket_read (&cmd) > 0)
1024 {
1025 if (0 == sl_strcmp(cmd.cmd, cancel_cmd))
1026 {
1027 sh_socket_rm2list (cmd.clt);
1028 }
1029 else
1030 {
1031 sh_socket_rm2list (cmd.clt);
1032 sh_socket_add2list (&cmd);
1033 }
1034 }
1035 return 0;
1036}
1037
1038/* return the command associated with client_name
1039 and remove the corresponding entry
1040 */
1041char * sh_socket_check(const char * client_name)
1042{
1043 struct socket_cmd * old = cmdlist;
1044 struct socket_cmd * new = cmdlist;
1045 static char out[SH_MAXMSGLEN];
1046
1047 while (new)
1048 {
1049 if (0 == sl_strcmp(new->clt, client_name))
1050 {
1051 sl_strlcpy(out, new->cmd, sizeof(out));
1052 sh_socket_add2run (new);
1053 sh_socket_rm2list (client_name);
1054 return out;
1055 }
1056 old = new;
1057 new = new->next;
1058 }
1059 return NULL;
1060}
1061
1062/* #if defined (SH_WITH_SERVER)
1063 */
1064#endif
1065
Note: See TracBrowser for help on using the repository browser.