/* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * * Copyright 1998-2004 The OpenLDAP Foundation. * Portions Copyright 1998 A. Hartgers. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP * Public License. * * A copy of this license is available in the file LICENSE in the * top-level directory of the distribution or, alternatively, at * . */ /* ACKNOWLEDGEMENTS: * This work was initially developed by Bart Hartgers for inclusion in * OpenLDAP Software. */ /* * util-int.c Various functions to replace missing threadsafe ones. * Without the real *_r funcs, things will * work, but might not be threadsafe. */ #include "portable.h" #include #include #include #include #include #include #include "ldap-int.h" #ifndef h_errno /* newer systems declare this in for you, older ones don't. * harmless to declare it again (unless defined by a macro). */ extern int h_errno; #endif #ifdef HAVE_HSTRERROR # define HSTRERROR(e) hstrerror(e) #else # define HSTRERROR(e) hp_strerror(e) #endif #ifndef LDAP_R_COMPILE # undef HAVE_REENTRANT_FUNCTIONS # undef HAVE_CTIME_R # undef HAVE_GETHOSTBYNAME_R # undef HAVE_GETHOSTBYADDR_R #else # include ldap_pvt_thread_mutex_t ldap_int_resolv_mutex; #if (defined( HAVE_CTIME_R ) || defined( HAVE_REENTRANT_FUNCTIONS)) \ && defined( CTIME_R_NARGS ) # define USE_CTIME_R # else static ldap_pvt_thread_mutex_t ldap_int_ctime_mutex; # endif # if defined(HAVE_GETHOSTBYNAME_R) && \ (GETHOSTBYNAME_R_NARGS < 5) || (6 < GETHOSTBYNAME_R_NARGS) /* Don't know how to handle this version, pretend it's not there */ # undef HAVE_GETHOSTBYNAME_R # endif # if defined(HAVE_GETHOSTBYADDR_R) && \ (GETHOSTBYADDR_R_NARGS < 7) || (8 < GETHOSTBYADDR_R_NARGS) /* Don't know how to handle this version, pretend it's not there */ # undef HAVE_GETHOSTBYADDR_R # endif #endif /* LDAP_R_COMPILE */ char *ldap_pvt_ctime( const time_t *tp, char *buf ) { #ifdef USE_CTIME_R # if (CTIME_R_NARGS > 3) || (CTIME_R_NARGS < 2) # error "CTIME_R_NARGS should be 2 or 3" # elif CTIME_R_NARGS > 2 && defined(CTIME_R_RETURNS_INT) return( ctime_r(tp,buf,26) < 0 ? 0 : buf ); # elif CTIME_R_NARGS > 2 return ctime_r(tp,buf,26); # else return ctime_r(tp,buf); # endif #else # ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_lock( &ldap_int_ctime_mutex ); # endif AC_MEMCPY( buf, ctime(tp), 26 ); # ifdef LDAP_R_COMPILE ldap_pvt_thread_mutex_unlock( &ldap_int_ctime_mutex ); # endif return buf; #endif } #define BUFSTART (1024-32) #define BUFMAX (32*1024-32) static char *safe_realloc( char **buf, int len ); #if !defined(HAVE_GETHOSTBYNAME_R) && defined(LDAP_R_COMPILE) static int copy_hostent( struct hostent *res, char **buf, struct hostent * src ); #endif int ldap_pvt_gethostbyname_a( const char *name, struct hostent *resbuf, char **buf, struct hostent **result, int *herrno_ptr ) { #if defined( HAVE_GETHOSTBYNAME_R ) # define NEED_SAFE_REALLOC 1 int r=-1; int buflen=BUFSTART; *buf = NULL; for(;buflensa_family == AF_INET6) { struct sockaddr_in6 *sin = (struct sockaddr_in6 *)sa; addr = (char *)&sin->sin6_addr; alen = sizeof(sin->sin6_addr); } else #endif if (sa->sa_family == AF_INET) { struct sockaddr_in *sin = (struct sockaddr_in *)sa; addr = (char *)&sin->sin_addr; alen = sizeof(sin->sin_addr); } else { rc = NO_RECOVERY; *err = (char *)HSTRERROR( rc ); return rc; } #if defined( HAVE_GETHOSTBYADDR_R ) for(;buflensa_family, &hb, buf, buflen, &h_errno ); rc = (hp == NULL) ? -1 : 0; #else rc = gethostbyaddr_r( addr, alen, sa->sa_family, &hb, buf, buflen, &hp, &h_errno ); #endif #ifdef NETDB_INTERNAL if ((rc<0) && (h_errno==NETDB_INTERNAL) && (errno==ERANGE)) { buflen*=2; continue; } #endif break; } if (hp) { strncpy( name, hp->h_name, namelen ); } else { *err = (char *)HSTRERROR( h_errno ); } LDAP_FREE(buf); #else /* HAVE_GETHOSTBYADDR_R */ #if defined( LDAP_R_COMPILE ) ldap_pvt_thread_mutex_lock( &ldap_int_resolv_mutex ); #endif hp = gethostbyaddr( addr, alen, sa->sa_family ); if (hp) { strncpy( name, hp->h_name, namelen ); rc = 0; } else { rc = h_errno; *err = (char *)hp_strerror( h_errno ); } #if defined( LDAP_R_COMPILE ) ldap_pvt_thread_mutex_unlock( &ldap_int_resolv_mutex ); #endif #endif /* !HAVE_GETHOSTBYADDR_R */ return rc; #endif /* !HAVE_GETNAMEINFO */ } int ldap_pvt_gethostbyaddr_a( const char *addr, int len, int type, struct hostent *resbuf, char **buf, struct hostent **result, int *herrno_ptr ) { #if defined( HAVE_GETHOSTBYADDR_R ) # undef NEED_SAFE_REALLOC # define NEED_SAFE_REALLOC int r=-1; int buflen=BUFSTART; *buf = NULL; for(;buflenh_name ) + 1; if( src->h_aliases != NULL ) { for( p = src->h_aliases; (*p) != NULL; p++ ) { total_alias_len += strlen( *p ) + 1; n_alias++; } } if( src->h_addr_list != NULL ) { for( p = src->h_addr_list; (*p) != NULL; p++ ) { n_addr++; } total_addr_len = n_addr * src->h_length; } total_len = (n_alias + n_addr + 2) * sizeof( char * ) + total_addr_len + total_alias_len + name_len; if (safe_realloc( buf, total_len )) { tp = (char **) *buf; tbuf = *buf + (n_alias + n_addr + 2) * sizeof( char * ); AC_MEMCPY( res, src, sizeof( struct hostent ) ); /* first the name... */ AC_MEMCPY( tbuf, src->h_name, name_len ); res->h_name = tbuf; tbuf+=name_len; /* now the aliases */ res->h_aliases = tp; if ( src->h_aliases != NULL ) { tbuf = cpy_aliases( &tp, tbuf, src->h_aliases ); } *tp++=NULL; /* finally the addresses */ res->h_addr_list = tp; if ( src->h_addr_list != NULL ) { tbuf = cpy_addresses( &tp, tbuf, src->h_addr_list, src->h_length ); } *tp++=NULL; return 0; } return -1; } #endif #if defined( NEED_SAFE_REALLOC ) static char *safe_realloc( char **buf, int len ) { char *tmpbuf; tmpbuf = LDAP_REALLOC( *buf, len ); if (tmpbuf) { *buf=tmpbuf; } return tmpbuf; } #endif char * ldap_pvt_get_fqdn( char *name ) { char *fqdn, *ha_buf; char hostbuf[MAXHOSTNAMELEN+1]; struct hostent *hp, he_buf; int rc, local_h_errno; if( name == NULL ) { if( gethostname( hostbuf, MAXHOSTNAMELEN ) == 0 ) { hostbuf[MAXHOSTNAMELEN] = '\0'; name = hostbuf; } else { name = "localhost"; } } rc = ldap_pvt_gethostbyname_a( name, &he_buf, &ha_buf, &hp, &local_h_errno ); if( rc < 0 || hp == NULL || hp->h_name == NULL ) { fqdn = LDAP_STRDUP( name ); } else { fqdn = LDAP_STRDUP( hp->h_name ); } LDAP_FREE( ha_buf ); return fqdn; } #if ( defined( HAVE_GETADDRINFO ) || defined( HAVE_GETNAMEINFO ) ) \ && !defined( HAVE_GAI_STRERROR ) char *ldap_pvt_gai_strerror (int code) { static struct { int code; const char *msg; } values[] = { #ifdef EAI_ADDRFAMILY { EAI_ADDRFAMILY, N_("Address family for hostname not supported") }, #endif { EAI_AGAIN, N_("Temporary failure in name resolution") }, { EAI_BADFLAGS, N_("Bad value for ai_flags") }, { EAI_FAIL, N_("Non-recoverable failure in name resolution") }, { EAI_FAMILY, N_("ai_family not supported") }, { EAI_MEMORY, N_("Memory allocation failure") }, #ifdef EAI_NODATA { EAI_NODATA, N_("No address associated with hostname") }, #endif { EAI_NONAME, N_("Name or service not known") }, { EAI_SERVICE, N_("Servname not supported for ai_socktype") }, { EAI_SOCKTYPE, N_("ai_socktype not supported") }, { EAI_SYSTEM, N_("System error") }, { 0, NULL } }; int i; for ( i = 0; values[i].msg != NULL; i++ ) { if ( values[i].code == code ) { return (char *) _(values[i].msg); } } return _("Unknown error"); } #endif