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 :
13 32346 : struct sbuf *sbuf_alloc()
14 : {
15 : struct sbuf *sb;
16 32346 : if(!(sb=(struct sbuf *)calloc_w(1, sizeof(struct sbuf), __func__)))
17 : return NULL;
18 32346 : iobuf_init(&sb->path);
19 32346 : iobuf_init(&sb->attr);
20 32346 : sb->attr.cmd=CMD_ATTRIBS;
21 32346 : iobuf_init(&sb->link);
22 32346 : iobuf_init(&sb->endfile);
23 32346 : sb->compression=-1;
24 32346 : if(!(sb->protocol1=sbuf_protocol1_alloc())) return NULL;
25 32346 : return sb;
26 : }
27 :
28 59651 : void sbuf_free_content(struct sbuf *sb)
29 : {
30 59651 : iobuf_free_content(&sb->path);
31 59651 : iobuf_free_content(&sb->attr);
32 59651 : iobuf_free_content(&sb->link);
33 59651 : iobuf_free_content(&sb->endfile);
34 59651 : memset(&(sb->statp), 0, sizeof(sb->statp));
35 59651 : sb->compression=-1;
36 59651 : sb->winattr=0;
37 59651 : sb->flags=0;
38 59651 : sbuf_protocol1_free_content(sb->protocol1);
39 59651 : }
40 :
41 32367 : void sbuf_free(struct sbuf **sb)
42 : {
43 32367 : if(!sb || !*sb) return;
44 32346 : sbuf_free_content(*sb);
45 32346 : free_v((void **)&((*sb)->protocol1));
46 32346 : free_v((void **)sb);
47 : }
48 :
49 26 : int sbuf_is_link(struct sbuf *sb)
50 : {
51 26 : return iobuf_is_link(&sb->path);
52 : }
53 :
54 24462 : int sbuf_is_filedata(struct sbuf *sb)
55 : {
56 32744 : return iobuf_is_filedata(&sb->path);
57 : }
58 :
59 5060 : int sbuf_is_vssdata(struct sbuf *sb)
60 : {
61 5158 : return iobuf_is_vssdata(&sb->path);
62 : }
63 :
64 38 : int sbuf_is_encrypted(struct sbuf *sb)
65 : {
66 38 : return iobuf_is_encrypted(&sb->path);
67 : }
68 :
69 0 : int sbuf_is_metadata(struct sbuf *sb)
70 : {
71 0 : return iobuf_is_metadata(&sb->path);
72 : }
73 :
74 0 : int sbuf_is_estimatable(struct sbuf *sb)
75 : {
76 0 : return iobuf_is_estimatable(&sb->path);
77 : }
78 :
79 11932 : int sbuf_to_manifest(struct sbuf *sb, struct fzp *fzp)
80 : {
81 11932 : if(!sb->path.buf) return 0;
82 :
83 11932 : if(sb->protocol1)
84 : {
85 11932 : if(sb->protocol1->datapth.buf
86 6324 : && iobuf_send_msg_fzp(&(sb->protocol1->datapth), fzp))
87 : return -1;
88 :
89 11932 : if(iobuf_send_msg_fzp(&sb->attr, fzp))
90 : return -1;
91 : }
92 : else
93 : {
94 : // Hackity hack: Strip the file index from the beginning of
95 : // the attribs so that manifests where nothing changed are
96 : // identical to each other. Better would be to preserve the
97 : // index.
98 : char *cp;
99 0 : if(!(cp=strchr(sb->attr.buf, ' ')))
100 : {
101 0 : logp("Strange attributes: %s\n",
102 : iobuf_to_printable(&sb->attr));
103 0 : return -1;
104 : }
105 0 : if(send_msg_fzp(fzp, CMD_ATTRIBS,
106 0 : cp, sb->attr.len-(cp-sb->attr.buf)))
107 : return -1;
108 : }
109 11932 : if(iobuf_send_msg_fzp(&sb->path, fzp))
110 : return -1;
111 11932 : if(sb->link.buf
112 1426 : && iobuf_send_msg_fzp(&sb->link, fzp))
113 : return -1;
114 11932 : if(sb->endfile.buf
115 6324 : && iobuf_send_msg_fzp(&sb->endfile, fzp))
116 : return -1;
117 :
118 : return 0;
119 : }
120 :
121 84 : int sbuf_to_manifest_cntr(struct sbuf *sb, struct fzp *fzp,
122 : enum cntr_manio what)
123 : {
124 84 : if(!sb->path.buf) return 0;
125 84 : fzp_printf(fzp, "%c", (char)what);
126 84 : return iobuf_send_msg_fzp(&sb->path, fzp);
127 : }
128 :
129 : // Like pathcmp, but sort entries that have the same paths so that metadata
130 : // comes later, and vss comes earlier, and trailing vss comes later.
131 17 : int sbuf_pathcmp(struct sbuf *a, struct sbuf *b)
132 : {
133 17 : return iobuf_pathcmp(&a->path, &b->path);
134 : }
135 :
136 : enum parse_ret
137 : {
138 : PARSE_RET_ERROR=-1,
139 : PARSE_RET_NEED_MORE=0,
140 : PARSE_RET_COMPLETE=1,
141 : PARSE_RET_FINISHED=2,
142 : };
143 :
144 45359 : static enum parse_ret parse_cmd(struct sbuf *sb, struct asfd *asfd,
145 : struct iobuf *rbuf, struct cntr *cntr)
146 : {
147 45359 : switch(rbuf->cmd)
148 : {
149 : case CMD_ATTRIBS:
150 13677 : if(sb->protocol1->datapth.buf)
151 8316 : iobuf_free_content(&sb->attr);
152 : else
153 5361 : sbuf_free_content(sb);
154 13677 : iobuf_move(&sb->attr, rbuf);
155 13677 : attribs_decode(sb);
156 13677 : return PARSE_RET_NEED_MORE;
157 :
158 : case CMD_FILE:
159 : case CMD_DIRECTORY:
160 : case CMD_SOFT_LINK:
161 : case CMD_HARD_LINK:
162 : case CMD_SPECIAL:
163 : // Stuff not currently supported in burp-2, but OK
164 : // to find in burp-1.
165 : case CMD_ENC_FILE:
166 : case CMD_METADATA:
167 : case CMD_ENC_METADATA:
168 : case CMD_EFS_FILE:
169 : case CMD_VSS:
170 : case CMD_ENC_VSS:
171 : case CMD_VSS_T:
172 : case CMD_ENC_VSS_T:
173 15064 : if(!sb->attr.buf)
174 : {
175 1 : log_and_send(asfd, "read cmd with no attribs");
176 1 : return PARSE_RET_ERROR;
177 : }
178 15063 : if(sb->flags & SBUF_NEED_LINK)
179 : {
180 1396 : if(cmd_is_link(rbuf->cmd))
181 : {
182 1396 : iobuf_free_content(&sb->link);
183 1396 : iobuf_move(&sb->link, rbuf);
184 1396 : sb->flags &= ~SBUF_NEED_LINK;
185 1396 : return PARSE_RET_COMPLETE;
186 : }
187 : else
188 : {
189 0 : log_and_send(asfd, "got non-link after link in manifest");
190 0 : return PARSE_RET_NEED_MORE;
191 : }
192 : }
193 : else
194 : {
195 13667 : if(iobuf_relative_path_attack(rbuf))
196 : return PARSE_RET_ERROR;
197 :
198 13667 : iobuf_free_content(&sb->path);
199 13667 : iobuf_move(&sb->path, rbuf);
200 13667 : if(cmd_is_link(rbuf->cmd))
201 : {
202 1396 : sb->flags |= SBUF_NEED_LINK;
203 1396 : return PARSE_RET_NEED_MORE;
204 : }
205 12271 : else if(sb->protocol1
206 12271 : && sb->protocol1->datapth.buf)
207 : {
208 : // Protocol1 client restore reads
209 : // CMD_APPEND and CMD_END_FILE in the
210 : // calling function, so pretend it is
211 : // complete if we have the hack flag.
212 8316 : if(sb->flags & SBUF_CLIENT_RESTORE_HACK)
213 : return PARSE_RET_COMPLETE;
214 8312 : return PARSE_RET_NEED_MORE;
215 : }
216 : return PARSE_RET_COMPLETE;
217 : }
218 : case CMD_MESSAGE:
219 : case CMD_WARNING:
220 0 : log_recvd(rbuf, cntr, 1);
221 0 : return PARSE_RET_NEED_MORE;
222 : case CMD_GEN:
223 19 : if(!strcmp(rbuf->buf, "restoreend")
224 17 : || !strcmp(rbuf->buf, "phase1end")
225 1 : || !strcmp(rbuf->buf, "backupphase2")
226 : // Think these are protocol1 things.
227 1 : || !strcmp(rbuf->buf, "backupend")
228 1 : || !strcmp(rbuf->buf, "estimateend"))
229 : return PARSE_RET_FINISHED;
230 1 : iobuf_log_unexpected(rbuf, __func__);
231 1 : return PARSE_RET_ERROR;
232 : case CMD_MANIFEST:
233 0 : if(iobuf_relative_path_attack(rbuf))
234 : return PARSE_RET_ERROR;
235 0 : iobuf_free_content(&sb->path);
236 0 : iobuf_move(&sb->path, rbuf);
237 0 : return PARSE_RET_COMPLETE;
238 : case CMD_ERROR:
239 0 : logp("got error: %s\n", rbuf->buf);
240 0 : return PARSE_RET_ERROR;
241 : case CMD_DATAPTH:
242 8317 : if(iobuf_relative_path_attack(rbuf))
243 : return PARSE_RET_ERROR;
244 :
245 8317 : if(!sb->protocol1)
246 : {
247 0 : iobuf_log_unexpected(rbuf, __func__);
248 0 : return PARSE_RET_ERROR;
249 : }
250 8317 : if(sb->flags & SBUF_CLIENT_RESTORE_HACK)
251 : {
252 5 : sbuf_free_content(sb);
253 5 : sb->flags |= SBUF_CLIENT_RESTORE_HACK;
254 : }
255 : else
256 8312 : sbuf_free_content(sb);
257 :
258 8317 : iobuf_move(&sb->protocol1->datapth, rbuf);
259 8317 : return PARSE_RET_NEED_MORE;
260 : case CMD_END_FILE:
261 8282 : iobuf_free_content(&sb->endfile);
262 8282 : iobuf_move(&sb->endfile, rbuf);
263 8282 : if(sb->protocol1)
264 : {
265 8282 : if(!sb->attr.buf
266 8282 : || !sb->protocol1->datapth.buf
267 8282 : || (!sbuf_is_filedata(sb)
268 98 : && !sbuf_is_vssdata(sb)))
269 : {
270 0 : logp("got unexpected cmd_endfile");
271 0 : return PARSE_RET_ERROR;
272 : }
273 : }
274 : return PARSE_RET_COMPLETE;
275 : default:
276 0 : iobuf_log_unexpected(rbuf, __func__);
277 0 : return PARSE_RET_ERROR;
278 : }
279 : logp("Fell out of switch unexpectedly in %s()\n", __func__);
280 : return PARSE_RET_ERROR;
281 : }
282 :
283 13791 : static int sbuf_fill(struct sbuf *sb, struct asfd *asfd, struct fzp *fzp,
284 : struct cntr *cntr)
285 : {
286 : static struct iobuf *rbuf;
287 : static struct iobuf localrbuf;
288 13791 : int ret=-1;
289 :
290 13791 : if(asfd) rbuf=asfd->rbuf;
291 : else
292 : {
293 : // If not given asfd, use our own iobuf.
294 13777 : memset(&localrbuf, 0, sizeof(struct iobuf));
295 13777 : rbuf=&localrbuf;
296 : }
297 : while(1)
298 : {
299 77195 : iobuf_free_content(rbuf);
300 45493 : if(fzp)
301 : {
302 45461 : if((ret=iobuf_fill_from_fzp(rbuf, fzp)))
303 : goto end;
304 : }
305 : else
306 : {
307 32 : if(asfd->read(asfd))
308 : {
309 1 : logp("error in async_read\n");
310 1 : break;
311 : }
312 : }
313 45359 : switch(parse_cmd(sb, asfd, rbuf, cntr))
314 : {
315 : case PARSE_RET_NEED_MORE:
316 31702 : continue;
317 : case PARSE_RET_COMPLETE:
318 : return 0;
319 : case PARSE_RET_FINISHED:
320 : ret=1;
321 : goto end;
322 : case PARSE_RET_ERROR:
323 : default:
324 2 : ret=-1;
325 2 : goto end;
326 : }
327 : }
328 : end:
329 154 : iobuf_free_content(rbuf);
330 154 : return ret;
331 : }
332 :
333 14 : int sbuf_fill_from_net(struct sbuf *sb, struct asfd *asfd,
334 : struct cntr *cntr)
335 : {
336 14 : return sbuf_fill(sb, asfd, NULL, cntr);
337 : }
338 :
339 13777 : int sbuf_fill_from_file(struct sbuf *sb, struct fzp *fzp)
340 : {
341 13777 : return sbuf_fill(sb, NULL, fzp, NULL);
342 : }
|