/* * Copyright (C) 2013-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved. * Copyright (C) 2002-2013 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ #if HAVE_CONFIG_H #include "clamav-config.h" #endif #ifdef BUILD_CLAMD #include #ifdef HAVE_UNISTD_H #include #endif #include #ifndef _WIN32 #include #include #include #include #include #endif #include #include #include "shared/optparser.h" #include "shared/output.h" #include "shared/clamdcom.h" #include "notify.h" int clamd_connect (const char *cfgfile, const char *option) { #ifndef _WIN32 struct sockaddr_un server; #endif struct addrinfo hints, *res, *p; char port[6]; int ret; struct optstruct *opts; const struct optstruct *opt; int sockd; if ((opts = optparse (cfgfile, 0, NULL, 1, OPT_CLAMD, 0, NULL)) == NULL) { logg ("!%s: Can't find or parse configuration file %s\n", option, cfgfile); return -11; } #ifndef _WIN32 if ((opt = optget (opts, "LocalSocket"))->enabled) { memset(&server, 0x00, sizeof(server)); server.sun_family = AF_UNIX; strncpy (server.sun_path, opt->strarg, sizeof (server.sun_path)); server.sun_path[sizeof (server.sun_path) - 1] = '\0'; if ((sockd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0) { logg ("^Clamd was NOT notified: Can't create socket endpoint for %s: %s\n", opt->strarg, strerror(errno)); optfree (opts); return -1; } if (connect (sockd, (struct sockaddr *) &server, sizeof (struct sockaddr_un)) < 0) { logg ("^Clamd was NOT notified: Can't connect to clamd through %s: %s\n", opt->strarg, strerror(errno)); closesocket (sockd); optfree (opts); return -11; } return sockd; } else #endif if ((opt = optget (opts, "TCPSocket"))->enabled) { memset (&hints, 0, sizeof (hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; snprintf (port, sizeof (port), "%u", (unsigned int) opt->numarg); port[5] = 0; opt = optget(opts, "TCPAddr"); while (opt) { ret = getaddrinfo (opt->strarg, port, &hints, &res); if (ret) { logg ("!%s: Can't resolve hostname %s (%s)\n", option, opt->strarg ? opt->strarg : "", (ret == EAI_SYSTEM) ? strerror (errno) : gai_strerror (ret)); opt = opt->nextarg; continue; } for (p = res; p != NULL; p = p->ai_next) { if ((sockd = socket (p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) { logg ("!%s: Can't create TCP socket to connect to %s: %s\n", option, opt->strarg ? opt->strarg : "localhost", strerror(errno)); continue; } if (connect (sockd, p->ai_addr, p->ai_addrlen) == -1) { logg ("!%s: Can't connect to clamd on %s:%s: %s\n", option, opt->strarg ? opt->strarg : "localhost", port, strerror(errno)); closesocket (sockd); continue; } optfree(opts); freeaddrinfo(res); return sockd; } freeaddrinfo (res); opt = opt->nextarg; } } else { logg ("!%s: No communication socket specified in %s\n", option, cfgfile); optfree (opts); return 1; } optfree (opts); return -1; } int notify (const char *cfgfile) { char buff[20]; int sockd, bread; if ((sockd = clamd_connect (cfgfile, "NotifyClamd")) < 0) return 1; if (sendln (sockd, "RELOAD", 7) < 0) { logg ("!NotifyClamd: Could not write to clamd socket: %s\n", strerror(errno)); closesocket (sockd); return 1; } memset (buff, 0, sizeof (buff)); if ((bread = recv (sockd, buff, sizeof (buff), 0)) > 0) { if (!strstr (buff, "RELOADING")) { logg ("!NotifyClamd: Unknown answer from clamd: '%s'\n", buff); closesocket (sockd); return -1; } } closesocket (sockd); logg ("Clamd successfully notified about the update.\n"); return 0; } #endif