Ok here it is my latest work on privileges
[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 = lp_printcapname();
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, fstring 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         if (dev[0] == '?' || !dev[0]) {
231                 if (lp_print_ok(snum)) {
232                         fstrcpy(dev,"LPT1:");
233                 } else if (strequal(lp_fstype(snum), "IPC")) {
234                         fstrcpy(dev, "IPC");
235                 } else {
236                         fstrcpy(dev,"A:");
237                 }
238         }
239
240         strupper_m(dev);
241
242         if (lp_print_ok(snum)) {
243                 if (!strequal(dev, "LPT1:")) {
244                         return NT_STATUS_BAD_DEVICE_TYPE;
245                 }
246         } else if (strequal(lp_fstype(snum), "IPC")) {
247                 if (!strequal(dev, "IPC")) {
248                         return NT_STATUS_BAD_DEVICE_TYPE;
249                 }
250         } else if (!strequal(dev, "A:")) {
251                 return NT_STATUS_BAD_DEVICE_TYPE;
252         }
253
254         /* Behave as a printer if we are supposed to */
255         if (lp_print_ok(snum) && (strcmp(dev, "A:") == 0)) {
256                 fstrcpy(dev, "LPT1:");
257         }
258
259         return NT_STATUS_OK;
260 }
261
262 /****************************************************************************
263   Make a connection, given the snum to connect to, and the vuser of the
264   connecting user if appropriate.
265 ****************************************************************************/
266
267 static connection_struct *make_connection_snum(int snum, user_struct *vuser,
268                                                DATA_BLOB password, 
269                                                const char *pdev, NTSTATUS *status)
270 {
271         struct passwd *pass = NULL;
272         BOOL guest = False;
273         connection_struct *conn;
274         struct stat st;
275         fstring user;
276         fstring dev;
277
278         *user = 0;
279         fstrcpy(dev, pdev);
280
281         if (NT_STATUS_IS_ERR(*status = share_sanity_checks(snum, dev))) {
282                 return NULL;
283         }       
284
285         conn = conn_new();
286         if (!conn) {
287                 DEBUG(0,("Couldn't find free connection.\n"));
288                 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
289                 return NULL;
290         }
291
292         if (lp_guest_only(snum)) {
293                 const char *guestname = lp_guestaccount();
294                 guest = True;
295                 pass = getpwnam_alloc(guestname);
296                 if (!pass) {
297                         DEBUG(0,("make_connection_snum: Invalid guest account %s??\n",guestname));
298                         conn_free(conn);
299                         *status = NT_STATUS_NO_SUCH_USER;
300                         return NULL;
301                 }
302                 fstrcpy(user,pass->pw_name);
303                 conn->force_user = True;
304                 conn->uid = pass->pw_uid;
305                 conn->gid = pass->pw_gid;
306                 string_set(&conn->user,pass->pw_name);
307                 passwd_free(&pass);
308                 DEBUG(3,("Guest only user %s\n",user));
309         } else if (vuser) {
310                 if (vuser->guest) {
311                         if (!lp_guest_ok(snum)) {
312                                 DEBUG(2, ("guest user (from session setup) not permitted to access this share (%s)\n", lp_servicename(snum)));
313                                       conn_free(conn);
314                                       *status = NT_STATUS_ACCESS_DENIED;
315                                       return NULL;
316                         }
317                 } else {
318                         if (!user_ok(vuser->user.unix_name, snum, vuser->groups, vuser->n_groups)) {
319                                 DEBUG(2, ("user '%s' (from session setup) not permitted to access this share (%s)\n", vuser->user.unix_name, lp_servicename(snum)));
320                                 conn_free(conn);
321                                 *status = NT_STATUS_ACCESS_DENIED;
322                                 return NULL;
323                         }
324                 }
325                 conn->vuid = vuser->vuid;
326                 conn->uid = vuser->uid;
327                 conn->gid = vuser->gid;
328                 string_set(&conn->user,vuser->user.unix_name);
329                 fstrcpy(user,vuser->user.unix_name);
330                 guest = vuser->guest; 
331         } else if (lp_security() == SEC_SHARE) {
332                 /* add it as a possible user name if we 
333                    are in share mode security */
334                 add_session_user(lp_servicename(snum));
335                 /* shall we let them in? */
336                 if (!authorise_login(snum,user,password,&guest)) {
337                         DEBUG( 2, ( "Invalid username/password for [%s]\n", 
338                                     lp_servicename(snum)) );
339                         conn_free(conn);
340                         *status = NT_STATUS_WRONG_PASSWORD;
341                         return NULL;
342                 }
343                 pass = Get_Pwnam(user);
344                 conn->force_user = True;
345                 conn->uid = pass->pw_uid;
346                 conn->gid = pass->pw_gid;
347                 string_set(&conn->user, pass->pw_name);
348                 fstrcpy(user, pass->pw_name);
349
350         } else {
351                 DEBUG(0, ("invalid VUID (vuser) but not in security=share\n"));
352                 conn_free(conn);
353                 *status = NT_STATUS_ACCESS_DENIED;
354                 return NULL;
355         }
356
357         add_session_user(user);
358
359         safe_strcpy(conn->client_address, client_addr(), 
360                     sizeof(conn->client_address)-1);
361         conn->num_files_open = 0;
362         conn->lastused = time(NULL);
363         conn->service = snum;
364         conn->used = True;
365         conn->printer = (strncmp(dev,"LPT",3) == 0);
366         conn->ipc = ((strncmp(dev,"IPC",3) == 0) || strequal(dev,"ADMIN$"));
367         conn->dirptr = NULL;
368         conn->veto_list = NULL;
369         conn->hide_list = NULL;
370         conn->veto_oplock_list = NULL;
371         string_set(&conn->dirpath,"");
372         string_set(&conn->user,user);
373         conn->nt_user_token = NULL;
374         conn->privs = NULL;
375
376         conn->read_only = lp_readonly(conn->service);
377         conn->admin_user = False;
378
379         /*
380          * If force user is true, then store the
381          * given userid and also the groups
382          * of the user we're forcing.
383          */
384         
385         if (*lp_force_user(snum)) {
386                 struct passwd *pass2;
387                 pstring fuser;
388                 pstrcpy(fuser,lp_force_user(snum));
389
390                 /* Allow %S to be used by force user. */
391                 pstring_sub(fuser,"%S",lp_servicename(snum));
392
393                 pass2 = (struct passwd *)Get_Pwnam(fuser);
394                 if (pass2) {
395                         conn->uid = pass2->pw_uid;
396                         conn->gid = pass2->pw_gid;
397                         string_set(&conn->user,pass2->pw_name);
398                         fstrcpy(user,pass2->pw_name);
399                         conn->force_user = True;
400                         DEBUG(3,("Forced user %s\n",user));       
401                 } else {
402                         DEBUG(1,("Couldn't find user %s\n",fuser));
403                         conn_free(conn);
404                         *status = NT_STATUS_NO_SUCH_USER;
405                         return NULL;
406                 }
407         }
408
409 #ifdef HAVE_GETGRNAM 
410         /*
411          * If force group is true, then override
412          * any groupid stored for the connecting user.
413          */
414         
415         if (*lp_force_group(snum)) {
416                 gid_t gid;
417                 pstring gname;
418                 pstring tmp_gname;
419                 BOOL user_must_be_member = False;
420                 
421                 pstrcpy(tmp_gname,lp_force_group(snum));
422                 
423                 if (tmp_gname[0] == '+') {
424                         user_must_be_member = True;
425                         /* even now, tmp_gname is null terminated */
426                         pstrcpy(gname,&tmp_gname[1]);
427                 } else {
428                         pstrcpy(gname,tmp_gname);
429                 }
430                 /* default service may be a group name          */
431                 pstring_sub(gname,"%S",lp_servicename(snum));
432                 gid = nametogid(gname);
433                 
434                 if (gid != (gid_t)-1) {
435
436                         /*
437                          * If the user has been forced and the forced group starts
438                          * with a '+', then we only set the group to be the forced
439                          * group if the forced user is a member of that group.
440                          * Otherwise, the meaning of the '+' would be ignored.
441                          */
442                         if (conn->force_user && user_must_be_member) {
443                                 if (user_in_group_list( user, gname, NULL, 0)) {
444                                                 conn->gid = gid;
445                                                 DEBUG(3,("Forced group %s for member %s\n",gname,user));
446                                 }
447                         } else {
448                                 conn->gid = gid;
449                                 DEBUG(3,("Forced group %s\n",gname));
450                         }
451                         conn->force_group = True;
452                 } else {
453                         DEBUG(1,("Couldn't find group %s\n",gname));
454                         conn_free(conn);
455                         *status = NT_STATUS_NO_SUCH_GROUP;
456                         return NULL;
457                 }
458         }
459 #endif /* HAVE_GETGRNAM */
460
461         {
462                 pstring s;
463                 pstrcpy(s,lp_pathname(snum));
464                 standard_sub_conn(conn,s,sizeof(s));
465                 string_set(&conn->connectpath,s);
466                 DEBUG(3,("Connect path is '%s' for service [%s]\n",s, lp_servicename(snum)));
467         }
468
469         if (conn->force_user || conn->force_group) {
470
471                 /* groups stuff added by ih */
472                 conn->ngroups = 0;
473                 conn->groups = NULL;
474                 
475                 /* Find all the groups this uid is in and
476                    store them. Used by change_to_user() */
477                 initialise_groups(conn->user, conn->uid, conn->gid); 
478                 get_current_groups(conn->gid, &conn->ngroups,&conn->groups);
479                 
480                 conn->nt_user_token = create_nt_token(conn->uid, conn->gid, 
481                                                       conn->ngroups, conn->groups,
482                                                       guest);
483
484                 init_privilege(&(conn->privs));
485                 pdb_get_privilege_set(conn->nt_user_token, conn->privs);
486         }
487
488         /*
489          * New code to check if there's a share security descripter
490          * added from NT server manager. This is done after the
491          * smb.conf checks are done as we need a uid and token. JRA.
492          *
493          */
494
495         {
496                 BOOL can_write = share_access_check(conn, snum, vuser, FILE_WRITE_DATA);
497
498                 if (!can_write) {
499                         if (!share_access_check(conn, snum, vuser, FILE_READ_DATA)) {
500                                 /* No access, read or write. */
501                                 DEBUG(0,( "make_connection: connection to %s denied due to security descriptor.\n",
502                                           lp_servicename(snum)));
503                                 conn_free(conn);
504                                 *status = NT_STATUS_ACCESS_DENIED;
505                                 return NULL;
506                         } else {
507                                 conn->read_only = True;
508                         }
509                 }
510         }
511         /* Initialise VFS function pointers */
512
513         if (!smbd_vfs_init(conn)) {
514                 DEBUG(0, ("vfs_init failed for service %s\n", lp_servicename(SNUM(conn))));
515                 conn_free(conn);
516                 *status = NT_STATUS_BAD_NETWORK_NAME;
517                 return NULL;
518         }
519
520 /* ROOT Activities: */  
521         /* check number of connections */
522         if (!claim_connection(conn,
523                               lp_servicename(SNUM(conn)),
524                               lp_max_connections(SNUM(conn)),
525                               False,0)) {
526                 DEBUG(1,("too many connections - rejected\n"));
527                 conn_free(conn);
528                 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
529                 return NULL;
530         }  
531
532         /* Preexecs are done here as they might make the dir we are to ChDir to below */
533         /* execute any "root preexec = " line */
534         if (*lp_rootpreexec(SNUM(conn))) {
535                 int ret;
536                 pstring cmd;
537                 pstrcpy(cmd,lp_rootpreexec(SNUM(conn)));
538                 standard_sub_conn(conn,cmd,sizeof(cmd));
539                 DEBUG(5,("cmd=%s\n",cmd));
540                 ret = smbrun(cmd,NULL);
541                 if (ret != 0 && lp_rootpreexec_close(SNUM(conn))) {
542                         DEBUG(1,("root preexec gave %d - failing connection\n", ret));
543                         yield_connection(conn, lp_servicename(SNUM(conn)));
544                         conn_free(conn);
545                         *status = NT_STATUS_ACCESS_DENIED;
546                         return NULL;
547                 }
548         }
549
550 /* USER Activites: */
551         if (!change_to_user(conn, conn->vuid)) {
552                 /* No point continuing if they fail the basic checks */
553                 DEBUG(0,("Can't become connected user!\n"));
554                 conn_free(conn);
555                 *status = NT_STATUS_LOGON_FAILURE;
556                 return NULL;
557         }
558
559         /* Remember that a different vuid can connect later without these checks... */
560         
561         /* Preexecs are done here as they might make the dir we are to ChDir to below */
562         /* execute any "preexec = " line */
563         if (*lp_preexec(SNUM(conn))) {
564                 int ret;
565                 pstring cmd;
566                 pstrcpy(cmd,lp_preexec(SNUM(conn)));
567                 standard_sub_conn(conn,cmd,sizeof(cmd));
568                 ret = smbrun(cmd,NULL);
569                 if (ret != 0 && lp_preexec_close(SNUM(conn))) {
570                         DEBUG(1,("preexec gave %d - failing connection\n", ret));
571                         change_to_root_user();
572                         yield_connection(conn, lp_servicename(SNUM(conn)));
573                         conn_free(conn);
574                         *status = NT_STATUS_ACCESS_DENIED;
575                         return NULL;
576                 }
577         }
578
579 #ifdef WITH_FAKE_KASERVER
580         if (lp_afs_share(SNUM(conn))) {
581                 afs_login(conn);
582         }
583 #endif
584         
585 #if CHECK_PATH_ON_TCONX
586         /* win2000 does not check the permissions on the directory
587            during the tree connect, instead relying on permission
588            check during individual operations. To match this behaviour
589            I have disabled this chdir check (tridge) */
590         if (vfs_ChDir(conn,conn->connectpath) != 0) {
591                 DEBUG(0,("%s (%s) Can't change directory to %s (%s)\n",
592                          get_remote_machine_name(), conn->client_address,
593                          conn->connectpath,strerror(errno)));
594                 change_to_root_user();
595                 yield_connection(conn, lp_servicename(SNUM(conn)));
596                 conn_free(conn);
597                 *status = NT_STATUS_BAD_NETWORK_NAME;
598                 return NULL;
599         }
600 #else
601         /* the alternative is just to check the directory exists */
602         if (stat(conn->connectpath, &st) != 0 || !S_ISDIR(st.st_mode)) {
603                 DEBUG(0,("'%s' does not exist or is not a directory, when connecting to [%s]\n", conn->connectpath, lp_servicename(SNUM(conn))));
604                 change_to_root_user();
605                 yield_connection(conn, lp_servicename(SNUM(conn)));
606                 conn_free(conn);
607                 *status = NT_STATUS_BAD_NETWORK_NAME;
608                 return NULL;
609         }
610 #endif
611         
612         string_set(&conn->origpath,conn->connectpath);
613         
614 #if SOFTLINK_OPTIMISATION
615         /* resolve any soft links early if possible */
616         if (vfs_ChDir(conn,conn->connectpath) == 0) {
617                 pstring s;
618                 pstrcpy(s,conn->connectpath);
619                 vfs_GetWd(conn,s);
620                 string_set(&conn->connectpath,s);
621                 vfs_ChDir(conn,conn->connectpath);
622         }
623 #endif
624         
625         /*
626          * Print out the 'connected as' stuff here as we need
627          * to know the effective uid and gid we will be using
628          * (at least initially).
629          */
630
631         if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
632                 dbgtext( "%s (%s) ", get_remote_machine_name(), conn->client_address );
633                 dbgtext( "%s", srv_is_signing_active() ? "signed " : "");
634                 dbgtext( "connect to service %s ", lp_servicename(SNUM(conn)) );
635                 dbgtext( "initially as user %s ", user );
636                 dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
637                 dbgtext( "(pid %d)\n", (int)sys_getpid() );
638         }
639         
640         /* Add veto/hide lists */
641         if (!IS_IPC(conn) && !IS_PRINT(conn)) {
642                 set_namearray( &conn->veto_list, lp_veto_files(SNUM(conn)));
643                 set_namearray( &conn->hide_list, lp_hide_files(SNUM(conn)));
644                 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(SNUM(conn)));
645         }
646         
647         /* Invoke VFS make connection hook */
648
649         if (SMB_VFS_CONNECT(conn, lp_servicename(snum), user) < 0) {
650                 DEBUG(0,("make_connection: VFS make connection failed!\n"));
651                 change_to_root_user();
652                 conn_free(conn);
653                 *status = NT_STATUS_UNSUCCESSFUL;
654                 return NULL;
655         }
656
657         /* we've finished with the user stuff - go back to root */
658         change_to_root_user();
659             
660         return(conn);
661 }
662
663 /***************************************************************************************
664  Simple wrapper function for make_connection() to include a call to 
665  vfs_chdir()
666  **************************************************************************************/
667  
668 connection_struct *make_connection_with_chdir(const char *service_in, DATA_BLOB password, 
669                                    const char *dev, uint16 vuid, NTSTATUS *status)
670 {
671         connection_struct *conn = NULL;
672         
673         conn = make_connection(service_in, password, dev, vuid, status);
674         
675         /*
676          * make_connection() does not change the directory for us any more
677          * so we have to do it as a separate step  --jerry
678          */
679          
680         if ( conn && vfs_ChDir(conn,conn->connectpath) != 0 ) {
681                 DEBUG(0,("move_driver_to_download_area: Can't change directory to %s for [print$] (%s)\n",
682                          conn->connectpath,strerror(errno)));
683                 yield_connection(conn, lp_servicename(SNUM(conn)));
684                 conn_free(conn);
685                 *status = NT_STATUS_UNSUCCESSFUL;
686                 return NULL;
687         }
688         
689         return conn;
690 }
691
692 /****************************************************************************
693  Make a connection to a service.
694  *
695  * @param service 
696 ****************************************************************************/
697
698 connection_struct *make_connection(const char *service_in, DATA_BLOB password, 
699                                    const char *pdev, uint16 vuid, NTSTATUS *status)
700 {
701         uid_t euid;
702         user_struct *vuser = NULL;
703         fstring service;
704         fstring dev;
705         int snum = -1;
706
707         fstrcpy(dev, pdev);
708
709         /* This must ONLY BE CALLED AS ROOT. As it exits this function as root. */
710         if (!non_root_mode() && (euid = geteuid()) != 0) {
711                 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot (%u)\n", (unsigned int)euid ));
712                 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
713         }
714
715         if(lp_security() != SEC_SHARE) {
716                 vuser = get_valid_user_struct(vuid);
717                 if (!vuser) {
718                         DEBUG(1,("make_connection: refusing to connect with no session setup\n"));
719                         *status = NT_STATUS_ACCESS_DENIED;
720                         return NULL;
721                 }
722         }
723
724         /* Logic to try and connect to the correct [homes] share, preferably without too many
725            getpwnam() lookups.  This is particulary nasty for winbind usernames, where the
726            share name isn't the same as unix username.
727
728            The snum of the homes share is stored on the vuser at session setup time.
729         */
730
731         if (strequal(service_in,HOMES_NAME)) {
732                 if(lp_security() != SEC_SHARE) {
733                         DATA_BLOB no_pw = data_blob(NULL, 0);
734                         if (vuser->homes_snum == -1) {
735                                 DEBUG(2, ("[homes] share not available for this user because it was not found or created at session setup time\n"));
736                                 *status = NT_STATUS_BAD_NETWORK_NAME;
737                                 return NULL;
738                         }
739                         DEBUG(5, ("making a connection to [homes] service created at session setup time\n"));
740                         return make_connection_snum(vuser->homes_snum,
741                                                     vuser, no_pw, 
742                                                     dev, status);
743                 } else {
744                         /* Security = share. Try with current_user_info.smb_name
745                          * as the username.  */
746                         if (*current_user_info.smb_name) {
747                                 fstring unix_username;
748                                 fstrcpy(unix_username,
749                                         current_user_info.smb_name);
750                                 map_username(unix_username);
751                                 snum = find_service(unix_username);
752                         } 
753                         if (snum != -1) {
754                                 DEBUG(5, ("making a connection to 'homes' service %s based on security=share\n", service_in));
755                                 return make_connection_snum(snum, NULL,
756                                                             password,
757                                                             dev, status);
758                         }
759                 }
760         } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
761                    && strequal(service_in, lp_servicename(vuser->homes_snum))) {
762                 DATA_BLOB no_pw = data_blob(NULL, 0);
763                 DEBUG(5, ("making a connection to 'homes' service [%s] created at session setup time\n", service_in));
764                 return make_connection_snum(vuser->homes_snum,
765                                             vuser, no_pw, 
766                                             dev, status);
767         }
768         
769         fstrcpy(service, service_in);
770
771         strlower_m(service);
772
773         snum = find_service(service);
774
775         if (snum < 0) {
776                 if (strequal(service,"IPC$") || strequal(service,"ADMIN$")) {
777                         DEBUG(3,("refusing IPC connection to %s\n", service));
778                         *status = NT_STATUS_ACCESS_DENIED;
779                         return NULL;
780                 }
781
782                 DEBUG(0,("%s (%s) couldn't find service %s\n",
783                          get_remote_machine_name(), client_addr(), service));
784                 *status = NT_STATUS_BAD_NETWORK_NAME;
785                 return NULL;
786         }
787
788         /* Handle non-Dfs clients attempting connections to msdfs proxy */
789         if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0'))  {
790                 DEBUG(3, ("refusing connection to dfs proxy '%s'\n", service));
791                 *status = NT_STATUS_BAD_NETWORK_NAME;
792                 return NULL;
793         }
794
795         DEBUG(5, ("making a connection to 'normal' service %s\n", service));
796
797         return make_connection_snum(snum, vuser,
798                                     password,
799                                     dev, status);
800 }
801
802 /****************************************************************************
803 close a cnum
804 ****************************************************************************/
805 void close_cnum(connection_struct *conn, uint16 vuid)
806 {
807         DirCacheFlush(SNUM(conn));
808
809         change_to_root_user();
810
811         DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
812                                  get_remote_machine_name(),conn->client_address,
813                                  lp_servicename(SNUM(conn))));
814
815         /* Call VFS disconnect hook */    
816         SMB_VFS_DISCONNECT(conn);
817
818         yield_connection(conn, lp_servicename(SNUM(conn)));
819
820         file_close_conn(conn);
821         dptr_closecnum(conn);
822
823         /* make sure we leave the directory available for unmount */
824         vfs_ChDir(conn, "/");
825
826         /* execute any "postexec = " line */
827         if (*lp_postexec(SNUM(conn)) && 
828             change_to_user(conn, vuid))  {
829                 pstring cmd;
830                 pstrcpy(cmd,lp_postexec(SNUM(conn)));
831                 standard_sub_conn(conn,cmd,sizeof(cmd));
832                 smbrun(cmd,NULL);
833                 change_to_root_user();
834         }
835
836         change_to_root_user();
837         /* execute any "root postexec = " line */
838         if (*lp_rootpostexec(SNUM(conn)))  {
839                 pstring cmd;
840                 pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
841                 standard_sub_conn(conn,cmd,sizeof(cmd));
842                 smbrun(cmd,NULL);
843         }
844
845         conn_free(conn);
846 }