source: branches/samba-3.0/source/smbd/service.c

Last change on this file was 336, checked in by Herwig Bauernfeind, 16 years ago

Update 3.0 to 3.0.37 (unsupported security update)

File size: 35.1 KB
Line 
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 2 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, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19*/
20
21#include "includes.h"
22
23extern userdom_struct current_user_info;
24
25static BOOL canonicalize_path(connection_struct *conn, pstring path)
26{
27#ifdef REALPATH_TAKES_NULL
28 char *resolved_name = SMB_VFS_REALPATH(conn,path,NULL);
29 if (!resolved_name) {
30 return False;
31 }
32 pstrcpy(path, resolved_name);
33 SAFE_FREE(resolved_name);
34 return True;
35#else
36#ifdef PATH_MAX
37 char resolved_name_buf[PATH_MAX+1];
38#else
39 pstring resolved_name_buf;
40#endif
41 char *resolved_name = SMB_VFS_REALPATH(conn,path,resolved_name_buf);
42 if (!resolved_name) {
43 return False;
44 }
45 pstrcpy(path, resolved_name);
46 return True;
47#endif /* REALPATH_TAKES_NULL */
48}
49
50/****************************************************************************
51 Ensure when setting connectpath it is a canonicalized (no ./ // or ../)
52 absolute path stating in / and not ending in /.
53 Observent people will notice a similarity between this and check_path_syntax :-).
54****************************************************************************/
55
56void set_conn_connectpath(connection_struct *conn, const pstring connectpath)
57{
58 pstring destname;
59 char *d = destname;
60 const char *s = connectpath;
61 BOOL start_of_name_component = True;
62#ifndef __OS2__
63 *d++ = '/'; /* Always start with root. */
64
65 while (*s) {
66 if (*s == '/') {
67 /* Eat multiple '/' */
68 while (*s == '/') {
69 s++;
70 }
71 if ((d > destname + 1) && (*s != '\0')) {
72 *d++ = '/';
73 }
74 start_of_name_component = True;
75 continue;
76 }
77
78 if (start_of_name_component) {
79 if ((s[0] == '.') && (s[1] == '.') && (s[2] == '/' || s[2] == '\0')) {
80 /* Uh oh - "/../" or "/..\0" ! */
81
82 /* Go past the ../ or .. */
83 if (s[2] == '/') {
84 s += 3;
85 } else {
86 s += 2; /* Go past the .. */
87 }
88
89 /* If we just added a '/' - delete it */
90 if ((d > destname) && (*(d-1) == '/')) {
91 *(d-1) = '\0';
92 d--;
93 }
94
95 /* Are we at the start ? Can't go back further if so. */
96 if (d <= destname) {
97 *d++ = '/'; /* Can't delete root */
98 continue;
99 }
100 /* Go back one level... */
101 /* Decrement d first as d points to the *next* char to write into. */
102 for (d--; d > destname; d--) {
103 if (*d == '/') {
104 break;
105 }
106 }
107 /* We're still at the start of a name component, just the previous one. */
108 continue;
109 } else if ((s[0] == '.') && ((s[1] == '\0') || s[1] == '/')) {
110 /* Component of pathname can't be "." only - skip the '.' . */
111 if (s[1] == '/') {
112 s += 2;
113 } else {
114 s++;
115 }
116 continue;
117 }
118 }
119
120 if (!(*s & 0x80)) {
121 *d++ = *s++;
122 } else {
123 size_t siz;
124 /* Get the size of the next MB character. */
125 next_codepoint(s,&siz);
126 switch(siz) {
127 case 5:
128 *d++ = *s++;
129 /*fall through*/
130 case 4:
131 *d++ = *s++;
132 /*fall through*/
133 case 3:
134 *d++ = *s++;
135 /*fall through*/
136 case 2:
137 *d++ = *s++;
138 /*fall through*/
139 case 1:
140 *d++ = *s++;
141 break;
142 default:
143 break;
144 }
145 }
146 start_of_name_component = False;
147 }
148 *d = '\0';
149
150 /* And must not end in '/' */
151 if (d > destname + 1 && (*(d-1) == '/')) {
152 *(d-1) = '\0';
153 }
154#else
155 /* Assume OS/2 users are smart enough to put a correct path in smb.conf, and simply copy the string */
156 pstrcpy(destname, connectpath);
157#endif
158
159 DEBUG(10,("set_conn_connectpath: service %s, connectpath = %s\n",
160 lp_servicename(SNUM(conn)), destname ));
161 string_set(&conn->connectpath, destname);
162}
163
164/****************************************************************************
165 Load parameters specific to a connection/service.
166****************************************************************************/
167
168BOOL set_current_service(connection_struct *conn, uint16 flags, BOOL do_chdir)
169{
170 static connection_struct *last_conn;
171 static uint16 last_flags;
172 int snum;
173
174 if (!conn) {
175 last_conn = NULL;
176 return(False);
177 }
178
179 conn->lastused_count++;
180
181 snum = SNUM(conn);
182
183 if (do_chdir &&
184 vfs_ChDir(conn,conn->connectpath) != 0 &&
185 vfs_ChDir(conn,conn->origpath) != 0) {
186 DEBUG(0,("chdir (%s) failed\n",
187 conn->connectpath));
188 return(False);
189 }
190
191 if ((conn == last_conn) && (last_flags == flags)) {
192 return(True);
193 }
194
195 last_conn = conn;
196 last_flags = flags;
197
198 /* Obey the client case sensitivity requests - only for clients that support it. */
199 switch (lp_casesensitive(snum)) {
200 case Auto:
201 {
202 /* We need this uglyness due to DOS/Win9x clients that lie about case insensitivity. */
203 enum remote_arch_types ra_type = get_remote_arch();
204 if ((ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
205 /* Client can't support per-packet case sensitive pathnames. */
206 conn->case_sensitive = False;
207 } else {
208 conn->case_sensitive = !(flags & FLAG_CASELESS_PATHNAMES);
209 }
210 }
211 break;
212 case True:
213 conn->case_sensitive = True;
214 break;
215 default:
216 conn->case_sensitive = False;
217 break;
218 }
219 return(True);
220}
221
222/****************************************************************************
223 Add a home service. Returns the new service number or -1 if fail.
224****************************************************************************/
225
226int add_home_service(const char *service, const char *username, const char *homedir)
227{
228 int iHomeService;
229
230 if (!service || !homedir || homedir[0] == '\0')
231 return -1;
232
233 if ((iHomeService = lp_servicenumber(HOMES_NAME)) < 0)
234 return -1;
235
236 /*
237 * If this is a winbindd provided username, remove
238 * the domain component before adding the service.
239 * Log a warning if the "path=" parameter does not
240 * include any macros.
241 */
242
243 {
244 const char *p = strchr(service,*lp_winbind_separator());
245
246 /* We only want the 'user' part of the string */
247 if (p) {
248 service = p + 1;
249 }
250 }
251
252 if (!lp_add_home(service, iHomeService, username, homedir)) {
253 return -1;
254 }
255
256 return lp_servicenumber(service);
257
258}
259
260
261/**
262 * Find a service entry.
263 *
264 * @param service is modified (to canonical form??)
265 **/
266
267int find_service(fstring service)
268{
269 int iService;
270
271 all_string_sub(service,"\\","/",0);
272
273 iService = lp_servicenumber(service);
274
275 /* now handle the special case of a home directory */
276 if (iService < 0) {
277 char *phome_dir = get_user_home_dir(service);
278
279 if(!phome_dir) {
280 /*
281 * Try mapping the servicename, it may
282 * be a Windows to unix mapped user name.
283 */
284 if(map_username(service))
285 phome_dir = get_user_home_dir(service);
286 }
287
288 DEBUG(3,("checking for home directory %s gave %s\n",service,
289 phome_dir?phome_dir:"(NULL)"));
290
291 iService = add_home_service(service,service /* 'username' */, phome_dir);
292 }
293
294 /* If we still don't have a service, attempt to add it as a printer. */