1 #ifndef LINT
2 static char *rcsid="$Id: clnt_unixd.c,v 1.7 2001/07/20 07:35:54 crosser Exp $";
3 #endif
4 
5 /*
6 	$Log: clnt_unixd.c,v $
7 	Revision 1.7  2001/07/20 07:35:54  crosser
8 	more tuning of AF_UNIX address size, now works on FreeBSD
9 
10 	Revision 1.6  2001/07/20 05:48:59  crosser
11 	address bug with AF_UNIX address size
12 	fix permissions of unix datagram socket (on Linux, honors umask)
13 
14 	Revision 1.5  1999/10/03 21:18:03  crosser
15 	First (probably) working version with new run time config parser.
16 	Also added listenq parameter (backlog size for listen()) and
17 	renamed wtest to whoson (and with man page).  Release 2.00beta1.
18 
19 	Revision 1.4  1999/08/19 17:22:15  crosser
20 	Move to new config scheme (does not work yet)
21 
22 	Revision 1.3  1999/07/27 17:30:05  crosser
23 	fix names
24 
25 	Revision 1.2  1999/01/30 16:44:17  crosser
26 	add unlink()
27 
28 	Revision 1.1  1999/01/30 15:43:40  crosser
29 	Initial revision
30 
31 */
32 
33 /*
34 	WHAT IS IT:
35 		Implementation of experimental "whoson" protocol
36 	AUTHOR:
37 		Eugene G. Crosser <crosser@average.org>
38 	COPYRIGHT:
39 		Public domain
40 */
41 
42 #include "config.h"
43 
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <time.h>
47 #include <sys/time.h>
48 #include <sys/socket.h>
49 #include <netinet/in.h>
50 #include <arpa/inet.h>
51 #include <sys/un.h>
52 #include <netdb.h>
53 #ifdef HAVE_SYS_SELECT_H
54 #include <sys/select.h>
55 #endif
56 #include <unistd.h>
57 #include <errno.h>
58 #include <signal.h>
59 #include <setjmp.h>
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63 #include <ctype.h>
64 
65 #include "whoson.h"
66 #include "rtconfig.h"
67 #include "checkperm.h"
68 #include "clnt_common.h"
69 #include "report.h"
70 
71 #include "rtc_begin.h"
72 #include "clnt_unixd_cfg.h"
73 #include "rtc_middle.h"
74 #include "clnt_unixd_cfg.h"
75 #include "rtc_end.h"
76 
77 #define MAXREQL 1024
78 
79 #define INITTIMEOUT 100000
80 #define MAXTRIES 5
81 #define MAXREREADS 20
82 
wso_unixd_clnt_connect(void * priv,char * buf)83 int wso_unixd_clnt_connect(void *priv,char *buf)
84 {
85 	wso_clnt_unixd_cfg *rec=(wso_clnt_unixd_cfg *)(priv);
86 	struct sockaddr_un server,me,frominet;
87 	int fd;
88 	int len,slen;
89 	fd_set rfds,wfds,efds;
90 	struct timeval seltimer;
91 	unsigned long timeout;
92 	int tries,rereads,rc=0;
93 	char wbuf[MAXREQL];
94 	mode_t savemask;
95 
96 	memset((char *)&server,0,sizeof(server));
97 	server.sun_family = AF_UNIX;
98 	strncpy(server.sun_path,rec->port,sizeof(server.sun_path)-1);
99 	server.sun_path[sizeof(server.sun_path)-1]='\0';
100 	if ((fd=socket(AF_UNIX,SOCK_DGRAM,0)) < 0) {
101 		ERRLOG((LOG_ERR,"[WHOSON] socket: %m"))
102 		return -1;
103 	}
104 	/* This may sound stupid, but when using UNIX DGRAM socket, we
105 	   must explicitely bind() it.  "man 2 socket" says that a unique
106 	   address will be assigned automatically, but apparently this
107 	   ony works for INET sockets... */
108 	memset((char *)&me,0,sizeof(me));
109 	me.sun_family = AF_UNIX;
110 	if (tmpnam(me.sun_path) == NULL) {
111 		ERRLOG((LOG_ERR,"[WHOSON] cannot create temporary socket address: %m"))
112 		return -1;
113 	}
114 	savemask=umask(0);
115 	if (bind(fd,(struct sockaddr*)&me,sizeof(me)-sizeof(me.sun_path)+
116 						strlen(me.sun_path)+1) < 0) {
117 		(void)umask(savemask);
118 		ERRLOG((LOG_ERR,"[WHOSON] bind: %m"))
119 		return -1;
120 	}
121 	(void)umask(savemask);
122 
123 	strncpy(wbuf,buf,sizeof(wbuf)-1);
124 	wbuf[sizeof(wbuf)-1]='\0';
125 	timeout=rec->inittimeout;
126 	for (tries=0;tries<(rec->maxtries);tries++) {
127 		len=strlen(wbuf);
128 		if (sendto(fd,wbuf,len,0,(struct sockaddr *)&server,
129 			sizeof(server)-sizeof(server.sun_path)+
130 					strlen(server.sun_path)+1) != len) {
131 			ERRLOG((LOG_ERR,"[WHOSON] sendto: %m"))
132 			close(fd);
133 			(void)unlink(me.sun_path);
134 			return -1;
135 		}
136 
137 		rereads=0;
138 reread:
139 
140 DPRINT(("unixd waiting try=%d(%d max) timeout=%lu (init %u)\n",
141 			tries,rec->maxtries,timeout,rec->inittimeout))
142 
143 		seltimer.tv_sec=timeout/1000000L;
144 		seltimer.tv_usec=timeout%1000000L;
145 DPRINT(("seltimer.tv_sec=%lu, seltimer.tv_usec=%lu\n",
146 			(long)seltimer.tv_sec,
147 			(long)seltimer.tv_usec))
148 		FD_ZERO(&rfds);
149 		FD_ZERO(&wfds);
150 		FD_ZERO(&efds);
151 		FD_SET(fd,&rfds);
152 
153 		rc=select(fd+1,&rfds,&wfds,&efds,&seltimer);
154 		if (rc < 0) {
155 			ERRLOG((LOG_ERR,"[WHOSON] select: %m"))
156 			close(fd);
157 			(void)unlink(me.sun_path);
158 			return -1;
159 		} else if (rc > 0) {
160 			slen=sizeof(frominet);
161 			if ((len=recvfrom(fd,buf,MAXREQL-1,0,
162 					(struct sockaddr *) &frominet, &slen)) < 0) {
163 				ERRLOG((LOG_ERR,"[WHOSON] recvfrom: %m"))
164 				close(fd);
165 				(void)unlink(me.sun_path);
166 				return -1;
167 			}
168 			buf[len]='\0';
169 DPRINT(("recvfrom returned %d bytes: \"%s\"\n",len,buf))
170 			if (strcmp(frominet.sun_path,server.sun_path) == 0)
171 				break;
172 DPRINT(("did not pass address check: from %s, dest was %s\n",
173 				frominet.sun_path,server.sun_path))
174 			ERRLOG((LOG_ERR,"[WHOSON] ignore reply from from %s (dest was %s)",
175 					frominet.sun_path,server.sun_path))
176 			if (++rereads < MAXREREADS)
177 				goto reread;
178 			else
179 				sprintf(buf,"*Ignoring reply from %s, sent to %s\r\n\r\n",
180 					frominet.sun_path,server.sun_path);
181 		}
182 
183 		timeout *= 2;
184 	}
185 
186 	if (rc == 0) {
187 		ERRLOG((LOG_ERR,"[WHOSON] unixd excessive retries\n"))
188 		close(fd);
189 		(void)unlink(me.sun_path);
190 		return -1;
191 	}
192 
193 	close(fd);
194 	(void)unlink(me.sun_path);
195 	return 0;
196 }
197