LCOV - code coverage report
Current view: top level - source4/lib/socket - socket_unix.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 122 212 57.5 %
Date: 2024-02-28 12:06:22 Functions: 12 17 70.6 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    unix domain socket functions
       5             : 
       6             :    Copyright (C) Stefan Metzmacher 2004
       7             :    Copyright (C) Andrew Tridgell 2004-2005
       8             :    
       9             :    This program is free software; you can redistribute it and/or modify
      10             :    it under the terms of the GNU General Public License as published by
      11             :    the Free Software Foundation; either version 3 of the License, or
      12             :    (at your option) any later version.
      13             :    
      14             :    This program is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU General Public License for more details.
      18             :    
      19             :    You should have received a copy of the GNU General Public License
      20             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      21             : */
      22             : 
      23             : #include "includes.h"
      24             : #include "lib/socket/socket.h"
      25             : #include "system/network.h"
      26             : #include "system/filesys.h"
      27             : 
      28             : _PUBLIC_ const struct socket_ops *socket_unixdom_ops(enum socket_type type);
      29             : 
      30             : 
      31             : /*
      32             :   approximate errno mapping
      33             : */
      34        1144 : static NTSTATUS unixdom_error(int ernum)
      35             : {
      36        1144 :         return map_nt_error_from_unix_common(ernum);
      37             : }
      38             : 
      39        2685 : static NTSTATUS unixdom_init(struct socket_context *sock)
      40             : {
      41          40 :         int type;
      42             : 
      43        2685 :         switch (sock->type) {
      44        2645 :         case SOCKET_TYPE_STREAM:
      45        2645 :                 type = SOCK_STREAM;
      46        2645 :                 break;
      47           0 :         case SOCKET_TYPE_DGRAM:
      48           0 :                 type = SOCK_DGRAM;
      49           0 :                 break;
      50           0 :         default:
      51           0 :                 return NT_STATUS_INVALID_PARAMETER;
      52             :         }
      53             : 
      54        2685 :         sock->fd = socket(PF_UNIX, type, 0);
      55        2685 :         if (sock->fd == -1) {
      56           0 :                 return map_nt_error_from_unix_common(errno);
      57             :         }
      58        2685 :         sock->private_data = NULL;
      59             : 
      60        2685 :         sock->backend_name = "unix";
      61             : 
      62        2685 :         smb_set_close_on_exec(sock->fd);
      63             : 
      64        2685 :         return NT_STATUS_OK;
      65             : }
      66             : 
      67         175 : static void unixdom_close(struct socket_context *sock)
      68             : {
      69         175 :         close(sock->fd);
      70         175 : }
      71             : 
      72        3120 : static NTSTATUS unixdom_connect_complete(struct socket_context *sock, uint32_t flags)
      73             : {
      74        3120 :         int error=0, ret;
      75        3120 :         socklen_t len = sizeof(error);
      76             : 
      77             :         /* check for any errors that may have occurred - this is needed
      78             :            for non-blocking connect */
      79        3120 :         ret = getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, &error, &len);
      80        3120 :         if (ret == -1) {
      81           0 :                 return map_nt_error_from_unix_common(errno);
      82             :         }
      83        3120 :         if (error != 0) {
      84           0 :                 return map_nt_error_from_unix_common(error);
      85             :         }
      86             : 
      87        3120 :         ret = set_blocking(sock->fd, false);
      88        3120 :         if (ret == -1) {
      89           0 :                 return map_nt_error_from_unix_common(errno);
      90             :         }
      91             : 
      92        3120 :         sock->state = SOCKET_STATE_CLIENT_CONNECTED;
      93             : 
      94        3120 :         return NT_STATUS_OK;
      95             : }
      96             : 
      97        1560 : static NTSTATUS unixdom_connect(struct socket_context *sock,
      98             :                                 const struct socket_address *my_address, 
      99             :                                 const struct socket_address *srv_address, 
     100             :                                 uint32_t flags)
     101             : {
     102           8 :         int ret;
     103             : 
     104        1560 :         if (srv_address->sockaddr) {
     105           0 :                 ret = connect(sock->fd, srv_address->sockaddr, srv_address->sockaddrlen);
     106             :         } else {
     107           8 :                 struct sockaddr_un srv_addr;
     108        1560 :                 if (strlen(srv_address->addr)+1 > sizeof(srv_addr.sun_path)) {
     109           0 :                         return NT_STATUS_OBJECT_PATH_INVALID;
     110             :                 }
     111             :                 
     112        1560 :                 ZERO_STRUCT(srv_addr);
     113        1560 :                 srv_addr.sun_family = AF_UNIX;
     114        1560 :                 snprintf(srv_addr.sun_path, sizeof(srv_addr.sun_path), "%s", srv_address->addr);
     115             : 
     116        1560 :                 ret = connect(sock->fd, (const struct sockaddr *)&srv_addr, sizeof(srv_addr));
     117             :         }
     118        1560 :         if (ret == -1) {
     119           0 :                 return unixdom_error(errno);
     120             :         }
     121             : 
     122        1560 :         return unixdom_connect_complete(sock, flags);
     123             : }
     124             : 
     125        1125 : static NTSTATUS unixdom_listen(struct socket_context *sock,
     126             :                                const struct socket_address *my_address, 
     127             :                                int queue_size, uint32_t flags)
     128             : {
     129          32 :         struct sockaddr_un my_addr;
     130          32 :         int ret;
     131             : 
     132             :         /* delete if it already exists */
     133        1125 :         if (my_address->addr) {
     134        1125 :                 unlink(my_address->addr);
     135             :         }
     136             : 
     137        1125 :         if (my_address->sockaddr) {
     138           0 :                 ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
     139        1125 :         } else if (my_address->addr == NULL) {
     140           0 :                 return NT_STATUS_INVALID_PARAMETER;
     141             :         } else {
     142        1125 :                 if (strlen(my_address->addr)+1 > sizeof(my_addr.sun_path)) {
     143           0 :                         return NT_STATUS_OBJECT_PATH_INVALID;
     144             :                 }
     145             :                 
     146             :                 
     147        1125 :                 ZERO_STRUCT(my_addr);
     148        1125 :                 my_addr.sun_family = AF_UNIX;
     149        1125 :                 snprintf(my_addr.sun_path, sizeof(my_addr.sun_path), "%s", my_address->addr);
     150             : 
     151        1125 :                 ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
     152             :         }
     153        1125 :         if (ret == -1) {
     154           0 :                 return unixdom_error(errno);
     155             :         }
     156             : 
     157        1125 :         if (sock->type == SOCKET_TYPE_STREAM) {
     158        1125 :                 ret = listen(sock->fd, queue_size);
     159        1125 :                 if (ret == -1) {
     160           0 :                         return unixdom_error(errno);
     161             :                 }
     162             :         }
     163             : 
     164        1125 :         ret = set_blocking(sock->fd, false);
     165        1125 :         if (ret == -1) {
     166           0 :                 return unixdom_error(errno);
     167             :         }
     168             : 
     169        1125 :         sock->state = SOCKET_STATE_SERVER_LISTEN;
     170        1125 :         sock->private_data = (void *)talloc_strdup(sock, my_address->addr);
     171             : 
     172        1125 :         return NT_STATUS_OK;
     173             : }
     174             : 
     175       10323 : static NTSTATUS unixdom_accept(struct socket_context *sock, 
     176             :                                struct socket_context **new_sock)
     177             : {
     178         826 :         struct sockaddr_un cli_addr;
     179       10323 :         socklen_t cli_addr_len = sizeof(cli_addr);
     180         826 :         int new_fd, ret;
     181             : 
     182       10323 :         if (sock->type != SOCKET_TYPE_STREAM) {
     183           0 :                 return NT_STATUS_INVALID_PARAMETER;
     184             :         }
     185             : 
     186       10323 :         new_fd = accept(sock->fd, (struct sockaddr *)&cli_addr, &cli_addr_len);
     187       10323 :         if (new_fd == -1) {
     188        1144 :                 return unixdom_error(errno);
     189             :         }
     190             : 
     191        9179 :         ret = set_blocking(new_fd, false);
     192        9179 :         if (ret == -1) {
     193           0 :                 close(new_fd);
     194           0 :                 return map_nt_error_from_unix_common(errno);
     195             :         }
     196             : 
     197        9179 :         smb_set_close_on_exec(new_fd);
     198             : 
     199        9179 :         (*new_sock) = talloc(NULL, struct socket_context);
     200        9179 :         if (!(*new_sock)) {
     201           0 :                 close(new_fd);
     202           0 :                 return NT_STATUS_NO_MEMORY;
     203             :         }
     204             : 
     205             :         /* copy the socket_context */
     206        9179 :         (*new_sock)->type            = sock->type;
     207        9179 :         (*new_sock)->state           = SOCKET_STATE_SERVER_CONNECTED;
     208        9179 :         (*new_sock)->flags           = sock->flags;
     209             : 
     210        9179 :         (*new_sock)->fd                      = new_fd;
     211             : 
     212        9179 :         (*new_sock)->private_data    = NULL;
     213        9179 :         (*new_sock)->ops             = sock->ops;
     214        9179 :         (*new_sock)->backend_name    = sock->backend_name;
     215             : 
     216        9179 :         return NT_STATUS_OK;
     217             : }
     218             : 
     219           0 : static NTSTATUS unixdom_recv(struct socket_context *sock, void *buf, 
     220             :                              size_t wantlen, size_t *nread)
     221             : {
     222           0 :         ssize_t gotlen;
     223             : 
     224           0 :         *nread = 0;
     225             : 
     226           0 :         gotlen = recv(sock->fd, buf, wantlen, 0);
     227           0 :         if (gotlen == 0) {
     228           0 :                 return NT_STATUS_END_OF_FILE;
     229           0 :         } else if (gotlen == -1) {
     230           0 :                 return unixdom_error(errno);
     231             :         }
     232             : 
     233           0 :         *nread = gotlen;
     234             : 
     235           0 :         return NT_STATUS_OK;
     236             : }
     237             : 
     238           0 : static NTSTATUS unixdom_send(struct socket_context *sock,
     239             :                              const DATA_BLOB *blob, size_t *sendlen)
     240             : {
     241           0 :         ssize_t len;
     242             : 
     243           0 :         *sendlen = 0;
     244             : 
     245           0 :         len = send(sock->fd, blob->data, blob->length, 0);
     246           0 :         if (len == -1) {
     247           0 :                 return unixdom_error(errno);
     248             :         }       
     249             : 
     250           0 :         *sendlen = len;
     251             : 
     252           0 :         return NT_STATUS_OK;
     253             : }
     254             : 
     255             : 
     256           0 : static NTSTATUS unixdom_sendto(struct socket_context *sock, 
     257             :                                const DATA_BLOB *blob, size_t *sendlen, 
     258             :                                const struct socket_address *dest)
     259             : {
     260           0 :         struct sockaddr_un srv_addr;
     261           0 :         const struct sockaddr *sa;
     262           0 :         socklen_t sa_len;
     263           0 :         ssize_t len;
     264             : 
     265           0 :         *sendlen = 0;
     266             : 
     267           0 :         if (dest->sockaddr) {
     268           0 :                 sa = dest->sockaddr;
     269           0 :                 sa_len = dest->sockaddrlen;
     270             :         } else {
     271           0 :                 if (strlen(dest->addr)+1 > sizeof(srv_addr.sun_path)) {
     272           0 :                         return NT_STATUS_OBJECT_PATH_INVALID;
     273             :                 }
     274             : 
     275           0 :                 ZERO_STRUCT(srv_addr);
     276           0 :                 srv_addr.sun_family = AF_UNIX;
     277           0 :                 snprintf(srv_addr.sun_path, sizeof(srv_addr.sun_path), "%s",
     278           0 :                          dest->addr);
     279           0 :                 sa = (struct sockaddr *) &srv_addr;
     280           0 :                 sa_len = sizeof(srv_addr);
     281             :         }
     282             : 
     283           0 :         len = sendto(sock->fd, blob->data, blob->length, 0, sa, sa_len);
     284             : 
     285             :         /* retry once */
     286           0 :         if (len == -1 && errno == EMSGSIZE) {
     287             :                 /* round up in 1K increments */
     288           0 :                 int bufsize = ((blob->length + 1023) & (~1023));
     289           0 :                 if (setsockopt(sock->fd, SOL_SOCKET, SO_SNDBUF, &bufsize,
     290             :                                sizeof(bufsize)) == -1)
     291             :                 {
     292           0 :                         return map_nt_error_from_unix_common(EMSGSIZE);
     293             :                 }
     294           0 :                 len = sendto(sock->fd, blob->data, blob->length, 0, sa, sa_len);
     295             :         }
     296             : 
     297           0 :         if (len == -1) {
     298           0 :                 return map_nt_error_from_unix_common(errno);
     299             :         }       
     300             : 
     301           0 :         *sendlen = len;
     302             : 
     303           0 :         return NT_STATUS_OK;
     304             : }
     305             : 
     306             : 
     307        1448 : static NTSTATUS unixdom_set_option(struct socket_context *sock, 
     308             :                                    const char *option, const char *val)
     309             : {
     310        1448 :         return NT_STATUS_OK;
     311             : }
     312             : 
     313           0 : static char *unixdom_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
     314             : {
     315           0 :         return talloc_strdup(mem_ctx, "LOCAL/unixdom");
     316             : }
     317             : 
     318        9353 : static struct socket_address *unixdom_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
     319             : {
     320         636 :         struct sockaddr_un *peer_addr;
     321        9353 :         socklen_t len = sizeof(*peer_addr);
     322         636 :         struct socket_address *peer;
     323         636 :         int ret;
     324             : 
     325        9353 :         peer = talloc(mem_ctx, struct socket_address);
     326        9353 :         if (!peer) {
     327           0 :                 return NULL;
     328             :         }
     329             :         
     330        9353 :         peer->family = sock->backend_name;
     331        9353 :         peer_addr = talloc(peer, struct sockaddr_un);
     332        9353 :         if (!peer_addr) {
     333           0 :                 talloc_free(peer);
     334           0 :                 return NULL;
     335             :         }
     336             : 
     337        9353 :         peer->sockaddr = (struct sockaddr *)peer_addr;
     338             : 
     339        9353 :         ret = getpeername(sock->fd, peer->sockaddr, &len);
     340        9353 :         if (ret == -1) {
     341           0 :                 talloc_free(peer);
     342           0 :                 return NULL;
     343             :         }
     344             : 
     345        9353 :         peer->sockaddrlen = len;
     346             : 
     347        9353 :         peer->port = 0;
     348        9353 :         peer->addr = talloc_strdup(peer, "LOCAL/unixdom");
     349        9353 :         if (!peer->addr) {
     350           0 :                 talloc_free(peer);
     351           0 :                 return NULL;
     352             :         }
     353             : 
     354        8717 :         return peer;
     355             : }
     356             : 
     357       10913 : static struct socket_address *unixdom_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
     358             : {
     359         644 :         struct sockaddr_un *local_addr;
     360       10913 :         socklen_t len = sizeof(*local_addr);
     361         644 :         struct socket_address *local;
     362         644 :         int ret;
     363             :         
     364       10913 :         local = talloc(mem_ctx, struct socket_address);
     365       10913 :         if (!local) {
     366           0 :                 return NULL;
     367             :         }
     368             :         
     369       10913 :         local->family = sock->backend_name;
     370       10913 :         local_addr = talloc(local, struct sockaddr_un);
     371       10913 :         if (!local_addr) {
     372           0 :                 talloc_free(local);
     373           0 :                 return NULL;
     374             :         }
     375             : 
     376       10913 :         local->sockaddr = (struct sockaddr *)local_addr;
     377             : 
     378       10913 :         ret = getsockname(sock->fd, local->sockaddr, &len);
     379       10913 :         if (ret == -1) {
     380           0 :                 talloc_free(local);
     381           0 :                 return NULL;
     382             :         }
     383             : 
     384       10913 :         local->sockaddrlen = len;
     385             : 
     386       10913 :         local->port = 0;
     387       10913 :         local->addr = talloc_strdup(local, "LOCAL/unixdom");
     388       10913 :         if (!local->addr) {
     389           0 :                 talloc_free(local);
     390           0 :                 return NULL;
     391             :         }
     392             : 
     393       10269 :         return local;
     394             : }
     395             : 
     396       34618 : static int unixdom_get_fd(struct socket_context *sock)
     397             : {
     398       34618 :         return sock->fd;
     399             : }
     400             : 
     401           0 : static NTSTATUS unixdom_pending(struct socket_context *sock, size_t *npending)
     402             : {
     403           0 :         int value = 0;
     404           0 :         if (ioctl(sock->fd, FIONREAD, &value) == 0) {
     405           0 :                 *npending = value;
     406           0 :                 return NT_STATUS_OK;
     407             :         }
     408           0 :         return map_nt_error_from_unix_common(errno);
     409             : }
     410             : 
     411             : static const struct socket_ops unixdom_ops = {
     412             :         .name                   = "unix",
     413             :         .fn_init                = unixdom_init,
     414             :         .fn_connect             = unixdom_connect,
     415             :         .fn_connect_complete    = unixdom_connect_complete,
     416             :         .fn_listen              = unixdom_listen,
     417             :         .fn_accept              = unixdom_accept,
     418             :         .fn_recv                = unixdom_recv,
     419             :         .fn_send                = unixdom_send,
     420             :         .fn_sendto              = unixdom_sendto,
     421             :         .fn_close               = unixdom_close,
     422             :         .fn_pending             = unixdom_pending,
     423             : 
     424             :         .fn_set_option          = unixdom_set_option,
     425             : 
     426             :         .fn_get_peer_name       = unixdom_get_peer_name,
     427             :         .fn_get_peer_addr       = unixdom_get_peer_addr,
     428             :         .fn_get_my_addr         = unixdom_get_my_addr,
     429             : 
     430             :         .fn_get_fd              = unixdom_get_fd
     431             : };
     432             : 
     433        2685 : _PUBLIC_ const struct socket_ops *socket_unixdom_ops(enum socket_type type)
     434             : {
     435        2685 :         return &unixdom_ops;
     436             : }

Generated by: LCOV version 1.14