]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/filed/authenticate.c
Add new features in plugin
[bacula/bacula] / bacula / src / filed / authenticate.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2010 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version three of the GNU Affero General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU Affero General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  * Authenticate Director who is attempting to connect.
30  *
31  *   Kern Sibbald, October 2000
32  *
33  */
34
35 #include "bacula.h"
36 #include "filed.h"
37
38 const int dbglvl = 50;
39
40 /* Version at end of Hello
41  *   prior to 10Mar08 no version
42  *   1 10Mar08
43  *   2 13Mar09 - added the ability to restore from multiple storages
44  *   3 03Sep10 - added the restore object command for vss plugin 4.0
45  *   4 25Nov10 - added bandwidth command 5.1
46  *   5 24Nov11 - added new restore object command format (pluginname) 6.0
47  */
48 static char OK_hello[]  = "2000 OK Hello 5\n";
49 static char Dir_sorry[] = "2999 Authentication failed.\n";
50 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
51
52 /*********************************************************************
53  *
54  */
55 static bool authenticate(int rcode, BSOCK *bs, JCR* jcr)
56 {
57    POOLMEM *dirname = get_pool_memory(PM_MESSAGE);
58    DIRRES *director = NULL;
59    int tls_local_need = BNET_TLS_NONE;
60    int tls_remote_need = BNET_TLS_NONE;
61    int compatible = true;                 /* Want md5 compatible DIR */
62    bool auth_success = false;
63    alist *verify_list = NULL;
64    btimer_t *tid = NULL;
65
66    if (rcode != R_DIRECTOR) {
67       Dmsg1(dbglvl, "I only authenticate directors, not %d\n", rcode);
68       Jmsg1(jcr, M_FATAL, 0, _("I only authenticate directors, not %d\n"), rcode);
69       goto auth_fatal;
70    }
71    if (bs->msglen < 25 || bs->msglen > 500) {
72       Dmsg2(dbglvl, "Bad Hello command from Director at %s. Len=%d.\n",
73             bs->who(), bs->msglen);
74       char addr[64];
75       char *who = bnet_get_peer(bs, addr, sizeof(addr)) ? bs->who() : addr;
76       Jmsg2(jcr, M_FATAL, 0, _("Bad Hello command from Director at %s. Len=%d.\n"),
77              who, bs->msglen);
78       goto auth_fatal;
79    }
80    dirname = check_pool_memory_size(dirname, bs->msglen);
81
82    if (sscanf(bs->msg, "Hello Director %s calling", dirname) != 1) {
83       char addr[64];
84       char *who = bnet_get_peer(bs, addr, sizeof(addr)) ? bs->who() : addr;
85       bs->msg[100] = 0;
86       Dmsg2(dbglvl, "Bad Hello command from Director at %s: %s\n",
87             bs->who(), bs->msg);
88       Jmsg2(jcr, M_FATAL, 0, _("Bad Hello command from Director at %s: %s\n"),
89             who, bs->msg);
90       goto auth_fatal;
91    }
92    unbash_spaces(dirname);
93    foreach_res(director, R_DIRECTOR) {
94       if (strcmp(director->hdr.name, dirname) == 0)
95          break;
96    }
97    if (!director) {
98       char addr[64];
99       char *who = bnet_get_peer(bs, addr, sizeof(addr)) ? bs->who() : addr;
100       Jmsg2(jcr, M_FATAL, 0, _("Connection from unknown Director %s at %s rejected.\n"), 
101             dirname, who);
102       goto auth_fatal;
103    }
104
105    if (have_tls) {
106       /* TLS Requirement */
107       if (director->tls_enable) {
108          if (director->tls_require) {
109             tls_local_need = BNET_TLS_REQUIRED;
110          } else {
111             tls_local_need = BNET_TLS_OK;
112          }
113       }
114
115       if (director->tls_authenticate) {
116          tls_local_need = BNET_TLS_REQUIRED;
117       }
118
119       if (director->tls_verify_peer) {
120          verify_list = director->tls_allowed_cns;
121       }
122    }
123
124    tid = start_bsock_timer(bs, AUTH_TIMEOUT);
125    /* Challenge the director */
126    auth_success = cram_md5_challenge(bs, director->password, tls_local_need, compatible);  
127    if (job_canceled(jcr)) {
128       auth_success = false;
129       goto auth_fatal;                   /* quick exit */
130    }
131    if (auth_success) {
132       auth_success = cram_md5_respond(bs, director->password, &tls_remote_need, &compatible);
133       if (!auth_success) {
134           char addr[64];
135           char *who = bnet_get_peer(bs, addr, sizeof(addr)) ? bs->who() : addr;
136           Dmsg1(dbglvl, "cram_get_auth failed for %s\n", who);
137       }
138    } else {
139        char addr[64];
140        char *who = bnet_get_peer(bs, addr, sizeof(addr)) ? bs->who() : addr;
141        Dmsg1(dbglvl, "cram_auth failed for %s\n", who);
142    }
143    if (!auth_success) {
144        Emsg1(M_FATAL, 0, _("Incorrect password given by Director at %s.\n"),
145              bs->who());
146        goto auth_fatal;
147    }
148
149    /* Verify that the remote host is willing to meet our TLS requirements */
150    if (tls_remote_need < tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
151       Jmsg0(jcr, M_FATAL, 0, _("Authorization problem: Remote server did not"
152            " advertize required TLS support.\n"));
153       Dmsg2(dbglvl, "remote_need=%d local_need=%d\n", tls_remote_need, tls_local_need);
154       auth_success = false;
155       goto auth_fatal;
156    }
157
158    /* Verify that we are willing to meet the remote host's requirements */
159    if (tls_remote_need > tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
160       Jmsg0(jcr, M_FATAL, 0, _("Authorization problem: Remote server requires TLS.\n"));
161       Dmsg2(dbglvl, "remote_need=%d local_need=%d\n", tls_remote_need, tls_local_need);
162       auth_success = false;
163       goto auth_fatal;
164    }
165
166    if (tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) {
167       /* Engage TLS! Full Speed Ahead! */
168       if (!bnet_tls_server(director->tls_ctx, bs, verify_list)) {
169          Jmsg0(jcr, M_FATAL, 0, _("TLS negotiation failed.\n"));
170          auth_success = false;
171          goto auth_fatal;
172       }
173       if (director->tls_authenticate) {         /* authentication only? */
174          bs->free_tls();                        /* shutodown tls */
175       }
176    }
177
178 auth_fatal:
179    if (tid) {
180       stop_bsock_timer(tid);
181       tid = NULL;
182    }
183    free_pool_memory(dirname);
184    jcr->director = director;
185    /* Single thread all failures to avoid DOS */
186    if (!auth_success) {
187       P(mutex);
188       bmicrosleep(6, 0);
189       V(mutex);
190    }
191    return auth_success;
192 }
193
194 /*
195  * Inititiate the communications with the Director.
196  * He has made a connection to our server.
197  *
198  * Basic tasks done here:
199  *   We read Director's initial message and authorize him.
200  *
201  */
202 int authenticate_director(JCR *jcr)
203 {
204    BSOCK *dir = jcr->dir_bsock;
205
206    if (!authenticate(R_DIRECTOR, dir, jcr)) {
207       bnet_fsend(dir, "%s", Dir_sorry);
208       Emsg0(M_FATAL, 0, _("Unable to authenticate Director\n"));
209       return 0;
210    }
211    return bnet_fsend(dir, "%s", OK_hello);
212 }
213
214 /*
215  * First prove our identity to the Storage daemon, then
216  * make him prove his identity.
217  */
218 int authenticate_storagedaemon(JCR *jcr)
219 {
220    BSOCK *sd = jcr->store_bsock;
221    int tls_local_need = BNET_TLS_NONE;
222    int tls_remote_need = BNET_TLS_NONE;
223    int compatible = true;
224    bool auth_success = false;
225
226    btimer_t *tid = start_bsock_timer(sd, AUTH_TIMEOUT);
227
228    /* TLS Requirement */
229    if (have_tls && me->tls_enable) {
230       if (me->tls_require) {
231          tls_local_need = BNET_TLS_REQUIRED;
232       } else {
233          tls_local_need = BNET_TLS_OK;
234       }
235    }
236
237    if (me->tls_authenticate) {
238       tls_local_need = BNET_TLS_REQUIRED;
239    }
240
241    if (job_canceled(jcr)) {
242       auth_success = false;     /* force quick exit */
243       goto auth_fatal;
244    }
245
246    /* Respond to SD challenge */
247    auth_success = cram_md5_respond(sd, jcr->sd_auth_key, &tls_remote_need, &compatible);
248    if (job_canceled(jcr)) {
249       auth_success = false;     /* force quick exit */
250       goto auth_fatal;
251    }
252    if (!auth_success) {
253       Dmsg1(dbglvl, "cram_respond failed for %s\n", sd->who());
254    } else {
255       /* Now challenge him */
256       auth_success = cram_md5_challenge(sd, jcr->sd_auth_key, tls_local_need, compatible);
257       if (!auth_success) {
258          Dmsg1(dbglvl, "cram_challenge failed for %s\n", sd->who());
259       }
260    }
261
262    if (!auth_success) {
263       Jmsg(jcr, M_FATAL, 0, _("Authorization key rejected by Storage daemon.\n"
264        "Please see " MANUAL_AUTH_URL " for help.\n"));
265       goto auth_fatal;
266    }
267
268    /* Verify that the remote host is willing to meet our TLS requirements */
269    if (tls_remote_need < tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
270       Jmsg(jcr, M_FATAL, 0, _("Authorization problem: Remote server did not" 
271            " advertize required TLS support.\n"));
272       Dmsg2(dbglvl, "remote_need=%d local_need=%d\n", tls_remote_need, tls_local_need);
273       auth_success = false;
274       goto auth_fatal;
275    }
276
277    /* Verify that we are willing to meet the remote host's requirements */
278    if (tls_remote_need > tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
279       Jmsg(jcr, M_FATAL, 0, _("Authorization problem: Remote server requires TLS.\n"));
280       Dmsg2(dbglvl, "remote_need=%d local_need=%d\n", tls_remote_need, tls_local_need);
281       auth_success = false;
282       goto auth_fatal;
283    }
284
285    if (tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) {
286       /* Engage TLS! Full Speed Ahead! */
287       if (!bnet_tls_client(me->tls_ctx, sd, NULL)) {
288          Jmsg(jcr, M_FATAL, 0, _("TLS negotiation failed.\n"));
289          auth_success = false;
290          goto auth_fatal;
291       }
292       if (me->tls_authenticate) {           /* tls authentication only? */
293          sd->free_tls();                    /* yes, shutdown tls */
294       }
295    }
296
297 auth_fatal:
298    /* Destroy session key */
299    memset(jcr->sd_auth_key, 0, strlen(jcr->sd_auth_key));
300    stop_bsock_timer(tid);
301    /* Single thread all failures to avoid DOS */
302    if (!auth_success) {
303       P(mutex);
304       bmicrosleep(6, 0);
305       V(mutex);
306    }
307    return auth_success;
308 }