1 /*
2 Bacula(R) - The Network Backup Solution
3
4 Copyright (C) 2000-2020 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 * Note: Enterprise versions now are in 10000 range
39 * prior to 06Aug13 no version
40 * 1 06Aug13 - added comm line compression
41 * 102 04Jun15 - added jobmedia change
42 * 103 14Feb17 - added comm line compression
43 * 10002 04Jun15 - added jobmedia batching (from queue in SD)
44 */
45 #define DIR_VERSION 10002
46
47
48 /* Command sent to SD */
49 static char hello[] = "Hello %sDirector %s calling %d tlspsk=%d\n";
50
51 /* Responses from Storage and File daemons */
52 static char OKhello[] = "3000 OK Hello";
53 static char SDOKnewHello[] = "3000 OK Hello %d";
54 static char FDOKhello[] = "2000 OK Hello";
55 static char FDOKnewHello[] = "2000 OK Hello %d";
56
57 /* Sent to User Agent */
58 static char Dir_sorry[] = "1999 You are not authorized.\n";
59
60 /* Forward referenced functions */
61
62 class DIRAuthenticateSD: public AuthenticateBase
63 {
64 public:
DIRAuthenticateSD(JCR * jcr)65 DIRAuthenticateSD(JCR *jcr):
66 AuthenticateBase(jcr, jcr->store_bsock, dtCli, dcDIR, dcSD)
67 {
68 }
~DIRAuthenticateSD()69 virtual ~DIRAuthenticateSD() {};
70 bool authenticate_storage_daemon(STORE *store);
71 };
72
authenticate_storage_daemon(JCR * jcr,STORE * store)73 bool authenticate_storage_daemon(JCR *jcr, STORE *store)
74 {
75 return DIRAuthenticateSD(jcr).authenticate_storage_daemon(store);
76 }
77
authenticate_storage_daemon(STORE * store)78 bool DIRAuthenticateSD::authenticate_storage_daemon(STORE *store)
79 {
80 BSOCK *sd = bsock;
81 char dirname[MAX_NAME_LENGTH];
82
83 /* Calculate tls_local_need from the resource */
84 CalcLocalTLSNeedFromRes(store->tls_enable, store->tls_require,
85 store->tls_authenticate, false, NULL, store->tls_ctx,
86 store->tls_psk_enable, store->psk_ctx, store->password);
87
88 /*
89 * Send my name to the Storage daemon then do authentication
90 */
91 bstrncpy(dirname, director->name(), sizeof(dirname));
92 bash_spaces(dirname);
93 /* Timeout Hello after 1 min */
94 StartAuthTimeout();
95 /* Sent Hello SD: Bacula Director <dirname> calling <version> */
96 if (!sd->fsend(hello, "SD: Bacula ", dirname, DIR_VERSION, tlspsk_local_need)) {
97 Dmsg3(dbglvl, _("Error sending Hello to Storage daemon at \"%s:%d\". ERR=%s\n"),
98 sd->host(), sd->port(), sd->bstrerror());
99 Jmsg(jcr, M_FATAL, 0, _("Error sending Hello to Storage daemon at \"%s:%d\". ERR=%s\n"),
100 sd->host(), sd->port(), sd->bstrerror());
101 return false;
102 }
103
104 /* Try to authenticate using cram-md5 */
105 if (!ClientCramMD5Authenticate(store->password)) {
106 return false;
107 }
108
109 if (!HandleTLS()) {
110 return false;
111 }
112
113 Dmsg1(116, ">stored: %s", sd->msg);
114 if (sd->recv() <= 0) {
115 Jmsg3(jcr, M_FATAL, 0, _("bdird<stored: \"%s:%s\" bad response to Hello command: ERR=%s\n"),
116 sd->who(), sd->host(), sd->bstrerror());
117 return 0;
118 }
119 Dmsg1(110, "<stored: %s", sd->msg);
120 jcr->SDVersion = 0;
121 if (sscanf(sd->msg, SDOKnewHello, &jcr->SDVersion) != 1 &&
122 strncmp(sd->msg, OKhello, sizeof(OKhello)) != 0) {
123 Dmsg0(dbglvl, _("Storage daemon rejected Hello command\n"));
124 Jmsg2(jcr, M_FATAL, 0, _("Storage daemon at \"%s:%d\" rejected Hello command\n"),
125 sd->host(), sd->port());
126 return 0;
127 }
128 /* For newer SD turn on comm line compression */
129 if (jcr->SDVersion >= 1 && director->comm_compression) {
130 sd->set_compress();
131 } else {
132 sd->clear_compress();
133 Dmsg0(050, "*** No Dir compression to SD\n");
134 }
135 if (jcr->SDVersion < SD_VERSION) {
136 Jmsg2(jcr, M_FATAL, 0, _("Older Storage daemon at \"%s:%d\" incompatible with this Director.\n"),
137 sd->host(), sd->port());
138 return 0;
139 }
140 return 1;
141 }
142
143 class DIRAuthenticateFD: public AuthenticateBase
144 {
145 public:
DIRAuthenticateFD(JCR * jcr)146 DIRAuthenticateFD(JCR *jcr):
147 AuthenticateBase(jcr, jcr->file_bsock, dtCli, dcDIR, dcFD)
148 {
149 }
~DIRAuthenticateFD()150 virtual ~DIRAuthenticateFD() {};
151 int authenticate_file_daemon();
152 };
153
authenticate_file_daemon(JCR * jcr)154 int authenticate_file_daemon(JCR *jcr)
155 {
156 return DIRAuthenticateFD(jcr).authenticate_file_daemon();
157 }
158
authenticate_file_daemon()159 int DIRAuthenticateFD::authenticate_file_daemon()
160 {
161 BSOCK *fd = bsock;
162 CLIENT *client = jcr->client;
163 char dirname[MAX_NAME_LENGTH];
164
165 /* Calculate tls_local_need from the resource */
166 CalcLocalTLSNeedFromRes(client->tls_enable, client->tls_require, client->tls_authenticate,
167 client->tls_allowed_cns, client->tls_allowed_cns, client->tls_ctx,
168 client->tls_psk_enable, client->psk_ctx, client->password);
169
170 /*
171 * Send my name to the File daemon then do authentication
172 */
173 bstrncpy(dirname, director->name(), sizeof(dirname));
174 bash_spaces(dirname);
175 /* Timeout Hello after 1 min */
176 StartAuthTimeout();
177 if (!fd->fsend(hello, "", dirname, DIR_VERSION, tlspsk_local_need)) {
178 Dmsg3(dbglvl, _("Error sending Hello to File daemon at \"%s:%d\". ERR=%s\n"),
179 fd->host(), fd->port(), fd->bstrerror());
180 Jmsg(jcr, M_FATAL, 0, _("Error sending Hello to File daemon at \"%s:%d\". ERR=%s\n"),
181 fd->host(), fd->port(), fd->bstrerror());
182 return false;
183 }
184
185 /* Try to authenticate using cram-md5 */
186 if (!ClientCramMD5Authenticate(client->password)) {
187 return false;
188 }
189
190 if (!HandleTLS()) {
191 return false;
192 }
193
194 Dmsg1(116, ">filed: %s", fd->msg);
195 if (fd->recv() <= 0) {
196 Dmsg1(dbglvl, _("Bad response from File daemon to Hello command: ERR=%s\n"),
197 fd->bstrerror());
198 Jmsg(jcr, M_FATAL, 0, _("Bad response from File daemon at \"%s:%d\" to Hello command: ERR=%s\n"),
199 fd->host(), fd->port(), fd->bstrerror());
200 return 0;
201 }
202 Dmsg1(110, "<filed: %s", fd->msg);
203 StopAuthTimeout();
204 jcr->FDVersion = 0;
205 if (strncmp(fd->msg, FDOKhello, sizeof(FDOKhello)) != 0 &&
206 sscanf(fd->msg, FDOKnewHello, &jcr->FDVersion) != 1) {
207 Dmsg0(dbglvl, _("File daemon rejected Hello command\n"));
208 Jmsg(jcr, M_FATAL, 0, _("File daemon at \"%s:%d\" rejected Hello command\n"),
209 fd->host(), fd->port());
210 return 0;
211 }
212 /* For newer FD turn on comm line compression */
213 if (jcr->FDVersion >= 9 && jcr->FDVersion != 213 && director->comm_compression) {
214 fd->set_compress();
215 } else {
216 fd->clear_compress();
217 Dmsg0(050, "*** No Dir compression to FD\n");
218 }
219 return 1;
220 }
221
222 class UAAuthenticate: public AuthenticateBase
223 {
224 UAContext *uac;
225 public:
UAAuthenticate(UAContext * uac)226 UAAuthenticate(UAContext *uac):
227 AuthenticateBase(NULL, uac->UA_sock, dtSrv, dcDIR, dcCON),
228 uac(uac)
229 {
230 }
~UAAuthenticate()231 virtual ~UAAuthenticate() {};
TLSFailure()232 void TLSFailure() {
233 Jmsg(jcr, M_SECURITY, 0, _("TLS negotiation failed with %s at \"%s:%d\"\n"),
234 GetRemoteClassShortName(), bsock->host(), bsock->port());
235 }
236
237 int authenticate_user_agent();
238 };
239
authenticate_user_agent(UAContext * uac)240 int authenticate_user_agent(UAContext *uac)
241 {
242 return UAAuthenticate(uac).authenticate_user_agent();
243 }
244
245 /*********************************************************************
246 *
247 */
authenticate_user_agent()248 int UAAuthenticate::authenticate_user_agent()
249 {
250 char name[MAX_NAME_LENGTH];
251 CONRES *cons = NULL;
252 BSOCK *ua = uac->UA_sock;
253 int ua_version = 0;
254 int tlspsk_remote = 0;
255 bool fdcallsdir=false;
256 CLIENT *cli=NULL;
257
258 if (ua->msglen < 16 || ua->msglen >= MAX_NAME_LENGTH + 15) {
259 Qmsg3(NULL, M_SECURITY, 0, _("UA Hello from %s:%s is invalid. Len=%d\n"), ua->who(),
260 ua->host(), ua->msglen);
261 sleep(5);
262 return 0;
263 }
264 Dmsg1(dbglvl, "authenticate user agent: %s", ua->msg);
265 if (scan_string(ua->msg, "Hello %127s fdcallsdir %d tlspsk=%d", name, &ua_version, &tlspsk_remote) == 3 ||
266 scan_string(ua->msg, "Hello %127s fdcallsdir %d", name, &ua_version) == 2) {
267 fdcallsdir = true;
268 } else if (scan_string(ua->msg, "Hello %127s calling %d tlspsk=%d", name, &ua_version, &tlspsk_remote) != 3 &&
269 scan_string(ua->msg, "Hello %127s calling %d", name, &ua_version) != 2 &&
270 scan_string(ua->msg, "Hello %127s calling", name) != 1)
271 {
272 ua->msg[100] = 0; /* terminate string */
273 Qmsg3(NULL, M_SECURITY, 0, _("UA Hello from %s:%s is invalid. Got: %s\n"), ua->who(),
274 ua->host(), ua->msg);
275 sleep(5);
276 return 0;
277 }
278
279 /* Turn on compression for newer consoles */
280 if (ua_version >= 1 && director->comm_compression) {
281 ua->set_compress();
282 } else {
283 Dmsg0(050, "*** No Dir compression to UA\n");
284 }
285
286 name[sizeof(name)-1] = 0; /* terminate name */
287 if (strcmp(name, "*UserAgent*") == 0) { /* default console */
288 /* TLS Requirement */
289 CalcLocalTLSNeedFromRes(director->tls_enable, director->tls_require,
290 director->tls_authenticate, director->tls_verify_peer,
291 director->tls_allowed_cns, director->tls_ctx,
292 director->tls_psk_enable, director->psk_ctx, director->password);
293
294 } else if (fdcallsdir) {
295 unbash_spaces(name);
296 cli = (CLIENT *)GetResWithName(R_CLIENT, name);
297 if (cli && cli->allow_fd_connections) {
298 /* TLS Requirement */
299 CalcLocalTLSNeedFromRes(cli->tls_enable, cli->tls_require,
300 cli->tls_authenticate, cli->tls_verify_peer,
301 cli->tls_allowed_cns, cli->tls_ctx,
302 cli->tls_psk_enable, cli->psk_ctx, cli->password);
303 } else {
304 if (cli) {
305 Dmsg1(10, "AllowFDConnections not set for %s\n", name);
306 }
307 auth_success = false;
308 goto auth_done;
309 }
310
311 } else {
312 unbash_spaces(name);
313 cons = (CONRES *)GetResWithName(R_CONSOLE, name);
314 if (cons) {
315 /* TLS Requirement */
316 CalcLocalTLSNeedFromRes(cons->tls_enable, cons->tls_require,
317 cons->tls_authenticate, cons->tls_verify_peer, cons->tls_allowed_cns,
318 cons->tls_ctx, cons->tls_psk_enable, cons->psk_ctx, cons->password);
319 } else {
320 auth_success = false;
321 goto auth_done;
322 }
323 }
324 DecodeRemoteTLSPSKNeed(tlspsk_remote);
325
326 if (!ServerCramMD5Authenticate(password)) {
327 goto auth_done;
328 }
329
330 if (cons) {
331 uac->cons = cons; /* save console resource pointer */
332 bstrncpy(uac->name, uac->cons->hdr.name, sizeof(uac->name));
333 }
334
335 this->auth_success = HandleTLS();
336
337 if (!auth_success) {
338 goto auth_done;
339 }
340
341 /* Authorization Completed */
342 auth_done:
343 if (!auth_success) {
344 ua->fsend("%s", _(Dir_sorry));
345 Jmsg4(NULL, M_SECURITY, 0, _("Unable to authenticate console \"%s\" at %s:%s:%d.\n"),
346 name, ua->who(), ua->host(), ua->port());
347 sleep(5);
348 return 0;
349 }
350 ua->fsend(_("1000 OK: %d %s %sVersion: %s (%s)\n"),
351 DIR_VERSION, my_name, BDEMO, VERSION, BDATE);
352
353 if (fdcallsdir) {
354 Dmsg1(10, "FDCallsDir OK for %s\n", name);
355 ua->fsend(_("OK\n"));
356 cli->setBSOCK(ua);
357 uac->UA_sock = NULL;
358 uac->quit = true;
359 }
360 return 1;
361 }
362