~ubuntu-branches/ubuntu/saucy/clamav/saucy-backports

« back to all changes in this revision

Viewing changes to .pc/0010-Call-cl_initialize_crypto-in-cl_init.patch/clamd/clamd.c

  • Committer: Package Import Robot
  • Author(s): Scott Kitterman
  • Date: 2014-07-15 01:08:10 UTC
  • mfrom: (0.35.47 sid)
  • Revision ID: package-import@ubuntu.com-20140715010810-ru66ek4fun2iseba
Tags: 0.98.4+dfsg-2~ubuntu13.10.1
No-change backport to saucy (LP: #1341962)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  Copyright (C) 2007-2009 Sourcefire, Inc.
 
3
 *
 
4
 *  Authors: Tomasz Kojm
 
5
 *
 
6
 *  This program is free software; you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License version 2 as
 
8
 *  published by the Free Software Foundation.
 
9
 *
 
10
 *  This program is distributed in the hope that it will be useful,
 
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 *  GNU General Public License for more details.
 
14
 *
 
15
 *  You should have received a copy of the GNU General Public License
 
16
 *  along with this program; if not, write to the Free Software
 
17
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 
18
 *  MA 02110-1301, USA.
 
19
 */
 
20
 
 
21
#if HAVE_CONFIG_H
 
22
#include "clamav-config.h"
 
23
#endif
 
24
 
 
25
#include <stdio.h>
 
26
#include <stdlib.h>
 
27
#include <string.h>
 
28
#ifdef HAVE_UNISTD_H
 
29
#include <unistd.h>
 
30
#endif
 
31
#ifndef _WIN32
 
32
#include <sys/time.h>
 
33
#include <sys/resource.h>
 
34
#endif
 
35
#include <sys/types.h>
 
36
#include <sys/stat.h>
 
37
#include <fcntl.h>
 
38
#include <time.h>
 
39
#ifdef HAVE_PWD_H
 
40
#include <pwd.h>
 
41
#endif
 
42
#ifdef HAVE_GRP_H
 
43
#include <grp.h>
 
44
#endif
 
45
#include <signal.h>
 
46
#include <errno.h>
 
47
 
 
48
#if defined(USE_SYSLOG) && !defined(C_AIX)
 
49
#include <syslog.h>
 
50
#endif
 
51
 
 
52
#ifdef C_LINUX
 
53
#include <sys/resource.h>
 
54
#endif
 
55
 
 
56
#include <openssl/ssl.h>
 
57
#include <openssl/err.h>
 
58
#include "libclamav/crypto.h"
 
59
 
 
60
#include "target.h"
 
61
 
 
62
#include "libclamav/clamav.h"
 
63
#include "libclamav/others.h"
 
64
#include "libclamav/matcher-ac.h"
 
65
#include "libclamav/readdb.h"
 
66
 
 
67
#include "shared/output.h"
 
68
#include "shared/optparser.h"
 
69
#include "shared/misc.h"
 
70
 
 
71
#include "server.h"
 
72
#include "tcpserver.h"
 
73
#include "localserver.h"
 
74
#include "others.h"
 
75
#include "shared.h"
 
76
#include "scanner.h"
 
77
 
 
78
short debug_mode = 0, logok = 0;
 
79
short foreground = 0;
 
80
char hostid[37];
 
81
 
 
82
char *get_hostid(void *cbdata);
 
83
 
 
84
static void help(void)
 
85
{
 
86
    printf("\n");
 
87
    printf("                      Clam AntiVirus Daemon %s\n", get_version());
 
88
    printf("           By The ClamAV Team: http://www.clamav.net/team\n");
 
89
    printf("           (C) 2007-2009 Sourcefire, Inc.\n\n");
 
90
 
 
91
    printf("    --help                   -h             Show this help.\n");
 
92
    printf("    --version                -V             Show version number.\n");
 
93
    printf("    --debug                                 Enable debug mode.\n");
 
94
    printf("    --config-file=FILE       -c FILE        Read configuration from FILE.\n\n");
 
95
}
 
96
 
 
97
static struct optstruct *opts;
 
98
 
 
99
/* When running under valgrind and daemonizing, valgrind incorrectly reports
 
100
 * leaks from the engine, because it can't see that all the memory is still
 
101
 * reachable (some pointers are stored mangled in the JIT). 
 
102
 * So free the engine on exit from the parent too (during daemonize)
 
103
 */
 
104
static struct cl_engine *gengine = NULL;
 
105
static void free_engine(void)
 
106
{
 
107
    if (gengine) {
 
108
        cl_engine_free(gengine);
 
109
        gengine = NULL;
 
110
    }
 
111
}
 
112
 
 
113
int main(int argc, char **argv)
 
114
{
 
115
    static struct cl_engine *engine = NULL;
 
116
    const struct optstruct *opt;
 
117
#ifndef _WIN32
 
118
    struct passwd *user = NULL;
 
119
    struct sigaction sa;
 
120
    struct rlimit rlim;
 
121
#endif
 
122
    time_t currtime;
 
123
    const char *dbdir, *cfgfile;
 
124
    char *pua_cats = NULL, *pt;
 
125
    int ret, tcpsock = 0, localsock = 0, i, min_port, max_port;
 
126
    unsigned int sigs = 0;
 
127
    int *lsockets=NULL;
 
128
    unsigned int nlsockets = 0;
 
129
    unsigned int dboptions = 0;
 
130
#ifdef C_LINUX
 
131
    STATBUF sb;
 
132
#endif
 
133
 
 
134
    if(check_flevel())
 
135
        exit(1);
 
136
 
 
137
#ifndef _WIN32
 
138
    memset(&sa, 0, sizeof(sa));
 
139
    sa.sa_handler = SIG_IGN;
 
140
    sigaction(SIGHUP, &sa, NULL);
 
141
    sigaction(SIGUSR2, &sa, NULL);
 
142
#endif
 
143
 
 
144
    cl_initialize_crypto();
 
145
 
 
146
    if((opts = optparse(NULL, argc, argv, 1, OPT_CLAMD, 0, NULL)) == NULL) {
 
147
        mprintf("!Can't parse command line options\n");
 
148
        return 1;
 
149
    }
 
150
 
 
151
    if(optget(opts, "help")->enabled) {
 
152
        help();
 
153
        optfree(opts);
 
154
        return 0;
 
155
    }
 
156
 
 
157
    if(optget(opts, "debug")->enabled) {
 
158
#if defined(C_LINUX)
 
159
        /* njh@bandsman.co.uk: create a dump if needed */
 
160
        rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
 
161
        if(setrlimit(RLIMIT_CORE, &rlim) < 0)
 
162
            perror("setrlimit");
 
163
#endif
 
164
        debug_mode = 1;
 
165
    }
 
166
 
 
167
    /* parse the config file */
 
168
    cfgfile = optget(opts, "config-file")->strarg;
 
169
    pt = strdup(cfgfile);
 
170
    if((opts = optparse(cfgfile, 0, NULL, 1, OPT_CLAMD, 0, opts)) == NULL) {
 
171
        fprintf(stderr, "ERROR: Can't open/parse the config file %s\n", pt);
 
172
        free(pt);
 
173
        return 1;
 
174
    }
 
175
    free(pt);
 
176
 
 
177
    if(optget(opts, "version")->enabled) {
 
178
        print_version(optget(opts, "DatabaseDirectory")->strarg);
 
179
        optfree(opts);
 
180
        return 0;
 
181
    }
 
182
 
 
183
    /* drop privileges */
 
184
#ifndef _WIN32
 
185
    if(geteuid() == 0 && (opt = optget(opts, "User"))->enabled) {
 
186
        if((user = getpwnam(opt->strarg)) == NULL) {
 
187
            fprintf(stderr, "ERROR: Can't get information about user %s.\n", opt->strarg);
 
188
            optfree(opts);
 
189
            return 1;
 
190
        }
 
191
 
 
192
        if(optget(opts, "AllowSupplementaryGroups")->enabled) {
 
193
#ifdef HAVE_INITGROUPS
 
194
            if(initgroups(opt->strarg, user->pw_gid)) {
 
195
                fprintf(stderr, "ERROR: initgroups() failed.\n");
 
196
                optfree(opts);
 
197
                return 1;
 
198
            }
 
199
#else
 
200
            mprintf("!AllowSupplementaryGroups: initgroups() is not available, please disable AllowSupplementaryGroups in %s\n", cfgfile);
 
201
            optfree(opts);
 
202
            return 1;
 
203
#endif
 
204
        } else {
 
205
#ifdef HAVE_SETGROUPS
 
206
            if(setgroups(1, &user->pw_gid)) {
 
207
                fprintf(stderr, "ERROR: setgroups() failed.\n");
 
208
                optfree(opts);
 
209
                return 1;
 
210
            }
 
211
#endif
 
212
        }
 
213
 
 
214
        if(setgid(user->pw_gid)) {
 
215
            fprintf(stderr, "ERROR: setgid(%d) failed.\n", (int) user->pw_gid);
 
216
            optfree(opts);
 
217
            return 1;
 
218
        }
 
219
 
 
220
        if(setuid(user->pw_uid)) {
 
221
            fprintf(stderr, "ERROR: setuid(%d) failed.\n", (int) user->pw_uid);
 
222
            optfree(opts);
 
223
            return 1;
 
224
        }
 
225
    }
 
226
#endif
 
227
 
 
228
    /* initialize logger */
 
229
    logg_lock = !optget(opts, "LogFileUnlock")->enabled;
 
230
    logg_time = optget(opts, "LogTime")->enabled;
 
231
    logok = optget(opts, "LogClean")->enabled;
 
232
    logg_size = optget(opts, "LogFileMaxSize")->numarg;
 
233
    logg_verbose = mprintf_verbose = optget(opts, "LogVerbose")->enabled;
 
234
    if (logg_size)
 
235
        logg_rotate = optget(opts, "LogRotate")->enabled;
 
236
    mprintf_send_timeout = optget(opts, "SendBufTimeout")->numarg;
 
237
 
 
238
    do { /* logger initialized */
 
239
        if((opt = optget(opts, "LogFile"))->enabled) {
 
240
            char timestr[32];
 
241
            logg_file = opt->strarg;
 
242
            if(!cli_is_abspath(logg_file)) {
 
243
                fprintf(stderr, "ERROR: LogFile requires full path.\n");
 
244
                ret = 1;
 
245
                break;
 
246
            }
 
247
            time(&currtime);
 
248
            if(logg("#+++ Started at %s", cli_ctime(&currtime, timestr, sizeof(timestr)))) {
 
249
                fprintf(stderr, "ERROR: Can't initialize the internal logger\n");
 
250
                ret = 1;
 
251
                break;
 
252
            }
 
253
        } else {
 
254
            logg_file = NULL;
 
255
        }
 
256
 
 
257
        if (optget(opts,"DevLiblog")->enabled)
 
258
            cl_set_clcb_msg(msg_callback);
 
259
 
 
260
        if((ret = cl_init(CL_INIT_DEFAULT))) {
 
261
            logg("!Can't initialize libclamav: %s\n", cl_strerror(ret));
 
262
            ret = 1;
 
263
            break;
 
264
        }
 
265
 
 
266
        if(optget(opts, "Debug")->enabled) {
 
267
            /* enable debug messages in libclamav */
 
268
            cl_debug();
 
269
            logg_verbose = 2;
 
270
        }
 
271
 
 
272
#if defined(USE_SYSLOG) && !defined(C_AIX)
 
273
        if(optget(opts, "LogSyslog")->enabled) {
 
274
            int fac = LOG_LOCAL6;
 
275
 
 
276
            opt = optget(opts, "LogFacility");
 
277
            if((fac = logg_facility(opt->strarg)) == -1) {
 
278
                logg("!LogFacility: %s: No such facility.\n", opt->strarg);
 
279
                ret = 1;
 
280
                break;
 
281
            }
 
282
 
 
283
            openlog("clamd", LOG_PID, fac);
 
284
            logg_syslog = 1;
 
285
        }
 
286
#endif
 
287
 
 
288
#ifdef C_LINUX
 
289
        procdev = 0;
 
290
        if(CLAMSTAT("/proc", &sb) != -1 && !sb.st_size)
 
291
            procdev = sb.st_dev;
 
292
#endif
 
293
 
 
294
        /* check socket type */
 
295
 
 
296
        if(optget(opts, "TCPSocket")->enabled)
 
297
            tcpsock = 1;
 
298
 
 
299
        if(optget(opts, "LocalSocket")->enabled)
 
300
            localsock = 1;
 
301
 
 
302
        if(!tcpsock && !localsock) {
 
303
            logg("!Please define server type (local and/or TCP).\n");
 
304
            ret = 1;
 
305
            break;
 
306
        }
 
307
 
 
308
        logg("#clamd daemon %s (OS: "TARGET_OS_TYPE", ARCH: "TARGET_ARCH_TYPE", CPU: "TARGET_CPU_TYPE")\n", get_version());
 
309
 
 
310
#ifndef _WIN32
 
311
        if(user)
 
312
            logg("#Running as user %s (UID %u, GID %u)\n", user->pw_name, user->pw_uid, user->pw_gid);
 
313
#endif
 
314
 
 
315
#if defined(RLIMIT_DATA) && defined(C_BSD)
 
316
        if (getrlimit(RLIMIT_DATA, &rlim) == 0) {
 
317
           /* bb #1941.
 
318
            * On 32-bit FreeBSD if you set ulimit -d to >2GB then mmap() will fail
 
319
            * too soon (after ~120 MB).
 
320
            * Set limit lower than 2G if on 32-bit */
 
321
           uint64_t lim = rlim.rlim_cur;
 
322
           if (sizeof(void*) == 4 &&
 
323
               lim > (1ULL << 31)) {
 
324
               rlim.rlim_cur = 1ULL << 31;
 
325
               if (setrlimit(RLIMIT_DATA, &rlim) < 0)
 
326
                   logg("!setrlimit(RLIMIT_DATA) failed: %s\n", strerror(errno));
 
327
               else
 
328
                   logg("Running on 32-bit system, and RLIMIT_DATA > 2GB, lowering to 2GB!\n");
 
329
           }
 
330
        }
 
331
#endif
 
332
 
 
333
 
 
334
        if(logg_size)
 
335
            logg("#Log file size limited to %u bytes.\n", logg_size);
 
336
        else
 
337
            logg("#Log file size limit disabled.\n");
 
338
 
 
339
        min_port = optget(opts, "StreamMinPort")->numarg;
 
340
        max_port = optget(opts, "StreamMaxPort")->numarg;
 
341
        if (min_port < 1024 || min_port > max_port || max_port > 65535) {
 
342
            logg("!Invalid StreamMinPort/StreamMaxPort: %d, %d\n", min_port, max_port);
 
343
            ret = 1;
 
344
            break;
 
345
        }
 
346
 
 
347
        if(!(engine = cl_engine_new())) {
 
348
            logg("!Can't initialize antivirus engine\n");
 
349
            ret = 1;
 
350
            break;
 
351
        }
 
352
 
 
353
        if (optget(opts, "disable-cache")->enabled)
 
354
            cl_engine_set_num(engine, CL_ENGINE_DISABLE_CACHE, 1);
 
355
 
 
356
        /* load the database(s) */
 
357
        dbdir = optget(opts, "DatabaseDirectory")->strarg;
 
358
        logg("#Reading databases from %s\n", dbdir);
 
359
 
 
360
        if(optget(opts, "DetectPUA")->enabled) {
 
361
            dboptions |= CL_DB_PUA;
 
362
 
 
363
            if((opt = optget(opts, "ExcludePUA"))->enabled) {
 
364
                dboptions |= CL_DB_PUA_EXCLUDE;
 
365
                i = 0;
 
366
                logg("#Excluded PUA categories:");
 
367
 
 
368
                while(opt) {
 
369
                    if(!(pua_cats = realloc(pua_cats, i + strlen(opt->strarg) + 3))) {
 
370
                        logg("!Can't allocate memory for pua_cats\n");
 
371
                        cl_engine_free(engine);
 
372
                        ret = 1;
 
373
                        break;
 
374
                    }
 
375
 
 
376
                    logg("# %s", opt->strarg);
 
377
 
 
378
                    sprintf(pua_cats + i, ".%s", opt->strarg);
 
379
                    i += strlen(opt->strarg) + 1;
 
380
                    pua_cats[i] = 0;
 
381
                    opt = opt->nextarg;
 
382
                }
 
383
 
 
384
                if (ret)
 
385
                    break;
 
386
 
 
387
                logg("#\n");
 
388
                pua_cats[i] = '.';
 
389
                pua_cats[i + 1] = 0;
 
390
            }
 
391
 
 
392
            if((opt = optget(opts, "IncludePUA"))->enabled) {
 
393
                if(pua_cats) {
 
394
                    logg("!ExcludePUA and IncludePUA cannot be used at the same time\n");
 
395
                    free(pua_cats);
 
396
                    ret = 1;
 
397
                    break;
 
398
                }
 
399
 
 
400
                dboptions |= CL_DB_PUA_INCLUDE;
 
401
                i = 0;
 
402
                logg("#Included PUA categories:");
 
403
                while(opt) {
 
404
                    if(!(pua_cats = realloc(pua_cats, i + strlen(opt->strarg) + 3))) {
 
405
                        logg("!Can't allocate memory for pua_cats\n");
 
406
                        ret = 1;
 
407
                        break;
 
408
                    }
 
409
 
 
410
                    logg("# %s", opt->strarg);
 
411
 
 
412
                    sprintf(pua_cats + i, ".%s", opt->strarg);
 
413
                    i += strlen(opt->strarg) + 1;
 
414
                    pua_cats[i] = 0;
 
415
                    opt = opt->nextarg;
 
416
                }
 
417
 
 
418
                if (ret)
 
419
                    break;
 
420
 
 
421
                logg("#\n");
 
422
                pua_cats[i] = '.';
 
423
                pua_cats[i + 1] = 0;
 
424
            }
 
425
 
 
426
            if(pua_cats) {
 
427
                if((ret = cl_engine_set_str(engine, CL_ENGINE_PUA_CATEGORIES, pua_cats))) {
 
428
                    logg("!cli_engine_set_str(CL_ENGINE_PUA_CATEGORIES) failed: %s\n", cl_strerror(ret));
 
429
                    free(pua_cats);
 
430
                    ret = 1;
 
431
                    break;
 
432
                }
 
433
                free(pua_cats);
 
434
            }
 
435
        } else {
 
436
            logg("#Not loading PUA signatures.\n");
 
437
        }
 
438
 
 
439
        if (optget(opts, "StatsEnabled")->enabled) {
 
440
            cl_engine_stats_enable(engine);
 
441
        }
 
442
 
 
443
        if (optget(opts, "StatsPEDisabled")->enabled) {
 
444
            cl_engine_set_num(engine, CL_ENGINE_DISABLE_PE_STATS, 1);
 
445
        }
 
446
 
 
447
        if (optget(opts, "StatsTimeout")->enabled) {
 
448
            cl_engine_set_num(engine, CL_ENGINE_STATS_TIMEOUT, optget(opts, "StatsTimeout")->numarg);
 
449
        }
 
450
 
 
451
        if (optget(opts, "StatsHostID")->enabled) {
 
452
            char *p = optget(opts, "StatsHostID")->strarg;
 
453
 
 
454
            if (strcmp(p, "default")) {
 
455
                if (!strcmp(p, "none")) {
 
456
                    cl_engine_set_clcb_stats_get_hostid(engine, NULL);
 
457
                } else if (!strcmp(p, "anonymous")) {
 
458
                    strcpy(hostid, STATS_ANON_UUID);
 
459
                } else {
 
460
                    if (strlen(p) > 36) {
 
461
                        logg("!Invalid HostID\n");
 
462
                        cl_engine_set_clcb_stats_submit(engine, NULL);
 
463
                        cl_engine_free(engine);
 
464
                        ret = 1;
 
465
                        break;
 
466
                    }
 
467
 
 
468
                    strcpy(hostid, p);
 
469
                }
 
470
 
 
471
                cl_engine_set_clcb_stats_get_hostid(engine, get_hostid);
 
472
            }
 
473
        }
 
474
 
 
475
        if(optget(opts, "OfficialDatabaseOnly")->enabled) {
 
476
            dboptions |= CL_DB_OFFICIAL_ONLY;
 
477
            logg("#Only loading official signatures.\n");
 
478
        }
 
479
 
 
480
        /* set the temporary dir */
 
481
        if((opt = optget(opts, "TemporaryDirectory"))->enabled) {
 
482
            if((ret = cl_engine_set_str(engine, CL_ENGINE_TMPDIR, opt->strarg))) {
 
483
                logg("!cli_engine_set_str(CL_ENGINE_TMPDIR) failed: %s\n", cl_strerror(ret));
 
484
                ret = 1;
 
485
                break;
 
486
            }
 
487
        }
 
488
 
 
489
        cl_engine_set_clcb_hash(engine, hash_callback);
 
490
 
 
491
        if(optget(opts, "LeaveTemporaryFiles")->enabled)
 
492
            cl_engine_set_num(engine, CL_ENGINE_KEEPTMP, 1);
 
493
 
 
494
        if(optget(opts, "ForceToDisk")->enabled)
 
495
            cl_engine_set_num(engine, CL_ENGINE_FORCETODISK, 1);
 
496
 
 
497
        if(optget(opts, "PhishingSignatures")->enabled)
 
498
            dboptions |= CL_DB_PHISHING;
 
499
        else
 
500
            logg("#Not loading phishing signatures.\n");
 
501
 
 
502
        if(optget(opts,"Bytecode")->enabled) {
 
503
            dboptions |= CL_DB_BYTECODE;
 
504
            if((opt = optget(opts,"BytecodeSecurity"))->enabled) {
 
505
                enum bytecode_security s;
 
506
 
 
507
                if (!strcmp(opt->strarg, "TrustSigned")) {
 
508
                    s = CL_BYTECODE_TRUST_SIGNED;
 
509
                    logg("#Bytecode: Security mode set to \"TrustSigned\".\n");
 
510
                } else if (!strcmp(opt->strarg, "Paranoid")) {
 
511
                    s = CL_BYTECODE_TRUST_NOTHING;
 
512
                    logg("#Bytecode: Security mode set to \"Paranoid\".\n");
 
513
                } else {
 
514
                    logg("!Unable to parse bytecode security setting:%s\n",
 
515
                        opt->strarg);
 
516
                    ret = 1;
 
517
                    break;
 
518
                }
 
519
 
 
520
                if ((ret = cl_engine_set_num(engine, CL_ENGINE_BYTECODE_SECURITY, s))) {
 
521
                    logg("^Invalid bytecode security setting %s: %s\n", opt->strarg, cl_strerror(ret));
 
522
                    ret = 1;
 
523
                    break;
 
524
                }
 
525
            }
 
526
            if((opt = optget(opts,"BytecodeUnsigned"))->enabled) {
 
527
                dboptions |= CL_DB_BYTECODE_UNSIGNED;
 
528
                logg("#Bytecode: Enabled support for unsigned bytecode.\n");
 
529
            }
 
530
 
 
531
            if((opt = optget(opts,"BytecodeMode"))->enabled) {
 
532
                enum bytecode_mode mode;
 
533
 
 
534
                if (!strcmp(opt->strarg, "ForceJIT"))
 
535
                    mode = CL_BYTECODE_MODE_JIT;
 
536
                else if(!strcmp(opt->strarg, "ForceInterpreter"))
 
537
                    mode = CL_BYTECODE_MODE_INTERPRETER;
 
538
                else if(!strcmp(opt->strarg, "Test"))
 
539
                    mode = CL_BYTECODE_MODE_TEST;
 
540
                else
 
541
                    mode = CL_BYTECODE_MODE_AUTO;
 
542
                cl_engine_set_num(engine, CL_ENGINE_BYTECODE_MODE, mode);
 
543
            }
 
544
 
 
545
            if((opt = optget(opts,"BytecodeTimeout"))->enabled) {
 
546
                cl_engine_set_num(engine, CL_ENGINE_BYTECODE_TIMEOUT, opt->numarg);
 
547
            }
 
548
        } else {
 
549
            logg("#Bytecode support disabled.\n");
 
550
        }
 
551
 
 
552
        if(optget(opts,"PhishingScanURLs")->enabled)
 
553
            dboptions |= CL_DB_PHISHING_URLS;
 
554
        else
 
555
            logg("#Disabling URL based phishing detection.\n");
 
556
 
 
557
        if(optget(opts,"DevACOnly")->enabled) {
 
558
            logg("#Only using the A-C matcher.\n");
 
559
            cl_engine_set_num(engine, CL_ENGINE_AC_ONLY, 1);
 
560
        }
 
561
 
 
562
        if((opt = optget(opts, "DevACDepth"))->enabled) {
 
563
            cl_engine_set_num(engine, CL_ENGINE_AC_MAXDEPTH, opt->numarg);
 
564
            logg("#Max A-C depth set to %u\n", (unsigned int) opt->numarg);
 
565
        }
 
566
 
 
567
        if((ret = cl_load(dbdir, engine, &sigs, dboptions))) {
 
568
            logg("!%s\n", cl_strerror(ret));
 
569
            ret = 1;
 
570
            break;
 
571
        }
 
572
 
 
573
        if (optget(opts, "DisableCertCheck")->enabled)
 
574
            engine->dconf->pe |= PE_CONF_DISABLECERT;
 
575
 
 
576
        logg("#Loaded %u signatures.\n", sigs);
 
577
 
 
578
        if((ret = cl_engine_compile(engine)) != 0) {
 
579
            logg("!Database initialization error: %s\n", cl_strerror(ret));
 
580
            ret = 1;
 
581
            break;
 
582
        }
 
583
 
 
584
        if(tcpsock) {
 
585
            int *t;
 
586
 
 
587
            opt = optget(opts, "TCPAddr");
 
588
            if (opt->enabled) {
 
589
                int breakout = 0;
 
590
 
 
591
                while (opt && opt->strarg) {
 
592
                    char *ipaddr = (!strcmp(opt->strarg, "all") ? NULL : opt->strarg);
 
593
 
 
594
                    if (tcpserver(&lsockets, &nlsockets, ipaddr, opts) == -1) {
 
595
                        ret = 1;
 
596
                        breakout = 1;
 
597
                        break;
 
598
                    }
 
599
 
 
600
                    opt = opt->nextarg;
 
601
                }
 
602
 
 
603
                if (breakout)
 
604
                    break;
 
605
            } else {
 
606
                if (tcpserver(&lsockets, &nlsockets, NULL, opts) == -1) {
 
607
                    ret = 1;
 
608
                    break;
 
609
                }
 
610
            }
 
611
        }
 
612
#ifndef _WIN32
 
613
        if(localsock) {
 
614
            int *t;
 
615
            mode_t sock_mode, umsk = umask(0777); /* socket is created with 000 to avoid races */
 
616
 
 
617
            t = realloc(lsockets, sizeof(int) * (nlsockets + 1));
 
618
            if (!(t)) {
 
619
                ret = 1;
 
620
                break;
 
621
            }
 
622
            lsockets = t;
 
623
 
 
624
            if ((lsockets[nlsockets] = localserver(opts)) == -1) {
 
625
                ret = 1;
 
626
                umask(umsk);
 
627
                break;
 
628
            }
 
629
            umask(umsk); /* restore umask */
 
630
 
 
631
            if(optget(opts, "LocalSocketGroup")->enabled) {
 
632
                char *gname = optget(opts, "LocalSocketGroup")->strarg, *end;
 
633
                gid_t sock_gid = strtol(gname, &end, 10);
 
634
 
 
635
                if(*end) {
 
636
                    struct group *pgrp = getgrnam(gname);
 
637
 
 
638
                    if(!pgrp) {
 
639
                        logg("!Unknown group %s\n", gname);
 
640
                        ret = 1;
 
641
                        break;
 
642
                    }
 
643
 
 
644
                    sock_gid = pgrp->gr_gid;
 
645
                }
 
646
                if(chown(optget(opts, "LocalSocket")->strarg, -1, sock_gid)) {
 
647
                    logg("!Failed to change socket ownership to group %s\n", gname);
 
648
                    ret = 1;
 
649
                    break;
 
650
                }
 
651
            }
 
652
            if(optget(opts, "LocalSocketMode")->enabled) {
 
653
                char *end;
 
654
 
 
655
                sock_mode = strtol(optget(opts, "LocalSocketMode")->strarg, &end, 8);
 
656
 
 
657
                if(*end) {
 
658
                    logg("!Invalid LocalSocketMode %s\n", optget(opts, "LocalSocketMode")->strarg);
 
659
                    ret = 1;
 
660
                    break;
 
661
                }
 
662
            } else {
 
663
                sock_mode = 0777 /* & ~umsk*/; /* conservative default: umask was 0 in clamd < 0.96 */
 
664
            }
 
665
 
 
666
            if(chmod(optget(opts, "LocalSocket")->strarg, sock_mode & 0666)) {
 
667
                logg("!Cannot set socket permission to %s\n", optget(opts, "LocalSocketMode")->strarg);
 
668
                ret = 1;
 
669
                break;
 
670
            }
 
671
 
 
672
            nlsockets++;
 
673
        }
 
674
 
 
675
        /* fork into background */
 
676
        if(!optget(opts, "Foreground")->enabled) {
 
677
#ifdef C_BSD        
 
678
            /* workaround for OpenBSD bug, see https://wwws.clamav.net/bugzilla/show_bug.cgi?id=885 */
 
679
            for(ret=0;ret<nlsockets;ret++) {
 
680
                if (fcntl(lsockets[ret], F_SETFL, fcntl(lsockets[ret], F_GETFL) | O_NONBLOCK) == -1) {
 
681
                    logg("!fcntl for lsockets[] failed\n");
 
682
                    close(lsockets[ret]);
 
683
                    ret = 1;
 
684
                    break;
 
685
                }
 
686
            }
 
687
#endif
 
688
            gengine = engine;
 
689
            atexit(free_engine);
 
690
            if(daemonize() == -1) {
 
691
                logg("!daemonize() failed: %s\n", strerror(errno));
 
692
                ret = 1;
 
693
                break;
 
694
            }
 
695
            gengine = NULL;
 
696
#ifdef C_BSD
 
697
            for(ret=0;ret<nlsockets;ret++) {
 
698
                if (fcntl(lsockets[ret], F_SETFL, fcntl(lsockets[ret], F_GETFL) & ~O_NONBLOCK) == -1) {
 
699
                    logg("!fcntl for lsockets[] failed\n");
 
700
                    close(lsockets[ret]);
 
701
                    ret = 1;
 
702
                    break;
 
703
                }
 
704
            }
 
705
#endif
 
706
            if(!debug_mode)
 
707
                if(chdir("/") == -1)
 
708
                    logg("^Can't change current working directory to root\n");
 
709
 
 
710
        } else {
 
711
            foreground = 1;
 
712
        }
 
713
#endif
 
714
 
 
715
        if (nlsockets == 0) {
 
716
            logg("!Not listening on any interfaces\n");
 
717
            ret = 1;
 
718
            break;
 
719
        }
 
720
 
 
721
        ret = recvloop_th(lsockets, nlsockets, engine, dboptions, opts);
 
722
 
 
723
    } while (0);
 
724
 
 
725
    logg("*Closing the main socket%s.\n", (nlsockets > 1) ? "s" : "");
 
726
 
 
727
    for (i = 0; i < nlsockets; i++) {
 
728
        closesocket(lsockets[i]);
 
729
    }
 
730
 
 
731
#ifndef _WIN32
 
732
    if(nlsockets && localsock) {
 
733
        opt = optget(opts, "LocalSocket");
 
734
 
 
735
        if(unlink(opt->strarg) == -1)
 
736
            logg("!Can't unlink the socket file %s\n", opt->strarg);
 
737
        else
 
738
            logg("Socket file removed.\n");
 
739
    }
 
740
#endif
 
741
 
 
742
    free(lsockets);
 
743
 
 
744
    logg_close();
 
745
    optfree(opts);
 
746
 
 
747
    cl_cleanup_crypto();
 
748
 
 
749
    return ret;
 
750
}
 
751
 
 
752
int is_valid_hostid(void)
 
753
{
 
754
    int count, i;
 
755
 
 
756
    if (strlen(hostid) != 36)
 
757
        return 0;
 
758
 
 
759
    count=0;
 
760
    for (i=0; i < 36; i++)
 
761
        if (hostid[i] == '-')
 
762
            count++;
 
763
 
 
764
    if (count != 4)
 
765
        return 0;
 
766
 
 
767
    if (hostid[8] != '-' || hostid[13] != '-' || hostid[18] != '-' || hostid[23] != '-')
 
768
        return 0;
 
769
 
 
770
    return 1;
 
771
}
 
772
 
 
773
char *get_hostid(void *cbdata)
 
774
{
 
775
    if (!strcmp(hostid, "none"))
 
776
        return NULL;
 
777
 
 
778
    if (!is_valid_hostid())
 
779
        return strdup(STATS_ANON_UUID);
 
780
 
 
781
    return strdup(hostid);
 
782
}