]>
git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/unix_utility.cc
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
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.
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.
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.
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.
30 #include "pdnsexception.hh"
36 #include <sys/types.h>
37 #include <sys/select.h>
39 #ifdef NEED_INET_NTOP_PROTO
41 const char *inet_ntop(int af
, const void *src
, char *dst
, size_t cnt
);
46 #include "namespaces.hh"
49 // Connects to socket with timeout
50 int Utility::timed_connect( Utility::sock_t sock
,
52 Utility::socklen_t sockaddr_size
,
57 struct timeval timeout
;
60 timeout
.tv_sec
= timeout_sec
;
61 timeout
.tv_usec
= timeout_usec
;
68 if ((ret
= connect (sock
, addr
, sockaddr_size
)) < 0) {
69 if (errno
!= EINPROGRESS
)
73 ret
= select(sock
+ 1, nullptr, &set
, nullptr, &timeout
);
81 void Utility::setBindAny([[maybe_unused
]] int af
, [[maybe_unused
]] sock_t sock
)
85 (void) one
; // avoids 'unused var' warning on systems that have none of the defines checked below
87 if (setsockopt(sock
, IPPROTO_IP
, IP_FREEBIND
, &one
, sizeof(one
)) < 0) {
89 SLOG(g_log
<<Logger::Warning
<<"Warning: IP_FREEBIND setsockopt failed: "<<stringerror(err
)<<endl
,
90 g_slog
->withName("runtime")->error(Logr::Warning
, err
, "Warning: IP_FREEBIND setsockopt failed"));
96 if (setsockopt(sock
, IPPROTO_IP
, IP_BINDANY
, &one
, sizeof(one
)) < 0) {
98 SLOG(g_log
<<Logger::Warning
<<"Warning: IP_BINDANY setsockopt failed: "<<stringerror(err
)<<endl
,
99 g_slog
->withName("runtime")->error(Logr::Warning
, err
, "Warning: IP_BINDANY setsockopt failed"));
103 if (af
== AF_INET6
) {
104 if (setsockopt(sock
, IPPROTO_IPV6
, IPV6_BINDANY
, &one
, sizeof(one
)) < 0) {
106 SLOG(g_log
<<Logger::Warning
<<"Warning: IPV6_BINDANY setsockopt failed: "<<stringerror(err
)<<endl
,
107 g_slog
->withName("runtime")->error(Logr::Warning
, err
, "Warning: IPV6_BINDANY setsockopt failed"));
112 if (setsockopt(sock
, SOL_SOCKET
, SO_BINDANY
, &one
, sizeof(one
)) < 0) {
114 SLOG(g_log
<<Logger::Warning
<<"Warning: SO_BINDANY setsockopt failed: "<<stringerror(err
)<<endl
,
115 g_slog
->withName("runtime")->error(Logr::Warning
, err
, "Warning: SO_BINDANY setsockopt failed"));
120 const char *Utility::inet_ntop(int af
, const char *src
, char *dst
, size_t size
)
122 return ::inet_ntop(af
,src
,dst
,size
);
125 unsigned int Utility::sleep(unsigned int sec
)
130 void Utility::usleep(unsigned long usec
)
133 ts
.tv_sec
= usec
/ 1000000;
134 ts
.tv_nsec
= (usec
% 1000000) * 1000;
135 // POSIX.1 recommends using nanosleep instead of usleep
136 ::nanosleep(&ts
, nullptr);
140 // Drops the program's group privileges.
141 void Utility::dropGroupPrivs( uid_t uid
, gid_t gid
)
143 if(gid
&& gid
!= getegid()) {
146 SLOG(g_log
<<Logger::Critical
<<"Unable to set effective group id to "<<gid
<<": "<<stringerror(err
)<<endl
,
147 g_slog
->withName("runtime")->error(Logr::Critical
, err
, "Unable to set effective group id", "gid", Logging::Loggable(gid
)));
151 SLOG(g_log
<<Logger::Info
<<"Set effective group id to "<<gid
<<endl
,
152 g_slog
->withName("runtime")->info(Logr::Info
, "Set effective group id", "gid", Logging::Loggable(gid
)));
154 struct passwd
*pw
=getpwuid(uid
);
156 SLOG(g_log
<<Logger::Warning
<<"Unable to determine user name for uid "<<uid
<<endl
,
157 g_slog
->withName("runtime")->info(Logr::Warning
, "Unable to determine user name", "uid", Logging::Loggable(uid
)));
158 if (setgroups(0, nullptr)<0) {
160 SLOG(g_log
<<Logger::Critical
<<"Unable to drop supplementary gids: "<<stringerror(err
)<<endl
,
161 g_slog
->withName("runtime")->error(Logr::Critical
, err
, "Unable to drop supplementary gids"));
165 if (initgroups(pw
->pw_name
, gid
)<0) {
167 SLOG(g_log
<<Logger::Critical
<<"Unable to set supplementary groups: "<<stringerror(err
)<<endl
,
168 g_slog
->withName("runtime")->error(Logr::Critical
, err
, "Unable to set supplementary groups"));
176 // Drops the program's user privileges.
177 void Utility::dropUserPrivs( uid_t uid
)
179 if(uid
&& uid
!= geteuid()) {
182 SLOG(g_log
<<Logger::Critical
<<"Unable to set effective user id to "<<uid
<<": "<<stringerror(err
)<<endl
,
183 g_slog
->withName("runtime")->error(Logr::Critical
, err
, "Unable to set effective user id", "uid", Logging::Loggable(uid
)));
187 SLOG(g_log
<<Logger::Info
<<"Set effective user id to "<<uid
<<endl
,
188 g_slog
->withName("runtime")->info(Logr::Info
, "Set effective user", "uid", Logging::Loggable(uid
)));
194 // Returns the current process id.
195 Utility::pid_t
Utility::getpid( )
201 // Returns the current time.
202 int Utility::gettimeofday( struct timeval
*tv
, void * /* tz */)
204 return ::gettimeofday(tv
, nullptr);
208 int Utility::writev(int socket
, const iovec
*vector
, size_t count
)
210 return ::writev(socket
,vector
,count
);
213 /* this is cut and pasted from dietlibc, gratefully copied! */
214 static int isleap(int year
) {
215 /* every fourth year is a leap year except for century years that are
216 * not divisible by 400. */
217 return (!(year
%4) && ((year
%100) || !(year
%400)));
220 time_t Utility::timegm(struct tm
*const t
)
222 const static short spm
[13] = /* days per month -- nonleap! */
230 (31+28+31+30+31+30+31),
231 (31+28+31+30+31+30+31+31),
232 (31+28+31+30+31+30+31+31+30),
233 (31+28+31+30+31+30+31+31+30+31),
234 (31+28+31+30+31+30+31+31+30+31+30),
235 (31+28+31+30+31+30+31+31+30+31+30+31),
240 time_t years
= t
->tm_year
- 70;
242 if (t
->tm_sec
>60) { t
->tm_min
+= t
->tm_sec
/60; t
->tm_sec
%=60; }
243 if (t
->tm_min
>60) { t
->tm_hour
+= t
->tm_min
/60; t
->tm_min
%=60; }
244 if (t
->tm_hour
>60) { t
->tm_mday
+= t
->tm_hour
/60; t
->tm_hour
%=60; }
245 if (t
->tm_mon
>11) { t
->tm_year
+= t
->tm_mon
/12; t
->tm_mon
%=12; }
247 while (t
->tm_mday
>spm
[1+t
->tm_mon
]) {
248 if (t
->tm_mon
==1 && isleap(t
->tm_year
+1900)) {
249 if (t
->tm_mon
==31+29) break;
252 t
->tm_mday
-=spm
[t
->tm_mon
];
254 if (t
->tm_mon
>11) { t
->tm_mon
=0; ++t
->tm_year
; }
259 /* Days since 1970 is 365 * number of years + number of leap years since 1970 */
260 day
= years
* 365 + (years
+ 1) / 4;
262 /* After 2100 we have to subtract 3 leap years for every 400 years
263 This is not intuitive. Most mktime implementations do not support
264 dates after 2059, anyway, so we might leave this out for its
266 if ((years
-= 131) >= 0) {
268 day
-= (years
>> 2) * 3 + 1;
269 if ((years
&= 3) == 3) years
--;
273 day
+= t
->tm_yday
= spm
[t
->tm_mon
] + t
->tm_mday
-1 + ( isleap (t
->tm_year
+1900) & (t
->tm_mon
> 1) );
275 /* day is now the number of days since 'Jan 1 1970' */
277 // coverity[store_truncates_time_t]
278 t
->tm_wday
= (day
+ 4) % i
; /* Sunday=0, Monday=1, ..., Saturday=6 */
283 return ((day
+ t
->tm_hour
) * i
+ t
->tm_min
) * i
+ t
->tm_sec
;