1 #include <string.h>
2 #include <bglibs/base64.h>
3 #include <bglibs/iobuf.h>
4 #include <bglibs/msg.h>
5 #include <bglibs/str.h>
6 #include "sasl.h"
7 #include "v2client.h"
8 
sasl_auth_init(struct sasl_auth * sa)9 int sasl_auth_init(struct sasl_auth* sa)
10 {
11   if (sa->prefix == 0)
12     sa->prefix = "";
13   if (sa->suffix == 0)
14     sa->suffix = "\r\n";
15   if (sa->in == 0)
16     sa->in = &inbuf;
17   if (sa->out == 0)
18     sa->out = &outbuf;
19   return sasl_init(&sa->state);
20 }
21 
sasl_auth_caps(str * caps)22 int sasl_auth_caps(str* caps)
23 {
24   const struct sasl_mechanism* smech;
25   if (!sasl_mechanisms)
26     return 0;
27 
28   if (!str_truncate(caps, 0) ||
29       !str_copys(caps, "AUTH"))
30     return -1;
31   for (smech = sasl_mechanisms; smech != 0; smech = smech->next)
32     if (!str_catc(caps, ' ') ||	!str_cats(caps, smech->name))
33       return -1;
34   return 1;
35 }
36 
sasl_auth2(struct sasl_auth * sa,const char * mechanism,const char * init_response)37 int sasl_auth2(struct sasl_auth* sa,
38 	       const char* mechanism,
39 	       const char* init_response)
40 {
41   str challenge = {0,0,0};
42   str challenge64 = {0,0,0};
43   str response = {0,0,0};
44   str response64 = {0,0,0};
45   int i;
46   str* iresponsestr;
47 
48   if (init_response != 0) {
49     if (!str_truncate(&response, 0))
50       return -1;
51     if (!base64_decode_line(init_response, &response)) {
52       msg3("SASL AUTH ", mechanism, " failed: bad response");
53       str_free(&response);
54       return SASL_RESP_BAD;
55     }
56     iresponsestr = &response;
57   }
58   else
59     iresponsestr = 0;
60   i = sasl_start(&sa->state, mechanism, iresponsestr, &challenge);
61   while (i == SASL_CHALLENGE) {
62     i = -1;
63     if (str_truncate(&challenge64, 0)
64 	&& base64_encode_line((const unsigned char*)challenge.s,
65 			      challenge.len, &challenge64)
66 	&& obuf_puts(sa->out, sa->prefix)
67 	&& obuf_putstr(sa->out, &challenge64)
68 	&& obuf_putsflush(sa->out, sa->suffix)
69 	&& ibuf_getstr_crlf(sa->in, &response64)) {
70       if (response64.len == 0 || response64.s[0] == '*') {
71 	msg3("SASL AUTH ", mechanism, " failed: aborted");
72 	i = SASL_AUTH_FAILED;
73       }
74       else if (!str_truncate(&response, 0) ||
75 	       !base64_decode_line(response64.s, &response)) {
76 	msg3("SASL AUTH ", mechanism, " failed: bad response");
77 	i = SASL_RESP_BAD;
78       }
79       else
80 	i = sa->state.response(&sa->state, &response, &challenge);
81     }
82     else if (ibuf_eof(sa->in))
83       i = SASL_RESP_EOF;
84   }
85   if (i == SASL_AUTH_OK) {
86     str_truncate(&response, 0);
87     str_copys(&response, "username=");
88     str_cats(&response, cvm_fact_username);
89     if (cvm_fact_sys_username != 0) {
90       str_cats(&response, " sys_username=");
91       str_cats(&response, cvm_fact_sys_username);
92     }
93     if (cvm_fact_domain != 0 && cvm_fact_domain[0] != 0) {
94       str_cats(&response, " domain=");
95       str_cats(&response, cvm_fact_domain);
96     }
97     msg4("SASL AUTH ", mechanism, " ", response.s);
98     cvm_client_setenv();
99   }
100   else
101     msg3("SASL AUTH ", mechanism, " failed");
102   str_free(&response);
103   str_free(&response64);
104   str_free(&challenge);
105   str_free(&challenge64);
106   return i;
107 }
108 
sasl_auth1(struct sasl_auth * sa,const str * arg)109 int sasl_auth1(struct sasl_auth* sa, const str* arg)
110 {
111   str mechanism = {0,0,0};
112   int s;
113   if ((s = str_findfirst(arg, ' ')) != -1) {
114     if (!str_copyb(&mechanism, arg->s, s))
115       return -1;
116     while (arg->s[s] == ' ')
117       ++s;
118     s = sasl_auth2(sa, mechanism.s, arg->s+s);
119     str_free(&mechanism);
120   }
121   else
122     s = sasl_auth2(sa, arg->s, 0);
123   return s;
124 }
125 
sasl_auth_msg(int * code)126 const char* sasl_auth_msg(int* code)
127 {
128   int newcode;
129   const char* msg;
130   #define R(C,M) newcode=C; msg=M; break
131   switch (*code) {
132   case SASL_AUTH_FAILED: R(501,"Authentication failed.");
133   case SASL_NO_MECH: R(504,"Unrecognized authentication mechanism.");
134   case SASL_RESP_REQUIRED: R(535,"Response was required but not given.");
135   case SASL_RESP_NOTALLOWED: R(535,"Initial response not allowed.");
136   case SASL_RESP_BAD: R(501,"Could not decode the response.");
137   case SASL_RESP_EOF: R(535,"End of file reached.");
138   default: R(451,"Internal error.");
139   }
140   *code = newcode;
141   return msg;
142 }
143