]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/cram-md5.c
- Integrated TLS network encryption
[bacula/bacula] / bacula / src / lib / cram-md5.c
1 /*
2  *  Challenge Response Authentication Method using MD5 (CRAM-MD5)
3  *
4  * cram-md5 is based on RFC2104.
5  *
6  * Written for Bacula by Kern E. Sibbald, May MMI.
7  *
8  *   Version $Id$
9  */
10 /*
11    Copyright (C) 2000-2004 Kern Sibbald and John Walker
12
13    This library is free software; you can redistribute it and/or
14    modify it under the terms of the GNU Lesser General Public
15    License as published by the Free Software Foundation; either
16    version 2.1 of the License, or (at your option) any later version.
17
18    This library is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21    Lesser General Public License for more details.
22
23    You should have received a copy of the GNU Lesser General Public
24    License along with this library; if not, write to the Free
25    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
26    MA 02111-1307, USA.
27
28  */
29
30 #include "bacula.h"
31
32 /* Authorize other end
33  * Codes that tls_local_need and tls_remote_need can take:
34  *   BNET_TLS_NONE     I cannot do tls
35  *   BNET_TLS_OK       I can do tls, but it is not required on my end
36  *   BNET_TLS_REQUIRED  tls is required on my end
37  */
38 int cram_md5_auth(BSOCK *bs, char *password, int tls_local_need)
39 {
40    struct timeval t1;
41    struct timeval t2;
42    struct timezone tz;
43    int i, ok;
44    char chal[MAXSTRING];
45    char host[MAXSTRING];
46    uint8_t hmac[20];
47
48    gettimeofday(&t1, &tz);
49    for (i=0; i<4; i++) {
50       gettimeofday(&t2, &tz);
51    }
52    srandom((t1.tv_sec&0xffff) * (t2.tv_usec&0xff));
53    if (!gethostname(host, sizeof(host))) {
54       bstrncpy(host, my_name, sizeof(host));
55    }
56    bsnprintf(chal, sizeof(chal), "<%u.%u@%s>", (uint32_t)random(), (uint32_t)time(NULL), host);
57    Dmsg2(50, "send: auth cram-md5 %s ssl=%d\n", chal, tls_local_need);
58    if (!bnet_fsend(bs, "auth cram-md5 %s ssl=%d\n", chal, tls_local_need)) {
59       Dmsg1(50, "Bnet send challenge error.\n", bnet_strerror(bs));
60       return 0;
61    }
62
63    if (bnet_wait_data(bs, 180) <= 0 || bnet_recv(bs) <= 0) {
64       Dmsg1(50, "Bnet receive challenge response error.\n", bnet_strerror(bs));
65       bmicrosleep(5, 0);
66       return 0;
67    }
68    hmac_md5((uint8_t *)chal, strlen(chal), (uint8_t *)password, strlen(password), hmac);
69    bin_to_base64(host, (char *)hmac, 16);
70    ok = strcmp(bs->msg, host) == 0;
71    if (ok) {
72       Dmsg1(50, "Authenticate OK %s\n", host);
73    } else {
74       Dmsg2(50, "Authenticate NOT OK: wanted %s, got %s\n", host, bs->msg);
75    }
76    if (ok) {
77       bnet_fsend(bs, "1000 OK auth\n");
78    } else {
79       Dmsg1(50, "Auth failed PW: %s\n", password);
80       bnet_fsend(bs, "1999 Authorization failed.\n");
81       bmicrosleep(5, 0);
82    }
83    return ok;
84 }
85
86 /* Get authorization from other end */
87 int cram_md5_get_auth(BSOCK *bs, char *password, int *tls_remote_need)
88 {
89    char chal[MAXSTRING];
90    uint8_t hmac[20];
91
92    if (bnet_recv(bs) <= 0) {
93       bmicrosleep(5, 0);
94       return 0;
95    }
96    if (bs->msglen >= MAXSTRING) {
97       Dmsg1(50, "Msg too long wanted auth cram... Got: %s", bs->msg);
98       bmicrosleep(5, 0);
99       return 0;
100    }
101    Dmsg1(100, "cram-get: %s", bs->msg);
102    if (sscanf(bs->msg, "auth cram-md5 %s ssl=%d\n", chal, tls_remote_need) != 2) {
103       if (sscanf(bs->msg, "auth cram-md5 %s\n", chal) != 1) {
104          Dmsg1(50, "Cannot scan challenge: %s", bs->msg);
105          bnet_fsend(bs, "1999 Authorization failed.\n");
106          bmicrosleep(5, 0);
107          return 0;
108       }
109    }
110
111    hmac_md5((uint8_t *)chal, strlen(chal), (uint8_t *)password, strlen(password), hmac);
112    bs->msglen = bin_to_base64(bs->msg, (char *)hmac, 16) + 1;
113    if (!bnet_send(bs)) {
114       Dmsg1(50, "Send challenge failed. ERR=%s\n", bnet_strerror(bs));
115       return 0;
116    }
117    Dmsg1(99, "sending resp to challenge: %s\n", bs->msg);
118    if (bnet_wait_data(bs, 180) <= 0 || bnet_recv(bs) <= 0) {
119       Dmsg1(50, "Receive chanllenge response failed. ERR=%s\n", bnet_strerror(bs));
120       bmicrosleep(5, 0);
121       return 0;
122    }
123    if (strcmp(bs->msg, "1000 OK auth\n") == 0) {
124       return 1;
125    }
126    Dmsg1(50, "Bad auth response: %s\n", bs->msg);
127    bmicrosleep(5, 0);
128    return 0;
129 }