| 1 | /*
|
|---|
| 2 | Unix SMB/CIFS implementation.
|
|---|
| 3 | Samba utility functions
|
|---|
| 4 | Copyright (C) Andrew Tridgell 1992-1998
|
|---|
| 5 | Copyright (C) Tim Potter 2000-2001
|
|---|
| 6 | Copyright (C) Jeremy Allison 1992-2005
|
|---|
| 7 |
|
|---|
| 8 | This program is free software; you can redistribute it and/or modify
|
|---|
| 9 | it under the terms of the GNU General Public License as published by
|
|---|
| 10 | the Free Software Foundation; either version 2 of the License, or
|
|---|
| 11 | (at your option) any later version.
|
|---|
| 12 |
|
|---|
| 13 | This program is distributed in the hope that it will be useful,
|
|---|
| 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|---|
| 16 | GNU General Public License for more details.
|
|---|
| 17 |
|
|---|
| 18 | You should have received a copy of the GNU General Public License
|
|---|
| 19 | along with this program; if not, write to the Free Software
|
|---|
| 20 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|---|
| 21 | */
|
|---|
| 22 |
|
|---|
| 23 | #include "includes.h"
|
|---|
| 24 |
|
|---|
| 25 | /* the following 3 client_*() functions are nasty ways of allowing
|
|---|
| 26 | some generic functions to get info that really should be hidden in
|
|---|
| 27 | particular modules */
|
|---|
| 28 | static int client_fd = -1;
|
|---|
| 29 | /* What to print out on a client disconnect error. */
|
|---|
| 30 | static char client_ip_string[16];
|
|---|
| 31 |
|
|---|
| 32 | void client_setfd(int fd)
|
|---|
| 33 | {
|
|---|
| 34 | client_fd = fd;
|
|---|
| 35 | safe_strcpy(client_ip_string, get_peer_addr(client_fd), sizeof(client_ip_string)-1);
|
|---|
| 36 | }
|
|---|
| 37 |
|
|---|
| 38 | static char *get_socket_addr(int fd)
|
|---|
| 39 | {
|
|---|
| 40 | struct sockaddr sa;
|
|---|
| 41 | struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
|
|---|
| 42 | socklen_t length = sizeof(sa);
|
|---|
| 43 | static fstring addr_buf;
|
|---|
| 44 |
|
|---|
| 45 | fstrcpy(addr_buf,"0.0.0.0");
|
|---|
| 46 |
|
|---|
| 47 | if (fd == -1) {
|
|---|
| 48 | return addr_buf;
|
|---|
| 49 | }
|
|---|
| 50 |
|
|---|
| 51 | if (getsockname(fd, &sa, &length) < 0) {
|
|---|
| 52 | DEBUG(0,("getsockname failed. Error was %s\n", strerror(errno) ));
|
|---|
| 53 | return addr_buf;
|
|---|
| 54 | }
|
|---|
| 55 |
|
|---|
| 56 | fstrcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr));
|
|---|
| 57 |
|
|---|
| 58 | return addr_buf;
|
|---|
| 59 | }
|
|---|
| 60 |
|
|---|
| 61 | static int get_socket_port(int fd)
|
|---|
| 62 | {
|
|---|
| 63 | struct sockaddr sa;
|
|---|
| 64 | struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
|
|---|
| 65 | socklen_t length = sizeof(sa);
|
|---|
| 66 |
|
|---|
| 67 | if (fd == -1)
|
|---|
| 68 | return -1;
|
|---|
| 69 |
|
|---|
| 70 | if (getsockname(fd, &sa, &length) < 0) {
|
|---|
| 71 | DEBUG(0,("getpeername failed. Error was %s\n", strerror(errno) ));
|
|---|
| 72 | return -1;
|
|---|
| 73 | }
|
|---|
| 74 |
|
|---|
| 75 | return ntohs(sockin->sin_port);
|
|---|
| 76 | }
|
|---|
| 77 |
|
|---|
| 78 | char *client_name(void)
|
|---|
| 79 | {
|
|---|
| 80 | return get_peer_name(client_fd,False);
|
|---|
| 81 | }
|
|---|
| 82 |
|
|---|
| 83 | char *client_addr(void)
|
|---|
| 84 | {
|
|---|
| 85 | return get_peer_addr(client_fd);
|
|---|
| 86 | }
|
|---|
| 87 |
|
|---|
| 88 | char *client_socket_addr(void)
|
|---|
| 89 | {
|
|---|
| 90 | return get_socket_addr(client_fd);
|
|---|
| 91 | }
|
|---|
| 92 |
|
|---|
| 93 | int client_socket_port(void)
|
|---|
| 94 | {
|
|---|
| 95 | return get_socket_port(client_fd);
|
|---|
| 96 | }
|
|---|
| 97 |
|
|---|
| 98 | struct in_addr *client_inaddr(struct sockaddr *sa)
|
|---|
| 99 | {
|
|---|
| 100 | struct sockaddr_in *sockin = (struct sockaddr_in *) (sa);
|
|---|
| 101 | socklen_t length = sizeof(*sa);
|
|---|
| 102 |
|
|---|
| 103 | if (getpeername(client_fd, sa, &length) < 0) {
|
|---|
| 104 | DEBUG(0,("getpeername failed. Error was %s\n", strerror(errno) ));
|
|---|
| 105 | return NULL;
|
|---|
| 106 | }
|
|---|
| 107 |
|
|---|
| 108 | return &sockin->sin_addr;
|
|---|
| 109 | }
|
|---|
| 110 |
|
|---|
| 111 | /* the last IP received from */
|
|---|
| 112 | struct in_addr lastip;
|
|---|
| 113 |
|
|---|
| 114 | /* the last port received from */
|
|---|
| 115 | int lastport=0;
|
|---|
| 116 |
|
|---|
| 117 | int smb_read_error = 0;
|
|---|
| 118 |
|
|---|
| 119 | /****************************************************************************
|
|---|
| 120 | Determine if a file descriptor is in fact a socket.
|
|---|
| 121 | ****************************************************************************/
|
|---|
| 122 |
|
|---|
| 123 | BOOL is_a_socket(int fd)
|
|---|
| 124 | {
|
|---|
| 125 | int v;
|
|---|
| 126 | socklen_t l;
|
|---|
| 127 | l = sizeof(int);
|
|---|
| 128 | return(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0);
|
|---|
| 129 | }
|
|---|
| 130 |
|
|---|
| 131 | enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
|
|---|
| 132 |
|
|---|
| 133 | typedef struct smb_socket_option {
|
|---|
| 134 | const char *name;
|
|---|
| 135 | int level;
|
|---|
| 136 | int option;
|
|---|
| 137 | int value;
|
|---|
| 138 | int opttype;
|
|---|
| 139 | } smb_socket_option;
|
|---|
| 140 |
|
|---|
| 141 | static const smb_socket_option socket_options[] = {
|
|---|
| 142 | {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL},
|
|---|
| 143 | {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL},
|
|---|
| 144 | {"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL},
|
|---|
| 145 | #ifdef TCP_NODELAY
|
|---|
| 146 | {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL},
|
|---|
| 147 | #endif
|
|---|
| 148 | #ifdef TCP_KEEPCNT
|
|---|
| 149 | {"TCP_KEEPCNT", IPPROTO_TCP, TCP_KEEPCNT, 0, OPT_INT},
|
|---|
| 150 | #endif
|
|---|
| 151 | #ifdef TCP_KEEPIDLE
|
|---|
| 152 | {"TCP_KEEPIDLE", IPPROTO_TCP, TCP_KEEPIDLE, 0, OPT_INT},
|
|---|
| 153 | #endif
|
|---|
| 154 | #ifdef TCP_KEEPINTVL
|
|---|
| 155 | {"TCP_KEEPINTVL", IPPROTO_TCP, TCP_KEEPINTVL, 0, OPT_INT},
|
|---|
| 156 | #endif
|
|---|
| 157 | #ifdef IPTOS_LOWDELAY
|
|---|
| 158 | {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON},
|
|---|
| 159 | #endif
|
|---|
| 160 | #ifdef IPTOS_THROUGHPUT
|
|---|
| 161 | {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON},
|
|---|
| 162 | #endif
|
|---|
| 163 | #ifdef SO_REUSEPORT
|
|---|
| 164 | {"SO_REUSEPORT", SOL_SOCKET, SO_REUSEPORT, 0, OPT_BOOL},
|
|---|
| 165 | #endif
|
|---|
| 166 | #ifdef SO_SNDBUF
|
|---|
| 167 | {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT},
|
|---|
| 168 | #endif
|
|---|
| 169 | #ifdef SO_RCVBUF
|
|---|
| 170 | {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT},
|
|---|
| 171 | #endif
|
|---|
| 172 | #ifdef SO_SNDLOWAT
|
|---|
| 173 | {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT},
|
|---|
| 174 | #endif
|
|---|
| 175 | #ifdef SO_RCVLOWAT
|
|---|
| 176 | {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT},
|
|---|
| 177 | #endif
|
|---|
| 178 | #ifdef SO_SNDTIMEO
|
|---|
| 179 | {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT},
|
|---|
| 180 | #endif
|
|---|
| 181 | #ifdef SO_RCVTIMEO
|
|---|
| 182 | {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT},
|
|---|
| 183 | #endif
|
|---|
| 184 | #ifdef TCP_FASTACK
|
|---|
| 185 | {"TCP_FASTACK", IPPROTO_TCP, TCP_FASTACK, 0, OPT_INT},
|
|---|
| 186 | #endif
|
|---|
| 187 | {NULL,0,0,0,0}};
|
|---|
| 188 |
|
|---|
| 189 | /****************************************************************************
|
|---|
| 190 | Print socket options.
|
|---|
| 191 | ****************************************************************************/
|
|---|
| 192 |
|
|---|
| 193 | static void print_socket_options(int s)
|
|---|
| 194 | {
|
|---|
| 195 | int value;
|
|---|
| 196 | socklen_t vlen = 4;
|
|---|
| 197 | const smb_socket_option *p = &socket_options[0];
|
|---|
| 198 |
|
|---|
| 199 | /* wrapped in if statement to prevent streams leak in SCO Openserver 5.0 */
|
|---|
| 200 | /* reported on samba-technical --jerry */
|
|---|
| 201 | if ( DEBUGLEVEL >= 5 ) {
|
|---|
| 202 | for (; p->name != NULL; p++) {
|
|---|
| 203 | if (getsockopt(s, p->level, p->option, (void *)&value, &vlen) == -1) {
|
|---|
| 204 | DEBUG(5,("Could not test socket option %s.\n", p->name));
|
|---|
| 205 | } else {
|
|---|
| 206 | DEBUG(5,("socket option %s = %d\n",p->name,value));
|
|---|
| 207 | }
|
|---|
| 208 | }
|
|---|
| 209 | }
|
|---|
| 210 | }
|
|---|
| 211 |
|
|---|
| 212 | /****************************************************************************
|
|---|
| 213 | Set user socket options.
|
|---|
| 214 | ****************************************************************************/
|
|---|
| 215 |
|
|---|
| 216 | void set_socket_options(int fd, const char *options)
|
|---|
| 217 | {
|
|---|
| 218 | fstring tok;
|
|---|
| 219 |
|
|---|
| 220 | while (next_token(&options,tok," \t,", sizeof(tok))) {
|
|---|
| 221 | int ret=0,i;
|
|---|
| 222 | int value = 1;
|
|---|
| 223 | char *p;
|
|---|
| 224 | BOOL got_value = False;
|
|---|
| 225 |
|
|---|
| 226 | if ((p = strchr_m(tok,'='))) {
|
|---|
| 227 | *p = 0;
|
|---|
| 228 | value = atoi(p+1);
|
|---|
| 229 | got_value = True;
|
|---|
| 230 | }
|
|---|
| 231 |
|
|---|
| 232 | for (i=0;socket_options[i].name;i++)
|
|---|
| 233 | if (strequal(socket_options[i].name,tok))
|
|---|
| 234 | break;
|
|---|
| 235 |
|
|---|
| 236 | if (!socket_options[i].name) {
|
|---|
| 237 | DEBUG(0,("Unknown socket option %s\n",tok));
|
|---|
| 238 | continue;
|
|---|
| 239 | }
|
|---|
| 240 |
|
|---|
| 241 | switch (socket_options[i].opttype) {
|
|---|
| 242 | case OPT_BOOL:
|
|---|
| 243 | case OPT_INT:
|
|---|
| 244 | ret = setsockopt(fd,socket_options[i].level,
|
|---|
| 245 | socket_options[i].option,(char *)&value,sizeof(int));
|
|---|
| 246 | break;
|
|---|
| 247 |
|
|---|
| 248 | case OPT_ON:
|
|---|
| 249 | if (got_value)
|
|---|
| 250 | DEBUG(0,("syntax error - %s does not take a value\n",tok));
|
|---|
| 251 |
|
|---|
| 252 | {
|
|---|
| 253 | int on = socket_options[i].value;
|
|---|
| 254 | ret = setsockopt(fd,socket_options[i].level,
|
|---|
| 255 | socket_options[i].option,(char *)&on,sizeof(int));
|
|---|
| 256 | }
|
|---|
| 257 | break;
|
|---|
| 258 | }
|
|---|
| 259 |
|
|---|
| 260 | if (ret != 0)
|
|---|
| 261 | DEBUG(0,("Failed to set socket option %s (Error %s)\n",tok, strerror(errno) ));
|
|---|
| 262 | }
|
|---|
| 263 |
|
|---|
| 264 | print_socket_options(fd);
|
|---|
| 265 | }
|
|---|
| 266 |
|
|---|
| 267 | /****************************************************************************
|
|---|
| 268 | Read from a socket.
|
|---|
| 269 | ****************************************************************************/
|
|---|
| 270 |
|
|---|
| 271 | ssize_t read_udp_socket(int fd,char *buf,size_t len)
|
|---|
| 272 | {
|
|---|
| 273 | ssize_t ret;
|
|---|
| 274 | struct sockaddr_in sock;
|
|---|
| 275 | socklen_t socklen = sizeof(sock);
|
|---|
| 276 |
|
|---|
| 277 | memset((char *)&sock,'\0',socklen);
|
|---|
| 278 | memset((char *)&lastip,'\0',sizeof(lastip));
|
|---|
| 279 | ret = (ssize_t)sys_recvfrom(fd,buf,len,0,(struct sockaddr *)&sock,&socklen);
|
|---|
| 280 | if (ret <= 0) {
|
|---|
| 281 | /* Don't print a low debug error for a non-blocking socket. */
|
|---|
| 282 | if (errno == EAGAIN) {
|
|---|
| 283 | DEBUG(10,("read socket returned EAGAIN. ERRNO=%s\n",strerror(errno)));
|
|---|
| 284 | } else {
|
|---|
| 285 | DEBUG(2,("read socket failed. ERRNO=%s\n",strerror(errno)));
|
|---|
| 286 | }
|
|---|
| 287 | return(0);
|
|---|
| 288 | }
|
|---|
| 289 |
|
|---|
| 290 | lastip = sock.sin_addr;
|
|---|
| 291 | lastport = ntohs(sock.sin_port);
|
|---|
| 292 |
|
|---|
| 293 | DEBUG(10,("read_udp_socket: lastip %s lastport %d read: %lu\n",
|
|---|
| 294 | inet_ntoa(lastip), lastport, (unsigned long)ret));
|
|---|
| 295 |
|
|---|
| 296 | return(ret);
|
|---|
| 297 | }
|
|---|
| 298 |
|
|---|
| 299 | #if 0
|
|---|
| 300 |
|
|---|
| 301 | Socket routines from HEAD - maybe re-enable in future. JRA.
|
|---|
| 302 |
|
|---|
| 303 | /****************************************************************************
|
|---|
| 304 | Work out if we've timed out.
|
|---|
| 305 | ****************************************************************************/
|
|---|
| 306 |
|
|---|
| 307 | static BOOL timeout_until(struct timeval *timeout, const struct timeval *endtime)
|
|---|
| 308 | {
|
|---|
| 309 | struct timeval now;
|
|---|
| 310 | SMB_BIG_INT t_dif;
|
|---|
| 311 |
|
|---|
| 312 | GetTimeOfDay(&now);
|
|---|
| 313 |
|
|---|
| 314 | t_dif = usec_time_diff(endtime, &now);
|
|---|
| 315 | if (t_dif <= 0) {
|
|---|
| 316 | return False;
|
|---|
| 317 | }
|
|---|
| 318 |
|
|---|
| 319 | timeout->tv_sec = (t_dif / (SMB_BIG_INT)1000000);
|
|---|
| 320 | timeout->tv_usec = (t_dif % (SMB_BIG_INT)1000000);
|
|---|
| 321 | return True;
|
|---|
| 322 | }
|
|---|
| 323 |
|
|---|
| 324 | /****************************************************************************
|
|---|
| 325 | Read data from the client, reading exactly N bytes, or until endtime timeout.
|
|---|
| 326 | Use with a non-blocking socket if endtime != NULL.
|
|---|
| 327 | ****************************************************************************/
|
|---|
| 328 |
|
|---|
| 329 | ssize_t read_data_until(int fd,char *buffer,size_t N, const struct timeval *endtime)
|
|---|
| 330 | {
|
|---|
| 331 | ssize_t ret;
|
|---|
| 332 | size_t total=0;
|
|---|
| 333 |
|
|---|
| 334 | #ifdef __OS2__
|
|---|
| 335 | fd_set fds;
|
|---|
| 336 | #endif
|
|---|
| 337 |
|
|---|
| 338 | smb_read_error = 0;
|
|---|
| 339 | #if __OS2__
|
|---|
| 340 | while (total < N) {
|
|---|
| 341 | FD_ZERO(&fds);
|
|---|
| 342 | FD_SET(fd,&fds);
|
|---|
| 343 |
|
|---|
| 344 | ret = sys_select_intr(fd+1,&fds,NULL,NULL,NULL);
|
|---|
| 345 |
|
|---|
| 346 | /* Check if error */
|
|---|
| 347 | if (ret == -1) {
|
|---|
| 348 | /* something is wrong. Maybe the socket is dead? */
|
|---|
| 349 | DEBUG(0,("read_socket_data: select error = %s.\n", strerror(errno) ));
|
|---|
| 350 | smb_read_error = READ_ERROR;
|
|---|
| 351 | return -1;
|
|---|
| 352 | }
|
|---|
| 353 |
|
|---|
| 354 | /* Did we timeout ? */
|
|---|
| 355 | if (ret == 0) {
|
|---|
| 356 | DEBUG(10,("read_socket_data: select timed out ??\n"));
|
|---|
| 357 | smb_read_error = READ_TIMEOUT;
|
|---|
| 358 | return -1;
|
|---|
| 359 | }
|
|---|
| 360 |
|
|---|
| 361 | ret = sys_read(fd,buffer + total,N - total);
|
|---|
| 362 |
|
|---|
| 363 | if (ret == 0) {
|
|---|
| 364 | DEBUG(10,("read_socket_data: recv of %d on %d returned 0. Error = %s\n", (int)(N - total), fd, strerror(errno) ));
|
|---|
| 365 | smb_read_error = READ_EOF;
|
|---|
| 366 | return 0;
|
|---|
| 367 | }
|
|---|
| 368 |
|
|---|
| 369 | if (ret == -1) {
|
|---|
| 370 | DEBUG(0,("read_socket_data: recv failure for %d on %d. Error = %s\n", (int)(N - total), fd, strerror(errno) ));
|
|---|
| 371 | smb_read_error = READ_ERROR;
|
|---|
| 372 | return -1;
|
|---|
| 373 | }
|
|---|
| 374 | total += ret;
|
|---|
| 375 | }
|
|---|
| 376 | #else
|
|---|
| 377 | while (total < N) {
|
|---|
| 378 |
|
|---|
| 379 | if (endtime != NULL) {
|
|---|
| 380 | fd_set r_fds;
|
|---|
| 381 | struct timeval timeout;
|
|---|
| 382 | int selrtn;
|
|---|
| 383 |
|
|---|
| 384 | if (!timeout_until(&timeout, endtime)) {
|
|---|
| 385 | DEBUG(10,("read_data_until: read timed out\n"));
|
|---|
| 386 | smb_read_error = READ_TIMEOUT;
|
|---|
| 387 | return -1;
|
|---|
| 388 | }
|
|---|
| 389 |
|
|---|
| 390 | FD_ZERO(&r_fds);
|
|---|
| 391 | FD_SET(fd, &r_fds);
|
|---|
| 392 |
|
|---|
| 393 | /* Select but ignore EINTR. */
|
|---|
| 394 | selrtn = sys_select_intr(fd+1, &r_fds, NULL, NULL, &timeout);
|
|---|
| 395 | if (selrtn == -1) {
|
|---|
| 396 | /* something is wrong. Maybe the socket is dead? */
|
|---|
| 397 | DEBUG(0,("read_data_until: select error = %s.\n", strerror(errno) ));
|
|---|
| 398 | smb_read_error = READ_ERROR;
|
|---|
| 399 | return -1;
|
|---|
| 400 | }
|
|---|
| 401 |
|
|---|
| 402 | /* Did we timeout ? */
|
|---|
| 403 | if (selrtn == 0) {
|
|---|
| 404 | DEBUG(10,("read_data_until: select timed out.\n"));
|
|---|
| 405 | smb_read_error = READ_TIMEOUT;
|
|---|
| 406 | return -1;
|
|---|
| 407 | }
|
|---|
| 408 | }
|
|---|
| 409 |
|
|---|
| 410 | ret = sys_read(fd,buffer + total,N - total);
|
|---|
| 411 |
|
|---|
| 412 | if (ret == 0) {
|
|---|
| 413 | DEBUG(10,("read_data_until: read of %d returned 0. Error = %s\n", (int)(N - total), strerror(errno) ));
|
|---|
| 414 | smb_read_error = READ_EOF;
|
|---|
| 415 | return 0;
|
|---|
| 416 | }
|
|---|
| 417 |
|
|---|
| 418 | if (ret == -1) {
|
|---|
| 419 | if (errno == EAGAIN) {
|
|---|
| 420 | /* Non-blocking socket with no data available. Try select again. */
|
|---|
| 421 | continue;
|
|---|
| 422 | }
|
|---|
| 423 | DEBUG(0,("read_data_until: read failure for %d. Error = %s\n", (int)(N - total), strerror(errno) ));
|
|---|
| 424 | smb_read_error = READ_ERROR;
|
|---|
| 425 | return -1;
|
|---|
| 426 | }
|
|---|
| 427 | total += ret;
|
|---|
| 428 | }
|
|---|
| 429 | #endif /* __OS2__ */
|
|---|
| 430 | return (ssize_t)total;
|
|---|
| 431 | }
|
|---|
| 432 | #endif
|
|---|
| 433 |
|
|---|
| 434 | /****************************************************************************
|
|---|
| 435 | Read data from a socket with a timout in msec.
|
|---|
| 436 | mincount = if timeout, minimum to read before returning
|
|---|
| 437 | maxcount = number to be read.
|
|---|
| 438 | time_out = timeout in milliseconds
|
|---|
| 439 | ****************************************************************************/
|
|---|
| 440 |
|
|---|
| 441 | ssize_t read_socket_with_timeout(int fd,char *buf,size_t mincnt,size_t maxcnt,unsigned int time_out)
|
|---|
| 442 | {
|
|---|
| 443 | fd_set fds;
|
|---|
| 444 | int selrtn;
|
|---|
| 445 | ssize_t readret;
|
|---|
| 446 | size_t nread = 0;
|
|---|
| 447 | struct timeval timeout;
|
|---|
| 448 |
|
|---|
| 449 | /* just checking .... */
|
|---|
| 450 | if (maxcnt <= 0)
|
|---|
| 451 | return(0);
|
|---|
| 452 |
|
|---|
| 453 | smb_read_error = 0;
|
|---|
| 454 |
|
|---|
| 455 | /* Blocking read */
|
|---|
| 456 | if (time_out == 0) {
|
|---|
| 457 | if (mincnt == 0) {
|
|---|
| 458 | mincnt = maxcnt;
|
|---|
| 459 | }
|
|---|
| 460 |
|
|---|
| 461 | while (nread < mincnt) {
|
|---|
| 462 | readret = sys_read(fd, buf + nread, maxcnt - nread);
|
|---|
| 463 |
|
|---|
| 464 | if (readret == 0) {
|
|---|
| 465 | DEBUG(5,("read_socket_with_timeout: blocking read. EOF from client.\n"));
|
|---|
| 466 | smb_read_error = READ_EOF;
|
|---|
| 467 | return -1;
|
|---|
| 468 | }
|
|---|
| 469 |
|
|---|
| 470 | if (readret == -1) {
|
|---|
| 471 | if (fd == client_fd) {
|
|---|
| 472 | /* Try and give an error message saying what client failed. */
|
|---|
| 473 | DEBUG(0,("read_socket_with_timeout: client %s read error = %s.\n",
|
|---|
| 474 | client_ip_string, strerror(errno) ));
|
|---|
| 475 | } else {
|
|---|
| 476 | DEBUG(0,("read_socket_with_timeout: read error = %s.\n", strerror(errno) ));
|
|---|
| 477 | }
|
|---|
| 478 | smb_read_error = READ_ERROR;
|
|---|
| 479 | return -1;
|
|---|
| 480 | }
|
|---|
| 481 | nread += readret;
|
|---|
| 482 | }
|
|---|
| 483 | return((ssize_t)nread);
|
|---|
| 484 | }
|
|---|
| 485 |
|
|---|
| 486 | /* Most difficult - timeout read */
|
|---|
| 487 | /* If this is ever called on a disk file and
|
|---|
| 488 | mincnt is greater then the filesize then
|
|---|
| 489 | system performance will suffer severely as
|
|---|
| 490 | select always returns true on disk files */
|
|---|
| 491 |
|
|---|
| 492 | /* Set initial timeout */
|
|---|
| 493 | timeout.tv_sec = (time_t)(time_out / 1000);
|
|---|
| 494 | timeout.tv_usec = (long)(1000 * (time_out % 1000));
|
|---|
| 495 |
|
|---|
| 496 | for (nread=0; nread < mincnt; ) {
|
|---|
| 497 | FD_ZERO(&fds);
|
|---|
| 498 | FD_SET(fd,&fds);
|
|---|
| 499 |
|
|---|
| 500 | selrtn = sys_select_intr(fd+1,&fds,NULL,NULL,&timeout);
|
|---|
| 501 |
|
|---|
| 502 | /* Check if error */
|
|---|
| 503 | if (selrtn == -1) {
|
|---|
| 504 | /* something is wrong. Maybe the socket is dead? */
|
|---|
| 505 | if (fd == client_fd) {
|
|---|
| 506 | /* Try and give an error message saying what client failed. */
|
|---|
| 507 | DEBUG(0,("read_socket_with_timeout: timeout read for client %s. select error = %s.\n",
|
|---|
| 508 | client_ip_string, strerror(errno) ));
|
|---|
| 509 | } else {
|
|---|
| 510 | DEBUG(0,("read_socket_with_timeout: timeout read. select error = %s.\n", strerror(errno) ));
|
|---|
| 511 | }
|
|---|
| 512 | smb_read_error = READ_ERROR;
|
|---|
| 513 | return -1;
|
|---|
| 514 | }
|
|---|
| 515 |
|
|---|
| 516 | /* Did we timeout ? */
|
|---|
| 517 | if (selrtn == 0) {
|
|---|
| 518 | DEBUG(10,("read_socket_with_timeout: timeout read. select timed out.\n"));
|
|---|
| 519 | smb_read_error = READ_TIMEOUT;
|
|---|
| 520 | return -1;
|
|---|
| 521 | }
|
|---|
| 522 |
|
|---|
| 523 | readret = sys_read(fd, buf+nread, maxcnt-nread);
|
|---|
| 524 |
|
|---|
| 525 | if (readret == 0) {
|
|---|
| 526 | /* we got EOF on the file descriptor */
|
|---|
| 527 | DEBUG(5,("read_socket_with_timeout: timeout read. EOF from client.\n"));
|
|---|
| 528 | smb_read_error = READ_EOF;
|
|---|
| 529 | return -1;
|
|---|
| 530 | }
|
|---|
| 531 |
|
|---|
| 532 | if (readret == -1) {
|
|---|
| 533 | /* the descriptor is probably dead */
|
|---|
| 534 | if (fd == client_fd) {
|
|---|
| 535 | /* Try and give an error message saying what client failed. */
|
|---|
| 536 | DEBUG(0,("read_socket_with_timeout: timeout read to client %s. read error = %s.\n",
|
|---|
| 537 | client_ip_string, strerror(errno) ));
|
|---|
| 538 | } else {
|
|---|
| 539 | DEBUG(0,("read_socket_with_timeout: timeout read. read error = %s.\n", strerror(errno) ));
|
|---|
| 540 | }
|
|---|
| 541 | smb_read_error = READ_ERROR;
|
|---|
| 542 | return -1;
|
|---|
| 543 | }
|
|---|
| 544 |
|
|---|
| 545 | nread += readret;
|
|---|
| 546 | }
|
|---|
| 547 |
|
|---|
| 548 | /* Return the number we got */
|
|---|
| 549 | return (ssize_t)nread;
|
|---|
| 550 | }
|
|---|
| 551 |
|
|---|
| 552 | /****************************************************************************
|
|---|
| 553 | Read data from the client, reading exactly N bytes.
|
|---|
| 554 | ****************************************************************************/
|
|---|
| 555 |
|
|---|
| 556 | ssize_t read_data(int fd,char *buffer,size_t N)
|
|---|
| 557 | {
|
|---|
| 558 | ssize_t ret;
|
|---|
| 559 | size_t total=0;
|
|---|
| 560 |
|
|---|
| 561 | smb_read_error = 0;
|
|---|
| 562 |
|
|---|
| 563 | while (total < N) {
|
|---|
| 564 | ret = sys_read(fd,buffer + total,N - total);
|
|---|
| 565 |
|
|---|
| 566 | if (ret == 0) {
|
|---|
| 567 | DEBUG(10,("read_data: read of %d returned 0. Error = %s\n", (int)(N - total), strerror(errno) ));
|
|---|
| 568 | smb_read_error = READ_EOF;
|
|---|
| 569 | return 0;
|
|---|
| 570 | }
|
|---|
| 571 |
|
|---|
| 572 | if (ret == -1) {
|
|---|
| 573 | if (fd == client_fd) {
|
|---|
| 574 | /* Try and give an error message saying what client failed. */
|
|---|
| 575 | DEBUG(0,("read_data: read failure for %d bytes to client %s. Error = %s\n",
|
|---|
| 576 | (int)(N - total), client_ip_string, strerror(errno) ));
|
|---|
| 577 | } else {
|
|---|
| 578 | DEBUG(0,("read_data: read failure for %d. Error = %s\n", (int)(N - total), strerror(errno) ));
|
|---|
| 579 | }
|
|---|
| 580 | smb_read_error = READ_ERROR;
|
|---|
| 581 | return -1;
|
|---|
| 582 | }
|
|---|
| 583 | total += ret;
|
|---|
| 584 | }
|
|---|
| 585 | return (ssize_t)total;
|
|---|
| 586 | }
|
|---|
| 587 |
|
|---|
| 588 | /****************************************************************************
|
|---|
| 589 | Write data to a fd.
|
|---|
| 590 | ****************************************************************************/
|
|---|
| 591 |
|
|---|
| 592 | ssize_t write_data(int fd, const char *buffer, size_t N)
|
|---|
| 593 | {
|
|---|
| 594 | size_t total=0;
|
|---|
| 595 | ssize_t ret;
|
|---|
| 596 |
|
|---|
| 597 | while (total < N) {
|
|---|
| 598 | ret = sys_write(fd,buffer + total,N - total);
|
|---|
| 599 |
|
|---|
| 600 | if (ret == -1) {
|
|---|
| 601 | if (fd == client_fd) {
|
|---|
| 602 | /* Try and give an error message saying what client failed. */
|
|---|
| 603 | DEBUG(0,("write_data: write failure in writing to client %s. Error %s\n",
|
|---|
| 604 | client_ip_string, strerror(errno) ));
|
|---|
| 605 | } else {
|
|---|
| 606 | DEBUG(0,("write_data: write failure. Error = %s\n", strerror(errno) ));
|
|---|
| 607 | }
|
|---|
| 608 | return -1;
|
|---|
| 609 | }
|
|---|
| 610 |
|
|---|
| 611 | if (ret == 0) {
|
|---|
| 612 | return total;
|
|---|
| 613 | }
|
|---|
| 614 |
|
|---|
| 615 | total += ret;
|
|---|
| 616 | }
|
|---|
| 617 | return (ssize_t)total;
|
|---|
| 618 | }
|
|---|
| 619 |
|
|---|
| 620 | /****************************************************************************
|
|---|
| 621 | Send a keepalive packet (rfc1002).
|
|---|
| 622 | ****************************************************************************/
|
|---|
| 623 |
|
|---|
| 624 | BOOL send_keepalive(int client)
|
|---|
| 625 | {
|
|---|
| 626 | unsigned char buf[4];
|
|---|
| 627 |
|
|---|
| 628 | buf[0] = SMBkeepalive;
|
|---|
| 629 | buf[1] = buf[2] = buf[3] = 0;
|
|---|
| 630 |
|
|---|
| 631 | return(write_data(client,(char *)buf,4) == 4);
|
|---|
| 632 | }
|
|---|
| 633 |
|
|---|
| 634 |
|
|---|
| 635 | /****************************************************************************
|
|---|
| 636 | Read 4 bytes of a smb packet and return the smb length of the packet.
|
|---|
| 637 | Store the result in the buffer.
|
|---|
| 638 | This version of the function will return a length of zero on receiving
|
|---|
| 639 | a keepalive packet.
|
|---|
| 640 | Timeout is in milliseconds.
|
|---|
| 641 | ****************************************************************************/
|
|---|
| 642 |
|
|---|
| 643 | static ssize_t read_smb_length_return_keepalive(int fd, char *inbuf, unsigned int timeout)
|
|---|
| 644 | {
|
|---|
| 645 | ssize_t len=0;
|
|---|
| 646 | int msg_type;
|
|---|
| 647 | BOOL ok = False;
|
|---|
| 648 |
|
|---|
| 649 | while (!ok) {
|
|---|
| 650 | if (timeout > 0)
|
|---|
| 651 | ok = (read_socket_with_timeout(fd,inbuf,4,4,timeout) == 4);
|
|---|
| 652 | else
|
|---|
| 653 | ok = (read_data(fd,inbuf,4) == 4);
|
|---|
| 654 |
|
|---|
| 655 | if (!ok)
|
|---|
| 656 | return(-1);
|
|---|
| 657 |
|
|---|
| 658 | len = smb_len(inbuf);
|
|---|
| 659 | msg_type = CVAL(inbuf,0);
|
|---|
| 660 |
|
|---|
| 661 | if (msg_type == SMBkeepalive)
|
|---|
| 662 | DEBUG(5,("Got keepalive packet\n"));
|
|---|
| 663 | }
|
|---|
| 664 |
|
|---|
| 665 | DEBUG(10,("got smb length of %lu\n",(unsigned long)len));
|
|---|
| 666 |
|
|---|
| 667 | return(len);
|
|---|
| 668 | }
|
|---|
| 669 |
|
|---|
| 670 | /****************************************************************************
|
|---|
| 671 | Read 4 bytes of a smb packet and return the smb length of the packet.
|
|---|
| 672 | Store the result in the buffer. This version of the function will
|
|---|
| 673 | never return a session keepalive (length of zero).
|
|---|
| 674 | Timeout is in milliseconds.
|
|---|
| 675 | ****************************************************************************/
|
|---|
| 676 |
|
|---|
| 677 | ssize_t read_smb_length(int fd, char *inbuf, unsigned int timeout)
|
|---|
| 678 | {
|
|---|
| 679 | ssize_t len;
|
|---|
| 680 |
|
|---|
| 681 | for(;;) {
|
|---|
| 682 | len = read_smb_length_return_keepalive(fd, inbuf, timeout);
|
|---|
| 683 |
|
|---|
| 684 | if(len < 0)
|
|---|
| 685 | return len;
|
|---|
| 686 |
|
|---|
| 687 | /* Ignore session keepalives. */
|
|---|
| 688 | if(CVAL(inbuf,0) != SMBkeepalive)
|
|---|
| 689 | break;
|
|---|
| 690 | }
|
|---|
| 691 |
|
|---|
| 692 | DEBUG(10,("read_smb_length: got smb length of %lu\n",
|
|---|
| 693 | (unsigned long)len));
|
|---|
| 694 |
|
|---|
| 695 | return len;
|
|---|
| 696 | }
|
|---|
| 697 |
|
|---|
| 698 | /****************************************************************************
|
|---|
| 699 | Read an smb from a fd. Note that the buffer *MUST* be of size
|
|---|
| 700 | BUFFER_SIZE+SAFETY_MARGIN.
|
|---|
| 701 | The timeout is in milliseconds.
|
|---|
| 702 | This function will return on receipt of a session keepalive packet.
|
|---|
| 703 | Doesn't check the MAC on signed packets.
|
|---|
| 704 | ****************************************************************************/
|
|---|
| 705 |
|
|---|
| 706 | BOOL receive_smb_raw(int fd, char *buffer, unsigned int timeout)
|
|---|
| 707 | {
|
|---|
| 708 | ssize_t len,ret;
|
|---|
| 709 |
|
|---|
| 710 | smb_read_error = 0;
|
|---|
| 711 |
|
|---|
| 712 | len = read_smb_length_return_keepalive(fd,buffer,timeout);
|
|---|
| 713 | if (len < 0) {
|
|---|
| 714 | DEBUG(10,("receive_smb_raw: length < 0!\n"));
|
|---|
| 715 |
|
|---|
| 716 | /*
|
|---|
| 717 | * Correct fix. smb_read_error may have already been
|
|---|
| 718 | * set. Only set it here if not already set. Global
|
|---|
| 719 | * variables still suck :-). JRA.
|
|---|
| 720 | */
|
|---|
| 721 |
|
|---|
| 722 | if (smb_read_error == 0)
|
|---|
| 723 | smb_read_error = READ_ERROR;
|
|---|
| 724 | return False;
|
|---|
| 725 | }
|
|---|
| 726 |
|
|---|
| 727 | /*
|
|---|
| 728 | * A WRITEX with CAP_LARGE_WRITEX can be 64k worth of data plus 65 bytes
|
|---|
| 729 | * of header. Don't print the error if this fits.... JRA.
|
|---|
| 730 | */
|
|---|
| 731 |
|
|---|
| 732 | if (len > (BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE)) {
|
|---|
| 733 | DEBUG(0,("Invalid packet length! (%lu bytes).\n",(unsigned long)len));
|
|---|
| 734 | if (len > BUFFER_SIZE + (SAFETY_MARGIN/2)) {
|
|---|
| 735 |
|
|---|
| 736 | /*
|
|---|
| 737 | * Correct fix. smb_read_error may have already been
|
|---|
| 738 | * set. Only set it here if not already set. Global
|
|---|
| 739 | * variables still suck :-). JRA.
|
|---|
| 740 | */
|
|---|
| 741 |
|
|---|
| 742 | if (smb_read_error == 0)
|
|---|
| 743 | smb_read_error = READ_ERROR;
|
|---|
| 744 | return False;
|
|---|
| 745 | }
|
|---|
| 746 | }
|
|---|
| 747 |
|
|---|
| 748 | if(len > 0) {
|
|---|
| 749 | if (timeout > 0) {
|
|---|
| 750 | ret = read_socket_with_timeout(fd,buffer+4,len,len,timeout);
|
|---|
| 751 | } else {
|
|---|
| 752 | ret = read_data(fd,buffer+4,len);
|
|---|
| 753 | }
|
|---|
| 754 |
|
|---|
| 755 | if (ret != len) {
|
|---|
| 756 | if (smb_read_error == 0) {
|
|---|
| 757 | smb_read_error = READ_ERROR;
|
|---|
| 758 | }
|
|---|
| 759 | return False;
|
|---|
| 760 | }
|
|---|
| 761 |
|
|---|
| 762 | /* not all of samba3 properly checks for packet-termination of strings. This
|
|---|
| 763 | ensures that we don't run off into empty space. */
|
|---|
| 764 | SSVAL(buffer+4,len, 0);
|
|---|
| 765 | }
|
|---|
| 766 |
|
|---|
| 767 | return True;
|
|---|
| 768 | }
|
|---|
| 769 |
|
|---|
| 770 | /****************************************************************************
|
|---|
| 771 | Wrapper for receive_smb_raw().
|
|---|
| 772 | Checks the MAC on signed packets.
|
|---|
| 773 | ****************************************************************************/
|
|---|
| 774 |
|
|---|
| 775 | BOOL receive_smb(int fd, char *buffer, unsigned int timeout)
|
|---|
| 776 | {
|
|---|
| 777 | if (!receive_smb_raw(fd, buffer, timeout)) {
|
|---|
| 778 | return False;
|
|---|
| 779 | }
|
|---|
| 780 |
|
|---|
| 781 | /* Check the incoming SMB signature. */
|
|---|
| 782 | if (!srv_check_sign_mac(buffer, True)) {
|
|---|
| 783 | DEBUG(0, ("receive_smb: SMB Signature verification failed on incoming packet!\n"));
|
|---|
| 784 | if (smb_read_error == 0)
|
|---|
| 785 | smb_read_error = READ_BAD_SIG;
|
|---|
| 786 | return False;
|
|---|
| 787 | };
|
|---|
| 788 |
|
|---|
| 789 | return(True);
|
|---|
| 790 | }
|
|---|
| 791 |
|
|---|
| 792 | /****************************************************************************
|
|---|
| 793 | Send an smb to a fd.
|
|---|
| 794 | ****************************************************************************/
|
|---|
| 795 |
|
|---|
| 796 | BOOL send_smb(int fd, char *buffer)
|
|---|
| 797 | {
|
|---|
| 798 | size_t len;
|
|---|
| 799 | size_t nwritten=0;
|
|---|
| 800 | ssize_t ret;
|
|---|
| 801 |
|
|---|
| 802 | /* Sign the outgoing packet if required. */
|
|---|
| 803 | srv_calculate_sign_mac(buffer);
|
|---|
| 804 |
|
|---|
| 805 | len = smb_len(buffer) + 4;
|
|---|
| 806 |
|
|---|
| 807 | while (nwritten < len) {
|
|---|
| 808 | ret = write_data(fd,buffer+nwritten,len - nwritten);
|
|---|
| 809 | if (ret <= 0) {
|
|---|
| 810 | DEBUG(0,("Error writing %d bytes to client. %d. (%s)\n",
|
|---|
| 811 | (int)len,(int)ret, strerror(errno) ));
|
|---|
| 812 | return False;
|
|---|
| 813 | }
|
|---|
| 814 | nwritten += ret;
|
|---|
| 815 | }
|
|---|
| 816 |
|
|---|
| 817 | return True;
|
|---|
| 818 | }
|
|---|
| 819 |
|
|---|
| 820 | /****************************************************************************
|
|---|
| 821 | Open a socket of the specified type, port, and address for incoming data.
|
|---|
| 822 | ****************************************************************************/
|
|---|
| 823 |
|
|---|
| 824 | int open_socket_in( int type, int port, int dlevel, uint32 socket_addr, BOOL rebind )
|
|---|
| 825 | {
|
|---|
| 826 | struct sockaddr_in sock;
|
|---|
| 827 | int res;
|
|---|
| 828 |
|
|---|
| 829 | memset( (char *)&sock, '\0', sizeof(sock) );
|
|---|
| 830 |
|
|---|
| 831 | #ifdef HAVE_SOCK_SIN_LEN
|
|---|
| 832 | sock.sin_len = sizeof(sock);
|
|---|
| 833 | #endif
|
|---|
| 834 | sock.sin_port = htons( port );
|
|---|
| 835 | sock.sin_family = AF_INET;
|
|---|
| 836 | sock.sin_addr.s_addr = socket_addr;
|
|---|
| 837 |
|
|---|
| 838 | res = socket( AF_INET, type, 0 );
|
|---|
| 839 | if( res == -1 ) {
|
|---|
| 840 | if( DEBUGLVL(0) ) {
|
|---|
| 841 | dbgtext( "open_socket_in(): socket() call failed: " );
|
|---|
| 842 | dbgtext( "%s\n", strerror( errno ) );
|
|---|
| 843 | }
|
|---|
| 844 | return -1;
|
|---|
| 845 | }
|
|---|
| 846 |
|
|---|
| 847 | /* This block sets/clears the SO_REUSEADDR and possibly SO_REUSEPORT. */
|
|---|
| 848 | {
|
|---|
| 849 | int val = rebind ? 1 : 0;
|
|---|
| 850 | if( setsockopt(res,SOL_SOCKET,SO_REUSEADDR,(char *)&val,sizeof(val)) == -1 ) {
|
|---|
| 851 | if( DEBUGLVL( dlevel ) ) {
|
|---|
| 852 | dbgtext( "open_socket_in(): setsockopt: " );
|
|---|
| 853 | dbgtext( "SO_REUSEADDR = %s ", val?"True":"False" );
|
|---|
| 854 | dbgtext( "on port %d failed ", port );
|
|---|
| 855 | dbgtext( "with error = %s\n", strerror(errno) );
|
|---|
| 856 | }
|
|---|
| 857 | }
|
|---|
| 858 | #ifdef SO_REUSEPORT
|
|---|
| 859 | if( setsockopt(res,SOL_SOCKET,SO_REUSEPORT,(char *)&val,sizeof(val)) == -1 ) {
|
|---|
| 860 | if( DEBUGLVL( dlevel ) ) {
|
|---|
| 861 | dbgtext( "open_socket_in(): setsockopt: ");
|
|---|
| 862 | dbgtext( "SO_REUSEPORT = %s ", val?"True":"False" );
|
|---|
| 863 | dbgtext( "on port %d failed ", port );
|
|---|
| 864 | dbgtext( "with error = %s\n", strerror(errno) );
|
|---|
| 865 | }
|
|---|
| 866 | }
|
|---|
| 867 | #endif /* SO_REUSEPORT */
|
|---|
| 868 | }
|
|---|
| 869 |
|
|---|
| 870 | /* now we've got a socket - we need to bind it */
|
|---|
| 871 | if( bind( res, (struct sockaddr *)&sock, sizeof(sock) ) == -1 ) {
|
|---|
| 872 | if( DEBUGLVL(dlevel) && (port == SMB_PORT1 || port == SMB_PORT2 || port == NMB_PORT) ) {
|
|---|
| 873 | dbgtext( "bind failed on port %d ", port );
|
|---|
| 874 | dbgtext( "socket_addr = %s.\n", inet_ntoa( sock.sin_addr ) );
|
|---|
| 875 | dbgtext( "Error = %s\n", strerror(errno) );
|
|---|
| 876 | }
|
|---|
| 877 | close( res );
|
|---|
| 878 | return( -1 );
|
|---|
| 879 | }
|
|---|
| 880 |
|
|---|
| 881 | DEBUG( 10, ( "bind succeeded on port %d\n", port ) );
|
|---|
| 882 |
|
|---|
| 883 | return( res );
|
|---|
| 884 | }
|
|---|
| 885 |
|
|---|
| 886 | /****************************************************************************
|
|---|
| 887 | Create an outgoing socket. timeout is in milliseconds.
|
|---|
| 888 | **************************************************************************/
|
|---|
| 889 |
|
|---|
| 890 | int open_socket_out(int type, struct in_addr *addr, int port ,int timeout)
|
|---|
| 891 | {
|
|---|
| 892 | struct sockaddr_in sock_out;
|
|---|
| 893 | int res,ret;
|
|---|
| 894 | int connect_loop = 10;
|
|---|
| 895 | int increment = 10;
|
|---|
| 896 |
|
|---|
| 897 | /* create a socket to write to */
|
|---|
| 898 | res = socket(PF_INET, type, 0);
|
|---|
| 899 | if (res == -1) {
|
|---|
| 900 | DEBUG(0,("socket error (%s)\n", strerror(errno)));
|
|---|
| 901 | return -1;
|
|---|
| 902 | }
|
|---|
| 903 |
|
|---|
| 904 | if (type != SOCK_STREAM)
|
|---|
| 905 | return(res);
|
|---|
| 906 |
|
|---|
| 907 | memset((char *)&sock_out,'\0',sizeof(sock_out));
|
|---|
| 908 | putip((char *)&sock_out.sin_addr,(char *)addr);
|
|---|
| 909 |
|
|---|
| 910 | sock_out.sin_port = htons( port );
|
|---|
| 911 | sock_out.sin_family = PF_INET;
|
|---|
| 912 |
|
|---|
| 913 | /* set it non-blocking */
|
|---|
| 914 | set_blocking(res,False);
|
|---|
| 915 |
|
|---|
| 916 | DEBUG(3,("Connecting to %s at port %d\n",inet_ntoa(*addr),port));
|
|---|
| 917 |
|
|---|
| 918 | /* and connect it to the destination */
|
|---|
| 919 | connect_again:
|
|---|
| 920 |
|
|---|
| 921 | ret = connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out));
|
|---|
| 922 |
|
|---|
| 923 | /* Some systems return EAGAIN when they mean EINPROGRESS */
|
|---|
| 924 | if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY ||
|
|---|
| 925 | errno == EAGAIN) && (connect_loop < timeout) ) {
|
|---|
| 926 | smb_msleep(connect_loop);
|
|---|
| 927 | timeout -= connect_loop;
|
|---|
| 928 | connect_loop += increment;
|
|---|
| 929 | if (increment < 250) {
|
|---|
| 930 | /* After 8 rounds we end up at a max of 255 msec */
|
|---|
| 931 | increment *= 1.5;
|
|---|
| 932 | }
|
|---|
| 933 | goto connect_again;
|
|---|
| 934 | }
|
|---|
| 935 |
|
|---|
| 936 | if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY ||
|
|---|
| 937 | errno == EAGAIN)) {
|
|---|
| 938 | DEBUG(1,("timeout connecting to %s:%d\n",inet_ntoa(*addr),port));
|
|---|
| 939 | close(res);
|
|---|
| 940 | return -1;
|
|---|
| 941 | }
|
|---|
| 942 |
|
|---|
| 943 | #ifdef EISCONN
|
|---|
| 944 |
|
|---|
| 945 | if (ret < 0 && errno == EISCONN) {
|
|---|
| 946 | errno = 0;
|
|---|
| 947 | ret = 0;
|
|---|
| 948 | }
|
|---|
| 949 | #endif
|
|---|
| 950 |
|
|---|
| 951 | if (ret < 0) {
|
|---|
| 952 | DEBUG(2,("error connecting to %s:%d (%s)\n",
|
|---|
| 953 | inet_ntoa(*addr),port,strerror(errno)));
|
|---|
| 954 | close(res);
|
|---|
| 955 | return -1;
|
|---|
| 956 | }
|
|---|
| 957 |
|
|---|
| 958 | /* set it blocking again */
|
|---|
| 959 | set_blocking(res,True);
|
|---|
| 960 |
|
|---|
| 961 | return res;
|
|---|
| 962 | }
|
|---|
| 963 |
|
|---|
| 964 | /****************************************************************************
|
|---|
| 965 | Create an outgoing TCP socket to any of the addrs. This is for
|
|---|
| 966 | simultaneous connects to port 445 and 139 of a host or even a variety
|
|---|
| 967 | of DC's all of which are equivalent for our purposes.
|
|---|
| 968 | **************************************************************************/
|
|---|
| 969 |
|
|---|
| 970 | BOOL open_any_socket_out(struct sockaddr_in *addrs, int num_addrs,
|
|---|
| 971 | int timeout, int *fd_index, int *fd)
|
|---|
| 972 | {
|
|---|
| 973 | int i, resulting_index, res;
|
|---|
| 974 | int *sockets;
|
|---|
| 975 | BOOL good_connect;
|
|---|
| 976 |
|
|---|
| 977 | fd_set r_fds, wr_fds;
|
|---|
| 978 | struct timeval tv;
|
|---|
| 979 | int maxfd;
|
|---|
| 980 |
|
|---|
| 981 | int connect_loop = 10000; /* 10 milliseconds */
|
|---|
| 982 |
|
|---|
| 983 | timeout *= 1000; /* convert to microseconds */
|
|---|
| 984 |
|
|---|
| 985 | sockets = SMB_MALLOC_ARRAY(int, num_addrs);
|
|---|
| 986 |
|
|---|
| 987 | if (sockets == NULL)
|
|---|
| 988 | return False;
|
|---|
| 989 |
|
|---|
| 990 | resulting_index = -1;
|
|---|
| 991 |
|
|---|
| 992 | for (i=0; i<num_addrs; i++)
|
|---|
| 993 | sockets[i] = -1;
|
|---|
| 994 |
|
|---|
| 995 | for (i=0; i<num_addrs; i++) {
|
|---|
| 996 | sockets[i] = socket(PF_INET, SOCK_STREAM, 0);
|
|---|
| 997 | if (sockets[i] < 0)
|
|---|
| 998 | goto done;
|
|---|
| 999 | set_blocking(sockets[i], False);
|
|---|
| 1000 | }
|
|---|
| 1001 |
|
|---|
| 1002 | connect_again:
|
|---|
| 1003 | good_connect = False;
|
|---|
| 1004 |
|
|---|
| 1005 | for (i=0; i<num_addrs; i++) {
|
|---|
| 1006 |
|
|---|
| 1007 | if (sockets[i] == -1)
|
|---|
| 1008 | continue;
|
|---|
| 1009 |
|
|---|
| 1010 | if (connect(sockets[i], (struct sockaddr *)&(addrs[i]),
|
|---|
| 1011 | sizeof(*addrs)) == 0) {
|
|---|
| 1012 | /* Rather unlikely as we are non-blocking, but it
|
|---|
| 1013 | * might actually happen. */
|
|---|
| 1014 | resulting_index = i;
|
|---|
| 1015 | goto done;
|
|---|
| 1016 | }
|
|---|
| 1017 |
|
|---|
| 1018 | if (errno == EINPROGRESS || errno == EALREADY ||
|
|---|
| 1019 | #ifdef EISCONN
|
|---|
| 1020 | errno == EISCONN ||
|
|---|
| 1021 | #endif
|
|---|
| 1022 | errno == EAGAIN || errno == EINTR) {
|
|---|
| 1023 | /* These are the error messages that something is
|
|---|
| 1024 | progressing. */
|
|---|
| 1025 | good_connect = True;
|
|---|
| 1026 | } else if (errno != 0) {
|
|---|
| 1027 | /* There was a direct error */
|
|---|
| 1028 | close(sockets[i]);
|
|---|
| 1029 | sockets[i] = -1;
|
|---|
| 1030 | }
|
|---|
| 1031 | }
|
|---|
| 1032 |
|
|---|
| 1033 | if (!good_connect) {
|
|---|
| 1034 | /* All of the connect's resulted in real error conditions */
|
|---|
| 1035 | goto done;
|
|---|
| 1036 | }
|
|---|
| 1037 |
|
|---|
| 1038 | /* Lets see if any of the connect attempts succeeded */
|
|---|
| 1039 |
|
|---|
| 1040 | maxfd = 0;
|
|---|
| 1041 | FD_ZERO(&wr_fds);
|
|---|
| 1042 | FD_ZERO(&r_fds);
|
|---|
| 1043 |
|
|---|
| 1044 | for (i=0; i<num_addrs; i++) {
|
|---|
| 1045 | if (sockets[i] == -1)
|
|---|
| 1046 | continue;
|
|---|
| 1047 | FD_SET(sockets[i], &wr_fds);
|
|---|
| 1048 | FD_SET(sockets[i], &r_fds);
|
|---|
| 1049 | if (sockets[i]>maxfd)
|
|---|
| 1050 | maxfd = sockets[i];
|
|---|
| 1051 | }
|
|---|
| 1052 |
|
|---|
| 1053 | tv.tv_sec = 0;
|
|---|
| 1054 | tv.tv_usec = connect_loop;
|
|---|
| 1055 |
|
|---|
| 1056 | res = sys_select_intr(maxfd+1, &r_fds, &wr_fds, NULL, &tv);
|
|---|
| 1057 |
|
|---|
| 1058 | if (res < 0)
|
|---|
| 1059 | goto done;
|
|---|
| 1060 |
|
|---|
| 1061 | if (res == 0)
|
|---|
| 1062 | goto next_round;
|
|---|
| 1063 |
|
|---|
| 1064 | for (i=0; i<num_addrs; i++) {
|
|---|
| 1065 |
|
|---|
| 1066 | if (sockets[i] == -1)
|
|---|
| 1067 | continue;
|
|---|
| 1068 |
|
|---|
| 1069 | /* Stevens, Network Programming says that if there's a
|
|---|
| 1070 | * successful connect, the socket is only writable. Upon an
|
|---|
| 1071 | * error, it's both readable and writable. */
|
|---|
| 1072 |
|
|---|
| 1073 | if (FD_ISSET(sockets[i], &r_fds) &&
|
|---|
| 1074 | FD_ISSET(sockets[i], &wr_fds)) {
|
|---|
| 1075 | /* readable and writable, so it's an error */
|
|---|
| 1076 | close(sockets[i]);
|
|---|
| 1077 | sockets[i] = -1;
|
|---|
| 1078 | continue;
|
|---|
| 1079 | }
|
|---|
| 1080 |
|
|---|
| 1081 | if (!FD_ISSET(sockets[i], &r_fds) &&
|
|---|
| 1082 | FD_ISSET(sockets[i], &wr_fds)) {
|
|---|
| 1083 | /* Only writable, so it's connected */
|
|---|
| 1084 | resulting_index = i;
|
|---|
| 1085 | goto done;
|
|---|
| 1086 | }
|
|---|
| 1087 | }
|
|---|
| 1088 |
|
|---|
| 1089 | next_round:
|
|---|
| 1090 |
|
|---|
| 1091 | timeout -= connect_loop;
|
|---|
| 1092 | if (timeout <= 0)
|
|---|
| 1093 | goto done;
|
|---|
| 1094 | connect_loop *= 1.5;
|
|---|
| 1095 | if (connect_loop > timeout)
|
|---|
| 1096 | connect_loop = timeout;
|
|---|
| 1097 | goto connect_again;
|
|---|
| 1098 |
|
|---|
| 1099 | done:
|
|---|
| 1100 | for (i=0; i<num_addrs; i++) {
|
|---|
| 1101 | if (i == resulting_index)
|
|---|
| 1102 | continue;
|
|---|
| 1103 | if (sockets[i] >= 0)
|
|---|
| 1104 | close(sockets[i]);
|
|---|
| 1105 | }
|
|---|
| 1106 |
|
|---|
| 1107 | if (resulting_index >= 0) {
|
|---|
| 1108 | *fd_index = resulting_index;
|
|---|
| 1109 | *fd = sockets[*fd_index];
|
|---|
| 1110 | set_blocking(*fd, True);
|
|---|
| 1111 | }
|
|---|
| 1112 |
|
|---|
| 1113 | free(sockets);
|
|---|
| 1114 |
|
|---|
| 1115 | return (resulting_index >= 0);
|
|---|
| 1116 | }
|
|---|
| 1117 | /****************************************************************************
|
|---|
| 1118 | Open a connected UDP socket to host on port
|
|---|
| 1119 | **************************************************************************/
|
|---|
| 1120 |
|
|---|
| 1121 | int open_udp_socket(const char *host, int port)
|
|---|
| 1122 | {
|
|---|
| 1123 | int type = SOCK_DGRAM;
|
|---|
| 1124 | struct sockaddr_in sock_out;
|
|---|
| 1125 | int res;
|
|---|
| 1126 | struct in_addr *addr;
|
|---|
| 1127 |
|
|---|
| 1128 | addr = interpret_addr2(host);
|
|---|
| 1129 |
|
|---|
| 1130 | res = socket(PF_INET, type, 0);
|
|---|
| 1131 | if (res == -1) {
|
|---|
| 1132 | return -1;
|
|---|
| 1133 | }
|
|---|
| 1134 |
|
|---|
| 1135 | memset((char *)&sock_out,'\0',sizeof(sock_out));
|
|---|
| 1136 | putip((char *)&sock_out.sin_addr,(char *)addr);
|
|---|
| 1137 | sock_out.sin_port = htons(port);
|
|---|
| 1138 | sock_out.sin_family = PF_INET;
|
|---|
| 1139 |
|
|---|
| 1140 | if (connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out))) {
|
|---|
| 1141 | close(res);
|
|---|
| 1142 | return -1;
|
|---|
| 1143 | }
|
|---|
| 1144 |
|
|---|
| 1145 | return res;
|
|---|
| 1146 | }
|
|---|
| 1147 |
|
|---|
| 1148 |
|
|---|
| 1149 | /*******************************************************************
|
|---|
| 1150 | Matchname - determine if host name matches IP address. Used to
|
|---|
| 1151 | confirm a hostname lookup to prevent spoof attacks.
|
|---|
| 1152 | ******************************************************************/
|
|---|
| 1153 |
|
|---|
| 1154 | static BOOL matchname(char *remotehost,struct in_addr addr)
|
|---|
| 1155 | {
|
|---|
| 1156 | struct hostent *hp;
|
|---|
| 1157 | int i;
|
|---|
| 1158 |
|
|---|
| 1159 | if ((hp = sys_gethostbyname(remotehost)) == 0) {
|
|---|
| 1160 | DEBUG(0,("sys_gethostbyname(%s): lookup failure.\n", remotehost));
|
|---|
| 1161 | return False;
|
|---|
| 1162 | }
|
|---|
| 1163 |
|
|---|
| 1164 | /*
|
|---|
| 1165 | * Make sure that gethostbyname() returns the "correct" host name.
|
|---|
| 1166 | * Unfortunately, gethostbyname("localhost") sometimes yields
|
|---|
| 1167 | * "localhost.domain". Since the latter host name comes from the
|
|---|
| 1168 | * local DNS, we just have to trust it (all bets are off if the local
|
|---|
| 1169 | * DNS is perverted). We always check the address list, though.
|
|---|
| 1170 | */
|
|---|
| 1171 |
|
|---|
| 1172 | if (!strequal(remotehost, hp->h_name)
|
|---|
| 1173 | && !strequal(remotehost, "localhost")) {
|
|---|
| 1174 | DEBUG(0,("host name/name mismatch: %s != %s\n",
|
|---|
| 1175 | remotehost, hp->h_name));
|
|---|
| 1176 | return False;
|
|---|
| 1177 | }
|
|---|
| 1178 |
|
|---|
| 1179 | /* Look up the host address in the address list we just got. */
|
|---|
| 1180 | for (i = 0; hp->h_addr_list[i]; i++) {
|
|---|
| 1181 | if (memcmp(hp->h_addr_list[i], (char *) & addr, sizeof(addr)) == 0)
|
|---|
| 1182 | return True;
|
|---|
| 1183 | }
|
|---|
| 1184 |
|
|---|
| 1185 | /*
|
|---|
| 1186 | * The host name does not map to the original host address. Perhaps
|
|---|
| 1187 | * someone has compromised a name server. More likely someone botched
|
|---|
| 1188 | * it, but that could be dangerous, too.
|
|---|
| 1189 | */
|
|---|
| 1190 |
|
|---|
| 1191 | DEBUG(0,("host name/address mismatch: %s != %s\n",
|
|---|
| 1192 | inet_ntoa(addr), hp->h_name));
|
|---|
| 1193 | return False;
|
|---|
| 1194 | }
|
|---|
| 1195 |
|
|---|
| 1196 | /*******************************************************************
|
|---|
| 1197 | Return the DNS name of the remote end of a socket.
|
|---|
| 1198 | ******************************************************************/
|
|---|
| 1199 |
|
|---|
| 1200 | char *get_peer_name(int fd, BOOL force_lookup)
|
|---|
| 1201 | {
|
|---|
| 1202 | static pstring name_buf;
|
|---|
| 1203 | pstring tmp_name;
|
|---|
| 1204 | static fstring addr_buf;
|
|---|
| 1205 | struct hostent *hp;
|
|---|
| 1206 | struct in_addr addr;
|
|---|
| 1207 | char *p;
|
|---|
| 1208 |
|
|---|
| 1209 | /* reverse lookups can be *very* expensive, and in many
|
|---|
| 1210 | situations won't work because many networks don't link dhcp
|
|---|
| 1211 | with dns. To avoid the delay we avoid the lookup if
|
|---|
| 1212 | possible */
|
|---|
| 1213 | if (!lp_hostname_lookups() && (force_lookup == False)) {
|
|---|
| 1214 | return get_peer_addr(fd);
|
|---|
| 1215 | }
|
|---|
| 1216 |
|
|---|
| 1217 | p = get_peer_addr(fd);
|
|---|
| 1218 |
|
|---|
| 1219 | /* it might be the same as the last one - save some DNS work */
|
|---|
| 1220 | if (strcmp(p, addr_buf) == 0)
|
|---|
| 1221 | return name_buf;
|
|---|
| 1222 |
|
|---|
| 1223 | pstrcpy(name_buf,"UNKNOWN");
|
|---|
| 1224 | if (fd == -1)
|
|---|
| 1225 | return name_buf;
|
|---|
| 1226 |
|
|---|
| 1227 | fstrcpy(addr_buf, p);
|
|---|
| 1228 |
|
|---|
| 1229 | addr = *interpret_addr2(p);
|
|---|
| 1230 |
|
|---|
| 1231 | /* Look up the remote host name. */
|
|---|
| 1232 | if ((hp = gethostbyaddr((char *)&addr.s_addr, sizeof(addr.s_addr), AF_INET)) == 0) {
|
|---|
| 1233 | DEBUG(1,("Gethostbyaddr failed for %s\n",p));
|
|---|
| 1234 | pstrcpy(name_buf, p);
|
|---|
| 1235 | } else {
|
|---|
| 1236 | pstrcpy(name_buf,(char *)hp->h_name);
|
|---|
| 1237 | if (!matchname(name_buf, addr)) {
|
|---|
| 1238 | DEBUG(0,("Matchname failed on %s %s\n",name_buf,p));
|
|---|
| 1239 | pstrcpy(name_buf,"UNKNOWN");
|
|---|
| 1240 | }
|
|---|
| 1241 | }
|
|---|
| 1242 |
|
|---|
| 1243 | /* can't pass the same source and dest strings in when you
|
|---|
| 1244 | use --enable-developer or the clobber_region() call will
|
|---|
| 1245 | get you */
|
|---|
| 1246 |
|
|---|
| 1247 | pstrcpy( tmp_name, name_buf );
|
|---|
| 1248 | alpha_strcpy(name_buf, tmp_name, "_-.", sizeof(name_buf));
|
|---|
| 1249 | if (strstr(name_buf,"..")) {
|
|---|
| 1250 | pstrcpy(name_buf, "UNKNOWN");
|
|---|
| 1251 | }
|
|---|
| 1252 |
|
|---|
| 1253 | return name_buf;
|
|---|
| 1254 | }
|
|---|
| 1255 |
|
|---|
| 1256 | /*******************************************************************
|
|---|
| 1257 | Return the IP addr of the remote end of a socket as a string.
|
|---|
| 1258 | ******************************************************************/
|
|---|
| 1259 |
|
|---|
| 1260 | char *get_peer_addr(int fd)
|
|---|
| 1261 | {
|
|---|
| 1262 | struct sockaddr sa;
|
|---|
| 1263 | struct sockaddr_in *sockin = (struct sockaddr_in *) (&sa);
|
|---|
| 1264 | socklen_t length = sizeof(sa);
|
|---|
| 1265 | static fstring addr_buf;
|
|---|
| 1266 |
|
|---|
| 1267 | fstrcpy(addr_buf,"0.0.0.0");
|
|---|
| 1268 |
|
|---|
| 1269 | if (fd == -1) {
|
|---|
| 1270 | return addr_buf;
|
|---|
| 1271 | }
|
|---|
| 1272 |
|
|---|
| 1273 | if (getpeername(fd, &sa, &length) < 0) {
|
|---|
| 1274 | DEBUG(0,("getpeername failed. Error was %s\n", strerror(errno) ));
|
|---|
| 1275 | return addr_buf;
|
|---|
| 1276 | }
|
|---|
| 1277 |
|
|---|
| 1278 | fstrcpy(addr_buf,(char *)inet_ntoa(sockin->sin_addr));
|
|---|
| 1279 |
|
|---|
| 1280 | return addr_buf;
|
|---|
| 1281 | }
|
|---|
| 1282 |
|
|---|
| 1283 | /*******************************************************************
|
|---|
| 1284 | Create protected unix domain socket.
|
|---|
| 1285 |
|
|---|
| 1286 | Some unixes cannot set permissions on a ux-dom-sock, so we
|
|---|
| 1287 | have to make sure that the directory contains the protection
|
|---|
| 1288 | permissions instead.
|
|---|
| 1289 | ******************************************************************/
|
|---|
| 1290 |
|
|---|
| 1291 | int create_pipe_sock(const char *socket_dir,
|
|---|
| 1292 | const char *socket_name,
|
|---|
| 1293 | mode_t dir_perms)
|
|---|
| 1294 | {
|
|---|
| 1295 | #ifdef HAVE_UNIXSOCKET
|
|---|
| 1296 | struct sockaddr_un sunaddr;
|
|---|
| 1297 | struct stat st;
|
|---|
| 1298 | int sock;
|
|---|
| 1299 | mode_t old_umask;
|
|---|
| 1300 | pstring path;
|
|---|
| 1301 |
|
|---|
| 1302 | old_umask = umask(0);
|
|---|
| 1303 |
|
|---|
| 1304 | /* Create the socket directory or reuse the existing one */
|
|---|
| 1305 |
|
|---|
| 1306 | #ifndef __OS2__
|
|---|
| 1307 | if (lstat(socket_dir, &st) == -1) {
|
|---|
| 1308 | if (errno == ENOENT) {
|
|---|
| 1309 | /* Create directory */
|
|---|
| 1310 | if (mkdir(socket_dir, dir_perms) == -1) {
|
|---|
| 1311 | DEBUG(0, ("error creating socket directory "
|
|---|
| 1312 | "%s: %s\n", socket_dir,
|
|---|
| 1313 | strerror(errno)));
|
|---|
| 1314 | goto out_umask;
|
|---|
| 1315 | }
|
|---|
| 1316 | } else {
|
|---|
| 1317 | DEBUG(0, ("lstat failed on socket directory %s: %s\n",
|
|---|
| 1318 | socket_dir, strerror(errno)));
|
|---|
| 1319 | goto out_umask;
|
|---|
| 1320 | }
|
|---|
| 1321 | } else {
|
|---|
| 1322 | /* Check ownership and permission on existing directory */
|
|---|
| 1323 | if (!S_ISDIR(st.st_mode)) {
|
|---|
| 1324 | DEBUG(0, ("socket directory %s isn't a directory\n",
|
|---|
| 1325 | socket_dir));
|
|---|
| 1326 | goto out_umask;
|
|---|
| 1327 | }
|
|---|
| 1328 | if ((st.st_uid != sec_initial_uid()) ||
|
|---|
| 1329 | ((st.st_mode & 0777) != dir_perms)) {
|
|---|
| 1330 | DEBUG(0, ("invalid permissions on socket directory "
|
|---|
| 1331 | "%s\n", socket_dir));
|
|---|
| 1332 | goto out_umask;
|
|---|
| 1333 | }
|
|---|
| 1334 | }
|
|---|
| 1335 | #endif
|
|---|
| 1336 | /* Create the socket file */
|
|---|
| 1337 |
|
|---|
| 1338 | sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
|---|
| 1339 |
|
|---|
| 1340 | if (sock == -1) {
|
|---|
| 1341 | perror("socket");
|
|---|
| 1342 | goto out_umask;
|
|---|
| 1343 | }
|
|---|
| 1344 |
|
|---|
| 1345 | #ifdef __OS2__
|
|---|
| 1346 | pstr_sprintf(path, "\\socket\\samba\\%s\\%s", socket_dir, socket_name);
|
|---|
| 1347 | #else
|
|---|
| 1348 | pstr_sprintf(path, "%s/%s", socket_dir, socket_name);
|
|---|
| 1349 | #endif
|
|---|
| 1350 |
|
|---|
| 1351 | unlink(path);
|
|---|
| 1352 | memset(&sunaddr, 0, sizeof(sunaddr));
|
|---|
| 1353 | sunaddr.sun_family = AF_UNIX;
|
|---|
| 1354 | safe_strcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path)-1);
|
|---|
| 1355 |
|
|---|
| 1356 | if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1) {
|
|---|
| 1357 | DEBUG(0, ("bind failed on pipe socket %s: %s\n", path,
|
|---|
| 1358 | strerror(errno)));
|
|---|
| 1359 | goto out_close;
|
|---|
| 1360 | }
|
|---|
| 1361 |
|
|---|
| 1362 | if (listen(sock, 5) == -1) {
|
|---|
| 1363 | DEBUG(0, ("listen failed on pipe socket %s: %s\n", path,
|
|---|
| 1364 | strerror(errno)));
|
|---|
| 1365 | goto out_close;
|
|---|
| 1366 | }
|
|---|
| 1367 |
|
|---|
| 1368 | umask(old_umask);
|
|---|
| 1369 | return sock;
|
|---|
| 1370 |
|
|---|
| 1371 | out_close:
|
|---|
| 1372 | close(sock);
|
|---|
| 1373 |
|
|---|
| 1374 | out_umask:
|
|---|
| 1375 | umask(old_umask);
|
|---|
| 1376 | return -1;
|
|---|
| 1377 |
|
|---|
| 1378 | #else
|
|---|
| 1379 | DEBUG(0, ("create_pipe_sock: No Unix sockets on this system\n"));
|
|---|
| 1380 | return -1;
|
|---|
| 1381 | #endif /* HAVE_UNIXSOCKET */
|
|---|
| 1382 | }
|
|---|