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