Browse code

closing other threads sockets is not a good idea closing other threads sockets is not a good idea closing other threads sockets is not a good idea closing other threads sockets is not a good idea closing other threads sockets is not a good idea closing other threads sockets is not a good idea closing other threads sockets is not a good idea closing other threads sockets is not a good idea

git-svn: trunk@4520

aCaB authored on 2008/12/05 01:26:13
Showing 5 changed files
... ...
@@ -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
 
... ...
@@ -7,5 +7,5 @@ uint64_t maxfilesize;
7 7
 
8 8
 sfsistat clamfi_body(SMFICTX *ctx, unsigned char *bodyp, size_t len);
9 9
 sfsistat clamfi_eom(SMFICTX *ctx);
10
-
10
+sfsistat clamfi_header(SMFICTX *ctx, char *headerf, char *headerv);
11 11
 #endif
... ...
@@ -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
 	}
... ...
@@ -7,6 +7,7 @@ void nc_ping_entry(struct CP_ENTRY *cpe);
7 7
 int nc_connect_rand(int *main, int *alt, int *local);
8 8
 int nc_send(int s, const void *buf, size_t len);
9 9
 char *nc_recv(int s);
10
+int nc_sendmsg(int s, int fd);
10 11
 
11 12
 extern long readtimeout;
12 13