Removed global_myworkgroup, global_myname, global_myscope. Added liberal
[kai/samba.git] / source3 / 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 int case_default;
25 extern BOOL case_preserve;
26 extern BOOL short_case_preserve;
27 extern BOOL case_mangle;
28 extern BOOL case_sensitive;
29 extern BOOL use_mangled_map;
30 extern userdom_struct current_user_info;
31
32
33 /****************************************************************************
34  Load parameters specific to a connection/service.
35 ****************************************************************************/
36
37 BOOL set_current_service(connection_struct *conn,BOOL do_chdir)
38 {
39         extern char magic_char;
40         static connection_struct *last_conn;
41         int snum;
42
43         if (!conn)  {
44                 last_conn = NULL;
45                 return(False);
46         }
47
48         conn->lastused = smb_last_time.tv_sec;
49
50         snum = SNUM(conn);
51   
52         if (do_chdir &&
53             vfs_ChDir(conn,conn->connectpath) != 0 &&
54             vfs_ChDir(conn,conn->origpath) != 0) {
55                 DEBUG(0,("chdir (%s) failed\n",
56                          conn->connectpath));
57                 return(False);
58         }
59
60         if (conn == last_conn)
61                 return(True);
62
63         last_conn = conn;
64
65         case_default = lp_defaultcase(snum);
66         case_preserve = lp_preservecase(snum);
67         short_case_preserve = lp_shortpreservecase(snum);
68         case_mangle = lp_casemangle(snum);
69         case_sensitive = lp_casesensitive(snum);
70         magic_char = lp_magicchar(snum);
71         use_mangled_map = (*lp_mangled_map(snum) ? True:False);
72         return(True);
73 }
74
75 /****************************************************************************
76  Add a home service. Returns the new service number or -1 if fail.
77 ****************************************************************************/
78
79 int add_home_service(const char *service, const char *username, const char *homedir)
80 {
81         int iHomeService;
82
83         if (!service || !homedir)
84                 return -1;
85
86         if ((iHomeService = lp_servicenumber(HOMES_NAME)) < 0)
87                 return -1;
88
89         /*
90          * If this is a winbindd provided username, remove
91          * the domain component before adding the service.
92          * Log a warning if the "path=" parameter does not
93          * include any macros.
94          */
95
96         {
97                 const char *p = strchr(service,*lp_winbind_separator());
98
99                 /* We only want the 'user' part of the string */
100                 if (p) {
101                         service = p + 1;
102                 }
103         }
104
105         if (!lp_add_home(service, iHomeService, username, homedir)) {
106                 return -1;
107         }
108         
109         return lp_servicenumber(service);
110
111 }
112
113
114 /**
115  * Find a service entry. service is always in dos codepage.
116  *
117  * @param service is modified (to canonical form??)
118  **/
119 int find_service(fstring service)
120 {
121    int iService;
122
123    all_string_sub(service,"\\","/",0);
124
125    iService = lp_servicenumber(service);
126
127    /* now handle the special case of a home directory */
128    if (iService < 0)
129    {
130       char *phome_dir = get_user_home_dir(service);
131
132       if(!phome_dir)
133       {
134         /*
135          * Try mapping the servicename, it may
136          * be a Windows to unix mapped user name.
137          */
138         if(map_username(service))
139           phome_dir = get_user_home_dir(service);
140       }
141
142       DEBUG(3,("checking for home directory %s gave %s\n",service,
143             phome_dir?phome_dir:"(NULL)"));
144
145       iService = add_home_service(service,service /* 'username' */, phome_dir);
146    }
147
148    /* If we still don't have a service, attempt to add it as a printer. */
149    if (iService < 0)
150    {
151       int iPrinterService;
152
153       if ((iPrinterService = lp_servicenumber(PRINTERS_NAME)) >= 0)
154       {
155          char *pszTemp;
156
157          DEBUG(3,("checking whether %s is a valid printer name...\n", service));
158          pszTemp = PRINTCAP;
159          if ((pszTemp != NULL) && pcap_printername_ok(service, pszTemp))
160          {
161             DEBUG(3,("%s is a valid printer name\n", service));
162             DEBUG(3,("adding %s as a printer service\n", service));
163             lp_add_printer(service, iPrinterService);
164             iService = lp_servicenumber(service);
165             if (iService < 0)
166                DEBUG(0,("failed to add %s as a printer service!\n", service));
167          }
168          else
169             DEBUG(3,("%s is not a valid printer name\n", service));
170       }
171    }
172
173    /* Check for default vfs service?  Unsure whether to implement this */
174    if (iService < 0)
175    {
176    }
177
178    /* just possibly it's a default service? */
179    if (iService < 0) 
180    {
181      char *pdefservice = lp_defaultservice();
182      if (pdefservice && *pdefservice && 
183          !strequal(pdefservice,service) &&
184          !strstr(service,".."))
185      {
186        /*
187         * We need to do a local copy here as lp_defaultservice() 
188         * returns one of the rotating lp_string buffers that
189         * could get overwritten by the recursive find_service() call
190         * below. Fix from Josef Hinteregger <joehtg@joehtg.co.at>.
191         */
192        pstring defservice;
193        pstrcpy(defservice, pdefservice);
194        iService = find_service(defservice);
195        if (iService >= 0)
196        {
197          all_string_sub(service, "_","/",0);
198          iService = lp_add_service(service, iService);
199        }
200      }
201    }
202
203    if (iService >= 0)
204      if (!VALID_SNUM(iService))
205      {
206        DEBUG(0,("Invalid snum %d for %s\n",iService, service));
207        iService = -1;
208      }
209
210    if (iService < 0)
211      DEBUG(3,("find_service() failed to find service %s\n", service));
212
213    return (iService);
214 }
215
216
217 /****************************************************************************
218  do some basic sainity checks on the share.  
219  This function modifies dev, ecode.
220 ****************************************************************************/
221 static NTSTATUS share_sanity_checks(int snum, pstring dev) 
222 {
223         
224         if (!lp_snum_ok(snum) || 
225             !check_access(smbd_server_fd(), 
226                           lp_hostsallow(snum), lp_hostsdeny(snum))) {    
227                 return NT_STATUS_ACCESS_DENIED;
228         }
229
230         /* you can only connect to the IPC$ service as an ipc device */
231         if (strequal(lp_fstype(snum), "IPC"))
232                 pstrcpy(dev,"IPC");
233         
234         if (dev[0] == '?' || !dev[0]) {
235                 if (lp_print_ok(snum)) {
236                         pstrcpy(dev,"LPT1:");
237                 } else {
238                         pstrcpy(dev,"A:");
239                 }
240         }
241
242         /* if the request is as a printer and you can't print then refuse */
243         strupper(dev);
244         if (!lp_print_ok(snum) && (strncmp(dev,"LPT",3) == 0)) {
245                 DEBUG(1,("Attempt to connect to non-printer as a printer\n"));
246                 return NT_STATUS_BAD_DEVICE_TYPE;
247         }
248
249         /* Behave as a printer if we are supposed to */
250         if (lp_print_ok(snum) && (strcmp(dev, "A:") == 0)) {
251                 pstrcpy(dev, "LPT1:");
252         }
253
254         return NT_STATUS_OK;
255 }
256
257
258 /****************************************************************************
259  readonly share?
260 ****************************************************************************/
261 static void set_read_only(connection_struct *conn) 
262 {
263         char **list;
264         char *service = lp_servicename(conn->service);
265         conn->read_only = lp_readonly(conn->service);
266
267         if (!service) return;
268
269         str_list_copy(&list, lp_readlist(conn->service));
270         if (list) {
271                 if (!str_list_substitute(list, "%S", service)) {
272                         DEBUG(0, ("ERROR: read list substitution failed\n"));
273                 }
274                 if (user_in_list(conn->user, (const char **)list))
275                         conn->read_only = True;
276                 str_list_free(&list);
277         }
278         
279         str_list_copy(&list, lp_writelist(conn->service));
280         if (list) {
281                 if (!str_list_substitute(list, "%S", service)) {
282                         DEBUG(0, ("ERROR: write list substitution failed\n"));
283                 }
284                 if (user_in_list(conn->user, (const char **)list))
285                         conn->read_only = False;
286                 str_list_free(&list);
287         }
288 }
289
290
291 /****************************************************************************
292   admin user check
293 ****************************************************************************/
294 static void set_admin_user(connection_struct *conn) 
295 {
296         /* admin user check */
297         
298         /* JRA - original code denied admin user if the share was
299            marked read_only. Changed as I don't think this is needed,
300            but old code left in case there is a problem here.
301         */
302         if (user_in_list(conn->user,lp_admin_users(conn->service)) 
303 #if 0
304             && !conn->read_only
305 #endif
306             ) {
307                 conn->admin_user = True;
308                 conn->force_user = True;  /* Admin users are effectivly 'forced' */
309                 DEBUG(0,("%s logged in as admin user (root privileges)\n",conn->user));
310         } else {
311                 conn->admin_user = False;
312         }
313
314 #if 0 /* This done later, for now */    
315         /* admin users always run as uid=0 */
316         if (conn->admin_user) {
317                 conn->uid = 0;
318         }
319 #endif
320 }
321
322 /****************************************************************************
323   Make a connection, given the snum to connect to, and the vuser of the
324   connecting user if appropriate.
325 ****************************************************************************/
326
327 static connection_struct *make_connection_snum(int snum, user_struct *vuser,
328                                                DATA_BLOB password, 
329                                                char *dev, NTSTATUS *status)
330 {
331         struct passwd *pass = NULL;
332         BOOL guest = False;
333         connection_struct *conn;
334         struct stat st;
335         fstring user;
336         *user = 0;
337
338         if (NT_STATUS_IS_ERR(*status = share_sanity_checks(snum, dev))) {
339                 return NULL;
340         }       
341
342         conn = conn_new();
343         if (!conn) {
344                 DEBUG(0,("Couldn't find free connection.\n"));
345                 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
346                 return NULL;
347         }
348
349         if (lp_guest_only(snum)) {
350                 const char *guestname = lp_guestaccount();
351                 guest = True;
352                 pass = getpwnam_alloc(guestname);
353                 if (!pass) {
354                         DEBUG(0,("authorise_login: Invalid guest account %s??\n",guestname));
355                         conn_free(conn);
356                         *status = NT_STATUS_NO_SUCH_USER;
357                         return NULL;
358                 }
359                 fstrcpy(user,pass->pw_name);
360                 conn->force_user = True;
361                 string_set(&conn->user,pass->pw_name);
362                 passwd_free(&pass);
363                 DEBUG(3,("Guest only user %s\n",user));
364         } else if (vuser) {
365                 if (vuser->guest) {
366                         if (!lp_guest_ok(snum)) {
367                                 DEBUG(2, ("guest user (from session setup) not permitted to access this share (%s)", lp_servicename(snum)));
368                                       conn_free(conn);
369                                       *status = NT_STATUS_ACCESS_DENIED;
370                                       return NULL;
371                         }
372                 } else {
373                         if (!user_ok(vuser->user.unix_name, snum)) {
374                                 DEBUG(2, ("user '%s' (from session setup) not permitted to access this share (%s)", vuser->user.unix_name, lp_servicename(snum)));
375                                 conn_free(conn);
376                                 *status = NT_STATUS_ACCESS_DENIED;
377                                 return NULL;
378                         }
379                 }
380                 conn->vuid = vuser->vuid;
381                 conn->uid = vuser->uid;
382                 conn->gid = vuser->gid;
383                 string_set(&conn->user,vuser->user.unix_name);
384                 fstrcpy(user,vuser->user.unix_name);
385                 guest = vuser->guest; 
386         } else if (lp_security() == SEC_SHARE) {
387                 /* add it as a possible user name if we 
388                    are in share mode security */
389                 add_session_user(lp_servicename(snum));
390                 /* shall we let them in? */
391                 if (!authorise_login(snum,user,password,&guest)) {
392                         DEBUG( 2, ( "Invalid username/password for [%s]\n", 
393                                     lp_servicename(snum)) );
394                         conn_free(conn);
395                         *status = NT_STATUS_WRONG_PASSWORD;
396                         return NULL;
397                 }
398                 pass = Get_Pwnam(user);
399                 conn->force_user = True;
400                 conn->uid = pass->pw_uid;
401                 conn->gid = pass->pw_gid;
402                 string_set(&conn->user, pass->pw_name);
403                 fstrcpy(user, pass->pw_name);
404
405         } else {
406                 DEBUG(0, ("invalid VUID (vuser) but not in security=share\n"));
407                 conn_free(conn);
408                 *status = NT_STATUS_ACCESS_DENIED;
409                 return NULL;
410         }
411
412         add_session_user(user);
413
414         safe_strcpy(conn->client_address, client_addr(), 
415                     sizeof(conn->client_address)-1);
416         conn->num_files_open = 0;
417         conn->lastused = time(NULL);
418         conn->service = snum;
419         conn->used = True;
420         conn->printer = (strncmp(dev,"LPT",3) == 0);
421         conn->ipc = ((strncmp(dev,"IPC",3) == 0) || strequal(dev,"ADMIN$"));
422         conn->dirptr = NULL;
423         conn->veto_list = NULL;
424         conn->hide_list = NULL;
425         conn->veto_oplock_list = NULL;
426         string_set(&conn->dirpath,"");
427         string_set(&conn->user,user);
428         conn->nt_user_token = NULL;
429         
430         set_read_only(conn);
431         
432         set_admin_user(conn);
433
434         /*
435          * If force user is true, then store the
436          * given userid and also the groups
437          * of the user we're forcing.
438          */
439         
440         if (*lp_force_user(snum)) {
441                 struct passwd *pass2;
442                 pstring fuser;
443                 pstrcpy(fuser,lp_force_user(snum));
444
445                 /* Allow %S to be used by force user. */
446                 pstring_sub(fuser,"%S",lp_servicename(snum));
447
448                 pass2 = (struct passwd *)Get_Pwnam(fuser);
449                 if (pass2) {
450                         conn->uid = pass2->pw_uid;
451                         conn->gid = pass2->pw_gid;
452                         string_set(&conn->user,pass2->pw_name);
453                         fstrcpy(user,pass2->pw_name);
454                         conn->force_user = True;
455                         DEBUG(3,("Forced user %s\n",user));       
456                 } else {
457                         DEBUG(1,("Couldn't find user %s\n",fuser));
458                         conn_free(conn);
459                         *status = NT_STATUS_NO_SUCH_USER;
460                         return NULL;
461                 }
462         }
463
464         /* admin users always run as uid=0 */
465         if (conn->admin_user) {
466                 conn->uid = 0;
467         }
468
469 #ifdef HAVE_GETGRNAM 
470         /*
471          * If force group is true, then override
472          * any groupid stored for the connecting user.
473          */
474         
475         if (*lp_force_group(snum)) {
476                 gid_t gid;
477                 pstring gname;
478                 pstring tmp_gname;
479                 BOOL user_must_be_member = False;
480                 
481                 StrnCpy(tmp_gname,lp_force_group(snum),sizeof(pstring)-1);
482                 
483                 if (tmp_gname[0] == '+') {
484                         user_must_be_member = True;
485                         StrnCpy(gname,&tmp_gname[1],sizeof(pstring)-2);
486                 } else {
487                         StrnCpy(gname,tmp_gname,sizeof(pstring)-1);
488                 }
489                 /* default service may be a group name          */
490                 pstring_sub(gname,"%S",lp_servicename(snum));
491                 gid = nametogid(gname);
492                 
493                 if (gid != (gid_t)-1) {
494
495                         /*
496                          * If the user has been forced and the forced group starts
497                          * with a '+', then we only set the group to be the forced
498                          * group if the forced user is a member of that group.
499                          * Otherwise, the meaning of the '+' would be ignored.
500                          */
501                         if (conn->force_user && user_must_be_member) {
502                                 if (user_in_group_list( user, gname )) {
503                                                 conn->gid = gid;
504                                                 DEBUG(3,("Forced group %s for member %s\n",gname,user));
505                                 }
506                         } else {
507                                 conn->gid = gid;
508                                 DEBUG(3,("Forced group %s\n",gname));
509                         }
510                         conn->force_group = True;
511                 } else {
512                         DEBUG(1,("Couldn't find group %s\n",gname));
513                         conn_free(conn);
514                         *status = NT_STATUS_NO_SUCH_GROUP;
515                         return NULL;
516                 }
517         }
518 #endif /* HAVE_GETGRNAM */
519
520         {
521                 pstring s;
522                 pstrcpy(s,lp_pathname(snum));
523                 standard_sub_conn(conn,s,sizeof(s));
524                 string_set(&conn->connectpath,s);
525                 DEBUG(3,("Connect path is '%s' for service [%s]\n",s, lp_servicename(snum)));
526         }
527
528         if (conn->force_user || conn->force_group) {
529
530                 /* groups stuff added by ih */
531                 conn->ngroups = 0;
532                 conn->groups = NULL;
533                 
534                 /* Find all the groups this uid is in and
535                    store them. Used by change_to_user() */
536                 initialise_groups(conn->user, conn->uid, conn->gid); 
537                 get_current_groups(conn->gid, &conn->ngroups,&conn->groups);
538                 
539                 conn->nt_user_token = create_nt_token(conn->uid, conn->gid, 
540                                                       conn->ngroups, conn->groups,
541                                                       guest);
542         }
543
544         /*
545          * New code to check if there's a share security descripter
546          * added from NT server manager. This is done after the
547          * smb.conf checks are done as we need a uid and token. JRA.
548          *
549          */
550
551         {
552                 BOOL can_write = share_access_check(conn, snum, vuser, FILE_WRITE_DATA);
553
554                 if (!can_write) {
555                         if (!share_access_check(conn, snum, vuser, FILE_READ_DATA)) {
556                                 /* No access, read or write. */
557                                 DEBUG(0,( "make_connection: connection to %s denied due to security descriptor.\n",
558                                           lp_servicename(snum)));
559                                 conn_free(conn);
560                                 *status = NT_STATUS_ACCESS_DENIED;
561                                 return NULL;
562                         } else {
563                                 conn->read_only = True;
564                         }
565                 }
566         }
567         /* Initialise VFS function pointers */
568
569         if (!smbd_vfs_init(conn)) {
570                 DEBUG(0, ("vfs_init failed for service %s\n", lp_servicename(SNUM(conn))));
571                 conn_free(conn);
572                 *status = NT_STATUS_UNSUCCESSFUL;
573                 return NULL;
574         }
575
576 /* ROOT Activities: */  
577         /* check number of connections */
578         if (!claim_connection(conn,
579                               lp_servicename(SNUM(conn)),
580                               lp_max_connections(SNUM(conn)),
581                               False,0)) {
582                 DEBUG(1,("too many connections - rejected\n"));
583                 conn_free(conn);
584                 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
585                 return NULL;
586         }  
587
588         /* Preexecs are done here as they might make the dir we are to ChDir to below */
589         /* execute any "root preexec = " line */
590         if (*lp_rootpreexec(SNUM(conn))) {
591                 int ret;
592                 pstring cmd;
593                 pstrcpy(cmd,lp_rootpreexec(SNUM(conn)));
594                 standard_sub_conn(conn,cmd,sizeof(cmd));
595                 DEBUG(5,("cmd=%s\n",cmd));
596                 ret = smbrun(cmd,NULL);
597                 if (ret != 0 && lp_rootpreexec_close(SNUM(conn))) {
598                         DEBUG(1,("root preexec gave %d - failing connection\n", ret));
599                         yield_connection(conn, lp_servicename(SNUM(conn)));
600                         conn_free(conn);
601                         *status = NT_STATUS_UNSUCCESSFUL;
602                         return NULL;
603                 }
604         }
605
606 /* USER Activites: */
607         if (!change_to_user(conn, conn->vuid)) {
608                 /* No point continuing if they fail the basic checks */
609                 DEBUG(0,("Can't become connected user!\n"));
610                 conn_free(conn);
611                 *status = NT_STATUS_LOGON_FAILURE;
612                 return NULL;
613         }
614         
615         /* Remember that a different vuid can connect later without these checks... */
616         
617         /* Preexecs are done here as they might make the dir we are to ChDir to below */
618         /* execute any "preexec = " line */
619         if (*lp_preexec(SNUM(conn))) {
620                 int ret;
621                 pstring cmd;
622                 pstrcpy(cmd,lp_preexec(SNUM(conn)));
623                 standard_sub_conn(conn,cmd,sizeof(cmd));
624                 ret = smbrun(cmd,NULL);
625                 if (ret != 0 && lp_preexec_close(SNUM(conn))) {
626                         DEBUG(1,("preexec gave %d - failing connection\n", ret));
627                         change_to_root_user();
628                         yield_connection(conn, lp_servicename(SNUM(conn)));
629                         conn_free(conn);
630                         *status = NT_STATUS_UNSUCCESSFUL;
631                         return NULL;
632                 }
633         }
634         
635 #if CHECK_PATH_ON_TCONX
636         /* win2000 does not check the permissions on the directory
637            during the tree connect, instead relying on permission
638            check during individual operations. To match this behaviour
639            I have disabled this chdir check (tridge) */
640         if (vfs_ChDir(conn,conn->connectpath) != 0) {
641                 DEBUG(0,("%s (%s) Can't change directory to %s (%s)\n",
642                          get_remote_machine_name(), conn->client_address,
643                          conn->connectpath,strerror(errno)));
644                 change_to_root_user();
645                 yield_connection(conn, lp_servicename(SNUM(conn)));
646                 conn_free(conn);
647                 *status = NT_STATUS_BAD_NETWORK_NAME;
648                 return NULL;
649         }
650 #else
651         /* the alternative is just to check the directory exists */
652         if (stat(conn->connectpath, &st) != 0 || !S_ISDIR(st.st_mode)) {
653                 DEBUG(0,("'%s' is not a directory, when connecting to [%s]\n", conn->connectpath, lp_servicename(SNUM(conn))));
654                 change_to_root_user();
655                 yield_connection(conn, lp_servicename(SNUM(conn)));
656                 conn_free(conn);
657                 *status = NT_STATUS_BAD_NETWORK_NAME;
658                 return NULL;
659         }
660 #endif
661         
662         string_set(&conn->origpath,conn->connectpath);
663         
664 #if SOFTLINK_OPTIMISATION
665         /* resolve any soft links early if possible */
666         if (vfs_ChDir(conn,conn->connectpath) == 0) {
667                 pstring s;
668                 pstrcpy(s,conn->connectpath);
669                 vfs_GetWd(conn,s);
670                 string_set(&conn->connectpath,s);
671                 vfs_ChDir(conn,conn->connectpath);
672         }
673 #endif
674         
675         /*
676          * Print out the 'connected as' stuff here as we need
677          * to know the effective uid and gid we will be using
678          * (at least initially).
679          */
680
681         if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
682                 dbgtext( "%s (%s) ", get_remote_machine_name(), conn->client_address );
683                 dbgtext( "connect to service %s ", lp_servicename(SNUM(conn)) );
684                 dbgtext( "initially as user %s ", user );
685                 dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
686                 dbgtext( "(pid %d)\n", (int)sys_getpid() );
687         }
688         
689         /* Add veto/hide lists */
690         if (!IS_IPC(conn) && !IS_PRINT(conn)) {
691                 set_namearray( &conn->veto_list, lp_veto_files(SNUM(conn)));
692                 set_namearray( &conn->hide_list, lp_hide_files(SNUM(conn)));
693                 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(SNUM(conn)));
694         }
695         
696         /* Invoke VFS make connection hook */
697
698         if (conn->vfs_ops.connect) {
699                 if (conn->vfs_ops.connect(conn, lp_servicename(snum), user) < 0) {
700                         DEBUG(0,("make_connection: VFS make connection failed!\n"));
701                         change_to_root_user();
702                         conn_free(conn);
703                         *status = NT_STATUS_UNSUCCESSFUL;
704                         return NULL;
705                 }
706         }
707
708         /* we've finished with the user stuff - go back to root */
709         change_to_root_user();
710             
711         return(conn);
712 }
713
714 /***************************************************************************************
715  Simple wrapper function for make_connection() to include a call to 
716  vfs_chdir()
717  **************************************************************************************/
718  
719 connection_struct *make_connection_with_chdir(const char *service_in, DATA_BLOB password, 
720                                    char *dev, uint16 vuid, NTSTATUS *status)
721 {
722         connection_struct *conn = NULL;
723         
724         conn = make_connection(service_in, password, dev, vuid, status);
725         
726         /*
727          * make_connection() does not change the directory for us any more
728          * so we have to do it as a separate step  --jerry
729          */
730          
731         if ( conn && vfs_ChDir(conn,conn->connectpath) != 0 ) {
732                 DEBUG(0,("move_driver_to_download_area: Can't change directory to %s for [print$] (%s)\n",
733                          conn->connectpath,strerror(errno)));
734                 yield_connection(conn, lp_servicename(SNUM(conn)));
735                 conn_free(conn);
736                 *status = NT_STATUS_UNSUCCESSFUL;
737                 return NULL;
738         }
739         
740         return conn;
741 }
742
743 /****************************************************************************
744  Make a connection to a service.
745  *
746  * @param service 
747 ****************************************************************************/
748
749 connection_struct *make_connection(const char *service_in, DATA_BLOB password, 
750                                    char *dev, uint16 vuid, NTSTATUS *status)
751 {
752         uid_t euid;
753         user_struct *vuser = NULL;
754         pstring service;
755         int snum = -1;
756
757         /* This must ONLY BE CALLED AS ROOT. As it exits this function as root. */
758         if (!non_root_mode() && (euid = geteuid()) != 0) {
759                 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot (%u)\n", (unsigned int)euid ));
760                 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
761         }
762
763         if(lp_security() != SEC_SHARE) {
764                 vuser = get_valid_user_struct(vuid);
765                 if (!vuser) {
766                         DEBUG(1,("make_connection: refusing to connect with no session setup\n"));
767                         *status = NT_STATUS_ACCESS_DENIED;
768                         return NULL;
769                 }
770         }
771
772         /* Logic to try and connect to the correct [homes] share, preferably without too many
773            getpwnam() lookups.  This is particulary nasty for winbind usernames, where the
774            share name isn't the same as unix username.
775
776            The snum of the homes share is stored on the vuser at session setup time.
777         */
778
779         if (strequal(service_in,HOMES_NAME)) {
780                 if(lp_security() != SEC_SHARE) {
781                         DATA_BLOB no_pw = data_blob(NULL, 0);
782                         if (vuser->homes_snum == -1) {
783                                 DEBUG(2, ("[homes] share not available for this user becouse it was not found or created at session setup time\n"));
784                                 *status = NT_STATUS_BAD_NETWORK_NAME;
785                                 return NULL;
786                         }
787                         DEBUG(5, ("making a connection to [homes] service created at session setup time\n"));
788                         return make_connection_snum(vuser->homes_snum,
789                                                     vuser, no_pw, 
790                                                     dev, status);
791                 } else {
792                         /* Security = share. Try with current_user_info.smb_name
793                          * as the username.  */
794                         if (*current_user_info.smb_name) {
795                                 fstring unix_username;
796                                 fstrcpy(unix_username,
797                                         current_user_info.smb_name);
798                                 map_username(unix_username);
799                                 snum = find_service(unix_username);
800                         } 
801                         if (snum != -1) {
802                                 DEBUG(5, ("making a connection to 'homes' service %s based on security=share\n", service_in));
803                                 return make_connection_snum(snum, NULL,
804                                                             password,
805                                                             dev, status);
806                         }
807                 }
808         } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
809                    && strequal(service_in, lp_servicename(vuser->homes_snum))) {
810                 DATA_BLOB no_pw = data_blob(NULL, 0);
811                 DEBUG(5, ("making a connection to 'homes' service [%s] created at session setup time\n", service_in));
812                 return make_connection_snum(vuser->homes_snum,
813                                             vuser, no_pw, 
814                                             dev, status);
815         }
816         
817         pstrcpy(service, service_in);
818
819         strlower(service);
820
821         snum = find_service(service);
822
823         if (snum < 0) {
824                 if (strequal(service,"IPC$") || strequal(service,"ADMIN$")) {
825                         DEBUG(3,("refusing IPC connection to %s\n", service));
826                         *status = NT_STATUS_ACCESS_DENIED;
827                         return NULL;
828                 }
829
830                 DEBUG(0,("%s (%s) couldn't find service %s\n",
831                          get_remote_machine_name(), client_addr(), service));
832                 *status = NT_STATUS_BAD_NETWORK_NAME;
833                 return NULL;
834         }
835
836         DEBUG(5, ("making a connection to 'normal' service %s\n", service));
837
838         return make_connection_snum(snum, vuser,
839                                     password,
840                                     dev, status);
841 }
842
843 /****************************************************************************
844 close a cnum
845 ****************************************************************************/
846 void close_cnum(connection_struct *conn, uint16 vuid)
847 {
848         DirCacheFlush(SNUM(conn));
849
850         change_to_root_user();
851
852         DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
853                                  get_remote_machine_name(),conn->client_address,
854                                  lp_servicename(SNUM(conn))));
855
856         if (conn->vfs_ops.disconnect != NULL) {
857
858             /* Call VFS disconnect hook */
859             
860             conn->vfs_ops.disconnect(conn);
861             
862         }
863
864         yield_connection(conn, lp_servicename(SNUM(conn)));
865
866         file_close_conn(conn);
867         dptr_closecnum(conn);
868
869         /* execute any "postexec = " line */
870         if (*lp_postexec(SNUM(conn)) && 
871             change_to_user(conn, vuid))  {
872                 pstring cmd;
873                 pstrcpy(cmd,lp_postexec(SNUM(conn)));
874                 standard_sub_conn(conn,cmd,sizeof(cmd));
875                 smbrun(cmd,NULL);
876                 change_to_root_user();
877         }
878
879         change_to_root_user();
880         /* execute any "root postexec = " line */
881         if (*lp_rootpostexec(SNUM(conn)))  {
882                 pstring cmd;
883                 pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
884                 standard_sub_conn(conn,cmd,sizeof(cmd));
885                 smbrun(cmd,NULL);
886         }
887
888         /* make sure we leave the directory available for unmount */
889         vfs_ChDir(conn, "/");
890
891         conn_free(conn);
892 }