~ubuntu-branches/ubuntu/hardy/clamav/hardy-security

« back to all changes in this revision

Viewing changes to clamdscan/client.c

  • Committer: Bazaar Package Importer
  • Author(s): Jamie Strandboge
  • Date: 2009-04-30 14:44:26 UTC
  • mfrom: (0.28.3 sid)
  • Revision ID: james.westby@ubuntu.com-20090430144426-933t29chbo6phaa7
Tags: 0.94.dfsg.2-1ubuntu0.3~hardy4
No change rebuild from backports for use with ClamAV 0.94

Show diffs side-by-side

added added

removed removed

Lines of Context:
26
26
#include <sys/types.h>
27
27
#include <sys/stat.h>
28
28
#include <sys/socket.h>
 
29
#ifdef HAVE_SYS_LIMITS_H
 
30
#include <sys/limits.h>
 
31
#endif
29
32
#include <sys/un.h>
30
33
#include <netinet/in.h>
31
34
#include <arpa/inet.h>
45
48
#include "misc.h"
46
49
#include "str.h"
47
50
#include "client.h"
48
 
 
49
 
#ifdef PF_INET
50
 
# define SOCKET_INET    PF_INET
51
 
#else
52
 
# define SOCKET_INET    AF_INET
53
 
#endif
54
 
 
55
 
/* #define ENABLE_FD_PASSING        FIXME: Doesn't work yet */
 
51
#include "clamd_fdscan.h"
 
52
 
 
53
#define SOCKET_INET     AF_INET
56
54
 
57
55
void move_infected(const char *filename, const struct optstruct *opt);
58
56
int notremoved = 0, notmoved = 0;
 
57
int printinfected = 0;
59
58
 
60
59
static int dsresult(int sockd, const struct optstruct *opt)
61
60
{
83
82
                    *pt = 0;
84
83
                    move_infected(buff, opt);
85
84
                } else {
86
 
                    mprintf("@Broken data format. File not %s.\n", opt_check(opt, "move") ? "moved" : "copied");
 
85
                    logg("!Incorrect output from clamd. File not %s.\n", opt_check(opt, "move") ? "moved" : "copied");
87
86
                }
88
87
 
89
88
            } else if(opt_check(opt, "remove")) {
90
89
                if(!(pt = strrchr(buff, ':'))) {
91
 
                    mprintf("@Broken data format. File not removed.\n");
 
90
                    logg("!Incorrect output from clamd. File not removed.\n");
92
91
                } else {
93
92
                    *pt = 0;
94
93
                    if(unlink(buff)) {
95
 
                        mprintf("~%s: Can't remove.\n", buff);
96
 
                        logg("~%s: Can't remove.\n", buff);
 
94
                        logg("!%s: Can't remove.\n", buff);
97
95
                        notremoved++;
98
96
                    } else {
99
 
                        mprintf("~%s: Removed.\n", buff);
100
97
                        logg("~%s: Removed.\n", buff);
101
98
                    }
102
99
                }
104
101
        }
105
102
 
106
103
        if(strstr(buff, "ERROR\n")) {
107
 
            logg("%s", buff);
 
104
            logg("~%s", buff);
108
105
            waserror = 1;
109
106
        }
110
107
    }
135
132
 
136
133
    ret = dsresult(sockd, opt);
137
134
 
138
 
    if(!ret)
 
135
    if(!ret && !printinfected)
139
136
        logg("~%s: OK\n", filename);
140
137
 
141
138
    return ret;
142
139
}
143
140
 
144
 
#if defined(ENABLE_FD_PASSING) && defined(HAVE_SENDMSG) && (defined(HAVE_ACCRIGHTS_IN_MSGHDR) || defined(HAVE_CONTROL_IN_MSGHDR)) && !defined(C_CYGWIN)
145
 
 
146
 
/* Submitted by Richard Lyons <frob-clamav*webcentral.com.au> */
147
 
static int dsfd(int sockfd, int fd, const struct optstruct *opt)
148
 
