Line data Source code
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.
28 6 : int do_quick_read(struct asfd *asfd, const char *datapth, struct cntr *cntr)
29 : {
30 6 : int r=0;
31 : struct iobuf *rbuf;
32 6 : if(asfd->as->read_quick(asfd->as)) return -1;
33 6 : rbuf=asfd->rbuf;
34 :
35 6 : if(rbuf->buf)
36 : {
37 0 : if(rbuf->cmd==CMD_MESSAGE
38 0 : || rbuf->cmd==CMD_WARNING)
39 : {
40 0 : log_recvd(rbuf, cntr, 0);
41 : }
42 0 : 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 0 : if(datapth && !strcmp(rbuf->buf, datapth))
48 0 : r=1;
49 : }
50 : else
51 : {
52 0 : iobuf_log_unexpected(rbuf, __func__);
53 0 : r=-1;
54 : }
55 0 : iobuf_free_content(rbuf);
56 : }
57 6 : return r;
58 : }
59 :
60 0 : 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 0 : int ret=0;
66 0 : int zret=0;
67 :
68 : unsigned have;
69 : z_stream strm;
70 0 : 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 0 : strm.zalloc = Z_NULL;
78 0 : strm.zfree = Z_NULL;
79 0 : strm.opaque = Z_NULL;
80 0 : if((zret=deflateInit2(&strm, compression, Z_DEFLATED, (15+16),
81 : 8, Z_DEFAULT_STRATEGY))!=Z_OK)
82 : return -1;
83 :
84 : do
85 : {
86 0 : strm.avail_in=fzp_read(fzp, in, ZCHUNK);
87 0 : if(!compression && !strm.avail_in) break;
88 :
89 0 : *bytes+=strm.avail_in;
90 :
91 0 : if(strm.avail_in) flush=Z_NO_FLUSH;
92 0 : else flush=Z_FINISH;
93 :
94 0 : 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 0 : if(compression)
101 : {
102 0 : strm.avail_out=ZCHUNK;
103 0 : strm.next_out=out;
104 0 : zret=deflate(&strm, flush);
105 0 : if(zret==Z_STREAM_ERROR)
106 : {
107 0 : logp("z_stream_error\n");
108 0 : ret=-1;
109 0 : break;
110 : }
111 0 : have=ZCHUNK-strm.avail_out;
112 : }
113 : else
114 : {
115 0 : have=strm.avail_in;
116 0 : memcpy(out, in, have);
117 : }
118 :
119 0 : wbuf.cmd=CMD_APPEND;
120 0 : wbuf.buf=(char *)out;
121 0 : wbuf.len=have;
122 0 : if(asfd->write(asfd, &wbuf))
123 : {
124 : ret=-1;
125 : break;
126 : }
127 0 : if(quick_read && datapth)
128 : {
129 : int qr;
130 0 : if((qr=do_quick_read(asfd, datapth, cntr))<0)
131 : {
132 : ret=-1;
133 : break;
134 : }
135 0 : if(qr) // Client wants to interrupt.
136 : {
137 : goto cleanup;
138 : }
139 : }
140 0 : if(!compression) break;
141 0 : } while(!strm.avail_out);
142 :
143 0 : if(ret) break;
144 :
145 0 : if(!compression) continue;
146 :
147 0 : if(strm.avail_in) /* all input will be used */
148 : {
149 0 : ret=-1;
150 0 : logp("strm.avail_in=%d\n", strm.avail_in);
151 0 : break;
152 : }
153 0 : } while(flush!=Z_FINISH);
154 :
155 0 : if(!ret)
156 : {
157 0 : if(compression && zret!=Z_STREAM_END)
158 : {
159 0 : logp("ret OK, but zstream not finished: %d\n", zret);
160 0 : ret=-1;
161 : }
162 : }
163 :
164 : cleanup:
165 0 : deflateEnd(&strm);
166 :
167 0 : if(!ret)
168 : {
169 0 : return write_endfile(asfd, *bytes, NULL);
170 : }
171 : //logp("end of send\n");
172 : return ret;
173 : }
174 :
175 9 : int set_non_blocking(int fd)
176 : {
177 : int flags;
178 9 : if((flags = fcntl(fd, F_GETFL, 0))<0) flags = 0;
179 9 : return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
180 : }
181 :
182 1 : int set_blocking(int fd)
183 : {
184 : int flags;
185 1 : if((flags = fcntl(fd, F_GETFL, 0))<0) flags = 0;
186 1 : return fcntl(fd, F_SETFL, flags | ~O_NONBLOCK);
187 : }
188 :
189 8 : char *get_tmp_filename(const char *basis)
190 : {
191 8 : return prepend(basis, ".tmp");
192 : }
193 :
194 0 : void add_fd_to_sets(int fd, fd_set *read_set, fd_set *write_set, fd_set *err_set, int *max_fd)
195 : {
196 0 : if(read_set) FD_SET((unsigned int) fd, read_set);
197 0 : if(write_set) FD_SET((unsigned int) fd, write_set);
198 0 : if(err_set) FD_SET((unsigned int) fd, err_set);
199 :
200 0 : if(fd > *max_fd) *max_fd = fd;
201 0 : }
202 :
203 : #ifndef HAVE_WIN32
204 0 : static 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 0 : switch(addr->ss_family)
211 : {
212 : case AF_INET:
213 0 : s4=(struct sockaddr_in *)addr;
214 0 : inet_ntop(AF_INET, &s4->sin_addr, addrstr, len);
215 0 : *port=ntohs(s4->sin_port);
216 0 : break;
217 : case AF_INET6:
218 0 : s6=(struct sockaddr_in6 *)addr;
219 0 : inet_ntop(AF_INET6, &s6->sin6_addr, addrstr, len);
220 0 : *port=ntohs(s6->sin6_port);
221 0 : break;
222 : default:
223 0 : logp("unknown addr.ss_family: %d\n", addr->ss_family);
224 0 : return -1;
225 : }
226 : return 0;
227 : }
228 : #endif
229 :
230 0 : int log_peer_address(struct sockaddr_storage *addr)
231 : {
232 : #ifndef HAVE_WIN32
233 0 : uint16_t port=0;
234 0 : char addrstr[INET6_ADDRSTRLEN]="";
235 0 : if(get_address_and_port(addr, addrstr, INET6_ADDRSTRLEN, &port))
236 : return -1;
237 0 : logp("Connect from peer: %s:%d\n", addrstr, port);
238 : #endif
239 0 : return 0;
240 : }
241 :
242 0 : int set_peer_env_vars(struct sockaddr_storage *addr)
243 : {
244 : #ifndef HAVE_WIN32
245 0 : uint16_t port=0;
246 0 : char portstr[16]="";
247 0 : char addrstr[INET6_ADDRSTRLEN]="";
248 :
249 0 : if(get_address_and_port(addr, addrstr, INET6_ADDRSTRLEN, &port))
250 : return -1;
251 :
252 0 : if(setenv("REMOTE_ADDR", addrstr, 1))
253 : {
254 0 : logp("setenv REMOTE_ADDR to %s failed: %s\n",
255 0 : addrstr, strerror(errno));
256 0 : return -1;
257 : }
258 0 : snprintf(portstr, sizeof(portstr), "%d", port);
259 0 : if(setenv("REMOTE_PORT", portstr, 1))
260 : {
261 0 : logp("setenv REMOTE_PORT failed: %s\n", strerror(errno));
262 0 : return -1;
263 : }
264 : #endif
265 : return 0;
266 : }
267 :
268 0 : int set_keepalive(int fd, int value)
269 : {
270 0 : int keepalive=value;
271 0 : if(setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
272 : (char *)&keepalive, sizeof(keepalive)))
273 : {
274 0 : logp("setsockopt keepalive=%d failed: %s\n",
275 0 : value, strerror(errno));
276 0 : return -1;
277 : }
278 : return 0;
279 : }
280 :
281 0 : int init_client_socket(const char *host, const char *port)
282 : {
283 0 : int rfd=-1;
284 : int gai_ret;
285 : struct addrinfo hints;
286 : struct addrinfo *result;
287 : struct addrinfo *rp;
288 :
289 : memset(&hints, 0, sizeof(struct addrinfo));
290 : hints.ai_family = AF_UNSPEC;
291 0 : hints.ai_socktype = SOCK_STREAM;
292 : hints.ai_flags = 0;
293 : hints.ai_protocol = 0;
294 :
295 0 : if((gai_ret=getaddrinfo(host, port, &hints, &result)))
296 : {
297 0 : logp("getaddrinfo: %s\n", gai_strerror(gai_ret));
298 0 : return -1;
299 : }
300 :
301 0 : for(rp=result; rp; rp=rp->ai_next)
302 : {
303 0 : rfd=socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
304 0 : if(rfd<0) continue;
305 0 : set_keepalive(rfd, 1);
306 0 : if(connect(rfd, rp->ai_addr, rp->ai_addrlen) != -1) break;
307 0 : close_fd(&rfd);
308 : }
309 0 : freeaddrinfo(result);
310 0 : if(!rp)
311 : {
312 : /* host==NULL and AI_PASSIVE not set -> loopback */
313 0 : logp("could not connect to %s:%s\n",
314 : host?host:"loopback", port);
315 0 : close_fd(&rfd);
316 0 : return -1;
317 : }
318 0 : reuseaddr(rfd);
319 :
320 : #ifdef HAVE_WIN32
321 : setmode(rfd, O_BINARY);
322 : #endif
323 0 : return rfd;
324 : }
325 :
326 0 : void reuseaddr(int fd)
327 : {
328 0 : int optval=1;
329 : #ifdef HAVE_OLD_SOCKOPT
330 : #define sockopt_val_t char *
331 : #else
332 : #define sockopt_val_t void *
333 : #endif
334 0 : if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
335 : (sockopt_val_t)&optval, sizeof(optval))<0)
336 0 : logp("Error: setsockopt SO_REUSEADDR: %s",
337 0 : strerror(errno));
338 0 : }
339 :
340 0 : void setup_signal(int sig, void handler(int sig))
341 : {
342 : struct sigaction sa;
343 : memset(&sa, 0, sizeof(sa));
344 0 : sa.sa_handler=handler;
345 0 : sigaction(sig, &sa, NULL);
346 0 : }
347 :
348 : /* Function based on src/lib/priv.c from bacula. */
349 0 : int chuser_and_or_chgrp(const char *user, const char *group)
350 : {
351 : #ifndef HAVE_WIN32
352 0 : struct passwd *passw = NULL;
353 0 : struct group *grp = NULL;
354 : gid_t gid;
355 : uid_t uid;
356 0 : char *username=NULL;
357 :
358 0 : if(!user && !group) return 0;
359 :
360 0 : if(user)
361 : {
362 0 : if(!(passw=getpwnam(user)))
363 : {
364 0 : logp("could not find user '%s': %s\n",
365 0 : user, strerror(errno));
366 0 : return -1;
367 : }
368 : }
369 : else
370 : {
371 0 : if(!(passw=getpwuid(getuid())))
372 : {
373 0 : logp("could not find password entry: %s\n",
374 0 : strerror(errno));
375 0 : return -1;
376 : }
377 0 : user=passw->pw_name;
378 : }
379 : // Any OS uname pointer may get overwritten, so save name, uid, and gid
380 0 : if(!(username=strdup_w(user, __func__)))
381 : return -1;
382 0 : uid=passw->pw_uid;
383 0 : gid=passw->pw_gid;
384 0 : if(group)
385 : {
386 0 : if(!(grp=getgrnam(group)))
387 : {
388 0 : logp("could not find group '%s': %s\n", group,
389 0 : strerror(errno));
390 0 : free_w(&username);
391 0 : return -1;
392 : }
393 0 : gid=grp->gr_gid;
394 : }
395 0 : if(gid!=getgid() // do not do it if we already have the same gid.
396 0 : && initgroups(username, gid))
397 : {
398 0 : if(grp)
399 0 : logp("could not initgroups for group '%s', user '%s': %s\n", group, user, strerror(errno));
400 : else
401 0 : logp("could not initgroups for user '%s': %s\n", user, strerror(errno));
402 0 : free_w(&username);
403 0 : return -1;
404 : }
405 0 : free_w(&username);
406 0 : if(grp)
407 : {
408 0 : if(gid!=getgid() // do not do it if we already have the same gid
409 0 : && setgid(gid))
410 : {
411 0 : logp("could not set group '%s': %s\n", group,
412 0 : strerror(errno));
413 0 : return -1;
414 : }
415 : }
416 0 : if(uid!=getuid() // do not do it if we already have the same uid
417 0 : && setuid(uid))
418 : {
419 0 : logp("could not set specified user '%s': %s\n", username,
420 0 : strerror(errno));
421 0 : return -1;
422 : }
423 : #endif
424 : return 0;
425 : }
426 :
427 : static const char *format_datestr(const struct tm *ctm)
428 : {
429 : static char buf[32]="";
430 127 : strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", ctm);
431 : return buf;
432 : }
433 :
434 127 : const char *getdatestr(const time_t t)
435 : {
436 127 : const struct tm *ctm=NULL;
437 :
438 127 : if(!t
439 127 : || !(ctm=gmtime(&t)))
440 : return "never";
441 127 : return format_datestr(ctm);
442 : }
443 :
444 0 : const char *getlocaldatestr(const time_t t)
445 : {
446 0 : const struct tm *ctm=NULL;
447 0 : ctm=localtime(&t);
448 0 : return format_datestr(ctm);
449 : }
450 :
451 0 : const char *time_taken(time_t d)
452 : {
453 : static char str[32]="";
454 0 : int seconds=0;
455 0 : int minutes=0;
456 0 : int hours=0;
457 0 : int days=0;
458 0 : char ss[4]="";
459 0 : char ms[4]="";
460 0 : char hs[4]="";
461 0 : char ds[4]="";
462 0 : seconds=d % 60;
463 0 : minutes=(d/60) % 60;
464 0 : hours=(d/60/60) % 24;
465 0 : days=(d/60/60/24);
466 0 : if(days)
467 : {
468 : snprintf(ds, sizeof(ds), "%02d:", days);
469 : snprintf(hs, sizeof(hs), "%02d:", hours);
470 : }
471 0 : else if(hours)
472 : {
473 : snprintf(hs, sizeof(hs), "%02d:", hours);
474 : }
475 : snprintf(ms, sizeof(ms), "%02d:", minutes);
476 : snprintf(ss, sizeof(ss), "%02d", seconds);
477 : snprintf(str, sizeof(str), "%s%s%s%s", ds, hs, ms, ss);
478 0 : return str;
479 : }
480 :
481 : // Not in dpth.c so that Windows client can see it.
482 14 : int dpth_protocol1_is_compressed(int compressed, const char *datapath)
483 : {
484 14 : const char *dp=NULL;
485 :
486 14 : if(compressed>0) return compressed;
487 12 : if(compressed==0) return 0;
488 :
489 : /* Legacy - if the compressed value is -1 - that is, it is not set in
490 : the manifest, deduce the value from the datapath. */
491 6 : if((dp=strrchr(datapath, '.')) && !strcmp(dp, ".gz")) return 1;
492 6 : return 0;
493 : }
494 :
495 313 : long version_to_long(const char *version)
496 : {
497 313 : long ret=0;
498 313 : char *copy=NULL;
499 313 : char *tok1=NULL;
500 313 : char *tok2=NULL;
501 313 : char *tok3=NULL;
502 313 : if(!version || !*version) return 0;
503 310 : if(!(copy=strdup_w(version, __func__)))
504 : return -1;
505 310 : if(!(tok1=strtok(copy, "."))
506 310 : || !(tok2=strtok(NULL, "."))
507 310 : || !(tok3=strtok(NULL, ".")))
508 : {
509 0 : free_w(©);
510 0 : return -1;
511 : }
512 310 : ret+=atol(tok3);
513 310 : ret+=atol(tok2)*100;
514 310 : ret+=atol(tok1)*100*100;
515 310 : free_w(©);
516 310 : return ret;
517 : }
518 :
519 : /* These receive_a_file() and send_file() functions are for use by extra_comms
520 : and the CA stuff, rather than backups/restores. */
521 0 : int receive_a_file(struct asfd *asfd, const char *path, struct cntr *cntr)
522 : {
523 0 : int ret=-1;
524 0 : struct BFILE *bfd=NULL;
525 0 : uint64_t rcvdbytes=0;
526 0 : uint64_t sentbytes=0;
527 :
528 0 : if(!(bfd=bfile_alloc())) goto end;
529 0 : bfile_init(bfd, 0, cntr);
530 : #ifdef HAVE_WIN32
531 : bfd->set_win32_api(bfd, 0);
532 : #endif
533 0 : if(bfd->open(bfd, asfd, path,
534 : O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
535 : S_IRUSR | S_IWUSR))
536 : {
537 : struct berrno be;
538 0 : berrno_init(&be);
539 0 : logp("Could not open for writing %s: %s\n",
540 0 : path, berrno_bstrerror(&be, errno));
541 : goto end;
542 : }
543 :
544 0 : ret=transfer_gzfile_in(asfd, bfd, &rcvdbytes, &sentbytes);
545 0 : if(bfd->close(bfd, asfd))
546 : {
547 0 : logp("error closing %s in %s\n", path, __func__);
548 0 : goto end;
549 : }
550 0 : logp("Received: %s\n", path);
551 0 : ret=0;
552 : end:
553 0 : bfd->close(bfd, asfd);
554 0 : bfile_free(&bfd);
555 0 : return ret;
556 : }
557 :
558 : /* Windows will use this function, when sending a certificate signing request.
559 : It is not using the Windows API stuff because it needs to arrive on the
560 : server side without any junk in it. */
561 0 : int send_a_file(struct asfd *asfd, const char *path, struct cntr *cntr)
562 : {
563 0 : int ret=0;
564 0 : struct fzp *fzp=NULL;
565 0 : uint64_t bytes=0;
566 0 : if(!(fzp=fzp_open(path, "rb"))
567 0 : || send_whole_file_gz(asfd, "datapth", 0, &bytes,
568 : cntr, 9 /*compression*/, fzp))
569 : {
570 : ret=-1;
571 : goto end;
572 : }
573 0 : logp("Sent %s\n", path);
574 : end:
575 0 : fzp_close(&fzp);
576 0 : return ret;
577 : }
578 :
579 206 : int strncmp_w(const char *s1, const char *s2)
580 : {
581 206 : return strncmp(s1, s2, strlen(s2));
582 : }
583 :
584 : // Strip any trailing slashes (unless it is '/').
585 2 : void strip_trailing_slashes(char **str)
586 : {
587 : size_t l;
588 : // FIX THIS: pretty crappy.
589 : while(1)
590 : {
591 2 : if(!str || !*str
592 2 : || !strcmp(*str, "/")
593 2 : || !(l=strlen(*str))
594 2 : || (*str)[l-1]!='/')
595 2 : return;
596 0 : (*str)[l-1]='\0';
597 0 : }
598 : }
599 :
600 0 : int breakpoint(int breakpoint, const char *func)
601 : {
602 0 : logp("Breakpoint %d hit in %s\n", breakpoint, func);
603 0 : return -1;
604 : }
605 :
606 : /* Windows users have a nasty habit of putting in backslashes. Convert them. */
607 : #ifdef HAVE_WIN32
608 : void convert_backslashes(char **path)
609 : {
610 : char *p=NULL;
611 : for(p=*path; *p; p++) if(*p=='\\') *p='/';
612 : }
613 : #endif
614 :
615 0 : char *encode_time(time_t utime, char *buf)
616 : {
617 : const struct tm *tm;
618 0 : int n=0;
619 0 : time_t time=utime;
620 :
621 : #ifdef HAVE_WIN32
622 : /* Avoid a seg fault in Microsoft's CRT localtime_r(),
623 : * which incorrectly references a NULL returned from gmtime() if
624 : * time is negative before or after the timezone adjustment. */
625 : struct tm *gtm;
626 :
627 : if(!(gtm=gmtime(&time))) return buf;
628 :
629 : if(gtm->tm_year==1970 && gtm->tm_mon==1 && gtm->tm_mday<3) return buf;
630 : #endif
631 :
632 0 : if((tm=localtime(&time)))
633 0 : n=sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d",
634 0 : tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
635 : tm->tm_hour, tm->tm_min, tm->tm_sec);
636 0 : return buf+n;
637 : }
638 :
639 3 : char *strlwr(char *s)
640 : {
641 3 : char *tmp=s;
642 3 : for(;*tmp;++tmp) *tmp=tolower((unsigned char)*tmp);
643 3 : return s;
644 : }
645 :
646 1 : void strip_fqdn(char **fqdn)
647 : {
648 : char *tmp;
649 1 : if(!fqdn || !*fqdn)
650 1 : return;
651 1 : if((tmp=strchr(*fqdn, '.')))
652 1 : *tmp='\0';
653 : }
654 :
|