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