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