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

« back to all changes in this revision

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