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