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