]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/qt-console/bcomm/dircomm_auth.cpp
Big backport from Enterprise
[bacula/bacula] / bacula / src / qt-console / bcomm / dircomm_auth.cpp
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2017 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 UA authentication. Provides authentication with
22  *     the Director.
23  *
24  *     Kern Sibbald, June MMI   adapted to bat, Jan MMVI
25  *
26  */
27
28
29 #include "bat.h"
30
31 /*
32  * Version at end of Hello
33  *   prior to 06Aug13 no version
34  *   1 21Oct13 - added comm line compression
35  */
36 #define BAT_VERSION 1
37
38
39 /* Commands sent to Director */
40 static char hello[]    = "Hello %s calling %d\n";
41
42 /* Response from Director */
43 static char oldOKhello[]   = "1000 OK:";
44 static char newOKhello[]   = "1000 OK: %d";
45 static char FDOKhello[]   = "2000 OK Hello %d";
46
47 /* Forward referenced functions */
48
49 /*
50  * Authenticate Director
51  */
52 bool DirComm::authenticate_director(JCR *jcr, DIRRES *director, CONRES *cons, 
53                 char *errmsg, int errmsg_len) 
54 {
55    BSOCK *dir = jcr->dir_bsock;
56    int tls_local_need = BNET_TLS_NONE;
57    int tls_remote_need = BNET_TLS_NONE;
58    int dir_version = 0;
59    bool tls_authenticate;
60    int compatible = true;
61    char bashed_name[MAX_NAME_LENGTH];
62    char *password;
63    TLS_CONTEXT *tls_ctx = NULL;
64
65    errmsg[0] = 0;
66    /*
67     * Send my name to the Director then do authentication
68     */
69    if (cons) {
70       bstrncpy(bashed_name, cons->hdr.name, sizeof(bashed_name));
71       bash_spaces(bashed_name);
72       password = cons->password;
73       /* TLS Requirement */
74       if (cons->tls_enable) {
75          if (cons->tls_require) {
76             tls_local_need = BNET_TLS_REQUIRED;
77          } else {
78             tls_local_need = BNET_TLS_OK;
79          }
80       }
81       tls_authenticate = cons->tls_authenticate;
82       tls_ctx = cons->tls_ctx;
83    } else {
84       bstrncpy(bashed_name, "*UserAgent*", sizeof(bashed_name));
85       password = director->password;
86       /* TLS Requirement */
87       if (director->tls_enable) {
88          if (director->tls_require) {
89             tls_local_need = BNET_TLS_REQUIRED;
90          } else {
91             tls_local_need = BNET_TLS_OK;
92          }
93       }
94
95       tls_authenticate = director->tls_authenticate;
96       tls_ctx = director->tls_ctx;
97    }
98    if (tls_authenticate) {
99       tls_local_need = BNET_TLS_REQUIRED;
100    }
101
102    /* Timeout Hello after 15 secs */
103    dir->start_timer(15);
104    dir->fsend(hello, bashed_name, BAT_VERSION);
105
106    /* respond to Dir challenge */
107    if (!cram_md5_respond(dir, password, &tls_remote_need, &compatible) ||
108        /* Now challenge dir */
109        !cram_md5_challenge(dir, password, tls_local_need, compatible)) {
110       bsnprintf(errmsg, errmsg_len, _("Director authorization problem at \"%s:%d\"\n"),
111          dir->host(), dir->port());
112       goto bail_out;
113    }
114
115    /* Verify that the remote host is willing to meet our TLS requirements */
116    if (tls_remote_need < tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
117       bsnprintf(errmsg, errmsg_len, _("Authorization problem:"
118              " Remote server at \"%s:%d\" did not advertise required TLS support.\n"),
119              dir->host(), dir->port());
120       goto bail_out;
121    }
122
123    /* Verify that we are willing to meet the remote host's requirements */
124    if (tls_remote_need > tls_local_need && tls_local_need != BNET_TLS_OK && tls_remote_need != BNET_TLS_OK) {
125       bsnprintf(errmsg, errmsg_len, _("Authorization problem with Director at \"%s:%d\":"
126                      " Remote server requires TLS.\n"),
127                      dir->host(), dir->port());
128
129       goto bail_out;
130    }
131
132    /* Is TLS Enabled? */
133    if (tls_local_need >= BNET_TLS_OK && tls_remote_need >= BNET_TLS_OK) {
134       /* Engage TLS! Full Speed Ahead! */
135       if (!bnet_tls_client(tls_ctx, dir, NULL)) {
136          bsnprintf(errmsg, errmsg_len, _("TLS negotiation failed with Director at \"%s:%d\"\n"),
137             dir->host(), dir->port());
138          goto bail_out;
139       }
140       if (tls_authenticate) {               /* authenticate only? */
141          dir->free_tls();                   /* Yes, shutdown tls */
142       }
143    }
144
145    Dmsg1(6, ">dird: %s", dir->msg);
146    if (dir->recv() <= 0) {
147       dir->stop_timer();
148       bsnprintf(errmsg, errmsg_len, _("Bad response to Hello command: ERR=%s\n"
149                       "The Director at \"%s:%d\" is probably not running.\n"),
150                     dir->bstrerror(), dir->host(), dir->port());
151       return false;
152    }
153
154    dir->stop_timer();
155    Dmsg1(10, "<dird: %s", dir->msg);
156    if (strncmp(dir->msg, oldOKhello, sizeof(oldOKhello)-1) == 0) {
157       /* If Dir version exists, get it */
158       sscanf(dir->msg, newOKhello, &dir_version);
159
160       /* We do not check the last %d */
161    } else if (strncmp(dir->msg, FDOKhello, sizeof(FDOKhello)-3) == 0) {
162       sscanf(dir->msg, FDOKhello, &dir_version);
163       // TODO: Keep somewhere that we need a proxy command, or run it directly?
164    } else {
165       bsnprintf(errmsg, errmsg_len, _("Director at \"%s:%d\" rejected Hello command\n"),
166                 dir->host(), dir->port());
167       return false;
168    }
169    
170    /* Turn on compression for newer Directors */
171    if (dir_version >= 1 && (!cons || cons->comm_compression)) {
172       dir->set_compress();
173    }
174
175    if (m_conn == 0) { 
176       bsnprintf(errmsg, errmsg_len, "%s", dir->msg);
177    }
178    return true;
179
180 bail_out:
181    dir->stop_timer();
182    bsnprintf(errmsg, errmsg_len, _("Authorization problem with Director at \"%s:%d\"\n"
183              "Most likely the passwords do not agree.\n"
184              "If you are using TLS, there may have been a certificate validation error during the TLS handshake.\n"
185              "For help, please see " MANUAL_AUTH_URL "\n"),
186              dir->host(), dir->port());
187    return false;
188 }