1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
|
/**
* @file proxy_unix.c
* @author Michal Vasko <mvasko@cesnet.cz>
* @brief libnetconf2 UNIX proxy functions
*
* @copyright
* Copyright (c) 2025 CESNET, z.s.p.o.
*
* This source code is licensed under BSD 3-Clause License (the "License").
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*/
#define _GNU_SOURCE
#include "proxy_unix.h"
#include <errno.h>
#include <fcntl.h>
#include <pwd.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
#include "compat.h"
#include "config.h"
#include "log_p.h"
#include "session_p.h"
API int
nc_proxy_unix_connect(const char *address, const char *username)
{
struct sockaddr_un sun;
struct passwd *pw, pw_buf;
int sock = -1;
char *buf = NULL;
size_t buf_size = 0;
/* connect to the UNIX socket */
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
ERR(NULL, "Failed to create socket (%s).", strerror(errno));
goto error;
}
memset(&sun, 0, sizeof(sun));
sun.sun_family = AF_UNIX;
snprintf(sun.sun_path, sizeof(sun.sun_path), "%s", address);
if (connect(sock, (struct sockaddr *)&sun, sizeof(sun)) < 0) {
ERR(NULL, "Cannot connect to sock server %s (%s)", address, strerror(errno));
goto error;
}
if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
ERR(NULL, "fcntl failed (%s).", strerror(errno));
goto error;
}
/* NETCONF username */
if (!username) {
pw = nc_getpw(geteuid(), NULL, &pw_buf, &buf, &buf_size);
if (!pw) {
ERR(NULL, "Failed to find username for UID %u.", (unsigned int)geteuid());
goto error;
}
username = pw->pw_name;
}
/* connect UNIX session */
if (nc_connect_unix_session(NULL, sock, username, NC_TRANSPORT_TIMEOUT) != 1) {
goto error;
}
free(buf);
return sock;
error:
if (sock > -1) {
close(sock);
}
free(buf);
return -1;
}
API int
nc_proxy_read_msg(int fd, NC_PROT_VERSION version, int timeout_ms, char **buf, uint32_t *buf_len)
{
int r;
struct pollfd fds;
struct nc_session sess = {0};
/* poll */
fds.fd = fd;
fds.events = POLLIN;
fds.revents = 0;
r = nc_poll(&fds, 1, timeout_ms);
if (r < 0) {
/* error */
ERR(NULL, "poll error (%s).", strerror(errno));
return -1;
} else if (r == 0) {
/* timeout */
return 0;
} else {
/* socket error */
if (fds.revents & POLLERR) {
ERR(NULL, "Communication channel error.");
return -1;
}
/* some poll() implementations may return POLLHUP|POLLIN when the other
* side has closed but there is data left to read in the buffer */
if ((fds.revents & POLLHUP) && !(fds.revents & POLLIN)) {
ERR(NULL, "Communication channel unexpectedly closed.");
return -1;
}
}
/* fill dummy session (id 0 causes session not to be included in log messages) */
sess.status = NC_STATUS_RUNNING;
sess.version = version;
sess.ti_type = NC_TI_UNIX;
sess.ti.unixsock.sock = fd;
/* read a message */
r = nc_read_msg_io(&sess, 0, 1, buf, buf_len);
switch (r) {
case -2:
ERR(NULL, "Malformed message received.");
return -1;
case -1:
/* error printed */
return -1;
case 0:
/* timeout */
return 0;
default:
/* success */
break;
}
return r;
}
API int
nc_proxy_write_msg(int fd, NC_PROT_VERSION version, const char *buf, uint32_t buf_len)
{
struct nc_session sess = {0};
struct nc_wclb_arg warg = {.session = &sess};
/* fill dummy session (id 0 causes session not to be included in log messages) */
sess.status = NC_STATUS_RUNNING;
sess.version = version;
sess.ti_type = NC_TI_UNIX;
sess.ti.unixsock.sock = fd;
/* write the whole message */
if (nc_write_clb(&warg, buf, buf_len, 0) == -1) {
return -1;
}
/* flush buffer writing the final end tag */
if (nc_write_clb(&warg, NULL, 0, 0) == -1) {
return -1;
}
return buf_len;
}
API int
nc_proxy_unix_close(int fd)
{
if (fd < 0) {
return 0;
}
/* just close the socket */
return close(fd);
}
|