2 * Copyright (C) 2011 Martin Willi
3 * Copyright (C) 2011 revosec AG
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 #include "whitelist_control.h"
18 #include <sys/types.h>
20 #include <sys/socket.h>
26 #include <threading/thread.h>
27 #include <processing/jobs/callback_job.h>
29 #include "whitelist_msg.h"
31 typedef struct private_whitelist_control_t private_whitelist_control_t
;
34 * Private data of an whitelist_control_t object.
36 struct private_whitelist_control_t
{
39 * Public whitelist_control_t interface.
41 whitelist_control_t
public;
46 whitelist_listener_t
*listener
;
49 * Whitelist unix socket file descriptor
54 * Callback job dispatching commands
60 * Open whitelist unix socket
62 static bool open_socket(private_whitelist_control_t
*this)
64 struct sockaddr_un addr
;
67 addr
.sun_family
= AF_UNIX
;
68 strcpy(addr
.sun_path
, WHITELIST_SOCKET
);
70 this->socket
= socket(AF_UNIX
, SOCK_SEQPACKET
, 0);
71 if (this->socket
== -1)
73 DBG1(DBG_CFG
, "creating whitelist socket failed");
76 unlink(addr
.sun_path
);
77 old
= umask(~(S_IRWXU
| S_IRWXG
));
78 if (bind(this->socket
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0)
80 DBG1(DBG_CFG
, "binding whitelist socket failed: %s", strerror(errno
));
85 if (chown(addr
.sun_path
, charon
->uid
, charon
->gid
) != 0)
87 DBG1(DBG_CFG
, "changing whitelist socket permissions failed: %s",
90 if (listen(this->socket
, 10) < 0)
92 DBG1(DBG_CFG
, "listening on whitelist socket failed: %s", strerror(errno
));
94 unlink(addr
.sun_path
);
101 * Dispatch a received message
103 static void dispatch(private_whitelist_control_t
*this,
104 int fd
, whitelist_msg_t
*msg
)
106 identification_t
*id
, *current
;
107 enumerator_t
*enumerator
;
109 msg
->id
[sizeof(msg
->id
)-1] = 0;
110 id
= identification_create_from_string(msg
->id
);
114 this->listener
->add(this->listener
, id
);
116 case WHITELIST_REMOVE
:
117 this->listener
->remove(this->listener
, id
);
120 enumerator
= this->listener
->create_enumerator(this->listener
);
121 while (enumerator
->enumerate(enumerator
, ¤t
))
123 if (current
->matches(current
, id
))
125 snprintf(msg
->id
, sizeof(msg
->id
), "%Y", current
);
126 if (send(fd
, msg
, sizeof(*msg
), 0) != sizeof(*msg
))
128 DBG1(DBG_CFG
, "listing whitelist failed");
133 enumerator
->destroy(enumerator
);
134 msg
->type
= WHITELIST_END
;
135 memset(msg
->id
, 0, sizeof(msg
->id
));
136 send(fd
, msg
, sizeof(*msg
), 0);
138 case WHITELIST_FLUSH
:
139 this->listener
->flush(this->listener
, id
);
141 case WHITELIST_ENABLE
:
142 this->listener
->set_active(this->listener
, TRUE
);
144 case WHITELIST_DISABLE
:
145 this->listener
->set_active(this->listener
, FALSE
);
148 DBG1(DBG_CFG
, "received unknown whitelist command");
155 * Accept whitelist control connections, dispatch
157 static job_requeue_t
receive(private_whitelist_control_t
*this)
159 struct sockaddr_un addr
;
160 int fd
, len
= sizeof(addr
);
164 oldstate
= thread_cancelability(TRUE
);
165 fd
= accept(this->socket
, (struct sockaddr
*)&addr
, &len
);
166 thread_cancelability(oldstate
);
172 oldstate
= thread_cancelability(TRUE
);
173 len
= recv(fd
, &msg
, sizeof(msg
), 0);
174 thread_cancelability(oldstate
);
176 if (len
== sizeof(msg
))
178 dispatch(this, fd
, &msg
);
184 DBG1(DBG_CFG
, "receiving whitelist msg failed: %s",
194 DBG1(DBG_CFG
, "accepting whitelist connection failed: %s",
197 return JOB_REQUEUE_FAIR
;
200 METHOD(whitelist_control_t
, destroy
, void,
201 private_whitelist_control_t
*this)
203 this->job
->cancel(this->job
);
211 whitelist_control_t
*whitelist_control_create(whitelist_listener_t
*listener
)
213 private_whitelist_control_t
*this;
219 .listener
= listener
,
222 if (!open_socket(this))
228 this->job
= callback_job_create_with_prio((callback_job_cb_t
)receive
,
229 this, NULL
, NULL
, JOB_PRIO_CRITICAL
);
230 lib
->processor
->queue_job(lib
->processor
, (job_t
*)this->job
);
232 return &this->public;