r23784: use the GPLv3 boilerplate as recommended by the FSF and the license text
[tprouty/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 NULL IP address !\n", i));
60                                 continue;
61                         }
62
63                         for (ptr=ports; next_token(&ptr, tok, " \t,", sizeof(tok)); ) {
64                                 unsigned port = atoi(tok);
65                                 if (port == 0 || port > 0xffff) {
66                                         continue;
67                                 }
68                                 s = listenset[num_sockets] = open_socket_in(SOCK_STREAM, port, 0, ifip->s_addr, True);
69                                 if(s == -1)
70                                         return 0;
71
72                                 /* ready to listen */
73                                 set_socket_options(s,"SO_KEEPALIVE"); 
74                                 set_socket_options(s,user_socket_options);
75      
76                                 /* Set server socket to non-blocking for the accept. */
77                                 set_blocking(s,False); 
78  
79                                 if (listen(s, SMBD_LISTEN_BACKLOG) == -1) {
80                                         DEBUG(0,("listen: %s\n",strerror(errno)));
81                                         close(s);
82                                         return 0;
83                                 }
84
85                                 num_sockets++;
86                                 if (num_sockets >= FD_SETSIZE) {
87                                         DEBUG(0,("init_sockets_smbd: Too many sockets to bind to\n"));
88                                         return 0;
89                                 }
90                         }
91                 }
92         } else {
93                 /* Just bind to 0.0.0.0 - accept connections
94                    from anywhere. */
95
96                 fstring tok;
97                 const char *ptr;
98
99                 num_interfaces = 1;
100                 
101                 for (ptr=ports; next_token(&ptr, tok, " \t,", sizeof(tok)); ) {
102                         unsigned port = atoi(tok);
103                         if (port == 0  || port > 0xffff) continue;
104                         /* open an incoming socket */
105                         s = open_socket_in(SOCK_STREAM, port, 0,
106                                            interpret_addr(lp_socket_address()),True);
107                         if (s == -1)
108                                 return 0;
109                 
110                         /* ready to listen */
111                         set_socket_options(s,"SO_KEEPALIVE"); 
112                         set_socket_options(s,user_socket_options);
113                         
114                         /* Set server socket to non-blocking for the accept. */
115                         set_blocking(s,False); 
116  
117                         if (listen(s, SMBD_LISTEN_BACKLOG) == -1) {
118                                 DEBUG(0,("init_sockets_smbd: listen: %s\n",
119                                          strerror(errno)));
120                                 close(s);
121                                 return 0;
122                         }
123
124                         listenset[num_sockets] = s;
125                         num_sockets++;
126
127                         if (num_sockets >= FD_SETSIZE) {
128                                 DEBUG(0,("init_sockets_smbd: Too many sockets to bind to\n"));
129                                 return 0;
130                         }
131                 }
132         } 
133
134         SAFE_FREE(ports);
135         return num_sockets;
136 }
137
138 static int init_sockets_launchd(const struct smb_launch_info *linfo,
139                                 const char * smb_ports,
140                                 int listenset[FD_SETSIZE])
141 {
142         int num_sockets;
143         int i;
144
145         /* The launchd service configuration does not have to provide sockets,
146          * even though it's basically useless without it.
147          */
148         if (!linfo->num_sockets) {
149                 return init_sockets_smbd(smb_ports, listenset);
150         }
151
152         /* Make sure we don't get more sockets than we can handle. */
153         num_sockets = MIN(FD_SETSIZE, linfo->num_sockets);
154         memcpy(listenset, linfo->socket_list, num_sockets * sizeof(int));
155
156         /* Get the sockets ready. This could be hoisted into
157          * open_sockets_smbd(), but the order of socket operations might
158          * matter for some platforms, so this approach seems less risky.
159          *      --jpeach
160          */
161         for (i = 0; i < num_sockets; ++i) {
162                 set_socket_options(listenset[i], "SO_KEEPALIVE");
163                 set_socket_options(listenset[i], user_socket_options);
164
165                 /* Set server socket to non-blocking for the accept. */
166                 set_blocking(listenset[i], False);
167         }
168
169         return num_sockets;
170 }
171
172 /* This function is responsible for opening (or retrieving) all the sockets we
173  * smbd will be listening on. It should apply all the configured socket options
174  * and return the number of valid sockets in listenset.
175  */
176 int smbd_sockinit(const char *cmdline_ports, int listenset[FD_SETSIZE],
177                         struct timeval *idle)
178 {
179         int num_sockets;
180         struct smb_launch_info linfo;
181
182         ZERO_STRUCTP(idle);
183
184         if (smb_launchd_checkin(&linfo)) {
185                 /* We are running under launchd and launchd has
186                  * opened some sockets for us.
187                  */
188                 num_sockets = init_sockets_launchd(&linfo,
189                                             cmdline_ports,
190                                             listenset);
191                 idle->tv_sec = linfo.idle_timeout_secs;
192                 smb_launchd_checkout(&linfo);
193         } else {
194                 num_sockets = init_sockets_smbd(cmdline_ports,
195                                             listenset);
196         }
197
198         return num_sockets;
199 }
200