Coverage Report

Created: 2024-02-29 06:05

/src/strongswan/src/libstrongswan/networking/streams/stream_service_unix.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2013 Martin Willi
3
 *
4
 * Copyright (C) secunet Security Networks AG
5
 *
6
 * This program is free software; you can redistribute it and/or modify it
7
 * under the terms of the GNU General Public License as published by the
8
 * Free Software Foundation; either version 2 of the License, or (at your
9
 * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
10
 *
11
 * This program is distributed in the hope that it will be useful, but
12
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14
 * for more details.
15
 */
16
17
#include <library.h>
18
#include <networking/streams/stream_unix.h>
19
20
#include <errno.h>
21
#include <unistd.h>
22
#include <sys/socket.h>
23
#include <sys/un.h>
24
#include <sys/stat.h>
25
26
/**
27
 * See header
28
 */
29
stream_service_t *stream_service_create_unix(char *uri, int backlog)
30
0
{
31
0
  struct sockaddr_un addr;
32
0
  mode_t old;
33
0
  int fd, len;
34
35
0
  len = stream_parse_uri_unix(uri, &addr);
36
0
  if (len == -1)
37
0
  {
38
0
    DBG1(DBG_NET, "invalid stream URI: '%s'", uri);
39
0
    return NULL;
40
0
  }
41
0
  if (!lib->caps->check(lib->caps, CAP_CHOWN))
42
0
  { /* required to chown(2) service socket */
43
0
    DBG1(DBG_NET, "cannot change ownership of socket '%s' without "
44
0
       "CAP_CHOWN capability. socket directory should be accessible to "
45
0
       "UID/GID under which the daemon will run", uri);
46
0
  }
47
0
  fd = socket(AF_UNIX, SOCK_STREAM, 0);
48
0
  if (fd == -1)
49
0
  {
50
0
    DBG1(DBG_NET, "opening socket '%s' failed: %s", uri, strerror(errno));
51
0
    return NULL;
52
0
  }
53
0
  unlink(addr.sun_path);
54
55
0
  old = umask(S_IRWXO);
56
0
  if (bind(fd, (struct sockaddr*)&addr, len) < 0)
57
0
  {
58
0
    DBG1(DBG_NET, "binding socket '%s' failed: %s", uri, strerror(errno));
59
0
    close(fd);
60
0
    return NULL;
61
0
  }
62
0
  umask(old);
63
  /* Only attempt to change owner of socket if we have CAP_CHOWN. Otherwise,
64
   * attempt to change group of socket to group under which charon runs after
65
   * dropping caps. This requires the user that charon starts as to:
66
   * a) Have write access to the socket dir.
67
   * b) Belong to the group that charon will run under after dropping caps. */
68
0
  if (lib->caps->check(lib->caps, CAP_CHOWN))
69
0
  {
70
0
    if (chown(addr.sun_path, lib->caps->get_uid(lib->caps),
71
0
          lib->caps->get_gid(lib->caps)) != 0)
72
0
    {
73
0
      DBG1(DBG_NET, "changing socket owner/group for '%s' failed: %s",
74
0
         uri, strerror(errno));
75
0
    }
76
0
  }
77
0
  else
78
0
  {
79
0
    if (chown(addr.sun_path, -1, lib->caps->get_gid(lib->caps)) != 0)
80
0
    {
81
0
      DBG1(DBG_NET, "changing socket group for '%s' failed: %s",
82
0
         uri, strerror(errno));
83
0
    }
84
0
  }
85
0
  if (listen(fd, backlog) < 0)
86
0
  {
87
0
    DBG1(DBG_NET, "listen on socket '%s' failed: %s", uri, strerror(errno));
88
0
    unlink(addr.sun_path);
89
0
    close(fd);
90
0
    return NULL;
91
0
  }
92
0
  return stream_service_create_from_fd(fd);
93
0
}