1 /*
2  *     Copyright 2013 Couchbase, Inc.
3  *
4  *   Licensed under the Apache License, Version 2.0 (the "License");
5  *   you may not use this file except in compliance with the License.
6  *   You may obtain a copy of the License at
7  *
8  *       http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *   Unless required by applicable law or agreed to in writing, software
11  *   distributed under the License is distributed on an "AS IS" BASIS,
12  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *   See the License for the specific language governing permissions and
14  *   limitations under the License.
15  */
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <platform/platform.h>
20 #include <cbsasl/cbsasl.h>
21 #include "cbsasl/cram-md5/hmac.h"
22 #include "cbsasl/pwfile.h"
23 #include "cbsasl/util.h"
24 
25 const char *cbpwfile = "sasl_server_test.pw";
26 
create_pw_filenull27 static void create_pw_file()
28 {
29     FILE *fp = fopen(cbpwfile, "w");
30     cb_assert(fp != NULL);
31 
32     fprintf(fp, "mikewied mikepw \ncseo cpw \njlim jpw \nnopass\n");
33     cb_assert(fclose(fp) == 0);
34 
35     putenv("ISASL_PWFILE=sasl_server_test.pw");
36 }
37 
remove_pw_filenull38 static void remove_pw_file()
39 {
40     cb_assert(remove(cbpwfile) == 0);
41     free_user_ht();
42 }
43 
construct_cram_md5_credentials(char *buffer, unsigned *bufferlen, const char *user, unsigned userlen, const char *pass, unsigned passlen, const char *challenge, unsigned challengelen)44 static void construct_cram_md5_credentials(char *buffer,
45                                            unsigned *bufferlen,
46                                            const char *user,
47                                            unsigned userlen,
48                                            const char *pass,
49                                            unsigned passlen,
50                                            const char *challenge,
51                                            unsigned challengelen)
52 {
53     unsigned char digest[DIGEST_LENGTH];
54     memcpy(buffer, user, userlen);
55     buffer[userlen + 1] = ' ';
56 
57     hmac_md5((unsigned char *)challenge, challengelen, (unsigned char *)pass, passlen, digest);
58 
59     cbsasl_hex_encode(buffer + userlen + 1, (char *) digest, DIGEST_LENGTH);
60     *bufferlen = 1 + (DIGEST_LENGTH * 2) + userlen;
61 }
62 
test_list_mechsnull63 static void test_list_mechs()
64 {
65     const char *mechs = NULL;
66     unsigned len = 0;
67     cbsasl_error_t err = cbsasl_list_mechs(&mechs, &len);
68     cb_assert(err == SASL_OK);
69     cb_assert(strncmp(mechs, "CRAM-MD5 PLAIN", len) == 0);
70     cb_assert(strncmp(mechs, "CRDM-MD5 PLAIN", len) != 0);
71 }
72 
test_plain_authnull73 static void test_plain_auth()
74 {
75     cbsasl_conn_t *conn = NULL;
76     const char *output = NULL;
77     unsigned outputlen = 0;
78     cbsasl_error_t err;
79 
80     err = cbsasl_server_init();
81     cb_assert(err == SASL_OK);
82 
83     err = cbsasl_server_start(&conn, "bad_mech", NULL, 0, NULL, NULL);
84     cb_assert(err == SASL_BADPARAM);
85     free((void *)output);
86 
87     /* Normal behavior */
88     output = NULL;
89     err = cbsasl_server_start(&conn, "PLAIN", NULL, 0, NULL, NULL);
90     cb_assert(err == SASL_CONTINUE);
91 
92     err = cbsasl_server_step(conn, "\0mikewied\0mikepw", 16, &output, &outputlen);
93     cb_assert(err == SASL_OK);
94     free((void *)output);
95     cbsasl_server_term();
96 
97 
98     /* With wrong password */
99     output = NULL;
100     err = cbsasl_server_init();
101     cb_assert(err == SASL_OK);
102 
103     err = cbsasl_server_start(&conn, "PLAIN", NULL, 0, NULL, NULL);
104     cb_assert(err == SASL_CONTINUE);
105 
106     err = cbsasl_server_step(conn, "\0mikewied\0badpPW", 16, &output, &outputlen);
107     cb_assert(err == SASL_PWERR);
108     free((void *)output);
109 
110     cbsasl_dispose(&conn);
111     cb_assert(conn == NULL);
112 
113     cbsasl_server_term();
114 
115     /* with no password */
116     output = NULL;
117     err = cbsasl_server_init();
118     cb_assert(err == SASL_OK);
119 
120     err = cbsasl_server_start(&conn, "PLAIN", NULL, 0, NULL, NULL);
121     cb_assert(err == SASL_CONTINUE);
122 
123     err = cbsasl_server_step(conn, "\0nopass\0", 8, &output, &outputlen);
124     cb_assert(err == SASL_OK);
125     free((void *)output);
126 
127     cbsasl_server_term();
128 
129     /* with authzid */
130     output = NULL;
131     err = cbsasl_server_init();
132     cb_assert(err == SASL_OK);
133 
134     err = cbsasl_server_start(&conn, "PLAIN", NULL, 0, NULL, NULL);
135     cb_assert(err == SASL_CONTINUE);
136 
137     err = cbsasl_server_step(conn, "funzid\0mikewied\0mikepw", 22, &output, &outputlen);
138     cb_assert(err == SASL_OK);
139     free((void *)output);
140 
141     cbsasl_server_term();
142 
143     /* with no pw or username ending null */
144     output = NULL;
145     err = cbsasl_server_init();
146     cb_assert(err == SASL_OK);
147 
148     err = cbsasl_server_start(&conn, "PLAIN", NULL, 0, NULL, NULL);
149     cb_assert(err == SASL_CONTINUE);
150 
151     err = cbsasl_server_step(conn, "funzid\0mikewied", 15, &output, &outputlen);
152     cb_assert(err != SASL_OK);
153     free((void *)output);
154     cbsasl_server_term();
155 
156     /* with no nulls at all */
157     output = NULL;
158     err = cbsasl_server_init();
159     cb_assert(err == SASL_OK);
160 
161     err = cbsasl_server_start(&conn, "PLAIN", NULL, 0, NULL, NULL);
162     cb_assert(err == SASL_CONTINUE);
163 
164     err = cbsasl_server_step(conn, "funzidmikewied", 14, &output, &outputlen);
165     cb_assert(err != SASL_OK);
166     free((void *)output);
167     cbsasl_server_term();
168 
169     cbsasl_dispose(&conn);
170     cb_assert(conn == NULL);
171 }
172 
test_cram_md5_authnull173 static void test_cram_md5_auth()
174 {
175     const char *user = "mikewied";
176     const char *pass = "mikepw";
177     cbsasl_conn_t *conn = NULL;
178     char creds[128];
179     unsigned credslen = 0;
180     const char *output = NULL;
181     unsigned outputlen = 0;
182 
183     cbsasl_error_t err = cbsasl_server_init();
184     cb_assert(err == SASL_OK);
185 
186     err = cbsasl_server_start(&conn, "CRAM-MD5", NULL, 0, NULL, NULL);
187     cb_assert(err == SASL_CONTINUE);
188 
189     construct_cram_md5_credentials(creds, &credslen, user, strlen(user), pass,
190                                    strlen(pass), conn->c.server.sasl_data,
191                                    conn->c.server.sasl_data_len);
192 
193     err = cbsasl_server_step(conn, creds, credslen, &output, &outputlen);
194     cb_assert(err == SASL_OK);
195     if (output != NULL) {
196         free((char *)output);
197     }
198 
199     cbsasl_dispose(&conn);
200     cbsasl_server_term();
201     cb_assert(conn == NULL);
202 }
203 
mainnull204 int main()
205 {
206     create_pw_file();
207 
208     test_list_mechs();
209     test_plain_auth();
210     test_cram_md5_auth();
211 
212     remove_pw_file();
213     return 0;
214 }
215