Give an idea what service didn't have the directory.
[ira/wip.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 fstring remote_machine;
31 extern userdom_struct current_user_info;
32 extern fstring remote_machine;
33
34
35 /****************************************************************************
36  Load parameters specific to a connection/service.
37 ****************************************************************************/
38
39 BOOL set_current_service(connection_struct *conn,BOOL do_chdir)
40 {
41         extern char magic_char;
42         static connection_struct *last_conn;
43         int snum;
44
45         if (!conn)  {
46                 last_conn = NULL;
47                 return(False);
48         }
49
50         conn->lastused = smb_last_time.tv_sec;
51
52         snum = SNUM(conn);
53   
54         if (do_chdir &&
55             vfs_ChDir(conn,conn->connectpath) != 0 &&
56             vfs_ChDir(conn,conn->origpath) != 0) {
57                 DEBUG(0,("chdir (%s) failed\n",
58                          conn->connectpath));
59                 return(False);
60         }
61
62         if (conn == last_conn)
63                 return(True);
64
65         last_conn = conn;
66
67         case_default = lp_defaultcase(snum);
68         case_preserve = lp_preservecase(snum);
69         short_case_preserve = lp_shortpreservecase(snum);
70         case_mangle = lp_casemangle(snum);
71         case_sensitive = lp_casesensitive(snum);
72         magic_char = lp_magicchar(snum);
73         use_mangled_map = (*lp_mangled_map(snum) ? True:False);
74         return(True);
75 }
76
77 /****************************************************************************
78  Add a home service. Returns the new service number or -1 if fail.
79 ****************************************************************************/
80
81 int add_home_service(const char *service, const char *username, const char *homedir)
82 {
83         int iHomeService;
84
85         if (!service || !homedir)
86                 return -1;
87
88         if ((iHomeService = lp_servicenumber(HOMES_NAME)) < 0)
89                 return -1;
90
91         /*
92          * If this is a winbindd provided username, remove
93          * the domain component before adding the service.
94          * Log a warning if the "path=" parameter does not
95          * include any macros.
96          */
97
98         {
99                 const char *p = strchr(service,*lp_winbind_separator());
100
101                 /* We only want the 'user' part of the string */
102                 if (p) {
103                         service = p + 1;
104                 }
105         }
106
107         lp_add_home(service, iHomeService, username, homedir);
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, 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, 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                 DEBUG(0,("%s logged in as admin user (root privileges)\n",conn->user));
309         } else {
310                 conn->admin_user = False;
311         }
312
313 #if 0 /* This done later, for now */    
314         /* admin users always run as uid=0 */
315         if (conn->admin_user) {
316                 conn->uid = 0;
317         }
318 #endif
319 }
320
321 /****************************************************************************
322   Make a connection, given the snum to connect to, and the vuser of the
323   connecting user if appropriate.
324 ****************************************************************************/
325
326 static connection_struct *make_connection_snum(int snum, user_struct *vuser,
327                                                DATA_BLOB password, 
328                                                char *dev, NTSTATUS *status)
329 {
330         struct passwd *pass = NULL;
331         BOOL guest = False;
332         BOOL force = 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                 char *guestname = lp_guestaccount();
351                 guest = True;
352                 force = True;
353                 pass = getpwnam_alloc(guestname);
354                 if (!pass) {
355                         DEBUG(0,("authorise_login: Invalid guest account %s??\n",guestname));
356                         conn_free(conn);
357                         *status = NT_STATUS_NO_SUCH_USER;
358                         return NULL;
359                 }
360                 fstrcpy(user,pass->pw_name);
361                 conn->force_user = True;
362                 string_set(&conn->user,pass->pw_name);
363                 passwd_free(&pass);
364                 DEBUG(3,("Guest only user %s\n",user));
365         } else if (vuser) {
366                 if (vuser->guest) {
367                         if (!lp_guest_ok(snum)) {
368                                 DEBUG(2, ("guest user (from session setup) not permitted to access this share (%s)", lp_servicename(snum)));
369                                       conn_free(conn);
370                                       *status = NT_STATUS_ACCESS_DENIED;
371                                       return NULL;
372                         }
373                 } else {
374                         if (!user_ok(vuser->user.unix_name, snum)) {
375                                 DEBUG(2, ("user '%s' (from session setup) not permitted to access this share (%s)", vuser->user.unix_name, lp_servicename(snum)));
376                                 conn_free(conn);
377                                 *status = NT_STATUS_ACCESS_DENIED;
378                                 return NULL;
379                         }
380                 }
381                 conn->vuid = vuser->vuid;
382                 conn->uid = vuser->uid;
383                 conn->gid = vuser->gid;
384                 string_set(&conn->user,vuser->user.unix_name);
385                 fstrcpy(user,vuser->user.unix_name);
386                 guest = vuser->guest; 
387         } else if (lp_security() == SEC_SHARE) {
388                 /* add it as a possible user name if we 
389                    are in share mode security */
390                 add_session_user(lp_servicename(snum));
391                 /* shall we let them in? */
392                 if (!authorise_login(snum,user,password,&guest)) {
393                         DEBUG( 2, ( "Invalid username/password for [%s]\n", 
394                                     lp_servicename(snum)) );
395                         conn_free(conn);
396                         *status = NT_STATUS_WRONG_PASSWORD;
397                         return NULL;
398                 }
399                 pass = Get_Pwnam(user);
400                 conn->force_user = force;
401                 conn->uid = pass->pw_uid;
402                 conn->gid = pass->pw_gid;
403                 string_set(&conn->user, pass->pw_name);
404                 fstrcpy(user, pass->pw_name);
405
406         } else {
407                 DEBUG(0, ("invalid VUID (vuser) but not in security=share\n"));
408                 conn_free(conn);
409                 *status = NT_STATUS_ACCESS_DENIED;
410                 return NULL;
411         }
412
413         add_session_user(user);
414
415         safe_strcpy(conn->client_address, client_addr(), 
416                     sizeof(conn->client_address)-1);
417         conn->num_files_open = 0;
418         conn->lastused = time(NULL);
419         conn->service = snum;
420         conn->used = True;
421         conn->printer = (strncmp(dev,"LPT",3) == 0);
422         conn->ipc = ((strncmp(dev,"IPC",3) == 0) || strequal(dev,"ADMIN$"));
423         conn->dirptr = NULL;
424         conn->veto_list = NULL;
425         conn->hide_list = NULL;
426         conn->veto_oplock_list = NULL;
427         string_set(&conn->dirpath,"");
428         string_set(&conn->user,user);
429         conn->nt_user_token = NULL;
430         
431         set_read_only(conn);
432         
433         set_admin_user(conn);
434
435         /*
436          * If force user is true, then store the
437          * given userid and also the primary groupid
438          * of the user we're forcing.
439          */
440         
441         if (*lp_force_user(snum)) {
442                 struct passwd *pass2;
443                 pstring fuser;
444                 pstrcpy(fuser,lp_force_user(snum));
445
446                 /* Allow %S to be used by force user. */
447                 pstring_sub(fuser,"%S",lp_servicename(snum));
448
449                 pass2 = (struct passwd *)Get_Pwnam(fuser);
450                 if (pass2) {
451                         conn->uid = pass2->pw_uid;
452                         conn->gid = pass2->pw_gid;
453                         string_set(&conn->user,pass2->pw_name);
454                         fstrcpy(user,pass2->pw_name);
455                         conn->force_user = True;
456                         DEBUG(3,("Forced user %s\n",user));       
457                 } else {
458                         DEBUG(1,("Couldn't find user %s\n",fuser));
459                         conn_free(conn);
460                         *status = NT_STATUS_NO_SUCH_USER;
461                         return NULL;
462                 }
463         }
464
465         /* admin users always run as uid=0 */
466         if (conn->admin_user) {
467                 conn->uid = 0;
468         }
469
470 #ifdef HAVE_GETGRNAM 
471         /*
472          * If force group is true, then override
473          * any groupid stored for the connecting user.
474          */
475         
476         if (*lp_force_group(snum)) {
477                 gid_t gid;
478                 pstring gname;
479                 pstring tmp_gname;
480                 BOOL user_must_be_member = False;
481                 
482                 StrnCpy(tmp_gname,lp_force_group(snum),sizeof(pstring)-1);
483                 
484                 if (tmp_gname[0] == '+') {
485                         user_must_be_member = True;
486                         StrnCpy(gname,&tmp_gname[1],sizeof(pstring)-2);
487                 } else {
488                         StrnCpy(gname,tmp_gname,sizeof(pstring)-1);
489                 }
490                 /* default service may be a group name          */
491                 pstring_sub(gname,"%S",lp_servicename(snum));
492                 gid = nametogid(gname);
493                 
494                 if (gid != (gid_t)-1) {
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                 } else {
511                         DEBUG(1,("Couldn't find group %s\n",gname));
512                         conn_free(conn);
513                         *status = NT_STATUS_NO_SUCH_GROUP;
514                         return NULL;
515                 }
516         }
517 #endif /* HAVE_GETGRNAM */
518
519         {
520                 pstring s;
521                 pstrcpy(s,lp_pathname(snum));
522                 standard_sub_conn(conn,s,sizeof(s));
523                 string_set(&conn->connectpath,s);
524                 DEBUG(3,("Connect path is %s\n",s));
525         }
526
527         /* groups stuff added by ih */
528         conn->ngroups = 0;
529         conn->groups = NULL;
530         
531         /* Find all the groups this uid is in and
532            store them. Used by change_to_user() */
533         initialise_groups(conn->user, conn->uid, conn->gid); 
534         get_current_groups(conn->gid, &conn->ngroups,&conn->groups);
535                 
536         conn->nt_user_token = create_nt_token(conn->uid, conn->gid, 
537                                               conn->ngroups, conn->groups,
538                                               guest, NULL);
539
540         /*
541          * New code to check if there's a share security descripter
542          * added from NT server manager. This is done after the
543          * smb.conf checks are done as we need a uid and token. JRA.
544          */
545
546         {
547                 BOOL can_write = share_access_check(conn, snum, vuser, FILE_WRITE_DATA);
548
549                 if (!can_write) {
550                         if (!share_access_check(conn, snum, vuser, FILE_READ_DATA)) {
551                                 /* No access, read or write. */
552                                 DEBUG(0,( "make_connection: connection to %s denied due to security descriptor.\n",
553                                           lp_servicename(snum)));
554                                 conn_free(conn);
555                                 *status = NT_STATUS_ACCESS_DENIED;
556                                 return NULL;
557                         } else {
558                                 conn->read_only = True;
559                         }
560                 }
561         }
562         /* Initialise VFS function pointers */
563
564         if (!smbd_vfs_init(conn)) {
565                 DEBUG(0, ("vfs_init failed for service %s\n", lp_servicename(SNUM(conn))));
566                 conn_free(conn);
567                 *status = NT_STATUS_UNSUCCESSFUL;
568                 return NULL;
569         }
570
571 /* ROOT Activities: */  
572         /* check number of connections */
573         if (!claim_connection(conn,
574                               lp_servicename(SNUM(conn)),
575                               lp_max_connections(SNUM(conn)),
576                               False)) {
577                 DEBUG(1,("too many connections - rejected\n"));
578                 conn_free(conn);
579                 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
580                 return NULL;
581         }  
582
583         /* Preexecs are done here as they might make the dir we are to ChDir to below */
584         /* execute any "root preexec = " line */
585         if (*lp_rootpreexec(SNUM(conn))) {
586                 int ret;
587                 pstring cmd;
588                 pstrcpy(cmd,lp_rootpreexec(SNUM(conn)));
589                 standard_sub_conn(conn,cmd,sizeof(cmd));
590                 DEBUG(5,("cmd=%s\n",cmd));
591                 ret = smbrun(cmd,NULL);
592                 if (ret != 0 && lp_rootpreexec_close(SNUM(conn))) {
593                         DEBUG(1,("root preexec gave %d - failing connection\n", ret));
594                         yield_connection(conn, lp_servicename(SNUM(conn)));
595                         conn_free(conn);
596                         *status = NT_STATUS_UNSUCCESSFUL;
597                         return NULL;
598                 }
599         }
600
601 /* USER Activites: */
602         if (!change_to_user(conn, conn->vuid)) {
603                 /* No point continuing if they fail the basic checks */
604                 DEBUG(0,("Can't become connected user!\n"));
605                 conn_free(conn);
606                 *status = NT_STATUS_LOGON_FAILURE;
607                 return NULL;
608         }
609         
610         /* Remember that a different vuid can connect later without these checks... */
611         
612         /* Preexecs are done here as they might make the dir we are to ChDir to below */
613         /* execute any "preexec = " line */
614         if (*lp_preexec(SNUM(conn))) {
615                 int ret;
616                 pstring cmd;
617                 pstrcpy(cmd,lp_preexec(SNUM(conn)));
618                 standard_sub_conn(conn,cmd,sizeof(cmd));
619                 ret = smbrun(cmd,NULL);
620                 if (ret != 0 && lp_preexec_close(SNUM(conn))) {
621                         DEBUG(1,("preexec gave %d - failing connection\n", ret));
622                         change_to_root_user();
623                         yield_connection(conn, lp_servicename(SNUM(conn)));
624                         conn_free(conn);
625                         *status = NT_STATUS_UNSUCCESSFUL;
626                         return NULL;
627                 }
628         }
629         
630 #if CHECK_PATH_ON_TCONX
631         /* win2000 does not check the permissions on the directory
632            during the tree connect, instead relying on permission
633            check during individual operations. To match this behaviour
634            I have disabled this chdir check (tridge) */
635         if (vfs_ChDir(conn,conn->connectpath) != 0) {
636                 DEBUG(0,("%s (%s) Can't change directory to %s (%s)\n",
637                          remote_machine, conn->client_address,
638                          conn->connectpath,strerror(errno)));
639                 change_to_root_user();
640                 yield_connection(conn, lp_servicename(SNUM(conn)));
641                 conn_free(conn);
642                 *status = NT_STATUS_BAD_NETWORK_NAME;
643                 return NULL;
644         }
645 #else
646         /* the alternative is just to check the directory exists */
647         if (stat(conn->connectpath, &st) != 0 || !S_ISDIR(st.st_mode)) {
648                 DEBUG(0,("'%s' is not a directory, when connecting to [%s]\n", conn->connectpath, lp_servicename(SNUM(conn))));
649                 change_to_root_user();
650                 yield_connection(conn, lp_servicename(SNUM(conn)));
651                 conn_free(conn);
652                 *status = NT_STATUS_BAD_NETWORK_NAME;
653                 return NULL;
654         }
655 #endif
656         
657         string_set(&conn->origpath,conn->connectpath);
658         
659 #if SOFTLINK_OPTIMISATION
660         /* resolve any soft links early if possible */
661         if (vfs_ChDir(conn,conn->connectpath) == 0) {
662                 pstring s;
663                 pstrcpy(s,conn->connectpath);
664                 vfs_GetWd(conn,s);
665                 string_set(&conn->connectpath,s);
666                 vfs_ChDir(conn,conn->connectpath);
667         }
668 #endif
669         
670         /*
671          * Print out the 'connected as' stuff here as we need
672          * to know the effective uid and gid we will be using
673          * (at least initially).
674          */
675
676         if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
677                 dbgtext( "%s (%s) ", remote_machine, conn->client_address );
678                 dbgtext( "connect to service %s ", lp_servicename(SNUM(conn)) );
679                 dbgtext( "initially as user %s ", user );
680                 dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
681                 dbgtext( "(pid %d)\n", (int)sys_getpid() );
682         }
683         
684         /* Add veto/hide lists */
685         if (!IS_IPC(conn) && !IS_PRINT(conn)) {
686                 set_namearray( &conn->veto_list, lp_veto_files(SNUM(conn)));
687                 set_namearray( &conn->hide_list, lp_hide_files(SNUM(conn)));
688                 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(SNUM(conn)));
689         }
690         
691         /* Invoke VFS make connection hook */
692
693         if (conn->vfs_ops.connect) {
694                 if (conn->vfs_ops.connect(conn, lp_servicename(snum), user) < 0) {
695                         DEBUG(0,("make_connection: VFS make connection failed!\n"));
696                         change_to_root_user();
697                         conn_free(conn);
698                         *status = NT_STATUS_UNSUCCESSFUL;
699                         return NULL;
700                 }
701         }
702
703         /* we've finished with the user stuff - go back to root */
704         change_to_root_user();
705             
706         return(conn);
707 }
708
709 /***************************************************************************************
710  Simple wrapper function for make_connection() to include a call to 
711  vfs_chdir()
712  **************************************************************************************/
713  
714 connection_struct *make_connection_with_chdir(const char *service_in, DATA_BLOB password, 
715                                    char *dev, uint16 vuid, NTSTATUS *status)
716 {
717         connection_struct *conn = NULL;
718         
719         conn = make_connection(service_in, password, dev, vuid, status);
720         
721         /*
722          * make_connection() does not change the directory for us any more
723          * so we have to do it as a separate step  --jerry
724          */
725          
726         if ( conn && vfs_ChDir(conn,conn->connectpath) != 0 ) {
727                 DEBUG(0,("move_driver_to_download_area: Can't change directory to %s for [print$] (%s)\n",
728                          conn->connectpath,strerror(errno)));
729                 yield_connection(conn, lp_servicename(SNUM(conn)));
730                 conn_free(conn);
731                 *status = NT_STATUS_UNSUCCESSFUL;
732                 return NULL;
733         }
734         
735         return conn;
736 }
737
738 /****************************************************************************
739  Make a connection to a service.
740  *
741  * @param service 
742 ****************************************************************************/
743
744 connection_struct *make_connection(const char *service_in, DATA_BLOB password, 
745                                    char *dev, uint16 vuid, NTSTATUS *status)
746 {
747         uid_t euid;
748         user_struct *vuser = NULL;
749         pstring service;
750         int snum = -1;
751
752         /* This must ONLY BE CALLED AS ROOT. As it exits this function as root. */
753         if (!non_root_mode() && (euid = geteuid()) != 0) {
754                 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot (%u)\n", (unsigned int)euid ));
755                 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
756         }
757
758         if(lp_security() != SEC_SHARE) {
759                 vuser = get_valid_user_struct(vuid);
760                 if (!vuser) {
761                         DEBUG(1,("make_connection: refusing to connect with no session setup\n"));
762                         return NULL;
763                 }
764         }
765
766         /* Logic to try and connect to the correct [homes] share, preferably without too many
767            getpwnam() lookups.  This is particulary nasty for winbind usernames, where the
768            share name isn't the same as unix username.
769
770            The snum of the homes share is stored on the vuser at session setup time.
771         */
772
773         if (strequal(service_in,HOMES_NAME)) {
774                 if(lp_security() != SEC_SHARE) {
775                         DATA_BLOB no_pw = data_blob(NULL, 0);
776                         if (vuser->homes_snum != -1) {
777                                 DEBUG(5, ("making a connection to [homes] service created at session setup time\n"));
778                                         return make_connection_snum(vuser->homes_snum,
779                                                                     vuser, no_pw, 
780                                                             dev, status);
781                         }
782                 } else {
783                         /* Security = share. Try with current_user_info.smb_name
784                          * as the username.  */
785                         if (*current_user_info.smb_name) {
786                                 fstring unix_username;
787                                 fstrcpy(unix_username,
788                                         current_user_info.smb_name);
789                                 map_username(unix_username);
790                                 snum = find_service(unix_username);
791                         } 
792                         if (snum != -1) {
793                                 DEBUG(5, ("making a connection to 'homes' service %s based on security=share\n", service_in));
794                                 return make_connection_snum(snum, NULL,
795                                                             password,
796                                                             dev, status);
797                         }
798                 }
799         } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
800                    && strequal(service_in, lp_servicename(vuser->homes_snum))) {
801                 DATA_BLOB no_pw = data_blob(NULL, 0);
802                 DEBUG(5, ("making a connection to 'homes' service [%s] created at session setup time\n", service));
803                 return make_connection_snum(vuser->homes_snum,
804                                             vuser, no_pw, 
805                                             dev, status);
806         }
807         
808         pstrcpy(service, service_in);
809
810         strlower(service);
811
812         snum = find_service(service);
813
814         if (snum < 0) {
815                 if (strequal(service,"IPC$") || strequal(service,"ADMIN$")) {
816                         DEBUG(3,("refusing IPC connection to %s\n", service));
817                         *status = NT_STATUS_ACCESS_DENIED;
818                         return NULL;
819                 }
820
821                 DEBUG(0,("%s (%s) couldn't find service %s\n",
822                          remote_machine, client_addr(), service));
823                 *status = NT_STATUS_BAD_NETWORK_NAME;
824                 return NULL;
825         }
826
827         DEBUG(5, ("making a connection to 'normal' service %s\n", service));
828
829         return make_connection_snum(snum, vuser,
830                                     password,
831                                     dev, status);
832 }
833
834 /****************************************************************************
835 close a cnum
836 ****************************************************************************/
837 void close_cnum(connection_struct *conn, uint16 vuid)
838 {
839         DirCacheFlush(SNUM(conn));
840
841         change_to_root_user();
842
843         DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
844                                  remote_machine,conn->client_address,
845                                  lp_servicename(SNUM(conn))));
846
847         if (conn->vfs_ops.disconnect != NULL) {
848
849             /* Call VFS disconnect hook */
850             
851             conn->vfs_ops.disconnect(conn);
852             
853         }
854
855         yield_connection(conn, lp_servicename(SNUM(conn)));
856
857         file_close_conn(conn);
858         dptr_closecnum(conn);
859
860         /* execute any "postexec = " line */
861         if (*lp_postexec(SNUM(conn)) && 
862             change_to_user(conn, vuid))  {
863                 pstring cmd;
864                 pstrcpy(cmd,lp_postexec(SNUM(conn)));
865                 standard_sub_conn(conn,cmd,sizeof(cmd));
866                 smbrun(cmd,NULL);
867                 change_to_root_user();
868         }
869
870         change_to_root_user();
871         /* execute any "root postexec = " line */
872         if (*lp_rootpostexec(SNUM(conn)))  {
873                 pstring cmd;
874                 pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
875                 standard_sub_conn(conn,cmd,sizeof(cmd));
876                 smbrun(cmd,NULL);
877         }
878
879         /* make sure we leave the directory available for unmount */
880         vfs_ChDir(conn, "/");
881
882         conn_free(conn);
883 }