| 1 | /// ----------------------------------------*- mode: C++; -*--
 | 
|---|
| 2 | /// @file threadsafe_db.cpp
 | 
|---|
| 3 | /// Thread-safe access for some resolving functions (netdb)...
 | 
|---|
| 4 | /// ----------------------------------------------------------
 | 
|---|
| 5 | /// $Id: threadsafe_db.cpp 2872 2008-02-18 10:58:03Z bless $
 | 
|---|
| 6 | /// $HeadURL: https://svn.ipv6.tm.uka.de/nsis/protlib/trunk/src/threadsafe_db.cpp $
 | 
|---|
| 7 | // ===========================================================
 | 
|---|
| 8 | //                      
 | 
|---|
| 9 | // Copyright (C) 2005-2007, all rights reserved by
 | 
|---|
| 10 | // - Institute of Telematics, Universitaet Karlsruhe (TH)
 | 
|---|
| 11 | //
 | 
|---|
| 12 | // More information and contact:
 | 
|---|
| 13 | // https://projekte.tm.uka.de/trac/NSIS
 | 
|---|
| 14 | //                      
 | 
|---|
| 15 | // This program is free software; you can redistribute it and/or modify
 | 
|---|
| 16 | // it under the terms of the GNU General Public License as published by
 | 
|---|
| 17 | // the Free Software Foundation; version 2 of the License
 | 
|---|
| 18 | //
 | 
|---|
| 19 | // This program is distributed in the hope that it will be useful,
 | 
|---|
| 20 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
|---|
| 21 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
|---|
| 22 | // GNU General Public License for more details.
 | 
|---|
| 23 | //
 | 
|---|
| 24 | // You should have received a copy of the GNU General Public License along
 | 
|---|
| 25 | // with this program; if not, write to the Free Software Foundation, Inc.,
 | 
|---|
| 26 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 | 
|---|
| 27 | //
 | 
|---|
| 28 | // ===========================================================
 | 
|---|
| 29 | /** @ingroup protlib
 | 
|---|
| 30 |  *
 | 
|---|
| 31 |  * As the reentrant functions for netdb access seem not portable, I decided to 
 | 
|---|
| 32 |  * write some wrappers for those functions I need. This is not 
 | 
|---|
| 33 |  * object-oriented because the NetDB would be another singleton object and
 | 
|---|
| 34 |  * I only want some wrapper functions.
 | 
|---|
| 35 |  */
 | 
|---|
| 36 | 
 | 
|---|
| 37 | #include <netdb.h>
 | 
|---|
| 38 | #include <pwd.h>
 | 
|---|
| 39 | #include <netinet/in.h>
 | 
|---|
| 40 | #include <cerrno>
 | 
|---|
| 41 | 
 | 
|---|
| 42 | #include "threadsafe_db.h"
 | 
|---|
| 43 | #include "cleanuphandler.h"
 | 
|---|
| 44 | #include "logfile.h"
 | 
|---|
| 45 | 
 | 
