git-svn: trunk@4520
aCaB authored on 2008/12/05 01:26:13... | ... |
@@ -52,7 +52,7 @@ struct smfiDesc descr = { |
52 | 52 |
NULL, /* SMTP HELO command filter */ |
53 | 53 |
NULL, /* envelope sender filter */ |
54 | 54 |
NULL, /* envelope recipient filter */ |
55 |
- NULL, /* header filter */ |
|
55 |
+ clamfi_header, /* header filter */ |
|
56 | 56 |
NULL, /* end of header */ |
57 | 57 |
clamfi_body, /* body block */ |
58 | 58 |
clamfi_eom, /* end of message */ |
... | ... |
@@ -246,10 +246,11 @@ int main(int argc, char **argv) { |
246 | 246 |
logg("^Can't change current working directory to root\n"); |
247 | 247 |
} |
248 | 248 |
|
249 |
- freecfg(copt); |
|
250 | 249 |
|
251 | 250 |
ret = smfi_main(); |
252 | 251 |
|
252 |
+ freecfg(copt); |
|
253 |
+ |
|
253 | 254 |
logg_close(); |
254 | 255 |
cpool_free(); |
255 | 256 |
return ret; |
... | ... |
@@ -43,35 +43,28 @@ struct CLAMFI { |
43 | 43 |
int local; |
44 | 44 |
int main; |
45 | 45 |
int alt; |
46 |
- unsigned int altsz; |
|
46 |
+ unsigned int totsz; |
|
47 | 47 |
unsigned int bufsz; |
48 | 48 |
}; |
49 | 49 |
|
50 | 50 |
|
51 |
-#define FREECF freecf(ctx, cf) |
|
52 |
- |
|
53 |
-static void freecf(SMFICTX *ctx, struct CLAMFI *cf) { |
|
54 |
- close(cf->main); |
|
55 |
- close(cf->alt); |
|
56 |
- smfi_setpriv(ctx, NULL); |
|
57 |
- free(cf); |
|
58 |
-} |
|
59 |
- |
|
60 |
- |
|
61 | 51 |
static sfsistat sendchunk(struct CLAMFI *cf, unsigned char *bodyp, size_t len, SMFICTX *ctx) { |
62 |
- if(cf->altsz > maxfilesize) |
|
52 |
+ if(cf->totsz > maxfilesize) |
|
63 | 53 |
return SMFIS_CONTINUE; /* FIXME: SMFIS_SKIP needs negotiation (only for _body() */ |
64 | 54 |
|
65 |
- if(cf->altsz + len > maxfilesize) |
|
66 |
- len = maxfilesize - cf->altsz; |
|
55 |
+ if(cf->totsz + len > maxfilesize) |
|
56 |
+ len = maxfilesize - cf->totsz; |
|
67 | 57 |
|
68 | 58 |
if(cf->local) { |
69 | 59 |
while(len) { |
70 | 60 |
int n = write(cf->alt, bodyp, len); |
71 | 61 |
|
72 | 62 |
if (n==-1) { |
73 |
- logg("!clamfi_body: Failed to write temporary file\n"); |
|
74 |
- FREECF; |
|
63 |
+ logg("!Failed to write temporary file\n"); |
|
64 |
+ close(cf->main); |
|
65 |
+ close(cf->alt); |
|
66 |
+ smfi_setpriv(ctx, NULL); |
|
67 |
+ free(cf); |
|
75 | 68 |
return SMFIS_TEMPFAIL; |
76 | 69 |
} |
77 | 70 |
len -= n; |
... | ... |
@@ -90,35 +83,37 @@ static sfsistat sendchunk(struct CLAMFI *cf, unsigned char *bodyp, size_t len, S |
90 | 90 |
memcpy(cf->buffer, &bodyp[CLAMFIBUFSZ - cf->bufsz], len); |
91 | 91 |
cf->bufsz = len; |
92 | 92 |
} else { |
93 |
- sendfailed = nc_send(cf->alt, cf->buffer, cf->bufsz); |
|
94 |
- sendfailed += nc_send(cf->alt, bodyp, len); |
|
93 |
+ if(nc_send(cf->alt, cf->buffer, cf->bufsz) || nc_send(cf->alt, bodyp, len)) |
|
94 |
+ sendfailed = 1; |
|
95 | 95 |
cf->bufsz = 0; |
96 | 96 |
} |
97 | 97 |
if(sendfailed) { |
98 |
- logg("!clamfi_body: Streaming failed\n"); |
|
99 |
- FREECF; |
|
98 |
+ logg("!Streaming failed\n"); |
|
99 |
+ close(cf->main); |
|
100 |
+ smfi_setpriv(ctx, NULL); |
|
101 |
+ free(cf); |
|
100 | 102 |
return SMFIS_TEMPFAIL; |
101 | 103 |
} |
102 | 104 |
} |
103 |
- cf->altsz += len; |
|
105 |
+ cf->totsz += len; |
|
104 | 106 |
return SMFIS_CONTINUE; |
105 | 107 |
} |
106 | 108 |
|
107 | 109 |
|
108 |
-sfsistat clamfi_body(SMFICTX *ctx, unsigned char *bodyp, size_t len) { |
|
110 |
+sfsistat clamfi_header(SMFICTX *ctx, char *headerf, char *headerv) { |
|
109 | 111 |
struct CLAMFI *cf; |
112 |
+ sfsistat ret; |
|
110 | 113 |
|
111 | 114 |
if(!(cf = (struct CLAMFI *)smfi_getpriv(ctx))) { |
112 |
- sfsistat ret; |
|
113 | 115 |
cf = (struct CLAMFI *)malloc(sizeof(*cf)); |
114 | 116 |
if(!cf) { |
115 |
- logg("!clamfi_body: Failed to allocate CLAMFI struct\n"); |
|
117 |
+ logg("!Failed to allocate CLAMFI struct\n"); |
|
116 | 118 |
return SMFIS_TEMPFAIL; |
117 | 119 |
} |
118 |
- cf->altsz = 0; |
|
119 |
- cf->bufsz = 0; |
|
120 |
+ cf->totsz = 0; |
|
121 |
+ cf->totsz = 0; |
|
120 | 122 |
if(nc_connect_rand(&cf->main, &cf->alt, &cf->local)) { |
121 |
- logg("!clamfi_body: Failed to initiate streaming/fdpassing\n"); |
|
123 |
+ logg("!Failed to initiate streaming/fdpassing\n"); |
|
122 | 124 |
free(cf); |
123 | 125 |
return SMFIS_TEMPFAIL; |
124 | 126 |
} |
... | ... |
@@ -126,6 +121,21 @@ sfsistat clamfi_body(SMFICTX *ctx, unsigned char *bodyp, size_t len) { |
126 | 126 |
if((ret = sendchunk(cf, (unsigned char *)"From clamav-milter\n", 19, ctx)) != SMFIS_CONTINUE) |
127 | 127 |
return ret; |
128 | 128 |
} |
129 |
+ if((ret = sendchunk(cf, (unsigned char *)headerf, strlen(headerf), ctx)) != SMFIS_CONTINUE) |
|
130 |
+ return ret; |
|
131 |
+ if((ret = sendchunk(cf, (unsigned char *)": ", 2, ctx)) != SMFIS_CONTINUE) |
|
132 |
+ return ret; |
|
133 |
+ if((ret = sendchunk(cf, (unsigned char *)headerv, strlen(headerv), ctx)) != SMFIS_CONTINUE) |
|
134 |
+ return ret; |
|
135 |
+ return sendchunk(cf, (unsigned char *)"\r\n", 2, ctx); |
|
136 |
+} |
|
137 |
+ |
|
138 |
+ |
|
139 |
+sfsistat clamfi_body(SMFICTX *ctx, unsigned char *bodyp, size_t len) { |
|
140 |
+ struct CLAMFI *cf; |
|
141 |
+ |
|
142 |
+ if(!(cf = (struct CLAMFI *)smfi_getpriv(ctx))) |
|
143 |
+ return SMFIS_CONTINUE; /* whatever */ |
|
129 | 144 |
return sendchunk(cf, bodyp, len, ctx); |
130 | 145 |
} |
131 | 146 |
|
... | ... |
@@ -139,41 +149,29 @@ sfsistat clamfi_eom(SMFICTX *ctx) { |
139 | 139 |
return SMFIS_CONTINUE; /* whatever */ |
140 | 140 |
|
141 | 141 |
if(cf->local) { |
142 |
- struct iovec iov[1]; |
|
143 |
- struct msghdr msg; |
|
144 |
- struct cmsghdr *cmsg; |
|
145 |
- unsigned char fdbuf[CMSG_SPACE(sizeof(int))]; |
|
146 |
- char dummy[]=""; |
|
147 |
- |
|
148 | 142 |
if(nc_send(cf->main, "nFILDES\n", 8)) { |
149 |
- logg("!clamfi_eom: FD scan request failed\n"); |
|
150 |
- FREECF; |
|
143 |
+ logg("!FD scan request failed\n"); |
|
144 |
+ close(cf->alt); |
|
145 |
+ smfi_setpriv(ctx, NULL); |
|
146 |
+ free(cf); |
|
151 | 147 |
return SMFIS_TEMPFAIL; |
152 | 148 |
} |
153 | 149 |
|
154 | 150 |
lseek(cf->alt, 0, SEEK_SET); |
155 |
- iov[0].iov_base = dummy; |
|
156 |
- iov[0].iov_len = 1; |
|
157 |
- memset(&msg, 0, sizeof(msg)); |
|
158 |
- msg.msg_control = fdbuf; |
|
159 |
- msg.msg_iov = iov; |
|
160 |
- msg.msg_iovlen = 1; |
|
161 |
- msg.msg_controllen = CMSG_LEN(sizeof(int)); |
|
162 |
- cmsg = CMSG_FIRSTHDR(&msg); |
|
163 |
- cmsg->cmsg_len = CMSG_LEN(sizeof(int)); |
|
164 |
- cmsg->cmsg_level = SOL_SOCKET; |
|
165 |
- cmsg->cmsg_type = SCM_RIGHTS; |
|
166 |
- *(int *)CMSG_DATA(cmsg) = cf->alt; |
|
167 |
- if(sendmsg(cf->main, &msg, 0) == -1) { |
|
168 |
- /* FIXME: nonblock code needed (?) */ |
|
169 |
- logg("!clamfi_eom: FD send failed\n"); |
|
170 |
- FREECF; |
|
151 |
+ |
|
152 |
+ if(nc_sendmsg(cf->main, cf->alt) == -1) { |
|
153 |
+ logg("!FD send failed\n"); |
|
154 |
+ close(cf->alt); |
|
155 |
+ smfi_setpriv(ctx, NULL); |
|
156 |
+ free(cf); |
|
171 | 157 |
return SMFIS_TEMPFAIL; |
172 | 158 |
} |
173 | 159 |
} else { |
174 | 160 |
if(cf->bufsz && nc_send(cf->alt, cf->buffer, cf->bufsz)) { |
175 |
- logg("!clamfi_eom: Flushing failed\n"); |
|
176 |
- FREECF; |
|
161 |
+ logg("!Failed to flush STREAM\n"); |
|
162 |
+ close(cf->main); |
|
163 |
+ smfi_setpriv(ctx, NULL); |
|
164 |
+ free(cf); |
|
177 | 165 |
return SMFIS_TEMPFAIL; |
178 | 166 |
} |
179 | 167 |
close(cf->alt); |
... | ... |
@@ -181,23 +179,27 @@ sfsistat clamfi_eom(SMFICTX *ctx) { |
181 | 181 |
|
182 | 182 |
reply = nc_recv(cf->main); |
183 | 183 |
|
184 |
- if(cf->local) close(cf->alt); |
|
185 |
- close(cf->main); |
|
186 |
- close(cf->alt); |
|
187 |
- smfi_setpriv(ctx, NULL); |
|
188 |
- free(cf); |
|
184 |
+ if(cf->local) |
|
185 |
+ close(cf->alt); |
|
189 | 186 |
|
190 | 187 |
if(!reply) { |
191 |
- logg("!clamfi_eom: no reply to scan request\n"); |
|
188 |
+ logg("!No reply from clamd\n"); |
|
189 |
+ smfi_setpriv(ctx, NULL); |
|
190 |
+ free(cf); |
|
192 | 191 |
return SMFIS_TEMPFAIL; |
193 | 192 |
} |
193 |
+ close(cf->main); |
|
194 |
+ smfi_setpriv(ctx, NULL); |
|
195 |
+ free(cf); |
|
196 |
+ |
|
194 | 197 |
len = strlen(reply); |
198 |
+ logg("^reply: %s\n", reply); |
|
195 | 199 |
if(len>5 && !strcmp(reply + len - 5, ": OK\n")) |
196 | 200 |
ret = SMFIS_ACCEPT; |
197 | 201 |
else if (len>7 && !strcmp(reply + len - 7, " FOUND\n")) |
198 | 202 |
ret = SMFIS_REJECT; |
199 | 203 |
else { |
200 |
- logg("!clamfi_eom: unknown reply from clamd\n"); |
|
204 |
+ logg("!Unknown reply from clamd\n"); |
|
201 | 205 |
ret = SMFIS_TEMPFAIL; |
202 | 206 |
} |
203 | 207 |
|
... | ... |
@@ -43,18 +43,26 @@ |
43 | 43 |
/* for recv */ |
44 | 44 |
long readtimeout; |
45 | 45 |
|
46 |
- |
|
47 | 46 |
int nc_socket(struct CP_ENTRY *cpe) { |
48 | 47 |
int flags, s = socket(cpe->server->sa_family, SOCK_STREAM, 0); |
48 |
+ char er[256]; |
|
49 | 49 |
|
50 |
- if (s == -1) return -1; |
|
50 |
+ if (s == -1) { |
|
51 |
+ strerror_r(errno, er, sizeof(er)); |
|
52 |
+ logg("!Failed to create socket: %s\n", er); |
|
53 |
+ return -1; |
|
54 |
+ } |
|
51 | 55 |
flags = fcntl(s, F_GETFL, 0); |
52 | 56 |
if (flags == -1) { |
57 |
+ strerror_r(errno, er, sizeof(er)); |
|
58 |
+ logg("!fcntl_get failed: %s\n", er); |
|
53 | 59 |
close(s); |
54 | 60 |
return -1; |
55 | 61 |
} |
56 | 62 |
flags |= O_NONBLOCK; |
57 | 63 |
if (fcntl(s, F_SETFL, flags) == -1) { |
64 |
+ strerror_r(errno, er, sizeof(er)); |
|
65 |
+ logg("!fcntl_set failed: %s\n", er); |
|
58 | 66 |
close(s); |
59 | 67 |
return -1; |
60 | 68 |
} |
... | ... |
@@ -66,9 +74,12 @@ int nc_connect(int s, struct CP_ENTRY *cpe) { |
66 | 66 |
time_t timeout = time(NULL) + TIMEOUT; |
67 | 67 |
int res = connect(s, cpe->server, cpe->socklen); |
68 | 68 |
struct timeval tv; |
69 |
+ char er[256]; |
|
69 | 70 |
|
70 | 71 |
if (!res) return 0; |
71 | 72 |
if (errno != EINPROGRESS) { |
73 |
+ strerror_r(errno, er, sizeof(er)); |
|
74 |
+ logg("!connect failed: %s\n", er); |
|
72 | 75 |
close(s); |
73 | 76 |
return -1; |
74 | 77 |
} |
... | ... |
@@ -85,16 +96,18 @@ int nc_connect(int s, struct CP_ENTRY *cpe) { |
85 | 85 |
res = select(s+1, NULL, &fds, NULL, &tv); |
86 | 86 |
if(res < 1) { |
87 | 87 |
time_t now; |
88 |
+ |
|
88 | 89 |
if (res == -1 && errno == EINTR && ((now = time(NULL)) < timeout)) { |
89 | 90 |
tv.tv_sec = timeout - now; |
90 | 91 |
tv.tv_usec = 0; |
91 | 92 |
continue; |
92 | 93 |
} |
94 |
+ logg("!Failed to establish a connection to clamd\n"); |
|
93 | 95 |
close(s); |
94 | 96 |
return -1; |
95 | 97 |
} |
96 | 98 |
if (getsockopt(s, SOL_SOCKET, SO_ERROR, &s_err, &s_len) || s_err) { |
97 |
- logg("!getsockopt failed: %s\n", strerror(s_err)); |
|
99 |
+ logg("!Failed to establish a connection to clamd\n"); |
|
98 | 100 |
close(s); |
99 | 101 |
return -1; |
100 | 102 |
} |
... | ... |
@@ -108,6 +121,7 @@ int nc_send(int s, const void *buf, size_t len) { |
108 | 108 |
int res = send(s, buf, len, 0); |
109 | 109 |
time_t timeout = time(NULL) + TIMEOUT; |
110 | 110 |
struct timeval tv; |
111 |
+ char er[256]; |
|
111 | 112 |
|
112 | 113 |
if(res!=-1) { |
113 | 114 |
len-=res; |
... | ... |
@@ -116,6 +130,8 @@ int nc_send(int s, const void *buf, size_t len) { |
116 | 116 |
continue; |
117 | 117 |
} |
118 | 118 |
if(errno != EAGAIN && errno != EWOULDBLOCK) { |
119 |
+ strerror_r(errno, er, sizeof(er)); |
|
120 |
+ logg("!send failed: %s\n", er); |
|
119 | 121 |
close(s); |
120 | 122 |
return 1; |
121 | 123 |
} |
... | ... |
@@ -132,15 +148,13 @@ int nc_send(int s, const void *buf, size_t len) { |
132 | 132 |
res = select(s+1, NULL, &fds, NULL, &tv); |
133 | 133 |
if(res < 1) { |
134 | 134 |
time_t now; |
135 |
+ |
|
135 | 136 |
if (res == -1 && errno == EINTR && ((now = time(NULL)) < timeout)) { |
136 | 137 |
tv.tv_sec = timeout - now; |
137 | 138 |
tv.tv_usec = 0; |
138 | 139 |
continue; |
139 | 140 |
} |
140 |
- close(s); |
|
141 |
- return 1; |
|
142 |
- } |
|
143 |
- if (getsockopt(s, SOL_SOCKET, SO_ERROR, &s_err, &s_len)) { |
|
141 |
+ logg("!Failed stream to clamd\n"); |
|
144 | 142 |
close(s); |
145 | 143 |
return 1; |
146 | 144 |
} |
... | ... |
@@ -153,6 +167,37 @@ int nc_send(int s, const void *buf, size_t len) { |
153 | 153 |
} |
154 | 154 |
|
155 | 155 |
|
156 |
+int nc_sendmsg(int s, int fd) { |
|
157 |
+ struct iovec iov[1]; |
|
158 |
+ struct msghdr msg; |
|
159 |
+ struct cmsghdr *cmsg; |
|
160 |
+ int ret; |
|
161 |
+ unsigned char fdbuf[CMSG_SPACE(sizeof(int))]; |
|
162 |
+ char dummy[]=""; |
|
163 |
+ |
|
164 |
+ iov[0].iov_base = dummy; |
|
165 |
+ iov[0].iov_len = 1; |
|
166 |
+ memset(&msg, 0, sizeof(msg)); |
|
167 |
+ msg.msg_control = fdbuf; |
|
168 |
+ msg.msg_iov = iov; |
|
169 |
+ msg.msg_iovlen = 1; |
|
170 |
+ msg.msg_controllen = CMSG_LEN(sizeof(int)); |
|
171 |
+ cmsg = CMSG_FIRSTHDR(&msg); |
|
172 |
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int)); |
|
173 |
+ cmsg->cmsg_level = SOL_SOCKET; |
|
174 |
+ cmsg->cmsg_type = SCM_RIGHTS; |
|
175 |
+ *(int *)CMSG_DATA(cmsg) = fd; |
|
176 |
+ /* FIXME: nonblock code needed (?) */ |
|
177 |
+ |
|
178 |
+ if((ret = sendmsg(s, &msg, 0)) == -1) { |
|
179 |
+ char er[256]; |
|
180 |
+ strerror_r(errno, er, sizeof(er)); |
|
181 |
+ logg("!clamfi_eom: FD send failed (%s)\n", er); |
|
182 |
+ close(s); |
|
183 |
+ } |
|
184 |
+ return ret; |
|
185 |
+} |
|
186 |
+ |
|
156 | 187 |
char *nc_recv(int s) { |
157 | 188 |
char buf[BUFSIZ], *ret=NULL; |
158 | 189 |
time_t timeout = time(NULL) + readtimeout; |
... | ... |
@@ -169,11 +214,13 @@ char *nc_recv(int s) { |
169 | 169 |
res = select(s+1, &fds, NULL, NULL, &tv); |
170 | 170 |
if(res<1) { |
171 | 171 |
time_t now; |
172 |
+ |
|
172 | 173 |
if (res == -1 && errno == EINTR && ((now = time(NULL)) < timeout)) { |
173 | 174 |
tv.tv_sec = timeout - now; |
174 | 175 |
tv.tv_usec = 0; |
175 |
- continue; |
|
176 |
+ continue; |
|
176 | 177 |
} |
178 |
+ logg("!Failed to read clamd reply\n"); |
|
177 | 179 |
close(s); |
178 | 180 |
return NULL; |
179 | 181 |
} |
... | ... |
@@ -181,7 +228,15 @@ char *nc_recv(int s) { |
181 | 181 |
} |
182 | 182 |
/* FIXME: check for EOL@EObuf ? */ |
183 | 183 |
res = recv(s, buf, sizeof(buf), 0); |
184 |
- if (res==-1 || !(ret = (char *)malloc(res+1))) { |
|
184 |
+ if (res==-1) { |
|
185 |
+ char er[256]; |
|
186 |
+ strerror_r(errno, er, sizeof(er)); |
|
187 |
+ logg("!recv failed after successful select: %s\n", er); |
|
188 |
+ close(s); |
|
189 |
+ return NULL; |
|
190 |
+ } |
|
191 |
+ if(!(ret = (char *)malloc(res+1))) { |
|
192 |
+ logg("!malloc(%d) failed\n", res+1); |
|
185 | 193 |
close(s); |
186 | 194 |
return NULL; |
187 | 195 |
} |
... | ... |
@@ -201,17 +256,21 @@ int nc_connect_entry(struct CP_ENTRY *cpe) { |
201 | 201 |
void nc_ping_entry(struct CP_ENTRY *cpe) { |
202 | 202 |
int s = nc_connect_entry(cpe); |
203 | 203 |
char *reply; |
204 |
+ |
|
204 | 205 |
if (s!=-1 && !nc_send(s, "nPING\n", 6) && (reply = nc_recv(s))) { |
205 | 206 |
cpe->dead = strcmp(reply, "PONG\n")!=0; |
206 |
- free(reply); |
|
207 |
- close(s); |
|
208 | 207 |
} else cpe->dead = 1; |
208 |
+ return; |
|
209 | 209 |
} |
210 | 210 |
|
211 | 211 |
|
212 | 212 |
int nc_connect_rand(int *main, int *alt, int *local) { |
213 | 213 |
struct CP_ENTRY *cpe = cpool_get_rand(); |
214 | 214 |
|
215 |
+ /* FIXME logic is broken here: |
|
216 |
+ 1- we must not fail on the 1st dead socket but keep on trying |
|
217 |
+ 2- we must not set *local unless we enforce local_cpe |
|
218 |
+ */ |
|
215 | 219 |
if(!cpe) return 1; |
216 | 220 |
*local = cpe->local; |
217 | 221 |
if ((*main = nc_connect_entry(cpe)) == -1) return 1; /* FIXME : this should be delayed till eom if local */ |
... | ... |
@@ -234,8 +293,10 @@ int nc_connect_rand(int *main, int *alt, int *local) { |
234 | 234 |
|
235 | 235 |
if(nc_send(*main, "nSTREAM\n", 8) || !(reply = nc_recv(*main)) || !(port = strstr(reply, "PORT"))) { |
236 | 236 |
logg("!Failed to communicate with clamd\n"); |
237 |
- if(reply) free(reply); |
|
238 |
- close(*main); |
|
237 |
+ if(reply) { |
|
238 |
+ free(reply); |
|
239 |
+ close(*main); |
|
240 |
+ } |
|
239 | 241 |
return 1; |
240 | 242 |
} |
241 | 243 |
port+=5; |
... | ... |
@@ -250,7 +311,7 @@ int nc_connect_rand(int *main, int *alt, int *local) { |
250 | 250 |
sa.sa6.sin6_port = htons(nport); |
251 | 251 |
new_cpe.socklen = sizeof(struct sockaddr_in6); |
252 | 252 |
} else { |
253 |
- logg("!WTF WHY AM I DOING HERE???"); |
|
253 |
+ logg("!WTF WHY AM I DOING HERE???\n"); |
|
254 | 254 |
close(*main); |
255 | 255 |
return 1; |
256 | 256 |
} |