summaryrefslogtreecommitdiffstats
path: root/src/auth/userdb-static.c
blob: bed0f586167ec6c94f6a36198a8aef70c5103af7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */

#include "auth-common.h"

#include "array.h"
#include "str.h"
#include "var-expand.h"
#include "userdb.h"
#include "userdb-template.h"


struct static_context {
	userdb_callback_t *callback, *old_callback;
	void *old_context;
};

struct static_userdb_module {
	struct userdb_module module;
	struct userdb_template *tmpl;

	bool allow_all_users:1;
};

static void static_lookup_real(struct auth_request *auth_request,
			       userdb_callback_t *callback)
{
	struct userdb_module *_module = auth_request->userdb->userdb;
	struct static_userdb_module *module =
		(struct static_userdb_module *)_module;
	const char *error;

	if (userdb_template_export(module->tmpl, auth_request, &error) < 0) {
		e_error(authdb_event(auth_request),
			"Failed to expand template: %s", error);
		callback(USERDB_RESULT_INTERNAL_FAILURE, auth_request);
	}
	callback(USERDB_RESULT_OK, auth_request);
}

static void
static_credentials_callback(enum passdb_result result,
			    const unsigned char *credentials ATTR_UNUSED,
			    size_t size ATTR_UNUSED,
			    struct auth_request *auth_request)
{
	struct static_context *ctx = auth_request->context;

	auth_request->userdb_lookup = TRUE;

	auth_request->private_callback.userdb = ctx->old_callback;
	auth_request->context = ctx->old_context;
	auth_request_set_state(auth_request, AUTH_REQUEST_STATE_USERDB);

	switch (result) {
	case PASSDB_RESULT_OK:
		static_lookup_real(auth_request, ctx->callback);
		break;
	case PASSDB_RESULT_USER_UNKNOWN:
	case PASSDB_RESULT_USER_DISABLED:
	case PASSDB_RESULT_PASS_EXPIRED:
		ctx->callback(USERDB_RESULT_USER_UNKNOWN, auth_request);
		break;
	case PASSDB_RESULT_SCHEME_NOT_AVAILABLE:
		e_error(authdb_event(auth_request),
			"passdb doesn't support lookups, "
			"can't verify user's existence");
		/* fall through */
	default:
		ctx->callback(USERDB_RESULT_INTERNAL_FAILURE, auth_request);
		break;
	}

	i_free(ctx);
}

static void static_lookup(struct auth_request *auth_request,
			  userdb_callback_t *callback)
{
	struct userdb_module *_module = auth_request->userdb->userdb;
	struct static_userdb_module *module =
		(struct static_userdb_module *)_module;
	struct static_context *ctx;

	if (!auth_request->fields.successful && !module->allow_all_users) {
		/* this is a userdb-only lookup. we need to know if this
		   users exists or not. use a passdb lookup to do that.
		   if the passdb doesn't support returning credentials, this
		   will of course fail.. */
		ctx = i_new(struct static_context, 1);
		ctx->old_callback = auth_request->private_callback.userdb;
		ctx->old_context = auth_request->context;
		ctx->callback = callback;

		i_assert(auth_request->state == AUTH_REQUEST_STATE_USERDB);
		auth_request_set_state(auth_request,
				       AUTH_REQUEST_STATE_MECH_CONTINUE);

		auth_request->context = ctx;
		if (auth_request->passdb != NULL) {
			/* kludge: temporarily work as if we weren't doing
			   a userdb lookup. this is to get auth cache to use
			   passdb caching instead of userdb caching. */
			auth_request->userdb_lookup = FALSE;
			auth_request_lookup_credentials(auth_request, "",
				static_credentials_callback);
		} else {
			static_credentials_callback(
				PASSDB_RESULT_SCHEME_NOT_AVAILABLE,
				uchar_empty_ptr, 0, auth_request);
		}
	} else {
		static_lookup_real(auth_request, callback);
	}
}

static struct userdb_module *
static_preinit(pool_t pool, const char *args)
{
	struct static_userdb_module *module;
	const char *value;

	module = p_new(pool, struct static_userdb_module, 1);
	module->tmpl = userdb_template_build(pool, "static", args);

	if (userdb_template_remove(module->tmpl, "allow_all_users", &value)) {
		module->allow_all_users = value == NULL ||
			strcasecmp(value, "yes") == 0;
	}
	return &module->module;
}

struct userdb_module_interface userdb_static = {
	"static",

	static_preinit,
	NULL,
	NULL,

	static_lookup,

	NULL,
	NULL,
	NULL
};