2 * Challenge Response Authentication Method using MD5 (CRAM-MD5)
4 * cram-md5 is based on RFC2104.
6 * Written for Bacula by Kern E. Sibbald, May MMI.
11 Copyright (C) 2000-2006 Kern Sibbald
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License
15 version 2 as amended with additional clauses defined in the
16 file LICENSE in the main source directory.
18 This program 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
21 the file LICENSE for additional details.
27 /* Authorize other end
28 * Codes that tls_local_need and tls_remote_need can take:
29 * BNET_TLS_NONE I cannot do tls
30 * BNET_TLS_OK I can do tls, but it is not required on my end
31 * BNET_TLS_REQUIRED tls is required on my end
33 int cram_md5_auth(BSOCK *bs, char *password, int tls_local_need)
43 gettimeofday(&t1, &tz);
45 gettimeofday(&t2, &tz);
47 srandom((t1.tv_sec&0xffff) * (t2.tv_usec&0xff));
48 if (!gethostname(host, sizeof(host))) {
49 bstrncpy(host, my_name, sizeof(host));
51 bsnprintf(chal, sizeof(chal), "<%u.%u@%s>", (uint32_t)random(), (uint32_t)time(NULL), host);
52 Dmsg2(50, "send: auth cram-md5 %s ssl=%d\n", chal, tls_local_need);
53 if (!bnet_fsend(bs, "auth cram-md5 %s ssl=%d\n", chal, tls_local_need)) {
54 Dmsg1(50, "Bnet send challenge error.\n", bnet_strerror(bs));
58 if (bnet_wait_data(bs, 180) <= 0 || bnet_recv(bs) <= 0) {
59 Dmsg1(50, "Bnet receive challenge response error.\n", bnet_strerror(bs));
63 hmac_md5((uint8_t *)chal, strlen(chal), (uint8_t *)password, strlen(password), hmac);
64 bin_to_base64(host, (char *)hmac, 16);
65 // Dmsg3(100, "auth: chal=%s pw=%s hmac=%s\n", chal, password, host);
66 ok = strcmp(bs->msg, host) == 0;
68 Dmsg1(50, "Authenticate OK %s\n", host);
70 Dmsg2(50, "Authenticate NOT OK: wanted %s, got %s\n", host, bs->msg);
73 bnet_fsend(bs, "1000 OK auth\n");
75 Dmsg1(50, "Auth failed PW: %s\n", password);
76 bnet_fsend(bs, _("1999 Authorization failed.\n"));
82 /* Get authorization from other end */
83 int cram_md5_get_auth(BSOCK *bs, char *password, int *tls_remote_need)
88 if (bnet_recv(bs) <= 0) {
92 if (bs->msglen >= MAXSTRING) {
93 Dmsg1(50, "Msg too long wanted auth cram... Got: %s", bs->msg);
97 Dmsg1(100, "cram-get: %s", bs->msg);
98 if (sscanf(bs->msg, "auth cram-md5 %s ssl=%d\n", chal, tls_remote_need) != 2) {
99 if (sscanf(bs->msg, "auth cram-md5 %s\n", chal) != 1) {
100 Dmsg1(50, "Cannot scan challenge: %s", bs->msg);
101 bnet_fsend(bs, _("1999 Authorization failed.\n"));
107 hmac_md5((uint8_t *)chal, strlen(chal), (uint8_t *)password, strlen(password), hmac);
108 bs->msglen = bin_to_base64(bs->msg, (char *)hmac, 16) + 1;
109 // Dmsg3(100, "get_auth: chal=%s pw=%s hmac=%s\n", chal, password, bs->msg);
110 if (!bnet_send(bs)) {
111 Dmsg1(50, "Send challenge failed. ERR=%s\n", bnet_strerror(bs));
114 Dmsg1(99, "sending resp to challenge: %s\n", bs->msg);
115 if (bnet_wait_data(bs, 180) <= 0 || bnet_recv(bs) <= 0) {
116 Dmsg1(50, "Receive chanllenge response failed. ERR=%s\n", bnet_strerror(bs));
120 if (strcmp(bs->msg, "1000 OK auth\n") == 0) {
123 Dmsg1(50, "Bad auth response: %s\n", bs->msg);