mech.c revision de7f381feed323acf07f990150a55db67e0c6259
89a126810703c666309310d0f3189e9834d70b5bTimo Sirainen/* Copyright (C) 2002 Timo Sirainen */
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainenconst char *const *auth_realms;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainenchar username_chars[256], username_translation[256];
64510d2cc23a79d2142030bf5bade44baa490db3Timo Sirainenstatic struct auth_client_request_reply failure_reply;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainenvoid mech_register_module(struct mech_module *module)
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainenvoid mech_unregister_module(struct mech_module *module)
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen for (pos = &mech_modules; *pos != NULL; pos = &(*pos)->next) {
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen if (strcmp((*pos)->module.mech_name, module->mech_name) == 0) {
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen for (list = mech_modules; list != NULL; list = list->next)
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainenstatic struct mech_module *mech_module_find(const char *name)
c69a255a68103a50fa3f04a527281a169075403fTimo Sirainen for (list = mech_modules; list != NULL; list = list->next) {
0f66f12eb4cdbf47670975044c88d8f388bf92dfTimo Sirainen if (strcasecmp(list->module.mech_name, name) == 0)
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainenvoid mech_request_new(struct auth_client_connection *conn,
687d1dee0e92229232aa8be416897b640df67d07Timo Sirainen const unsigned char *data,
87b426af6a2365c6840b14281a98c23e903bf28eTimo Sirainen /* make sure data is NUL-terminated */
87b426af6a2365c6840b14281a98c23e903bf28eTimo Sirainen if (request->data_size <= ip_size*2 || request->initial_resp_idx == 0 ||
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen request->protocol_idx >= request->data_size ||
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen request->initial_resp_idx > request->data_size ||
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen i_error("BUG: Auth client %u sent corrupted request",
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen mech = mech_module_find((const char *)data + request->mech_idx);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen /* unsupported mechanism */
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen i_error("BUG: Auth client %u requested unsupported "
687d1dee0e92229232aa8be416897b640df67d07Timo Sirainen auth_request = mech_cyrus_sasl_new(conn, request, callback);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen auth_request->local_ip.family = request->ip_family;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen auth_request->remote_ip.family = request->ip_family;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen memcpy(&auth_request->local_ip.ip, data, ip_size);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen memcpy(&auth_request->remote_ip.ip, data + ip_size, ip_size);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen (request->flags & AUTH_CLIENT_FLAG_SSL_VALID_CLIENT_CERT) == 0) {
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen /* we fail without valid certificate */
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen "Client didn't present valid SSL certificate",
72388282bf6718c39af34cfcf51438910f9d62daTimo Sirainen hash_insert(conn->auth_requests, POINTER_CAST(request->id),
0ce8f754204c7eeb33805993807393f74faf2cd3Timo Sirainen if (!auth_request->auth_initial(auth_request, request, data, callback))
e1b83f64e62cc3e8967c75fcc3f9b5dbb243d3b3Timo Sirainenvoid mech_request_continue(struct auth_client_connection *conn,
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen const unsigned char *data,
345253fb28498b2e0a60f4a2a8644c65feee7e75Timo Sirainen auth_request = hash_lookup(conn->auth_requests,
e1b83f64e62cc3e8967c75fcc3f9b5dbb243d3b3Timo Sirainen /* timeouted */
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen if (!auth_request->auth_continue(auth_request,
62394a19cba1a8df01cad66eaa9331a70464441eTimo Sirainenvoid mech_request_free(struct auth_request *auth_request, unsigned int id)
62394a19cba1a8df01cad66eaa9331a70464441eTimo Sirainen hash_remove(auth_request->conn->auth_requests,
62394a19cba1a8df01cad66eaa9331a70464441eTimo Sirainenvoid mech_init_auth_client_reply(struct auth_client_request_reply *reply)
62394a19cba1a8df01cad66eaa9331a70464441eTimo Sirainenvoid *mech_auth_success(struct auth_client_request_reply *reply,
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen buf = buffer_create_dynamic(pool_datastack_create(), 256, (size_t)-1);
1dba794aa92dc13e6afd7a50a8c33cb19d6aa235Timo Sirainen buffer_append(buf, auth_request->user, strlen(auth_request->user)+1);
1dba794aa92dc13e6afd7a50a8c33cb19d6aa235Timo Sirainenvoid mech_auth_finish(struct auth_request *auth_request,
1dba794aa92dc13e6afd7a50a8c33cb19d6aa235Timo Sirainen const void *data, size_t data_size, int success)
1dba794aa92dc13e6afd7a50a8c33cb19d6aa235Timo Sirainen /* failure. don't announce it immediately to avoid
1dba794aa92dc13e6afd7a50a8c33cb19d6aa235Timo Sirainen a) timing attacks, b) flooding */
1dba794aa92dc13e6afd7a50a8c33cb19d6aa235Timo Sirainen /* get this before callback because it can destroy connection */
1dba794aa92dc13e6afd7a50a8c33cb19d6aa235Timo Sirainen free_request = AUTH_MASTER_IS_DUMMY(auth_request->conn->master);
1dba794aa92dc13e6afd7a50a8c33cb19d6aa235Timo Sirainen reply_data = mech_auth_success(&reply, auth_request, data, data_size);
1dba794aa92dc13e6afd7a50a8c33cb19d6aa235Timo Sirainen auth_request->callback(&reply, reply_data, auth_request->conn);
1dba794aa92dc13e6afd7a50a8c33cb19d6aa235Timo Sirainen /* we don't have master process, the request is no longer
1dba794aa92dc13e6afd7a50a8c33cb19d6aa235Timo Sirainen mech_request_free(auth_request, auth_request->id);
1dba794aa92dc13e6afd7a50a8c33cb19d6aa235Timo Sirainenint mech_fix_username(char *username, const char **error_r)
1dba794aa92dc13e6afd7a50a8c33cb19d6aa235Timo Sirainen unsigned char *p;
1dba794aa92dc13e6afd7a50a8c33cb19d6aa235Timo Sirainen for (p = (unsigned char *)username; *p != '\0'; p++) {
1dba794aa92dc13e6afd7a50a8c33cb19d6aa235Timo Sirainen *error_r = "Username contains disallowed characters";
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainenvoid auth_request_ref(struct auth_request *request)
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainenint auth_request_unref(struct auth_request *request)
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainenstatic const char *escape_none(const char *str)
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainenauth_request_get_var_expand_table(const struct auth_request *auth_request,
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen const char *(*escape_func)(const char *))
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen static struct var_expand_table static_tab[] = {
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen tab[0].value = escape_func(auth_request->user);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen tab[1].value = escape_func(t_strcut(auth_request->user, '@'));
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen tab[2].value = strchr(auth_request->user, '@');
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen /* tab[4] = we have no home dir */
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen tab[5].value = net_ip2addr(&auth_request->local_ip);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen tab[6].value = net_ip2addr(&auth_request->remote_ip);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen tab[7].value = dec2str(auth_request->conn->pid);
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainenconst char *get_log_prefix(const struct auth_request *auth_request)
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen const char *p, *ip;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen /* any control characters in username will be replaced by '?' */
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen for (p = auth_request->user; *p != '\0'; p++) {
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen if ((unsigned char)*p < 32)
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen for (; *p != '\0'; p++) {
e619ecbbc00cba9e6e1e8322caa59776507fac02Timo Sirainen if ((unsigned char)*p < 32)
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen auth_request = buffer_get_modifyable_data(auth_failures_buf, &size);
0ae99441ae9ef80f435f3eb85fad16e136036b0bTimo Sirainen for (i = 0; i < size; i++) {
e1b83f64e62cc3e8967c75fcc3f9b5dbb243d3b3Timo Sirainen auth_request[i]->callback(&reply, NULL, auth_request[i]->conn);
e1b83f64e62cc3e8967c75fcc3f9b5dbb243d3b3Timo Sirainen mech_request_free(auth_request[i], auth_request[i]->id);
1dba794aa92dc13e6afd7a50a8c33cb19d6aa235Timo Sirainenstatic void auth_failure_timeout(void *context __attr_unused__)
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen const char *const *mechanisms;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen const char *env;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen memset(&failure_reply, 0, sizeof(failure_reply));
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen failure_reply.result = AUTH_CLIENT_RESULT_FAILURE;
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen anonymous_username = getenv("ANONYMOUS_USERNAME");
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen if (anonymous_username != NULL && *anonymous_username == '\0')
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen /* register wanted mechanisms */
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen else if (strcasecmp(*mechanisms, "LOGIN") == 0)
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen else if (strcasecmp(*mechanisms, "APOP") == 0)
050975ee630c761ab237fce7b8f84fe189bb02d2Timo Sirainen else if (strcasecmp(*mechanisms, "CRAM-MD5") == 0)
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen else if (strcasecmp(*mechanisms, "DIGEST-MD5") == 0)
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen else if (strcasecmp(*mechanisms, "NTLM") == 0)
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen else if (strcasecmp(*mechanisms, "ANONYMOUS") == 0) {
2e03303e721a293d796c0287829396f5caea76eaTimo Sirainen "but anonymous_username not given");
*mechanisms);
mechanisms++;
#ifdef USE_CYRUS_SASL2
if (set_use_cyrus_sasl)
void mech_deinit(void)