/src/samba/source3/param/service.c
Line | Count | Source |
1 | | /* |
2 | | Unix SMB/CIFS implementation. |
3 | | service (connection) opening and closing |
4 | | Copyright (C) Andrew Tridgell 1992-1998 |
5 | | |
6 | | This program is free software; you can redistribute it and/or modify |
7 | | it under the terms of the GNU General Public License as published by |
8 | | the Free Software Foundation; either version 3 of the License, or |
9 | | (at your option) any later version. |
10 | | |
11 | | This program is distributed in the hope that it will be useful, |
12 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | GNU General Public License for more details. |
15 | | |
16 | | You should have received a copy of the GNU General Public License |
17 | | along with this program. If not, see <http://www.gnu.org/licenses/>. |
18 | | */ |
19 | | |
20 | | #include "includes.h" |
21 | | #include "system/filesys.h" |
22 | | #include "../lib/tsocket/tsocket.h" |
23 | | #include "smbd/smbd.h" |
24 | | #include "smbd/globals.h" |
25 | | #include "../librpc/gen_ndr/netlogon.h" |
26 | | #include "../libcli/security/security.h" |
27 | | #include "printing/pcap.h" |
28 | | #include "printing/printer_list.h" |
29 | | #include "passdb/lookup_sid.h" |
30 | | #include "auth.h" |
31 | | #include "lib/param/loadparm.h" |
32 | | |
33 | | static int load_registry_service(const char *servicename) |
34 | 0 | { |
35 | 0 | if (!lp_registry_shares()) { |
36 | 0 | return -1; |
37 | 0 | } |
38 | | |
39 | 0 | if ((servicename == NULL) || (*servicename == '\0')) { |
40 | 0 | return -1; |
41 | 0 | } |
42 | | |
43 | 0 | if (strequal(servicename, GLOBAL_NAME)) { |
44 | 0 | return -2; |
45 | 0 | } |
46 | | |
47 | 0 | if (!process_registry_service(servicename)) { |
48 | 0 | return -1; |
49 | 0 | } |
50 | | |
51 | 0 | return lp_servicenumber(servicename); |
52 | 0 | } |
53 | | |
54 | | void load_registry_shares(void) |
55 | 0 | { |
56 | 0 | DEBUG(8, ("load_registry_shares()\n")); |
57 | 0 | if (!lp_registry_shares()) { |
58 | 0 | return; |
59 | 0 | } |
60 | | |
61 | 0 | process_registry_shares(); |
62 | |
|
63 | 0 | return; |
64 | 0 | } |
65 | | |
66 | | /**************************************************************************** |
67 | | Add a home service. Returns the new service number or -1 if fail. |
68 | | ****************************************************************************/ |
69 | | |
70 | | int add_home_service(const char *service, const char *username, const char *homedir) |
71 | 0 | { |
72 | 0 | int iHomeService; |
73 | |
|
74 | 0 | if (!service || !homedir || homedir[0] == '\0') |
75 | 0 | return -1; |
76 | | |
77 | 0 | if ((iHomeService = lp_servicenumber(HOMES_NAME)) < 0) { |
78 | 0 | if ((iHomeService = load_registry_service(HOMES_NAME)) < 0) { |
79 | 0 | return -1; |
80 | 0 | } |
81 | 0 | } |
82 | | |
83 | | /* |
84 | | * If this is a winbindd provided username, remove |
85 | | * the domain component before adding the service. |
86 | | * Log a warning if the "path=" parameter does not |
87 | | * include any macros. |
88 | | */ |
89 | | |
90 | 0 | { |
91 | 0 | const char *p = strchr(service,*lp_winbind_separator()); |
92 | | |
93 | | /* We only want the 'user' part of the string */ |
94 | 0 | if (p) { |
95 | 0 | service = p + 1; |
96 | 0 | } |
97 | 0 | } |
98 | |
|
99 | 0 | if (!lp_add_home(service, iHomeService, username, homedir)) { |
100 | 0 | return -1; |
101 | 0 | } |
102 | | |
103 | 0 | return lp_servicenumber(service); |
104 | |
|
105 | 0 | } |
106 | | |
107 | | /** |
108 | | * Find a service entry. |
109 | | * |
110 | | * @param service is modified (to canonical form??) |
111 | | **/ |
112 | | |
113 | | int find_service(TALLOC_CTX *ctx, const char *service_in, char **p_service_out) |
114 | 0 | { |
115 | 0 | const struct loadparm_substitution *lp_sub = |
116 | 0 | loadparm_s3_global_substitution(); |
117 | 0 | int iService; |
118 | |
|
119 | 0 | if (!service_in) { |
120 | 0 | return -1; |
121 | 0 | } |
122 | | |
123 | | /* First make a copy. */ |
124 | 0 | *p_service_out = talloc_strdup(ctx, service_in); |
125 | 0 | if (!*p_service_out) { |
126 | 0 | return -1; |
127 | 0 | } |
128 | | |
129 | 0 | all_string_sub(*p_service_out,"\\","/",0); |
130 | |
|
131 | 0 | iService = lp_servicenumber(*p_service_out); |
132 | | |
133 | | /* |
134 | | * check for whether the service is a registry share before |
135 | | * handling home directories. This is to ensure that |
136 | | * that in the case service name is identical to a user's |
137 | | * home directory, the explicit service is preferred. |
138 | | */ |
139 | 0 | if (iService < 0) { |
140 | 0 | iService = load_registry_service(*p_service_out); |
141 | 0 | } |
142 | | |
143 | | /* now handle the special case of a home directory */ |
144 | 0 | if (iService < 0) { |
145 | 0 | char *phome_dir = get_user_home_dir(ctx, *p_service_out); |
146 | |
|
147 | 0 | if(!phome_dir) { |
148 | | /* |
149 | | * Try mapping the servicename, it may |
150 | | * be a Windows to unix mapped user name. |
151 | | */ |
152 | 0 | if(map_username(ctx, *p_service_out, p_service_out)) { |
153 | 0 | if (*p_service_out == NULL) { |
154 | | /* Out of memory. */ |
155 | 0 | return -1; |
156 | 0 | } |
157 | 0 | phome_dir = get_user_home_dir( |
158 | 0 | ctx, *p_service_out); |
159 | 0 | } |
160 | 0 | } |
161 | | |
162 | 0 | DEBUG(3,("checking for home directory %s gave %s\n",*p_service_out, |
163 | 0 | phome_dir?phome_dir:"(NULL)")); |
164 | |
|
165 | 0 | if (!strequal(phome_dir, "/")) { |
166 | 0 | iService = add_home_service(*p_service_out, |
167 | 0 | *p_service_out, /* username */ |
168 | 0 | phome_dir); |
169 | 0 | } |
170 | 0 | } |
171 | | |
172 | | /* If we still don't have a service, attempt to add it as a printer. */ |
173 | 0 | if (iService < 0) { |
174 | 0 | int iPrinterService; |
175 | |
|
176 | 0 | if ((iPrinterService = lp_servicenumber(PRINTERS_NAME)) < 0) { |
177 | 0 | iPrinterService = load_registry_service(PRINTERS_NAME); |
178 | 0 | } |
179 | 0 | if (iPrinterService >= 0) { |
180 | 0 | DEBUG(3,("checking whether %s is a valid printer name...\n", |
181 | 0 | *p_service_out)); |
182 | 0 | if (printer_list_printername_exists(*p_service_out)) { |
183 | 0 | DEBUG(3,("%s is a valid printer name\n", |
184 | 0 | *p_service_out)); |
185 | 0 | DEBUG(3,("adding %s as a printer service\n", |
186 | 0 | *p_service_out)); |
187 | 0 | lp_add_printer(*p_service_out, iPrinterService); |
188 | 0 | iService = lp_servicenumber(*p_service_out); |
189 | 0 | if (iService < 0) { |
190 | 0 | DEBUG(0,("failed to add %s as a printer service!\n", |
191 | 0 | *p_service_out)); |
192 | 0 | } |
193 | 0 | } else { |
194 | 0 | DEBUG(3,("%s is not a valid printer name\n", |
195 | 0 | *p_service_out)); |
196 | 0 | } |
197 | 0 | } |
198 | 0 | } |
199 | | |
200 | | /* Is it a usershare service ? */ |
201 | 0 | if (iService < 0 && *lp_usershare_path(talloc_tos(), lp_sub)) { |
202 | | /* Ensure the name is canonicalized. */ |
203 | 0 | if (!strlower_m(*p_service_out)) { |
204 | 0 | goto fail; |
205 | 0 | } |
206 | 0 | iService = load_usershare_service(*p_service_out); |
207 | 0 | } |
208 | | |
209 | | /* just possibly it's a default service? */ |
210 | 0 | if (iService < 0) { |
211 | 0 | char *pdefservice = lp_defaultservice(talloc_tos(), lp_sub); |
212 | 0 | if (pdefservice && |
213 | 0 | *pdefservice && |
214 | 0 | !strequal(pdefservice, *p_service_out) |
215 | 0 | && !strstr_m(*p_service_out,"..")) { |
216 | | /* |
217 | | * We need to do a local copy here as lp_defaultservice() |
218 | | * returns one of the rotating lp_string buffers that |
219 | | * could get overwritten by the recursive find_service() call |
220 | | * below. Fix from Josef Hinteregger <joehtg@joehtg.co.at>. |
221 | | */ |
222 | 0 | char *defservice = talloc_strdup(ctx, pdefservice); |
223 | |
|
224 | 0 | if (!defservice) { |
225 | 0 | goto fail; |
226 | 0 | } |
227 | | |
228 | | /* Disallow anything except explicit share names. */ |
229 | 0 | if (strequal(defservice,HOMES_NAME) || |
230 | 0 | strequal(defservice, PRINTERS_NAME) || |
231 | 0 | strequal(defservice, "IPC$")) { |
232 | 0 | TALLOC_FREE(defservice); |
233 | 0 | goto fail; |
234 | 0 | } |
235 | | |
236 | 0 | iService = find_service(ctx, defservice, p_service_out); |
237 | 0 | if (!*p_service_out) { |
238 | 0 | TALLOC_FREE(defservice); |
239 | 0 | iService = -1; |
240 | 0 | goto fail; |
241 | 0 | } |
242 | 0 | if (iService >= 0) { |
243 | 0 | all_string_sub(*p_service_out, "_","/",0); |
244 | 0 | iService = lp_add_service(*p_service_out, iService); |
245 | 0 | } |
246 | 0 | TALLOC_FREE(defservice); |
247 | 0 | } |
248 | 0 | } |
249 | | |
250 | 0 | if (iService >= 0) { |
251 | 0 | if (!VALID_SNUM(iService)) { |
252 | 0 | DEBUG(0,("Invalid snum %d for %s\n",iService, |
253 | 0 | *p_service_out)); |
254 | 0 | iService = -1; |
255 | 0 | } |
256 | 0 | } |
257 | |
|
258 | 0 | fail: |
259 | |
|
260 | 0 | if (iService < 0) { |
261 | 0 | DEBUG(3,("find_service() failed to find service %s\n", |
262 | 0 | *p_service_out)); |
263 | 0 | } |
264 | |
|
265 | 0 | return (iService); |
266 | 0 | } |
267 | | |
268 | | bool lp_allow_local_address( |
269 | | int snum, const struct tsocket_address *local_address) |
270 | 0 | { |
271 | 0 | bool is_inet = tsocket_address_is_inet(local_address, "ip"); |
272 | 0 | const char **server_addresses = lp_server_addresses(snum); |
273 | 0 | char *local = NULL; |
274 | 0 | ssize_t i; |
275 | |
|
276 | 0 | if (!is_inet) { |
277 | 0 | return false; |
278 | 0 | } |
279 | | |
280 | 0 | if (server_addresses == NULL) { |
281 | 0 | return true; |
282 | 0 | } |
283 | | |
284 | 0 | local = tsocket_address_inet_addr_string(local_address, talloc_tos()); |
285 | 0 | if (local == NULL) { |
286 | 0 | return false; |
287 | 0 | } |
288 | | |
289 | 0 | for (i=0; server_addresses[i] != NULL; i++) { |
290 | 0 | struct tsocket_address *server_addr = NULL; |
291 | 0 | char *server_addr_string = NULL; |
292 | 0 | bool equal; |
293 | 0 | int ret; |
294 | | |
295 | | /* |
296 | | * Go through struct tsocket_address to normalize the |
297 | | * string representation |
298 | | */ |
299 | |
|
300 | 0 | ret = tsocket_address_inet_from_strings( |
301 | 0 | talloc_tos(), |
302 | 0 | "ip", |
303 | 0 | server_addresses[i], |
304 | 0 | 0, |
305 | 0 | &server_addr); |
306 | 0 | if (ret == -1) { |
307 | 0 | DBG_WARNING("tsocket_address_inet_from_strings " |
308 | 0 | "failed for %s: %s, ignoring\n", |
309 | 0 | server_addresses[i], |
310 | 0 | strerror(errno)); |
311 | 0 | continue; |
312 | 0 | } |
313 | | |
314 | 0 | server_addr_string = tsocket_address_inet_addr_string( |
315 | 0 | server_addr, talloc_tos()); |
316 | 0 | TALLOC_FREE(server_addr); |
317 | 0 | if (server_addr_string == NULL) { |
318 | 0 | DBG_ERR("tsocket_address_inet_addr_string failed " |
319 | 0 | "for %s, ignoring\n", |
320 | 0 | server_addresses[i]); |
321 | 0 | continue; |
322 | 0 | } |
323 | | |
324 | 0 | equal = strequal(local, server_addr_string); |
325 | 0 | TALLOC_FREE(server_addr_string); |
326 | |
|
327 | 0 | if (equal) { |
328 | 0 | TALLOC_FREE(local); |
329 | 0 | return true; |
330 | 0 | } |
331 | 0 | } |
332 | | |
333 | 0 | TALLOC_FREE(local); |
334 | | return false; |
335 | 0 | } |