|---|
| 46 | namespace protlib { 
 | 
|---|
| 47 | 
 | 
|---|
| 48 | /** @addtogroup protlib
 | 
|---|
| 49 |  * @{
 | 
|---|
| 50 |  */
 | 
|---|
| 51 | 
 | 
|---|
| 52 |   using namespace log;
 | 
|---|
| 53 | 
 | 
|---|
| 54 | bool tsdb::is_init = false;
 | 
|---|
| 55 | bool tsdb::resolvenames = true;
 | 
|---|
| 56 | pthread_mutex_t tsdb::mutex = 
 | 
|---|
| 57 | #ifdef _DEBUG
 | 
|---|
| 58 |     PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
 | 
|---|
| 59 | #else
 | 
|---|
| 60 |     PTHREAD_MUTEX_INITIALIZER;
 | 
|---|
| 61 | #endif
 | 
|---|
| 62 | 
 | 
|---|
| 63 | 
 | 
|---|
| 64 | uint32 tsdb::id32 = 1;
 | 
|---|
| 65 | uint64 tsdb::id64 = 1;
 | 
|---|
| 66 | 
 | 
|---|
| 67 | protocol_t tsdb::udp_id= 17;
 | 
|---|
| 68 | protocol_t tsdb::tcp_id= 6;
 | 
|---|
| 69 | protocol_t tsdb::sctp_id= 132;
 | 
|---|
| 70 | 
 | 
|---|
| 71 | 
 | 
|---|
| 72 | void 
 | 
|---|
| 73 | tsdb::init(bool noresolving) 
 | 
|---|
| 74 | {
 | 
|---|
| 75 |   if (is_init) 
 | 
|---|
| 76 |   {
 | 
|---|
| 77 |     Log(ERROR_LOG,LOG_NORMAL, "Threadsafe_DB", "Tried to initialize tstdb although already initialized.");
 | 
|---|
| 78 |   } else 
 | 
|---|
| 79 |   {
 | 
|---|
| 80 |     pthread_mutex_init(&mutex,NULL);
 | 
|---|
| 81 |     is_init = true;
 | 
|---|
| 82 | 
 | 
|---|
| 83 |     // initialize frequently used protocol constants
 | 
|---|
| 84 |     udp_id= tsdb::getprotobyname("udp");
 | 
|---|
| 85 |     tcp_id= tsdb::getprotobyname("tcp");
 | 
|---|
| 86 |     sctp_id= tsdb::getprotobyname("sctp");
 | 
|---|
| 87 | 
 | 
|---|
| 88 |     resolvenames=!noresolving;
 | 
|---|
| 89 |     if (!resolvenames) 
 | 
|---|
| 90 |       Log(INFO_LOG,LOG_NORMAL,"Threadsafe_DB"," ** Disabled reverse name lookups - addresses will not be resolved to names **");
 | 
|---|
| 91 |   } // end if is_init
 | 
|---|
| 92 | } // end init
 | 
|---|
| 93 |   
 | 
|---|
| 94 | void tsdb::end() {
 | 
|---|
| 95 |         if (is_init) {
 | 
|---|
| 96 |                 is_init = false;
 | 
|---|
| 97 |                 pthread_mutex_destroy(&mutex);
 | 
|---|
| 98 |         } else {
 | 
|---|
| 99 |           Log(ERROR_LOG,LOG_NORMAL, "Threadsafe_DB", "Tried to end tstdb although not initialized.");
 | 
|---|
| 100 |         } // end if is_init
 | 
|---|
| 101 | } // end end
 | 
|---|
| 102 | 
 | 
|---|
| 103 | uint32 tsdb::get_new_id32() {
 | 
|---|
| 104 |         uint32 res = 0;
 | 
|---|
| 105 |         if (is_init) {
 | 
|---|
| 106 |                 pthread_mutex_lock(&mutex); // install_cleanup_mutex_lock(&mutex);
 | 
|---|
| 107 |                 res = id32++;
 | 
|---|
| 108 |                 pthread_mutex_unlock(&mutex); // uninstall_cleanup(1);
 | 
|---|
| 109 |         } else {
 | 
|---|
| 110 |           Log(ERROR_LOG,LOG_NORMAL, "Threadsafe_DB", "Tried to access tsdb although not initialized.");
 | 
|---|
| 111 |         } // end if is_init
 | 
|---|
| 112 |         return res;
 | 
|---|
| 113 | } // end get_new_id32
 | 
|---|
| 114 | 
 | 
|---|
| 115 | uint64 tsdb::get_new_id64() {
 | 
|---|
| 116 |         uint64 res = 0;
 | 
|---|
| 117 |         if (is_init) {
 | 
|---|
| 118 |                 pthread_mutex_lock(&mutex); // install_cleanup_mutex_lock(&mutex);
 | 
|---|
| 119 |                 res = id64++;
 | 
|---|
| 120 |                 pthread_mutex_unlock(&mutex); // uninstall_cleanup(1);
 | 
|---|
| 121 |         } else {
 | 
|---|
| 122 |           Log(ERROR_LOG,LOG_NORMAL, "Threadsafe_DB", "Tried to access tsdb although not initialized.");
 | 
|---|
| 123 |         } // end if is_init
 | 
|---|
| 124 |         return res;
 | 
|---|
| 125 | } // end get_new_id64
 | 
|---|
| 126 | 
 | 
|---|
| 127 | string tsdb::getprotobynumber(protocol_t proto, bool *res) {
 | 
|---|
| 128 |         string str;
 | 
|---|
| 129 |         if (is_init) 
 | 
|---|
| 130 |         {
 | 
|---|
| 131 |                 pthread_mutex_lock(&mutex); // install_cleanup_mutex_lock(&mutex);
 | 
|---|
| 132 |                 struct protoent* entry = ::getprotobynumber(proto);
 | 
|---|
| 133 | 
 | 
|---|
| 134 |                 if (res) *res = (entry!=NULL);
 | 
|---|
| 135 |                 if (entry) 
 | 
|---|
| 136 |                   str = entry->p_name;
 | 
|---|
| 137 |                 else 
 | 
|---|
| 138 |                   str = "UNKNOWN";
 | 
|---|
| 139 | 
 | 
|---|
| 140 |                 pthread_mutex_unlock(&mutex); // uninstall_cleanup(1);
 | 
|---|
| 141 |         } 
 | 
|---|
| 142 |         else 
 | 
|---|
| 143 |         {
 | 
|---|
| 144 |           Log(ERROR_LOG,LOG_NORMAL, "Threadsafe_DB", "Tried to access tsdb although not initialized.");
 | 
|---|
| 145 |           if (res) *res = false;
 | 
|---|
| 146 |           str = "";
 | 
|---|
| 147 |         } // end if is_init
 | 
|---|
| 148 |         return str;
 | 
|---|
| 149 | } // end getprotobynumber
 | 
|---|
| 150 | 
 | 
|---|
| 151 | protocol_t tsdb::getprotobyname(const string &pname, bool *res) {
 | 
|---|
| 152 |         return getprotobyname(pname.c_str(),res);
 | 
|---|
| 153 | } // end getprotobyname
 | 
|---|
| 154 | 
 | 
|---|
| 155 | protocol_t tsdb::getprotobyname(const char* pname, bool *res) {
 | 
|---|
| 156 |         register protocol_t pnum;
 | 
|---|
| 157 |         struct protoent* entry = NULL;
 | 
|---|
| 158 |         if (is_init) {
 | 
|---|
| 159 |                 pthread_mutex_lock(&mutex); // install_cleanup_mutex_lock(&mutex);
 | 
|---|
| 160 |                 if (pname) entry = ::getprotobyname(pname);
 | 
|---|
| 161 |                 if (res) *res = (entry!=NULL);
 | 
|---|
| 162 |                 if (entry) pnum = entry->p_proto;
 | 
|---|
| 163 |                 else pnum = 0;
 | 
|---|
| 164 |                 pthread_mutex_unlock(&mutex); // uninstall_cleanup(1);
 | 
|---|
| 165 |         } else {
 | 
|---|
| 166 |           Log(ERROR_LOG,LOG_NORMAL, "Threadsafe_DB", "Tried to access tsdb although not initialized.");
 | 
|---|
| 167 |           if (res) *res = false;
 | 
|---|
| 168 |           pnum = 0;
 | 
|---|
| 169 |         } // end if is_init
 | 
|---|
| 170 |         return pnum;
 | 
|---|
| 171 | } // end getprotobyname
 | 
|---|
| 172 | 
 | 
|---|
| 173 | string tsdb::get_username(uid_t uid, bool *res) {
 | 
|---|
| 174 |         string str;
 | 
|---|
| 175 |         if (is_init) {
 | 
|---|
| 176 |                 pthread_mutex_lock(&mutex); // install_cleanup_mutex_lock(&mutex);
 | 
|---|
| 177 |                 struct passwd* entry = ::getpwuid(uid);
 | 
|---|
| 178 |                 if (res) *res = (entry!=NULL);
 | 
|---|
| 179 |                 if (entry) str = entry->pw_name;
 | 
|---|
| 180 |                 else str = "UNKNOWN";
 | 
|---|
| 181 |                 pthread_mutex_unlock(&mutex); // uninstall_cleanup(1);
 | 
|---|
| 182 |         } else {
 | 
|---|
| 183 |           Log(ERROR_LOG,LOG_NORMAL, "Threadsafe_DB", "Tried to access tsdb although not initialized.");
 | 
|---|
| 184 |           if (res) *res = false;
 | 
|---|
| 185 |           str = "";
 | 
|---|
| 186 |         } // end if is_init
 | 
|---|
| 187 |         return str;
 | 
|---|
| 188 | } // end get_username
 | 
|---|
| 189 | 
 | 
|---|
| 190 | uid_t tsdb::get_userid(const char* uname, bool *res) {
 | 
|---|
| 191 |         register uid_t uid;
 | 
|---|
| 192 |         struct passwd* entry = NULL;
 | 
|---|
| 193 |         if (is_init) {
 | 
|---|
| 194 |                 pthread_mutex_lock(&mutex); // install_cleanup_mutex_lock(&mutex);
 | 
|---|
| 195 |                 if (uname) entry = ::getpwnam(uname);
 | 
|---|
| 196 |                 if (res) *res = (entry!=NULL);
 | 
|---|
| 197 |                 if (entry) uid = entry->pw_uid;
 | 
|---|
| 198 |                 else uid = 0;
 | 
|---|
| 199 |                 pthread_mutex_unlock(&mutex); // uninstall_cleanup(1);
 | 
|---|
| 200 |         } else {
 | 
|---|
| 201 |           Log(ERROR_LOG,LOG_NORMAL, "Threadsafe_DB", "Tried to access tsdb although not initialized.");
 | 
|---|
| 202 |           if (res) *res = false;
 | 
|---|
| 203 |           uid = 0;
 | 
|---|
| 204 |         } // end if is_init
 | 
|---|
| 205 |         return uid;
 | 
|---|
| 206 | } // end get_userid
 | 
|---|
| 207 | 
 | 
|---|
| 208 | uid_t tsdb::get_userid(const string& uname, bool *res) {
 | 
|---|
| 209 |         return get_userid(uname.c_str(),res);
 | 
|---|
| 210 | } // end get_userid
 | 
|---|
| 211 | 
 | 
|---|
| 212 | string tsdb::get_portname(port_t port, protocol_t prot, bool *res) {
 | 
|---|
| 213 |         string str;
 | 
|---|
| 214 |         if (is_init) {
 | 
|---|
| 215 |                 bool tmpres = true;
 | 
|---|
| 216 |                 string pname = getprotobynumber(prot,&tmpres);
 | 
|---|
| 217 |                 if (tmpres) {
 | 
|---|
| 218 |                         pthread_mutex_lock(&mutex); // install_cleanup_mutex_lock(&mutex);
 | 
|---|
| 219 |                         struct servent* entry = ::getservbyport(htons(port),pname.c_str());
 | 
|---|
| 220 |                         if (res) *res = (entry!=NULL);
 | 
|---|
| 221 |                         if (entry) str = entry->s_name;
 | 
|---|
| 222 |                         else str = "UNKNOWN";
 | 
|---|
| 223 |                         pthread_mutex_unlock(&mutex); // uninstall_cleanup(1);
 | 
|---|
| 224 |                 } else {
 | 
|---|
| 225 |                         if (res) *res = false;
 | 
|---|
| 226 |                         str = "UNKNOWN";
 | 
|---|
| 227 |                 } // end if tmpres
 | 
|---|
| 228 |         } else {
 | 
|---|
| 229 |           Log(ERROR_LOG,LOG_NORMAL, "Threadsafe_DB", "Tried to access tsdb although not initialized.");
 | 
|---|
| 230 |           if (res) *res = false;
 | 
|---|
| 231 |           str = "";
 | 
|---|
| 232 |         } // end if is_init
 | 
|---|
| 233 |         return str;
 | 
|---|
| 234 | } // end get_portname
 | 
|---|
| 235 | 
 | 
|---|
| 236 | port_t tsdb::get_portnumber(const char* pname, protocol_t prot, bool *res) {
 | 
|---|
| 237 |         register port_t pnum;
 | 
|---|
| 238 |         struct servent* entry = NULL;
 | 
|---|
| 239 |         if (is_init) {
 | 
|---|
| 240 |                 bool tmpres = true;
 | 
|---|
| 241 |                 string protoname = getprotobynumber(prot,&tmpres);
 | 
|---|
| 242 |                 if (tmpres) {
 | 
|---|
| 243 |                         pthread_mutex_lock(&mutex); // install_cleanup_mutex_lock(&mutex);
 | 
|---|
| 244 |                         if (pname) entry = ::getservbyname(pname,protoname.c_str());
 | 
|---|
| 245 |                         if (res) *res = (entry!=NULL);
 | 
|---|
| 246 |                         if (entry) pnum = ntohs(entry->s_port);
 | 
|---|
| 247 |                         else pnum = 0;
 | 
|---|
| 248 |                         pthread_mutex_unlock(&mutex); // uninstall_cleanup(1);
 | 
|---|
| 249 |                 } else {
 | 
|---|
| 250 |                         if (res) *res = false;
 | 
|---|
| 251 |                         pnum = 0;
 | 
|---|
| 252 |                 } // end if tmpres
 | 
|---|
| 253 |         } else {
 | 
|---|
| 254 |           Log(ERROR_LOG,LOG_NORMAL, "Threadsafe_DB", "Tried to access tsdb although not initialized.");
 | 
|---|
| 255 |           if (res) *res = false;
 | 
|---|
| 256 |           pnum = 0;
 | 
|---|
| 257 |         } // end if is_init
 | 
|---|
| 258 |         return pnum;
 | 
|---|
| 259 | } // end get_portnumber
 | 
|---|
| 260 | 
 | 
|---|
| 261 | port_t tsdb::get_portnumber(const string& pname, protocol_t prot, bool *res) {
 | 
|---|
| 262 |         return get_portnumber(pname.c_str(),prot,res);
 | 
|---|
| 263 | } // end get_portnumber
 | 
|---|
| 264 | 
 | 
|---|
| 265 | 
 | 
|---|
| 266 | string 
 | 
|---|
| 267 | tsdb::get_hostname(const struct sockaddr* sa, bool *res) 
 | 
|---|
| 268 | {
 | 
|---|
| 269 |   string str;
 | 
|---|
| 270 |   static char tmpbuf[NI_MAXHOST];
 | 
|---|
| 271 | 
 | 
|---|
| 272 |   if (is_init) 
 | 
|---|
| 273 |   {
 | 
|---|
| 274 |     pthread_mutex_lock(&mutex); // install_cleanup_mutex_lock(&mutex);
 | 
|---|
| 275 |     if (resolvenames)
 | 
|---|
| 276 |     {
 | 
|---|
| 277 |       int resultval= getnameinfo(sa,sizeof(struct sockaddr),
 | 
|---|
| 278 |                                  tmpbuf,sizeof(tmpbuf),
 | 
|---|
| 279 |                                  0,0, // services
 | 
|---|
| 280 |                                  0);  // flags
 | 
|---|
| 281 |       
 | 
|---|
| 282 |       if (res) *res = (resultval==0);
 | 
|---|
| 283 |       if (resultval==0)
 | 
|---|
| 284 |       { // success
 | 
|---|
| 285 |         str= tmpbuf; // this should copy the buffer contents
 | 
|---|
| 286 |       }
 | 
|---|
| 287 |       else
 | 
|---|
| 288 |       {
 | 
|---|
| 289 |         str = "UNKNOWN";
 | 
|---|
| 290 |         if (resultval==EAI_AGAIN || errno==EAI_AGAIN)
 | 
|---|
| 291 |         {
 | 
|---|
| 292 |           Log(INFO_LOG,LOG_NORMAL, "Threadsafe_DB", "Temporary failure in name lookup. Try again later.");
 | 
|---|
| 293 |         }
 | 
|---|
| 294 |         else
 | 
|---|
| 295 |           Log(INFO_LOG,LOG_NORMAL, "Threadsafe_DB", "Name lookup failed -" << strerror(errno));
 | 
|---|
| 296 | 
 | 
|---|
| 297 |         if (res) *res= false;
 | 
|---|
| 298 |       }
 | 
|---|
| 299 |     }
 | 
|---|
| 300 |     else
 | 
|---|
| 301 |     {
 | 
|---|
| 302 |       str= "disabled";
 | 
|---|
| 303 |       if (res) *res= false;
 | 
|---|
| 304 |     }
 | 
|---|
| 305 |     pthread_mutex_unlock(&mutex); // uninstall_cleanup(1);
 | 
|---|
| 306 |   }
 | 
|---|
| 307 |   else 
 | 
|---|
| 308 |   {
 | 
|---|
| 309 |     Log(ERROR_LOG,LOG_NORMAL, "Threadsafe_DB", "Tried to access tsdb although not initialized.");
 | 
|---|
| 310 |     if (res) *res = false;
 | 
|---|
| 311 |     str = "";
 | 
|---|
| 312 |   } // end if is_init
 | 
|---|
| 313 |   return str;
 | 
|---|
| 314 | } // ent get_hostname(in_addr)
 | 
|---|
| 315 | 
 | 
|---|
| 316 | 
 | 
|---|
| 317 | 
 | 
|---|
| 318 | /** lookup of hostname for an ipv4 address
 | 
|---|
| 319 |  *  @param in ipv4 address structure
 | 
|---|
| 320 |  *  @param res returns true if name lookup was successful, otherwise false
 | 
|---|
| 321 |  *
 | 
|---|
| 322 |  *  @return in case that resolving is enabled it returns the host name corresponding to the given address or "UNKNOWN", 
 | 
|---|
| 323 |  *           otherwise it returns "disabled"
 | 
|---|
| 324 |  */
 | 
|---|
| 325 | string 
 | 
|---|
| 326 | tsdb::get_hostname(const in_addr& in, bool *res) 
 | 
|---|
| 327 | {
 | 
|---|
| 328 |   struct sockaddr_in sa={
 | 
|---|
| 329 |     AF_INET,
 | 
|---|
| 330 |     0,
 | 
|---|
| 331 |     in
 | 
|---|
| 332 |   };
 | 
|---|
| 333 |   return get_hostname(reinterpret_cast<const sockaddr*>(&sa),res);
 | 
|---|
| 334 | }
 | 
|---|
| 335 | 
 | 
|---|
| 336 | /** lookup of hostname for ipv6 address
 | 
|---|
| 337 |  *  @param in ipv6 address structure
 | 
|---|
| 338 |  *  @param res returns true if name lookup was successful, otherwise false
 | 
|---|
| 339 |  *
 | 
|---|
| 340 |  *  @return in case that resolving is enabled it returns the host name corresponding to the given address or "UNKNOWN", 
 | 
|---|
| 341 |  *           otherwise it returns "disabled"
 | 
|---|
| 342 |  */
 | 
|---|
| 343 | string 
 | 
|---|
| 344 | tsdb::get_hostname(const in6_addr& in, bool *res) 
 | 
|---|
| 345 | {
 | 
|---|
| 346 |   struct sockaddr_in6 sa={
 | 
|---|
| 347 |     AF_INET6,
 | 
|---|
| 348 |     0, // transport layer port #
 | 
|---|
| 349 |     0, // IPv6 flow information
 | 
|---|
| 350 |     in,
 | 
|---|
| 351 |     0  // scope id (new in RFC2553)
 | 
|---|
| 352 |   };
 | 
|---|
| 353 |   return get_hostname(reinterpret_cast<const sockaddr*>(&sa),res);
 | 
|---|
| 354 | } // ent get_hostname(in6_addr)
 | 
|---|
| 355 | 
 | 
|---|
| 356 | //@}
 | 
|---|
| 357 | 
 | 
|---|
| 358 | } // end namespace protlib
 | 
|---|