]> git.ipfire.org Git - thirdparty/strongswan.git/blob - src/libstrongswan/networking/streams/stream_service_unix.c
Allow strongSwan to be spawned as non-root user
[thirdparty/strongswan.git] / src / libstrongswan / networking / streams / stream_service_unix.c
1 /*
2 * Copyright (C) 2013 Martin Willi
3 * Copyright (C) 2013 revosec AG
4 *
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>.
9 *
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
13 * for more details.
14 */
15
16 #include <library.h>
17 #include <networking/streams/stream_unix.h>
18
19 #include <errno.h>
20 #include <unistd.h>
21 #include <sys/socket.h>
22 #include <sys/un.h>
23 #include <sys/stat.h>
24
25 /**
26 * See header
27 */
28 stream_service_t *stream_service_create_unix(char *uri, int backlog)
29 {
30 struct sockaddr_un addr;
31 mode_t old;
32 int fd, len;
33
34 len = stream_parse_uri_unix(uri, &addr);
35 if (len == -1)
36 {
37 DBG1(DBG_NET, "invalid stream URI: '%s'", uri);
38 return NULL;
39 }
40 if (!lib->caps->check(lib->caps, CAP_CHOWN))
41 { /* required to chown(2) service socket */
42 DBG1(DBG_NET, "cannot change ownership of socket '%s' without "
43 "CAP_CHOWN capability. socket directory should be accessible to "
44 "UID/GID under which the deamon will run", uri);
45 }
46 fd = socket(AF_UNIX, SOCK_STREAM, 0);
47 if (fd == -1)
48 {
49 DBG1(DBG_NET, "opening socket '%s' failed: %s", uri, strerror(errno));
50 return NULL;
51 }
52 unlink(addr.sun_path);
53
54 old = umask(S_IRWXO);
55 if (bind(fd, (struct sockaddr*)&addr, len) < 0)
56 {
57 DBG1(DBG_NET, "binding socket '%s' failed: %s", uri, strerror(errno));
58 close(fd);
59 return NULL;
60 }
61 umask(old);
62 /* only attempt to chown() socket if we have CAP_CHOWN */
63 if (lib->caps->check(lib->caps, CAP_CHOWN) &&
64 chown(addr.sun_path, lib->caps->get_uid(lib->caps),
65 lib->caps->get_gid(lib->caps)) != 0)
66 {
67 DBG1(DBG_NET, "changing socket permissions for '%s' failed: %s",
68 uri, strerror(errno));
69 }
70 if (listen(fd, backlog) < 0)
71 {
72 DBG1(DBG_NET, "listen on socket '%s' failed: %s", uri, strerror(errno));
73 unlink(addr.sun_path);
74 close(fd);
75 return NULL;
76 }
77 return stream_service_create_from_fd(fd);
78 }