static BOOL open_sockets_smbd(BOOL is_daemon, BOOL interactive, const char *smb_ports) { int num_interfaces = iface_count(); int num_sockets = 0; int fd_listenset[FD_SETSIZE]; fd_set listen_set; int s; int maxfd = 0; int i; char *ports; if (!is_daemon) { return open_sockets_inetd(); } #ifdef HAVE_ATEXIT { static int atexit_set; if(atexit_set == 0) { atexit_set=1; atexit(killkids); } } #endif #ifndef _XBOX /* Stop zombies */ CatchChild(); #endif FD_ZERO(&listen_set); /* use a reasonable default set of ports - listing on 445 and 139 */ if (!smb_ports) { ports = lp_smb_ports(); if (!ports || !*ports) { ports = smb_xstrdup(SMB_PORTS); } else { ports = smb_xstrdup(ports); } } else { ports = smb_xstrdup(smb_ports); } if (lp_interfaces() && lp_bind_interfaces_only()) { /* We have been given an interfaces line, and been told to only bind to those interfaces. Create a socket per interface and bind to only these. */ /* Now open a listen socket for each of the interfaces. */ for(i = 0; i < num_interfaces; i++) { struct in_addr *ifip = iface_n_ip(i); fstring tok; const char *ptr; if(ifip == NULL) { DEBUG(0,("open_sockets_smbd: interface %d has NULL IP address !\n", i)); continue; } for (ptr=ports; next_token(&ptr, tok, " \t,", sizeof(tok)); ) { unsigned port = atoi(tok); if (port == 0) { continue; } s = fd_listenset[num_sockets] = open_socket_in(SOCK_STREAM, port, 0, ifip->s_addr, True); if(s == -1) return False; /* ready to listen */ set_socket_options(s,"SO_KEEPALIVE"); set_socket_options(s,user_socket_options); /* Set server socket to non-blocking for the accept. */ set_blocking(s,False); if (listen(s, SMBD_LISTEN_BACKLOG) == -1) { DEBUG(0,("listen: %s\n",strerror(errno))); close(s); return False; } FD_SET(s,&listen_set); maxfd = MAX( maxfd, s); num_sockets++; if (num_sockets >= FD_SETSIZE) { DEBUG(0,("open_sockets_smbd: Too many sockets to bind to\n")); return False; } } } } else { /* Just bind to 0.0.0.0 - accept connections from anywhere. */ fstring tok; const char *ptr; num_interfaces = 1; for (ptr=ports; next_token(&ptr, tok, " \t,", sizeof(tok)); ) { unsigned port = atoi(tok); if (port == 0) continue; /* open an incoming socket */ s = open_socket_in(SOCK_STREAM, port, 0, interpret_addr(lp_socket_address()),True); if (s == -1) return(False); /* ready to listen */ #ifndef _XBOX set_socket_options(s,"SO_KEEPALIVE"); #endif set_socket_options(s,user_socket_options); /* Set server socket to non-blocking for the accept. */ set_blocking(s,False); if (listen(s, SMBD_LISTEN_BACKLOG) == -1) { DEBUG(0,("open_sockets_smbd: listen: %s\n", strerror(errno))); close(s); return False; } fd_listenset[num_sockets] = s; FD_SET(s,&listen_set); maxfd = MAX( maxfd, s); num_sockets++; if (num_sockets >= FD_SETSIZE) { DEBUG(0,("open_sockets_smbd: Too many sockets to bind to\n")); return False; } } } SAFE_FREE(ports); /* Listen to messages */ message_register(MSG_SMB_SAM_SYNC, msg_sam_sync); message_register(MSG_SMB_SAM_REPL, msg_sam_repl); message_register(MSG_SHUTDOWN, msg_exit_server); message_register(MSG_SMB_FILE_RENAME, msg_file_was_renamed); message_register(MSG_SMB_CONF_UPDATED, smb_conf_updated); #ifdef DEVELOPER message_register(MSG_SMB_INJECT_FAULT, msg_inject_fault); #endif /* now accept incoming connections - forking a new process for each incoming connection */ DEBUG(2,("waiting for a connection\n")); while (1) { fd_set lfds; int num; /* Free up temporary memory from the main smbd. */ lp_TALLOC_FREE(); /* Ensure we respond to PING and DEBUG messages from the main smbd. */ message_dispatch(); memcpy((char *)&lfds, (char *)&listen_set, sizeof(listen_set)); num = sys_select(maxfd+1,&lfds,NULL,NULL,NULL); if (num == -1 && errno == EINTR) { if (got_sig_term) { exit_server_cleanly(NULL); } /* check for sighup processing */ if (reload_after_sighup) { change_to_root_user(); DEBUG(1,("Reloading services after SIGHUP\n")); reload_services(False); reload_after_sighup = 0; } continue; } /* check if we need to reload services */ check_reload(time(NULL)); /* Find the sockets that are read-ready - accept on these. */ for( ; num > 0; num--) { struct sockaddr addr; socklen_t in_addrlen = sizeof(addr); s = -1; for(i = 0; i < num_sockets; i++) { if(FD_ISSET(fd_listenset[i],&lfds)) { s = fd_listenset[i]; /* Clear this so we don't look at it again. */ FD_CLR(fd_listenset[i],&lfds); break; } } smbd_set_server_fd(accept(s,&addr,&in_addrlen)); if (smbd_server_fd() == -1 && errno == EINTR) continue; if (smbd_server_fd() == -1) { DEBUG(0,("open_sockets_smbd: accept: %s\n", strerror(errno))); continue; } /* Ensure child is set to blocking mode */ set_blocking(smbd_server_fd(),True); if (smbd_server_fd() != -1 && interactive) { #ifdef _XBOX xb_IncClientCount(); #endif return True; } if (allowable_number_of_smbd_processes() && smbd_server_fd() != -1 && sys_fork()==0) { /* Child code ... */ /* close the listening socket(s) */ for(i = 0; i < num_sockets; i++) close(fd_listenset[i]); /* close our standard file descriptors */ close_low_fds(False); am_parent = 0; set_socket_options(smbd_server_fd(),"SO_KEEPALIVE"); set_socket_options(smbd_server_fd(),user_socket_options); /* this is needed so that we get decent entries in smbstatus for port 445 connects */ set_remote_machine_name(get_peer_addr(smbd_server_fd()), False); /* Reset the state of the random * number generation system, so * children do not get the same random * numbers as each other */ set_need_random_reseed(); /* tdb needs special fork handling - remove CLEAR_IF_FIRST flags */ if (tdb_reopen_all(1) == -1) { DEBUG(0,("tdb_reopen_all failed.\n")); smb_panic("tdb_reopen_all failed."); } return True; } /* The parent doesn't need this socket */ close(smbd_server_fd()); /* Sun May 6 18:56:14 2001 [email protected]: Clear the closed fd info out of server_fd -- and more importantly, out of client_fd in util_sock.c, to avoid a possible getpeername failure if we reopen the logs and use %I in the filename. */ smbd_set_server_fd(-1); /* Force parent to check log size after * spawning child. Fix from * [email protected]. The * parent smbd will log to logserver.smb. It * writes only two messages for each child * started/finished. But each child writes, * say, 50 messages also in logserver.smb, * begining with the debug_count of the * parent, before the child opens its own log * file logserver.client. In a worst case * scenario the size of logserver.smb would be * checked after about 50*50=2500 messages * (ca. 100kb). * */ force_check_log_size(); } /* end for num */ } /* end while 1 */ /* NOTREACHED return True; */ }
static NTSTATUS ipv6_set_option(struct socket_context *sock, const char *option, const char *val) { set_socket_options(sock->fd, option); return NT_STATUS_OK; }
void cli_sockopt(struct cli_state *cli, const char *options) { set_socket_options(cli->fd, options); }
/* * connect_by_number: Wheeeee. Yet another monster function i get to fix * for the sake of it being inadequate for extension. * * we now take four arguments: * * - hostname - name of the host (pathname) to connect to (if applicable) * - portnum - port number to connect to or listen on (0 if you dont care) * - service - 0 - set up a listening socket * 1 - set up a connecting socket * - protocol - 0 - use the TCP protocol * 1 - use the UDP protocol * * * Returns: * Non-negative number -- new file descriptor ready for use * -1 -- could not open a new file descriptor or * an illegal value for the protocol was specified * -2 -- call to bind() failed * -3 -- call to listen() failed. * -4 -- call to connect() failed * -5 -- call to getsockname() failed * -6 -- the name of the host could not be resolved * -7 -- illegal or unsupported request * -8 -- no socks access * * * Credit: I couldnt have put this together without the help of BSD4.4-lite * User SupplimenTary Document #20 (Inter-process Communications tutorial) */ int BX_connect_by_number(char *hostn, unsigned short *portnum, int service, int protocol, int nonblocking) { int fd = -1; int is_unix = (hostn && *hostn == '/'); int sock_type, proto_type; #ifndef __OPENNT sock_type = (is_unix) ? AF_UNIX : AF_INET; #else sock_type = AF_INET; #endif proto_type = (protocol == PROTOCOL_TCP) ? SOCK_STREAM : SOCK_DGRAM; if ((fd = socket(sock_type, proto_type, 0)) < 0) return -1; set_socket_options (fd); /* Unix domain server */ #ifdef HAVE_SYS_UN_H if (is_unix) { struct sockaddr_un name; memset(&name, 0, sizeof(struct sockaddr_un)); name.sun_family = AF_UNIX; strcpy(name.sun_path, hostn); #ifdef HAVE_SUN_LEN # ifdef SUN_LEN name.sun_len = SUN_LEN(&name); # else name.sun_len = strlen(hostn) + 1; # endif #endif if (is_unix && (service == SERVICE_SERVER)) { if (bind(fd, (struct sockaddr *)&name, strlen(name.sun_path) + sizeof(name.sun_family))) return close(fd), -2; if (protocol == PROTOCOL_TCP) if (listen(fd, 4) < 0) return close(fd), -3; } /* Unix domain client */ else if (service == SERVICE_CLIENT) { alarm(get_int_var(CONNECT_TIMEOUT_VAR)); if (connect (fd, (struct sockaddr *)&name, strlen(name.sun_path) + 2) < 0) { alarm(0); return close(fd), -4; } alarm(0); } } else #endif /* Inet domain server */ if (!is_unix && (service == SERVICE_SERVER)) { int length; #ifdef IP_PORTRANGE int ports; #endif /* Even on an IPv6 client this opens up a IPv4 socket... for now. * (Some OSes need two sockets to be able to accept both IPv4 and * IPv6 connections). */ struct sockaddr_in name; memset(&name, 0, sizeof name); name.sin_family = AF_INET; name.sin_addr.s_addr = htonl(INADDR_ANY); name.sin_port = htons(*portnum); #ifdef PARANOID name.sin_port += (unsigned short)(rand() & 255); #endif #ifdef IP_PORTRANGE if (getenv("EPIC_USE_HIGHPORTS")) { ports = IP_PORTRANGE_HIGH; setsockopt(fd, IPPROTO_IP, IP_PORTRANGE, (char *)&ports, sizeof(ports)); } #endif if (bind(fd, (struct sockaddr *)&name, sizeof(name))) return close(fd), -2; length = sizeof (name); if (getsockname(fd, (struct sockaddr *)&name, &length)) return close(fd), -5; *portnum = ntohs(name.sin_port); if (protocol == PROTOCOL_TCP) if (listen(fd, 4) < 0) return close(fd), -3; #ifdef NON_BLOCKING_CONNECTS if (nonblocking && set_non_blocking(fd) < 0) return close(fd), -4; #endif } /* Inet domain client */ else if (!is_unix && (service == SERVICE_CLIENT)) { struct sockaddr_foobar server; int server_len; struct hostent *hp; #ifdef WINNT char buf[BIG_BUFFER_SIZE+1]; #endif #ifdef IPV6 struct addrinfo hints, *res; struct sockaddr_foobar *sf = NULL; #else struct sockaddr_in localaddr; if (LocalHostName) { memset(&localaddr, 0, sizeof(struct sockaddr_in)); localaddr.sin_family = AF_INET; localaddr.sin_addr = LocalHostAddr.sf_addr; localaddr.sin_port = 0; if (bind(fd, (struct sockaddr *)&localaddr, sizeof(localaddr))) return close(fd), -2; } #endif memset(&server, 0, sizeof server); #ifndef WINNT #ifdef IPV6 memset(&hints, 0, sizeof(hints)); if (!getaddrinfo(hostn, NULL, &hints, &res) && res) { sf = (struct sockaddr_foobar*) res->ai_addr; close(fd); proto_type = (protocol == PROTOCOL_TCP) ? SOCK_STREAM : SOCK_DGRAM; if ((fd = socket(sf->sf_family, proto_type, 0)) < 0) return -1; set_socket_options (fd); if ((server.sf_family = sf->sf_family) == AF_INET) { memcpy(&server.sf_addr, &sf->sf_addr, sizeof(struct in_addr)); server_len = sizeof server.sins.sin; } else { memcpy(&server.sf_addr6, &sf->sf_addr6, sizeof(struct in6_addr)); server_len = sizeof server.sins.sin6; } server.sf_port = htons(*portnum); memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = res->ai_family; freeaddrinfo(res); if (LocalHostName && !getaddrinfo(LocalHostName, NULL, &hints, &res) && res) { if (bind(fd, (struct sockaddr *) res->ai_addr, res->ai_addrlen)) return close(fd), -2; freeaddrinfo(res); } } else return close(fd), -6; #else if (isdigit((unsigned char)hostn[strlen(hostn)-1])) inet_aton(hostn, (struct in_addr *)&server.sf_addr); else { if (!(hp = gethostbyname(hostn))) return close(fd), -6; memcpy(&server.sf_addr, hp->h_addr, hp->h_length); } server.sf_family = AF_INET; server.sf_port = htons(*portnum); server_len = sizeof server.sins.sin; #endif /* IPV6 */ #else /* for some odd reason resolv() fails on NT... */ /* server = (*(struct sockaddr_in *) hostn);*/ if (!hostn) { gethostname(buf, sizeof(buf)); hostn = buf; } if ((server.sf_addr.s_addr = inet_addr(hostn)) == -1) { if ((hp = gethostbyname(hostn)) != NULL) { memset(&server, 0, sizeof(server)); bcopy(hp->h_addr, (char *) &server.sf_addr, hp->h_length); server.sf_family = hp->h_addrtype; } else return (-2); } else server.sf_family = AF_INET; server.sf_port = (unsigned short) htons(*portnum); server_len = sizeof server.sins.sin; #endif /* WINNT */ #ifdef NON_BLOCKING_CONNECTS if (!use_socks && nonblocking && set_non_blocking(fd) < 0) return close(fd), -4; #endif #if !defined(WTERM_C) && !defined(STERM_C) && !defined(IPV6) if (use_socks && get_string_var(SOCKS_HOST_VAR)) { fd = handle_socks(fd, *((struct sockaddr_in*) &server), get_string_var(SOCKS_HOST_VAR), get_int_var(SOCKS_PORT_VAR)); if (fd == -1) return -4; else return fd; } #endif alarm(get_int_var(CONNECT_TIMEOUT_VAR)); if (connect(fd, (struct sockaddr *)&server, server_len) < 0 && errno != EINPROGRESS) { alarm(0); return close(fd), -4; } alarm(0); } /* error */ else return close(fd), -7; return fd; }
static bool smbd_open_one_socket(struct smbd_parent_context *parent, struct tevent_context *ev_ctx, struct messaging_context *msg_ctx, const struct sockaddr_storage *ifss, uint16_t port) { struct smbd_open_socket *s; s = talloc(parent, struct smbd_open_socket); if (!s) { return false; } s->parent = parent; s->fd = open_socket_in(SOCK_STREAM, port, parent->sockets == NULL ? 0 : 2, ifss, true); if (s->fd == -1) { DEBUG(0,("smbd_open_once_socket: open_socket_in: " "%s\n", strerror(errno))); TALLOC_FREE(s); /* * We ignore an error here, as we've done before */ return true; } /* ready to listen */ set_socket_options(s->fd, "SO_KEEPALIVE"); set_socket_options(s->fd, lp_socket_options()); /* Set server socket to * non-blocking for the accept. */ set_blocking(s->fd, False); if (listen(s->fd, SMBD_LISTEN_BACKLOG) == -1) { DEBUG(0,("open_sockets_smbd: listen: " "%s\n", strerror(errno))); close(s->fd); TALLOC_FREE(s); return false; } s->fde = tevent_add_fd(ev_ctx, s, s->fd, TEVENT_FD_READ, smbd_accept_connection, s); if (!s->fde) { DEBUG(0,("open_sockets_smbd: " "tevent_add_fd: %s\n", strerror(errno))); close(s->fd); TALLOC_FREE(s); return false; } tevent_fd_set_close_fn(s->fde, smbd_open_socket_close_fn); DLIST_ADD_END(parent->sockets, s, struct smbd_open_socket *); return true; }
static struct subnet_record *make_subnet(const char *name, enum subnet_type type, struct in_addr myip, struct in_addr bcast_ip, struct in_addr mask_ip) { struct subnet_record *subrec = NULL; int nmb_sock, dgram_sock; /* Check if we are creating a non broadcast subnet - if so don't create sockets. */ if(type != NORMAL_SUBNET) { nmb_sock = -1; dgram_sock = -1; } else { /* * Attempt to open the sockets on port 137/138 for this interface * and bind them. * Fail the subnet creation if this fails. */ if((nmb_sock = open_socket_in(SOCK_DGRAM, global_nmb_port,0, myip.s_addr,True)) == -1) { if( DEBUGLVL( 0 ) ) { Debug1( "nmbd_subnetdb:make_subnet()\n" ); Debug1( " Failed to open nmb socket on interface %s ", inet_ntoa(myip) ); Debug1( "for port %d. ", global_nmb_port ); Debug1( "Error was %s\n", strerror(errno) ); } return NULL; } if((dgram_sock = open_socket_in(SOCK_DGRAM,DGRAM_PORT,3, myip.s_addr,True)) == -1) { if( DEBUGLVL( 0 ) ) { Debug1( "nmbd_subnetdb:make_subnet()\n" ); Debug1( " Failed to open dgram socket on interface %s ", inet_ntoa(myip) ); Debug1( "for port %d. ", DGRAM_PORT ); Debug1( "Error was %s\n", strerror(errno) ); } return NULL; } /* Make sure we can broadcast from these sockets. */ set_socket_options(nmb_sock,"SO_BROADCAST"); set_socket_options(dgram_sock,"SO_BROADCAST"); /* Set them non-blocking. */ set_blocking(nmb_sock, False); set_blocking(dgram_sock, False); } subrec = SMB_MALLOC_P(struct subnet_record); if (!subrec) { DEBUG(0,("make_subnet: malloc fail !\n")); close(nmb_sock); close(dgram_sock); return(NULL); } ZERO_STRUCTP(subrec); if((subrec->subnet_name = SMB_STRDUP(name)) == NULL) { DEBUG(0,("make_subnet: malloc fail for subnet name !\n")); close(nmb_sock); close(dgram_sock); ZERO_STRUCTP(subrec); SAFE_FREE(subrec); return(NULL); } DEBUG(2, ("making subnet name:%s ", name )); DEBUG(2, ("Broadcast address:%s ", inet_ntoa(bcast_ip))); DEBUG(2, ("Subnet mask:%s\n", inet_ntoa(mask_ip))); subrec->namelist_changed = False; subrec->work_changed = False; subrec->bcast_ip = bcast_ip; subrec->mask_ip = mask_ip; subrec->myip = myip; subrec->type = type; subrec->nmb_sock = nmb_sock; subrec->dgram_sock = dgram_sock; return subrec; }
/* * connect_by_number: Wheeeee. Yet another monster function i get to fix * for the sake of it being inadequate for extension. * * we now take four arguments: * * - hostname - name of the host (pathname) to connect to (if applicable) * - portnum - port number to connect to or listen on (0 if you dont care) * - service - 0 - set up a listening socket * 1 - set up a connecting socket * - protocol - 0 - use the TCP protocol * 1 - use the UDP protocol * * * Returns: * Non-negative number -- new file descriptor ready for use * -1 -- could not open a new file descriptor or * an illegal value for the protocol was specified * -2 -- call to bind() failed * -3 -- call to listen() failed. * -4 -- call to connect() failed * -5 -- call to getsockname() failed * -6 -- the name of the host could not be resolved * -7 -- illegal or unsupported request * * * Credit: I couldnt have put this together without the help of BSD4.4-lite * User Supplimentary Document #20 (Inter-process Communications tutorial) */ int connect_by_number(char *hostn, unsigned short *portnum, int service, int protocol, int nonblocking) { int fd = -1; int is_unix = (hostn && *hostn == '/'); int sock_type, proto_type; sock_type = (is_unix) ? AF_UNIX : AF_INET; proto_type = (protocol == PROTOCOL_TCP) ? SOCK_STREAM : SOCK_DGRAM; if ((fd = socket(sock_type, proto_type, 0)) < 0) return -1; set_socket_options(fd); /* Unix domain server */ #ifdef HAVE_SYS_UN_H if (is_unix) { struct sockaddr_un name; memset(&name, 0, sizeof(struct sockaddr_un)); name.sun_family = AF_UNIX; strcpy(name.sun_path, hostn); #ifdef HAVE_SUN_LEN #ifdef SUN_LEN name.sun_len = SUN_LEN(&name); #else name.sun_len = strlen(hostn) + 1; #endif #endif if (is_unix && (service == SERVICE_SERVER)) { if (bind(fd, (struct sockaddr *) &name, strlen(name.sun_path) + 2)) return close(fd), -2; if (protocol == PROTOCOL_TCP) if (listen(fd, 4) < 0) return close(fd), -3; } /* Unix domain client */ else if (service == SERVICE_CLIENT) { alarm(get_int_var(CONNECT_TIMEOUT_VAR)); if (connect(fd, (struct sockaddr *) &name, strlen(name.sun_path) + 2) < 0) { alarm(0); return close(fd), -4; } alarm(0); } } else #endif /* Inet domain server */ if (!is_unix && (service == SERVICE_SERVER)) { socklen_t length; struct sockaddr_in name; memset(&name, 0, sizeof(struct sockaddr_in)); name.sin_family = AF_INET; name.sin_addr.s_addr = htonl(INADDR_ANY); name.sin_port = htons(*portnum); if (bind(fd, (struct sockaddr *) &name, sizeof(name))) return close(fd), -2; length = sizeof(name); if (getsockname(fd, (struct sockaddr *) &name, &length)) return close(fd), -5; *portnum = ntohs(name.sin_port); if (protocol == PROTOCOL_TCP) if (listen(fd, 4) < 0) return close(fd), -3; if (nonblocking && set_non_blocking(fd) < 0) return close(fd), -4; } /* Inet domain client */ else if (!is_unix && (service == SERVICE_CLIENT)) { struct sockaddr_in server; struct hostent *hp; #if 0 /* * Doing this bind is bad news unless you are sure that * the hostname is valid. This is not true for me at home, * since i dynamic-ip it. */ if (LocalHostName) { struct sockaddr_in localaddr; memset(&localaddr, 0, sizeof(struct sockaddr_in)); localaddr.sin_family = AF_INET; localaddr.sin_addr = LocalHostAddr; localaddr.sin_port = 0; if (bind(fd, (struct sockaddr *) &localaddr, sizeof(localaddr))) return close(fd), -2; } #endif memset(&server, 0, sizeof(struct sockaddr_in)); if (!(hp = resolv(hostn))) return close(fd), -6; memcpy(&(server.sin_addr), hp->h_addr, hp->h_length); server.sin_family = AF_INET; server.sin_port = htons(*portnum); if (nonblocking && set_non_blocking(fd) < 0) return close(fd), -4; alarm(get_int_var(CONNECT_TIMEOUT_VAR)); if (connect(fd, (struct sockaddr *) &server, sizeof(server)) < 0) { alarm(0); if (errno != EINPROGRESS && !nonblocking) return close(fd), -4; } alarm(0); } /* error */ else return close(fd), -7; return fd; }