xref: /memcached-1.4.29/sasl_defs.c (revision b4add044)
1 /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 #include "memcached.h"
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <sasl/saslplug.h>
7 
8 char my_sasl_hostname[1025];
9 
10 #ifdef HAVE_SASL_CB_GETCONF
11 /* The locations we may search for a SASL config file if the user didn't
12  * specify one in the environment variable SASL_CONF_PATH
13  */
14 const char * const locations[] = {
15     "/etc/sasl/memcached.conf",
16     "/etc/sasl2/memcached.conf",
17     NULL
18 };
19 #endif
20 
21 #ifndef HAVE_SASL_CALLBACK_FT
22 typedef int (*sasl_callback_ft)(void);
23 #endif
24 
25 #ifdef ENABLE_SASL_PWDB
26 #define MAX_ENTRY_LEN 256
27 
28 static const char *memcached_sasl_pwdb;
29 
sasl_server_userdb_checkpass(sasl_conn_t * conn,void * context,const char * user,const char * pass,unsigned passlen,struct propctx * propctx)30 static int sasl_server_userdb_checkpass(sasl_conn_t *conn,
31                                         void *context,
32                                         const char *user,
33                                         const char *pass,
34                                         unsigned passlen,
35                                         struct propctx *propctx)
36 {
37     size_t unmlen = strlen(user);
38     if ((passlen + unmlen) > (MAX_ENTRY_LEN - 4)) {
39         fprintf(stderr,
40                 "WARNING: Failed to authenticate <%s> due to too long password (%d)\n",
41                 user, passlen);
42         return SASL_NOAUTHZ;
43     }
44 
45     FILE *pwfile = fopen(memcached_sasl_pwdb, "r");
46     if (pwfile == NULL) {
47         if (settings.verbose) {
48             vperror("WARNING: Failed to open sasl database <%s>",
49                     memcached_sasl_pwdb);
50         }
51         return SASL_NOAUTHZ;
52     }
53 
54     char buffer[MAX_ENTRY_LEN];
55     bool ok = false;
56 
57     while ((fgets(buffer, sizeof(buffer), pwfile)) != NULL) {
58         if (memcmp(user, buffer, unmlen) == 0 && buffer[unmlen] == ':') {
59             /* This is the correct user */
60             ++unmlen;
61             if (memcmp(pass, buffer + unmlen, passlen) == 0 &&
62                 (buffer[unmlen + passlen] == ':' || /* Additional tokens */
63                  buffer[unmlen + passlen] == '\n' || /* end of line */
64                  buffer[unmlen + passlen] == '\r'|| /* dos format? */
65                  buffer[unmlen + passlen] == '\0')) { /* line truncated */
66                 ok = true;
67             }
68 
69             break;
70         }
71     }
72     (void)fclose(pwfile);
73     if (ok) {
74         return SASL_OK;
75     }
76 
77     if (settings.verbose) {
78         fprintf(stderr, "INFO: User <%s> failed to authenticate\n", user);
79     }
80 
81     return SASL_NOAUTHZ;
82 }
83 #endif
84 
85 #ifdef HAVE_SASL_CB_GETCONF
sasl_getconf(void * context,const char ** path)86 static int sasl_getconf(void *context, const char **path)
87 {
88     *path = getenv("SASL_CONF_PATH");
89 
90     if (*path == NULL) {
91         for (int i = 0; locations[i] != NULL; ++i) {
92             if (access(locations[i], F_OK) == 0) {
93                 *path = locations[i];
94                 break;
95             }
96         }
97     }
98 
99     if (settings.verbose) {
100         if (*path != NULL) {
101             fprintf(stderr, "Reading configuration from: <%s>\n", *path);
102         } else {
103             fprintf(stderr, "Failed to locate a config path\n");
104         }
105 
106     }
107 
108     return (*path != NULL) ? SASL_OK : SASL_FAIL;
109 }
110 #endif
111 
sasl_log(void * context,int level,const char * message)112 static int sasl_log(void *context, int level, const char *message)
113 {
114     bool log = true;
115 
116     switch (level) {
117     case SASL_LOG_NONE:
118         log = false;
119         break;
120     case SASL_LOG_PASS:
121     case SASL_LOG_TRACE:
122     case SASL_LOG_DEBUG:
123     case SASL_LOG_NOTE:
124         if (settings.verbose < 2) {
125             log = false;
126         }
127         break;
128     case SASL_LOG_WARN:
129     case SASL_LOG_FAIL:
130         if (settings.verbose < 1) {
131             log = false;
132         }
133         break;
134     default:
135         /* This is an error */
136         ;
137     }
138 
139     if (log) {
140         fprintf(stderr, "SASL (severity %d): %s\n", level, message);
141     }
142 
143     return SASL_OK;
144 }
145 
146 static sasl_callback_t sasl_callbacks[] = {
147 #ifdef ENABLE_SASL_PWDB
148    { SASL_CB_SERVER_USERDB_CHECKPASS, (sasl_callback_ft)sasl_server_userdb_checkpass, NULL },
149 #endif
150 
151    { SASL_CB_LOG, (sasl_callback_ft)sasl_log, NULL },
152 
153 #ifdef HAVE_SASL_CB_GETCONF
154    { SASL_CB_GETCONF, sasl_getconf, NULL },
155 #endif
156 
157    { SASL_CB_LIST_END, NULL, NULL }
158 };
159 
init_sasl(void)160 void init_sasl(void) {
161 #ifdef ENABLE_SASL_PWDB
162     memcached_sasl_pwdb = getenv("MEMCACHED_SASL_PWDB");
163     if (memcached_sasl_pwdb == NULL) {
164        if (settings.verbose) {
165           fprintf(stderr,
166                   "INFO: MEMCACHED_SASL_PWDB not specified. "
167                   "Internal passwd database disabled\n");
168        }
169        sasl_callbacks[0].id = SASL_CB_LIST_END;
170        sasl_callbacks[0].proc = NULL;
171     }
172 #endif
173 
174     memset(my_sasl_hostname, 0, sizeof(my_sasl_hostname));
175     if (gethostname(my_sasl_hostname, sizeof(my_sasl_hostname)-1) == -1) {
176         if (settings.verbose) {
177             fprintf(stderr, "Error discovering hostname for SASL\n");
178         }
179         my_sasl_hostname[0] = '\0';
180     }
181 
182     if (sasl_server_init(sasl_callbacks, "memcached") != SASL_OK) {
183         fprintf(stderr, "Error initializing sasl.\n");
184         exit(EXIT_FAILURE);
185     } else {
186         if (settings.verbose) {
187             fprintf(stderr, "Initialized SASL.\n");
188         }
189     }
190 }
191