LCOV - code coverage report
Current view: top level - shishi/lib - netio.c (source / functions) Hit Total Coverage
Test: GNU Shishi Lines: 0 171 0.0 %
Date: 2010-05-20 Functions: 0 9 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 90 0.0 %

           Branch data     Line data    Source code
       1                 :            : /* netio.c --- Network I/O functions.
       2                 :            :  * Copyright (C) 2002, 2003, 2004, 2006, 2007, 2008, 2010  Simon Josefsson
       3                 :            :  *
       4                 :            :  * This file is part of Shishi.
       5                 :            :  *
       6                 :            :  * Shishi is free software; you can redistribute it and/or modify it
       7                 :            :  * under the terms of the GNU General Public License as published by
       8                 :            :  * the Free Software Foundation; either version 3 of the License, or
       9                 :            :  * (at your option) any later version.
      10                 :            :  *
      11                 :            :  * Shishi is distributed in the hope that it will be useful, but
      12                 :            :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      13                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14                 :            :  * GNU General Public License for more details.
      15                 :            :  *
      16                 :            :  * You should have received a copy of the GNU General Public License
      17                 :            :  * along with Shishi; if not, see http://www.gnu.org/licenses or write
      18                 :            :  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
      19                 :            :  * Floor, Boston, MA 02110-1301, USA
      20                 :            :  *
      21                 :            :  */
      22                 :            : 
      23                 :            : #include "internal.h"
      24                 :            : 
      25                 :            : /* Get _shishi_sendrecv_tls, etc. */
      26                 :            : #include "starttls.h"
      27                 :            : 
      28                 :            : /* Get _shishi_realminfo, etc. */
      29                 :            : #include "diskio.h"
      30                 :            : 
      31                 :            : /* Get _shishi_realminfo. */
      32                 :            : #include "cfg.h"
      33                 :            : 
      34                 :            : static int
      35                 :          0 : sendrecv_udp (Shishi * handle,
      36                 :            :               struct addrinfo *ai,
      37                 :            :               const char *indata, int inlen, char **outdata, size_t * outlen)
      38                 :            : {
      39                 :            :   char tmpbuf[BUFSIZ];          /* XXX can we do without it?
      40                 :            :                                    MSG_PEEK|MSG_TRUNC doesn't work for udp.. */
      41                 :            :   int sockfd;
      42                 :            :   int bytes_sent;
      43                 :            :   fd_set readfds;
      44                 :            :   struct timeval tout;
      45                 :            :   ssize_t slen;
      46                 :            :   int rc;
      47                 :            : 
      48                 :          0 :   sockfd = socket (ai->ai_family, ai->ai_socktype, ai->ai_protocol);
      49         [ #  # ]:          0 :   if (sockfd < 0)
      50                 :            :     {
      51                 :          0 :       shishi_error_set (handle, strerror (errno));
      52                 :          0 :       return SHISHI_SOCKET_ERROR;
      53                 :            :     }
      54                 :            : 
      55         [ #  # ]:          0 :   if (connect (sockfd, ai->ai_addr, ai->ai_addrlen) != 0)
      56                 :            :     {
      57                 :          0 :       shishi_error_set (handle, strerror (errno));
      58                 :          0 :       close (sockfd);
      59                 :          0 :       return SHISHI_BIND_ERROR;
      60                 :            :     }
      61                 :            : 
      62                 :          0 :   bytes_sent = write (sockfd, indata, inlen);
      63         [ #  # ]:          0 :   if (bytes_sent != inlen)
      64                 :            :     {
      65                 :          0 :       shishi_error_set (handle, strerror (errno));
      66                 :          0 :       close (sockfd);
      67                 :          0 :       return SHISHI_SENDTO_ERROR;
      68                 :            :     }
      69                 :            : 
      70                 :          0 :   FD_ZERO (&readfds);
      71                 :          0 :   FD_SET (sockfd, &readfds);
      72                 :          0 :   tout.tv_sec = handle->kdctimeout;
      73                 :          0 :   tout.tv_usec = 0;
      74         [ #  # ]:          0 :   if ((rc = select (sockfd + 1, &readfds, NULL, NULL, &tout)) != 1)
      75                 :            :     {
      76         [ #  # ]:          0 :       if (rc == -1)
      77                 :          0 :         shishi_error_set (handle, strerror (errno));
      78                 :            :       else
      79                 :          0 :         shishi_error_clear (handle);
      80                 :          0 :       close (sockfd);
      81                 :          0 :       return SHISHI_KDC_TIMEOUT;
      82                 :            :     }
      83                 :            : 
      84                 :          0 :   *outlen = sizeof (tmpbuf);
      85                 :          0 :   slen = read (sockfd, tmpbuf, *outlen);
      86         [ #  # ]:          0 :   if (slen == -1)
      87                 :            :     {
      88                 :          0 :       shishi_error_set (handle, strerror (errno));
      89                 :          0 :       close (sockfd);
      90                 :          0 :       return SHISHI_RECVFROM_ERROR;
      91                 :            :     }
      92                 :            : 
      93                 :          0 :   *outdata = xmalloc (slen);
      94                 :          0 :   *outlen = slen;
      95                 :          0 :   memcpy (*outdata, tmpbuf, slen);
      96                 :            : 
      97         [ #  # ]:          0 :   if (close (sockfd) != 0)
      98                 :            :     {
      99                 :          0 :       shishi_error_set (handle, strerror (errno));
     100                 :          0 :       return SHISHI_CLOSE_ERROR;
     101                 :            :     }
     102                 :            : 
     103                 :          0 :   return SHISHI_OK;
     104                 :            : }
     105                 :            : 
     106                 :            : static int
     107                 :          0 : sendrecv_tcp (Shishi * handle,
     108                 :            :               struct addrinfo *ai,
     109                 :            :               const char *indata, int inlen, char **outdata, size_t * outlen)
     110                 :            : {
     111                 :            :   char tmpbuf[BUFSIZ];          /* XXX can we do without it?
     112                 :            :                                    MSG_PEEK|MSG_TRUNC doesn't work for udp.. */
     113                 :            :   int sockfd;
     114                 :            :   int bytes_sent;
     115                 :            :   struct sockaddr_storage from_sa;
     116                 :          0 :   socklen_t length = sizeof (struct sockaddr_storage);
     117                 :            :   fd_set readfds;
     118                 :            :   struct timeval tout;
     119                 :            :   int rc;
     120                 :            :   ssize_t slen;
     121                 :            : 
     122                 :          0 :   sockfd = socket (ai->ai_family, ai->ai_socktype, ai->ai_protocol);
     123         [ #  # ]:          0 :   if (sockfd < 0)
     124                 :            :     {
     125                 :          0 :       shishi_error_set (handle, strerror (errno));
     126                 :          0 :       return SHISHI_SOCKET_ERROR;
     127                 :            :     }
     128                 :            : 
     129         [ #  # ]:          0 :   if (connect (sockfd, ai->ai_addr, ai->ai_addrlen) != 0)
     130                 :            :     {
     131                 :          0 :       shishi_error_set (handle, strerror (errno));
     132                 :          0 :       close (sockfd);
     133                 :          0 :       return SHISHI_BIND_ERROR;
     134                 :            :     }
     135                 :            : 
     136                 :          0 :   tmpbuf[3] = inlen & 0xFF;
     137                 :          0 :   tmpbuf[2] = (inlen >> 8) & 0xFF;
     138                 :          0 :   tmpbuf[1] = (inlen >> 16) & 0xFF;
     139                 :          0 :   tmpbuf[0] = (inlen >> 24) & 0xFF;
     140                 :            : 
     141                 :          0 :   bytes_sent = write (sockfd, tmpbuf, 4);
     142         [ #  # ]:          0 :   if (bytes_sent != 4)
     143                 :            :     {
     144                 :          0 :       shishi_error_set (handle, strerror (errno));
     145                 :          0 :       return SHISHI_SENDTO_ERROR;
     146                 :            :     }
     147                 :            : 
     148                 :          0 :   bytes_sent = write (sockfd, (const void *) indata, inlen);
     149         [ #  # ]:          0 :   if (bytes_sent != inlen)
     150                 :            :     {
     151                 :          0 :       shishi_error_set (handle, strerror (errno));
     152                 :          0 :       return SHISHI_SENDTO_ERROR;
     153                 :            :     }
     154                 :            : 
     155                 :          0 :   FD_ZERO (&readfds);
     156                 :          0 :   FD_SET (sockfd, &readfds);
     157                 :          0 :   tout.tv_sec = handle->kdctimeout;
     158                 :          0 :   tout.tv_usec = 0;
     159         [ #  # ]:          0 :   if ((rc = select (sockfd + 1, &readfds, NULL, NULL, &tout)) != 1)
     160                 :            :     {
     161         [ #  # ]:          0 :       if (rc == -1)
     162                 :          0 :         shishi_error_set (handle, strerror (errno));
     163                 :            :       else
     164                 :          0 :         shishi_error_clear (handle);
     165                 :          0 :       return SHISHI_KDC_TIMEOUT;
     166                 :            :     }
     167                 :            : 
     168                 :          0 :   *outlen = 4;
     169                 :          0 :   slen = recvfrom (sockfd, tmpbuf, *outlen, 0,
     170                 :            :                    (struct sockaddr *) &from_sa, &length);
     171         [ #  # ]:          0 :   if (slen == -1)
     172                 :            :     {
     173                 :          0 :       shishi_error_set (handle, strerror (errno));
     174                 :          0 :       return SHISHI_RECVFROM_ERROR;
     175                 :            :     }
     176                 :            : 
     177                 :          0 :   *outlen = sizeof (tmpbuf);
     178                 :          0 :   slen = recvfrom (sockfd, tmpbuf, *outlen, 0,
     179                 :            :                    (struct sockaddr *) &from_sa, &length);
     180         [ #  # ]:          0 :   if (slen == -1)
     181                 :            :     {
     182                 :          0 :       shishi_error_set (handle, strerror (errno));
     183                 :          0 :       return SHISHI_RECVFROM_ERROR;
     184                 :            :     }
     185                 :            : 
     186                 :          0 :   *outdata = xmalloc (slen);
     187                 :          0 :   *outlen = slen;
     188                 :          0 :   memcpy (*outdata, tmpbuf, slen);
     189                 :            : 
     190         [ #  # ]:          0 :   if (close (sockfd) != 0)
     191                 :            :     {
     192                 :          0 :       shishi_error_set (handle, strerror (errno));
     193                 :          0 :       return SHISHI_CLOSE_ERROR;
     194                 :            :     }
     195                 :            : 
     196                 :          0 :   return SHISHI_OK;
     197                 :            : }
     198                 :            : 
     199                 :            : static int
     200                 :          0 : sendrecv_host (Shishi * handle,
     201                 :            :                int transport, const char *host, const char *port,
     202                 :            :                const char *indata, size_t inlen,
     203                 :            :                char **outdata, size_t * outlen)
     204                 :            : {
     205                 :            :   struct addrinfo hints;
     206                 :            :   struct addrinfo *ai;
     207                 :            :   int rc;
     208                 :            : 
     209                 :          0 :   memset (&hints, 0, sizeof (hints));
     210 [ #  # ][ #  # ]:          0 :   if (transport == TCP || transport == TLS)
     211                 :          0 :     hints.ai_socktype = SOCK_STREAM;
     212                 :            :   else
     213                 :          0 :     hints.ai_socktype = SOCK_DGRAM;
     214                 :          0 :   hints.ai_flags = AI_ADDRCONFIG;
     215                 :            : 
     216         [ #  # ]:          0 :   if (port == NULL)
     217                 :          0 :     port = "88";
     218                 :            : 
     219                 :          0 :   rc = getaddrinfo (host, port, &hints, &ai);
     220         [ #  # ]:          0 :   if (rc != 0)
     221                 :            :     {
     222                 :          0 :       shishi_error_printf (handle, "Cannot find host %s", host);
     223                 :          0 :       return SHISHI_KDC_NOT_KNOWN_FOR_REALM;
     224                 :            :     }
     225                 :            : 
     226                 :            :   do
     227                 :            :     {
     228                 :            :       char nodename[NI_MAXHOST];
     229                 :          0 :       size_t j = 0;
     230                 :            : 
     231                 :          0 :       rc = getnameinfo (ai->ai_addr, ai->ai_addrlen,
     232                 :            :                         nodename, sizeof (nodename), NULL, 0, NI_NUMERICHOST);
     233         [ #  # ]:          0 :       shishi_verbose (handle, "Sending to %s (%s) port %s transport %s",
     234                 :            :                       host, rc == 0 ? nodename : "unknown address", port,
     235                 :            :                       _shishi_transport2string (transport));
     236                 :            : 
     237                 :            :       do
     238                 :            :         {
     239         [ #  # ]:          0 :           if (transport == TCP)
     240                 :          0 :             rc = sendrecv_tcp (handle, ai, indata, inlen, outdata, outlen);
     241                 :            : #ifdef USE_STARTTLS
     242         [ #  # ]:          0 :           else if (transport == TLS)
     243                 :          0 :             rc = _shishi_sendrecv_tls (handle, ai, indata, inlen,
     244                 :            :                                        outdata, outlen);
     245                 :            : #endif
     246                 :            :           else
     247                 :          0 :             rc = sendrecv_udp (handle, ai, indata, inlen, outdata, outlen);
     248                 :            : 
     249         [ #  # ]:          0 :           if (rc != SHISHI_OK)
     250                 :          0 :             shishi_verbose (handle, "Error sending to KDC: %s",
     251                 :            :                             shishi_strerror (rc));
     252                 :            :         }
     253 [ #  # ][ #  # ]:          0 :       while (rc == SHISHI_KDC_TIMEOUT && ++j < handle->kdcretries);
     254                 :            :     }
     255 [ #  # ][ #  # ]:          0 :   while (rc != SHISHI_OK && (ai = ai->ai_next));
     256                 :            : 
     257                 :          0 :   return rc;
     258                 :            : }
     259                 :            : 
     260                 :            : static int
     261                 :          0 : sendrecv_srv3 (Shishi * handle,
     262                 :            :                int transport,
     263                 :            :                const char *realm,
     264                 :            :                const char *indata, size_t inlen,
     265                 :            :                char **outdata, size_t * outlen,
     266                 :            :                Shishi_dns rrs, bool * found_srv_records)
     267                 :            : {
     268                 :          0 :   int rc = SHISHI_KDC_NOT_KNOWN_FOR_REALM;
     269                 :            : 
     270         [ #  # ]:          0 :   for (; rrs; rrs = rrs->next)
     271                 :            :     {
     272                 :          0 :       Shishi_dns_srv srv = rrs->rr;
     273                 :            :       char *port;
     274                 :            : 
     275         [ #  # ]:          0 :       if (rrs->class != SHISHI_DNS_IN)
     276                 :          0 :         continue;
     277         [ #  # ]:          0 :       if (rrs->type != SHISHI_DNS_SRV)
     278                 :          0 :         continue;
     279                 :            : 
     280                 :          0 :       shishi_verbose (handle, "Found SRV host %s port %d",
     281                 :          0 :                       srv->name, srv->port);
     282                 :          0 :       *found_srv_records = true;
     283                 :            : 
     284                 :          0 :       port = xasprintf ("%d", srv->port);
     285                 :          0 :       rc = sendrecv_host (handle, transport,
     286                 :            :                           srv->name, port, indata, inlen, outdata, outlen);
     287                 :          0 :       free (port);
     288                 :            : 
     289         [ #  # ]:          0 :       if (rc == SHISHI_OK)
     290                 :          0 :         return rc;
     291                 :            :     }
     292                 :            : 
     293                 :          0 :   return rc;
     294                 :            : }
     295                 :            : 
     296                 :            : static int
     297                 :          0 : sendrecv_srv2 (Shishi * handle,
     298                 :            :                int transport,
     299                 :            :                const char *realm,
     300                 :            :                const char *indata, size_t inlen,
     301                 :            :                char **outdata, size_t * outlen, bool * found_srv_records)
     302                 :            : {
     303                 :            :   Shishi_dns rrs;
     304                 :            :   char *tmp;
     305                 :            :   int rc;
     306                 :            : 
     307 [ #  # ][ #  # ]:          0 :   if (transport != UDP && transport != TCP)
     308                 :          0 :     return SHISHI_KDC_NOT_KNOWN_FOR_REALM;
     309                 :            : 
     310         [ #  # ]:          0 :   tmp = xasprintf ("_kerberos._%s.%s", transport == UDP ? "udp" : "tcp",
     311                 :            :                    realm);
     312                 :          0 :   shishi_verbose (handle, "Looking up SRV for %s", tmp);
     313                 :          0 :   rrs = shishi_resolv (tmp, SHISHI_DNS_SRV);
     314                 :          0 :   free (tmp);
     315                 :            : 
     316         [ #  # ]:          0 :   if (rrs)
     317                 :          0 :     rc = sendrecv_srv3 (handle, transport, realm, indata, inlen,
     318                 :            :                         outdata, outlen, rrs, found_srv_records);
     319                 :            :   else
     320                 :          0 :     rc = SHISHI_KDC_NOT_KNOWN_FOR_REALM;
     321                 :            : 
     322                 :          0 :   shishi_resolv_free (rrs);
     323                 :            : 
     324                 :          0 :   return rc;
     325                 :            : }
     326                 :            : 
     327                 :            : static int
     328                 :          0 : sendrecv_srv (Shishi * handle, const char *realm,
     329                 :            :               const char *indata, size_t inlen,
     330                 :            :               char **outdata, size_t * outlen, bool * found_srv_records)
     331                 :            : {
     332                 :          0 :   int rc = sendrecv_srv2 (handle, UDP, realm, indata, inlen,
     333                 :          0 :                           outdata, outlen, found_srv_records);
     334         [ #  # ]:          0 :   if (rc == SHISHI_OK)
     335                 :          0 :     return rc;
     336                 :          0 :   return sendrecv_srv2 (handle, TCP, realm, indata, inlen,
     337                 :            :                         outdata, outlen, found_srv_records);
     338                 :            : }
     339                 :            : 
     340                 :            : static int
     341                 :          0 : sendrecv_static (Shishi * handle, const char *realm,
     342                 :            :                  const char *indata, size_t inlen,
     343                 :            :                  char **outdata, size_t * outlen)
     344                 :            : {
     345                 :            :   struct Shishi_realminfo *ri;
     346                 :            :   size_t k;
     347                 :            :   int rc;
     348                 :            : 
     349                 :          0 :   ri = _shishi_realminfo (handle, realm);
     350   [ #  #  #  # ]:          0 :   if (!ri || ri->nkdcaddresses == 0)
     351                 :            :     {
     352                 :          0 :       shishi_error_printf (handle, "No KDC configured for %s", realm);
     353                 :          0 :       return SHISHI_KDC_NOT_KNOWN_FOR_REALM;
     354                 :            :     }
     355                 :            : 
     356                 :          0 :   rc = SHISHI_KDC_NOT_KNOWN_FOR_REALM;
     357         [ #  # ]:          0 :   for (k = 0; k < ri->nkdcaddresses; k++)
     358                 :            :     {
     359                 :          0 :       rc = sendrecv_host (handle,
     360                 :          0 :                           ri->kdcaddresses[k].transport,
     361                 :          0 :                           ri->kdcaddresses[k].hostname,
     362                 :          0 :                           ri->kdcaddresses[k].port,
     363                 :            :                           indata, inlen, outdata, outlen);
     364         [ #  # ]:          0 :       if (rc == SHISHI_OK)
     365                 :          0 :         return rc;
     366                 :            :     }
     367                 :            : 
     368                 :          0 :   return rc;
     369                 :            : }
     370                 :            : 
     371                 :            : /**
     372                 :            :  * shishi_kdc_sendrecv_hint:
     373                 :            :  * @handle: Shishi library handle create by shishi_init().
     374                 :            :  * @realm: string with realm name.
     375                 :            :  * @indata: Packet to send to KDC.
     376                 :            :  * @inlen: Length of @indata.
     377                 :            :  * @outdata: Newly allocated string with data returned from KDC.
     378                 :            :  * @outlen: Length of @outdata.
     379                 :            :  * @hint: a #Shishi_tkts_hint structure with flags.
     380                 :            :  *
     381                 :            :  * Send packet to KDC for realm and receive response.  The code finds
     382                 :            :  * KDC addresses from configuration file, then by querying for SRV
     383                 :            :  * records for the realm, and finally by using the realm name as a
     384                 :            :  * hostname.
     385                 :            :  *
     386                 :            :  * Returns: %SHISHI_OK on success, %SHISHI_KDC_TIMEOUT if a timeout
     387                 :            :  *   was reached, or other errors.
     388                 :            :  **/
     389                 :            : int
     390                 :          0 : shishi_kdc_sendrecv_hint (Shishi * handle, const char *realm,
     391                 :            :                           const char *indata, size_t inlen,
     392                 :            :                           char **outdata, size_t * outlen,
     393                 :            :                           Shishi_tkts_hint * hint)
     394                 :            : {
     395                 :            :   struct Shishi_realminfo *ri;
     396                 :          0 :   bool found_srv_records = false;
     397                 :            :   int rc;
     398                 :            : 
     399                 :          0 :   ri = _shishi_realminfo (handle, realm);
     400   [ #  #  #  # ]:          0 :   if (ri && ri->nkdcaddresses > 0)
     401                 :            :     /* If we have configured KDCs, never use DNS or direct method. */
     402                 :          0 :     return sendrecv_static (handle, realm, indata, inlen, outdata, outlen);
     403                 :            : 
     404                 :          0 :   rc = sendrecv_srv (handle, realm, indata, inlen, outdata, outlen,
     405                 :            :                      &found_srv_records);
     406   [ #  #  #  # ]:          0 :   if (rc != SHISHI_OK && !found_srv_records)
     407                 :            :     {
     408                 :          0 :       shishi_verbose (handle, "No SRV RRs, trying realm host mapping for %s",
     409                 :            :                       realm);
     410                 :          0 :       rc = sendrecv_host (handle, UDP, realm, NULL,
     411                 :            :                           indata, inlen, outdata, outlen);
     412                 :            :     }
     413                 :            : 
     414                 :          0 :   return rc;
     415                 :            : }
     416                 :            : 
     417                 :            : /**
     418                 :            :  * shishi_kdc_sendrecv:
     419                 :            :  * @handle: Shishi library handle create by shishi_init().
     420                 :            :  * @realm: string with realm name.
     421                 :            :  * @indata: Packet to send to KDC.
     422                 :            :  * @inlen: Length of @indata.
     423                 :            :  * @outdata: Newly allocated string with data returned from KDC.
     424                 :            :  * @outlen: Length of @outdata.
     425                 :            :  *
     426                 :            :  * Send packet to KDC for realm and receive response.  The code finds
     427                 :            :  * KDC addresses from configuration file, then by querying for SRV
     428                 :            :  * records for the realm, and finally by using the realm name as a
     429                 :            :  * hostname.
     430                 :            :  *
     431                 :            :  * Returns: %SHISHI_OK on success, %SHISHI_KDC_TIMEOUT if a timeout
     432                 :            :  *   was reached, or other errors.
     433                 :            :  **/
     434                 :            : int
     435                 :          0 : shishi_kdc_sendrecv (Shishi * handle, const char *realm,
     436                 :            :                      const char *indata, size_t inlen,
     437                 :            :                      char **outdata, size_t * outlen)
     438                 :            : {
     439                 :          0 :   return shishi_kdc_sendrecv_hint (handle, realm, indata, inlen,
     440                 :            :                                    outdata, outlen, NULL);
     441                 :            : }

Generated by: LCOV version 1.8