+vde_cryptcab generic bugfixes
[vde.git] / vde-2 / libvdeplug / libvdeplug.c
blob48141f12a55eff1994e6cc6b26a9d97003573758
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include "libvdeplug.h"
21 #include <errno.h>
22 #include <sys/socket.h>
23 #include <sys/un.h>
24 #include <stdint.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <pwd.h>
28 #include <grp.h>
30 #ifndef VDESTDSOCK
31 #define VDESTDSOCK "/var/run/vde.ctl"
32 #define VDETMPSOCK "/tmp/vde.ctl"
33 #endif
35 struct vdeconn {
36 int fdctl;
37 int fddata;
38 struct sockaddr_un inpath;
41 #define SWITCH_MAGIC 0xfeedface
42 #define MAXDESCR 128
44 enum request_type { REQ_NEW_CONTROL };
46 struct request_v3 {
47 uint32_t magic;
48 uint32_t version;
49 enum request_type type;
50 struct sockaddr_un sock;
51 char description[MAXDESCR];
54 VDECONN *vde_open_real(char *sockname,char *descr,int interface_version,
55 struct vde_open_args *open_args)
57 struct vdeconn *conn;
58 struct passwd *callerpwd;
59 struct request_v3 req;
60 int pid = getpid();
61 static struct sockaddr_un sockun;
62 static struct sockaddr_un dataout;
63 int port=0;
64 char *group=NULL;
65 int sockno=0;
66 int res;
67 mode_t mode=0;
69 if (open_args != NULL) {
70 if (interface_version == 1) {
71 port=open_args->port;
72 group=open_args->group;
73 mode=open_args->mode;
75 else {
76 errno=EINVAL;
77 return NULL;
81 if ((conn=calloc(1,sizeof(struct vdeconn)))==NULL)
83 errno=ENOMEM;
84 return NULL;
86 //get the login name
87 callerpwd=getpwuid(getuid());
88 if((conn->fddata = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0){
89 int err=errno;
90 free(conn);
91 errno=err;
92 return NULL;
94 if((conn->fdctl = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
95 int err=errno;
96 close(conn->fddata);
97 free(conn);
98 errno=err;
99 return NULL;
101 if (sockname == NULL)
102 sockname=VDESTDSOCK;
103 else {
104 char *split;
105 if(sockname[strlen(sockname)-1] == ']' && (split=rindex(sockname,'[')) != NULL) {
106 *split=0;
107 split++;
108 port=atoi(split);
109 if (*sockname==0) sockname=VDESTDSOCK;
112 sockun.sun_family = AF_UNIX;
113 snprintf(sockun.sun_path, sizeof(sockun.sun_path), "%s/ctl", sockname);
114 if(connect(conn->fdctl, (struct sockaddr *) &sockun, sizeof(sockun))){
115 if (sockname == VDESTDSOCK) {
116 sockname=VDETMPSOCK;
117 snprintf(sockun.sun_path, sizeof(sockun.sun_path), "%s/ctl", sockname);
118 if(connect(conn->fdctl, (struct sockaddr *) &sockun, sizeof(sockun))){
119 snprintf(sockun.sun_path, sizeof(sockun.sun_path), "%s", sockname);
120 if(connect(conn->fdctl, (struct sockaddr *) &sockun, sizeof(sockun))){
121 close(conn->fddata);
122 close(conn->fdctl);
123 free(conn);
124 errno=ENOENT;
125 return NULL;
131 req.magic=SWITCH_MAGIC;
132 req.version=3;
133 req.type=REQ_NEW_CONTROL+(port << 8);
134 req.sock.sun_family=AF_UNIX;
136 /* First choice, store the return socket from the switch in the control dir*/
137 memset(req.sock.sun_path, 0, sizeof(req.sock.sun_path));
140 sprintf(req.sock.sun_path, "%s.%05d-%05d", sockname, pid, sockno++);
141 res=bind(conn->fddata, (struct sockaddr *) &req.sock, sizeof (req.sock));
143 while (res < 0 && errno == EADDRINUSE);
144 if (res < 0){
145 /* if it is not possible -> /tmp */
146 memset(req.sock.sun_path, 0, sizeof(req.sock.sun_path));
149 sprintf(req.sock.sun_path, "%s.%05d-%05d", sockname, pid, sockno++);
150 res=bind(conn->fddata, (struct sockaddr *) &req.sock, sizeof (req.sock));
152 while (res < 0 && errno == EADDRINUSE);
154 if (res < 0){
155 int err=errno;
156 close(conn->fddata);
157 close(conn->fdctl);
158 free(conn);
159 errno=err;
160 return NULL;
163 snprintf(req.description,MAXDESCR,"%s user=%s PID=%d %s SOCK=%s",
164 descr,callerpwd->pw_name,pid,getenv("SSH_CLIENT")?getenv("SSH_CLIENT"):"",req.sock.sun_path);
165 memcpy(&(conn->inpath),&req.sock,sizeof(req.sock));
167 if (send(conn->fdctl,&req,sizeof(req)-MAXDESCR+strlen(req.description),0) < 0) {
168 int err=errno;
169 close(conn->fddata);
170 close(conn->fdctl);
171 free(conn);
172 errno=err;
173 return NULL;
176 if (recv(conn->fdctl,&(dataout),sizeof(struct sockaddr_un),0)<0) {
177 int err=errno;
178 close(conn->fddata);
179 close(conn->fdctl);
180 free(conn);
181 errno=err;
182 return NULL;
185 if (connect(conn->fddata,(struct sockaddr *)&(dataout),sizeof(struct sockaddr_un))<0) {
186 int err=errno;
187 close(conn->fddata);
188 close(conn->fdctl);
189 free(conn);
190 errno=err;
191 return NULL;
194 if (group) {
195 struct group *gs;
196 gid_t gid;
197 if ((gs=getgrnam(group)) == NULL)
198 gid=atoi(group);
199 else
200 gid=gs->gr_gid;
201 chown(conn->inpath.sun_path,-1,gid);
203 if (mode>=0)
204 chmod(conn->inpath.sun_path,mode);
206 return conn;
209 ssize_t vde_recv(VDECONN *conn,char *buf,size_t len,int flags)
211 if (__builtin_expect(conn!=0,1))
212 return recv(conn->fddata,buf,len,0);
213 else {
214 errno=EBADF;
215 return -1;
219 ssize_t vde_send(VDECONN *conn,const char *buf,size_t len,int flags)
221 if (__builtin_expect(conn!=0,1))
222 return send(conn->fddata,buf,len,0);
223 else {
224 errno=EBADF;
225 return -1;
229 int vde_datafd(VDECONN *conn)
231 if (__builtin_expect(conn!=0,1))
232 return conn->fddata;
233 else {
234 errno=EBADF;
235 return -1;
239 int vde_ctlfd(VDECONN *conn)
241 if (__builtin_expect(conn!=0,1))
242 return conn->fdctl;
243 else {
244 errno=EBADF;
245 return -1;
249 int vde_close(VDECONN *conn)
251 if (__builtin_expect(conn!=0,1)) {
252 unlink(conn->inpath.sun_path);
253 close(conn->fddata);
254 close(conn->fdctl);
255 free(conn);
256 return 0;
257 } else {
258 errno=EBADF;
259 return -1;