]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/cram-md5.c
Add Peter Eriksson's const code + turn bsscanf code
[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 int cram_md5_auth(BSOCK *bs, char *password, int ssl_need)
34 {
35    struct timeval t1;
36    struct timeval t2;
37    struct timezone tz;
38    int i, ok;
39    char chal[MAXSTRING];
40    char host[MAXSTRING];
41    uint8_t hmac[20];
42
43    gettimeofday(&t1, &tz);
44    for (i=0; i<4; i++) {
45       gettimeofday(&t2, &tz);
46    }
47    srandom((t1.tv_sec&0xffff) * (t2.tv_usec&0xff));
48    if (!gethostname(host, sizeof(host))) {
49       bstrncpy(host, my_name, sizeof(host));
50    }
51    bsnprintf(chal, sizeof(chal), "<%u.%u@%s>", (uint32_t)random(), (uint32_t)time(NULL), host);
52    Dmsg2(100, "send: auth cram-md5 %s ssl=%d\n", chal, ssl_need);
53    if (!bnet_fsend(bs, "auth cram-md5 %s ssl=%d\n", chal, ssl_need)) {
54       Dmsg0(100, "Send challenge error.\n");
55       return 0;
56    }
57
58    if (!bnet_ssl_client(bs, password, ssl_need)) {
59       return 0;
60    }
61    if (bnet_wait_data(bs, 180) <= 0 || bnet_recv(bs) <= 0) {
62       bmicrosleep(5, 0);
63       return 0;
64    }
65    hmac_md5((uint8_t *)chal, strlen(chal), (uint8_t *)password, strlen(password), hmac);
66    bin_to_base64(host, (char *)hmac, 16);
67    ok = strcmp(mp_chr(bs->msg), host) == 0;
68    if (ok) {
69       Dmsg0(99, "Authenticate OK\n");
70    } else {
71       Dmsg2(99, "Authenticate NOT OK: wanted %s, got %s\n", host, bs->msg);
72    }
73    if (ok) {
74       bnet_fsend(bs, "1000 OK auth\n");
75    } else {
76       Dmsg1(100, "PW: %s\n", password);
77       bnet_fsend(bs, "1999 Authorization failed.\n");
78       bmicrosleep(5, 0);
79    }
80    return ok;
81 }
82
83 /* Get authorization from other end */
84 int cram_md5_get_auth(BSOCK *bs, char *password, int ssl_need)
85 {
86    char chal[MAXSTRING];
87    uint8_t hmac[20];
88    int ssl_has;                       /* This is what the other end has */
89
90    if (bnet_recv(bs) <= 0) {
91       bmicrosleep(5, 0);
92       return 0;
93    }
94    if (bs->msglen >= MAXSTRING) {
95       Dmsg1(99, "Wanted auth cram... Got: %s", bs->msg);
96       bmicrosleep(5, 0);
97       return 0;
98    }
99    Dmsg1(100, "cram-get: %s", bs->msg);
100    if (sscanf(bs->msg, "auth cram-md5 %s ssl=%d\n", chal, &ssl_has) != 2) {
101       ssl_has = BNET_SSL_NONE;
102       if (sscanf(bs->msg, "auth cram-md5 %s\n", chal) != 1) {
103          Dmsg1(100, "Cannot scan challenge: %s", bs->msg);
104          bnet_fsend(bs, "1999 Authorization failed.\n");
105          bmicrosleep(5, 0);
106          return 0;
107       }
108    }
109    if (!bnet_ssl_server(bs, password, ssl_need, ssl_has)) {
110       return 0;
111    }
112
113    hmac_md5((uint8_t *)chal, strlen(chal), (uint8_t *)password, strlen(password), hmac);
114    bs->msglen = bin_to_base64(mp_chr(bs->msg), (char *)hmac, 16) + 1;
115    if (!bnet_send(bs)) {
116       Dmsg0(100, "Send response failed.\n");
117       return 0;
118    }
119    Dmsg1(99, "sending resp to challenge: %s\n", bs->msg);
120    if (bnet_wait_data(bs, 180) <= 0 || bnet_recv(bs) <= 0) {
121       bmicrosleep(5, 0);
122       return 0;
123    }
124    if (strcmp(mp_chr(bs->msg), "1000 OK auth\n") == 0) {
125       return 1;
126    }
127    Dmsg1(100, "Bad response: %s\n", bs->msg);
128    bmicrosleep(5, 0);
129    return 0;
130 }