1 #include "burp.h"
2 #include "alloc.h"
3 #include "asfd.h"
4 #include "async.h"
5 #include "berrno.h"
6 #include "cmd.h"
7 #include "fsops.h"
8 #include "fzp.h"
9 #include "handy.h"
10 #include "hexmap.h"
11 #include "iobuf.h"
12 #include "log.h"
13 #include "msg.h"
14 #include "prepend.h"
15 #include "protocol1/handy.h"
16 #include "protocol2/blk.h"
17 
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 
21 #ifdef HAVE_WIN32
22 #include <winsock2.h>
23 #include <ws2tcpip.h>
24 #endif
25 
26 // return -1 for error, 0 for OK, 1 if the client wants to interrupt the
27 // transfer.
do_quick_read(struct asfd * asfd,const char * datapth,struct cntr * cntr)28 int do_quick_read(struct asfd *asfd, const char *datapth, struct cntr *cntr)
29 {
30 	int r=0;
31 	struct iobuf *rbuf;
32 	if(asfd->as->read_quick(asfd->as)) return -1;
33 	rbuf=asfd->rbuf;
34 
35 	if(rbuf->buf)
36 	{
37 		if(rbuf->cmd==CMD_MESSAGE
38 		  || rbuf->cmd==CMD_WARNING)
39 		{
40 			log_recvd(rbuf, cntr, 0);
41 		}
42 		else if(rbuf->cmd==CMD_INTERRUPT)
43 		{
44 			// Client wants to interrupt - double check that
45 			// it is still talking about the file that we are
46 			// sending.
47 			if(datapth && !strcmp(rbuf->buf, datapth))
48 				r=1;
49 		}
50 		else
51 		{
52 			iobuf_log_unexpected(rbuf, __func__);
53 			r=-1;
54 		}
55 		iobuf_free_content(rbuf);
56 	}
57 	return r;
58 }
59 
send_whole_file_gz(struct asfd * asfd,const char * datapth,int quick_read,uint64_t * bytes,struct cntr * cntr,int compression,struct fzp * fzp)60 static int send_whole_file_gz(struct asfd *asfd,
61 	const char *datapth, int quick_read,
62 	uint64_t *bytes, struct cntr *cntr,
63 	int compression, struct fzp *fzp)
64 {
65 	int ret=0;
66 	int zret=0;
67 
68 	unsigned have;
69 	z_stream strm;
70 	int flush=Z_NO_FLUSH;
71 	uint8_t in[ZCHUNK];
72 	uint8_t out[ZCHUNK];
73 
74 	struct iobuf wbuf;
75 
76 	/* allocate deflate state */
77 	strm.zalloc = Z_NULL;
78 	strm.zfree = Z_NULL;
79 	strm.opaque = Z_NULL;
80 	if((zret=deflateInit2(&strm, compression, Z_DEFLATED, (15+16),
81 		8, Z_DEFAULT_STRATEGY))!=Z_OK)
82 			return -1;
83 
84 	do
85 	{
86 		strm.avail_in=fzp_read(fzp, in, ZCHUNK);
87 		if(!compression && !strm.avail_in) break;
88 
89 		*bytes+=strm.avail_in;
90 
91 		if(strm.avail_in) flush=Z_NO_FLUSH;
92 		else flush=Z_FINISH;
93 
94 		strm.next_in=in;
95 
96 		// Run deflate() on input until output buffer not full, finish
97 		// compression if all of source has been read in.
98 		do
99 		{
100 			if(compression)
101 			{
102 				strm.avail_out=ZCHUNK;
103 				strm.next_out=out;
104 				zret=deflate(&strm, flush);
105 				if(zret==Z_STREAM_ERROR)
106 				{
107 					logp("z_stream_error\n");
108 					ret=-1;
109 					break;
110 				}
111 				have=ZCHUNK-strm.avail_out;
112 			}
113 			else
114 			{
115 				have=strm.avail_in;
116 				memcpy(out, in, have);
117 			}
118 
119 			wbuf.cmd=CMD_APPEND;
120 			wbuf.buf=(char *)out;
121 			wbuf.len=have;
122 			if(asfd->write(asfd, &wbuf))
123 			{
124 				ret=-1;
125 				break;
126 			}
127 			if(quick_read && datapth)
128 			{
129 				int qr;
130 				if((qr=do_quick_read(asfd, datapth, cntr))<0)
131 				{
132 					ret=-1;
133 					break;
134 				}
135 				if(qr) // Client wants to interrupt.
136 				{
137 					goto cleanup;
138 				}
139 			}
140 			if(!compression) break;
141 		} while(!strm.avail_out);
142 
143 		if(ret) break;
144 
145 		if(!compression) continue;
146 
147 		if(strm.avail_in) /* all input will be used */
148 		{
149 			ret=-1;
150 			logp("strm.avail_in=%d\n", strm.avail_in);
151 			break;
152 		}
153 	} while(flush!=Z_FINISH);
154 
155 	if(!ret)
156 	{
157 		if(compression && zret!=Z_STREAM_END)
158 		{
159 			logp("ret OK, but zstream not finished: %d\n", zret);
160 			ret=-1;
161 		}
162 	}
163 
164 cleanup:
165 	deflateEnd(&strm);
166 
167 	if(!ret)
168 	{
169 		return write_endfile(asfd, *bytes, NULL);
170 	}
171 //logp("end of send\n");
172 	return ret;
173 }
174 
set_non_blocking(int fd)175 int set_non_blocking(int fd)
176 {
177 	int flags;
178 	if((flags = fcntl(fd, F_GETFL, 0))<0) flags = 0;
179 	return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
180 }
181 
set_blocking(int fd)182 int set_blocking(int fd)
183 {
184 	int flags;
185 	if((flags = fcntl(fd, F_GETFL, 0))<0) flags = 0;
186 	return fcntl(fd, F_SETFL, flags | ~O_NONBLOCK);
187 }
188 
get_tmp_filename(const char * basis)189 char *get_tmp_filename(const char *basis)
190 {
191 	return prepend(basis, ".tmp");
192 }
193 
add_fd_to_sets(int fd,fd_set * read_set,fd_set * write_set,fd_set * err_set,int * max_fd)194 void add_fd_to_sets(int fd, fd_set *read_set, fd_set *write_set, fd_set *err_set, int *max_fd)
195 {
196 	if(read_set) FD_SET((unsigned int) fd, read_set);
197 	if(write_set) FD_SET((unsigned int) fd, write_set);
198 	if(err_set) FD_SET((unsigned int) fd, err_set);
199 
200 	if(fd > *max_fd) *max_fd = fd;
201 }
202 
203 #ifndef HAVE_WIN32
get_address_and_port(struct sockaddr_storage * addr,char * addrstr,size_t len,uint16_t * port)204 int get_address_and_port(struct sockaddr_storage *addr,
205 	char *addrstr, size_t len, uint16_t *port)
206 {
207 	struct sockaddr_in *s4;
208 	struct sockaddr_in6 *s6;
209 
210 	switch(addr->ss_family)
211 	{
212 		case AF_INET:
213 			s4=(struct sockaddr_in *)addr;
214 			inet_ntop(AF_INET, &s4->sin_addr, addrstr, len);
215 			*port=ntohs(s4->sin_port);
216 			break;
217 		case AF_INET6:
218 			s6=(struct sockaddr_in6 *)addr;
219 			inet_ntop(AF_INET6, &s6->sin6_addr, addrstr, len);
220 			*port=ntohs(s6->sin6_port);
221 			break;
222 		default:
223 			logp("unknown addr.ss_family: %d\n", addr->ss_family);
224 			return -1;
225 	}
226 	return 0;
227 }
228 #endif
229 
set_peer_env_vars(struct sockaddr_storage * addr)230 int set_peer_env_vars(struct sockaddr_storage *addr)
231 {
232 #ifndef HAVE_WIN32
233 	uint16_t port=0;
234 	char portstr[16]="";
235 	char addrstr[INET6_ADDRSTRLEN]="";
236 
237 	if(get_address_and_port(addr, addrstr, INET6_ADDRSTRLEN, &port))
238 		return -1;
239 
240 	if(setenv("REMOTE_ADDR",  addrstr, 1))
241 	{
242 		logp("setenv REMOTE_ADDR to %s failed: %s\n",
243 				addrstr, strerror(errno));
244 		return -1;
245 	}
246 	snprintf(portstr, sizeof(portstr), "%d", port);
247 	if(setenv("REMOTE_PORT",  portstr, 1))
248 	{
249 		logp("setenv REMOTE_PORT failed: %s\n", strerror(errno));
250 		return -1;
251 	}
252 #endif
253 	return 0;
254 }
255 
set_keepalive(int fd,int value)256 int set_keepalive(int fd, int value)
257 {
258 	int keepalive=value;
259 	if(setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
260 		(char *)&keepalive, sizeof(keepalive)))
261 	{
262 		logp("setsockopt keepalive=%d failed: %s\n",
263 			value, strerror(errno));
264 		return -1;
265 	}
266 	return 0;
267 }
268 
init_client_socket(const char * host,const char * port)269 int init_client_socket(const char *host, const char *port)
270 {
271 	int rfd=-1;
272 	int gai_ret;
273 	struct addrinfo hints;
274 	struct addrinfo *result;
275 	struct addrinfo *rp;
276 
277 	memset(&hints, 0, sizeof(struct addrinfo));
278 	hints.ai_family = AF_UNSPEC;
279 	hints.ai_socktype = SOCK_STREAM;
280 	hints.ai_flags = 0;
281 	hints.ai_protocol = 0;
282 
283 	logp("Connecting to %s:%s\n", host?host:"loopback", port);
284 
285 	if((gai_ret=getaddrinfo(host, port, &hints, &result)))
286 	{
287 		logp("getaddrinfo: %s\n", gai_strerror(gai_ret));
288 		return -1;
289 	}
290 
291 	for(rp=result; rp; rp=rp->ai_next)
292 	{
293 		rfd=socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
294 		if(rfd<0) continue;
295 		set_keepalive(rfd, 1);
296 		if(connect(rfd, rp->ai_addr, rp->ai_addrlen) != -1) break;
297 		close_fd(&rfd);
298 	}
299 	freeaddrinfo(result);
300 	if(!rp)
301 	{
302 		// host==NULL and AI_PASSIVE not set -> loopback
303 		logp("Could not connect to %s:%s\n",
304 			host?host:"loopback", port);
305 		close_fd(&rfd);
306 		return -1;
307 	}
308 	reuseaddr(rfd);
309 
310 #ifdef HAVE_WIN32
311 	setmode(rfd, O_BINARY);
312 #endif
313 	return rfd;
314 }
315 
reuseaddr(int fd)316 void reuseaddr(int fd)
317 {
318 	int optval=1;
319 #ifdef HAVE_OLD_SOCKOPT
320 #define sockopt_val_t char *
321 #else
322 #define sockopt_val_t void *
323 #endif
324 	if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
325 		(sockopt_val_t)&optval, sizeof(optval))<0)
326 			logp("Error: setsockopt SO_REUSEADDR: %s",
327 				strerror(errno));
328 }
329 
setup_signal(int sig,void handler (int sig))330 void setup_signal(int sig, void handler(int sig))
331 {
332 	struct sigaction sa;
333 	memset(&sa, 0, sizeof(sa));
334 	sa.sa_handler=handler;
335 	sigaction(sig, &sa, NULL);
336 }
337 
338 /* Function based on src/lib/priv.c from bacula. */
chuser_and_or_chgrp(const char * user,const char * group,int readall)339 int chuser_and_or_chgrp(const char *user, const char *group, int readall)
340 {
341 #ifdef HAVE_WIN32
342 	return 0;
343 #else
344 	struct passwd *passw = NULL;
345 	struct group *grp = NULL;
346 	gid_t gid;
347 	uid_t uid;
348 	char *username=NULL;
349 
350 	// Allow setting readall=1 without setting user
351 	if(readall && !user)
352 		user="nobody";
353 	if(!user && !group) return 0;
354 
355 	if(user)
356 	{
357 		if(!(passw=getpwnam(user)))
358 		{
359 			logp("could not find user '%s': %s\n",
360 				user, strerror(errno));
361 			return -1;
362 		}
363 	}
364 	else
365 	{
366 		if(!(passw=getpwuid(getuid())))
367 		{
368 			logp("could not find password entry: %s\n",
369 				strerror(errno));
370 			return -1;
371 		}
372 		user=passw->pw_name;
373 	}
374 	// Any OS uname pointer may get overwritten, so save name, uid, and gid
375 	if(!(username=strdup_w(user, __func__)))
376 		return -1;
377 	uid=passw->pw_uid;
378 	gid=passw->pw_gid;
379 	if(group)
380 	{
381 		if(!(grp=getgrnam(group)))
382 		{
383 			logp("could not find group '%s': %s\n", group,
384 				strerror(errno));
385 			goto err;
386 		}
387 		gid=grp->gr_gid;
388 	} else {
389 		// Resolve gid to group name for logp()
390 		if (!(grp=getgrgid(gid)))
391 		{
392 			logp("could not find group for gid %d: %s\n", gid,
393 				strerror(errno));
394 			goto err;
395 		}
396 		group=grp->gr_name;
397 		grp=NULL;
398 	}
399 	if(gid!=getgid() // do not do it if we already have the same gid.
400 	  && initgroups(username, gid))
401 	{
402 		if(grp)
403 			logp("could not initgroups for group '%s', user '%s': %s\n", group, username, strerror(errno));
404 		else
405 			logp("could not initgroups for user '%s': %s\n", username, strerror(errno));
406 		goto err;
407 	}
408 	if(grp)
409 	{
410 		if(gid!=getgid() // do not do it if we already have the same gid
411 		 && setgid(gid))
412 		{
413 			logp("could not set group '%s': %s\n", group,
414 				strerror(errno));
415 			goto err;
416 		}
417 	}
418 	if (readall)
419 	{
420 #ifdef ENABLE_KEEP_READALL_CAPS_SUPPORT
421 		cap_t caps;
422 		// Make capabilities pass through setreuid
423 		if(prctl(PR_SET_KEEPCAPS, 1))
424 		{
425 			logp("prctl(PR_SET_KEEPCAPS) failed: %s\n", strerror(errno));
426 			goto err;
427 		}
428 		if(setreuid(uid, uid))
429 		{
430 			logp("Could not switch to user=%s (uid=%u): %s\n", username, uid, strerror(errno));
431 			goto err;
432 		}
433 		// `ep' is Effective and Permitted
434 		caps=cap_from_text("cap_dac_read_search=ep");
435 		if(!caps)
436 		{
437 			logp("cap_from_text() failed: %s\n", strerror(errno));
438 			goto err;
439 		}
440 		if(cap_set_proc(caps) < 0)
441 		{
442 			logp("cap_set_proc() failed: %s\n", strerror(errno));
443 			goto err;
444 		}
445 		cap_free(caps);
446 		logp("Privileges switched to %s keeping readall capability.\n", username);
447 #else
448 		logp("Keep readall capabilities is not implemented on this platform yet\n");
449 		goto err;
450 #endif
451 	} else if(uid!=getuid() // do not do it if we already have the same uid
452 	  && setuid(uid))
453 	{
454 		logp("could not set specified user '%s': %s\n", username,
455 			strerror(errno));
456 		goto err;
457 	}
458 	return 0;
459 err:
460 	free_w(&username);
461 	return -1;
462 #endif
463 }
464 
465 // Not in dpth.c so that Windows client can see it.
dpth_protocol1_is_compressed(int compressed,const char * datapath)466 int dpth_protocol1_is_compressed(int compressed, const char *datapath)
467 {
468 	const char *dp=NULL;
469 
470 	if(compressed>0) return compressed;
471 	if(compressed==0) return 0;
472 
473 	/* Legacy - if the compressed value is -1 - that is, it is not set in
474 	   the manifest, deduce the value from the datapath. */
475 	if((dp=strrchr(datapath, '.')) && !strcmp(dp, ".gz")) return 1;
476 	return 0;
477 }
478 
version_to_long(const char * version)479 long version_to_long(const char *version)
480 {
481 	long ret=0;
482 	char *copy=NULL;
483 	char *tok1=NULL;
484 	char *tok2=NULL;
485 	char *tok3=NULL;
486 	if(!version || !*version) return 0;
487 	if(!(copy=strdup_w(version, __func__)))
488 		return -1;
489 	if(!(tok1=strtok(copy, "."))
490 	  || !(tok2=strtok(NULL, "."))
491 	  || !(tok3=strtok(NULL, ".")))
492 	{
493 		free_w(&copy);
494 		return -1;
495 	}
496 	ret+=atol(tok3);
497 	ret+=atol(tok2)*100;
498 	ret+=atol(tok1)*100*100;
499 	free_w(&copy);
500 	return ret;
501 }
502 
503 /* These receive_a_file() and send_a_file() functions are for use by
504    extra_comms and the CA stuff, rather than backups/restores. */
receive_a_file(struct asfd * asfd,const char * path,struct cntr * cntr)505 int receive_a_file(struct asfd *asfd, const char *path, struct cntr *cntr)
506 {
507 	int ret=-1;
508 	struct BFILE *bfd=NULL;
509 	uint64_t rcvdbytes=0;
510 	uint64_t sentbytes=0;
511 
512 	if(!(bfd=bfile_alloc())) goto end;
513 	bfile_init(bfd, 0, cntr);
514 #ifdef HAVE_WIN32
515 	bfd->set_win32_api(bfd, 0);
516 #else
517 	bfd->set_vss_strip(bfd, 0);
518 #endif
519 	if(bfd->open(bfd, asfd, path,
520 #ifdef O_NOFOLLOW
521 		O_NOFOLLOW |
522 #endif
523 		O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
524 		S_IRUSR | S_IWUSR))
525 	{
526 		struct berrno be;
527 		berrno_init(&be);
528 		logp("Could not open for writing %s: %s\n",
529 			path, berrno_bstrerror(&be, errno));
530 		goto end;
531 	}
532 
533 	ret=transfer_gzfile_in(asfd, bfd, &rcvdbytes, &sentbytes);
534 	if(bfd->close(bfd, asfd))
535 	{
536 		logp("error closing %s in %s\n", path, __func__);
537 		goto end;
538 	}
539 	logp("Received: %s\n", path);
540 	ret=0;
541 end:
542 	bfd->close(bfd, asfd);
543 	bfile_free(&bfd);
544 	return ret;
545 }
546 
547 /* Windows will use this function, when sending a certificate signing request.
548    It is not using the Windows API stuff because it needs to arrive on the
549    server side without any junk in it. */
send_a_file(struct asfd * asfd,const char * path,struct cntr * cntr)550 int send_a_file(struct asfd *asfd, const char *path, struct cntr *cntr)
551 {
552 	int ret=0;
553 	struct fzp *fzp=NULL;
554 	uint64_t bytes=0;
555 	if(!(fzp=fzp_open(path, "rb"))
556 	  || send_whole_file_gz(asfd, "datapth", 0, &bytes,
557 		cntr, 9 /*compression*/, fzp))
558 	{
559 		ret=-1;
560 		goto end;
561 	}
562 	logp("Sent %s\n", path);
563 end:
564 	fzp_close(&fzp);
565 	return ret;
566 }
567 
strncmp_w(const char * s1,const char * s2)568 int strncmp_w(const char *s1, const char *s2)
569 {
570 	return strncmp(s1, s2, strlen(s2));
571 }
572 
strreplace_w(char * orig,char * search,char * replace,const char * func)573 char *strreplace_w(char *orig, char *search, char *replace, const char *func)
574 {
575 	char *result=NULL; // the return string
576 	char *ins;         // the next insert point
577 	char *tmp;         // varies
578 	int len_rep;       // length of replace (the string to replace search with)
579 	int len_search;    // length of search (the string to look for)
580 	int len_front;     // distance between rep and end of last rep
581 	int count;         // number of replacements
582 
583 	// sanity checks and initialization
584 	if(!orig || !search) goto end;
585 	len_search = strlen(search);
586 	if(len_search==0)
587 		goto end;
588 	if(!replace)
589 		len_rep=0;
590 	else
591 		len_rep=strlen(replace);
592 
593 	// count the number of replacements needed
594 	ins=orig;
595 	for(count=0; (tmp=strstr(ins, search)); ++count)
596 		ins=tmp+len_search;
597 
598 	tmp=result=(char *)malloc_w(strlen(orig)+(len_rep-len_search)*count+1, func);
599 
600 	if(!result) goto end;
601 
602 	while(count--)
603 	{
604 		ins=strstr(orig, search);
605 		len_front=ins-orig;
606 		tmp=strncpy(tmp, orig, len_front)+len_front;
607 		tmp=strcpy(tmp, replace)+len_rep;
608 		orig+=len_front+len_search; // move to next "end of rep"
609 	}
610 	strcpy(tmp, orig);
611 end:
612 	return result;
613 }
614 
charcount_noescaped(const char * orig,char search,int repeat)615 static int charcount_noescaped(const char *orig, char search, int repeat)
616 {
617 	int count=0;
618 	int len;
619 	int i;
620 	char quote='\0';
621 	char prev='\0';
622 	if(!orig) return count;
623 	len=strlen(orig);
624 	for(count=0, i=0; i<len; i++)
625 	{
626 		if(quote=='\0' && (orig[i]=='\'' || orig[i]=='"'))
627 			quote=orig[i];
628 		else if(quote!='\0' && orig[i]==quote)
629 		{
630 			// ignore escaped quote
631 			if(i>0 && orig[i-1]=='\\')
632 				goto loop_tail;
633 			quote='\0';
634 		}
635 		else if(quote=='\0' && orig[i]==search)
636 		{
637 			// ignore escaped char
638 			if(i>0 && orig[i-1]=='\\')
639 				goto loop_tail;
640 			if(repeat || prev!=orig[i])
641 				count++;
642 		}
643 loop_tail:
644 		prev=orig[i];
645 	}
646 	return count;
647 }
648 
charreplace_noescaped_w(const char * orig,char search,const char * replace,int * count,const char * func)649 char *charreplace_noescaped_w(const char *orig, char search, const char *replace, int *count, const char *func)
650 {
651 	char *result=NULL;
652 	char *tmp;
653 	char quote='\0';
654 	int nb_repl=0;  // number of replacement
655 	int i;
656 	int len;
657 	int len_replace;
658 	int len_dest;
659 
660 	if(!orig || !search) goto end;
661 
662 	len=strlen(orig);
663 	len_replace=strlen(replace);
664 
665 	if(!(nb_repl=charcount_noescaped(orig, search, 1)))
666 	{
667 		result=strdup_w(orig, func);
668 		goto end;
669 	}
670 
671 	len_dest=len+((len_replace-1)*nb_repl)+1;
672 	tmp=result=(char *)malloc_w(len_dest, func);
673 	if(!result) goto end;
674 
675 	quote='\0';
676 	for(i=0; i<len; i++)
677 	{
678 		if(quote=='\0' && (orig[i]=='\'' || orig[i]=='"'))
679 			quote=orig[i];
680 		else if(quote!='\0' && orig[i]==quote)
681 		{
682 			if(i<=0 || orig[i-1]!='\\')
683 				quote='\0';
684 		}
685 		else if(quote=='\0' && orig[i]==search)
686 		{
687 			if(i<=0 || orig[i-1]!='\\')
688 			{
689 				tmp=(char *)memcpy(tmp, replace, len_replace);
690 				tmp+=len_replace;
691 				continue;
692 			}
693 		}
694 		*tmp=orig[i];
695 		tmp++;
696 	}
697 	*tmp='\0';
698 end:
699 	*count=nb_repl;
700 	return result;
701 }
702 
703 /*
704  * Returns NULL-terminated list of tokens found in string src,
705  * also sets *size to number of tokens found (list length without final NULL).
706  * On failure returns NULL. List itself and tokens are dynamically allocated.
707  * Calls to strtok with delimiters in second argument are used (see its docs),
708  * but neither src nor delimiters arguments are altered.
709  */
strsplit_w(const char * src,const char * delimiters,size_t * size,const char * func)710 char **strsplit_w(const char *src, const char *delimiters, size_t *size, const char *func)
711 {
712 	size_t allocated;
713 	char *init=NULL;
714 	char **ret=NULL;
715 
716 	*size=0;
717 	if(!(init=strdup_w(src, func))) goto end;
718 	if(!(ret=(char **)malloc_w((allocated=10)*sizeof(char *), func)))
719 		goto end;
720 	for(char *tmp=strtok(init, delimiters); tmp; tmp=strtok(NULL, delimiters))
721 	{
722 		// Check if space is present for another token and terminating NULL.
723 		if(allocated<*size+2)
724 		{
725 			if(!(ret=(char **)realloc_w(ret,
726 				(allocated=*size+11)*sizeof(char *), func)))
727 					goto end;
728 		}
729 		if(!(ret[(*size)++]=strdup_w(tmp, func)))
730 		{
731 			ret=NULL;
732 			goto end;
733 		}
734 	}
735 	ret[*size]=NULL;
736 
737 end:
738 	free_w(&init);
739 	return ret;
740 }
741 
strip_whitespace_w(const char * src,const char * func)742 static char *strip_whitespace_w(const char *src, const char *func)
743 {
744 	char *ret=NULL;
745 	char *ptr=(char *)src;
746 	int len=strlen(src);
747 	int size;
748 	if(*ptr!=' ' && ptr[len-1]!=' ')
749 	{
750 		if(!(ret=strdup_w(src, func))) goto end;
751 		return ret;
752 	}
753 	for(; *ptr==' '; ptr++);
754 	size=strlen(ptr);
755 	for(; ptr[size-1]==' '; --size);
756 	if(!(ret=(char *)malloc_w(size+2, func))) goto end;
757 	ret=strncpy(ret, ptr, size);
758 	ret[size]='\0';
759 end:
760 	return ret;
761 }
762 
763 // same as strsplit_w except the delimiter is a single char and if the delimiter
764 // is inside quotes or escaped with '\' it is ignored.
charsplit_noescaped_w(const char * src,char delimiter,size_t * size,const char * func)765 char **charsplit_noescaped_w(const char *src, char delimiter, size_t *size, const char *func)
766 {
767 	char **ret=NULL;
768 	char *ptr=NULL;
769 	char *buf;
770 	char *end;
771 	char quote='\0';
772 	char prev='\0';
773 	int count;
774 	int i, j, k;
775 	int len;
776 
777 	if(!src) goto end;
778 	ptr=strip_whitespace_w(src, func);
779 	buf=ptr;
780 	len=strlen(ptr);
781 	if(!(count=charcount_noescaped(ptr, delimiter, 0)))
782 		goto end;
783 	// need one more space than the number of delimiters
784 	count++;
785 	if(!(ret=(char **)malloc_w((count+1)*sizeof(char *), func)))
786 		goto error;
787 	*size=(size_t)count;
788 	for(i=0, j=0, k=0; i<len; i++)
789 	{
790 		if(quote=='\0' && (ptr[i]=='\'' || ptr[i]=='"'))
791 			quote=ptr[i];
792 		else if(quote!='\0' && ptr[i]==quote)
793 		{
794 			if(i<=0 || ptr[i-1]!='\\')
795 				quote='\0';
796 		}
797 		else if(quote=='\0' && ptr[i]==delimiter)
798 		{
799 			if(i<=0 || ptr[i-1]!='\\')
800 			{
801 				if(prev==ptr[i])
802 					buf++;
803 				else
804 				{
805 					char *tmp;
806 					int tmp_len=j+1;
807 					if(k>0) buf++;
808 					if(!(tmp=(char *)malloc_w(
809 						tmp_len, func)))
810 							goto error;
811 					tmp=strncpy(tmp, buf, tmp_len);
812 					tmp[tmp_len-1]='\0';
813 					ret[k]=tmp;
814 					buf+=j;
815 					j=0;
816 					k++;
817 				}
818 				goto loop_tail;
819 			}
820 		}
821 		j++;
822 loop_tail:
823 		prev=ptr[i];
824 	}
825 	while(*buf==delimiter && *(buf-1)!='\\') buf++;
826 	if(!(end=(char *)malloc_w(j+1, func)))
827 		goto error;
828 	end=strncpy(end, buf, j+1);
829 	end[j]='\0';
830 	ret[k]=end;
831 	ret[k+1]=NULL;
832 end:
833 	free_w(&ptr);
834 	return ret;
835 error:
836 	free_w(&ptr);
837 	free_list_w(&ret, *size);
838 	return NULL;
839 }
840 
free_list_w(char *** list,size_t size)841 void free_list_w(char ***list, size_t size)
842 {
843 	char **l=*list;
844 	if(!l) return;
845 	size_t i;
846 	for(i=0; i<size; i++)
847 		if(l[i]) free_w(&l[i]);
848 	free_v((void **)list);
849 }
850 
851 // Strip any trailing slashes (unless it is '/').
strip_trailing_slashes(char ** str)852 void strip_trailing_slashes(char **str)
853 {
854 	size_t l;
855 	// FIX THIS: pretty crappy.
856 	while(1)
857 	{
858 		if(!str || !*str
859 		  || !strcmp(*str, "/")
860 		  || !(l=strlen(*str))
861 		  || (*str)[l-1]!='/')
862 			return;
863 		(*str)[l-1]='\0';
864 	}
865 }
866 
breakpoint(int breakpoint,const char * func)867 int breakpoint(int breakpoint, const char *func)
868 {
869 	logp("Breakpoint %d hit in %s\n", breakpoint, func);
870 	return -1;
871 }
872 
873 /* Windows users have a nasty habit of putting in backslashes. Convert them. */
874 #ifdef HAVE_WIN32
convert_backslashes(char ** path)875 void convert_backslashes(char **path)
876 {
877 	char *p=NULL;
878 	for(p=*path; *p; p++) if(*p=='\\') *p='/';
879 }
880 #endif
881 
strlwr(char * s)882 char *strlwr(char *s)
883 {
884 	char *tmp=s;
885 	for(;*tmp;++tmp) *tmp=tolower((unsigned char)*tmp);
886 	return s;
887 }
888 
strip_fqdn(char ** fqdn)889 void strip_fqdn(char **fqdn)
890 {
891 	char *tmp;
892 	if(!fqdn || !*fqdn)
893 		return;
894 	if((tmp=strchr(*fqdn, '.')))
895 		*tmp='\0';
896 }
897