AF_NETBEUI is not defined in some FreeBSD/MACOSX versions. Fixed.
[vde.git] / vde-2 / src / lib / libvdeplug.c
blob72ca7d836662dfb3248c3c37c52f3585aa1d5994
1 /*
2 * libvdeplug - A library to connect to a VDE Switch.
3 * Copyright (C) 2006 Renzo Davoli, University of Bologna
5 * This library is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation version 2.1 of the License, or (at
8 * your option) any later version.
10 * This library is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
13 * General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include <errno.h>
21 #include <sys/socket.h>
22 #include <sys/un.h>
23 #include <stdint.h>
24 #include <stdio.h>
25 #include <limits.h>
26 #include <stdlib.h>
27 #include <pwd.h>
28 #include <grp.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <unistd.h>
32 #include <string.h>
34 #include <config.h>
35 #include <vde.h>
36 #include <vdecommon.h>
38 #include <libvdeplug.h>
40 #ifdef USE_IPN
41 #ifndef AF_IPN
42 #define AF_IPN 34 /* IPN sockets */
43 #define PF_IPN AF_IPN
44 #endif
45 #ifndef AF_NETBEUI
46 #ifdef PF_NETBEUI
47 #define AF_NETBEUI PF_NETBEUI
48 #else
49 #define AF_NETBEUI 13
50 #endif
51 #endif
52 #define AF_IPN_STOLEN AF_NETBEUI /* IPN temporary sockets */
53 #define PF_IPN_STOLEN AF_IPN_STOLEN
54 #define IPN_ANY 0
56 #define IPN_SO_PORT 0
57 #define IPN_SO_DESCR 1
58 #endif
60 /* Fallback names for the control socket, NULL-terminated array of absolute
61 * filenames. */
62 char *fallback_sockname[] = {
63 "/var/run/vde.ctl/ctl",
64 "/tmp/vde.ctl/ctl",
65 "/tmp/vde.ctl",
66 NULL,
69 /* Fallback directories for the data socket, NULL-terminated array of absolute
70 * directory names, with no trailing /. */
71 const char *fallback_dirname[] = {
72 "/var/run",
73 "/var/tmp",
74 "/tmp",
75 NULL,
78 struct vdeconn {
79 int fdctl;
80 int fddata;
81 struct sockaddr_un inpath;
84 #define SWITCH_MAGIC 0xfeedface
85 #define MAXDESCR 128
87 enum request_type { REQ_NEW_CONTROL, REQ_NEW_PORT0 };
89 struct request_v3 {
90 uint32_t magic;
91 uint32_t version;
92 enum request_type type;
93 struct sockaddr_un sock;
94 char description[MAXDESCR];
95 } __attribute__((packed));
97 VDECONN *vde_open_real(char *given_sockname, char *descr,int interface_version,
98 struct vde_open_args *open_args)
100 struct vdeconn *conn;
101 struct passwd *callerpwd;
102 struct request_v3 req;
103 int pid = getpid();
104 static struct sockaddr_un sockun;
105 static struct sockaddr_un dataout;
106 int port=0;
107 char *group=NULL;
108 int sockno=0;
109 int res;
110 mode_t mode=0700;
111 char real_sockname[PATH_MAX];
112 char *sockname = real_sockname;
114 if (open_args != NULL) {
115 if (interface_version == 1) {
116 port=open_args->port;
117 group=open_args->group;
118 mode=open_args->mode;
120 else {
121 errno=EINVAL;
122 return NULL;
126 if ((conn=calloc(1,sizeof(struct vdeconn)))==NULL)
128 errno=ENOMEM;
129 return NULL;
131 //get the login name
132 callerpwd=getpwuid(getuid());
133 req.type = REQ_NEW_CONTROL;
134 if (given_sockname == NULL || *given_sockname == '\0')
135 given_sockname = NULL;
136 else {
137 char *split;
138 if(given_sockname[strlen(given_sockname)-1] == ']' && (split=rindex(given_sockname,'[')) != NULL) {
139 *split=0;
140 split++;
141 port=atoi(split);
142 if (port == 0)
143 req.type = REQ_NEW_PORT0;
144 if (*given_sockname==0)
145 given_sockname = NULL;
149 /* Canonicalize the sockname: we need to send an absolute pathname to the
150 * switch (we don't know its cwd) for the data socket. Appending
151 * given_sockname to getcwd() would be enough, but we could end up with a
152 * name longer than PATH_MAX that couldn't be used as sun_path. */
153 if (given_sockname && vde_realpath(given_sockname, real_sockname) == NULL)
155 free(conn);
156 return NULL;
159 #ifdef USE_IPN
160 if((conn->fddata = socket(AF_IPN,SOCK_RAW,IPN_ANY)) >= 0) {
161 /* IPN service exists */
162 sockun.sun_family = AF_IPN;
164 if((conn->fddata = socket(AF_IPN_STOLEN,SOCK_RAW,IPN_ANY)) >= 0) {
165 /* IPN_STOLEN service exists */
166 sockun.sun_family = AF_IPN_STOLEN;
168 if (conn->fddata >= 0) {
169 if (port != 0 || req.type == REQ_NEW_PORT0)
170 setsockopt(conn->fddata,0,IPN_SO_PORT,&port,sizeof(port));
171 /* If we're given a sockname, just try it */
172 if (given_sockname)
174 snprintf(sockun.sun_path, sizeof(sockun.sun_path), "%s", sockname);
175 res = connect(conn->fddata, (struct sockaddr *) &sockun, sizeof(sockun));
177 /* Else try all the fallback socknames, one by one */
178 else
180 int i;
181 for (i = 0, res = -1; fallback_sockname[i] && (res != 0); i++)
183 snprintf(sockun.sun_path, sizeof(sockun.sun_path), "%s", fallback_sockname[i]);
184 res = connect(conn->fddata, (struct sockaddr *) &sockun, sizeof(sockun));
188 /* If one of the connect succeeded, we're done */
189 if (res == 0)
191 snprintf(req.description,MAXDESCR,"%s user=%s PID=%d %s",
192 descr,(callerpwd != NULL)?callerpwd->pw_name:"??",
193 pid,getenv("SSH_CLIENT")?getenv("SSH_CLIENT"):"");
194 setsockopt(conn->fddata,0,IPN_SO_DESCR,req.description,
195 strlen(req.description+1));
196 *(conn->inpath.sun_path)=0; /*null string, do not delete "return path"*/
197 conn->fdctl=-1;
198 return conn;
201 #endif
202 if((conn->fdctl = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
203 free(conn);
204 return NULL;
206 if((conn->fddata = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0){
207 int err=errno;
208 close(conn->fdctl);
209 free(conn);
210 errno=err;
211 return NULL;
213 sockun.sun_family = AF_UNIX;
215 /* If we're given a sockname, just try it (remember: sockname is the
216 * canonicalized version of given_sockname - though we don't strictly need
217 * the canonicalized versiono here). sockname should be the name of a
218 * *directory* which contains the control socket, named ctl. Older
219 * versions of VDE used a socket instead of a directory (so an additional
220 * attempt with %s instead of %s/ctl could be made), but they should
221 * really not be used anymore. */
222 if (given_sockname)
224 snprintf(sockun.sun_path, sizeof(sockun.sun_path), "%s/ctl", sockname);
225 res = connect(conn->fdctl, (struct sockaddr *) &sockun, sizeof(sockun));
227 /* Else try all the fallback socknames, one by one */
228 else
230 int i;
231 for (i = 0, res = -1; fallback_sockname[i] && (res != 0); i++)
233 /* Remember sockname for the data socket directory */
234 sockname = fallback_sockname[i];
235 snprintf(sockun.sun_path, sizeof(sockun.sun_path), "%s", sockname);
236 res = connect(conn->fdctl, (struct sockaddr *) &sockun, sizeof(sockun));
240 if (res != 0)
242 int err = errno;
243 close(conn->fddata);
244 close(conn->fdctl);
245 free(conn);
246 errno = err;
247 return NULL;
250 req.magic=SWITCH_MAGIC;
251 req.version=3;
252 req.type=req.type+(port << 8);
253 req.sock.sun_family=AF_UNIX;
255 /* First choice, store the return socket from the switch in the control
256 * dir. We assume that given_sockname (hence sockname) is a directory.
257 * Should be a safe assumption unless someone modifies the previous group
258 * of connect() attempts (see the comments above for more information). */
259 memset(req.sock.sun_path, 0, sizeof(req.sock.sun_path));
262 /* Here sockname is the last successful one in the previous step. */
263 sprintf(req.sock.sun_path, "%s/.%05d-%05d", sockname, pid, sockno++);
264 res=bind(conn->fddata, (struct sockaddr *) &req.sock, sizeof (req.sock));
266 while (res < 0 && errno == EADDRINUSE);
268 /* It didn't work. So we cycle on the fallback directories until we find a
269 * suitable one (or the list ends). */
270 if (res < 0)
272 int i;
273 for (i = 0, res = -1; fallback_dirname[i] && (res != 0); i++)
275 memset(req.sock.sun_path, 0, sizeof(req.sock.sun_path));
278 sprintf(req.sock.sun_path, "%s/vde.%05d-%05d", fallback_dirname[i], pid, sockno++);
279 res = bind(conn->fddata, (struct sockaddr *) &req.sock, sizeof (req.sock));
281 while (res < 0 && errno == EADDRINUSE);
285 /* Nothing worked, so cleanup and return with an error. */
286 if (res < 0){
287 int err = errno;
288 close(conn->fddata);
289 close(conn->fdctl);
290 free(conn);
291 errno = err;
292 return NULL;
295 memcpy(&(conn->inpath),&req.sock,sizeof(req.sock));
296 if (group) {
297 struct group *gs;
298 gid_t gid;
299 if ((gs=getgrnam(group)) == NULL)
300 gid=atoi(group);
301 else
302 gid=gs->gr_gid;
303 chown(conn->inpath.sun_path,-1,gid);
305 chmod(conn->inpath.sun_path,mode);
307 snprintf(req.description,MAXDESCR,"%s user=%s PID=%d %s SOCK=%s",
308 descr,(callerpwd != NULL)?callerpwd->pw_name:"??",
309 pid,getenv("SSH_CLIENT")?getenv("SSH_CLIENT"):"",req.sock.sun_path);
311 if (send(conn->fdctl,&req,sizeof(req)-MAXDESCR+strlen(req.description),0) < 0) {
312 int err=errno;
313 close(conn->fddata);
314 close(conn->fdctl);
315 free(conn);
316 errno=err;
317 return NULL;
320 if (recv(conn->fdctl,&(dataout),sizeof(struct sockaddr_un),0)<0) {
321 int err=errno;
322 close(conn->fddata);
323 close(conn->fdctl);
324 free(conn);
325 errno=err;
326 return NULL;
329 if (connect(conn->fddata,(struct sockaddr *)&(dataout),sizeof(struct sockaddr_un))<0) {
330 int err=errno;
331 close(conn->fddata);
332 close(conn->fdctl);
333 free(conn);
334 errno=err;
335 return NULL;
337 chmod(dataout.sun_path,mode);
339 return conn;
342 ssize_t vde_recv(VDECONN *conn,void *buf,size_t len,int flags)
344 if (__builtin_expect(conn!=0,1))
345 return recv(conn->fddata,buf,len,0);
346 else {
347 errno=EBADF;
348 return -1;
352 ssize_t vde_send(VDECONN *conn,const void *buf,size_t len,int flags)
354 if (__builtin_expect(conn!=0,1))
355 return send(conn->fddata,buf,len,0);
356 else {
357 errno=EBADF;
358 return -1;
362 int vde_datafd(VDECONN *conn)
364 if (__builtin_expect(conn!=0,1))
365 return conn->fddata;
366 else {
367 errno=EBADF;
368 return -1;
372 int vde_ctlfd(VDECONN *conn)
374 if (__builtin_expect(conn!=0,1))
375 return conn->fdctl;
376 else {
377 errno=EBADF;
378 return -1;
382 int vde_close(VDECONN *conn)
384 if (__builtin_expect(conn!=0,1)) {
385 if (*(conn->inpath.sun_path))
386 unlink(conn->inpath.sun_path);
387 close(conn->fddata);
388 close(conn->fdctl);
389 free(conn);
390 return 0;
391 } else {
392 errno=EBADF;
393 return -1;