r13316: Let the carnage begin....
[samba.git] / source / smbd / service.c
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
23 extern struct timeval smb_last_time;
24 extern userdom_struct current_user_info;
25
26 /****************************************************************************
27  Ensure when setting connectpath it is a canonicalized (no ./ // or ../)
28  absolute path stating in / and not ending in /.
29  Observent people will notice a similarity between this and check_path_syntax :-).
30 ****************************************************************************/
31
32 void set_conn_connectpath(connection_struct *conn, const pstring connectpath)
33 {
34         pstring destname;
35         char *d = destname;
36         const char *s = connectpath;
37         BOOL start_of_name_component = True;
38
39         *d++ = '/'; /* Always start with root. */
40
41         while (*s) {
42                 if (*s == '/') {
43                         /* Eat multiple '/' */
44                         while (*s == '/') {
45                                 s++;
46                         }
47                         if ((d > destname + 1) && (*s != '\0')) {
48                                 *d++ = '/';
49                         }
50                         start_of_name_component = True;
51                         continue;
52                 }
53
54                 if (start_of_name_component) {
55                         if ((s[0] == '.') && (s[1] == '.') && (s[2] == '/' || s[2] == '\0')) {
56                                 /* Uh oh - "/../" or "/..\0" ! */
57
58                                 /* Go past the ../ or .. */
59                                 if (s[2] == '/') {
60                                         s += 3;
61                                 } else {
62                                         s += 2; /* Go past the .. */
63                                 }
64
65                                 /* If  we just added a '/' - delete it */
66                                 if ((d > destname) && (*(d-1) == '/')) {
67                                         *(d-1) = '\0';
68                                         d--;
69                                 }
70
71                                 /* Are we at the start ? Can't go back further if so. */
72                                 if (d <= destname) {
73                                         *d++ = '/'; /* Can't delete root */
74                                         continue;
75                                 }
76                                 /* Go back one level... */
77                                 /* Decrement d first as d points to the *next* char to write into. */
78                                 for (d--; d > destname; d--) {
79                                         if (*d == '/') {
80                                                 break;
81                                         }
82                                 }
83                                 /* We're still at the start of a name component, just the previous one. */
84                                 continue;
85                         } else if ((s[0] == '.') && ((s[1] == '\0') || s[1] == '/')) {
86                                 /* Component of pathname can't be "." only - skip the '.' . */
87                                 if (s[1] == '/') {
88                                         s += 2;
89                                 } else {
90                                         s++;
91                                 }
92                                 continue;
93                         }
94                 }
95
96                 if (!(*s & 0x80)) {
97                         *d++ = *s++;
98                 } else {
99                         switch(next_mb_char_size(s)) {
100                                 case 4:
101                                         *d++ = *s++;
102                                 case 3:
103                                         *d++ = *s++;
104                                 case 2:
105                                         *d++ = *s++;
106                                 case 1:
107                                         *d++ = *s++;
108                                         break;
109                                 default:
110                                         break;
111                         }
112                 }
113                 start_of_name_component = False;
114         }
115         *d = '\0';
116
117         /* And must not end in '/' */
118         if (d > destname + 1 && (*(d-1) == '/')) {
119                 *(d-1) = '\0';
120         }
121
122         DEBUG(10,("set_conn_connectpath: service %s, connectpath = %s\n",
123                 lp_servicename(SNUM(conn)), destname ));
124
125         string_set(&conn->connectpath, destname);
126 }
127
128 /****************************************************************************
129  Load parameters specific to a connection/service.
130 ****************************************************************************/
131
132 BOOL set_current_service(connection_struct *conn, uint16 flags, BOOL do_chdir)
133 {
134         static connection_struct *last_conn;
135         static uint16 last_flags;
136         int snum;
137
138         if (!conn)  {
139                 last_conn = NULL;
140                 return(False);
141         }
142
143         conn->lastused = smb_last_time.tv_sec;
144
145         snum = SNUM(conn);
146   
147         if (do_chdir &&
148             vfs_ChDir(conn,conn->connectpath) != 0 &&
149             vfs_ChDir(conn,conn->origpath) != 0) {
150                 DEBUG(0,("chdir (%s) failed\n",
151                          conn->connectpath));
152                 return(False);
153         }
154
155         if ((conn == last_conn) && (last_flags == flags)) {
156                 return(True);
157         }
158
159         last_conn = conn;
160         last_flags = flags;
161         
162         /* Obey the client case sensitivity requests - only for clients that support it. */
163         switch (lp_casesensitive(snum)) {
164                 case Auto:
165                         {
166                                 /* We need this uglyness due to DOS/Win9x clients that lie about case insensitivity. */
167                                 enum remote_arch_types ra_type = get_remote_arch();
168                                 if ((ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
169                                         /* Client can't support per-packet case sensitive pathnames. */
170                                         conn->case_sensitive = False;
171                                 } else {
172                                         conn->case_sensitive = !(flags & FLAG_CASELESS_PATHNAMES);
173                                 }
174                         }
175                         break;
176                 case True:
177                         conn->case_sensitive = True;
178                         break;
179                 default:
180                         conn->case_sensitive = False;
181                         break;
182         }
183         return(True);
184 }
185
186 /****************************************************************************
187  Add a home service. Returns the new service number or -1 if fail.
188 ****************************************************************************/
189
190 int add_home_service(const char *service, const char *username, const char *homedir)
191 {
192         int iHomeService;
193
194         if (!service || !homedir)
195                 return -1;
196
197         if ((iHomeService = lp_servicenumber(HOMES_NAME)) < 0)
198                 return -1;
199
200         /*
201          * If this is a winbindd provided username, remove
202          * the domain component before adding the service.
203          * Log a warning if the "path=" parameter does not
204          * include any macros.
205          */
206
207         {
208                 const char *p = strchr(service,*lp_winbind_separator());
209
210                 /* We only want the 'user' part of the string */
211                 if (p) {
212                         service = p + 1;
213                 }
214         }
215
216         if (!lp_add_home(service, iHomeService, username, homedir)) {
217                 return -1;
218         }
219         
220         return lp_servicenumber(service);
221
222 }
223
224
225 /**
226  * Find a service entry.
227  *
228  * @param service is modified (to canonical form??)
229  **/
230
231 int find_service(fstring service)
232 {
233         int iService;
234
235         all_string_sub(service,"\\","/",0);
236
237         iService = lp_servicenumber(service);
238
239         /* now handle the special case of a home directory */
240         if (iService < 0) {
241                 char *phome_dir = get_user_home_dir(service);
242
243                 if(!phome_dir) {
244                         /*
245                          * Try mapping the servicename, it may
246                          * be a Windows to unix mapped user name.
247                          */
248                         if(map_username(service))
249                                 phome_dir = get_user_home_dir(service);
250                 }
251
252                 DEBUG(3,("checking for home directory %s gave %s\n",service,
253                         phome_dir?phome_dir:"(NULL)"));
254
255                 iService = add_home_service(service,service /* 'username' */, phome_dir);
256         }
257
258         /* If we still don't have a service, attempt to add it as a printer. */
259         if (iService < 0) {
260                 int iPrinterService;
261
262                 if ((iPrinterService = lp_servicenumber(PRINTERS_NAME)) >= 0) {
263                         DEBUG(3,("checking whether %s is a valid printer name...\n", service));
264                         if (pcap_printername_ok(service)) {
265                                 DEBUG(3,("%s is a valid printer name\n", service));
266                                 DEBUG(3,("adding %s as a printer service\n", service));
267                                 lp_add_printer(service, iPrinterService);
268                                 iService = lp_servicenumber(service);
269                                 if (iService < 0) {
270                                         DEBUG(0,("failed to add %s as a printer service!\n", service));
271                                 }
272                         } else {
273                                 DEBUG(3,("%s is not a valid printer name\n", service));
274                         }
275                 }
276         }
277
278         /* Check for default vfs service?  Unsure whether to implement this */
279         if (iService < 0) {
280         }
281
282         /* just possibly it's a default service? */
283         if (iService < 0) {
284                 char *pdefservice = lp_defaultservice();
285                 if (pdefservice && *pdefservice && !strequal(pdefservice,service) && !strstr_m(service,"..")) {
286                         /*
287                          * We need to do a local copy here as lp_defaultservice() 
288                          * returns one of the rotating lp_string buffers that
289                          * could get overwritten by the recursive find_service() call
290                          * below. Fix from Josef Hinteregger <joehtg@joehtg.co.at>.
291                          */
292                         pstring defservice;
293                         pstrcpy(defservice, pdefservice);
294                         iService = find_service(defservice);
295                         if (iService >= 0) {
296                                 all_string_sub(service, "_","/",0);
297                                 iService = lp_add_service(service, iService);
298                         }
299                 }
300         }
301
302         /* Is it a usershare service ? */
303         if (iService < 0 && *lp_usershare_path()) {
304                 /* Ensure the name is canonicalized. */
305                 strlower_m(service);
306                 iService = load_usershare_service(service);
307         }
308
309         if (iService >= 0) {
310                 if (!VALID_SNUM(iService)) {
311                         DEBUG(0,("Invalid snum %d for %s\n",iService, service));
312                         iService = -1;
313                 }
314         }
315
316         if (iService < 0)
317                 DEBUG(3,("find_service() failed to find service %s\n", service));
318
319         return (iService);
320 }
321
322
323 /****************************************************************************
324  do some basic sainity checks on the share.  
325  This function modifies dev, ecode.
326 ****************************************************************************/
327
328 static NTSTATUS share_sanity_checks(int snum, fstring dev) 
329 {
330         
331         if (!lp_snum_ok(snum) || 
332             !check_access(smbd_server_fd(), 
333                           lp_hostsallow(snum), lp_hostsdeny(snum))) {    
334                 return NT_STATUS_ACCESS_DENIED;
335         }
336
337         if (dev[0] == '?' || !dev[0]) {
338                 if (lp_print_ok(snum)) {
339                         fstrcpy(dev,"LPT1:");
340                 } else if (strequal(lp_fstype(snum), "IPC")) {
341                         fstrcpy(dev, "IPC");
342                 } else {
343                         fstrcpy(dev,"A:");
344                 }
345         }
346
347         strupper_m(dev);
348
349         if (lp_print_ok(snum)) {
350                 if (!strequal(dev, "LPT1:")) {
351                         return NT_STATUS_BAD_DEVICE_TYPE;
352                 }
353         } else if (strequal(lp_fstype(snum), "IPC")) {
354                 if (!strequal(dev, "IPC")) {
355                         return NT_STATUS_BAD_DEVICE_TYPE;
356                 }
357         } else if (!strequal(dev, "A:")) {
358                 return NT_STATUS_BAD_DEVICE_TYPE;
359         }
360
361         /* Behave as a printer if we are supposed to */
362         if (lp_print_ok(snum) && (strcmp(dev, "A:") == 0)) {
363                 fstrcpy(dev, "LPT1:");
364         }
365
366         return NT_STATUS_OK;
367 }
368
369 static NTSTATUS find_forced_user(int snum, BOOL vuser_is_guest,
370                                  uid_t *uid, gid_t *gid, fstring username,
371                                  struct nt_user_token **token)
372 {
373         TALLOC_CTX *mem_ctx;
374         char *fuser, *found_username;
375         NTSTATUS result;
376
377         mem_ctx = talloc_new(NULL);
378         if (mem_ctx == NULL) {
379                 DEBUG(0, ("talloc_new failed\n"));
380                 return NT_STATUS_NO_MEMORY;
381         }
382
383         fuser = talloc_string_sub(mem_ctx, lp_force_user(snum), "%S",
384                                   lp_servicename(snum));
385         if (fuser == NULL) {
386                 result = NT_STATUS_NO_MEMORY;
387                 goto done;
388         }
389
390         result = create_token_from_username(mem_ctx, fuser, vuser_is_guest,
391                                             uid, gid, &found_username,
392                                             token);
393         if (!NT_STATUS_IS_OK(result)) {
394                 goto done;
395         }
396
397         talloc_steal(NULL, *token);
398         fstrcpy(username, found_username);
399
400         result = NT_STATUS_OK;
401  done:
402         talloc_free(mem_ctx);
403         return result;
404 }
405
406 /*
407  * Go through lookup_name etc to find the force'd group.  
408  *
409  * Create a new token from src_token, replacing the primary group sid with the
410  * one found.
411  */
412
413 static NTSTATUS find_forced_group(BOOL force_user,
414                                   int snum, const char *username,
415                                   DOM_SID *pgroup_sid,
416                                   gid_t *pgid)
417 {
418         NTSTATUS result = NT_STATUS_NO_SUCH_GROUP;
419         TALLOC_CTX *mem_ctx;
420         DOM_SID group_sid;
421         enum SID_NAME_USE type;
422         char *groupname;
423         BOOL user_must_be_member = False;
424         gid_t gid;
425
426         mem_ctx = talloc_new(NULL);
427         if (mem_ctx == NULL) {
428                 DEBUG(0, ("talloc_new failed\n"));
429                 return NT_STATUS_NO_MEMORY;
430         }
431
432         groupname = talloc_strdup(mem_ctx, lp_force_group(snum));
433         if (groupname == NULL) {
434                 DEBUG(1, ("talloc_strdup failed\n"));
435                 result = NT_STATUS_NO_MEMORY;
436                 goto done;
437         }
438
439         if (groupname[0] == '+') {
440                 user_must_be_member = True;
441                 groupname += 1;
442         }
443
444         groupname = talloc_string_sub(mem_ctx, groupname,
445                                       "%S", lp_servicename(snum));
446
447         if (!lookup_name(mem_ctx, groupname,
448                          LOOKUP_NAME_ALL|LOOKUP_NAME_GROUP,
449                          NULL, NULL, &group_sid, &type)) {
450                 DEBUG(10, ("lookup_name(%s) failed\n",
451                            groupname));
452                 goto done;
453         }
454
455         if ((type != SID_NAME_DOM_GRP) && (type != SID_NAME_ALIAS) &&
456             (type != SID_NAME_WKN_GRP)) {
457                 DEBUG(10, ("%s is a %s, not a group\n", groupname,
458                            sid_type_lookup(type)));
459                 goto done;
460         }
461
462         if (!sid_to_gid(&group_sid, &gid)) {
463                 DEBUG(10, ("sid_to_gid(%s) for %s failed\n",
464                            sid_string_static(&group_sid), groupname));
465                 goto done;
466         }
467
468         /*
469          * If the user has been forced and the forced group starts with a '+',
470          * then we only set the group to be the forced group if the forced
471          * user is a member of that group.  Otherwise, the meaning of the '+'
472          * would be ignored.
473          */
474
475         if (force_user && user_must_be_member) {
476                 if (user_in_group(username, groupname)) {
477                         sid_copy(pgroup_sid, &group_sid);
478                         *pgid = gid;
479                         DEBUG(3,("Forced group %s for member %s\n",
480                                  groupname, username));
481                 }
482         } else {
483                 sid_copy(pgroup_sid, &group_sid);
484                 *pgid = gid;
485                 DEBUG(3,("Forced group %s\n", groupname));
486         }
487
488         result = NT_STATUS_OK;
489  done:
490         talloc_free(mem_ctx);
491         return result;
492 }
493
494 /****************************************************************************
495   Make a connection, given the snum to connect to, and the vuser of the
496   connecting user if appropriate.
497 ****************************************************************************/
498
499 static connection_struct *make_connection_snum(int snum, user_struct *vuser,
500                                                DATA_BLOB password, 
501                                                const char *pdev,
502                                                NTSTATUS *status)
503 {
504         struct passwd *pass = NULL;
505         BOOL guest = False;
506         connection_struct *conn;
507         SMB_STRUCT_STAT st;
508         fstring user;
509         fstring dev;
510         int ret;
511
512         *user = 0;
513         fstrcpy(dev, pdev);
514         SET_STAT_INVALID(st);
515
516         if (NT_STATUS_IS_ERR(*status = share_sanity_checks(snum, dev))) {
517                 return NULL;
518         }       
519
520         conn = conn_new();
521         if (!conn) {
522                 DEBUG(0,("Couldn't find free connection.\n"));
523                 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
524                 return NULL;
525         }
526
527         if (lp_guest_only(snum)) {
528                 const char *guestname = lp_guestaccount();
529                 guest = True;
530                 pass = getpwnam_alloc(NULL, guestname);
531                 if (!pass) {
532                         DEBUG(0,("make_connection_snum: Invalid guest "
533                                  "account %s??\n",guestname));
534                         conn_free(conn);
535                         *status = NT_STATUS_NO_SUCH_USER;
536                         return NULL;
537                 }
538                 fstrcpy(user,pass->pw_name);
539                 conn->force_user = True;
540                 conn->uid = pass->pw_uid;
541                 conn->gid = pass->pw_gid;
542                 string_set(&conn->user,pass->pw_name);
543                 talloc_free(pass);
544                 DEBUG(3,("Guest only user %s\n",user));
545         } else if (vuser) {
546                 if (vuser->guest) {
547                         if (!lp_guest_ok(snum)) {
548                                 DEBUG(2, ("guest user (from session setup) "
549                                           "not permitted to access this share "
550                                           "(%s)\n", lp_servicename(snum)));
551                                       conn_free(conn);
552                                       *status = NT_STATUS_ACCESS_DENIED;
553                                       return NULL;
554                         }
555                 } else {
556                         if (!user_ok_token(vuser->user.unix_name,
557                                            vuser->nt_user_token, snum)) {
558                                 DEBUG(2, ("user '%s' (from session setup) not "
559                                           "permitted to access this share "
560                                           "(%s)\n", vuser->user.unix_name,
561                                           lp_servicename(snum)));
562                                 conn_free(conn);
563                                 *status = NT_STATUS_ACCESS_DENIED;
564                                 return NULL;
565                         }
566                 }
567                 conn->vuid = vuser->vuid;
568                 conn->uid = vuser->uid;
569                 conn->gid = vuser->gid;
570                 string_set(&conn->user,vuser->user.unix_name);
571                 fstrcpy(user,vuser->user.unix_name);
572                 guest = vuser->guest; 
573         } else if (lp_security() == SEC_SHARE) {
574                 /* add it as a possible user name if we 
575                    are in share mode security */
576                 add_session_user(lp_servicename(snum));
577                 /* shall we let them in? */
578                 if (!authorise_login(snum,user,password,&guest)) {
579                         DEBUG( 2, ( "Invalid username/password for [%s]\n", 
580                                     lp_servicename(snum)) );
581                         conn_free(conn);
582                         *status = NT_STATUS_WRONG_PASSWORD;
583                         return NULL;
584                 }
585                 pass = Get_Pwnam(user);
586                 conn->force_user = True;
587                 conn->uid = pass->pw_uid;
588                 conn->gid = pass->pw_gid;
589                 string_set(&conn->user, pass->pw_name);
590                 fstrcpy(user, pass->pw_name);
591
592         } else {
593                 DEBUG(0, ("invalid VUID (vuser) but not in security=share\n"));
594                 conn_free(conn);
595                 *status = NT_STATUS_ACCESS_DENIED;
596                 return NULL;
597         }
598
599         add_session_user(user);
600
601         safe_strcpy(conn->client_address, client_addr(), 
602                     sizeof(conn->client_address)-1);
603         conn->num_files_open = 0;
604         conn->lastused = time(NULL);
605         conn->service = snum;
606         conn->used = True;
607         conn->printer = (strncmp(dev,"LPT",3) == 0);
608         conn->ipc = ( (strncmp(dev,"IPC",3) == 0) ||
609                       ( lp_enable_asu_support() && strequal(dev,"ADMIN$")) );
610         conn->dirptr = NULL;
611
612         /* Case options for the share. */
613         if (lp_casesensitive(snum) == Auto) {
614                 /* We will be setting this per packet. Set to be case
615                  * insensitive for now. */
616                 conn->case_sensitive = False;
617         } else {
618                 conn->case_sensitive = (BOOL)lp_casesensitive(snum);
619         }
620
621         conn->case_preserve = lp_preservecase(snum);
622         conn->short_case_preserve = lp_shortpreservecase(snum);
623
624         conn->veto_list = NULL;
625         conn->hide_list = NULL;
626         conn->veto_oplock_list = NULL;
627         conn->aio_write_behind_list = NULL;
628         string_set(&conn->dirpath,"");
629         string_set(&conn->user,user);
630         conn->nt_user_token = NULL;
631
632         conn->read_only = lp_readonly(conn->service);
633         conn->admin_user = False;
634
635         /*
636          * If force user is true, then store the given userid and the gid of
637          * the user we're forcing.
638          * For auxiliary groups see below.
639          */
640         
641         if (*lp_force_user(snum)) {
642                 NTSTATUS status2;
643
644                 status2 = find_forced_user(snum,
645                                            (vuser != NULL) && vuser->guest,
646                                            &conn->uid, &conn->gid, user,
647                                            &conn->nt_user_token);
648                 if (!NT_STATUS_IS_OK(status2)) {
649                         conn_free(conn);
650                         *status = status2;
651                         return NULL;
652                 }
653                 string_set(&conn->user,user);
654                 conn->force_user = True;
655                 DEBUG(3,("Forced user %s\n",user));       
656         }
657
658         /*
659          * If force group is true, then override
660          * any groupid stored for the connecting user.
661          */
662         
663         if (*lp_force_group(snum)) {
664                 NTSTATUS status2;
665                 DOM_SID group_sid;
666
667                 status2 = find_forced_group(conn->force_user,
668                                             snum, user,
669                                             &group_sid, &conn->gid);
670                 if (!NT_STATUS_IS_OK(status2)) {
671                         conn_free(conn);
672                         *status = status2;
673                         return NULL;
674                 }
675
676                 if ((conn->nt_user_token == NULL) && (vuser != NULL)) {
677
678                         /* Not force user and not security=share, but force
679                          * group. vuser has a token to copy */
680                         
681                         conn->nt_user_token = dup_nt_token(
682                                 NULL, vuser->nt_user_token);
683                         if (conn->nt_user_token == NULL) {
684                                 DEBUG(0, ("dup_nt_token failed\n"));
685                                 conn_free(conn);
686                                 *status = NT_STATUS_NO_MEMORY;
687                                 return NULL;
688                         }
689                 }
690
691                 /* If conn->nt_user_token is still NULL, we have
692                  * security=share. This means ignore the SID, as we had no
693                  * vuser to copy from */
694
695                 if (conn->nt_user_token != NULL) {
696                         /* Overwrite the primary group sid */
697                         sid_copy(&conn->nt_user_token->user_sids[1],
698                                  &group_sid);
699
700                 }
701                 conn->force_group = True;
702         }
703
704         if (conn->nt_user_token != NULL) {
705                 size_t i;
706
707                 /* We have a share-specific token from force [user|group].
708                  * This means we have to create the list of unix groups from
709                  * the list of sids. */
710
711                 conn->ngroups = 0;
712                 conn->groups = NULL;
713
714                 for (i=0; i<conn->nt_user_token->num_sids; i++) {
715                         gid_t gid;
716                         DOM_SID *sid = &conn->nt_user_token->user_sids[i];
717
718                         if (!sid_to_gid(sid, &gid)) {
719                                 DEBUG(10, ("Could not convert SID %s to gid, "
720                                            "ignoring it\n",
721                                            sid_string_static(sid)));
722                                 continue;
723                         }
724                         add_gid_to_array_unique(NULL, gid, &conn->groups,
725                                                 &conn->ngroups);
726                 }
727         }
728
729         {
730                 pstring s;
731                 pstrcpy(s,lp_pathname(snum));
732                 standard_sub_conn(conn,s,sizeof(s));
733                 set_conn_connectpath(conn,s);
734                 DEBUG(3,("Connect path is '%s' for service [%s]\n",s,
735                          lp_servicename(snum)));
736         }
737
738         /*
739          * New code to check if there's a share security descripter
740          * added from NT server manager. This is done after the
741          * smb.conf checks are done as we need a uid and token. JRA.
742          *
743          */
744
745         {
746                 BOOL can_write = share_access_check(conn, snum, vuser,
747                                                     FILE_WRITE_DATA);
748
749                 if (!can_write) {
750                         if (!share_access_check(conn, snum, vuser,
751                                                 FILE_READ_DATA)) {
752                                 /* No access, read or write. */
753                                 DEBUG(0,("make_connection: connection to %s "
754                                          "denied due to security "
755                                          "descriptor.\n",
756                                           lp_servicename(snum)));
757                                 conn_free(conn);
758                                 *status = NT_STATUS_ACCESS_DENIED;
759                                 return NULL;
760                         } else {
761                                 conn->read_only = True;
762                         }
763                 }
764         }
765         /* Initialise VFS function pointers */
766
767         if (!smbd_vfs_init(conn)) {
768                 DEBUG(0, ("vfs_init failed for service %s\n",
769                           lp_servicename(snum)));
770                 conn_free(conn);
771                 *status = NT_STATUS_BAD_NETWORK_NAME;
772                 return NULL;
773         }
774
775         /*
776          * If widelinks are disallowed we need to canonicalise the connect
777          * path here to ensure we don't have any symlinks in the
778          * connectpath. We will be checking all paths on this connection are
779          * below this directory. We must do this after the VFS init as we
780          * depend on the realpath() pointer in the vfs table. JRA.
781          */
782         if (!lp_widelinks(snum)) {
783                 pstring s;
784                 pstrcpy(s,conn->connectpath);
785                 canonicalize_path(conn, s);
786                 set_conn_connectpath(conn,s);
787         }
788
789 /* ROOT Activities: */  
790         /* check number of connections */
791         if (!claim_connection(conn,
792                               lp_servicename(snum),
793                               lp_max_connections(snum),
794                               False,0)) {
795                 DEBUG(1,("too many connections - rejected\n"));
796                 conn_free(conn);
797                 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
798                 return NULL;
799         }  
800
801         /* Preexecs are done here as they might make the dir we are to ChDir
802          * to below */
803         /* execute any "root preexec = " line */
804         if (*lp_rootpreexec(snum)) {
805                 pstring cmd;
806                 pstrcpy(cmd,lp_rootpreexec(snum));
807                 standard_sub_conn(conn,cmd,sizeof(cmd));
808                 DEBUG(5,("cmd=%s\n",cmd));
809                 ret = smbrun(cmd,NULL);
810                 if (ret != 0 && lp_rootpreexec_close(snum)) {
811                         DEBUG(1,("root preexec gave %d - failing "
812                                  "connection\n", ret));
813                         yield_connection(conn, lp_servicename(snum));
814                         conn_free(conn);
815                         *status = NT_STATUS_ACCESS_DENIED;
816                         return NULL;
817                 }
818         }
819
820 /* USER Activites: */
821         if (!change_to_user(conn, conn->vuid)) {
822                 /* No point continuing if they fail the basic checks */
823                 DEBUG(0,("Can't become connected user!\n"));
824                 yield_connection(conn, lp_servicename(snum));
825                 conn_free(conn);
826                 *status = NT_STATUS_LOGON_FAILURE;
827                 return NULL;
828         }
829
830         /* Remember that a different vuid can connect later without these
831          * checks... */
832         
833         /* Preexecs are done here as they might make the dir we are to ChDir
834          * to below */
835
836         /* execute any "preexec = " line */
837         if (*lp_preexec(snum)) {
838                 pstring cmd;
839                 pstrcpy(cmd,lp_preexec(snum));
840                 standard_sub_conn(conn,cmd,sizeof(cmd));
841                 ret = smbrun(cmd,NULL);
842                 if (ret != 0 && lp_preexec_close(snum)) {
843                         DEBUG(1,("preexec gave %d - failing connection\n",
844                                  ret));
845                         change_to_root_user();
846                         yield_connection(conn, lp_servicename(snum));
847                         conn_free(conn);
848                         *status = NT_STATUS_ACCESS_DENIED;
849                         return NULL;
850                 }
851         }
852
853 #ifdef WITH_FAKE_KASERVER
854         if (lp_afs_share(snum)) {
855                 afs_login(conn);
856         }
857 #endif
858         
859         /* Add veto/hide lists */
860         if (!IS_IPC(conn) && !IS_PRINT(conn)) {
861                 set_namearray( &conn->veto_list, lp_veto_files(snum));
862                 set_namearray( &conn->hide_list, lp_hide_files(snum));
863                 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(snum));
864         }
865         
866         /* Invoke VFS make connection hook - do this before the VFS_STAT call
867            to allow any filesystems needing user credentials to initialize
868            themselves. */
869
870         if (SMB_VFS_CONNECT(conn, lp_servicename(snum), user) < 0) {
871                 DEBUG(0,("make_connection: VFS make connection failed!\n"));
872                 change_to_root_user();
873                 yield_connection(conn, lp_servicename(snum));
874                 conn_free(conn);
875                 *status = NT_STATUS_UNSUCCESSFUL;
876                 return NULL;
877         }
878
879         /* win2000 does not check the permissions on the directory
880            during the tree connect, instead relying on permission
881            check during individual operations. To match this behaviour
882            I have disabled this chdir check (tridge) */
883         /* the alternative is just to check the directory exists */
884         if ((ret = SMB_VFS_STAT(conn, conn->connectpath, &st)) != 0 ||
885             !S_ISDIR(st.st_mode)) {
886                 if (ret == 0 && !S_ISDIR(st.st_mode)) {
887                         DEBUG(0,("'%s' is not a directory, when connecting to "
888                                  "[%s]\n", conn->connectpath,
889                                  lp_servicename(snum)));
890                 } else {
891                         DEBUG(0,("'%s' does not exist or permission denied "
892                                  "when connecting to [%s] Error was %s\n",
893                                  conn->connectpath, lp_servicename(snum),
894                                  strerror(errno) ));
895                 }
896                 change_to_root_user();
897                 /* Call VFS disconnect hook */    
898                 SMB_VFS_DISCONNECT(conn);
899                 yield_connection(conn, lp_servicename(snum));
900                 conn_free(conn);
901                 *status = NT_STATUS_BAD_NETWORK_NAME;
902                 return NULL;
903         }
904         
905         string_set(&conn->origpath,conn->connectpath);
906         
907 #if SOFTLINK_OPTIMISATION
908         /* resolve any soft links early if possible */
909         if (vfs_ChDir(conn,conn->connectpath) == 0) {
910                 pstring s;
911                 pstrcpy(s,conn->connectpath);
912                 vfs_GetWd(conn,s);
913                 set_conn_connectpath(conn,s);
914                 vfs_ChDir(conn,conn->connectpath);
915         }
916 #endif
917         
918         /*
919          * Print out the 'connected as' stuff here as we need
920          * to know the effective uid and gid we will be using
921          * (at least initially).
922          */
923
924         if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
925                 dbgtext( "%s (%s) ", get_remote_machine_name(),
926                          conn->client_address );
927                 dbgtext( "%s", srv_is_signing_active() ? "signed " : "");
928                 dbgtext( "connect to service %s ", lp_servicename(snum) );
929                 dbgtext( "initially as user %s ", user );
930                 dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
931                 dbgtext( "(pid %d)\n", (int)sys_getpid() );
932         }
933         
934         /* we've finished with the user stuff - go back to root */
935         change_to_root_user();
936         return(conn);
937 }
938
939 /***************************************************************************************
940  Simple wrapper function for make_connection() to include a call to 
941  vfs_chdir()
942  **************************************************************************************/
943  
944 connection_struct *make_connection_with_chdir(const char *service_in,
945                                               DATA_BLOB password, 
946                                               const char *dev, uint16 vuid,
947                                               NTSTATUS *status)
948 {
949         connection_struct *conn = NULL;
950         
951         conn = make_connection(service_in, password, dev, vuid, status);
952         
953         /*
954          * make_connection() does not change the directory for us any more
955          * so we have to do it as a separate step  --jerry
956          */
957          
958         if ( conn && vfs_ChDir(conn,conn->connectpath) != 0 ) {
959                 DEBUG(0,("move_driver_to_download_area: Can't change "
960                          "directory to %s for [print$] (%s)\n",
961                          conn->connectpath,strerror(errno)));
962                 yield_connection(conn, lp_servicename(SNUM(conn)));
963                 conn_free(conn);
964                 *status = NT_STATUS_UNSUCCESSFUL;
965                 return NULL;
966         }
967         
968         return conn;
969 }
970
971 /****************************************************************************
972  Make a connection to a service.
973  *
974  * @param service 
975 ****************************************************************************/
976
977 connection_struct *make_connection(const char *service_in, DATA_BLOB password, 
978                                    const char *pdev, uint16 vuid,
979                                    NTSTATUS *status)
980 {
981         uid_t euid;
982         user_struct *vuser = NULL;
983         fstring service;
984         fstring dev;
985         int snum = -1;
986
987         fstrcpy(dev, pdev);
988
989         /* This must ONLY BE CALLED AS ROOT. As it exits this function as
990          * root. */
991         if (!non_root_mode() && (euid = geteuid()) != 0) {
992                 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot "
993                          "(%u)\n", (unsigned int)euid ));
994                 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
995         }
996
997         if(lp_security() != SEC_SHARE) {
998                 vuser = get_valid_user_struct(vuid);
999                 if (!vuser) {
1000                         DEBUG(1,("make_connection: refusing to connect with "
1001                                  "no session setup\n"));
1002                         *status = NT_STATUS_ACCESS_DENIED;
1003                         return NULL;
1004                 }
1005         }
1006
1007         /* Logic to try and connect to the correct [homes] share, preferably
1008            without too many getpwnam() lookups.  This is particulary nasty for
1009            winbind usernames, where the share name isn't the same as unix
1010            username.
1011
1012            The snum of the homes share is stored on the vuser at session setup
1013            time.
1014         */
1015
1016         if (strequal(service_in,HOMES_NAME)) {
1017                 if(lp_security() != SEC_SHARE) {
1018                         DATA_BLOB no_pw = data_blob(NULL, 0);
1019                         if (vuser->homes_snum == -1) {
1020                                 DEBUG(2, ("[homes] share not available for "
1021                                           "this user because it was not found "
1022                                           "or created at session setup "
1023                                           "time\n"));
1024                                 *status = NT_STATUS_BAD_NETWORK_NAME;
1025                                 return NULL;
1026                         }
1027                         DEBUG(5, ("making a connection to [homes] service "
1028                                   "created at session setup time\n"));
1029                         return make_connection_snum(vuser->homes_snum,
1030                                                     vuser, no_pw, 
1031                                                     dev, status);
1032                 } else {
1033                         /* Security = share. Try with
1034                          * current_user_info.smb_name as the username.  */
1035                         if (*current_user_info.smb_name) {
1036                                 fstring unix_username;
1037                                 fstrcpy(unix_username,
1038                                         current_user_info.smb_name);
1039                                 map_username(unix_username);
1040                                 snum = find_service(unix_username);
1041                         } 
1042                         if (snum != -1) {
1043                                 DEBUG(5, ("making a connection to 'homes' "
1044                                           "service %s based on "
1045                                           "security=share\n", service_in));
1046                                 return make_connection_snum(snum, NULL,
1047                                                             password,
1048                                                             dev, status);
1049                         }
1050                 }
1051         } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
1052                    && strequal(service_in,
1053                                lp_servicename(vuser->homes_snum))) {
1054                 DATA_BLOB no_pw = data_blob(NULL, 0);
1055                 DEBUG(5, ("making a connection to 'homes' service [%s] "
1056                           "created at session setup time\n", service_in));
1057                 return make_connection_snum(vuser->homes_snum,
1058                                             vuser, no_pw, 
1059                                             dev, status);
1060         }
1061         
1062         fstrcpy(service, service_in);
1063
1064         strlower_m(service);
1065
1066         snum = find_service(service);
1067
1068         if (snum < 0) {
1069                 if (strequal(service,"IPC$") ||
1070                     (lp_enable_asu_support() && strequal(service,"ADMIN$"))) {
1071                         DEBUG(3,("refusing IPC connection to %s\n", service));
1072                         *status = NT_STATUS_ACCESS_DENIED;
1073                         return NULL;
1074                 }
1075
1076                 DEBUG(0,("%s (%s) couldn't find service %s\n",
1077                          get_remote_machine_name(), client_addr(), service));
1078                 *status = NT_STATUS_BAD_NETWORK_NAME;
1079                 return NULL;
1080         }
1081
1082         /* Handle non-Dfs clients attempting connections to msdfs proxy */
1083         if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0'))  {
1084                 DEBUG(3, ("refusing connection to dfs proxy share '%s' "
1085                           "(pointing to %s)\n", 
1086                         service, lp_msdfs_proxy(snum)));
1087                 *status = NT_STATUS_BAD_NETWORK_NAME;
1088                 return NULL;
1089         }
1090
1091         DEBUG(5, ("making a connection to 'normal' service %s\n", service));
1092
1093         return make_connection_snum(snum, vuser,
1094                                     password,
1095                                     dev, status);
1096 }
1097
1098 /****************************************************************************
1099  Close a cnum.
1100 ****************************************************************************/
1101
1102 void close_cnum(connection_struct *conn, uint16 vuid)
1103 {
1104         if (IS_IPC(conn)) {
1105                 pipe_close_conn(conn);
1106         } else {
1107                 file_close_conn(conn);
1108                 dptr_closecnum(conn);
1109         }
1110
1111         change_to_root_user();
1112
1113         DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
1114                                  get_remote_machine_name(),
1115                                  conn->client_address,
1116                                  lp_servicename(SNUM(conn))));
1117
1118         /* Call VFS disconnect hook */    
1119         SMB_VFS_DISCONNECT(conn);
1120
1121         yield_connection(conn, lp_servicename(SNUM(conn)));
1122
1123         /* make sure we leave the directory available for unmount */
1124         vfs_ChDir(conn, "/");
1125
1126         /* execute any "postexec = " line */
1127         if (*lp_postexec(SNUM(conn)) && 
1128             change_to_user(conn, vuid))  {
1129                 pstring cmd;
1130                 pstrcpy(cmd,lp_postexec(SNUM(conn)));
1131                 standard_sub_conn(conn,cmd,sizeof(cmd));
1132                 smbrun(cmd,NULL);
1133                 change_to_root_user();
1134         }
1135
1136         change_to_root_user();
1137         /* execute any "root postexec = " line */
1138         if (*lp_rootpostexec(SNUM(conn)))  {
1139                 pstring cmd;
1140                 pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
1141                 standard_sub_conn(conn,cmd,sizeof(cmd));
1142                 smbrun(cmd,NULL);
1143         }
1144
1145         conn_free(conn);
1146 }