summaryrefslogtreecommitdiffstats
path: root/src/auth/db-ldap.h
blob: e919e79e3dfe7bc6867873a3a71f1e0fecb89e7d (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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
#ifndef DB_LDAP_H
#define DB_LDAP_H

/* Functions like ldap_bind() have been deprecated in OpenLDAP 2.3
   This define enables them until the code here can be refactored */
#define LDAP_DEPRECATED 1

/* Maximum number of pending requests before delaying new requests. */
#define DB_LDAP_MAX_PENDING_REQUESTS 8
/* connect() timeout to LDAP */
#define DB_LDAP_CONNECT_TIMEOUT_SECS 5
/* If LDAP connection is down, fail requests after waiting for this long. */
#define DB_LDAP_REQUEST_DISCONNECT_TIMEOUT_SECS 4
/* If request is still in queue after this many seconds and other requests
   have been replied, assume the request was lost and abort it. */
#define DB_LDAP_REQUEST_LOST_TIMEOUT_SECS 60
/* If server disconnects us, don't reconnect if no requests have been sent
   for this many seconds. */
#define DB_LDAP_IDLE_RECONNECT_SECS 60

#include <ldap.h>

struct auth_request;
struct ldap_connection;
struct ldap_request;

typedef void db_search_callback_t(struct ldap_connection *conn,
				  struct ldap_request *request,
				  LDAPMessage *res);

struct ldap_settings {
	const char *hosts;
	const char *uris;
	const char *dn;
	const char *dnpass;
	bool auth_bind;
	const char *auth_bind_userdn;

	bool tls;
	bool sasl_bind;
	const char *sasl_mech;
	const char *sasl_realm;
	const char *sasl_authz_id;

	const char *tls_ca_cert_file;
	const char *tls_ca_cert_dir;
	const char *tls_cert_file;
	const char *tls_key_file;
	const char *tls_cipher_suite;
	const char *tls_require_cert;

	const char *deref;
	const char *scope;
	const char *base;
	unsigned int ldap_version;

	const char *ldaprc_path;
	const char *debug_level;

	const char *user_attrs;
	const char *user_filter;
	const char *pass_attrs;
	const char *pass_filter;
	const char *iterate_attrs;
	const char *iterate_filter;

	const char *default_pass_scheme;
	bool userdb_warning_disable; /* deprecated for now at least */
	bool blocking;

	/* ... */
	int ldap_deref, ldap_scope, ldap_tls_require_cert_parsed;
	uid_t uid;
	gid_t gid;
};

enum ldap_request_type {
	LDAP_REQUEST_TYPE_SEARCH,
	LDAP_REQUEST_TYPE_BIND
};

struct ldap_field {
	/* Dovecot field name. */
	const char *name;
	/* Field value template with %vars. NULL = same as LDAP value. */
	const char *value;
	/* LDAP attribute name, or "" if this is a static field. */
	const char *ldap_attr_name;

	/* LDAP value contains a DN, which is looked up and used for @name
	   attributes. */
	bool value_is_dn;
	/* This attribute is used internally only via %{ldap_ptr},
	   it shouldn't be returned in iteration. */
	bool skip;
};
ARRAY_DEFINE_TYPE(ldap_field, struct ldap_field);

struct ldap_request {
	enum ldap_request_type type;

	/* msgid for sent requests, -1 if not sent */
	int msgid;
	/* timestamp when request was created */
	time_t create_time;

	/* Number of times this request has been sent to LDAP server. This
	   increases when LDAP gets disconnected and reconnect send the request
	   again. */
	unsigned int send_count;

	bool failed:1;
	/* This is to prevent double logging the result */
	bool result_logged:1;

	db_search_callback_t *callback;
	struct auth_request *auth_request;
};

struct ldap_request_named_result {
	const struct ldap_field *field;
	const char *dn;
	struct db_ldap_result *result;
};

struct ldap_request_search {
	struct ldap_request request;

	const char *base;
	const char *filter;
	char **attributes; /* points to pass_attr_names / user_attr_names */
	const ARRAY_TYPE(ldap_field) *attr_map;

	struct db_ldap_result *result;
	ARRAY(struct ldap_request_named_result) named_results;
	unsigned int name_idx;

	bool multi_entry;
};

struct ldap_request_bind {
	struct ldap_request request;

	const char *dn;
};

enum ldap_connection_state {
	/* Not connected */
	LDAP_CONN_STATE_DISCONNECTED,
	/* Binding - either to default dn or doing auth bind */
	LDAP_CONN_STATE_BINDING,
	/* Bound to auth dn */
	LDAP_CONN_STATE_BOUND_AUTH,
	/* Bound to default dn */
	LDAP_CONN_STATE_BOUND_DEFAULT
};

struct ldap_connection {
	struct ldap_connection *next;

	pool_t pool;
	int refcount;
	struct event *event;

	char *config_path;
        struct ldap_settings set;

	LDAP *ld;
	enum ldap_connection_state conn_state;
	int default_bind_msgid;

	int fd;
	struct io *io;
	struct timeout *to;

	/* Request queue contains sent requests at tail (msgid != -1) and
	   queued requests at head (msgid == -1). */
	struct aqueue *request_queue;
	ARRAY(struct ldap_request *) request_array;
	/* Number of messages in queue with msgid != -1 */
	unsigned int pending_count;

	/* Timestamp when we last received a reply */
	time_t last_reply_stamp;

	char **pass_attr_names, **user_attr_names, **iterate_attr_names;
	ARRAY_TYPE(ldap_field) pass_attr_map, user_attr_map, iterate_attr_map;
	bool userdb_used;
	bool delayed_connect;
};

/* Send/queue request */
void db_ldap_request(struct ldap_connection *conn,
		     struct ldap_request *request);

void db_ldap_set_attrs(struct ldap_connection *conn, const char *attrlist,
		       char ***attr_names_r, ARRAY_TYPE(ldap_field) *attr_map,
		       const char *skip_attr) ATTR_NULL(5);

struct ldap_connection *db_ldap_init(const char *config_path, bool userdb);
void db_ldap_unref(struct ldap_connection **conn);

int db_ldap_connect(struct ldap_connection *conn);
void db_ldap_connect_delayed(struct ldap_connection *conn);

void db_ldap_enable_input(struct ldap_connection *conn, bool enable);

const char *ldap_escape(const char *str,
			const struct auth_request *auth_request);
const char *ldap_get_error(struct ldap_connection *conn);

struct db_ldap_result_iterate_context *
db_ldap_result_iterate_init(struct ldap_connection *conn,
			    struct ldap_request_search *ldap_request,
			    LDAPMessage *res, bool skip_null_values);
bool db_ldap_result_iterate_next(struct db_ldap_result_iterate_context *ctx,
				 const char **name_r,
				 const char *const **values_r);
void db_ldap_result_iterate_deinit(struct db_ldap_result_iterate_context **ctx);

#endif