1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1985-2013 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                 Eclipse Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *          http://www.eclipse.org/org/documents/epl-v10.html           *
11 *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *               Glenn Fowler <glenn.s.fowler@gmail.com>                *
18 *                    David Korn <dgkorn@gmail.com>                     *
19 *                     Phong Vo <phongvo@gmail.com>                     *
20 *                                                                      *
21 ***********************************************************************/
22 #pragma prototyped
23 /*
24  * Glenn Fowler
25  * AT&T Research
26  *
27  * open canonicalized path with checks for pathdev() files
28  * canon==0 to disable canonicalization
29  */
30 
31 #include <ast.h>
32 #include <error.h>
33 #if _sys_socket
34 #include <sys/socket.h>
35 #endif
36 #if _hdr_netdb
37 #include <netdb.h>
38 #endif
39 #if _hdr_netinet_in
40 #include <netinet/in.h>
41 #endif
42 
43 #ifndef O_XATTR
44 #define O_XATTR		0
45 #endif
46 
47 #if !_lib_getaddrinfo
48 
49 #if !defined(htons) && !_lib_htons
50 #define htons(x)		(x)
51 #endif
52 #if !defined(htonl) && !_lib_htonl
53 #define htonl(x)		(x)
54 #endif
55 
56 #undef	EAI_SYSTEM
57 
58 #define EAI_SYSTEM		1
59 
60 #undef	addrinfo
61 #undef	getaddrinfo
62 #undef	freeaddrinfo
63 
64 #define addrinfo		local_addrinfo
65 #define getaddrinfo		local_getaddrinfo
66 #define freeaddrinfo		local_freeaddrinfo
67 
68 struct addrinfo
69 {
70         int			ai_flags;
71         int			ai_family;
72         int			ai_socktype;
73         int			ai_protocol;
74         socklen_t		ai_addrlen;
75         struct sockaddr*	ai_addr;
76         struct addrinfo*	ai_next;
77 };
78 
79 static int
getaddrinfo(const char * node,const char * service,const struct addrinfo * hint,struct addrinfo ** addr)80 getaddrinfo(const char* node, const char* service, const struct addrinfo* hint, struct addrinfo **addr)
81 {
82 	unsigned long	    	ip_addr = 0;
83 	unsigned short	    	ip_port = 0;
84 	struct addrinfo*	ap;
85 	struct hostent*		hp;
86 	struct sockaddr_in*	ip;
87 	char*			prot;
88 	long			n;
89 
90 	if (!(hp = gethostbyname(node)) || hp->h_addrtype != AF_INET || hp->h_length > sizeof(struct in_addr))
91 	{
92 		errno = EADDRNOTAVAIL;
93 		return EAI_SYSTEM;
94 	}
95 	ip_addr = (unsigned long)((struct in_addr*)hp->h_addr)->s_addr;
96 	if ((n = strtol(service, &prot, 10)) > 0 && n <= USHRT_MAX && !*prot)
97 		ip_port = htons((unsigned short)n);
98 	else
99 	{
100 		struct servent*	sp;
101 		const char*	protocol = 0;
102 
103 		if (hint)
104 			switch (hint->ai_socktype)
105 			{
106 			case SOCK_STREAM:
107 				switch (hint->ai_protocol)
108 				{
109 				case 0:
110 					protocol = "tcp";
111 					break;
112 #ifdef IPPROTO_SCTP
113 				case IPPROTO_SCTP:
114 					protocol = "sctp";
115 					break;
116 #endif
117 				}
118 				break;
119 			case SOCK_DGRAM:
120 				protocol = "udp";
121 				break;
122 			}
123 		if (!protocol)
124 		{
125 			errno =  EPROTONOSUPPORT;
126 			return 1;
127 		}
128 		if (sp = getservbyname(service, protocol))
129 			ip_port = sp->s_port;
130 	}
131 	if (!ip_port)
132 	{
133 		errno = EADDRNOTAVAIL;
134 		return EAI_SYSTEM;
135 	}
136 	if (!(ap = newof(0, struct addrinfo, 1, sizeof(struct sockaddr_in))))
137 		return EAI_SYSTEM;
138 	if (hint)
139 		*ap = *hint;
140 	ap->ai_family = hp->h_addrtype;
141 	ap->ai_addrlen 	= sizeof(struct sockaddr_in);
142 	ap->ai_addr = (struct sockaddr *)(ap+1);
143 	ip = (struct sockaddr_in *)ap->ai_addr;
144 	ip->sin_family = AF_INET;
145 	ip->sin_port = ip_port;
146 	ip->sin_addr.s_addr = ip_addr;
147 	*addr = ap;
148 	return 0;
149 }
150 
151 static void
freeaddrinfo(struct addrinfo * ap)152 freeaddrinfo(struct addrinfo* ap)
153 {
154 	if (ap)
155 		free(ap);
156 }
157 
158 #endif
159 
160 int
pathopen(int dfd,const char * path,char * canon,size_t size,int flags,int oflags,mode_t mode)161 pathopen(int dfd, const char* path, char* canon, size_t size, int flags, int oflags, mode_t mode)
162 {
163 	char*		b;
164 	Pathdev_t	dev;
165 	int		f;
166 	int		fd;
167 	int		oerrno;
168 
169 	b = canon ? canon : (char*)path;
170 	if (!pathdev(dfd, path, canon, size, flags, &dev))
171 		return 0;
172 	if (dev.path.offset)
173 	{
174 		oerrno = errno;
175 		oflags |= dev.oflags;
176 		if (dev.fd >= 0)
177 		{
178 			if (dev.pid > 0 && dev.pid != getpid())
179 			{
180 				if (flags & PATH_DEV)
181 					return access(b, F_OK) ? -1 : 1;
182 				return openat(AT_FDCWD, b, oflags|O_INTERCEPT, mode);
183 			}
184 
185 			/* check for auxilliary directory fd which must be closed before returning */
186 
187 			if (dev.oflags & O_INTERCEPT)
188 			{
189 				if (!*(b += dev.path.offset))
190 					b = ".";
191 				if (flags & PATH_DEV)
192 					f = faccessat(dev.fd, b, F_OK, 0) ? -1 : 1;
193 				else
194 					f = openat(dev.fd, b, oflags, mode);
195 				close(dev.fd);
196 				return f;
197 			}
198 
199 			/* prevent getting here again with this path */
200 
201 			oflags |= O_INTERCEPT;
202 
203 			/* dev.fd must be valid */
204 
205 			if ((f = fcntl(dev.fd, F_GETFL, 0)) < 0)
206 				return -1;
207 			if (flags & PATH_DEV)
208 			{
209 				if (!b[dev.path.offset])
210 					return 1;
211 				return faccessat(dev.fd, b + dev.path.offset, F_OK, 0) < 0 ? -1 : 1;
212 			}
213 
214 			/* a trailing path component means dev.fd must be a directory -- easy */
215 
216 			if (b[dev.path.offset])
217 				return openat(dev.fd, b + dev.path.offset, oflags, mode);
218 
219 			/* the path boils down to just dev.fd -- F_GETFL must match oflags */
220 
221 			if (!(f & O_RDWR) && (f & O_ACCMODE) != (oflags & O_ACCMODE))
222 			{
223 				errno = EACCES;
224 				return -1;
225 			}
226 
227 			/* preserve open() semantics if possible */
228 
229 			if (oflags & (O_DIRECTORY|O_SEARCH|O_XATTR))
230 				return openat(dev.fd, ".", oflags|O_INTERCEPT, mode);
231 #if O_XATTR
232 			if ((f = openat(dev.fd, ".", O_INTERCEPT|O_RDONLY|O_XATTR)) >= 0)
233 			{
234 				fd = openat(f, "..", oflags|O_INTERCEPT, mode);
235 				close(f);
236 				return fd;
237 			}
238 #endif
239 
240 			/* see if the filesystem groks .../[<pid>]/<fd>/... paths */
241 
242 			if ((!(oflags & O_CREAT) || !access(b, F_OK)) && (fd = openat(AT_FDCWD, b, oflags|O_INTERCEPT, mode)) >= 0)
243 				return fd;
244 
245 			/* stuck with dup semantics -- the best we can do at this point */
246 
247 			if ((fd = fcntl(dev.fd, (oflags & O_CLOEXEC) ? F_DUPFD_CLOEXEC : F_DUPFD, 0)) >= 0)
248 				goto adjust;
249 			return -1;
250 		}
251 		else if (dev.fd == AT_FDCWD)
252 			return (flags & PATH_DEV) ? 1 : -1;
253 		else if (dev.prot.offset)
254 		{
255 			int			server = (oflags&(O_CREAT|O_NOCTTY)) == (O_CREAT|O_NOCTTY);
256 			int			prot;
257 			int			type;
258 			char*			p;
259 			char*			q;
260 			struct addrinfo		hint;
261 			struct addrinfo*	addr;
262 			struct addrinfo*	a;
263 
264 			memset(&hint, 0, sizeof(hint));
265 			hint.ai_family = PF_UNSPEC;
266 			p = b + dev.prot.offset;
267 			switch (p[0])
268 			{
269 #ifdef IPPROTO_SCTP
270 			case 's':
271 				if (dev.prot.size != 4 || p[1] != 'c' || p[2] != 't' || p[3] != 'p' || p[4] != '/')
272 				{
273 					errno = ENOTDIR;
274 					return -1;
275 				}
276 				hint.ai_socktype = SOCK_STREAM;
277 				hint.ai_protocol = IPPROTO_SCTP;
278 				break;
279 #endif
280 			case 't':
281 				if (dev.prot.size != 3 || p[1] != 'c' || p[2] != 'p' || p[3] != '/')
282 				{
283 					errno = ENOTDIR;
284 					return -1;
285 				}
286 				hint.ai_socktype = SOCK_STREAM;
287 				break;
288 			case 'u':
289 				if (dev.prot.size!=3 || p[1]!='d' || p[2]!='p' || p[3]!='/')
290 				{
291 					errno = ENOTDIR;
292 					return -1;
293 				}
294 				hint.ai_socktype = SOCK_DGRAM;
295 				break;
296 			default:
297 				errno = ENOTDIR;
298 				return -1;
299 			}
300 			if (!dev.host.offset)
301 			{
302 				if (flags & PATH_DEV)
303 					return 1;
304 				errno = ENOENT;
305 				return -1;
306 			}
307 			if (!dev.port.offset)
308 				dev.port.size = 0;
309 			p = fmtbuf(dev.host.size + dev.port.size + 2);
310 			memcpy(p, b + dev.host.offset, dev.host.size);
311 			q = p + dev.host.size;
312 			*q++ = 0;
313 			if (dev.port.size)
314 			{
315 				memcpy(q, b + dev.port.offset, dev.port.size);
316 				q[dev.port.size] = 0;
317 			}
318 			else
319 				q = 0;
320 			if (streq(p, "local"))
321 				p = "localhost";
322 			fd = getaddrinfo(p, q, &hint, &addr);
323 			if (fd)
324 			{
325 				if (fd != EAI_SYSTEM)
326 					errno = ENOTDIR;
327 				return -1;
328 			}
329 			if (flags & PATH_DEV)
330 			{
331 				fd = 1;
332 				goto done;
333 			}
334 			errno = 0;
335 			fd = -1;
336 			for (a = addr; a; a = a->ai_next)
337 			{
338 				/* some api's don't take the hint */
339 
340 				if (!(type = a->ai_socktype))
341 					type = hint.ai_socktype;
342 				if (oflags & O_CLOEXEC)
343 					type |= SOCK_CLOEXEC;
344 				if (!(prot = a->ai_protocol))
345 					prot = hint.ai_protocol;
346 				if ((fd = socket(a->ai_family, type, prot)) >= 0)
347 				{
348 					if (server && !bind(fd, a->ai_addr, a->ai_addrlen) && !listen(fd, 5) || !server && !connect(fd, a->ai_addr, a->ai_addrlen))
349 						goto done;
350 					close(fd);
351 					fd = -1;
352 				}
353 			}
354 		done:
355 			freeaddrinfo(addr);
356 			if (fd < 0)
357 				return -1;
358 		adjust:
359 			if (dev.oflags && (f = fcntl(fd, F_GETFL, 0)) >= 0 && (dev.oflags & f) != dev.oflags && fcntl(fd, F_SETFL, f|dev.oflags) < 0)
360 			{
361 				close(fd);
362 				errno = EINVAL;
363 				return -1;
364 			}
365 			errno = oerrno;
366 			return fd;
367 		}
368 		else
369 			b += dev.path.offset;
370 	}
371 	if (flags & PATH_DEV)
372 	{
373 		errno = ENODEV;
374 		return -1;
375 	}
376 	return openat(dfd, b, oflags|dev.oflags|O_INTERCEPT, mode);
377 }
378