]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/win_efs.c
Remove old Bacula Systems notices
[bacula/bacula] / bacula / src / filed / win_efs.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2018 Kern Sibbald
5
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13
14    This notice must be preserved when any source code is
15    conveyed and/or propagated.
16
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  *  Bacula File Daemon  Windows EFS restore
21  *
22  *    Kern Sibbald, September MMXIV
23  *
24  */
25
26 #include "bacula.h"
27 #include "filed.h"
28 #include "ch.h"
29 #include "restore.h"
30 #include "backup.h"
31
32 #ifdef TEST_WORKER
33 /*
34  * This is the test version of the worker routines, which simulates
35  *  Windows EFS backup on Linux.
36  *
37  * This subroutine is called back from the Windows
38  *  WriteEncryptedFileRaw and returns a single buffer of data or
39  *  sets ulLength = 0 to indicate the end.
40  */
41 static uint32_t test_write_efs_data_cb(char *pbData, void *arctx, uint32_t *len)
42 {
43    r_ctx *rctx = (r_ctx *)arctx;
44    worker *wrk = (worker *)rctx->efs;
45    char *head, *buf;
46    uint32_t data_len;
47    int32_t count;
48
49    head = (char *)wrk->dequeue();      /* dequeue buffer to write */
50    Dmsg1(200, "dequeue buffer. head=%p\n", head);
51    if (!head) {
52       *len = 0;
53       Dmsg0(200, "cb got NULL.\n");
54    } else {
55       data_len = *(int32_t *)head;
56       Dmsg1(200, "data_len=%d\n", data_len);
57       if (data_len == 0) {
58          Dmsg0(200, "Length is zero.\n");
59          wrk->push_free_buffer(head);
60          return ERROR_BUFFER_OVERFLOW;
61       }
62       if (data_len > *len) {
63          Dmsg2(200, "Restore data %ld bytes too long for Microsoft buffer %ld bytes.\n",
64             data_len, *len);
65          *len = 0;
66          errno = b_errno_win32;
67          wrk->push_free_buffer(head);
68          return ERROR_BUFFER_OVERFLOW;
69       } else {
70          buf = head + sizeof(uint32_t);    /* Point to buffer */
71          count = *(int32_t *)buf;
72          buf += sizeof(int32_t);
73          memcpy(pbData, buf, data_len);
74          *len = data_len;
75          Dmsg2(200, "Got count=%d len=%d\n", count, data_len);
76          wrk->push_free_buffer(head);
77       }
78    }
79    return ERROR_SUCCESS;
80 }
81
82 /*
83  * Thread created to run the WriteEncryptedFileRaw code
84  */
85 static void *test_efs_write_thread(void *awrk)
86 {
87    ssize_t wstat;
88    worker *wrk = (worker *)awrk;
89    r_ctx *rctx;
90    uint32_t len;
91    uint32_t size = 100000;
92    char *buf = (char *)malloc(size);    /* allocate working buffer */
93
94    rctx = (r_ctx *)wrk->get_ctx();
95    Dmsg2(200, "rctx=%p wrk=%p\n", rctx, wrk);
96    wrk->set_running();
97
98    while (!wrk->is_quit_state()) {
99       if (wrk->is_wait_state()) {      /* wait if so requested */
100          Dmsg0(200, "Enter wait state\n");
101          wrk->wait();
102          Dmsg0(200, "Leave wait state\n");
103          continue;
104       }
105       len = size;
106       if (test_write_efs_data_cb(buf, rctx, &len) != 0) {  /* get a buffer */
107          berrno be;
108          Qmsg2(rctx->jcr, M_FATAL, 0, _("Restore data %ld bytes too long for Microsoft buffer %ld bytes.\n"),
109             len, size);
110          break;
111       }
112       if (len == 0) {       /* done? */
113          Dmsg0(200, "Got len 0 set_wait_state.\n");
114          continue;          /* yes */
115       }
116       Dmsg2(200, "Write buf=%p len=%d\n", buf, len);
117       if ((wstat=bwrite(&rctx->bfd, buf, len)) != (ssize_t)len) {
118          Dmsg4(000, "bwrite of %d error %d open=%d on file=%s\n",
119             len, wstat, is_bopen(&rctx->bfd), rctx->jcr->last_fname);
120          continue;
121       }
122    }
123    Dmsg0(200, "worker thread quiting\n");
124    free(buf);
125    return NULL;
126 }
127
128 /*
129  * If the writer thread is not created, create it, then queue
130  *  a buffer to be written by the thread.
131  */
132 bool test_write_efs_data(r_ctx &rctx, char *data, const int32_t length)
133 {
134    POOLMEM *buf, *head;
135
136    if (!rctx.efs) {
137       rctx.efs = New(worker(10));
138       Dmsg2(200, "Start test_efs_write_thread rctx=%p work=%p\n", &rctx, rctx.efs);
139       rctx.efs->start(test_efs_write_thread, &rctx);
140    }
141    head = (POOLMEM *)rctx.efs->pop_free_buffer();
142    if (!head) {
143       head = get_memory(length + 2*sizeof(int32_t)+1);
144    } else {
145       head = check_pool_memory_size(head, length+2*sizeof(int32_t)+1);
146    }
147    buf = head;
148    *(int32_t *)buf = length;
149    buf += sizeof(int32_t);
150    *(int32_t *)buf = ++rctx.count;
151    buf += sizeof(int32_t);
152    memcpy(buf, data, length);
153    Dmsg3(200, "Put count=%d len=%d head=%p\n", rctx.count, length, head);
154    rctx.efs->queue(head);
155    rctx.efs->set_run_state();
156    return true;
157 }
158 #endif
159
160
161 #ifdef HAVE_WIN32
162
163 /* =============================================================
164  *
165  *   Win EFS functions for restore
166  *
167  * =============================================================
168  */
169
170 /*
171  * This subroutine is called back from the Windows
172  *  WriteEncryptedFileRaw.
173  */
174 static DWORD WINAPI write_efs_data_cb(PBYTE pbData, PVOID arctx, PULONG ulLength)
175 {
176    r_ctx *rctx = (r_ctx *)arctx;
177    worker *wrk = (worker *)rctx->efs;
178    char *data;
179    char *buf;
180    uint32_t data_len;
181    JCR *jcr = rctx->jcr;
182
183    data = (char *)rctx->efs->dequeue();    /* dequeue buffer to write */
184    Dmsg1(200, "dequeue buffer. head=%p\n", data);
185    if (jcr->is_job_canceled()) {
186       return ERROR_CANCELLED;
187    }
188    if (!data) {
189       *ulLength = 0;
190       Dmsg0(200, "cb got NULL.\n");
191    } else {
192       data_len = *(int32_t *)data;
193       if (data_len > *ulLength) {
194          Qmsg2(rctx->jcr, M_FATAL, 0, _("Restore data %ld bytes too long for Microsoft buffer %lld bytes.\n"),
195             data_len, *ulLength);
196          *ulLength = 0;
197       } else {
198          buf = data + sizeof(uint32_t);
199          memcpy(pbData, buf, data_len);
200          *ulLength = (ULONG)data_len;
201          Dmsg1(200, "Got len=%d\n", data_len);
202       }
203       wrk->push_free_buffer(data);
204    }
205    return ERROR_SUCCESS;
206 }
207
208 /*
209  * Thread created to run the WriteEncryptedFileRaw code
210  */
211 static void *efs_write_thread(void *awrk)
212 {
213    worker *wrk = (worker *)awrk;
214    r_ctx *rctx;
215
216    rctx = (r_ctx *)wrk->get_ctx();
217    wrk->set_running();
218
219    while (!wrk->is_quit_state() && !rctx->jcr->is_job_canceled()) {
220       if (wrk->is_wait_state()) {      /* wait if so requested */
221          Dmsg0(200, "Enter wait state\n");
222          wrk->wait();
223          Dmsg0(200, "Leave wait state\n");
224          continue;
225       }
226       if (p_WriteEncryptedFileRaw((PFE_IMPORT_FUNC)write_efs_data_cb, rctx,
227              rctx->bfd.pvContext)) {
228          berrno be;
229          Qmsg1(rctx->jcr, M_FATAL, 0, _("WriteEncryptedFileRaw failure: ERR=%s\n"),
230             be.bstrerror(b_errno_win32));
231          return NULL;
232       }
233       Dmsg0(200, "Got return from WriteEncryptedFileRaw\n");
234    }         
235    return NULL;
236 }
237
238 /*
239  * Called here from Bacula to write a block to a Windows EFS file.
240  * Since the Windows WriteEncryptedFileRaw function uses a callback
241  *  subroutine to get the blocks to write, we create a writer thread,
242  *  and queue the blocks (buffers) we get in this routine.  That
243  *  writer thread then hangs on the WriteEncryptedRaw file, calling
244  *  back to the callback subroutine which then dequeues the blocks
245  *  we have queued.
246  *
247  * If the writer thread is not created, create it, then queue
248  *  a buffer to be written by the thread.
249  */
250 bool win_write_efs_data(r_ctx &rctx, char *data, const int32_t length)
251 {
252    POOLMEM *buf;
253
254    if (!rctx.efs) {
255       rctx.efs = New(worker(10));
256       rctx.efs->start(efs_write_thread, &rctx);
257    }
258    buf = (POOLMEM *)rctx.efs->pop_free_buffer();
259    if (!buf) {
260       buf = get_memory(length + sizeof(int32_t)+1);
261    } else {
262       buf = check_pool_memory_size(buf, length+sizeof(int32_t)+1);
263    }
264    *(int32_t *)buf = length;
265    memcpy(buf+sizeof(int32_t), data, length);
266    Dmsg2(200, "Put len=%d head=%p\n", length, buf);
267    rctx.efs->queue(buf);
268    rctx.efs->set_run_state();
269    return true;
270 }
271
272 /*
273  * The ReadEncryptedFileRaw from bacula.c calls us back here
274  */
275 DWORD WINAPI read_efs_data_cb(PBYTE pbData, PVOID pvCallbackContext, ULONG ulLength)
276 {
277    bctx_t *ctx = (bctx_t *)pvCallbackContext;  /* get our context */
278    BSOCK *sd = ctx->jcr->store_bsock;
279    ULONG ulSent = 0;
280
281    if (ctx->jcr->is_job_canceled()) {
282       return ERROR_CANCELLED;
283    }
284    if (ulLength == 0) {
285       Dmsg0(200, "ulLen=0 => done.\n");
286       return ERROR_SUCCESS;           /* all done */
287    }
288    while (ulLength > 0) {
289       /* Get appropriate block length */
290       if (ulLength <= (ULONG)ctx->rsize) {
291          sd->msglen = ulLength;
292       } else {
293          sd->msglen = (ULONG)ctx->rsize;
294       }
295       Dmsg5(200, "ctx->rbuf=%p msg=%p msgbuflen=%d ulSent=%d len=%d\n", 
296         ctx->rbuf, sd->msg, ctx->rsize, ulSent, sd->msglen);
297       /* Copy data into Bacula buffer */
298       memcpy(ctx->rbuf, pbData + ulSent, sd->msglen);
299       /* Update sent count and remaining count */
300       ulSent += sd->msglen;
301       ulLength -= sd->msglen;
302       /* Send the data off to the SD */
303       if (!process_and_send_data(*ctx)) {
304          return ERROR_UNEXP_NET_ERR;
305       }
306    }
307    return ERROR_SUCCESS;
308 }
309
310 #endif