1e21fb479STrond Norbye/*
2e21fb479STrond Norbye *     Copyright 2013 Couchbase, Inc.
3e21fb479STrond Norbye *
4e21fb479STrond Norbye *   Licensed under the Apache License, Version 2.0 (the "License");
5e21fb479STrond Norbye *   you may not use this file except in compliance with the License.
6e21fb479STrond Norbye *   You may obtain a copy of the License at
7e21fb479STrond Norbye *
8e21fb479STrond Norbye *       http://www.apache.org/licenses/LICENSE-2.0
9e21fb479STrond Norbye *
10e21fb479STrond Norbye *   Unless required by applicable law or agreed to in writing, software
11e21fb479STrond Norbye *   distributed under the License is distributed on an "AS IS" BASIS,
12e21fb479STrond Norbye *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e21fb479STrond Norbye *   See the License for the specific language governing permissions and
14e21fb479STrond Norbye *   limitations under the License.
15e21fb479STrond Norbye */
16e21fb479STrond Norbye
17e21fb479STrond Norbye#include <cbsasl/cbsasl.h>
18e21fb479STrond Norbye
19e21fb479STrond Norbye#include "cram-md5/cram-md5.h"
20e21fb479STrond Norbye#include "cram-md5/hmac.h"
21e21fb479STrond Norbye#include "plain/plain.h"
22e21fb479STrond Norbye#include "pwfile.h"
23e21fb479STrond Norbye#include "util.h"
24e21fb479STrond Norbye#include <time.h>
25e21fb479STrond Norbye#include <platform/random.h>
26e21fb479STrond Norbye#include <string.h>
27e21fb479STrond Norbye#include <stdlib.h>
28e21fb479STrond Norbye
29e21fb479STrond Norbyestatic cb_rand_t randgen;
30e21fb479STrond Norbye
31e21fb479STrond Norbye#define IS_MECH(str, mech) (strncmp(str, mech, strlen(mech)))
32e21fb479STrond Norbye
33e21fb479STrond Norbyecbsasl_error_t cbsasl_list_mechs(const char **mechs,
34e21fb479STrond Norbye                                 unsigned *mechslen)
35e21fb479STrond Norbye{
36e21fb479STrond Norbye    *mechs = "CRAM-MD5 PLAIN";
37e21fb479STrond Norbye    *mechslen = strlen(*mechs);
38e21fb479STrond Norbye    return SASL_OK;
39e21fb479STrond Norbye}
40e21fb479STrond Norbye
41e21fb479STrond NorbyeCBSASL_PUBLIC_API
42e21fb479STrond Norbyecbsasl_error_t cbsasl_server_init(void)
43e21fb479STrond Norbye{
44e21fb479STrond Norbye    if (cb_rand_open(&randgen) != 0) {
45e21fb479STrond Norbye        return SASL_FAIL;
46e21fb479STrond Norbye    }
47e21fb479STrond Norbye    pwfile_init();
48e21fb479STrond Norbye    return load_user_db();
49e21fb479STrond Norbye}
50e21fb479STrond Norbye
51e21fb479STrond NorbyeCBSASL_PUBLIC_API
52e21fb479STrond Norbyecbsasl_error_t cbsasl_server_term(void)
53e21fb479STrond Norbye{
54e21fb479STrond Norbye    return cb_rand_close(randgen) == 0 ? SASL_OK : SASL_FAIL;
55e21fb479STrond Norbye
56e21fb479STrond Norbye}
57e21fb479STrond Norbye
58e21fb479STrond NorbyeCBSASL_PUBLIC_API
59e21fb479STrond Norbyecbsasl_error_t cbsasl_server_start(cbsasl_conn_t **conn,
60e21fb479STrond Norbye                                   const char *mech,
61e21fb479STrond Norbye                                   const char *clientin,
62e21fb479STrond Norbye                                   unsigned int clientinlen,
63e21fb479STrond Norbye                                   unsigned char **serverout,
64e21fb479STrond Norbye                                   unsigned int *serveroutlen)
65e21fb479STrond Norbye{
66e21fb479STrond Norbye    cbsasl_error_t err;
67e21fb479STrond Norbye
68e21fb479STrond Norbye    if (*conn != NULL) {
69e21fb479STrond Norbye        cbsasl_dispose(conn);
70e21fb479STrond Norbye    }
71e21fb479STrond Norbye
72e21fb479STrond Norbye    *conn = calloc(1, sizeof(cbsasl_conn_t));
73e21fb479STrond Norbye    if (*conn == NULL) {
74e21fb479STrond Norbye        return SASL_NOMEM;
75e21fb479STrond Norbye    }
76e21fb479STrond Norbye
77e21fb479STrond Norbye    if (IS_MECH(mech, MECH_NAME_PLAIN) == 0) {
78e21fb479STrond Norbye        cbsasl_mechs_t plain_mech = get_plain_mechs();
79e21fb479STrond Norbye        memcpy(&(*conn)->c.server.mech, &plain_mech, sizeof(cbsasl_mechs_t));
80e21fb479STrond Norbye    } else if (IS_MECH(mech, MECH_NAME_CRAM_MD5) == 0) {
81e21fb479STrond Norbye        cbsasl_mechs_t cram_md5_mech = get_cram_md5_mechs();
82e21fb479STrond Norbye        memcpy(&(*conn)->c.server.mech, &cram_md5_mech, sizeof(cbsasl_mechs_t));
83e21fb479STrond Norbye    } else {
84e21fb479STrond Norbye        cbsasl_dispose(conn);
85e21fb479STrond Norbye        return SASL_BADPARAM;
86e21fb479STrond Norbye    }
87e21fb479STrond Norbye
88e21fb479STrond Norbye    if ((err = (*conn)->c.server.mech.init()) != SASL_OK) {
89e21fb479STrond Norbye        cbsasl_dispose(conn);
90e21fb479STrond Norbye        return err;
91e21fb479STrond Norbye    }
92e21fb479STrond Norbye
93e21fb479STrond Norbye    err = (*conn)->c.server.mech.start(*conn);
94e21fb479STrond Norbye    if (serverout) {
95e21fb479STrond Norbye        *serverout = (void*)(*conn)->c.server.sasl_data;
96e21fb479STrond Norbye    }
97e21fb479STrond Norbye    if (serveroutlen) {
98e21fb479STrond Norbye        *serveroutlen = (*conn)->c.server.sasl_data_len;
99e21fb479STrond Norbye    }
100e21fb479STrond Norbye
101e21fb479STrond Norbye    if (err == SASL_CONTINUE && clientinlen != 0) {
102e21fb479STrond Norbye        return cbsasl_server_step(*conn, clientin, clientinlen,
103e21fb479STrond Norbye                                  (const char**)serverout, serveroutlen);
104e21fb479STrond Norbye    }
105e21fb479STrond Norbye
106e21fb479STrond Norbye    return err;
107e21fb479STrond Norbye}
108e21fb479STrond Norbye
109e21fb479STrond NorbyeCBSASL_PUBLIC_API
110e21fb479STrond Norbyecbsasl_error_t cbsasl_server_step(cbsasl_conn_t *conn,
111e21fb479STrond Norbye                                  const char *input,
112e21fb479STrond Norbye                                  unsigned inputlen,
113e21fb479STrond Norbye                                  const char **output,
114e21fb479STrond Norbye                                  unsigned *outputlen)
115e21fb479STrond Norbye{
116bfa6d2ebSTrond Norbye    if (conn == NULL || conn->client) {
117e21fb479STrond Norbye        return SASL_BADPARAM;
118e21fb479STrond Norbye    }
119e21fb479STrond Norbye    return conn->c.server.mech.step(conn, input, inputlen, output, outputlen);
120e21fb479STrond Norbye}
121e21fb479STrond Norbye
122e21fb479STrond NorbyeCBSASL_PUBLIC_API
123e21fb479STrond Norbyecbsasl_error_t cbsasl_server_refresh(void)
124e21fb479STrond Norbye{
125e21fb479STrond Norbye    return load_user_db();
126e21fb479STrond Norbye}
127e21fb479STrond Norbye
128e21fb479STrond NorbyeCBSASL_PUBLIC_API
129e21fb479STrond Norbyecbsasl_error_t cbsasl_getprop(cbsasl_conn_t *conn,
130e21fb479STrond Norbye                              cbsasl_prop_t propnum,
131e21fb479STrond Norbye                              const void **pvalue)
132e21fb479STrond Norbye{
133e21fb479STrond Norbye    if (conn->client || pvalue == NULL) {
134e21fb479STrond Norbye        return SASL_BADPARAM;
135e21fb479STrond Norbye    }
136e21fb479STrond Norbye
137e21fb479STrond Norbye    switch (propnum) {
138e21fb479STrond Norbye    case CBSASL_USERNAME:
139e21fb479STrond Norbye        *pvalue = conn->c.server.username;
140e21fb479STrond Norbye        break;
141e21fb479STrond Norbye    case CBSASL_CONFIG:
142e21fb479STrond Norbye        *pvalue = conn->c.server.config;
143e21fb479STrond Norbye        break;
144e21fb479STrond Norbye    default:
145e21fb479STrond Norbye        return SASL_BADPARAM;
146e21fb479STrond Norbye    }
147e21fb479STrond Norbye
148e21fb479STrond Norbye    return SASL_OK;
149e21fb479STrond Norbye}
150e21fb479STrond Norbye
151e21fb479STrond NorbyeCBSASL_PUBLIC_API
152e21fb479STrond Norbyecbsasl_error_t cbsasl_setprop(cbsasl_conn_t *conn,
153e21fb479STrond Norbye                              cbsasl_prop_t propnum,
154e21fb479STrond Norbye                              const void *pvalue)
155e21fb479STrond Norbye{
156e21fb479STrond Norbye    void *old;
157e21fb479STrond Norbye    if (conn->client) {
158e21fb479STrond Norbye        return SASL_BADPARAM;
159e21fb479STrond Norbye    }
160e21fb479STrond Norbye
161e21fb479STrond Norbye    switch (propnum) {
162e21fb479STrond Norbye    case CBSASL_USERNAME:
163e21fb479STrond Norbye        old = conn->c.server.username;
164e21fb479STrond Norbye        if ((conn->c.server.username = strdup(pvalue)) == NULL) {
165e21fb479STrond Norbye            conn->c.server.username = old;
166e21fb479STrond Norbye            return SASL_NOMEM;
167e21fb479STrond Norbye        }
168e21fb479STrond Norbye        break;
169e21fb479STrond Norbye    case CBSASL_CONFIG:
170e21fb479STrond Norbye        old = conn->c.server.config;
171e21fb479STrond Norbye        if ((conn->c.server.config = strdup(pvalue)) == NULL) {
172e21fb479STrond Norbye            conn->c.server.config = old;
173e21fb479STrond Norbye            return SASL_NOMEM;
174e21fb479STrond Norbye        }
175e21fb479STrond Norbye        break;
176e21fb479STrond Norbye    default:
177e21fb479STrond Norbye        return SASL_BADPARAM;
178e21fb479STrond Norbye    }
179e21fb479STrond Norbye
180e21fb479STrond Norbye    free(old);
181e21fb479STrond Norbye    return SASL_OK;
182e21fb479STrond Norbye
183e21fb479STrond Norbye}
184e21fb479STrond Norbye
185e21fb479STrond Norbye/* This function is added to keep the randgen static ;-) */
186e21fb479STrond Norbyecbsasl_error_t cbsasl_secure_random(char *dest, size_t len) {
187e21fb479STrond Norbye    return (cb_rand_get(randgen, dest, len) == 0) ? SASL_OK : SASL_FAIL;
188e21fb479STrond Norbye}