{
149
 
        struct iovec iov[1];
150
 
        struct msghdr msg;
151
 
#ifdef HAVE_CONTROL_IN_MSGHDR
152
 
#ifndef CMSG_SPACE
153
 
#define CMSG_SPACE(len)     (_CMSG_ALIGN(sizeof(struct cmsghdr)) + _CMSG_ALIGN(len))
154
 
#endif
155
 
#ifndef CMSG_LEN
156
 
#define CMSG_LEN(len)       (_CMSG_ALIGN(sizeof(struct cmsghdr)) + (len))
157
 
#endif
158
 
        struct cmsghdr *cmsg;
159
 
        char tmp[CMSG_SPACE(sizeof(fd))];
160
 
#endif
161
 
 
162
 
    iov[0].iov_base = "";
163
 
    iov[0].iov_len = 1;
164
 
    memset(&msg, 0, sizeof(msg));
165
 
    msg.msg_iov = iov;
166
 
    msg.msg_iovlen = 1;
167
 
#ifdef HAVE_CONTROL_IN_MSGHDR
168
 
    msg.msg_control = tmp;
169
 
    msg.msg_controllen = sizeof(tmp);
170
 
    cmsg = CMSG_FIRSTHDR(&msg);
171
 
    cmsg->cmsg_level = SOL_SOCKET;
172
 
    cmsg->cmsg_type = SCM_RIGHTS;
173
 
    cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
174
 
    *(int *)CMSG_DATA(cmsg) = fd;
175
 
#endif
176
 
#ifdef HAVE_ACCRIGHTS_IN_MSGHDR
177
 
    msg.msg_accrights = (caddr_t)&fd;
178
 
    msg.msg_accrightslen = sizeof(fd);
179
 
#endif
180
 
    if (sendmsg(sockfd, &msg, 0) != iov[0].iov_len) {
181
 
        logg("^Can't write to the socket.\n");
182
 
        return -1;
183
 
    }
184
 
    return dsresult(sockfd, opt);
185
 
}
186
 
#endif
187
 
 
188
141
static int dsstream(int sockd, const struct optstruct *opt)
189
142
{
190
143
        int wsockd, loopw = 60, bread, port, infected = 0;
242
195
            server.sin_addr.s_addr = peer.sin_addr.s_addr;
243
196
            break;
244
197
        default:
245
 
            mprintf("^Unexpected socket type: %d.\n", peer.sin_family);
 
198
            logg("^Unexpected socket type: %d.\n", peer.sin_family);
246
199
            return -1;
247
200
    }
248
201
 
278
231
    return infected;
279
232
}
280
233
 
 
234
#ifndef PATH_MAX
 
235
#define PATH_MAX 1024
 
236
#endif
 
237
 
