598bbd1bda7a2993fc3e4b96d586ee035e11df50
[samba.git] / source / smbd / sockinit.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Copyright (C) Andrew Tridgell                1992-1998
5    Copyright (C) James Peach                    2007
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "smb_launchd.h"
23
24 extern pstring user_socket_options;
25
26 static int init_sockets_smbd(const char *smb_ports, int listenset[FD_SETSIZE])
27 {
28         int num_interfaces = iface_count();
29         char * ports;
30         int num_sockets = 0;
31         int i, s;
32
33         /* use a reasonable default set of ports - listing on 445 and 139 */
34         if (!smb_ports) {
35                 ports = lp_smb_ports();
36                 if (!ports || !*ports) {
37                         ports = smb_xstrdup(SMB_PORTS);
38                 } else {
39                         ports = smb_xstrdup(ports);
40                 }
41         } else {
42                 ports = smb_xstrdup(smb_ports);
43         }
44
45         if (lp_interfaces() && lp_bind_interfaces_only()) {
46                 /* We have been given an interfaces line, and been
47                    told to only bind to those interfaces. Create a
48                    socket per interface and bind to only these.
49                 */
50
51                 /* Now open a listen socket for each of the
52                    interfaces. */
53                 for(i = 0; i < num_interfaces; i++) {
54                         struct in_addr *ifip = iface_n_ip(i);
55                         fstring tok;
56                         const char *ptr;
57
58                         if(ifip == NULL) {
59                                 DEBUG(0,("init_sockets_smbd: interface %d has "
60                                         "NULL IP address !\n", i));
61                                 continue;
62                         }
63
64                         for (ptr=ports; next_token(&ptr, tok, " \t,",
65                                                 sizeof(tok)); ) {
66                                 unsigned port = atoi(tok);
67                                 if (port == 0 || port > 0xffff) {
68                                         continue;
69                                 }
70                                 s = listenset[num_sockets] =
71                                         open_socket_in(SOCK_STREAM,
72                                                         port,
73                                                         0,
74                                                         ifip->s_addr,
75                                                         True);
76                                 if(s == -1)
77                                         return 0;
78
79                                 /* ready to listen */
80                                 set_socket_options(s,"SO_KEEPALIVE");
81                                 set_socket_options(s,user_socket_options);
82
83                                 /* Set server socket to non-blocking
84                                  * for the accept. */
85                                 set_blocking(s,False);
86
87                                 if (listen(s, SMBD_LISTEN_BACKLOG) == -1) {
88                                         DEBUG(0,("listen: %s\n",
89                                                 strerror(errno)));
90                                         close(s);
91                                         return 0;
92                                 }
93
94                                 num_sockets++;
95                                 if (num_sockets >= FD_SETSIZE) {
96                                         DEBUG(0,("init_sockets_smbd: "
97                                         "Too many sockets to bind to\n"));
98                                         return 0;
99                                 }
100                         }
101                 }
102         } else {
103                 /* Just bind to 0.0.0.0 - accept connections
104                    from anywhere. */
105
106                 fstring tok;
107                 const char *ptr;
108
109                 num_interfaces = 1;
110
111                 for (ptr=ports; next_token(&ptr, tok, " \t,", sizeof(tok)); ) {
112                         unsigned port = atoi(tok);
113                         if (port == 0  || port > 0xffff) continue;
114                         /* open an incoming socket */
115                         s = open_socket_in(SOCK_STREAM, port, 0,
116                                            interpret_addr(lp_socket_address()),
117                                            True);
118                         if (s == -1)
119                                 return 0;
120
121                         /* ready to listen */
122                         set_socket_options(s,"SO_KEEPALIVE");
123                         set_socket_options(s,user_socket_options);
124
125                         /* Set server socket to non-blocking for the accept. */
126                         set_blocking(s,False);
127
128                         if (listen(s, SMBD_LISTEN_BACKLOG) == -1) {
129                                 DEBUG(0,("init_sockets_smbd: listen: %s\n",
130                                          strerror(errno)));
131                                 close(s);
132                                 return 0;
133                         }
134
135                         listenset[num_sockets] = s;
136                         num_sockets++;
137
138                         if (num_sockets >= FD_SETSIZE) {
139                                 DEBUG(0,("init_sockets_smbd: "
140                                         "Too many sockets to bind to\n"));
141                                 return 0;
142                         }
143                 }
144         }
145
146         SAFE_FREE(ports);
147         return num_sockets;
148 }
149
150 static int init_sockets_launchd(const struct smb_launch_info *linfo,
151                                 const char * smb_ports,
152                                 int listenset[FD_SETSIZE])
153 {
154         int num_sockets;
155         int i;
156
157         /* The launchd service configuration does not have to provide sockets,
158          * even though it's basically useless without it.
159          */
160         if (!linfo->num_sockets) {
161                 return init_sockets_smbd(smb_ports, listenset);
162         }
163
164         /* Make sure we don't get more sockets than we can handle. */
165         num_sockets = MIN(FD_SETSIZE, linfo->num_sockets);
166         memcpy(listenset, linfo->socket_list, num_sockets * sizeof(int));
167
168         /* Get the sockets ready. This could be hoisted into
169          * open_sockets_smbd(), but the order of socket operations might
170          * matter for some platforms, so this approach seems less risky.
171          *      --jpeach
172          */
173         for (i = 0; i < num_sockets; ++i) {
174                 set_socket_options(listenset[i], "SO_KEEPALIVE");
175                 set_socket_options(listenset[i], user_socket_options);
176
177                 /* Set server socket to non-blocking for the accept. */
178                 set_blocking(listenset[i], False);
179         }
180
181         return num_sockets;
182 }
183
184 /* This function is responsible for opening (or retrieving) all the sockets we
185  * smbd will be listening on. It should apply all the configured socket options
186  * and return the number of valid sockets in listenset.
187  */
188 int smbd_sockinit(const char *cmdline_ports, int listenset[FD_SETSIZE],
189                         struct timeval *idle)
190 {
191         int num_sockets;
192         struct smb_launch_info linfo;
193
194         ZERO_STRUCTP(idle);
195
196         if (smb_launchd_checkin(&linfo)) {
197                 /* We are running under launchd and launchd has
198                  * opened some sockets for us.
199                  */
200                 num_sockets = init_sockets_launchd(&linfo,
201                                             cmdline_ports,
202                                             listenset);
203                 idle->tv_sec = linfo.idle_timeout_secs;
204                 smb_launchd_checkout(&linfo);
205         } else {
206                 num_sockets = init_sockets_smbd(cmdline_ports,
207                                             listenset);
208         }
209
210         return num_sockets;
211 }