Changelog update
[public/netxms.git] / src / libnetxms / nxproc_unix.cpp
CommitLineData
05f298fe
VK
1/*
2** NetXMS - Network Management System
3** NetXMS Foundation Library
4** Copyright (C) 2003-2017 Victor Kirhenshtein
5**
6** This program is free software; you can redistribute it and/or modify
7** it under the terms of the GNU Lesser General Public License as published
8** by the Free Software Foundation; either version 3 of the License, or
9** (at your option) any later version.
10**
11** This program is distributed in the hope that it will be useful,
12** but WITHOUT ANY WARRANTY; without even the implied warranty of
13** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14** GNU General Public License for more details.
15**
16** You should have received a copy of the GNU Lesser General Public License
17** along with this program; if not, write to the Free Software
18** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19**
20** File: nxproc_unix.cpp
21**
22**/
23
24#include "libnetxms.h"
25#include <nxproc.h>
c9ce784e 26#include <pwd.h>
05f298fe 27
57b6a0f9
VK
28#ifdef __sun
29#include <ucred.h>
30#endif
31
05f298fe
VK
32/**
33 * Create listener end for named pipe
34 */
c9ce784e 35NamedPipeListener *NamedPipeListener::create(const TCHAR *name, NamedPipeRequestHandler reqHandler, void *userArg, const TCHAR *user)
05f298fe
VK
36{
37 mode_t prevMask = 0;
38
39 int s = socket(AF_UNIX, SOCK_STREAM, 0);
40 if (s == INVALID_SOCKET)
41 {
b6883988 42 nxlog_debug(2, _T("NamedPipeListener(%s): socket() call failed (%s)"), name, _tcserror(errno));
05f298fe
VK
43 return NULL;
44 }
45
46 struct sockaddr_un addrLocal;
47 addrLocal.sun_family = AF_UNIX;
48#ifdef UNICODE
49 sprintf(addrLocal.sun_path, "/tmp/.%S", name);
50#else
51 sprintf(addrLocal.sun_path, "/tmp/.%s", name);
52#endif
53 unlink(addrLocal.sun_path);
cd102a51 54 prevMask = umask(0);
05f298fe
VK
55 if (bind(s, (struct sockaddr *)&addrLocal, SUN_LEN(&addrLocal)) == -1)
56 {
b6883988 57 nxlog_debug(2, _T("NamedPipeListener(%s): bind failed (%s)"), name, _tcserror(errno));
05f298fe
VK
58 umask(prevMask);
59 goto failure;
60 }
61 umask(prevMask);
62
63 if (listen(s, 5) == -1)
64 {
b6883988 65 nxlog_debug(2, _T("NamedPipeListener(%s): listen() call failed (%s)"), name, _tcserror(errno));
05f298fe
VK
66 goto failure;
67 }
68
c9ce784e 69 return new NamedPipeListener(name, s, reqHandler, userArg, user);
05f298fe
VK
70
71failure:
72 close(s);
73 unlink(addrLocal.sun_path);
74 return NULL;
75}
76
77/**
05f298fe
VK
78 * Pipe destructor
79 */
b6883988 80NamedPipeListener::~NamedPipeListener()
05f298fe
VK
81{
82 close(m_handle);
b6883988
VK
83 stop();
84 char path[MAX_PATH];
05f298fe 85#ifdef UNICODE
b6883988 86 sprintf(path, "/tmp/.%S", m_name);
05f298fe 87#else
b6883988 88 sprintf(path, "/tmp/.%s", m_name);
05f298fe 89#endif
b6883988 90 unlink(path);
05f298fe
VK
91}
92
93/**
57b6a0f9
VK
94 * Get UNIX socket peer user ID
95 */
96static bool GetPeerUID(SOCKET s, unsigned int *uid)
97{
98#if defined(__sun)
d5ed2656 99 ucred_t *peer = NULL;
57b6a0f9
VK
100 if (getpeerucred(s, &peer) == 0)
101 {
102 *uid = (unsigned int)ucred_geteuid(peer);
103 ucred_free(peer);
104 return true;
105 }
15bf4b02
VK
106#elif HAVE_GETPEEREID
107 uid_t euid;
108 gid_t egid;
109 if (getpeereid(s, &euid, &egid) == 0)
110 {
111 *uid = (unsigned int)euid;
112 return true;
113 }
57b6a0f9
VK
114#elif defined(SO_PEERID)
115 struct peercred_struct peer;
116 unsigned int len = sizeof(peer);
117 if (getsockopt(s, SOL_SOCKET, SO_PEERID, &peer, &len) == 0)
118 {
119 *uid = (unsigned int)peer.euid;
120 return true;
121 }
122#elif defined(SO_PEERCRED)
123 struct ucred peer;
124 unsigned int len = sizeof(peer);
125 if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &peer, &len) == 0)
126 {
127 *uid = (unsigned int)peer.uid;
128 return true;
129 }
891d89bd
VK
130#elif defined(_HPUX)
131 // implementation for HP-UX is not possible
57b6a0f9
VK
132#else
133#error no valid method to get socket peer UID
134#endif
135 return false;
136}
137
138/**
05f298fe
VK
139 * Named pipe server thread
140 */
b6883988 141void NamedPipeListener::serverThread()
05f298fe 142{
b6883988 143 nxlog_debug(2, _T("NamedPipeListener(%s): waiting for connection"), m_name);
05f298fe
VK
144 while(!m_stop)
145 {
146 struct sockaddr_un addrRemote;
147 socklen_t size = sizeof(struct sockaddr_un);
148 SOCKET cs = accept(m_handle, (struct sockaddr *)&addrRemote, &size);
149 if (cs > 0)
150 {
c9ce784e 151 TCHAR user[64];
57b6a0f9
VK
152 unsigned int uid;
153 if (GetPeerUID(cs, &uid))
c9ce784e
VK
154 {
155#if HAVE_GETPWUID_R
156 struct passwd pwbuf, *pw;
157 char sbuf[4096];
57b6a0f9 158 getpwuid_r(uid, &pwbuf, sbuf, 4096, &pw);
c9ce784e 159#else
57b6a0f9 160 struct passwd *pw = getpwuid(uid);
c9ce784e
VK
161#endif
162 if (pw != NULL)
163 {
164#ifdef UNICODE
165 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pw->pw_name, -1, user, 64);
166#else
3a4c13cc 167 strlcpy(user, pw->pw_name, 64);
c9ce784e
VK
168#endif
169 }
170 else
171 {
57b6a0f9 172 _sntprintf(user, 64, _T("[%u]"), uid);
c9ce784e
VK
173 }
174 }
175 else
176 {
177 _tcscpy(user, _T("[unknown]"));
178 }
179
180 if ((m_user[0] == 0) || !_tcscmp(m_user, user))
181 {
182 nxlog_debug(5, _T("NamedPipeListener(%s): accepted connection by user %s"), m_name, user);
183 NamedPipe *cp = new NamedPipe(m_name, cs, user);
184 m_reqHandler(cp, m_userArg);
185 delete cp;
186 }
187 else
188 {
189 nxlog_debug(5, _T("NamedPipeListener(%s): rejected connection by user %s"), m_name, user);
190 }
05f298fe
VK
191 }
192 else
193 {
b6883988 194 nxlog_debug(2, _T("NamedPipeListener(%s): accept failed (%s)"), m_name, _tcserror(errno));
05f298fe
VK
195 }
196 }
197}
b6883988
VK
198
199/**
200 * Pipe destructor
201 */
202NamedPipe::~NamedPipe()
203{
204 close(m_handle);
205 MutexDestroy(m_writeLock);
206}
207
208/**
209 * Create client end for named pipe
210 */
211NamedPipe *NamedPipe::connect(const TCHAR *name, UINT32 timeout)
212{
213 int s = socket(AF_UNIX, SOCK_STREAM, 0);
214 if (s == INVALID_SOCKET)
215 {
216 nxlog_debug(2, _T("NamedPipe(%s): socket() call failed (%s)"), name, _tcserror(errno));
217 return NULL;
218 }
219
220 struct sockaddr_un remote;
221 remote.sun_family = AF_UNIX;
222#ifdef UNICODE
223 sprintf(remote.sun_path, "/tmp/.%S", name);
224#else
225 sprintf(remote.sun_path, "/tmp/.%s", name);
226#endif
227 if (::connect(s, (struct sockaddr *)&remote, SUN_LEN(&remote)) == -1)
228 {
cd102a51 229 nxlog_debug(2, _T("NamedPipe(%s): connect() call failed (%s)"), name, _tcserror(errno));
b6883988
VK
230 close(s);
231 return NULL;
232 }
233
c9ce784e 234 return new NamedPipe(name, s, NULL);
b6883988
VK
235}
236
237/**
238 * Write to pipe
239 */
240bool NamedPipe::write(const void *data, size_t size)
241{
242 return SendEx(m_handle, data, size, 0, m_writeLock) == (int)size;
243}
7afa2e6d
VK
244
245/**
246 * Get user name
247 */
248const TCHAR *NamedPipe::user()
249{
250 return m_user;
251}