src/login-common/sasl-server.c
author Timo Sirainen <tss@iki.fi>
Mon Nov 05 20:23:32 2007 +0200 (2007-11-05)
branchbranch_1_0
changeset 5449 6df077099f0b
parent 5217 a30ef30c8f8e
child 5458 73a3a6b1af36
permissions -rw-r--r--
"Unsupported auth mechanism" and "Plaintext auth disabled" errors should
result in NO instead of BAD reply.
     1 /* Copyright (C) 2002-2004 Timo Sirainen */
     2 
     3 #include "common.h"
     4 #include "base64.h"
     5 #include "buffer.h"
     6 #include "str-sanitize.h"
     7 #include "auth-client.h"
     8 #include "ssl-proxy.h"
     9 #include "client-common.h"
    10 #include "master.h"
    11 
    12 static enum auth_request_flags
    13 client_get_auth_flags(struct client *client)
    14 {
    15         enum auth_request_flags auth_flags = 0;
    16 
    17 	if (client->proxy != NULL &&
    18 	    ssl_proxy_has_valid_client_cert(client->proxy))
    19 		auth_flags |= AUTH_REQUEST_FLAG_VALID_CLIENT_CERT;
    20 	if (client->secured)
    21 		auth_flags |= AUTH_REQUEST_FLAG_SECURED;
    22 	return auth_flags;
    23 }
    24 
    25 static void
    26 call_client_callback(struct client *client, enum sasl_server_reply reply,
    27 		     const char *data, const char *const *args)
    28 {
    29 	sasl_server_callback_t *sasl_callback;
    30 
    31 	i_assert(reply != SASL_SERVER_REPLY_CONTINUE);
    32 
    33 	sasl_callback = client->sasl_callback;
    34 	client->sasl_callback = NULL;
    35 
    36 	sasl_callback(client, reply, data, args);
    37 	/* NOTE: client may be destroyed now */
    38 }
    39 
    40 static void master_callback(struct client *client, bool success)
    41 {
    42 	client->authenticating = FALSE;
    43 	call_client_callback(client, success ? SASL_SERVER_REPLY_SUCCESS :
    44 			     SASL_SERVER_REPLY_MASTER_FAILED, NULL, NULL);
    45 }
    46 
    47 static void authenticate_callback(struct auth_request *request, int status,
    48 				  const char *data_base64,
    49 				  const char *const *args, void *context)
    50 {
    51 	struct client *client = context;
    52 	unsigned int i;
    53 	bool nologin;
    54 
    55 	if (!client->authenticating) {
    56 		/* client aborted */
    57 		i_assert(status < 0);
    58 		return;
    59 	}
    60 
    61 	i_assert(client->auth_request == request);
    62 	client->waiting_auth_reply = FALSE;
    63 
    64 	switch (status) {
    65 	case 0:
    66 		/* continue */
    67 		client->sasl_callback(client, SASL_SERVER_REPLY_CONTINUE,
    68 				      data_base64, NULL);
    69 		break;
    70 	case 1:
    71 		client->auth_request = NULL;
    72 
    73 		nologin = FALSE;
    74 		for (i = 0; args[i] != NULL; i++) {
    75 			if (strncmp(args[i], "user=", 5) == 0) {
    76 				i_free(client->virtual_user);
    77 				client->virtual_user = i_strdup(args[i] + 5);
    78 			}
    79 			if (strcmp(args[i], "nologin") == 0 ||
    80 			    strcmp(args[i], "proxy") == 0) {
    81 				/* user can't login */
    82 				nologin = TRUE;
    83 			}
    84 		}
    85 
    86 		if (nologin) {
    87 			client->authenticating = FALSE;
    88 			call_client_callback(client, SASL_SERVER_REPLY_SUCCESS,
    89 					     NULL, args);
    90 		} else {
    91 			master_request_login(client, master_callback,
    92 				auth_client_request_get_server_pid(request),
    93 				auth_client_request_get_id(request));
    94 		}
    95 		break;
    96 	case -1:
    97 		client->auth_request = NULL;
    98 
    99 		if (args != NULL) {
   100 			/* parse our username if it's there */
   101 			for (i = 0; args[i] != NULL; i++) {
   102 				if (strncmp(args[i], "user=", 5) == 0) {
   103 					i_free(client->virtual_user);
   104 					client->virtual_user =
   105 						i_strdup(args[i] + 5);
   106 				}
   107 			}
   108 		}
   109 
   110 		client->authenticating = FALSE;
   111 		call_client_callback(client, SASL_SERVER_REPLY_AUTH_FAILED,
   112 				     NULL, args);
   113 		break;
   114 	}
   115 }
   116 
   117 void sasl_server_auth_begin(struct client *client,
   118 			    const char *service, const char *mech_name,
   119 			    const char *initial_resp_base64,
   120 			    sasl_server_callback_t *callback)
   121 {
   122 	struct auth_request_info info;
   123 	const struct auth_mech_desc *mech;
   124 	const char *error;
   125 
   126 	client->authenticating = TRUE;
   127 	i_free(client->auth_mech_name);
   128 	client->auth_mech_name = str_ucase(i_strdup(mech_name));
   129 	client->sasl_callback = callback;
   130 
   131 	mech = auth_client_find_mech(auth_client, mech_name);
   132 	if (mech == NULL) {
   133 		sasl_server_auth_failed(client,
   134 			"Unsupported authentication mechanism.");
   135 		return;
   136 	}
   137 
   138 	if (!client->secured && disable_plaintext_auth &&
   139 	    (mech->flags & MECH_SEC_PLAINTEXT) != 0) {
   140 		sasl_server_auth_failed(client,
   141 			"Plaintext authentication disabled.");
   142 		return;
   143 	}
   144 
   145 	memset(&info, 0, sizeof(info));
   146 	info.mech = mech->name;
   147 	info.service = service;
   148 	info.cert_username = client->proxy == NULL ? NULL :
   149 		ssl_proxy_get_peer_name(client->proxy);
   150 	info.flags = client_get_auth_flags(client);
   151 	info.local_ip = client->local_ip;
   152 	info.remote_ip = client->ip;
   153 	info.initial_resp_base64 = initial_resp_base64;
   154 
   155 	client->auth_request =
   156 		auth_client_request_new(auth_client, NULL, &info,
   157 					authenticate_callback, client, &error);
   158 	if (client->auth_request == NULL) {
   159 		sasl_server_auth_failed(client,
   160 			 t_strconcat("Authentication failed: ", error, NULL));
   161 	}
   162 }
   163 
   164 static void sasl_server_auth_cancel(struct client *client, const char *reason,
   165 				    enum sasl_server_reply reply)
   166 {
   167 	i_assert(client->authenticating);
   168 
   169 	if (verbose_auth && reason != NULL) {
   170 		const char *auth_name =
   171 			str_sanitize(client->auth_mech_name, MAX_MECH_NAME);
   172 		client_syslog(client,
   173 			t_strdup_printf("Authenticate %s failed: %s",
   174 					auth_name, reason));
   175 	}
   176 
   177 	client->authenticating = FALSE;
   178 	client->waiting_auth_reply = FALSE;
   179 
   180 	if (client->auth_request != NULL) {
   181 		auth_client_request_abort(client->auth_request);
   182 		client->auth_request = NULL;
   183 	}
   184 
   185 	call_client_callback(client, reply, reason, NULL);
   186 }
   187 
   188 void sasl_server_auth_failed(struct client *client, const char *reason)
   189 {
   190 	sasl_server_auth_cancel(client, reason, SASL_SERVER_REPLY_AUTH_FAILED);
   191 }
   192 
   193 void sasl_server_auth_client_error(struct client *client, const char *reason)
   194 {
   195 	sasl_server_auth_cancel(client, reason, SASL_SERVER_REPLY_CLIENT_ERROR);
   196 }