1 #include "links.h"
2 
3 #ifndef DISABLE_SMB
4 
5 #define SMBCLIENT	0
6 #define SMBC		1
7 #define N_CLIENTS	2
8 
9 static int smb_client = 0;
10 
11 #define CLIENT_NOT_FOUND_STRING	"client not found"
12 
13 struct smb_connection_info {
14 	int client;
15 	int list;
16 	int cl;
17 	int ntext;
18 	unsigned char text[1];
19 };
20 
21 static void smb_got_data(struct connection *);
22 static void smb_got_text(struct connection *);
23 static void end_smb_connection(struct connection *);
24 
smb_func(struct connection * c)25 void smb_func(struct connection *c)
26 {
27 	int i;
28 	int po[2];
29 	int pe[2];
30 	unsigned char *host, *user, *pass, *port, *data1, *data, *share, *dir;
31 	int datal;
32 	unsigned char *p;
33 	pid_t r;
34 	int rs;
35 	struct smb_connection_info *si;
36 	si = mem_alloc(sizeof(struct smb_connection_info) + 2);
37 	memset(si, 0, sizeof(struct smb_connection_info));
38 	c->info = si;
39 	si->client = smb_client;
40 	host = get_host_name(c->url);
41 	if (!host) {
42 		setcstate(c, S_INTERNAL);
43 		abort_connection(c);
44 		return;
45 	}
46 	if (!(user = get_user_name(c->url))) user = stracpy(cast_uchar "");
47 	if (!(pass = get_pass(c->url))) pass = stracpy(cast_uchar "");
48 	if (!(port = get_port_str(c->url))) port = stracpy(cast_uchar "");
49 	if (!(data1 = get_url_data(c->url))) data1 = cast_uchar "";
50 	data = init_str(), datal = 0;
51 	add_conv_str(&data, &datal, data1, (int)strlen(cast_const_char data1), -2);
52 
53 	for (i = 0; data[i]; i++) if (data[i] < 32 || data[i] == ';' || (data[i] == '"' && smb_client == SMBCLIENT)) {
54 /* ';' shouldn't cause security problems but samba doesn't like it */
55 /* '"' is allowed for smbc */
56 		mem_free(host);
57 		mem_free(port);
58 		mem_free(user);
59 		mem_free(pass);
60 		mem_free(data);
61 		setcstate(c, S_BAD_URL);
62 		abort_connection(c);
63 		return;
64 	}
65 
66 	if ((p = cast_uchar strchr(cast_const_char data, '/'))) share = memacpy(data, p - data), dir = p + 1;
67 	else if (*data) {
68 		if (!c->cache) {
69 			if (get_cache_entry(c->url, &c->cache)) {
70 				mem_free(host);
71 				mem_free(port);
72 				mem_free(user);
73 				mem_free(pass);
74 				mem_free(data);
75 				setcstate(c, S_OUT_OF_MEM);
76 				abort_connection(c);
77 				return;
78 			}
79 			c->cache->refcount--;
80 		}
81 		if (c->cache->redirect) mem_free(c->cache->redirect);
82 		c->cache->redirect = stracpy(c->url);
83 		c->cache->redirect_get = 1;
84 		add_to_strn(&c->cache->redirect, cast_uchar "/");
85 		c->cache->incomplete = 0;
86 		mem_free(host);
87 		mem_free(port);
88 		mem_free(user);
89 		mem_free(pass);
90 		mem_free(data);
91 		setcstate(c, S__OK);
92 		abort_connection(c);
93 		return;
94 	} else share = stracpy(cast_uchar ""), dir = cast_uchar "";
95 	if (!*share) si->list = 1;
96 	else if (!*dir || dir[strlen(cast_const_char dir) - 1] == '/' || dir[strlen(cast_const_char dir) - 1] == '\\') si->list = 2;
97 	if (c_pipe(po)) {
98 		int err = errno;
99 		mem_free(host);
100 		mem_free(port);
101 		mem_free(user);
102 		mem_free(pass);
103 		mem_free(share);
104 		mem_free(data);
105 		setcstate(c, get_error_from_errno(err));
106 		abort_connection(c);
107 		return;
108 	}
109 	if (c_pipe(pe)) {
110 		int err = errno;
111 		mem_free(host);
112 		mem_free(port);
113 		mem_free(user);
114 		mem_free(pass);
115 		mem_free(share);
116 		mem_free(data);
117 		EINTRLOOP(rs, close(po[0]));
118 		EINTRLOOP(rs, close(po[1]));
119 		setcstate(c, get_error_from_errno(err));
120 		abort_connection(c);
121 		return;
122 	}
123 	c->from = 0;
124 	EINTRLOOP(r, fork());
125 	if (r == -1) {
126 		int err = errno;
127 		mem_free(host);
128 		mem_free(port);
129 		mem_free(user);
130 		mem_free(pass);
131 		mem_free(share);
132 		mem_free(data);
133 		EINTRLOOP(rs, close(po[0]));
134 		EINTRLOOP(rs, close(po[1]));
135 		EINTRLOOP(rs, close(pe[0]));
136 		EINTRLOOP(rs, close(pe[1]));
137 		setcstate(c, get_error_from_errno(err));
138 		retry_connection(c);
139 		return;
140 	}
141 	if (!r) {
142 		int n;
143 		unsigned char *v[32];
144 		unsigned char *uphp;
145 		close_fork_tty();
146 		EINTRLOOP(rs, close(1));
147 		if (si->list)
148 			EINTRLOOP(rs, dup2(pe[1], 1));
149 		else
150 			EINTRLOOP(rs, dup2(po[1], 1));
151 		EINTRLOOP(rs, close(2));
152 		EINTRLOOP(rs, dup2(pe[1], 2));
153 		EINTRLOOP(rs, close(0));
154 		EINTRLOOP(rs, open("/dev/null", O_RDONLY));
155 		EINTRLOOP(rs, close(po[0]));
156 		EINTRLOOP(rs, close(pe[0]));
157 		EINTRLOOP(rs, close(po[1]));
158 		EINTRLOOP(rs, close(pe[1]));
159 		n = 0;
160 		switch (si->client) {
161 		case SMBCLIENT:
162 			v[n++] = cast_uchar "smbclient";
163 			if (!*share) {
164 				v[n++] = cast_uchar "-L";
165 				v[n++] = host;
166 			} else {
167 				unsigned char *s = stracpy(cast_uchar "//");
168 				add_to_strn(&s, host);
169 				add_to_strn(&s, cast_uchar "/");
170 				add_to_strn(&s, share);
171 				v[n++] = s;
172 				if (*pass && !*user) {
173 					v[n++] = pass;
174 				}
175 			}
176 			v[n++] = cast_uchar "-N";
177 			v[n++] = cast_uchar "-E";
178 			if (*port) {
179 				v[n++] = cast_uchar "-p";
180 				v[n++] = port;
181 			}
182 			if (*user) {
183 				v[n++] = cast_uchar "-U";
184 				if (!*pass) {
185 					v[n++] = user;
186 				} else {
187 					unsigned char *s = stracpy(user);
188 					add_to_strn(&s, cast_uchar "%");
189 					add_to_strn(&s, pass);
190 					v[n++] = s;
191 				}
192 			}
193 			if (*share) {
194 				if (!*dir || dir[strlen(cast_const_char dir) - 1] == '/' || dir[strlen(cast_const_char dir) - 1] == '\\') {
195 					if (*dir) {
196 						v[n++] = cast_uchar "-D";
197 						v[n++] = dir;
198 					}
199 					v[n++] = cast_uchar "-c";
200 					v[n++] = cast_uchar "ls";
201 				} else {
202 					unsigned char *ss;
203 					unsigned char *s = stracpy(cast_uchar "get \"");
204 					add_to_strn(&s, dir);
205 					add_to_strn(&s, cast_uchar "\" -");
206 					while ((ss = cast_uchar strchr(cast_const_char s, '/'))) *ss = '\\';
207 					v[n++] = cast_uchar "-c";
208 					v[n++] = s;
209 				}
210 			}
211 			break;
212 		case SMBC:
213 			v[n++] = cast_uchar "smbc";
214 			uphp = stracpy(cast_uchar "");
215 			if (*user) {
216 				add_to_strn(&uphp, user);
217 				if (*pass) {
218 					add_to_strn(&uphp, cast_uchar ":");
219 					add_to_strn(&uphp, pass);
220 				}
221 				add_to_strn(&uphp, cast_uchar "@");
222 			}
223 			add_to_strn(&uphp, host);
224 			if (*port) {
225 				add_to_strn(&uphp, cast_uchar ":");
226 				add_to_strn(&uphp, port);
227 			}
228 			if (!*share) {
229 				v[n++] = cast_uchar "-L";
230 				v[n++] = uphp;
231 			} else {
232 				add_to_strn(&uphp, cast_uchar "/");
233 				add_to_strn(&uphp, share);
234 				if (!*dir || dir[strlen(cast_const_char dir) - 1] == '/' || dir[strlen(cast_const_char dir) - 1] == '\\') {
235 					add_to_strn(&uphp, cast_uchar "/");
236 					add_to_strn(&uphp, dir);
237 					v[n++] = uphp;
238 					v[n++] = cast_uchar "-c";
239 					v[n++] = cast_uchar "ls";
240 				} else {
241 					unsigned char *d = init_str();
242 					int dl = 0;
243 					unsigned char *dp = dir;
244 					v[n++] = uphp;
245 					v[n++] = cast_uchar "-c";
246 					add_to_str(&d, &dl, cast_uchar "pipe cat ");
247 					while (*dp) {
248 						if (*dp <= ' ' || *dp == '\\' || *dp == '"' || *dp == '\'' || *dp == '*' || *dp == '?') add_chr_to_str(&d, &dl, '\\');
249 						add_chr_to_str(&d, &dl, *dp);
250 						dp++;
251 					}
252 					v[n++] = d;
253 				}
254 			}
255 			break;
256 		default:
257 			internal("unsupported smb client");
258 		}
259 		v[n++] = NULL;
260 		EINTRLOOP(rs, execvp(cast_const_char v[0], (void *)v));
261 		hard_write(2, cast_uchar CLIENT_NOT_FOUND_STRING, (int)strlen(CLIENT_NOT_FOUND_STRING));
262 		_exit(1);
263 	}
264 	c->pid = r;
265 	mem_free(host);
266 	mem_free(port);
267 	mem_free(user);
268 	mem_free(pass);
269 	mem_free(share);
270 	mem_free(data);
271 	c->sock1 = po[0];
272 	c->sock2 = pe[0];
273 	EINTRLOOP(rs, close(po[1]));
274 	EINTRLOOP(rs, close(pe[1]));
275 	set_handlers(po[0], (void (*)(void *))smb_got_data, NULL, NULL, c);
276 	set_handlers(pe[0], (void (*)(void *))smb_got_text, NULL, NULL, c);
277 	setcstate(c, S_CONN);
278 }
279 
smbc_get_num(unsigned char * text,int * ptr,off_t * res)280 static int smbc_get_num(unsigned char *text, int *ptr, off_t *res)
281 {
282 	off_t num;
283 	int dec, dec_order, unit;
284 	int was_digit;
285 	int i = *ptr;
286 	const off_t max_off_t = (((off_t)1 << ((sizeof(off_t) * 8 - 2))) - 1) * 2 + 1;
287 
288 	while (text[i] == ' ' || text[i] == '\t') i++;
289 	was_digit = 0;
290 	num = 0;
291 	while (text[i] >= '0' && text[i] <= '9') {
292 		if (num >= max_off_t / 10) return -1;
293 		num = num * 10 + text[i] - '0';
294 		i++;
295 		was_digit = 1;
296 	}
297 	dec = 0; dec_order = 1;
298 	if (text[i] == '.') {
299 		i++;
300 		while (text[i] >= '0' && text[i] <= '9') {
301 			if (dec_order < 1000000) {
302 				dec = dec * 10 + text[i] - '0';
303 				dec_order *= 10;
304 			}
305 			i++;
306 			was_digit = 1;
307 		}
308 	}
309 	if (!was_digit) return -1;
310 	if (upcase(text[i]) == 'B') unit = 1;
311 	else if (upcase(text[i]) == 'K') unit = 1 << 10;
312 	else if (upcase(text[i]) == 'M') unit = 1 << 20;
313 	else if (upcase(text[i]) == 'G') unit = 1 << 30;
314 	else return -1;
315 	i++;
316 	*ptr = i;
317 	if (num >= max_off_t / unit) return -1;
318 	*res = num * unit + (off_t)((double)dec * ((double)unit / (double)dec_order));
319 	return 0;
320 }
321 
smb_read_text(struct connection * c,int sock)322 static void smb_read_text(struct connection *c, int sock)
323 {
324 	int r;
325 	struct smb_connection_info *si = c->info;
326 	if ((unsigned)sizeof(struct smb_connection_info) + si->ntext + page_size + 2 > MAXINT) overalloc();
327 	si = mem_realloc(si, sizeof(struct smb_connection_info) + si->ntext + page_size + 2);
328 	c->info = si;
329 	EINTRLOOP(r, (int)read(sock, si->text + si->ntext, page_size));
330 	if (r == -1) {
331 		setcstate(c, get_error_from_errno(errno));
332 		retry_connection(c);
333 		return;
334 	}
335 	if (r == 0) {
336 		if (!si->cl) {
337 			si->cl = 1;
338 			set_handlers(sock, NULL, NULL, NULL, NULL);
339 			return;
340 		}
341 		end_smb_connection(c);
342 		return;
343 	}
344 	si->ntext += r;
345 	if (!c->from) setcstate(c, S_GETH);
346 	if (c->from && si->client == SMBC) {
347 		int lasti = 0;
348 		int i = 0;
349 		si->text[si->ntext] = 0;
350 		for (i = 0; si->ntext - i > 7; i++) {
351 			nexti:
352 			if ((si->text[i] == '\n' || si->text[i] == '\r') && (si->text[i + 1] == ' ' || (si->text[i + 1] >= '0' && si->text[i + 1] <= '9')) && ((si->text[i + 2] == ' ' && si->text[i + 1] == ' ') || (si->text[i + 2] >= '0' && si->text[i + 2] <= '9')) && (si->text[i + 3] >= '0' && si->text[i + 3] <= '9') && si->text[i + 4] == '%' && si->text[i + 5] == ' ' && si->text[i + 6] == '[') {
353 				off_t position, total = 0; /* against warning */
354 				i += 7;
355 				while (si->text[i] != ']') {
356 					if (!si->text[i] || si->text[i] == '\n' || si->text[i] == '\r') {
357 						goto nexti;
358 					}
359 					i++;
360 				}
361 				i++;
362 				if (smbc_get_num(si->text, &i, &position)) {
363 					goto nexti;
364 				}
365 				while (si->text[i] == ' ' || si->text[i] == '\t') i++;
366 				if (si->text[i] != '/') {
367 					goto nexti;
368 				}
369 				i++;
370 				if (smbc_get_num(si->text, &i, &total)) {
371 					goto nexti;
372 				}
373 				if (total < c->from) total = c->from;
374 				c->est_length = total;
375 				lasti = i;
376 			}
377 		}
378 		if (lasti) memmove(si->text, si->text + lasti, si->ntext -= lasti);
379 	}
380 }
381 
smb_got_data(struct connection * c)382 static void smb_got_data(struct connection *c)
383 {
384 	struct smb_connection_info *si = c->info;
385 	unsigned char *buffer = mem_alloc(page_size);
386 	int r;
387 	int a;
388 	if (si->list) {
389 		smb_read_text(c, c->sock1);
390 		mem_free(buffer);
391 		return;
392 	}
393 	EINTRLOOP(r, (int)read(c->sock1, buffer, page_size));
394 	if (r == -1) {
395 		setcstate(c, get_error_from_errno(errno));
396 		retry_connection(c);
397 		mem_free(buffer);
398 		return;
399 	}
400 	if (r == 0) {
401 		mem_free(buffer);
402 		if (!si->cl) {
403 			si->cl = 1;
404 			set_handlers(c->sock1, NULL, NULL, NULL, NULL);
405 			return;
406 		}
407 		end_smb_connection(c);
408 		return;
409 	}
410 	setcstate(c, S_TRANS);
411 	if (!c->cache) {
412 		if (get_cache_entry(c->url, &c->cache)) {
413 			setcstate(c, S_OUT_OF_MEM);
414 			abort_connection(c);
415 			mem_free(buffer);
416 			return;
417 		}
418 		c->cache->refcount--;
419 	}
420 	if ((off_t)(0UL + c->from + r) < 0) {
421 		setcstate(c, S_LARGE_FILE);
422 		abort_connection(c);
423 		mem_free(buffer);
424 		return;
425 	}
426 	c->received += r;
427 	a = add_fragment(c->cache, c->from, buffer, r);
428 	if (a < 0) {
429 		setcstate(c, a);
430 		abort_connection(c);
431 		mem_free(buffer);
432 		return;
433 	}
434 	if (a == 1) c->tries = 0;
435 	c->from += r;
436 	mem_free(buffer);
437 }
438 
smb_got_text(struct connection * c)439 static void smb_got_text(struct connection *c)
440 {
441 	smb_read_text(c, c->sock2);
442 }
443 
end_smb_connection(struct connection * c)444 static void end_smb_connection(struct connection *c)
445 {
446 	struct smb_connection_info *si = c->info;
447 	if (!c->cache) {
448 		if (get_cache_entry(c->url, &c->cache)) {
449 			setcstate(c, S_OUT_OF_MEM);
450 			abort_connection(c);
451 			return;
452 		}
453 		c->cache->refcount--;
454 	}
455 	if (!c->from) {
456 		int sdir;
457 		if (si->ntext && si->text[si->ntext - 1] != '\n') si->text[si->ntext++] = '\n';
458 		si->text[si->ntext] = 0;
459 		if (!strcmp(cast_const_char si->text, CLIENT_NOT_FOUND_STRING "\n")) {
460 			setcstate(c, S_NO_SMB_CLIENT);
461 			if (++si->client < N_CLIENTS) {
462 				if (si->client > smb_client) smb_client = si->client;
463 				c->tries = -1;
464 				retry_connection(c);
465 			} else {
466 				smb_client = 0;
467 				abort_connection(c);
468 			}
469 			return;
470 		}
471 		sdir = 0;
472 		if (si->client == SMBC) {
473 			unsigned char *st = si->text;
474 			if (!memcmp(st, "ServerName", 10) && strchr(cast_const_char st, '\n')) st = cast_uchar strchr(cast_const_char st, '\n') + 1;
475 			if (!memcmp(st, "Logged", 6) && strchr(cast_const_char st, '\n')) st = cast_uchar strchr(cast_const_char st, '\n') + 1;
476 			if (!strstr(cast_const_char st, "ERR")) sdir = 1;
477 		}
478 		if (!si->list && *c->url &&
479 		    c->url[strlen(cast_const_char c->url) - 1] != '/' &&
480 		    c->url[strlen(cast_const_char c->url) - 1] != '\\' &&
481 		    (strstr(cast_const_char si->text, "NT_STATUS_FILE_IS_A_DIRECTORY") ||
482 		     strstr(cast_const_char si->text, "NT_STATUS_ACCESS_DENIED") ||
483 		     strstr(cast_const_char si->text, "ERRbadfile") || sdir)) {
484 			if (c->cache->redirect) mem_free(c->cache->redirect);
485 			c->cache->redirect = stracpy(c->url);
486 			c->cache->redirect_get = 1;
487 			add_to_strn(&c->cache->redirect, cast_uchar "/");
488 			c->cache->incomplete = 0;
489 		} else {
490 			unsigned char *ls, *le, *le2;
491 			unsigned char *ud;
492 			unsigned char *t = init_str();
493 			int l = 0;
494 			int type = 0;
495 			int pos = 0;
496 			int a;
497 			add_to_str(&t, &l, cast_uchar "<html><head><title>");
498 			ud = stracpy(c->url);
499 			if (strchr(cast_const_char ud, POST_CHAR)) *cast_uchar strchr(cast_const_char ud, POST_CHAR) = 0;
500 			add_conv_str(&t, &l, ud, (int)strlen(cast_const_char ud), -1);
501 			mem_free(ud);
502 			add_to_str(&t, &l, cast_uchar "</title></head><body><pre>");
503 			if (si->list == 1 && si->client == SMBC) {
504 /* smbc has a nasty bug that it writes field descriptions to stderr and data to
505    stdout. Because of stdout buffer, they'll get mixed in the output. Try to
506    demix them. */
507 #define SERVER	"Server              Comment\n------              -------\n"
508 #define WORKGR	"Workgroup           Master\n---------           ------\n"
509 				unsigned char *spos = cast_uchar strstr(cast_const_char si->text, SERVER);
510 				unsigned char *gpos;
511 				unsigned char *p, *pp, *ppp;
512 				if (spos) memmove(spos, spos + strlen(SERVER), strlen(cast_const_char spos) - strlen(SERVER) + 1);
513 				gpos = cast_uchar strstr(cast_const_char si->text, WORKGR);
514 				if (gpos) memmove(gpos, gpos + strlen(WORKGR), strlen(cast_const_char gpos) - strlen(WORKGR) + 1);
515 				if (!spos && !gpos) goto sc;
516 				pp = NULL, ppp = NULL, p = si->text;
517 				while ((p = cast_uchar strstr(cast_const_char p, "\n\n"))) ppp = pp, pp = p + 2, p++;
518 				if (!pp) goto sc;
519 				if (!spos || !gpos) ppp = NULL;
520 				if (spos) {
521 					if (!ppp) ppp = pp, pp = NULL;
522 					memmove(ppp + strlen(SERVER), ppp, strlen(cast_const_char ppp) + 1);
523 					memcpy(ppp, SERVER, strlen(SERVER));
524 					if (pp) pp += strlen(SERVER);
525 				}
526 				if (gpos && pp) {
527 					memmove(pp + strlen(WORKGR), pp, strlen(cast_const_char pp) + 1);
528 					memcpy(pp, WORKGR, strlen(WORKGR));
529 				}
530 				goto sc;
531 			}
532 			sc:
533 			ls = si->text;
534 			while ((le = cast_uchar strchr(cast_const_char ls, '\n'))) {
535 				unsigned char *lx;
536 				unsigned char *st;
537 				le2 = cast_uchar strchr(cast_const_char ls, '\r');
538 				if (!le2 || le2 > le) le2 = le;
539 				lx = memacpy(ls, le2 - ls);
540 				if (si->list == 1) {
541 					unsigned char *ll, *lll;
542 					if (!*lx) type = 0;
543 					if (strstr(cast_const_char lx, "Sharename") && (st = cast_uchar strstr(cast_const_char lx, "Type"))) {
544 						pos = (int)(st - lx);
545 						type = 1;
546 						goto af;
547 					}
548 					if (strstr(cast_const_char lx, "Server") && strstr(cast_const_char lx, "Comment")) {
549 						type = 2;
550 						goto af;
551 					}
552 					if (strstr(cast_const_char lx, "Workgroup") && (st = cast_uchar strstr(cast_const_char lx, "Master"))) {
553 						pos = (int)(st - lx);
554 						type = 3;
555 						goto af;
556 					}
557 					if (!type) goto af;
558 					for (ll = lx; *ll; ll++) if (!WHITECHAR(*ll) && *ll != '-') goto np;
559 					goto af;
560 					np:
561 					for (ll = lx; *ll; ll++) if (!WHITECHAR(*ll)) break;
562 					for (lll = ll; *lll /* && lll[1]*/; lll++) if (WHITECHAR(*lll) /*&& WHITECHAR(lll[1])*/) break;
563 					if (type == 1) {
564 						unsigned char *llll;
565 						if (!strstr(cast_const_char lll, "Disk")) goto af;
566 						if (pos && (size_t)pos < strlen(cast_const_char lx) && WHITECHAR(*(llll = lx + pos - 1)) && llll > ll) {
567 							while (llll > ll && WHITECHAR(*llll)) llll--;
568 							if (!WHITECHAR(*llll)) lll = llll + 1;
569 						}
570 						add_conv_str(&t, &l, lx, (int)(ll - lx), 0);
571 						add_to_str(&t, &l, cast_uchar "<a href=\"/");
572 						add_conv_str(&t, &l, ll, (int)(lll - ll), 1);
573 						add_to_str(&t, &l, cast_uchar "/\">");
574 						add_conv_str(&t, &l, ll, (int)(lll - ll), 0);
575 						add_to_str(&t, &l, cast_uchar "</a>");
576 						add_conv_str(&t, &l, lll, (int)strlen(cast_const_char lll), 0);
577 					} else if (type == 2) {
578 						sss:
579 						add_conv_str(&t, &l, lx, (int)(ll - lx), 0);
580 						add_to_str(&t, &l, cast_uchar "<a href=\"smb://");
581 						add_conv_str(&t, &l, ll, (int)(lll - ll), 1);
582 						add_to_str(&t, &l, cast_uchar "/\">");
583 						add_conv_str(&t, &l, ll, (int)(lll - ll), 0);
584 						add_to_str(&t, &l, cast_uchar "</a>");
585 						add_conv_str(&t, &l, lll, (int)strlen(cast_const_char lll), 0);
586 					} else if (type == 3) {
587 						if ((size_t)pos < strlen(cast_const_char lx) && pos && WHITECHAR(lx[pos - 1]) && !WHITECHAR(lx[pos])) ll = lx + pos;
588 						else for (ll = lll; *ll; ll++) if (!WHITECHAR(*ll)) break;
589 						for (lll = ll; *lll; lll++) if (WHITECHAR(*lll)) break;
590 						goto sss;
591 					} else goto af;
592 				} else if (si->list == 2 && si->client == SMBCLIENT) {
593 					if (strstr(cast_const_char lx, "NT_STATUS")) {
594 						le[1] = 0;
595 						goto af;
596 					}
597 					if (le2 - ls >= 5 && ls[0] == ' ' && ls[1] == ' ' && ls[2] != ' ') {
598 						int dir;
599 						unsigned char *pp;
600 						unsigned char *p = ls + 3;
601 						while (le2 - p >= 2) {
602 							if (p[0] == ' ' && p[1] == ' ') goto o;
603 							p++;
604 						}
605 						goto af;
606 						o:
607 						dir = 0;
608 						pp = p;
609 						while (pp < le2 && *pp == ' ') pp++;
610 						while (pp < le2 && *pp != ' ') {
611 							if (*pp == 'D') {
612 								dir = 1;
613 								break;
614 							}
615 							pp++;
616 						}
617 						add_to_str(&t, &l, cast_uchar "  <a href=\"./");
618 						add_conv_str(&t, &l, ls + 2, (int)(p - (ls + 2)), 1);
619 						if (dir) add_chr_to_str(&t, &l, '/');
620 						add_to_str(&t, &l, cast_uchar "\">");
621 						add_conv_str(&t, &l, ls + 2, (int)(p - (ls + 2)), 0);
622 						add_to_str(&t, &l, cast_uchar "</a>");
623 						add_conv_str(&t, &l, p, (int)(le - p), 0);
624 					} else goto af;
625 				} else if (si->list == 2 && si->client == SMBC) {
626 					unsigned char *d;
627 					if (le2 - ls <= 17) goto af;
628 					d = ls + 17;
629 					smbc_next_chr:
630 					if (d + 9 >= le2) goto af;
631 					if (!(d[0] == ':' && d[1] >= '0' && d[1] <= '9' && d[2] >= '0' && d[2] <= '9' && d[3] == ' ' && ((d[4] == '1' && d[5] == '9') || (d[4] == '2' && d[5] >= '0' && d[5] <= '9')) && d[6] >= '0' && d[6] <= '9' && d[7] >= '0' && d[7] <= '9' && d[8] == ' ')) {
632 						d++;
633 						goto smbc_next_chr;
634 					}
635 					d += 9;
636 					add_conv_str(&t, &l, ls, (int)(d - ls), 0);
637 					add_to_str(&t, &l, cast_uchar "<a href=\"./");
638 					add_conv_str(&t, &l, d, (int)(le2 - d), 1);
639 					if (ls[4] == 'D') add_chr_to_str(&t, &l, '/');
640 					add_to_str(&t, &l, cast_uchar "\">");
641 					add_conv_str(&t, &l, d, (int)(le2 - d), 0);
642 					add_to_str(&t, &l, cast_uchar "</a>");
643 				} else af: add_conv_str(&t, &l, ls, (int)(le2 - ls), 0);
644 				add_chr_to_str(&t, &l, '\n');
645 				ls = le + 1;
646 				mem_free(lx);
647 			}
648 			/*add_to_str(&t, &l, si->text);*/
649 			a = add_fragment(c->cache, 0, t, l);
650 			if (a < 0) {
651 				mem_free(t);
652 				setcstate(c, a);
653 				abort_connection(c);
654 				return;
655 			}
656 			c->from += l;
657 			truncate_entry(c->cache, l, 1);
658 			c->cache->incomplete = 0;
659 			mem_free(t);
660 			if (!c->cache->head) c->cache->head = stracpy(cast_uchar "\r\n");
661 			add_to_strn(&c->cache->head, cast_uchar "Content-Type: text/html\r\n");
662 		}
663 	} else {
664 		truncate_entry(c->cache, c->from, 1);
665 		c->cache->incomplete = 0;
666 	}
667 	close_socket(&c->sock1);
668 	close_socket(&c->sock2);
669 	setcstate(c, S__OK);
670 	abort_connection(c);
671 	return;
672 }
673 
674 #endif
675