]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/hello.c
Apply patches from bugs #2325 and #2326 to fix FIFO bugs
[bacula/bacula] / bacula / src / stored / hello.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2017 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  * Hello routines for Storage daemon.
21  *
22  * This file contains all the code relating to reading and writing of
23  *  all Hello commands between the daemons.
24  *
25  *   Written by Kern Sibbald, June 2014
26  *
27  */
28
29
30 #include "bacula.h"
31 #include "stored.h"
32
33 extern STORES *me;               /* our Global resource */
34
35 const int dbglvl = 50;
36
37 /*
38  * SD_VERSION history
39  * Note: Enterprise versions now numbered in 30000
40  *       and community is at SD version 3
41  *     None prior to 06Aug13
42  *      1         - Skipped
43  *      2          - Skipped
44  *      3 22Feb14 - Added SD->SD with SD_Calls_Client
45  *      4 22Jun14 - Skipped
46  *    305 04Jun15 - Added JobMedia queueing
47  *    306 20Mar15 - Added comm line compression
48  */
49
50 #define SD_VERSION 306     /* Community SD version */
51 #define FD_VERSION 214     /* Community FD version */
52
53 static char hello_sd[]  = "Hello Bacula SD: Start Job %s %d %d\n";
54
55 static char Sorry[]     = "3999 No go\n";
56 static char OK_hello[]  = "3000 OK Hello %d\n";
57
58
59 /*********************************************************************
60  *
61  *  Validate hello from the Director.
62  *
63  * Returns: true  if Hello is good.
64  *          false if Hello is bad.
65  */
66 bool validate_dir_hello(JCR* jcr)
67 {
68    POOLMEM *dirname;
69    DIRRES *director = NULL;
70    int dir_version = 0;
71    BSOCK *dir = jcr->dir_bsock;
72
73    if (dir->msglen < 25 || dir->msglen > 500) {
74       Dmsg2(dbglvl, "Bad Hello command from Director at %s. Len=%d.\n",
75             dir->who(), dir->msglen);
76       Jmsg2(jcr, M_FATAL, 0, _("Bad Hello command from Director at %s. Len=%d.\n"),
77             dir->who(), dir->msglen);
78       return false;
79    }
80    dirname = get_pool_memory(PM_MESSAGE);
81    dirname = check_pool_memory_size(dirname, dir->msglen);
82
83    if (sscanf(dir->msg, "Hello SD: Bacula Director %127s calling %d",
84           dirname, &dir_version) != 2 &&
85        sscanf(dir->msg, "Hello SD: Bacula Director %127s calling",
86           dirname) != 1) {
87       dir->msg[100] = 0;
88       Dmsg2(dbglvl, "Bad Hello command from Director at %s: %s\n",
89             dir->who(), dir->msg);
90       Jmsg2(jcr, M_FATAL, 0, _("Bad Hello command from Director at %s: %s\n"),
91             dir->who(), dir->msg);
92       free_pool_memory(dirname);
93       return false;
94    }
95
96    if (dir_version >= 1 && me->comm_compression) {
97       dir->set_compress();
98    } else {
99       dir->clear_compress();
100       Dmsg0(050, "**** No SD compression to Dir\n");
101    }
102    director = NULL;
103    unbash_spaces(dirname);
104    foreach_res(director, R_DIRECTOR) {
105       if (strcasecmp(director->hdr.name, dirname) == 0) {
106          break;
107       }
108    }
109    if (!director) {
110       Dmsg2(dbglvl, "Connection from unknown Director %s at %s rejected.\n",
111             dirname, dir->who());
112       Jmsg2(jcr, M_FATAL, 0, _("Connection from unknown Director %s at %s rejected.\n"
113             "Please see " MANUAL_AUTH_URL " for help.\n"),
114             dirname, dir->who());
115       free_pool_memory(dirname);
116       return false;
117    }
118    jcr->director = director;
119    free_pool_memory(dirname);
120    return true;
121 }
122
123 /*
124  * After receiving a connection (in dircmd.c) if it is
125  *   from the File daemon, this routine is called.
126  */
127 void handle_client_connection(BSOCK *fd)
128 {
129    JCR *jcr;
130    int fd_version = 0;
131    int sd_version = 0;
132    char job_name[500];
133    /*
134     * Do a sanity check on the message received
135     */
136    if (fd->msglen < 25 || fd->msglen > (int)sizeof(job_name)) {
137       Pmsg1(000, "<filed: %s", fd->msg);
138       Jmsg2(NULL, M_ERROR, 0, _("Invalid connection from %s. Len=%d\n"), fd->who(), fd->msglen);
139       bmicrosleep(5, 0);   /* make user wait 5 seconds */
140       fd->destroy();
141       return;
142    }
143
144    Dmsg1(100, "Conn: %s", fd->msg);
145    /*
146     * See if this is a File daemon connection. If so
147     *   call FD handler.
148     */
149    if (sscanf(fd->msg, "Hello Bacula SD: Start Job %127s %d %d", job_name, &fd_version, &sd_version) != 3 &&
150        sscanf(fd->msg, "Hello FD: Bacula Storage calling Start Job %127s %d", job_name, &sd_version) != 2 &&
151        sscanf(fd->msg, "Hello Start Job %127s", job_name) != 1) {
152       Jmsg2(NULL, M_ERROR, 0, _("Invalid Hello from %s. Len=%d\n"), fd->who(), fd->msglen);
153       return;
154    }
155
156    if (!(jcr=get_jcr_by_full_name(job_name))) {
157       Jmsg1(NULL, M_FATAL, 0, _("Client connect failed: Job name not found: %s\n"), job_name);
158       Dmsg1(3, "**** Job \"%s\" not found.\n", job_name);
159       fd->destroy();
160       return;
161    }
162
163    /* After this point, we can use bail_out */
164    Dmsg1(100, "Found Client Job %s\n", job_name);
165    if (jcr->authenticated) {
166       Jmsg3(jcr, M_WARNING, 0, _("A Client \"%s\" tried to authenticate for Job %s, "
167                                  "but the Job is already authenticated with \"%s\".\n"),
168             fd->who(), jcr->Job, jcr->file_bsock?jcr->file_bsock->who():"N/A");
169       Dmsg2(050, "Hey!!!! JobId %u Job %s already authenticated.\n",
170          (uint32_t)jcr->JobId, jcr->Job);
171       goto bail_out;
172    }
173
174    fd->set_jcr(jcr);
175    Dmsg2(050, "fd_version=%d sd_version=%d\n", fd_version, sd_version);
176
177    /* Turn on compression for newer FDs */
178    if (fd_version >= 214 || sd_version >= 306) {
179       fd->set_compress();             /* set compression allowed */
180    } else {
181       fd->clear_compress();
182       Dmsg0(050, "*** No SD compression to FD\n");
183    }
184
185    /*
186     * Authenticate the Client (FD or SD)
187     */
188    jcr->lock_auth();     /* Ensure that only one thread is dealing with auth */
189    if (jcr->authenticated) {
190       Jmsg2(jcr, M_WARNING, 0, _("A Client \"%s\" tried to authenticate for Job %s, "
191                                  "but the job is already authenticated.\n"),
192             fd->who(), jcr->Job);
193
194    } else if (!authenticate_filed(jcr, fd, fd_version)) {
195       Dmsg1(50, "Authentication failed Job %s\n", jcr->Job);
196       /* Job not yet started, we can cancel */
197       Jmsg(jcr, M_FATAL, 0, _("Unable to authenticate File daemon\n"));
198
199    } else {
200       Dmsg2(050, "OK Authentication jid=%u Job %s\n", (uint32_t)jcr->JobId, jcr->Job);
201       jcr->file_bsock = fd;
202       jcr->FDVersion = fd_version;
203       jcr->SDVersion = sd_version;
204       jcr->authenticated = true;
205
206       if (sd_version > 0) {
207          jcr->sd_client = true;
208       }
209    }
210    jcr->unlock_auth();
211
212    if (!jcr->authenticated) {
213       jcr->setJobStatus(JS_ErrorTerminated);
214    }
215
216    Dmsg4(050, "=== Auth %s, unblock Job %s jid=%d sd_ver=%d\n",
217          jcr->authenticated?"OK":"KO", job_name, jcr->JobId, sd_version);
218
219 bail_out:
220    /* file_bsock might be NULL or a previous BSOCK */
221    if (jcr->file_bsock != fd) {
222       free_bsock(fd);
223    }
224    pthread_cond_signal(&jcr->job_start_wait); /* wake waiting job */
225    free_jcr(jcr);
226    return;
227 }
228
229
230 bool is_client_connection(BSOCK *bs)
231 {
232    return
233       sscanf(bs->msg, "Hello Bacula SD: Start Job ") == 0 ||
234       sscanf(bs->msg, "Hello FD: Bacula Storage calling Start Job ") == 0 ||
235       sscanf(bs->msg, "Hello Start Job ") == 0;
236 }
237
238 /*
239  * If sd_calls_client, we must read the client's response to
240  *   the hello we previously sent.
241  */
242 bool read_client_hello(JCR *jcr)
243 {
244    int i;
245    int stat;
246    int fd_version = 0;
247    int sd_version = 0;
248    BSOCK *cl = jcr->file_bsock;
249    char job_name[500];
250
251    /* We connected to Client, so finish work */
252    if (!cl) {
253       Jmsg0(jcr, M_FATAL, 0, _("Client socket not open. Could not connect to Client.\n"));
254       Dmsg0(050, "Client socket not open. Could not connect to Client.\n");
255       return false;
256    }
257    /* Get response to Hello command sent earlier */
258    Dmsg0(050, "Read Hello command from Client\n");
259    for (i=0; i<60; i++) {
260       stat = cl->recv();
261       if (stat <= 0) {
262          bmicrosleep(1, 0);
263       } else {
264          break;
265       }
266    }
267    if (stat <= 0) {
268       berrno be;
269       Jmsg1(jcr, M_FATAL, 0, _("Recv request to Client failed. ERR=%s\n"),
270          be.bstrerror());
271       Dmsg1(050, _("Recv request to Client failed. ERR=%s\n"), be.bstrerror());
272       return false;
273    }
274    Dmsg1(050, ">filed: %s\n", cl->msg);
275    if (sscanf(cl->msg, "Hello Bacula SD: Start Job %127s %d %d", job_name, &fd_version, &sd_version) != 3) {
276       Jmsg1(jcr, M_FATAL, 0, _("Bad Hello from Client: %s.\n"), cl->msg);
277       Dmsg1(050, _("Bad Hello from Client: %s.\n"), cl->msg);
278       return false;
279    }
280    unbash_spaces(job_name);
281    jcr->FDVersion = fd_version;
282    jcr->SDVersion = sd_version;
283    Dmsg1(050, "FDVersion=%d\n", fd_version);
284    /* Turn on compression for newer FDs, except for Community version */
285    if (jcr->FDVersion >= 214 && me->comm_compression) {
286       cl->set_compress();             /* set compression allowed */
287    } else {
288       cl->clear_compress();
289       Dmsg0(050, "*** No SD compression to FD\n");
290    }
291
292    return true;
293 }
294
295 /*
296  * Send Hello OK to DIR or FD
297  */
298 bool send_hello_ok(BSOCK *bs)
299 {
300    return bs->fsend(OK_hello, SD_VERSION);
301 }
302
303 bool send_sorry(BSOCK *bs)
304 {
305    return bs->fsend(Sorry);
306 }
307
308 /*
309  * We are acting as a client, so send Hello to the SD.
310  */
311 bool send_hello_sd(JCR *jcr, char *Job)
312 {
313    bool rtn;
314    BSOCK *sd = jcr->store_bsock;
315
316    bash_spaces(Job);
317    rtn = sd->fsend(hello_sd, Job, FD_VERSION, SD_VERSION);
318    unbash_spaces(Job);
319    Dmsg1(100, "Send to SD: %s\n", sd->msg);
320    if (!rtn) {
321       return false;
322    }
323    return true;
324 }
325
326 /*
327  * We are SD so send Hello to client
328  *  Note: later the Client will send us a Hello.
329  */
330 bool send_hello_client(JCR *jcr, char *Job)
331 {
332    bool rtn;
333    BSOCK *cl = jcr->file_bsock;
334
335    bash_spaces(Job);
336    rtn = cl->fsend("Hello FD: Bacula Storage calling Start Job %s %d\n", Job, SD_VERSION);
337    unbash_spaces(Job);
338    if (!rtn) {
339       return false;
340    }
341    return rtn;
342 }