18 static struct stat prev_stat = { 0 };
20 static pthread_mutex_t uhash_lock = PTHREAD_MUTEX_INITIALIZER;
21 static pthread_mutex_t sasl_db_thread_lock = PTHREAD_MUTEX_INITIALIZER;
22 static bool run_sasl_db_thread;
23 static pthread_t sasl_db_thread_tid;
26 static const int n_uht_buckets = 12289;
28 static void kill_whitey(
char *s) {
29 for(
int i = strlen(s) - 1;
i > 0 && isspace(s[
i]);
i--) {
34 static int u_hash_key(
const char *u)
36 uint32_t h = hash(u, strlen(u), 0) % n_uht_buckets;
37 assert(h < n_uht_buckets);
41 static char *find_pw(
const char *u,
char **cfg)
46 int h = u_hash_key(u);
49 while (e && strcmp(e->username, u) != 0) {
61 static void store_pw(
user_db_entry_t **ht,
const char *u,
const char *p,
const char *cfg)
68 e->username = strdup(u);
70 e->password = strdup(p);
72 e->config = cfg ? strdup(cfg) : NULL;
73 assert(!cfg || e->config);
75 int h = u_hash_key(u);
81 static void free_user_ht(
void)
84 for (
int i = 0;
i < n_uht_buckets;
i++) {
100 static const char *get_isasl_filename(
void)
102 return getenv(
"ISASL_PWFILE");
105 static int load_user_db(
void)
114 pthread_mutex_lock(&uhash_lock);
117 pthread_mutex_unlock(&uhash_lock);
119 const char *filename = get_isasl_filename();
123 FILE *sfile = fopen(filename,
"r");
134 while (fgets(up,
sizeof(up), sfile)) {
136 char *uname = up, *p = up, *cfg = NULL;
138 while (*p && !isspace(p[0])) {
148 while (*p && isspace(*p)) {
154 if (cfg[0] !=
'\0') {
156 while (*cfg && !isspace(cfg[0])) {
159 if (cfg[0] !=
'\0') {
163 while (*cfg && isspace(cfg[0])) {
168 store_pw(new_ut, uname, p, cfg);
175 settings.extensions.logger->
log(EXTENSION_LOG_INFO, NULL,
176 "Loaded isasl db from %s\n",
185 free((*pconn)->username);
186 free((*pconn)->config);
191 static bool isasl_is_fresh(
void)
195 const char *filename = get_isasl_filename();
198 if (stat(get_isasl_filename(), &st) < 0) {
199 perror(get_isasl_filename());
201 rv = prev_stat.st_mtime == st.st_mtime;
208 static void* check_isasl_db_thread(
void* arg)
210 uint32_t sleep_time = *(
int*)arg;
212 settings.extensions.logger->
log(EXTENSION_LOG_INFO, NULL,
213 "isasl checking DB every %ds",
217 run_sasl_db_thread =
true;
222 if (!isasl_is_fresh()) {
226 pthread_mutex_lock(&sasl_db_thread_lock);
227 if (!run_sasl_db_thread) {
230 pthread_mutex_unlock(&sasl_db_thread_lock);
236 void shutdown_sasl(
void)
238 pthread_mutex_lock(&sasl_db_thread_lock);
239 run_sasl_db_thread =
false;
240 pthread_mutex_unlock(&sasl_db_thread_lock);
241 pthread_join(sasl_db_thread_tid, NULL);
247 int rv = load_user_db();
249 static uint32_t sleep_time;
250 const char *sleep_time_str = getenv(
"ISASL_DB_CHECK_TIME");
253 if (pthread_attr_init(&attr) != 0 ||
254 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0)
256 settings.extensions.logger->
log(EXTENSION_LOG_WARNING, NULL,
257 "Failed to initialize pthread attributes: %s",
262 if (! (sleep_time_str && safe_strtoul(sleep_time_str, &sleep_time))) {
266 if (get_isasl_filename() != NULL &&
267 pthread_create(&sasl_db_thread_tid, &attr, check_isasl_db_thread,
270 settings.extensions.logger->
log(EXTENSION_LOG_WARNING, NULL,
271 "couldn't create isasl db update thread.");
278 int sasl_server_new(
const char *service,
279 const char *serverFQDN,
280 const char *user_realm,
281 const char *iplocalport,
282 const char *ipremoteport,
288 return *pconn ? SASL_OK : SASL_NOMEM;
302 assert(strcmp(prefix,
"") == 0);
303 assert(strcmp(sep,
" ") == 0);
304 assert(strcmp(suffix,
"") == 0);
307 *plen = strlen(*result);
311 static bool check_up(
const char *username,
const char *password,
char **cfg)
313 pthread_mutex_lock(&uhash_lock);
314 char *pw = find_pw(username, cfg);
315 bool rv = pw && (strcmp(password, pw) == 0);
316 pthread_mutex_unlock(&uhash_lock);
322 const char *clientin,
323 unsigned clientinlen,
324 const char **serverout,
325 unsigned *serveroutlen)
331 if(strcmp(mech,
"PLAIN") == 0) {
333 while (clientinlen > 0 && clientin[0] !=
'\0') {
338 if (clientinlen > 2 && clientinlen < 128 && clientin[0] ==
'\0') {
339 const char *username = clientin + 1;
341 int pwlen = clientinlen - 2 - strlen(username);
345 password[pwlen] =
'\0';
346 memcpy(password, clientin + 2 + strlen(username), pwlen);
348 if (check_up(username, password, &cfg)) {
349 if (conn->username) {
350 free(conn->username);
351 conn->username = NULL;
357 conn->username = strdup(username);
358 assert(conn->username);
359 conn->config = strdup(cfg);
360 assert(conn->config);
371 const char *clientin,
372 unsigned clientinlen,
373 const char **serverout,
374 unsigned *serveroutlen)
386 *pvalue = conn->username;
389 *pvalue = conn->config;
392 return SASL_BADPARAM;