2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2011 Free Software Foundation Europe e.V.
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
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.
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
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.
31 * Kern Sibbald, October 2000
39 const int dbglvl = 50;
41 static char Dir_sorry[] = "3999 No go\n";
42 static char OK_hello[] = "3000 OK Hello\n";
45 /*********************************************************************
49 static int authenticate(int rcode, BSOCK *bs, JCR* jcr)
52 DIRRES *director = NULL;
53 int tls_local_need = BNET_TLS_NONE;
54 int tls_remote_need = BNET_TLS_NONE;
55 int compatible = true; /* require md5 compatible DIR */
56 bool auth_success = false;
57 alist *verify_list = NULL;
59 if (rcode != R_DIRECTOR) {
60 Dmsg1(dbglvl, "I only authenticate Directors, not %d\n", rcode);
61 Jmsg1(jcr, M_FATAL, 0, _("I only authenticate Directors, not %d\n"), rcode);
64 if (bs->msglen < 25 || bs->msglen > 500) {
65 Dmsg2(dbglvl, "Bad Hello command from Director at %s. Len=%d.\n",
66 bs->who(), bs->msglen);
67 Jmsg2(jcr, M_FATAL, 0, _("Bad Hello command from Director at %s. Len=%d.\n"),
68 bs->who(), bs->msglen);
71 dirname = get_pool_memory(PM_MESSAGE);
72 dirname = check_pool_memory_size(dirname, bs->msglen);
74 if (sscanf(bs->msg, "Hello Director %127s calling", dirname) != 1) {
76 Dmsg2(dbglvl, "Bad Hello command from Director at %s: %s\n",
78 Jmsg2(jcr, M_FATAL, 0, _("Bad Hello command from Director at %s: %s\n"),
83 unbash_spaces(dirname);
84 foreach_res(director, rcode) {
85 if (strcmp(director->hdr.name, dirname) == 0) {
90 Dmsg2(dbglvl, "Connection from unknown Director %s at %s rejected.\n",
92 Jmsg2(jcr, M_FATAL, 0, _("Connection from unknown Director %s at %s rejected.\n"
93 "Please see " MANUAL_AUTH_URL " for help.\n"),
95 free_pool_memory(dirname);
100 if (director->tls_enable) {
101 if (director->tls_require) {
102 tls_local_need = BNET_TLS_REQUIRED;
104 tls_local_need = BNET_TLS_OK;
108 if (director->tls_authenticate) {
109 tls_local_need = BNET_TLS_REQUIRED;
112 if (director->tls_verify_peer) {
113 verify_list = director->tls_allowed_cns;
116 /* Timeout Hello after 10 mins */
117 btimer_t *tid = start_bsock_timer(bs, AUTH_TIMEOUT);
118 auth_success = cram_md5_challenge(bs, director->password, tls_local_need, compatible);
120 auth_success = cram_md5_respond(bs, director->password, &tls_remote_need, &compatible);
122 Dmsg1(dbglvl, "cram_get_auth failed with %s\n", bs->who());
125 Dmsg1(dbglvl, "cram_auth failed with %s\n", bs->who());
129 Jmsg0(jcr, M_FATAL, 0, _("Incorrect password given by Director.\n"
130 "Please see " MANUAL_AUTH_URL " for help.\n"));
131 auth_success = false;
135 /* Verify that the remote host is willing to meet our TLS requirements */
136 if (tls_remote_need < tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
137 Jmsg0(jcr, M_FATAL, 0, _("Authorization problem: Remote server did not"
138 " advertize required TLS support.\n"));
139 Dmsg2(dbglvl, "remote_need=%d local_need=%d\n", tls_remote_need, tls_local_need);
140 auth_success = false;
144 /* Verify that we are willing to meet the remote host's requirements */
145 if (tls_remote_need > tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
146 Jmsg0(jcr, M_FATAL, 0, _("Authorization problem: Remote server requires TLS.\n"));
147 Dmsg2(dbglvl, "remote_need=%d local_need=%d\n", tls_remote_need, tls_local_need);
148 auth_success = false;
152 if (tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) {
153 /* Engage TLS! Full Speed Ahead! */
154 if (!bnet_tls_server(director->tls_ctx, bs, verify_list)) {
155 Jmsg(jcr, M_FATAL, 0, _("TLS negotiation failed with DIR at \"%s:%d\"\n"),
156 bs->host(), bs->port());
157 auth_success = false;
160 if (director->tls_authenticate) { /* authenticate with tls only? */
161 bs->free_tls(); /* yes, shut it down */
166 stop_bsock_timer(tid);
167 free_pool_memory(dirname);
168 jcr->director = director;
173 * Inititiate the message channel with the Director.
174 * He has made a connection to our server.
176 * Basic tasks done here:
177 * Assume the Hello message is already in the input
178 * buffer. We then authenticate him.
179 * Get device, media, and pool information from Director
181 * This is the channel across which we will send error
182 * messages and job status information.
184 int authenticate_director(JCR *jcr)
186 BSOCK *dir = jcr->dir_bsock;
188 if (!authenticate(R_DIRECTOR, dir, jcr)) {
189 dir->fsend("%s", Dir_sorry);
190 Dmsg1(dbglvl, "Unable to authenticate Director at %s.\n", dir->who());
191 Jmsg1(jcr, M_ERROR, 0, _("Unable to authenticate Director at %s.\n"), dir->who());
195 return dir->fsend("%s", OK_hello);
198 int authenticate_filed(JCR *jcr)
200 BSOCK *fd = jcr->file_bsock;
201 int tls_local_need = BNET_TLS_NONE;
202 int tls_remote_need = BNET_TLS_NONE;
203 int compatible = true; /* require md5 compatible FD */
204 bool auth_success = false;
205 alist *verify_list = NULL;
207 /* TLS Requirement */
208 if (me->tls_enable) {
209 if (me->tls_require) {
210 tls_local_need = BNET_TLS_REQUIRED;
212 tls_local_need = BNET_TLS_OK;
216 if (me->tls_authenticate) {
217 tls_local_need = BNET_TLS_REQUIRED;
220 if (me->tls_verify_peer) {
221 verify_list = me->tls_allowed_cns;
224 /* Timeout Hello after 5 mins */
225 btimer_t *tid = start_bsock_timer(fd, AUTH_TIMEOUT);
227 auth_success = cram_md5_challenge(fd, jcr->sd_auth_key, tls_local_need, compatible);
229 /* Respond to his challenge */
230 auth_success = cram_md5_respond(fd, jcr->sd_auth_key, &tls_remote_need, &compatible);
232 Dmsg1(dbglvl, "Respond cram-get-auth failed with %s\n", fd->who());
235 Dmsg1(dbglvl, "Challenge cram-auth failed with %s\n", fd->who());
239 Jmsg(jcr, M_FATAL, 0, _("Incorrect authorization key from File daemon at %s rejected.\n"
240 "Please see " MANUAL_AUTH_URL " for help.\n"),
242 auth_success = false;
246 /* Verify that the remote host is willing to meet our TLS requirements */
247 if (tls_remote_need < tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
248 Jmsg(jcr, M_FATAL, 0, _("Authorization problem: Remote server did not"
249 " advertize required TLS support.\n"));
250 Dmsg2(dbglvl, "remote_need=%d local_need=%d\n", tls_remote_need, tls_local_need);
251 auth_success = false;
255 /* Verify that we are willing to meet the remote host's requirements */
256 if (tls_remote_need > tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
257 Jmsg(jcr, M_FATAL, 0, _("Authorization problem: Remote server requires TLS.\n"));
258 Dmsg2(dbglvl, "remote_need=%d local_need=%d\n", tls_remote_need, tls_local_need);
259 auth_success = false;
263 if (tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) {
264 /* Engage TLS! Full Speed Ahead! */
265 if (!bnet_tls_server(me->tls_ctx, fd, verify_list)) {
266 Jmsg(jcr, M_FATAL, 0, _("TLS negotiation failed with FD at \"%s:%d\"\n"),
267 fd->host(), fd->port());
268 auth_success = false;
271 if (me->tls_authenticate) { /* tls authenticate only? */
272 fd->free_tls(); /* yes, shut it down */
277 stop_bsock_timer(tid);
279 Jmsg(jcr, M_FATAL, 0, _("Incorrect authorization key from File daemon at %s rejected.\n"
280 "Please see " MANUAL_AUTH_URL " for help.\n"),
283 jcr->authenticated = auth_success;