s/qmail 4.3.17
Next generation secure email transport
Loading...
Searching...
No Matches
qmail-ldapam.c
Go to the documentation of this file.
1#define LDAP_DEPRECATE 1
2#include <sys/types.h>
3#include <unistd.h>
4#include <grp.h>
5#include <pwd.h>
6#include <ldap.h>
7#include "auto_qmail.h"
8#include "qmail.h"
9#include "case.h"
10#include "control.h"
11#include "constmap.h"
12#include "readwrite.h"
13#include "buffer.h"
14#include "fd.h"
15#include "byte.h"
16#include "case.h"
17#include "str.h"
18#include "stralloc.h"
19#include "exit.h"
20#include "logmsg.h"
21#include "pathexec.h"
22#include "getln.h"
23#include "scan.h"
24
25#define WHO "qmail-ldapam"
26
27#define LDAP_SCOPE LDAP_SCOPE_SUBTREE
28
29#define MAIL_ACCOUNT_NAME "mail"
30#define MAIL_ACCOUNT_UID 8
31#define MAIL_ACCOUNT_GID 12
32
33#define FDAUTH 3
34#define FDPWD 5
35#define FLAG_DIR "-d"
36#define FLAG_MAIL "-m"
37
38#define PORT_LDAP 389
39#define PORT_LDAPS 636
40
42buffer ba = BUFFER_INIT(write,FDAUTH,authbuf,sizeof(authbuf));
43char bspace[512];
44buffer bp;
45
47stralloc ldapcntl = {0};
48stralloc disabled = {0};
49
50/* LDAP binding params */
51
52stralloc binddn = {0};
53stralloc bindpw = {0};
54stralloc bindpwds = {0};
55stralloc bindbase = {0};
56stralloc bindhost = {0};
57stralloc bindmbox = {0};
58stralloc filter = {0};
59
60stralloc user = {0}; // user w/o domain appended
61stralloc homeparam = {0};
62
63unsigned long port = PORT_LDAP;
64
66{
67 logmsg(WHO,110,FATAL,"out of memory");
68}
69
70void exit(int fail)
71{
72 int i;
73 for (i = 0; i < sizeof(authbuf); ++i) authbuf[i] = 0;
74 _exit(fail);
75}
76
77int match = 0;
78
79void read_passwd(void)
80{
81 if (!bindpwds.len) {
82 buffer_init(&bp,buffer_unixread,FDPWD,bspace,sizeof(bspace));
83 if (getln(&bp,&bindpwds,&match,'\0') == -1)
84 logmsg(WHO,111,ERROR,"unable to read password");
85 close(5);
86 if (match) --bindpwds.len;
87 }
88}
89
90static int ldap_lookup(char *host,int port,char *user,char *pwd)
91{
92 char *attrs[] = { NULL };
93 char *dn = 0;
94 LDAP *ld;
95 LDAPMessage *res, *entry;
96 int r;
97
98 if ((ld = ldap_init(host,port)) == 0)
99 logmsg(WHO,110,ERROR,"Unable to initialise LDAP connection");
100
101// if (starttls)
102// ldap_start_tls_s(LDAP *ld, LDAPControl **serverctrls, LDAPControl **clientctrls);
103
104
105 r = ldap_simple_bind_s(ld,binddn.s,bindpw.s);
106 if (r) logmsg(WHO,110,ERROR,"can't bind with LDAP server");
107
108 r = ldap_search_s(ld,bindbase.s,LDAP_SCOPE,filter.s,attrs,0,&res);
109 if (r) logmsg(WHO,1,ERROR,B("search failed:",ldap_err2string(r)));
110
111 entry = ldap_first_entry(ld,res);
112 if (!entry) return 1;
113
114 dn = ldap_get_dn(ld,res);
115 ldap_msgfree(res);
116 r = ldap_simple_bind_s(ld,dn,pwd);
117 if (r) return 1;
118
119 ldap_memfree(dn);
120 ldap_unbind(ld);
121
122 return 0;
123}
124
125static int ldap_userhome(char *host,int port,char *user,char *pwd,char *mbox)
126{
127 char *attrs[] = { NULL };
128 char **values;
129 LDAP *ld;
130 LDAPMessage *res, *entry;
131 int r;
132
133 if ((ld = ldap_init(host,port) == 0))
134 logmsg(WHO,110,ERROR,"Unable to setup connection");
135
136 r = ldap_simple_bind_s(ld,binddn.s,bindpw.s);
137 if (r) logmsg(WHO,110,ERROR,"can't bind to LDAP server");
138
139 r = ldap_search_s(ld,bindbase.s,LDAP_SCOPE,filter.s,attrs,0,&res);
140 if (r) logmsg(WHO,1,ERROR,B("search failed: ",ldap_err2string(r)));
141
142 entry = ldap_first_entry(ld,res);
143 if (!entry) return 1;
144
145 values = ldap_get_values(ld,entry,mbox);
146 if (values && values[0]) {
147 if (!stralloc_copys(&homeparam,values[0])) temp_nomem();
148 if (!stralloc_cats(&homeparam,"../../")) temp_nomem();
149 if (!stralloc_0(&homeparam)) temp_nomem();
150 }
151
152 ldap_msgfree(res);
153 ldap_unbind(ld);
154
155 return 0;
156}
157
158static stralloc cafile = {0};
159static stralloc cadir = {0};
160static stralloc certfile = {0};
161static stralloc keyfile = {0};
162static stralloc certpwd = {0};
163
164int main (int argc, char **argv)
165{
166 char *authuser = 0;
167 char *ldaparam = 0;
168 char *domain = 0;
169 char *password = 0;
170 char *host = 0;
171 int authlen = 0;
172 int buflen = 0;
173 int domlen = 0;
174 int flaghome = 0;
175 int flagmail = 0;
176 int i = 0;
177 int f, h, j, k, p, c, r, t, w;
178 int rc;
179
180 if (!argv[1]) logmsg(WHO,100,USAGE," [-d|-m] prog");
181 if (!case_diffs(argv[1],FLAG_DIR)) {
182 if (!argv[2]) logmsg(WHO,100,USAGE," [-d|-m] prog");
183 flaghome = 1;
184 } else {
185 if (!case_diffs(argv[1],FLAG_MAIL)) {
186 if (!argv[2]) logmsg(WHO,100,USAGE," [-d|-m] prog");
187 flagmail = 1;
188 }
189 }
190
191 for (;;) {
192 do
193 rc = read(FDAUTH,authbuf + buflen,sizeof(authbuf) - buflen);
194 while ((rc == -1) && (errno == EINTR));
195 if (r == -1) exit(111);
196 if (rc == 0) break;
197 buflen += rc;
198 if (buflen >= sizeof(authbuf)) exit(2);
199 }
200 close(FDAUTH);
201
202 authuser = authbuf + i; /* username */
203 if (i == buflen) exit(2);
204 while (authbuf[i++]) /* password */
205 if (i == buflen) exit(2);
206 password= authbuf + i;
207 if (i == buflen) exit(2);
208
209 authlen = str_len(authuser);
210 if (!stralloc_copyb(&user,authuser,authlen)) temp_nomem();
211
212 if ((i = byte_rchr(authuser,authlen,'@'))) /* @domain */
213 if (i < authlen && authuser[i] == '@') {
214 domain = authuser + i;
215 domlen = str_len(domain);
216 case_lowerb(domain,domlen);
217 user.len = 0;
218 if (!stralloc_copyb(&user,authuser,i)) temp_nomem();
219 }
220 if (!stralloc_0(&user)) exit(111);
221
222 /* Read control file users/ldapauth and go for checks */
223
224 if (chdir(auto_qmail) == -1) exit(110);
225
226 switch (control_readfile(&ldapcntl,"control/ldapauth",0)) {
227 case -1: exit(110);
228 case 0: if (!constmap_init(&mapldapauth,"",0,1)) temp_nomem();
229 case 1: if (!constmap_init(&mapldapauth,ldapcntl.s,ldapcntl.len,1)) temp_nomem();
230 }
231
232 /* Check for disabled authuser/domains */
233
234 if (!stralloc_copys(&disabled,"!")) temp_nomem();
235 if (!stralloc_catb(&disabled,authuser,authlen)) temp_nomem();
237
238 if (domlen) {
239 disabled.len = 0;
240 if (!stralloc_copys(&disabled,"!")) temp_nomem();
241 if (!stralloc_catb(&disabled,domain,domlen)) temp_nomem();
243 }
244
245 if (!ldaparam && domlen)
246 ldaparam = constmap(&mapldapauth,domain,domlen); // 1. ldap server by domain
247 if (!ldaparam)
248 ldaparam = constmap(&mapldapauth,"*",1); // 2. one ldap for all
249
250 if (!ldaparam) exit(1);
251
252 /* Evaluate LDAP lookup params: i j h p t c w f h
253 Host:Bind_DN|Bind_PW|Base|Host;Port|CA|Cert:Pwd|Filter:Homedir */
254
255 if (!stralloc_copys(&bindhost,"localhost")) temp_nomem(); /* Default LDAP host */
256 if (!stralloc_copys(&bindmbox,"homeDirectory")) temp_nomem(); /* Default POSIX name*/
257
258 i = str_chr(ldaparam,'|'); /* Bind DN */
259 if (ldaparam[i] == '|') {
260 ldaparam[i] = 0;
261
262 j = str_chr(ldaparam + i,'|'); /* Bind PWD */
263 if (ldaparam[i + j + 1] == '|') {
264 ldaparam[i + j + 1] = 0;
265
266 k = str_chr(ldaparam + i + j + 2,'|'); /* Base */
267 if (ldaparam[i + j + k + 2] == '|') {
268 ldaparam[i + j + k + 2] = 0;
269 if (!stralloc_copys(&bindbase,ldaparam + i + j + 2)) temp_nomem();
270
271 p = str_chr(ldaparam + i + j + k + 3,';'); /* Host;Port */
272 if (ldaparam[i + j + k + p + 3] == ';') {
273 ldaparam[i + j + k + p + 2] = 0;
274 if (p > 0) scan_ulong(ldaparam + i + j + k + p + 4,&port);
275 if (!stralloc_copys(&bindhost,ldaparam + i + j + k + 3)) temp_nomem();
276
277 t = str_chr(ldaparam + i + j + k + 3,'|'); /* Trust Cert */
278 if (ldaparam[i + j + k + t + 3] == '|') {
279 ldaparam[i + j + k + t + 3] = 0;
280 if (ldaparam[i + j + k + t + 2] == '/') {
281 if (!stralloc_copys(&cadir,ldaparam + i + j + k + t + 3)) temp_nomem();
282 if (!stralloc_0(&cadir)) temp_nomem();
283 } else {
284 if (!stralloc_copys(&cafile,ldaparam + i + j + k + t + 3)) temp_nomem();
285 if (!stralloc_0(&cafile)) temp_nomem();
286 }
287
288 w = str_chr(ldaparam + i + j + k + t + 4,':'); /* Cert:Pwd */
289 if (ldaparam[i + j + k + t + w + 4] == ':') {
290 ldaparam[i + j + k + t + w + 4] = 0;
291 if (!stralloc_copys(&certfile,ldaparam + i + j + k + t + 4)) temp_nomem();
292
293 f = str_chr(ldaparam + i + j + k + t + w + 5,':'); /* Filter */
294 if (ldaparam[i + j + k + t + w + 4] == '|') {
295 ldaparam[i + j + k + t + w + 4] = 0;
296 if (!stralloc_copys(&certpwd,ldaparam + i + j + k + f + 4)) temp_nomem();
297
298 h = str_chr(ldaparam + i + j + k + 3,'|'); /* Homedir */
299 if (ldaparam[i + j + k + h + 3] == '|') {
300 ldaparam[i + j + k + t + 3] = 0;
301 if (!stralloc_copys(&bindmbox,ldaparam + i + j + k + 3)) temp_nomem();
302 if (!stralloc_0(&bindmbox)) temp_nomem();
303 }
304
305 } // f
306 } // c
307 } // t
308 } // k
309 } // j
310
311 if (!stralloc_copys(&bindpw,ldaparam + i + 1)) temp_nomem();
312 if (!stralloc_0(&bindpw)) temp_nomem();
313 } // i
314 if (!stralloc_copys(&binddn,ldaparam)) temp_nomem();
315 if (!stralloc_0(&binddn)) temp_nomem();
316 }
317
318 if (flagmail) { /* LDAP filter */
319 if (!stralloc_copys(&filter,"(&(mail=")) temp_nomem();
320 if (!stralloc_cats(&filter,authuser)) temp_nomem();
321 if (!stralloc_cats(&filter,"))")) temp_nomem();
322 if (!stralloc_0(&filter)) temp_nomem();
323 } else {
324 if (!stralloc_copys(&filter,"(&uid=")) temp_nomem();
325 if (!stralloc_cat(&filter,&user)) temp_nomem();
326 if (!stralloc_cats(&filter,")(dc=")) temp_nomem();
327 if (!stralloc_cats(&filter,host)) temp_nomem();
328 if (!stralloc_cats(&filter,"))")) temp_nomem();
329 if (!stralloc_0(&filter)) temp_nomem();
330 }
331
332 if (!str_diff(bindpw.s,"*")) {
333 read_passwd();
334
335 for (i = 0; i < bindpwds.len; i++) {
336 if (bindpwds.s[i] == ' ') {
337 if (!stralloc_copyb(&bindpw,bindpwds.s,i - 1)) temp_nomem();
338 if (!stralloc_0(&bindpw)) temp_nomem();
339 host = bindhost.s;
340 if (!ldap_lookup(host,port,authuser,password)) break;
341 bindpwds.s = bindpwds.s + i;
342 ++i;
343 }
344 }
345 logmsg(WHO,110,ERROR,B("can't bind to LDAP host: ",host));
346 } else
347 if (ldap_lookup(host,port,authuser,password))
348 logmsg(WHO,110,ERROR,B("can't bind to LDAP host: ",host));
349
350 /* Now we check the user's mailbox for POP3 and IMAP4 capabilities */
351
352 if (flaghome) {
353 if (ldap_userhome(host,port,authuser,password,bindmbox.s)) exit(1);
354
355 if (initgroups(MAIL_ACCOUNT_NAME, MAIL_ACCOUNT_GID))
356 logmsg(WHO,107,ERROR,B("Unable to set supplementary groups: ",strerror(errno)));
357 if (setgid(MAIL_ACCOUNT_GID))
358 logmsg(WHO,106,ERROR,B("Unable to set gid: ",strerror(errno)));
359 if (setuid(MAIL_ACCOUNT_UID))
360 logmsg(WHO,105,ERROR,B("Unable to set uid: ",strerror(errno)));
361 if (chdir(homeparam.s))
362 logmsg(WHO,108,ERROR,B("Unable to change to home dir: ",homeparam.s,strerror(errno)));
363 }
364
365 for (i = 0; i < sizeof(authbuf); ++i) authbuf[i] = 0;
366
367 if (flaghome || flagmail) pathexec(argv + 2);
368 else pathexec(argv + 1);
369 exit(111);
370}
char auto_qmail[]
int main()
Definition: chkshsgr.c:6
int constmap_init(struct constmap *cm, char *s, int len, int flagcolon)
Definition: constmap.c:35
int control_readfile(stralloc *sa, char *fn, int flagme)
Definition: control.c:87
int stralloc_copys(stralloc *, char const *)
void _exit(int)
void h(char *, char *, int, int, int)
Definition: install.c:15
void c(char *, char *, char *, int, int, int)
Definition: install.c:67
void p(char *, char *, int, int, int)
Definition: install.c:49
char host[256]
Definition: hostname.c:5
char * mbox
Definition: maildir2mbox.c:18
void exit(int fail)
Definition: qmail-ldapam.c:70
#define FDPWD
Definition: qmail-ldapam.c:34
stralloc bindmbox
Definition: qmail-ldapam.c:57
buffer ba
Definition: qmail-ldapam.c:42
stralloc disabled
Definition: qmail-ldapam.c:48
char authbuf[BUFSIZE_AUTH]
Definition: qmail-ldapam.c:41
#define PORT_LDAP
Definition: qmail-ldapam.c:38
stralloc homeparam
Definition: qmail-ldapam.c:61
unsigned long port
Definition: qmail-ldapam.c:63
stralloc ldapcntl
Definition: qmail-ldapam.c:47
stralloc bindpw
Definition: qmail-ldapam.c:53
stralloc user
Definition: qmail-ldapam.c:60
stralloc bindpwds
Definition: qmail-ldapam.c:54
#define FLAG_DIR
Definition: qmail-ldapam.c:35
stralloc bindhost
Definition: qmail-ldapam.c:56
#define MAIL_ACCOUNT_GID
Definition: qmail-ldapam.c:31
#define FDAUTH
Definition: qmail-ldapam.c:33
struct constmap mapldapauth
Definition: qmail-ldapam.c:46
char bspace[512]
Definition: qmail-ldapam.c:43
#define MAIL_ACCOUNT_NAME
Definition: qmail-ldapam.c:29
#define MAIL_ACCOUNT_UID
Definition: qmail-ldapam.c:30
void temp_nomem()
Definition: qmail-ldapam.c:65
buffer bp
Definition: qmail-ldapam.c:44
void read_passwd(void)
Definition: qmail-ldapam.c:79
#define FLAG_MAIL
Definition: qmail-ldapam.c:36
int match
Definition: qmail-ldapam.c:77
stralloc binddn
Definition: qmail-ldapam.c:52
#define WHO
Definition: qmail-ldapam.c:25
#define LDAP_SCOPE
Definition: qmail-ldapam.c:27
stralloc bindbase
Definition: qmail-ldapam.c:55
stralloc filter
Definition: qmail-ldapam.c:58
int j
Definition: qmail-send.c:926
#define BUFSIZE_AUTH
Definition: qmail.h:9
uint32_t k[64]
Definition: sha256.c:26
stralloc domain
Definition: spf.c:34
stralloc certfile
Definition: qmail-remote.c:422
stralloc keyfile
Definition: qmail-remote.c:423
stralloc cadir
Definition: qmail-remote.c:421
stralloc cafile
Definition: qmail-remote.c:420
void write()