source: trunk/src/sh_socket.c@ 190

Last change on this file since 190 was 177, checked in by katerina, 16 years ago

Fix for compile failure on Fedora 9 (ticket #115).

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