1 /*
2 ** Copyright 2000-2020 Double Precision, Inc. See COPYING for
3 ** distribution information.
4 */
5
6 #include "auth.h"
7 #include "courierauthstaticlist.h"
8 #include "courierauthsasl.h"
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #if HAVE_UNISTD_H
13 #include <unistd.h>
14 #endif
15 #include <fcntl.h>
16 #include <sys/types.h>
17 #include <sys/socket.h>
18 #include <sys/un.h>
19 #include <sys/time.h>
20 #if HAVE_SYS_SELECT_H
21 #include <sys/select.h>
22 #endif
23 #include <unistd.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <errno.h>
27 #include "authdaemonrc.h"
28 #include "numlib/numlib.h"
29
30 static int TIMEOUT_SOCK=10,
31 TIMEOUT_WRITE=10,
32 TIMEOUT_READ=30;
33
auth_meta_init_default_envvar(char ** p,size_t * i,const char * n)34 static int auth_meta_init_default_envvar(char **p, size_t *i,
35 const char *n)
36 {
37 const char *v=getenv(n);
38
39 if (!v)
40 return 0;
41
42 if ((p[*i]=malloc(strlen(v)+strlen(n)+2)) == 0)
43 {
44 return -1;
45 }
46
47 strcat(strcat(strcpy(p[*i], n), "="), v);
48 ++*i;
49 return 0;
50 }
51
auth_meta_init_default()52 struct auth_meta *auth_meta_init_default()
53 {
54 struct auth_meta *p=malloc(sizeof(struct auth_meta));
55 size_t i;
56
57 if (!p)
58 return 0;
59
60 if ((p->envvars=malloc(sizeof(char *)*2)) == 0)
61 {
62 free(p);
63 return 0;
64 }
65
66 i=0;
67
68 if (auth_meta_init_default_envvar(p->envvars, &i, "TCPREMOTEIP"))
69 {
70 while (i)
71 {
72 free(p->envvars[--i]);
73 }
74 free(p->envvars);
75 free(p);
76 return 0;
77 }
78
79 p->envvars[i]=0;
80 return p;
81 }
82
auth_meta_destroy_default(struct auth_meta * ptr)83 void auth_meta_destroy_default(struct auth_meta *ptr)
84 {
85 if (ptr->envvars)
86 {
87 size_t i;
88
89 for (i=0; ptr->envvars[i]; ++i)
90 free(ptr->envvars[i]);
91
92 free(ptr->envvars);
93 }
94 free(ptr);
95 }
96
s_connect(int sockfd,const struct sockaddr * addr,size_t addr_s,time_t connect_timeout)97 static int s_connect(int sockfd,
98 const struct sockaddr *addr,
99 size_t addr_s,
100 time_t connect_timeout)
101 {
102 fd_set fdr;
103 struct timeval tv;
104 int rc;
105
106 #ifdef SOL_KEEPALIVE
107 setsockopt(sockfd, SOL_SOCKET, SOL_KEEPALIVE,
108 (const char *)&dummy, sizeof(dummy));
109 #endif
110
111 #ifdef SOL_LINGER
112 {
113 struct linger l;
114
115 l.l_onoff=0;
116 l.l_linger=0;
117
118 setsockopt(sockfd, SOL_SOCKET, SOL_LINGER,
119 (const char *)&l, sizeof(l));
120 }
121 #endif
122
123 /*
124 ** If configuration says to use the kernel's timeout settings,
125 ** just call connect, and be done with it.
126 */
127
128 if (connect_timeout == 0)
129 return ( connect(sockfd, addr, addr_s));
130
131 /* Asynchronous connect with timeout. */
132
133 if (fcntl(sockfd, F_SETFL, O_NONBLOCK) < 0) return (-1);
134
135 if ( connect(sockfd, addr, addr_s) == 0)
136 {
137 /* That was easy, we're done. */
138
139 if (fcntl(sockfd, F_SETFL, 0) < 0) return (-1);
140 return (0);
141 }
142
143 if (errno != EINPROGRESS)
144 return -1;
145
146 /* Wait for the connection to go through, until the timeout expires */
147
148 FD_ZERO(&fdr);
149 FD_SET(sockfd, &fdr);
150 tv.tv_sec=connect_timeout;
151 tv.tv_usec=0;
152
153 rc=select(sockfd+1, 0, &fdr, 0, &tv);
154 if (rc < 0) return (-1);
155
156 if (!FD_ISSET(sockfd, &fdr))
157 {
158 errno=ETIMEDOUT;
159 return (-1);
160 }
161
162 {
163 int gserr;
164 socklen_t gslen = sizeof(gserr);
165
166 if (getsockopt(sockfd, SOL_SOCKET,
167 SO_ERROR,
168 (char *)&gserr, &gslen)==0)
169 {
170 if (gserr == 0)
171 return 0;
172
173 errno=gserr;
174 }
175 }
176 return (-1);
177 }
178
opensock()179 static int opensock()
180 {
181 int s=socket(PF_UNIX, SOCK_STREAM, 0);
182 struct sockaddr_un skun;
183
184 skun.sun_family=AF_UNIX;
185 strcpy(skun.sun_path, AUTHDAEMONSOCK);
186
187 if (s < 0)
188 {
189 perror("CRIT: authdaemon: socket() failed");
190 return (-1);
191 }
192
193 {
194 const char *p=getenv("TIMEOUT_SOCK");
195 int n=atoi(p ? p:"0");
196
197 if (n > 0)
198 TIMEOUT_SOCK=n;
199 }
200
201 {
202 const char *p=getenv("TIMEOUT_READ");
203 int n=atoi(p ? p:"0");
204
205 if (n > 0)
206 TIMEOUT_READ=n;
207 }
208
209 {
210 const char *p=getenv("TIMEOUT_WRITE");
211 int n=atoi(p ? p:"0");
212
213 if (n > 0)
214 TIMEOUT_WRITE=n;
215 }
216
217 if (s_connect(s, (const struct sockaddr *)&skun, sizeof(skun),
218 TIMEOUT_SOCK))
219 {
220 perror("ERR: authdaemon: s_connect() failed");
221 if (errno == ETIMEDOUT || errno == ECONNREFUSED)
222 fprintf(stderr, "ERR: [Hint: perhaps authdaemond is not running?]\n");
223 close(s);
224 return (-1);
225 }
226 return (s);
227 }
228
writeauth(int fd,const char * p,unsigned pl)229 static int writeauth(int fd, const char *p, unsigned pl)
230 {
231 fd_set fds;
232 struct timeval tv;
233
234 while (pl)
235 {
236 int n;
237
238 FD_ZERO(&fds);
239 FD_SET(fd, &fds);
240 tv.tv_sec=TIMEOUT_WRITE;
241 tv.tv_usec=0;
242 if (select(fd+1, 0, &fds, 0, &tv) <= 0 || !FD_ISSET(fd, &fds))
243 return (-1);
244 n=write(fd, p, pl);
245 if (n <= 0) return (-1);
246 p += n;
247 pl -= n;
248 }
249 return (0);
250 }
251
readauth(int fd,char * p,unsigned pl,const char * term)252 static void readauth(int fd, char *p, unsigned pl, const char *term)
253 {
254 time_t end_time, curtime;
255 unsigned len = 0, tlen = strlen(term);
256
257 --pl;
258
259 time(&end_time);
260 end_time += TIMEOUT_READ;
261
262 while (pl)
263 {
264 int n;
265 fd_set fds;
266 struct timeval tv;
267
268 time(&curtime);
269 if (curtime >= end_time)
270 break;
271
272 FD_ZERO(&fds);
273 FD_SET(fd, &fds);
274 tv.tv_sec=end_time - curtime;
275 tv.tv_usec=0;
276 if (select(fd+1, &fds, 0, 0, &tv) <= 0 || !FD_ISSET(fd, &fds))
277 break;
278
279 n=read(fd, p, pl);
280 if (n <= 0)
281 break;
282 p += n;
283 pl -= n;
284 /* end-of-message detection for authpipe */
285 len += n;
286 if (len >= tlen && strncmp(p-tlen, term, tlen) == 0)
287 break;
288 else if (len == 5 && strncmp(p-5, "FAIL\n", 5) == 0)
289 break;
290 }
291 *p=0;
292 }
293
_authdaemondopasswd(int wrfd,int rdfd,char * buffer,int bufsiz)294 int _authdaemondopasswd(int wrfd, int rdfd, char *buffer, int bufsiz)
295 {
296 if (writeauth(wrfd, buffer, strlen(buffer)))
297 return 1;
298
299 readauth(rdfd, buffer, bufsiz, "\n");
300
301 if (strcmp(buffer, "OK\n"))
302 {
303 errno=EPERM;
304 return -1;
305 }
306 return 0;
307 }
308
authdaemondopasswd(char * buffer,int bufsiz)309 int authdaemondopasswd(char *buffer, int bufsiz)
310 {
311 int s=opensock();
312 int rc;
313
314 if (s < 0)
315 return (1);
316 rc = _authdaemondopasswd(s, s, buffer, bufsiz);
317 close(s);
318 return rc;
319 }
320
_authdaemondo(int wrfd,int rdfd,const char * authreq,int (* func)(struct authinfo *,void *),void * arg)321 int _authdaemondo(int wrfd, int rdfd, const char *authreq,
322 int (*func)(struct authinfo *, void *), void *arg)
323 {
324 char buf[BUFSIZ];
325 char *p, *q, *r;
326 struct authinfo a;
327 uid_t u;
328
329 if (writeauth(wrfd, authreq, strlen(authreq)))
330 {
331 return (1);
332 }
333
334 readauth(rdfd, buf, sizeof(buf), "\n.\n");
335 memset(&a, 0, sizeof(a));
336 a.homedir="";
337 p=buf;
338 while (*p)
339 {
340 for (q=p; *q; q++)
341 if (*q == '\n')
342 {
343 *q++=0;
344 break;
345 }
346 if (strcmp(p, ".") == 0)
347 {
348 return ( (*func)(&a, arg));
349 }
350 if (strcmp(p, "FAIL") == 0)
351 {
352 errno=EPERM;
353 return (-1);
354 }
355 r=strchr(p, '=');
356 if (!r)
357 {
358 p=q;
359 continue;
360 }
361 *r++=0;
362
363 if (strcmp(p, "USERNAME") == 0)
364 a.sysusername=r;
365 else if (strcmp(p, "UID") == 0)
366 {
367 u=atol(r);
368 a.sysuserid= &u;
369 }
370 else if (strcmp(p, "GID") == 0)
371 {
372 a.sysgroupid=atol(r);
373 }
374 else if (strcmp(p, "HOME") == 0)
375 {
376 a.homedir=r;
377 }
378 else if (strcmp(p, "ADDRESS") == 0)
379 {
380 a.address=r;
381 }
382 else if (strcmp(p, "NAME") == 0)
383 {
384 a.fullname=r;
385 }
386 else if (strcmp(p, "MAILDIR") == 0)
387 {
388 a.maildir=r;
389 }
390 else if (strcmp(p, "QUOTA") == 0)
391 {
392 a.quota=r;
393 }
394 else if (strcmp(p, "PASSWD") == 0)
395 {
396 a.passwd=r;
397 }
398 else if (strcmp(p, "PASSWD2") == 0)
399 {
400 a.clearpasswd=r;
401 }
402 else if (strcmp(p, "OPTIONS") == 0)
403 {
404 a.options=r;
405 }
406 p=q;
407 }
408 errno=EIO;
409 return (1);
410 }
411
request_with_meta_create(struct auth_meta * meta,const char * authreq,void (* cb)(const char *,size_t,void *),void * ptr)412 static int request_with_meta_create(struct auth_meta *meta,
413 const char *authreq,
414 void (*cb)(const char *, size_t,
415 void *),
416 void *ptr)
417 {
418 if (meta->envvars)
419 {
420 for (size_t i=0; meta->envvars[i]; ++i)
421 {
422 const char *p=meta->envvars[i];
423 const char *q=p;
424
425 while (*q)
426 {
427 if (*q < ' ')
428 return -1;
429 ++q;
430 }
431 (*cb)(p, q-p, ptr);
432 (*cb)("\n", 1, ptr);
433 }
434 }
435
436 (*cb)(authreq, strlen(authreq)+1, ptr);
437 return 0;
438 }
439
count_request_with_meta(const char * ignored,size_t n,void * ptr)440 static void count_request_with_meta(const char *ignored, size_t n,
441 void *ptr)
442 {
443 *(size_t *)ptr += n;
444 }
445
save_request_with_meta(const char * chunk,size_t n,void * ptr)446 static void save_request_with_meta(const char *chunk, size_t n,
447 void *ptr)
448 {
449 char **q=(char **)ptr;
450
451 memcpy(*q, chunk, n);
452
453 *q += n;
454 }
455
request_with_meta(struct auth_meta * meta,const char * authreq)456 static char *request_with_meta(struct auth_meta *meta,
457 const char *authreq)
458 {
459 size_t cnt=0;
460 char *ptr, *q;
461
462 if (request_with_meta_create(meta, authreq, count_request_with_meta,
463 &cnt) < 0)
464 {
465 errno=EINVAL;
466 return 0;
467 }
468
469 ptr=malloc(cnt);
470
471 if (!ptr)
472 return 0;
473
474 q=ptr;
475
476 request_with_meta_create(meta, authreq, save_request_with_meta, &q);
477 return ptr;
478 }
479
do_authdaemondo_meta(const char * authreq,int (* func)(struct authinfo *,void *),void * arg)480 static int do_authdaemondo_meta(const char *authreq,
481 int (*func)(struct authinfo *, void *),
482 void *arg)
483 {
484 int s=opensock();
485 int rc;
486
487 if (s < 0)
488 {
489 return (1);
490 }
491 rc = _authdaemondo(s, s, authreq, func, arg);
492 close(s);
493 return rc;
494 }
495
authdaemondo_meta(struct auth_meta * meta,const char * authreq,int (* func)(struct authinfo *,void *),void * arg)496 int authdaemondo_meta(struct auth_meta *meta,
497 const char *authreq,
498 int (*func)(struct authinfo *, void *),
499 void *arg)
500 {
501 char *buf;
502 int rc;
503 struct auth_meta *default_meta=0;
504
505 if (!meta)
506 {
507 default_meta=auth_meta_init_default();
508
509 if (!default_meta)
510 return 1;
511
512 meta=default_meta;
513 }
514
515 buf=request_with_meta(meta, authreq);
516
517 if (default_meta)
518 auth_meta_destroy_default(default_meta);
519
520 if (!buf)
521 return 1;
522
523 rc=do_authdaemondo_meta(buf, func, arg);
524
525 free(buf);
526
527 return rc;
528 }
529
auth_daemon_cleanup()530 void auth_daemon_cleanup()
531 {
532 }
533
534 struct enum_getch {
535 char buffer[BUFSIZ];
536 char *buf_ptr;
537 size_t buf_left;
538 };
539
540 #define getauthc(fd,eg) ((eg)->buf_left-- ? \
541 (unsigned char)*((eg)->buf_ptr)++:\
542 fillgetauthc((fd),(eg)))
543
fillgetauthc(int fd,struct enum_getch * eg)544 static int fillgetauthc(int fd, struct enum_getch *eg)
545 {
546 time_t end_time, curtime;
547
548 time(&end_time);
549 end_time += 60;
550
551 for (;;)
552 {
553 int n;
554 fd_set fds;
555 struct timeval tv;
556
557 time(&curtime);
558 if (curtime >= end_time)
559 break;
560
561 FD_ZERO(&fds);
562 FD_SET(fd, &fds);
563 tv.tv_sec=end_time - curtime;
564 tv.tv_usec=0;
565 if (select(fd+1, &fds, 0, 0, &tv) <= 0 || !FD_ISSET(fd, &fds))
566 break;
567
568 n=read(fd, eg->buffer, sizeof(eg->buffer));
569 if (n <= 0)
570 break;
571
572 eg->buf_ptr=eg->buffer;
573 eg->buf_left=n;
574
575 --eg->buf_left;
576 return (unsigned char)*(eg->buf_ptr)++;
577 }
578 return EOF;
579 }
580
readline(int fd,struct enum_getch * eg,char * buf,size_t bufsize)581 static int readline(int fd, struct enum_getch *eg,
582 char *buf,
583 size_t bufsize)
584 {
585 if (bufsize == 0)
586 return EOF;
587
588 while (--bufsize)
589 {
590 int ch=getauthc(fd, eg);
591
592 if (ch == EOF)
593 return -1;
594 if (ch == '\n')
595 break;
596
597 *buf++=ch;
598 }
599 *buf=0;
600 return 0;
601 }
602
_auth_enumerate(int wrfd,int rdfd,void (* cb_func)(const char * name,uid_t uid,gid_t gid,const char * homedir,const char * maildir,const char * options,void * void_arg),void * void_arg)603 int _auth_enumerate(int wrfd, int rdfd,
604 void(*cb_func)(const char *name,
605 uid_t uid,
606 gid_t gid,
607 const char *homedir,
608 const char *maildir,
609 const char *options,
610 void *void_arg),
611 void *void_arg)
612 {
613 static char cmd[]="ENUMERATE\n";
614 struct enum_getch eg;
615 char linebuf[BUFSIZ];
616
617 if (writeauth(wrfd, cmd, sizeof(cmd)-1))
618 {
619 return 1;
620 }
621
622 eg.buf_left=0;
623
624 while (readline(rdfd, &eg, linebuf, sizeof(linebuf)) == 0)
625 {
626 char *p;
627 const char *name;
628 uid_t uid;
629 gid_t gid;
630 const char *homedir;
631 const char *maildir;
632 const char *options;
633
634 if (strcmp(linebuf, ".") == 0)
635 {
636 (*cb_func)(NULL, 0, 0, NULL, NULL, NULL, void_arg);
637 return 0;
638 }
639
640 p=strchr(linebuf, '#');
641 if (p) *p=0;
642
643 p=strchr(linebuf, '\t');
644
645 if (p)
646 {
647 name=linebuf;
648 *p++=0;
649
650 uid=libmail_atouid_t(p);
651 p=strchr(p, '\t');
652 if (uid && p)
653 {
654 *p++=0;
655 gid=libmail_atogid_t(p);
656 p=strchr(p, '\t');
657 if (gid && p)
658 {
659 *p++=0;
660 homedir=p;
661 p=strchr(p, '\t');
662 maildir=NULL;
663 options=NULL;
664
665 if (p)
666 {
667 *p++=0;
668 maildir=p;
669 p=strchr(p, '\t');
670
671 if (p)
672 {
673 *p++=0;
674 options=p;
675 p=strchr(p, '\t');
676 if (p) *p=0;
677 }
678 }
679
680
681 (*cb_func)(name, uid, gid, homedir,
682 maildir, options, void_arg);
683 }
684 }
685 }
686 }
687 return 1;
688 }
689
auth_enumerate(void (* cb_func)(const char * name,uid_t uid,gid_t gid,const char * homedir,const char * maildir,const char * options,void * void_arg),void * void_arg)690 void auth_enumerate( void(*cb_func)(const char *name,
691 uid_t uid,
692 gid_t gid,
693 const char *homedir,
694 const char *maildir,
695 const char *options,
696 void *void_arg),
697 void *void_arg)
698 {
699 int s=opensock();
700
701 if (s < 0)
702 return;
703
704 _auth_enumerate(s, s, cb_func, void_arg);
705
706 close(s);
707 }
708