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