]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/authenticate.c
0dce7ef5db62f139bf0c325ddf15d336c8cfb704
[bacula/bacula] / bacula / src / dird / authenticate.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2015 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  *
21  *   Bacula Director -- authenticate.c -- handles authorization of
22  *     Storage and File daemons.
23  *
24  *    Written by: Kern Sibbald, May MMI
25  *
26  *    This routine runs as a thread and must be thread reentrant.
27  *
28  */
29
30 #include "bacula.h"
31 #include "dird.h"
32
33 static const int dbglvl = 50;
34
35 extern DIRRES *director;
36
37 /* Version at end of Hello
38  *   prior to 06Aug13 no version
39  *      102 04Jun15 - added jobmedia change
40  */
41 #define DIR_VERSION 102
42
43
44 /* Command sent to SD */
45 static char hello[]    = "Hello %sDirector %s calling %d\n";
46
47 /* Responses from Storage and File daemons */
48 static char OKhello[]      = "3000 OK Hello";
49 static char SDOKnewHello[] = "3000 OK Hello %d";
50 static char FDOKhello[]    = "2000 OK Hello";
51 static char FDOKnewHello[] = "2000 OK Hello %d";
52
53 /* Sent to User Agent */
54 static char Dir_sorry[]  = "1999 You are not authorized.\n";
55
56 /* Forward referenced functions */
57
58 /*
59  * Authenticate Storage daemon connection
60  */
61 bool authenticate_storage_daemon(JCR *jcr, STORE *store)
62 {
63    BSOCK *sd = jcr->store_bsock;
64    char dirname[MAX_NAME_LENGTH];
65    int tls_local_need = BNET_TLS_NONE;
66    int tls_remote_need = BNET_TLS_NONE;
67    int compatible = true;
68    bool auth_success = false;
69
70    if (!sd) {
71       Dmsg0(dbglvl, "Invalid bsock\n");
72       return false;
73    }
74
75    /*
76     * Send my name to the Storage daemon then do authentication
77     */
78    bstrncpy(dirname, director->hdr.name, sizeof(dirname));
79    bash_spaces(dirname);
80    /* Timeout Hello after 1 min */
81    btimer_t *tid = start_bsock_timer(sd, AUTH_TIMEOUT);
82    /* Sent Hello SD: Bacula Director <dirname> calling <version> */
83    if (!sd->fsend(hello, "SD: Bacula ", dirname, DIR_VERSION)) {
84       stop_bsock_timer(tid);
85       Dmsg1(dbglvl, _("Error sending Hello to Storage daemon. ERR=%s\n"), sd->bstrerror());
86       Jmsg(jcr, M_FATAL, 0, _("Error sending Hello to Storage daemon. ERR=%s\n"), sd->bstrerror());
87       return 0;
88    }
89
90    /* TLS Requirement */
91    if (store->tls_enable) {
92      if (store->tls_require) {
93         tls_local_need = BNET_TLS_REQUIRED;
94      } else {
95         tls_local_need = BNET_TLS_OK;
96      }
97    }
98
99    if (store->tls_authenticate) {
100       tls_local_need = BNET_TLS_REQUIRED;
101    }
102
103    auth_success = cram_md5_respond(sd, store->password, &tls_remote_need, &compatible);
104    if (auth_success) {
105       auth_success = cram_md5_challenge(sd, store->password, tls_local_need, compatible);
106       if (!auth_success) {
107          Dmsg1(dbglvl, "cram_challenge failed for %s\n", sd->who());
108       }
109    } else {
110       Dmsg1(dbglvl, "cram_respond failed for %s\n", sd->who());
111    }
112
113    if (!auth_success) {
114       stop_bsock_timer(tid);
115       Dmsg0(dbglvl, _("Director and Storage daemon passwords or names not the same.\n"));
116       Jmsg2(jcr, M_FATAL, 0,
117             _("Director unable to authenticate with Storage daemon at \"%s:%d\". Possible causes:\n"
118             "Passwords or names not the same or\n"
119             "Maximum Concurrent Jobs exceeded on the SD or\n"
120             "SD networking messed up (restart daemon).\n"
121             "For help, please see: " MANUAL_AUTH_URL "\n"),
122             sd->host(), sd->port());
123       return 0;
124    }
125
126    /* Verify that the remote host is willing to meet our TLS requirements */
127    if (tls_remote_need < tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
128       stop_bsock_timer(tid);
129       Jmsg(jcr, M_FATAL, 0, _("Authorization problem: Remote server did not advertise required TLS support.\n"));
130       return 0;
131    }
132
133    /* Verify that we are willing to meet the remote host's requirements */
134    if (tls_remote_need > tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
135       stop_bsock_timer(tid);
136       Jmsg(jcr, M_FATAL, 0, _("Authorization problem: Remote server requires TLS.\n"));
137       return 0;
138    }
139
140    /* Is TLS Enabled? */
141    if (tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) {
142       /* Engage TLS! Full Speed Ahead! */
143       if (!bnet_tls_client(store->tls_ctx, sd, NULL)) {
144          stop_bsock_timer(tid);
145          Jmsg(jcr, M_FATAL, 0, _("TLS negotiation failed with SD at \"%s:%d\"\n"),
146             sd->host(), sd->port());
147          return 0;
148       }
149       if (store->tls_authenticate) {       /* authentication only? */
150          sd->free_tls();                   /* yes, stop tls */
151       }
152    }
153
154    Dmsg1(116, ">stored: %s", sd->msg);
155    if (sd->recv() <= 0) {
156       stop_bsock_timer(tid);
157       Jmsg3(jcr, M_FATAL, 0, _("bdird<stored: \"%s:%s\" bad response to Hello command: ERR=%s\n"),
158          sd->who(), sd->host(), sd->bstrerror());
159       return 0;
160    }
161    Dmsg1(110, "<stored: %s", sd->msg);
162    stop_bsock_timer(tid);
163    jcr->SDVersion = 0;
164    if (sscanf(sd->msg, SDOKnewHello, &jcr->SDVersion) != 1 &&
165        strncmp(sd->msg, OKhello, sizeof(OKhello)) != 0) {
166       Dmsg0(dbglvl, _("Storage daemon rejected Hello command\n"));
167       Jmsg2(jcr, M_FATAL, 0, _("Storage daemon at \"%s:%d\" rejected Hello command\n"),
168          sd->host(), sd->port());
169       return 0;
170    }
171    if (jcr->SDVersion < 305) {
172       Jmsg2(jcr, M_FATAL, 0, _("Older Storage daemon at \"%s:%d\" incompatible with this Director.\n"),
173          sd->host(), sd->port());
174       return 0;
175    }
176    return 1;
177 }
178
179 /*
180  * Authenticate File daemon connection
181  */
182 int authenticate_file_daemon(JCR *jcr)
183 {
184    BSOCK *fd = jcr->file_bsock;
185    CLIENT *client = jcr->client;
186    char dirname[MAX_NAME_LENGTH];
187    int tls_local_need = BNET_TLS_NONE;
188    int tls_remote_need = BNET_TLS_NONE;
189    int compatible = true;
190    bool auth_success = false;
191
192    /*
193     * Send my name to the File daemon then do authentication
194     */
195    bstrncpy(dirname, director->name(), sizeof(dirname));
196    bash_spaces(dirname);
197    /* Timeout Hello after 1 min */
198    btimer_t *tid = start_bsock_timer(fd, AUTH_TIMEOUT);
199    if (!fd->fsend(hello, "", dirname, DIR_VERSION)) {
200       stop_bsock_timer(tid);
201       Jmsg(jcr, M_FATAL, 0, _("Error sending Hello to File daemon at \"%s:%d\". ERR=%s\n"),
202            fd->host(), fd->port(), fd->bstrerror());
203       Dmsg3(50, _("Error sending Hello to File daemon at \"%s:%d\". ERR=%s\n"),
204            fd->host(), fd->port(), fd->bstrerror());
205       return 0;
206    }
207    Dmsg1(dbglvl, "Sent: %s", fd->msg);
208
209    /* TLS Requirement */
210    if (client->tls_enable) {
211      if (client->tls_require) {
212         tls_local_need = BNET_TLS_REQUIRED;
213      } else {
214         tls_local_need = BNET_TLS_OK;
215      }
216    }
217
218    if (client->tls_authenticate) {
219       tls_local_need = BNET_TLS_REQUIRED;
220    }
221
222    auth_success = cram_md5_respond(fd, client->password, &tls_remote_need, &compatible);
223    if (auth_success) {
224       auth_success = cram_md5_challenge(fd, client->password, tls_local_need, compatible);
225       if (!auth_success) {
226          Dmsg1(dbglvl, "cram_auth failed for %s\n", fd->who());
227       }
228    } else {
229       Dmsg1(dbglvl, "cram_get_auth failed for %s\n", fd->who());
230    }
231    if (!auth_success) {
232       stop_bsock_timer(tid);
233       Dmsg0(dbglvl, _("Director and File daemon passwords or names not the same.\n"));
234       Jmsg(jcr, M_FATAL, 0,
235             _("Unable to authenticate with File daemon at \"%s:%d\". Possible causes:\n"
236             "Passwords or names not the same or\n"
237             "Maximum Concurrent Jobs exceeded on the FD or\n"
238             "FD networking messed up (restart daemon).\n"
239             "For help, please see: " MANUAL_AUTH_URL "\n"),
240             fd->host(), fd->port());
241       return 0;
242    }
243
244    /* Verify that the remote host is willing to meet our TLS requirements */
245    if (tls_remote_need < tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
246       stop_bsock_timer(tid);
247       Jmsg(jcr, M_FATAL, 0, _("Authorization problem: FD \"%s:%s\" did not advertise required TLS support.\n"),
248            fd->who(), fd->host());
249       return 0;
250    }
251
252    /* Verify that we are willing to meet the remote host's requirements */
253    if (tls_remote_need > tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
254       stop_bsock_timer(tid);
255       Jmsg(jcr, M_FATAL, 0, _("Authorization problem: FD at \"%s:%d\" requires TLS.\n"),
256            fd->host(), fd->port());
257       return 0;
258    }
259
260    /* Is TLS Enabled? */
261    if (tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) {
262       /* Engage TLS! Full Speed Ahead! */
263       if (!bnet_tls_client(client->tls_ctx, fd, client->tls_allowed_cns)) {
264          stop_bsock_timer(tid);
265          Jmsg(jcr, M_FATAL, 0, _("TLS negotiation failed with FD at \"%s:%d\".\n"),
266               fd->host(), fd->port());
267          return 0;
268       }
269       if (client->tls_authenticate) {        /* tls authentication only? */
270          fd->free_tls();                     /* yes, shutdown tls */
271       }
272    }
273
274    Dmsg1(116, ">filed: %s", fd->msg);
275    if (fd->recv() <= 0) {
276       stop_bsock_timer(tid);
277       Dmsg1(dbglvl, _("Bad response from File daemon to Hello command: ERR=%s\n"),
278          fd->bstrerror());
279       Jmsg(jcr, M_FATAL, 0, _("Bad response from File daemon at \"%s:%d\" to Hello command: ERR=%s\n"),
280          fd->host(), fd->port(), fd->bstrerror());
281       return 0;
282    }
283    Dmsg1(110, "<filed: %s", fd->msg);
284    stop_bsock_timer(tid);
285    jcr->FDVersion = 0;
286    if (strncmp(fd->msg, FDOKhello, sizeof(FDOKhello)) != 0 &&
287        sscanf(fd->msg, FDOKnewHello, &jcr->FDVersion) != 1) {
288       Dmsg0(dbglvl, _("File daemon rejected Hello command\n"));
289       Jmsg(jcr, M_FATAL, 0, _("File daemon at \"%s:%d\" rejected Hello command\n"),
290            fd->host(), fd->port());
291       return 0;
292    }
293    return 1;
294 }
295
296 /*********************************************************************
297  *
298  */
299 int authenticate_user_agent(UAContext *uac)
300 {
301    char name[MAX_NAME_LENGTH];
302    int tls_local_need = BNET_TLS_NONE;
303    int tls_remote_need = BNET_TLS_NONE;
304    bool tls_authenticate;
305    int compatible = true;
306    CONRES *cons = NULL;
307    BSOCK *ua = uac->UA_sock;
308    bool auth_success = false;
309    TLS_CONTEXT *tls_ctx = NULL;
310    alist *verify_list = NULL;
311    int ua_version = 0;
312
313    if (ua->msglen < 16 || ua->msglen >= MAX_NAME_LENGTH + 15) {
314       Emsg4(M_ERROR, 0, _("UA Hello from %s:%s:%d is invalid. Len=%d\n"), ua->who(),
315             ua->host(), ua->port(), ua->msglen);
316       return 0;
317    }
318
319    if (sscanf(ua->msg, "Hello %127s calling %d", name, &ua_version) != 2 &&
320        sscanf(ua->msg, "Hello %127s calling", name) != 1) {
321       ua->msg[100] = 0;               /* terminate string */
322       Emsg4(M_ERROR, 0, _("UA Hello from %s:%s:%d is invalid. Got: %s\n"), ua->who(),
323             ua->host(), ua->port(), ua->msg);
324       return 0;
325    }
326
327    name[sizeof(name)-1] = 0;             /* terminate name */
328    if (strcmp(name, "*UserAgent*") == 0) {  /* default console */
329       /* TLS Requirement */
330       if (director->tls_enable) {
331          if (director->tls_require) {
332             tls_local_need = BNET_TLS_REQUIRED;
333          } else {
334             tls_local_need = BNET_TLS_OK;
335          }
336       }
337
338       tls_authenticate = director->tls_authenticate;
339
340       if (tls_authenticate) {
341          tls_local_need = BNET_TLS_REQUIRED;
342       }
343
344       if (director->tls_verify_peer) {
345          verify_list = director->tls_allowed_cns;
346       }
347
348       auth_success = cram_md5_challenge(ua, director->password, tls_local_need,
349                                         compatible) &&
350                      cram_md5_respond(ua, director->password, &tls_remote_need, &compatible);
351    } else {
352       unbash_spaces(name);
353       cons = (CONRES *)GetResWithName(R_CONSOLE, name);
354       if (cons) {
355          /* TLS Requirement */
356          if (cons->tls_enable) {
357             if (cons->tls_require) {
358                tls_local_need = BNET_TLS_REQUIRED;
359             } else {
360                tls_local_need = BNET_TLS_OK;
361             }
362          }
363
364          tls_authenticate = cons->tls_authenticate;
365
366          if (tls_authenticate) {
367             tls_local_need = BNET_TLS_REQUIRED;
368          }
369
370          if (cons->tls_verify_peer) {
371             verify_list = cons->tls_allowed_cns;
372          }
373
374          auth_success = cram_md5_challenge(ua, cons->password, tls_local_need,
375                                            compatible) &&
376                      cram_md5_respond(ua, cons->password, &tls_remote_need, &compatible);
377
378          if (auth_success) {
379             uac->cons = cons;         /* save console resource pointer */
380          }
381       } else {
382          auth_success = false;
383          goto auth_done;
384       }
385    }
386
387
388    /* Verify that the remote peer is willing to meet our TLS requirements */
389    if (tls_remote_need < tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
390       Emsg0(M_FATAL, 0, _("Authorization problem:"
391             " Remote client did not advertise required TLS support.\n"));
392       auth_success = false;
393       goto auth_done;
394    }
395
396    /* Verify that we are willing to meet the peer's requirements */
397    if (tls_remote_need > tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
398       Emsg0(M_FATAL, 0, _("Authorization problem:"
399             " Remote client requires TLS.\n"));
400       auth_success = false;
401       goto auth_done;
402    }
403
404    if (tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) {
405       if (cons) {
406          tls_ctx = cons->tls_ctx;
407       } else {
408          tls_ctx = director->tls_ctx;
409       }
410
411       /* Engage TLS! Full Speed Ahead! */
412       if (!bnet_tls_server(tls_ctx, ua, verify_list)) {
413          Emsg0(M_ERROR, 0, _("TLS negotiation failed.\n"));
414          auth_success = false;
415          goto auth_done;
416       }
417       if (tls_authenticate) {            /* authentication only? */
418          ua->free_tls();                 /* stop tls */
419       }
420    }
421
422
423 /* Authorization Completed */
424 auth_done:
425    if (!auth_success) {
426       ua->fsend("%s", _(Dir_sorry));
427       Emsg4(M_ERROR, 0, _("Unable to authenticate console \"%s\" at %s:%s:%d.\n"),
428             name, ua->who(), ua->host(), ua->port());
429       sleep(5);
430       return 0;
431    }
432    ua->fsend(_("1000 OK: %d %s %sVersion: %s (%s)\n"),
433       DIR_VERSION, my_name, "", VERSION, BDATE);
434    return 1;
435 }