xref: /memcached-1.4.29/sasl_defs.c (revision b4add044)
17a221d95STrond Norbye /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2f1307c4dSDustin Sallings #include "memcached.h"
3f1307c4dSDustin Sallings #include <stdio.h>
4f1307c4dSDustin Sallings #include <stdlib.h>
57a221d95STrond Norbye #include <string.h>
6ee486ab2SSteve Wills #include <sasl/saslplug.h>
77a221d95STrond Norbye 
8b0a858ceSDustin Sallings char my_sasl_hostname[1025];
9b0a858ceSDustin Sallings 
107a221d95STrond Norbye #ifdef HAVE_SASL_CB_GETCONF
117a221d95STrond Norbye /* The locations we may search for a SASL config file if the user didn't
127a221d95STrond Norbye  * specify one in the environment variable SASL_CONF_PATH
137a221d95STrond Norbye  */
147a221d95STrond Norbye const char * const locations[] = {
157a221d95STrond Norbye     "/etc/sasl/memcached.conf",
167a221d95STrond Norbye     "/etc/sasl2/memcached.conf",
177a221d95STrond Norbye     NULL
187a221d95STrond Norbye };
197a221d95STrond Norbye #endif
207a221d95STrond Norbye 
21dece7f87SDustin Sallings #ifndef HAVE_SASL_CALLBACK_FT
2239d59a90SDustin Sallings typedef int (*sasl_callback_ft)(void);
2339d59a90SDustin Sallings #endif
2439d59a90SDustin Sallings 
257a221d95STrond Norbye #ifdef ENABLE_SASL_PWDB
267a221d95STrond Norbye #define MAX_ENTRY_LEN 256
277a221d95STrond Norbye 
287a221d95STrond Norbye static const char *memcached_sasl_pwdb;
297a221d95STrond Norbye 
sasl_server_userdb_checkpass(sasl_conn_t * conn,void * context,const char * user,const char * pass,unsigned passlen,struct propctx * propctx)307a221d95STrond Norbye static int sasl_server_userdb_checkpass(sasl_conn_t *conn,
317a221d95STrond Norbye                                         void *context,
327a221d95STrond Norbye                                         const char *user,
337a221d95STrond Norbye                                         const char *pass,
347a221d95STrond Norbye                                         unsigned passlen,
357a221d95STrond Norbye                                         struct propctx *propctx)
367a221d95STrond Norbye {
377a221d95STrond Norbye     size_t unmlen = strlen(user);
387a221d95STrond Norbye     if ((passlen + unmlen) > (MAX_ENTRY_LEN - 4)) {
397a221d95STrond Norbye         fprintf(stderr,
407a221d95STrond Norbye                 "WARNING: Failed to authenticate <%s> due to too long password (%d)\n",
417a221d95STrond Norbye                 user, passlen);
427a221d95STrond Norbye         return SASL_NOAUTHZ;
437a221d95STrond Norbye     }
447a221d95STrond Norbye 
457a221d95STrond Norbye     FILE *pwfile = fopen(memcached_sasl_pwdb, "r");
467a221d95STrond Norbye     if (pwfile == NULL) {
477a221d95STrond Norbye         if (settings.verbose) {
487a221d95STrond Norbye             vperror("WARNING: Failed to open sasl database <%s>",
497a221d95STrond Norbye                     memcached_sasl_pwdb);
507a221d95STrond Norbye         }
517a221d95STrond Norbye         return SASL_NOAUTHZ;
527a221d95STrond Norbye     }
537a221d95STrond Norbye 
547a221d95STrond Norbye     char buffer[MAX_ENTRY_LEN];
557a221d95STrond Norbye     bool ok = false;
567a221d95STrond Norbye 
577a221d95STrond Norbye     while ((fgets(buffer, sizeof(buffer), pwfile)) != NULL) {
587a221d95STrond Norbye         if (memcmp(user, buffer, unmlen) == 0 && buffer[unmlen] == ':') {
597a221d95STrond Norbye             /* This is the correct user */
607a221d95STrond Norbye             ++unmlen;
617a221d95STrond Norbye             if (memcmp(pass, buffer + unmlen, passlen) == 0 &&
627a221d95STrond Norbye                 (buffer[unmlen + passlen] == ':' || /* Additional tokens */
637a221d95STrond Norbye                  buffer[unmlen + passlen] == '\n' || /* end of line */
647a221d95STrond Norbye                  buffer[unmlen + passlen] == '\r'|| /* dos format? */
657a221d95STrond Norbye                  buffer[unmlen + passlen] == '\0')) { /* line truncated */
667a221d95STrond Norbye                 ok = true;
677a221d95STrond Norbye             }
687a221d95STrond Norbye 
697a221d95STrond Norbye             break;
707a221d95STrond Norbye         }
717a221d95STrond Norbye     }
727a221d95STrond Norbye     (void)fclose(pwfile);
737a221d95STrond Norbye     if (ok) {
747a221d95STrond Norbye         return SASL_OK;
757a221d95STrond Norbye     }
767a221d95STrond Norbye 
777a221d95STrond Norbye     if (settings.verbose) {
787a221d95STrond Norbye         fprintf(stderr, "INFO: User <%s> failed to authenticate\n", user);
797a221d95STrond Norbye     }
807a221d95STrond Norbye 
817a221d95STrond Norbye     return SASL_NOAUTHZ;
827a221d95STrond Norbye }
837a221d95STrond Norbye #endif
847a221d95STrond Norbye 
857a221d95STrond Norbye #ifdef HAVE_SASL_CB_GETCONF
sasl_getconf(void * context,const char ** path)867a221d95STrond Norbye static int sasl_getconf(void *context, const char **path)
877a221d95STrond Norbye {
887a221d95STrond Norbye     *path = getenv("SASL_CONF_PATH");
897a221d95STrond Norbye 
907a221d95STrond Norbye     if (*path == NULL) {
917a221d95STrond Norbye         for (int i = 0; locations[i] != NULL; ++i) {
927a221d95STrond Norbye             if (access(locations[i], F_OK) == 0) {
937a221d95STrond Norbye                 *path = locations[i];
947a221d95STrond Norbye                 break;
957a221d95STrond Norbye             }
967a221d95STrond Norbye         }
977a221d95STrond Norbye     }
987a221d95STrond Norbye 
997a221d95STrond Norbye     if (settings.verbose) {
1007a221d95STrond Norbye         if (*path != NULL) {
1017a221d95STrond Norbye             fprintf(stderr, "Reading configuration from: <%s>\n", *path);
1027a221d95STrond Norbye         } else {
1037a221d95STrond Norbye             fprintf(stderr, "Failed to locate a config path\n");
1047a221d95STrond Norbye         }
1057a221d95STrond Norbye 
1067a221d95STrond Norbye     }
1077a221d95STrond Norbye 
1087a221d95STrond Norbye     return (*path != NULL) ? SASL_OK : SASL_FAIL;
1097a221d95STrond Norbye }
1107a221d95STrond Norbye #endif
1117a221d95STrond Norbye 
sasl_log(void * context,int level,const char * message)1127a221d95STrond Norbye static int sasl_log(void *context, int level, const char *message)
1137a221d95STrond Norbye {
1147a221d95STrond Norbye     bool log = true;
1157a221d95STrond Norbye 
1167a221d95STrond Norbye     switch (level) {
1177a221d95STrond Norbye     case SASL_LOG_NONE:
1187a221d95STrond Norbye         log = false;
1197a221d95STrond Norbye         break;
1207a221d95STrond Norbye     case SASL_LOG_PASS:
1217a221d95STrond Norbye     case SASL_LOG_TRACE:
1227a221d95STrond Norbye     case SASL_LOG_DEBUG:
1237a221d95STrond Norbye     case SASL_LOG_NOTE:
1247a221d95STrond Norbye         if (settings.verbose < 2) {
1257a221d95STrond Norbye             log = false;
1267a221d95STrond Norbye         }
1277a221d95STrond Norbye         break;
1287a221d95STrond Norbye     case SASL_LOG_WARN:
1297a221d95STrond Norbye     case SASL_LOG_FAIL:
1307a221d95STrond Norbye         if (settings.verbose < 1) {
1317a221d95STrond Norbye             log = false;
1327a221d95STrond Norbye         }
1337a221d95STrond Norbye         break;
1347a221d95STrond Norbye     default:
1357a221d95STrond Norbye         /* This is an error */
1367a221d95STrond Norbye         ;
1377a221d95STrond Norbye     }
1387a221d95STrond Norbye 
1397a221d95STrond Norbye     if (log) {
1407a221d95STrond Norbye         fprintf(stderr, "SASL (severity %d): %s\n", level, message);
1417a221d95STrond Norbye     }
1427a221d95STrond Norbye 
1437a221d95STrond Norbye     return SASL_OK;
1447a221d95STrond Norbye }
145f1307c4dSDustin Sallings 
146f1307c4dSDustin Sallings static sasl_callback_t sasl_callbacks[] = {
1477a221d95STrond Norbye #ifdef ENABLE_SASL_PWDB
148*b4add044SGabriel A. Samfira    { SASL_CB_SERVER_USERDB_CHECKPASS, (sasl_callback_ft)sasl_server_userdb_checkpass, NULL },
1497a221d95STrond Norbye #endif
1507a221d95STrond Norbye 
151ee486ab2SSteve Wills    { SASL_CB_LOG, (sasl_callback_ft)sasl_log, NULL },
1527a221d95STrond Norbye 
1537a221d95STrond Norbye #ifdef HAVE_SASL_CB_GETCONF
1547a221d95STrond Norbye    { SASL_CB_GETCONF, sasl_getconf, NULL },
1557a221d95STrond Norbye #endif
1567a221d95STrond Norbye 
1577a221d95STrond Norbye    { SASL_CB_LIST_END, NULL, NULL }
158f1307c4dSDustin Sallings };
159f1307c4dSDustin Sallings 
init_sasl(void)160f1307c4dSDustin Sallings void init_sasl(void) {
1617a221d95STrond Norbye #ifdef ENABLE_SASL_PWDB
1627a221d95STrond Norbye     memcached_sasl_pwdb = getenv("MEMCACHED_SASL_PWDB");
1637a221d95STrond Norbye     if (memcached_sasl_pwdb == NULL) {
1647a221d95STrond Norbye        if (settings.verbose) {
1657a221d95STrond Norbye           fprintf(stderr,
1667a221d95STrond Norbye                   "INFO: MEMCACHED_SASL_PWDB not specified. "
1677a221d95STrond Norbye                   "Internal passwd database disabled\n");
1687a221d95STrond Norbye        }
1697a221d95STrond Norbye        sasl_callbacks[0].id = SASL_CB_LIST_END;
1707a221d95STrond Norbye        sasl_callbacks[0].proc = NULL;
1717a221d95STrond Norbye     }
1727a221d95STrond Norbye #endif
1737a221d95STrond Norbye 
174b0a858ceSDustin Sallings     memset(my_sasl_hostname, 0, sizeof(my_sasl_hostname));
175b0a858ceSDustin Sallings     if (gethostname(my_sasl_hostname, sizeof(my_sasl_hostname)-1) == -1) {
176b0a858ceSDustin Sallings         if (settings.verbose) {
177b0a858ceSDustin Sallings             fprintf(stderr, "Error discovering hostname for SASL\n");
178b0a858ceSDustin Sallings         }
179b0a858ceSDustin Sallings         my_sasl_hostname[0] = '\0';
180b0a858ceSDustin Sallings     }
181b0a858ceSDustin Sallings 
182f1307c4dSDustin Sallings     if (sasl_server_init(sasl_callbacks, "memcached") != SASL_OK) {
183f1307c4dSDustin Sallings         fprintf(stderr, "Error initializing sasl.\n");
184f1307c4dSDustin Sallings         exit(EXIT_FAILURE);
185f1307c4dSDustin Sallings     } else {
186f1307c4dSDustin Sallings         if (settings.verbose) {
187f1307c4dSDustin Sallings             fprintf(stderr, "Initialized SASL.\n");
188f1307c4dSDustin Sallings         }
189f1307c4dSDustin Sallings     }
190f1307c4dSDustin Sallings }
191