]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/unix_utility.cc
spelling: syscall
[thirdparty/pdns.git] / pdns / unix_utility.cc
CommitLineData
12c86877 1/*
6edbf68a
PL
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
870a0fe4
AT
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
12c86877
BH
25#include "utility.hh"
26#include <cstring>
27#include <fcntl.h>
28#include <unistd.h>
29#include <stdlib.h>
5c409fa2 30#include "pdnsexception.hh"
12c86877
BH
31#include "logger.hh"
32#include "misc.hh"
33#include <pwd.h>
34#include <grp.h>
35#include <sys/types.h>
c7c7edb5 36#include <sys/select.h>
12c86877 37
1258abe0
BH
38#ifdef NEED_INET_NTOP_PROTO
39extern "C" {
40const char *inet_ntop(int af, const void *src, char *dst, size_t cnt);
41}
42#endif
43
44
10f4eea8 45#include "namespaces.hh"
12c86877 46
12c86877 47
c7c7edb5
IM
48// Connects to socket with timeout
49int Utility::timed_connect( Utility::sock_t sock,
50 const sockaddr *addr,
51 Utility::socklen_t sockaddr_size,
52 int timeout_sec,
53 int timeout_usec )
54{
55 fd_set set;
56 struct timeval timeout;
57 int ret;
58
59 timeout.tv_sec = timeout_sec;
60 timeout.tv_usec = timeout_usec;
61
62 FD_ZERO(&set);
63 FD_SET(sock, &set);
64
65 setNonBlocking(sock);
66
67 if ((ret = connect (sock, addr, sockaddr_size)) < 0) {
68 if (errno != EINPROGRESS)
69 return ret;
70 }
71
72 ret = select(sock + 1, NULL, &set, NULL, &timeout);
73 setBlocking(sock);
74
75 return ret;
76}
77
12c86877 78
42c235e5 79
fec7dd5a
SS
80void Utility::setBindAny(int af, sock_t sock)
81{
27eb476b 82 const int one = 1;
fec7dd5a 83
27eb476b 84 (void) one; // avoids 'unused var' warning on systems that have none of the defines checked below
fec7dd5a
SS
85#ifdef IP_FREEBIND
86 if (setsockopt(sock, IPPROTO_IP, IP_FREEBIND, &one, sizeof(one)) < 0)
e6a9dde5 87 g_log<<Logger::Warning<<"Warning: IP_FREEBIND setsockopt failed: "<<strerror(errno)<<endl;
fec7dd5a
SS
88#endif
89
90#ifdef IP_BINDANY
91 if (af == AF_INET)
4355c3ea 92 if (setsockopt(sock, IPPROTO_IP, IP_BINDANY, &one, sizeof(one)) < 0)
e6a9dde5 93 g_log<<Logger::Warning<<"Warning: IP_BINDANY setsockopt failed: "<<strerror(errno)<<endl;
fec7dd5a
SS
94#endif
95#ifdef IPV6_BINDANY
96 if (af == AF_INET6)
97 if (setsockopt(sock, IPPROTO_IPV6, IPV6_BINDANY, &one, sizeof(one)) < 0)
e6a9dde5 98 g_log<<Logger::Warning<<"Warning: IPV6_BINDANY setsockopt failed: "<<strerror(errno)<<endl;
fec7dd5a
SS
99#endif
100#ifdef SO_BINDANY
101 if (setsockopt(sock, SOL_SOCKET, SO_BINDANY, &one, sizeof(one)) < 0)
e6a9dde5 102 g_log<<Logger::Warning<<"Warning: SO_BINDANY setsockopt failed: "<<strerror(errno)<<endl;
fec7dd5a
SS
103#endif
104}
105
12c86877
BH
106const char *Utility::inet_ntop(int af, const char *src, char *dst, size_t size)
107{
1258abe0 108 return ::inet_ntop(af,src,dst,size);
12c86877
BH
109}
110
111unsigned int Utility::sleep(unsigned int sec)
112{
113 return ::sleep(sec);
114}
115
116void Utility::usleep(unsigned long usec)
117{
22cc5a36
AT
118 struct timespec ts;
119 ts.tv_sec = usec / 1000000;
120 ts.tv_nsec = (usec % 1000000) * 1000;
121 // POSIX.1 recommends using nanosleep instead of usleep
122 ::nanosleep(&ts, NULL);
12c86877
BH
123}
124
125
f1d6a7ce
KM
126// Drops the program's group privileges.
127void Utility::dropGroupPrivs( int uid, int gid )
12c86877
BH
128{
129 if(gid) {
130 if(setgid(gid)<0) {
e6a9dde5 131 g_log<<Logger::Critical<<"Unable to set effective group id to "<<gid<<": "<<stringerror()<<endl;
12c86877
BH
132 exit(1);
133 }
134 else
e6a9dde5 135 g_log<<Logger::Info<<"Set effective group id to "<<gid<<endl;
12c86877 136
cee857b0
KM
137 struct passwd *pw=getpwuid(uid);
138 if(!pw) {
e6a9dde5 139 g_log<<Logger::Warning<<"Unable to determine user name for uid "<<uid<<endl;
cee857b0 140 if (setgroups(0, NULL)<0) {
e6a9dde5 141 g_log<<Logger::Critical<<"Unable to drop supplementary gids: "<<stringerror()<<endl;
cee857b0
KM
142 exit(1);
143 }
144 } else {
145 if (initgroups(pw->pw_name, gid)<0) {
e6a9dde5 146 g_log<<Logger::Critical<<"Unable to set supplementary groups: "<<stringerror()<<endl;
cee857b0
KM
147 exit(1);
148 }
fe97f596 149 }
12c86877 150 }
f1d6a7ce
KM
151}
152
12c86877 153
f1d6a7ce
KM
154// Drops the program's user privileges.
155void Utility::dropUserPrivs( int uid )
156{
12c86877
BH
157 if(uid) {
158 if(setuid(uid)<0) {
84cbd0dc 159 g_log<<Logger::Critical<<"Unable to set effective user id to "<<uid<<": "<<stringerror()<<endl;
12c86877
BH
160 exit(1);
161 }
162 else
e6a9dde5 163 g_log<<Logger::Info<<"Set effective user id to "<<uid<<endl;
12c86877
BH
164 }
165}
166
167
168// Returns the current process id.
169Utility::pid_t Utility::getpid( void )
170{
171 return ::getpid();
172}
173
174
175// Returns the current time.
176int Utility::gettimeofday( struct timeval *tv, void *tz )
177{
178 return ::gettimeofday(tv,0);
179}
180
181
12c86877 182
12c86877
BH
183// Retrieves a gid using a groupname.
184int Utility::makeGidNumeric(const string &group)
185{
186 int newgid;
187 if(!(newgid=atoi(group.c_str()))) {
d0c0ae3a 188 errno=0;
12c86877
BH
189 struct group *gr=getgrnam(group.c_str());
190 if(!gr) {
e6a9dde5 191 g_log<<Logger::Critical<<"Unable to look up gid of group '"<<group<<"': "<< (errno ? strerror(errno) : "not found") <<endl;
12c86877
BH
192 exit(1);
193 }
194 newgid=gr->gr_gid;
195 }
196 return newgid;
197}
198
199
200// Retrieves an uid using a username.
201int Utility::makeUidNumeric(const string &username)
202{
203 int newuid;
204 if(!(newuid=atoi(username.c_str()))) {
205 struct passwd *pw=getpwnam(username.c_str());
206 if(!pw) {
e6a9dde5 207 g_log<<Logger::Critical<<"Unable to look up uid of user '"<<username<<"': "<< (errno ? strerror(errno) : "not found") <<endl;
12c86877
BH
208 exit(1);
209 }
210 newuid=pw->pw_uid;
211 }
212 return newuid;
213}
214
8342eb4f 215// Sets the random seed.
b51ef4f9 216void Utility::srandom(void)
8342eb4f 217{
b51ef4f9
OM
218 struct timeval tv;
219 gettimeofday(&tv, 0);
220 ::srandom(tv.tv_sec ^ tv.tv_usec ^ getpid());
8342eb4f 221}
896e5153 222
12c86877 223// Writes a vector.
092c9cc4 224int Utility::writev(int socket, const iovec *vector, size_t count )
12c86877
BH
225{
226 return ::writev(socket,vector,count);
227}
228
49f72da1
BH
229/* this is cut and pasted from dietlibc, gratefully copied! */
230static int isleap(int year) {
231 /* every fourth year is a leap year except for century years that are
232 * not divisible by 400. */
233 return (!(year%4) && ((year%100) || !(year%400)));
234}
235
236time_t Utility::timegm(struct tm *const t)
237{
238 const static short spm[13] = /* days per month -- nonleap! */
239 { 0,
240 (31),
241 (31+28),
242 (31+28+31),
243 (31+28+31+30),
244 (31+28+31+30+31),
245 (31+28+31+30+31+30),
246 (31+28+31+30+31+30+31),
247 (31+28+31+30+31+30+31+31),
248 (31+28+31+30+31+30+31+31+30),
249 (31+28+31+30+31+30+31+31+30+31),
250 (31+28+31+30+31+30+31+31+30+31+30),
251 (31+28+31+30+31+30+31+31+30+31+30+31),
252 };
253
254 time_t day;
255 time_t i;
256 time_t years = t->tm_year - 70;
257
258 if (t->tm_sec>60) { t->tm_min += t->tm_sec/60; t->tm_sec%=60; }
259 if (t->tm_min>60) { t->tm_hour += t->tm_min/60; t->tm_min%=60; }
260 if (t->tm_hour>60) { t->tm_mday += t->tm_hour/60; t->tm_hour%=60; }
813b1d93 261 if (t->tm_mon>11) { t->tm_year += t->tm_mon/12; t->tm_mon%=12; }
49f72da1
BH
262
263 while (t->tm_mday>spm[1+t->tm_mon]) {
264 if (t->tm_mon==1 && isleap(t->tm_year+1900)) {
265 if (t->tm_mon==31+29) break;
266 --t->tm_mday;
267 }
268 t->tm_mday-=spm[t->tm_mon];
269 ++t->tm_mon;
270 if (t->tm_mon>11) { t->tm_mon=0; ++t->tm_year; }
271 }
272
273 if (t->tm_year < 70)
274 return (time_t) -1;
275 /* Days since 1970 is 365 * number of years + number of leap years since 1970 */
276 day = years * 365 + (years + 1) / 4;
277
7c696097 278 /* After 2100 we have to subtract 3 leap years for every 400 years
49f72da1 279 This is not intuitive. Most mktime implementations do not support
1f6c983f 280 dates after 2059, anyway, so we might leave this out for its
49f72da1
BH
281 bloat. */
282 if ((years -= 131) >= 0) {
283 years /= 100;
284 day -= (years >> 2) * 3 + 1;
285 if ((years &= 3) == 3) years--;
286 day -= years;
287 }
288
289 day += t->tm_yday = spm [t->tm_mon] + t->tm_mday-1 + ( isleap (t->tm_year+1900) & (t->tm_mon > 1) );
290
291 /* day is now the number of days since 'Jan 1 1970' */
292 i = 7;
293 t->tm_wday = (day + 4) % i; /* Sunday=0, Monday=1, ..., Saturday=6 */
294
295 i = 24;
296 day *= i;
297 i = 60;
298 return ((day + t->tm_hour) * i + t->tm_min) * i + t->tm_sec;
299}
300