Line data Source code
1 : #include "burp.h"
2 : #include "sbuf.h"
3 : #include "alloc.h"
4 : #include "asfd.h"
5 : #include "attribs.h"
6 : #include "cmd.h"
7 : #include "conf.h"
8 : #include "handy.h"
9 : #include "log.h"
10 : #include "msg.h"
11 : #include "pathcmp.h"
12 : #include "protocol2/blk.h"
13 :
14 132954 : struct sbuf *sbuf_alloc(enum protocol protocol)
15 : {
16 : struct sbuf *sb;
17 132954 : if(!(sb=(struct sbuf *)calloc_w(1, sizeof(struct sbuf), __func__)))
18 : return NULL;
19 132954 : iobuf_init(&sb->path);
20 132954 : iobuf_init(&sb->attr);
21 132954 : sb->attr.cmd=CMD_ATTRIBS;
22 132954 : iobuf_init(&sb->link);
23 132954 : iobuf_init(&sb->endfile);
24 132954 : sb->compression=-1;
25 132954 : if(protocol==PROTO_1)
26 : {
27 32298 : if(!(sb->protocol1=sbuf_protocol1_alloc())) return NULL;
28 : }
29 : else
30 : {
31 100656 : if(!(sb->protocol2=sbuf_protocol2_alloc())) return NULL;
32 : }
33 : return sb;
34 : }
35 :
36 229758 : void sbuf_free_content(struct sbuf *sb)
37 : {
38 229758 : iobuf_free_content(&sb->path);
39 229758 : iobuf_free_content(&sb->attr);
40 229758 : iobuf_free_content(&sb->link);
41 229758 : iobuf_free_content(&sb->endfile);
42 229758 : memset(&(sb->statp), 0, sizeof(sb->statp));
43 229758 : sb->compression=-1;
44 229758 : sb->winattr=0;
45 229758 : sb->flags=0;
46 229758 : sbuf_protocol1_free_content(sb->protocol1);
47 229758 : sbuf_protocol2_free_content();
48 229758 : }
49 :
50 383714 : void sbuf_free(struct sbuf **sb)
51 : {
52 383714 : if(!sb || !*sb) return;
53 132954 : sbuf_free_content(*sb);
54 132954 : free_v((void **)&((*sb)->protocol1));
55 132954 : free_v((void **)&((*sb)->protocol2));
56 132954 : free_v((void **)sb);
57 : }
58 :
59 110 : int sbuf_is_link(struct sbuf *sb)
60 : {
61 110 : return iobuf_is_link(&sb->path);
62 : }
63 :
64 219251 : int sbuf_is_filedata(struct sbuf *sb)
65 : {
66 227520 : return iobuf_is_filedata(&sb->path);
67 : }
68 :
69 10733 : int sbuf_is_vssdata(struct sbuf *sb)
70 : {
71 10831 : return iobuf_is_vssdata(&sb->path);
72 : }
73 :
74 85249 : int sbuf_is_encrypted(struct sbuf *sb)
75 : {
76 85249 : return iobuf_is_encrypted(&sb->path);
77 : }
78 :
79 117 : int sbuf_is_metadata(struct sbuf *sb)
80 : {
81 117 : return iobuf_is_metadata(&sb->path);
82 : }
83 :
84 0 : int sbuf_is_estimatable(struct sbuf *sb)
85 : {
86 0 : return iobuf_is_estimatable(&sb->path);
87 : }
88 :
89 91874 : int sbuf_to_manifest(struct sbuf *sb, struct fzp *fzp)
90 : {
91 91874 : if(!sb->path.buf) return 0;
92 :
93 91874 : if(sb->protocol1)
94 : {
95 11912 : if(sb->protocol1->datapth.buf
96 6311 : && iobuf_send_msg_fzp(&(sb->protocol1->datapth), fzp))
97 : return -1;
98 :
99 11912 : if(iobuf_send_msg_fzp(&sb->attr, fzp))
100 : return -1;
101 : }
102 : else
103 : {
104 : // Hackity hack: Strip the file index from the beginning of
105 : // the attribs so that manifests where nothing changed are
106 : // identical to each other. Better would be to preserve the
107 : // index.
108 : char *cp;
109 79962 : if(!(cp=strchr(sb->attr.buf, ' ')))
110 : {
111 0 : logp("Strange attributes: %s\n",
112 : iobuf_to_printable(&sb->attr));
113 0 : return -1;
114 : }
115 79962 : if(send_msg_fzp(fzp, CMD_ATTRIBS,
116 79962 : cp, sb->attr.len-(cp-sb->attr.buf)))
117 : return -1;
118 : }
119 91874 : if(iobuf_send_msg_fzp(&sb->path, fzp))
120 : return -1;
121 91874 : if(sb->link.buf
122 15876 : && iobuf_send_msg_fzp(&sb->link, fzp))
123 : return -1;
124 91874 : if(sb->endfile.buf
125 6315 : && iobuf_send_msg_fzp(&sb->endfile, fzp))
126 : return -1;
127 :
128 : return 0;
129 : }
130 :
131 33804 : int sbuf_to_manifest_cntr(struct sbuf *sb, struct fzp *fzp,
132 : enum cntr_manio what)
133 : {
134 33804 : if(!sb->path.buf) return 0;
135 33804 : fzp_printf(fzp, "%c", (char)what);
136 33804 : return iobuf_send_msg_fzp(&sb->path, fzp);
137 : }
138 :
139 : // Like pathcmp, but sort entries that have the same paths so that metadata
140 : // comes later, and vss comes earlier, and trailing vss comes later.
141 23 : int sbuf_pathcmp(struct sbuf *a, struct sbuf *b)
142 : {
143 23 : return iobuf_pathcmp(&a->path, &b->path);
144 : }
145 :
146 : enum parse_ret
147 : {
148 : PARSE_RET_ERROR=-1,
149 : PARSE_RET_NEED_MORE=0,
150 : PARSE_RET_COMPLETE=1,
151 : PARSE_RET_FINISHED=2,
152 : };
153 :
154 354856 : static enum parse_ret parse_cmd(struct sbuf *sb, struct asfd *asfd,
155 : struct iobuf *rbuf, struct blk *blk, struct cntr *cntr)
156 : {
157 354856 : switch(rbuf->cmd)
158 : {
159 : case CMD_ATTRIBS:
160 60754 : if(sb->protocol2)
161 47097 : sbuf_free_content(sb);
162 : else
163 : {
164 13657 : if(sb->protocol1->datapth.buf)
165 : // protocol 1 phase 2+ file data
166 : // starts with datapth.
167 8303 : iobuf_free_content(&sb->attr);
168 : else
169 : // protocol 1 phase 1 or non file data
170 : // starts with attribs
171 5354 : sbuf_free_content(sb);
172 : }
173 60754 : iobuf_move(&sb->attr, rbuf);
174 60754 : attribs_decode(sb);
175 60754 : return PARSE_RET_NEED_MORE;
176 :
177 : case CMD_FILE:
178 : case CMD_DIRECTORY:
179 : case CMD_SOFT_LINK:
180 : case CMD_HARD_LINK:
181 : case CMD_SPECIAL:
182 : // Stuff not currently supported in burp-2, but OK
183 : // to find in burp-1.
184 : case CMD_ENC_FILE:
185 : case CMD_METADATA:
186 : case CMD_ENC_METADATA:
187 : case CMD_EFS_FILE:
188 : case CMD_VSS:
189 : case CMD_ENC_VSS:
190 : case CMD_VSS_T:
191 : case CMD_ENC_VSS_T:
192 69859 : if(!sb->attr.buf)
193 : {
194 1 : log_and_send(asfd, "read cmd with no attribs");
195 1 : return PARSE_RET_ERROR;
196 : }
197 69858 : if(sb->flags & SBUF_NEED_LINK)
198 : {
199 9124 : if(cmd_is_link(rbuf->cmd))
200 : {
201 9124 : iobuf_free_content(&sb->link);
202 9124 : iobuf_move(&sb->link, rbuf);
203 9124 : sb->flags &= ~SBUF_NEED_LINK;
204 9124 : return PARSE_RET_COMPLETE;
205 : }
206 : else
207 : {
208 0 : log_and_send(asfd, "got non-link after link in manifest");
209 0 : return PARSE_RET_NEED_MORE;
210 : }
211 : }
212 : else
213 : {
214 60734 : if(iobuf_relative_path_attack(rbuf))
215 : return PARSE_RET_ERROR;
216 :
217 60734 : iobuf_free_content(&sb->path);
218 60734 : iobuf_move(&sb->path, rbuf);
219 60734 : if(cmd_is_link(rbuf->cmd))
220 : {
221 9124 : sb->flags |= SBUF_NEED_LINK;
222 9124 : return PARSE_RET_NEED_MORE;
223 : }
224 51610 : else if(sb->protocol1
225 12254 : && sb->protocol1->datapth.buf)
226 : {
227 : // Protocol1 client restore reads
228 : // CMD_APPEND and CMD_END_FILE in the
229 : // calling function, so pretend it is
230 : // complete if we have the hack flag.
231 8303 : if(sb->flags & SBUF_CLIENT_RESTORE_HACK)
232 : return PARSE_RET_COMPLETE;
233 8299 : return PARSE_RET_NEED_MORE;
234 : }
235 : return PARSE_RET_COMPLETE;
236 : }
237 : #ifndef HAVE_WIN32
238 : case CMD_SIG:
239 : // Fill in the sig/block, if the caller provided
240 : // a pointer for one. Server only.
241 198651 : if(!blk) return PARSE_RET_NEED_MORE;
242 :
243 : // Just fill in the sig details.
244 46462 : if(blk_set_from_iobuf_sig_and_savepath(blk, rbuf))
245 : return PARSE_RET_ERROR;
246 46462 : blk->got_save_path=1;
247 46462 : iobuf_free_content(rbuf);
248 46462 : return PARSE_RET_COMPLETE;
249 : #endif
250 : case CMD_DATA:
251 : // Need to write the block to disk.
252 : // Client only.
253 14 : if(!blk) return PARSE_RET_NEED_MORE;
254 14 : blk->data=rbuf->buf;
255 14 : blk->length=rbuf->len;
256 14 : rbuf->buf=NULL;
257 14 : return PARSE_RET_COMPLETE;
258 : case CMD_MESSAGE:
259 : case CMD_WARNING:
260 0 : log_recvd(rbuf, cntr, 1);
261 0 : return PARSE_RET_NEED_MORE;
262 : case CMD_GEN:
263 43 : if(!strcmp(rbuf->buf, "restoreend")
264 39 : || !strcmp(rbuf->buf, "phase1end")
265 1 : || !strcmp(rbuf->buf, "backupphase2")
266 : // Think these are protocol1 things.
267 1 : || !strcmp(rbuf->buf, "backupend")
268 1 : || !strcmp(rbuf->buf, "estimateend"))
269 : return PARSE_RET_FINISHED;
270 1 : iobuf_log_unexpected(rbuf, __func__);
271 1 : return PARSE_RET_ERROR;
272 : case CMD_FINGERPRINT:
273 698 : if(blk && blk_set_from_iobuf_fingerprint(blk, rbuf))
274 : return PARSE_RET_ERROR;
275 698 : iobuf_free_content(&sb->path);
276 698 : iobuf_move(&sb->path, rbuf);
277 698 : return PARSE_RET_COMPLETE;
278 : case CMD_MANIFEST:
279 80 : if(iobuf_relative_path_attack(rbuf))
280 : return PARSE_RET_ERROR;
281 80 : iobuf_free_content(&sb->path);
282 80 : iobuf_move(&sb->path, rbuf);
283 80 : return PARSE_RET_COMPLETE;
284 : case CMD_ERROR:
285 0 : logp("got error: %s\n", rbuf->buf);
286 0 : return PARSE_RET_ERROR;
287 : case CMD_DATAPTH:
288 8304 : if(iobuf_relative_path_attack(rbuf))
289 : return PARSE_RET_ERROR;
290 :
291 8304 : if(!sb->protocol1)
292 : {
293 0 : iobuf_log_unexpected(rbuf, __func__);
294 0 : return PARSE_RET_ERROR;
295 : }
296 8304 : if(sb->flags & SBUF_CLIENT_RESTORE_HACK)
297 : {
298 5 : sbuf_free_content(sb);
299 5 : sb->flags |= SBUF_CLIENT_RESTORE_HACK;
300 : }
301 : else
302 8299 : sbuf_free_content(sb);
303 :
304 8304 : iobuf_move(&sb->protocol1->datapth, rbuf);
305 8304 : return PARSE_RET_NEED_MORE;
306 : case CMD_END_FILE:
307 16453 : iobuf_free_content(&sb->endfile);
308 16453 : iobuf_move(&sb->endfile, rbuf);
309 16453 : if(sb->protocol1)
310 : {
311 8269 : if(!sb->attr.buf
312 8269 : || !sb->protocol1->datapth.buf
313 8269 : || (!sbuf_is_filedata(sb)
314 98 : && !sbuf_is_vssdata(sb)))
315 : {
316 0 : logp("got unexpected cmd_endfile");
317 0 : return PARSE_RET_ERROR;
318 : }
319 : }
320 : return PARSE_RET_COMPLETE;
321 : default:
322 0 : iobuf_log_unexpected(rbuf, __func__);
323 0 : return PARSE_RET_ERROR;
324 : }
325 : logp("Fell out of switch unexpectedly in %s()\n", __func__);
326 : return PARSE_RET_ERROR;
327 : }
328 :
329 116571 : static int sbuf_fill(struct sbuf *sb, struct asfd *asfd, struct fzp *fzp,
330 : struct blk *blk, struct cntr *cntr)
331 : {
332 : static struct iobuf *rbuf;
333 : static struct iobuf localrbuf;
334 116571 : int ret=-1;
335 :
336 116571 : if(asfd) rbuf=asfd->rbuf;
337 : else
338 : {
339 : // If not given asfd, use our own iobuf.
340 116518 : memset(&localrbuf, 0, sizeof(struct iobuf));
341 116518 : rbuf=&localrbuf;
342 : }
343 : while(1)
344 : {
345 593911 : iobuf_free_content(rbuf);
346 355241 : if(fzp)
347 : {
348 355145 : if((ret=iobuf_fill_from_fzp(rbuf, fzp)))
349 : goto end;
350 : }
351 : else
352 : {
353 96 : if(asfd->read(asfd))
354 : {
355 1 : logp("error in async_read\n");
356 1 : break;
357 : }
358 : }
359 354856 : switch(parse_cmd(sb, asfd, rbuf, blk, cntr))
360 : {
361 : case PARSE_RET_NEED_MORE:
362 238670 : continue;
363 : case PARSE_RET_COMPLETE:
364 : return 0;
365 : case PARSE_RET_FINISHED:
366 : ret=1;
367 : goto end;
368 : case PARSE_RET_ERROR:
369 : default:
370 2 : ret=-1;
371 2 : goto end;
372 : }
373 : }
374 : end:
375 429 : iobuf_free_content(rbuf);
376 429 : return ret;
377 : }
378 :
379 53 : int sbuf_fill_from_net(struct sbuf *sb, struct asfd *asfd,
380 : struct blk *blk, struct cntr *cntr)
381 : {
382 53 : return sbuf_fill(sb, asfd, NULL, blk, cntr);
383 : }
384 :
385 116518 : int sbuf_fill_from_file(struct sbuf *sb, struct fzp *fzp,
386 : struct blk *blk)
387 : {
388 116518 : return sbuf_fill(sb, NULL, fzp, blk, NULL);
389 : }
|