281
238
static char *abpath(const char *filename)
282
239
{
283
240
        struct stat foo;
284
 
        char *fullpath, cwd[200];
 
241
        char *fullpath, cwd[PATH_MAX + 1];
285
242
 
286
243
    if(stat(filename, &foo) == -1) {
287
244
        logg("^Can't access file %s\n", filename);
288
245
        perror(filename);
289
246
        return NULL;
290
247
    } else {
291
 
        fullpath = malloc(200 + strlen(filename) + 10);
292
 
#ifdef C_CYGWIN
293
 
        sprintf(fullpath, "%s", filename);
294
 
#else
295
 
        if(!getcwd(cwd, 200)) {
 
248
        fullpath = malloc(PATH_MAX + strlen(filename) + 10);
 
249
        if(!getcwd(cwd, PATH_MAX)) {
296
250
            logg("^Can't get absolute pathname of current working directory.\n");
297
251
            return NULL;
298
252
        }
299
253
        sprintf(fullpath, "%s/%s", cwd, filename);
300
 
#endif
301
254
    }
302
255
 
303
256
    return fullpath;
304
257
}
305
258
 
306
 
static int dconnect(const struct optstruct *opt)
 
259
static int dconnect(const struct optstruct *opt, int *is_unix)
307
260
{
308
261
        struct sockaddr_un server;
309
262
        struct sockaddr_in server2;
313
266
        const char *clamav_conf = opt_arg(opt, "config-file");
314
267
        int sockd;
315
268
 
316
 
 
 
269
    if(is_unix)
 
270
            *is_unix = 0;
317
271
    if(!clamav_conf)
318
272
        clamav_conf = DEFAULT_CFG;
319
273
 
332
286
 
333
287
        server.sun_family = AF_UNIX;
334
288
        strncpy(server.sun_path, cpt->strarg, sizeof(server.sun_path));
 
289
        server.sun_path[sizeof(server.sun_path)-1]='\0';
335
290
 
336
291
        if((sockd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
337
292
            perror("socket()");
347
302
            freecfg(copt);
348
303
            return -1;
349
304
        }
350
 
 
 
305
        if(is_unix)
 
306
                *is_unix = 1;
351
307
    } else if((cpt = cfgopt(copt, "TCPSocket"))->enabled) {
352
308
 
353
309
        if((sockd = socket(SOCKET_INET, SOCK_STREAM, 0)) < 0) {
390
346
    return sockd;
391
347
}
392
348
 
 
349
int get_clamd_version(const struct optstruct *opt)
 
350
{
 
351
        char buff[64];
 
352
        int bread, sockd;
 
353
 
 
354
 
 
355
    if((sockd = dconnect(opt, NULL)) < 0)
 
356
        return 2;
 
357
 
 
358
    if(write(sockd, "VERSION", 7) <= 0) {
 
359
        logg("^Can't write to the socket.\n");
 
360
        close(sockd);
 
361
        return 2;
 
362
    }
 
363
 
 
364
    while((bread = read(sockd, buff, sizeof(buff)-1)) > 0) {
 
365
        buff[bread] = '\0';
 
366
        printf("%s\n", buff);
 
367
    }
 
368
 
 
369
    close(sockd);
 
370
    return 0;
 
371
}
 
372
 
 
373
int reload_clamd_database(const struct optstruct *opt)
 
374
{
 
375
        char buff[64];
 
376
        int bread, sockd;
 
377
 
 
378
 
 
379
    if((sockd = dconnect(opt, NULL)) < 0)
 
380
        return 2;
 
381
 
 
382
    if(write(sockd, "RELOAD", 6) <= 0) {
 
383
        logg("!Can't write to the socket.\n");
 
384
        close(sockd);
 
385
        return 2;
 
386
    }
 
387
 
 
388
    bread = read(sockd, buff, sizeof(buff) - 1);
 
389
    if(bread == -1 || strncmp(buff, "RELOADING", 9)) {
 
390
        logg("!Incorrect reply from clamd\n");
 
391
        close(sockd);
 
392
        return 2;
 
393
    }
 
394
 
 
395
    close(sockd);
 
396
    return 0;
 
397
}
 
398
 
393
399
int client(const struct optstruct *opt, int *infected)
394
400
{
395
 
        char cwd[200], *fullpath;
 
401
        char cwd[PATH_MAX+1], *fullpath;
396
402
        int sockd, ret, errors = 0;
397
403
        struct stat sb;
398
404
        const char *scantype = "CONTSCAN";
406
412
    /* parse argument list */
407
413
    if(opt->filename == NULL || strlen(opt->filename) == 0) {
408
414
        /* scan current directory */
409
 
        if(!getcwd(cwd, 200)) {
 
415
        if(!getcwd(cwd, PATH_MAX)) {
410
416
            logg("^Can't get absolute pathname of current working directory.\n");
411
417
            return 2;
412
418
        }
413
419
 
414
 
        if((sockd = dconnect(opt)) < 0)
 
420
        if((sockd = dconnect(opt, NULL)) < 0)
415
421
            return 2;
416
422
 
417
423
        if((ret = dsfile(sockd, scantype, cwd, opt)) >= 0)
421
427
 
422
428
        close(sockd);
423
429
 
424
 
#if defined(ENABLE_FD_PASSING) && defined(HAVE_SENDMSG) && (defined(HAVE_ACCRIGHTS_IN_MSGHDR) || defined(HAVE_CONTROL_IN_MSGHDR)) && !defined(C_CYGWIN)
425
430
    } else if(!strcmp(opt->filename, "-")) { /* scan data from stdin */
426
 
        if((sockd = dconnect(opt)) < 0)
 
431
        int is_unix;
 
432
        if((sockd = dconnect(opt, &is_unix)) < 0)
427
433
            return 2;
428
434
 
429
 
        if((ret = dsfd(sockd, 0, opt)) >= 0)
430
 
            *infected += ret;
431
 
        else
432
 
            errors++;
433
 
 
434
 
        close(sockd);
 
435
        if(opt_check(opt,"fdpass")) {
 
436
#ifndef HAVE_FD_PASSING
 
437
                logg("^File descriptor pass support not compiled in, falling back to stream scan\n");
 
438
                ret = dsstream(sockd, opt);
435
439
#else
436
 
    } else if(!strcmp(opt->filename, "-")) { /* scan data from stdin */
437
 
        if((sockd = dconnect(opt)) < 0)
438
 
            return 2;
439
 
 
440
 
        if((ret = dsstream(sockd, opt)) >= 0)
441
 
            *infected += ret;
442
 
        else
443
 
            errors++;
444
 
 
445
 
        close(sockd);
 
440
                if(!is_unix) {
 
441
                        logg("^File descriptor passing can only work on local (unix) sockets! Falling back to stream scan\n");
 
442
                        /* fall back to stream */
 
443
                        ret = dsstream(sockd, opt);
 
444
                } else {
 
445
                        char buff[4096];
 
446
                        memset(buff, 0, sizeof(buff));
 
447
                        ret = clamd_fdscan(sockd, 0, buff, sizeof(buff));
 
448
                        if(ret == 1 || ret == -1)
 
449
                            logg("fd: %s%s\n",buff, ret == 1 ? " FOUND" : " ERROR");
 
450
                        else if(!printinfected)
 
451
                            logg("fd: OK\n");
 
452
                }
446
453
#endif
 
454
        } else
 
455
                ret = dsstream(sockd, opt);
 
456
        if(ret >= 0)
 
457
            *infected += ret;
 
458
        else
 
459
            errors++;
 
460
 
 
461
        close(sockd);
447
462
 
448
463
    } else {
449
464
        int x;
469
484
                switch(sb.st_mode & S_IFMT) {
470
485
                    case S_IFREG:
471
486
                    case S_IFDIR:
472
 
                        if((sockd = dconnect(opt)) < 0)
 
487
                        if((sockd = dconnect(opt, NULL)) < 0)
473
488
                            return 2;
474
489
 
475
490
                        if((ret = dsfile(sockd, scantype, fullpath, opt)) >= 0)