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