root/source4/lib/socket/socket_unix.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. unixdom_error
  2. unixdom_init
  3. unixdom_close
  4. unixdom_connect_complete
  5. unixdom_connect
  6. unixdom_listen
  7. unixdom_accept
  8. unixdom_recv
  9. unixdom_send
  10. unixdom_sendto
  11. unixdom_set_option
  12. unixdom_get_peer_name
  13. unixdom_get_peer_addr
  14. unixdom_get_my_addr
  15. unixdom_get_fd
  16. unixdom_pending
  17. socket_unixdom_ops

   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 
  29 
  30 /*
  31   approximate errno mapping
  32 */
  33 static NTSTATUS unixdom_error(int ernum)
     /* [<][>][^][v][top][bottom][index][help] */
  34 {
  35         return map_nt_error_from_unix(ernum);
  36 }
  37 
  38 static NTSTATUS unixdom_init(struct socket_context *sock)
     /* [<][>][^][v][top][bottom][index][help] */
  39 {
  40         int type;
  41 
  42         switch (sock->type) {
  43         case SOCKET_TYPE_STREAM:
  44                 type = SOCK_STREAM;
  45                 break;
  46         case SOCKET_TYPE_DGRAM:
  47                 type = SOCK_DGRAM;
  48                 break;
  49         default:
  50                 return NT_STATUS_INVALID_PARAMETER;
  51         }
  52 
  53         sock->fd = socket(PF_UNIX, type, 0);
  54         if (sock->fd == -1) {
  55                 return map_nt_error_from_unix(errno);
  56         }
  57         sock->private_data = NULL;
  58 
  59         sock->backend_name = "unix";
  60 
  61         return NT_STATUS_OK;
  62 }
  63 
  64 static void unixdom_close(struct socket_context *sock)
     /* [<][>][^][v][top][bottom][index][help] */
  65 {
  66         close(sock->fd);
  67 }
  68 
  69 static NTSTATUS unixdom_connect_complete(struct socket_context *sock, uint32_t flags)
     /* [<][>][^][v][top][bottom][index][help] */
  70 {
  71         int error=0, ret;
  72         socklen_t len = sizeof(error);
  73 
  74         /* check for any errors that may have occurred - this is needed
  75            for non-blocking connect */
  76         ret = getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, &error, &len);
  77         if (ret == -1) {
  78                 return map_nt_error_from_unix(errno);
  79         }
  80         if (error != 0) {
  81                 return map_nt_error_from_unix(error);
  82         }
  83 
  84         if (!(flags & SOCKET_FLAG_BLOCK)) {
  85                 ret = set_blocking(sock->fd, false);
  86                 if (ret == -1) {
  87                         return map_nt_error_from_unix(errno);
  88                 }
  89         }
  90 
  91         sock->state = SOCKET_STATE_CLIENT_CONNECTED;
  92 
  93         return NT_STATUS_OK;
  94 }
  95 
  96 static NTSTATUS unixdom_connect(struct socket_context *sock,
     /* [<][>][^][v][top][bottom][index][help] */
  97                                 const struct socket_address *my_address, 
  98                                 const struct socket_address *srv_address, 
  99                                 uint32_t flags)
 100 {
 101         int ret;
 102 
 103         if (srv_address->sockaddr) {
 104                 ret = connect(sock->fd, srv_address->sockaddr, srv_address->sockaddrlen);
 105         } else {
 106                 struct sockaddr_un srv_addr;
 107                 if (strlen(srv_address->addr)+1 > sizeof(srv_addr.sun_path)) {
 108                         return NT_STATUS_OBJECT_PATH_INVALID;
 109                 }
 110                 
 111                 ZERO_STRUCT(srv_addr);
 112                 srv_addr.sun_family = AF_UNIX;
 113                 strncpy(srv_addr.sun_path, srv_address->addr, sizeof(srv_addr.sun_path));
 114 
 115                 ret = connect(sock->fd, (const struct sockaddr *)&srv_addr, sizeof(srv_addr));
 116         }
 117         if (ret == -1) {
 118                 return unixdom_error(errno);
 119         }
 120 
 121         return unixdom_connect_complete(sock, flags);
 122 }
 123 
 124 static NTSTATUS unixdom_listen(struct socket_context *sock,
     /* [<][>][^][v][top][bottom][index][help] */
 125                                const struct socket_address *my_address, 
 126                                int queue_size, uint32_t flags)
 127 {
 128         struct sockaddr_un my_addr;
 129         int ret;
 130 
 131         /* delete if it already exists */
 132         if (my_address->addr) {
 133                 unlink(my_address->addr);
 134         }
 135 
 136         if (my_address->sockaddr) {
 137                 ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
 138         } else if (my_address->addr == NULL) {
 139                 return NT_STATUS_INVALID_PARAMETER;
 140         } else {
 141                 if (strlen(my_address->addr)+1 > sizeof(my_addr.sun_path)) {
 142                         return NT_STATUS_OBJECT_PATH_INVALID;
 143                 }
 144                 
 145                 
 146                 ZERO_STRUCT(my_addr);
 147                 my_addr.sun_family = AF_UNIX;
 148                 strncpy(my_addr.sun_path, my_address->addr, sizeof(my_addr.sun_path));
 149                 
 150                 ret = bind(sock->fd, (struct sockaddr *)&my_addr, sizeof(my_addr));
 151         }
 152         if (ret == -1) {
 153                 return unixdom_error(errno);
 154         }
 155 
 156         if (sock->type == SOCKET_TYPE_STREAM) {
 157                 ret = listen(sock->fd, queue_size);
 158                 if (ret == -1) {
 159                         return unixdom_error(errno);
 160                 }
 161         }
 162 
 163         if (!(flags & SOCKET_FLAG_BLOCK)) {
 164                 ret = set_blocking(sock->fd, false);
 165                 if (ret == -1) {
 166                         return unixdom_error(errno);
 167                 }
 168         }
 169 
 170         sock->state = SOCKET_STATE_SERVER_LISTEN;
 171         sock->private_data = (void *)talloc_strdup(sock, my_address->addr);
 172 
 173         return NT_STATUS_OK;
 174 }
 175 
 176 static NTSTATUS unixdom_accept(struct socket_context *sock, 
     /* [<][>][^][v][top][bottom][index][help] */
 177                                struct socket_context **new_sock)
 178 {
 179         struct sockaddr_un cli_addr;
 180         socklen_t cli_addr_len = sizeof(cli_addr);
 181         int new_fd;
 182 
 183         if (sock->type != SOCKET_TYPE_STREAM) {
 184                 return NT_STATUS_INVALID_PARAMETER;
 185         }
 186 
 187         new_fd = accept(sock->fd, (struct sockaddr *)&cli_addr, &cli_addr_len);
 188         if (new_fd == -1) {
 189                 return unixdom_error(errno);
 190         }
 191 
 192         if (!(sock->flags & SOCKET_FLAG_BLOCK)) {
 193                 int ret = set_blocking(new_fd, false);
 194                 if (ret == -1) {
 195                         close(new_fd);
 196                         return map_nt_error_from_unix(errno);
 197                 }
 198         }
 199 
 200         (*new_sock) = talloc(NULL, struct socket_context);
 201         if (!(*new_sock)) {
 202                 close(new_fd);
 203                 return NT_STATUS_NO_MEMORY;
 204         }
 205 
 206         /* copy the socket_context */
 207         (*new_sock)->type               = sock->type;
 208         (*new_sock)->state              = SOCKET_STATE_SERVER_CONNECTED;
 209         (*new_sock)->flags              = sock->flags;
 210 
 211         (*new_sock)->fd                 = new_fd;
 212 
 213         (*new_sock)->private_data       = NULL;
 214         (*new_sock)->ops                = sock->ops;
 215         (*new_sock)->backend_name       = sock->backend_name;
 216 
 217         return NT_STATUS_OK;
 218 }
 219 
 220 static NTSTATUS unixdom_recv(struct socket_context *sock, void *buf, 
     /* [<][>][^][v][top][bottom][index][help] */
 221                              size_t wantlen, size_t *nread)
 222 {
 223         ssize_t gotlen;
 224 
 225         *nread = 0;
 226 
 227         gotlen = recv(sock->fd, buf, wantlen, 0);
 228         if (gotlen == 0) {
 229                 return NT_STATUS_END_OF_FILE;
 230         } else if (gotlen == -1) {
 231                 return unixdom_error(errno);
 232         }
 233 
 234         *nread = gotlen;
 235 
 236         return NT_STATUS_OK;
 237 }
 238 
 239 static NTSTATUS unixdom_send(struct socket_context *sock,
     /* [<][>][^][v][top][bottom][index][help] */
 240                              const DATA_BLOB *blob, size_t *sendlen)
 241 {
 242         ssize_t len;
 243 
 244         *sendlen = 0;
 245 
 246         len = send(sock->fd, blob->data, blob->length, 0);
 247         if (len == -1) {
 248                 return unixdom_error(errno);
 249         }       
 250 
 251         *sendlen = len;
 252 
 253         return NT_STATUS_OK;
 254 }
 255 
 256 
 257 static NTSTATUS unixdom_sendto(struct socket_context *sock, 
     /* [<][>][^][v][top][bottom][index][help] */
 258                                const DATA_BLOB *blob, size_t *sendlen, 
 259                                const struct socket_address *dest)
 260 {
 261         ssize_t len;
 262         *sendlen = 0;
 263                 
 264         if (dest->sockaddr) {
 265                 len = sendto(sock->fd, blob->data, blob->length, 0, 
 266                              dest->sockaddr, dest->sockaddrlen);
 267         } else {
 268                 struct sockaddr_un srv_addr;
 269                 
 270                 if (strlen(dest->addr)+1 > sizeof(srv_addr.sun_path)) {
 271                         return NT_STATUS_OBJECT_PATH_INVALID;
 272                 }
 273                 
 274                 ZERO_STRUCT(srv_addr);
 275                 srv_addr.sun_family = AF_UNIX;
 276                 strncpy(srv_addr.sun_path, dest->addr, sizeof(srv_addr.sun_path));
 277                 
 278                 len = sendto(sock->fd, blob->data, blob->length, 0, 
 279                              (struct sockaddr *)&srv_addr, sizeof(srv_addr));
 280         }
 281         if (len == -1) {
 282                 return map_nt_error_from_unix(errno);
 283         }       
 284 
 285         *sendlen = len;
 286 
 287         return NT_STATUS_OK;
 288 }
 289 
 290 
 291 static NTSTATUS unixdom_set_option(struct socket_context *sock, 
     /* [<][>][^][v][top][bottom][index][help] */
 292                                    const char *option, const char *val)
 293 {
 294         return NT_STATUS_OK;
 295 }
 296 
 297 static char *unixdom_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 298 {
 299         return talloc_strdup(mem_ctx, "LOCAL/unixdom");
 300 }
 301 
 302 static struct socket_address *unixdom_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 303 {
 304         struct sockaddr_in *peer_addr;
 305         socklen_t len = sizeof(*peer_addr);
 306         struct socket_address *peer;
 307         int ret;
 308 
 309         peer = talloc(mem_ctx, struct socket_address);
 310         if (!peer) {
 311                 return NULL;
 312         }
 313         
 314         peer->family = sock->backend_name;
 315         peer_addr = talloc(peer, struct sockaddr_in);
 316         if (!peer_addr) {
 317                 talloc_free(peer);
 318                 return NULL;
 319         }
 320 
 321         peer->sockaddr = (struct sockaddr *)peer_addr;
 322 
 323         ret = getpeername(sock->fd, peer->sockaddr, &len);
 324         if (ret == -1) {
 325                 talloc_free(peer);
 326                 return NULL;
 327         }
 328 
 329         peer->sockaddrlen = len;
 330 
 331         peer->port = 0;
 332         peer->addr = talloc_strdup(peer, "LOCAL/unixdom");
 333         if (!peer->addr) {
 334                 talloc_free(peer);
 335                 return NULL;
 336         }
 337 
 338         return peer;
 339 }
 340 
 341 static struct socket_address *unixdom_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 342 {
 343         struct sockaddr_in *local_addr;
 344         socklen_t len = sizeof(*local_addr);
 345         struct socket_address *local;
 346         int ret;
 347         
 348         local = talloc(mem_ctx, struct socket_address);
 349         if (!local) {
 350                 return NULL;
 351         }
 352         
 353         local->family = sock->backend_name;
 354         local_addr = talloc(local, struct sockaddr_in);
 355         if (!local_addr) {
 356                 talloc_free(local);
 357                 return NULL;
 358         }
 359 
 360         local->sockaddr = (struct sockaddr *)local_addr;
 361 
 362         ret = getsockname(sock->fd, local->sockaddr, &len);
 363         if (ret == -1) {
 364                 talloc_free(local);
 365                 return NULL;
 366         }
 367 
 368         local->sockaddrlen = len;
 369 
 370         local->port = 0;
 371         local->addr = talloc_strdup(local, "LOCAL/unixdom");
 372         if (!local->addr) {
 373                 talloc_free(local);
 374                 return NULL;
 375         }
 376 
 377         return local;
 378 }
 379 
 380 static int unixdom_get_fd(struct socket_context *sock)
     /* [<][>][^][v][top][bottom][index][help] */
 381 {
 382         return sock->fd;
 383 }
 384 
 385 static NTSTATUS unixdom_pending(struct socket_context *sock, size_t *npending)
     /* [<][>][^][v][top][bottom][index][help] */
 386 {
 387         int value = 0;
 388         if (ioctl(sock->fd, FIONREAD, &value) == 0) {
 389                 *npending = value;
 390                 return NT_STATUS_OK;
 391         }
 392         return map_nt_error_from_unix(errno);
 393 }
 394 
 395 static const struct socket_ops unixdom_ops = {
 396         .name                   = "unix",
 397         .fn_init                = unixdom_init,
 398         .fn_connect             = unixdom_connect,
 399         .fn_connect_complete    = unixdom_connect_complete,
 400         .fn_listen              = unixdom_listen,
 401         .fn_accept              = unixdom_accept,
 402         .fn_recv                = unixdom_recv,
 403         .fn_send                = unixdom_send,
 404         .fn_sendto              = unixdom_sendto,
 405         .fn_close               = unixdom_close,
 406         .fn_pending             = unixdom_pending,
 407 
 408         .fn_set_option          = unixdom_set_option,
 409 
 410         .fn_get_peer_name       = unixdom_get_peer_name,
 411         .fn_get_peer_addr       = unixdom_get_peer_addr,
 412         .fn_get_my_addr         = unixdom_get_my_addr,
 413 
 414         .fn_get_fd              = unixdom_get_fd
 415 };
 416 
 417 _PUBLIC_ const struct socket_ops *socket_unixdom_ops(enum socket_type type)
     /* [<][>][^][v][top][bottom][index][help] */
 418 {
 419         return &unixdom_ops;
 420 }

/* [<][>][^][v][top][bottom][index][help] */