r2: import HEAD into svn+ssh://svn.samba.org/home/svn/samba/trunk
[Samba.git] / source / smbd / service.c
blob1910ef9b72be2e96be9649a1276ddba7e543bd03
1 /*
2 Unix SMB/CIFS implementation.
3 service (connection) opening and closing
4 Copyright (C) Andrew Tridgell 1992-1998
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.
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.
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.
21 #include "includes.h"
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;
33 /****************************************************************************
34 Load parameters specific to a connection/service.
35 ****************************************************************************/
37 BOOL set_current_service(connection_struct *conn,BOOL do_chdir)
39 extern char magic_char;
40 static connection_struct *last_conn;
41 int snum;
43 if (!conn) {
44 last_conn = NULL;
45 return(False);
48 conn->lastused = smb_last_time.tv_sec;
50 snum = SNUM(conn);
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);
60 if (conn == last_conn)
61 return(True);
63 last_conn = conn;
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);
75 /****************************************************************************
76 Add a home service. Returns the new service number or -1 if fail.
77 ****************************************************************************/
79 int add_home_service(const char *service, const char *username, const char *homedir)
81 int iHomeService;
83 if (!service || !homedir)
84 return -1;
86 if ((iHomeService = lp_servicenumber(HOMES_NAME)) < 0)
87 return -1;
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.
97 const char *p = strchr(service,*lp_winbind_separator());
99 /* We only want the 'user' part of the string */
100 if (p) {
101 service = p + 1;
105 if (!lp_add_home(service, iHomeService, username, homedir)) {
106 return -1;
109 return lp_servicenumber(service);
115 * Find a service entry.
117 * @param service is modified (to canonical form??)
120 int find_service(fstring service)
122 int iService;
124 all_string_sub(service,"\\","/",0);
126 iService = lp_servicenumber(service);
128 /* now handle the special case of a home directory */
129 if (iService < 0) {
130 char *phome_dir = get_user_home_dir(service);
132 if(!phome_dir) {
134 * Try mapping the servicename, it may
135 * be a Windows to unix mapped user name.
137 if(map_username(service))
138 phome_dir = get_user_home_dir(service);
141 DEBUG(3,("checking for home directory %s gave %s\n",service,
142 phome_dir?phome_dir:"(NULL)"));
144 iService = add_home_service(service,service /* 'username' */, phome_dir);
147 /* If we still don't have a service, attempt to add it as a printer. */
148 if (iService < 0) {
149 int iPrinterService;
151 if ((iPrinterService = lp_servicenumber(PRINTERS_NAME)) >= 0) {
152 char *pszTemp;
154 DEBUG(3,("checking whether %s is a valid printer name...\n", service));
155 pszTemp = lp_printcapname();
156 if ((pszTemp != NULL) && pcap_printername_ok(service, pszTemp)) {
157 DEBUG(3,("%s is a valid printer name\n", service));
158 DEBUG(3,("adding %s as a printer service\n", service));
159 lp_add_printer(service, iPrinterService);
160 iService = lp_servicenumber(service);
161 if (iService < 0) {
162 DEBUG(0,("failed to add %s as a printer service!\n", service));
164 } else {
165 DEBUG(3,("%s is not a valid printer name\n", service));
170 /* Check for default vfs service? Unsure whether to implement this */
171 if (iService < 0) {
174 /* just possibly it's a default service? */
175 if (iService < 0) {
176 char *pdefservice = lp_defaultservice();
177 if (pdefservice && *pdefservice && !strequal(pdefservice,service) && !strstr_m(service,"..")) {
179 * We need to do a local copy here as lp_defaultservice()
180 * returns one of the rotating lp_string buffers that
181 * could get overwritten by the recursive find_service() call
182 * below. Fix from Josef Hinteregger <joehtg@joehtg.co.at>.
184 pstring defservice;
185 pstrcpy(defservice, pdefservice);
186 iService = find_service(defservice);
187 if (iService >= 0) {
188 all_string_sub(service, "_","/",0);
189 iService = lp_add_service(service, iService);
194 if (iService >= 0) {
195 if (!VALID_SNUM(iService)) {
196 DEBUG(0,("Invalid snum %d for %s\n",iService, service));
197 iService = -1;
201 if (iService < 0)
202 DEBUG(3,("find_service() failed to find service %s\n", service));
204 return (iService);
208 /****************************************************************************
209 do some basic sainity checks on the share.
210 This function modifies dev, ecode.
211 ****************************************************************************/
213 static NTSTATUS share_sanity_checks(int snum, fstring dev)
216 if (!lp_snum_ok(snum) ||
217 !check_access(smbd_server_fd(),
218 lp_hostsallow(snum), lp_hostsdeny(snum))) {
219 return NT_STATUS_ACCESS_DENIED;
222 if (dev[0] == '?' || !dev[0]) {
223 if (lp_print_ok(snum)) {
224 fstrcpy(dev,"LPT1:");
225 } else if (strequal(lp_fstype(snum), "IPC")) {
226 fstrcpy(dev, "IPC");
227 } else {
228 fstrcpy(dev,"A:");
232 strupper_m(dev);
234 if (lp_print_ok(snum)) {
235 if (!strequal(dev, "LPT1:")) {
236 return NT_STATUS_BAD_DEVICE_TYPE;
238 } else if (strequal(lp_fstype(snum), "IPC")) {
239 if (!strequal(dev, "IPC")) {
240 return NT_STATUS_BAD_DEVICE_TYPE;
242 } else if (!strequal(dev, "A:")) {
243 return NT_STATUS_BAD_DEVICE_TYPE;
246 /* Behave as a printer if we are supposed to */
247 if (lp_print_ok(snum) && (strcmp(dev, "A:") == 0)) {
248 fstrcpy(dev, "LPT1:");
251 return NT_STATUS_OK;
254 /****************************************************************************
255 Make a connection, given the snum to connect to, and the vuser of the
256 connecting user if appropriate.
257 ****************************************************************************/
259 static connection_struct *make_connection_snum(int snum, user_struct *vuser,
260 DATA_BLOB password,
261 const char *pdev, NTSTATUS *status)
263 struct passwd *pass = NULL;
264 BOOL guest = False;
265 connection_struct *conn;
266 struct stat st;
267 fstring user;
268 fstring dev;
270 *user = 0;
271 fstrcpy(dev, pdev);
273 if (NT_STATUS_IS_ERR(*status = share_sanity_checks(snum, dev))) {
274 return NULL;
277 conn = conn_new();
278 if (!conn) {
279 DEBUG(0,("Couldn't find free connection.\n"));
280 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
281 return NULL;
284 if (lp_guest_only(snum)) {
285 const char *guestname = lp_guestaccount();
286 guest = True;
287 pass = getpwnam_alloc(guestname);
288 if (!pass) {
289 DEBUG(0,("make_connection_snum: Invalid guest account %s??\n",guestname));
290 conn_free(conn);
291 *status = NT_STATUS_NO_SUCH_USER;
292 return NULL;
294 fstrcpy(user,pass->pw_name);
295 conn->force_user = True;
296 conn->uid = pass->pw_uid;
297 conn->gid = pass->pw_gid;
298 string_set(&conn->user,pass->pw_name);
299 passwd_free(&pass);
300 DEBUG(3,("Guest only user %s\n",user));
301 } else if (vuser) {
302 if (vuser->guest) {
303 if (!lp_guest_ok(snum)) {
304 DEBUG(2, ("guest user (from session setup) not permitted to access this share (%s)\n", lp_servicename(snum)));
305 conn_free(conn);
306 *status = NT_STATUS_ACCESS_DENIED;
307 return NULL;
309 } else {
310 if (!user_ok(vuser->user.unix_name, snum, vuser->groups, vuser->n_groups)) {
311 DEBUG(2, ("user '%s' (from session setup) not permitted to access this share (%s)\n", vuser->user.unix_name, lp_servicename(snum)));
312 conn_free(conn);
313 *status = NT_STATUS_ACCESS_DENIED;
314 return NULL;
317 conn->vuid = vuser->vuid;
318 conn->uid = vuser->uid;
319 conn->gid = vuser->gid;
320 string_set(&conn->user,vuser->user.unix_name);
321 fstrcpy(user,vuser->user.unix_name);
322 guest = vuser->guest;
323 } else if (lp_security() == SEC_SHARE) {
324 /* add it as a possible user name if we
325 are in share mode security */
326 add_session_user(lp_servicename(snum));
327 /* shall we let them in? */
328 if (!authorise_login(snum,user,password,&guest)) {
329 DEBUG( 2, ( "Invalid username/password for [%s]\n",
330 lp_servicename(snum)) );
331 conn_free(conn);
332 *status = NT_STATUS_WRONG_PASSWORD;
333 return NULL;
335 pass = Get_Pwnam(user);
336 conn->force_user = True;
337 conn->uid = pass->pw_uid;
338 conn->gid = pass->pw_gid;
339 string_set(&conn->user, pass->pw_name);
340 fstrcpy(user, pass->pw_name);
342 } else {
343 DEBUG(0, ("invalid VUID (vuser) but not in security=share\n"));
344 conn_free(conn);
345 *status = NT_STATUS_ACCESS_DENIED;
346 return NULL;
349 add_session_user(user);
351 safe_strcpy(conn->client_address, client_addr(),
352 sizeof(conn->client_address)-1);
353 conn->num_files_open = 0;
354 conn->lastused = time(NULL);
355 conn->service = snum;
356 conn->used = True;
357 conn->printer = (strncmp(dev,"LPT",3) == 0);
358 conn->ipc = ((strncmp(dev,"IPC",3) == 0) || strequal(dev,"ADMIN$"));
359 conn->dirptr = NULL;
360 conn->veto_list = NULL;
361 conn->hide_list = NULL;
362 conn->veto_oplock_list = NULL;
363 string_set(&conn->dirpath,"");
364 string_set(&conn->user,user);
365 conn->nt_user_token = NULL;
366 conn->privs = NULL;
368 conn->read_only = lp_readonly(conn->service);
369 conn->admin_user = False;
372 * If force user is true, then store the
373 * given userid and also the groups
374 * of the user we're forcing.
377 if (*lp_force_user(snum)) {
378 struct passwd *pass2;
379 pstring fuser;
380 pstrcpy(fuser,lp_force_user(snum));
382 /* Allow %S to be used by force user. */
383 pstring_sub(fuser,"%S",lp_servicename(snum));
385 pass2 = (struct passwd *)Get_Pwnam(fuser);
386 if (pass2) {
387 conn->uid = pass2->pw_uid;
388 conn->gid = pass2->pw_gid;
389 string_set(&conn->user,pass2->pw_name);
390 fstrcpy(user,pass2->pw_name);
391 conn->force_user = True;
392 DEBUG(3,("Forced user %s\n",user));
393 } else {
394 DEBUG(1,("Couldn't find user %s\n",fuser));
395 conn_free(conn);
396 *status = NT_STATUS_NO_SUCH_USER;
397 return NULL;
401 #ifdef HAVE_GETGRNAM
403 * If force group is true, then override
404 * any groupid stored for the connecting user.
407 if (*lp_force_group(snum)) {
408 gid_t gid;
409 pstring gname;
410 pstring tmp_gname;
411 BOOL user_must_be_member = False;
413 pstrcpy(tmp_gname,lp_force_group(snum));
415 if (tmp_gname[0] == '+') {
416 user_must_be_member = True;
417 /* even now, tmp_gname is null terminated */
418 pstrcpy(gname,&tmp_gname[1]);
419 } else {
420 pstrcpy(gname,tmp_gname);
422 /* default service may be a group name */
423 pstring_sub(gname,"%S",lp_servicename(snum));
424 gid = nametogid(gname);
426 if (gid != (gid_t)-1) {
429 * If the user has been forced and the forced group starts
430 * with a '+', then we only set the group to be the forced
431 * group if the forced user is a member of that group.
432 * Otherwise, the meaning of the '+' would be ignored.
434 if (conn->force_user && user_must_be_member) {
435 if (user_in_group_list( user, gname, NULL, 0)) {
436 conn->gid = gid;
437 DEBUG(3,("Forced group %s for member %s\n",gname,user));
439 } else {
440 conn->gid = gid;
441 DEBUG(3,("Forced group %s\n",gname));
443 conn->force_group = True;
444 } else {
445 DEBUG(1,("Couldn't find group %s\n",gname));
446 conn_free(conn);
447 *status = NT_STATUS_NO_SUCH_GROUP;
448 return NULL;
451 #endif /* HAVE_GETGRNAM */
454 pstring s;
455 pstrcpy(s,lp_pathname(snum));
456 standard_sub_conn(conn,s,sizeof(s));
457 string_set(&conn->connectpath,s);
458 DEBUG(3,("Connect path is '%s' for service [%s]\n",s, lp_servicename(snum)));
461 if (conn->force_user || conn->force_group) {
463 /* groups stuff added by ih */
464 conn->ngroups = 0;
465 conn->groups = NULL;
467 /* Find all the groups this uid is in and
468 store them. Used by change_to_user() */
469 initialise_groups(conn->user, conn->uid, conn->gid);
470 get_current_groups(conn->gid, &conn->ngroups,&conn->groups);
472 conn->nt_user_token = create_nt_token(conn->uid, conn->gid,
473 conn->ngroups, conn->groups,
474 guest);
476 init_privilege(&(conn->privs));
477 pdb_get_privilege_set(conn->nt_user_token->user_sids, conn->nt_user_token->num_sids, conn->privs);
481 * New code to check if there's a share security descripter
482 * added from NT server manager. This is done after the
483 * smb.conf checks are done as we need a uid and token. JRA.
488 BOOL can_write = share_access_check(conn, snum, vuser, FILE_WRITE_DATA);
490 if (!can_write) {
491 if (!share_access_check(conn, snum, vuser, FILE_READ_DATA)) {
492 /* No access, read or write. */
493 DEBUG(0,( "make_connection: connection to %s denied due to security descriptor.\n",
494 lp_servicename(snum)));
495 conn_free(conn);
496 *status = NT_STATUS_ACCESS_DENIED;
497 return NULL;
498 } else {
499 conn->read_only = True;
503 /* Initialise VFS function pointers */
505 if (!smbd_vfs_init(conn)) {
506 DEBUG(0, ("vfs_init failed for service %s\n", lp_servicename(SNUM(conn))));
507 conn_free(conn);
508 *status = NT_STATUS_BAD_NETWORK_NAME;
509 return NULL;
512 /* ROOT Activities: */
513 /* check number of connections */
514 if (!claim_connection(conn,
515 lp_servicename(SNUM(conn)),
516 lp_max_connections(SNUM(conn)),
517 False,0)) {
518 DEBUG(1,("too many connections - rejected\n"));
519 conn_free(conn);
520 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
521 return NULL;
524 /* Preexecs are done here as they might make the dir we are to ChDir to below */
525 /* execute any "root preexec = " line */
526 if (*lp_rootpreexec(SNUM(conn))) {
527 int ret;
528 pstring cmd;
529 pstrcpy(cmd,lp_rootpreexec(SNUM(conn)));
530 standard_sub_conn(conn,cmd,sizeof(cmd));
531 DEBUG(5,("cmd=%s\n",cmd));
532 ret = smbrun(cmd,NULL);
533 if (ret != 0 && lp_rootpreexec_close(SNUM(conn))) {
534 DEBUG(1,("root preexec gave %d - failing connection\n", ret));
535 yield_connection(conn, lp_servicename(SNUM(conn)));
536 conn_free(conn);
537 *status = NT_STATUS_ACCESS_DENIED;
538 return NULL;
542 /* USER Activites: */
543 if (!change_to_user(conn, conn->vuid)) {
544 /* No point continuing if they fail the basic checks */
545 DEBUG(0,("Can't become connected user!\n"));
546 conn_free(conn);
547 *status = NT_STATUS_LOGON_FAILURE;
548 return NULL;
551 /* Remember that a different vuid can connect later without these checks... */
553 /* Preexecs are done here as they might make the dir we are to ChDir to below */
554 /* execute any "preexec = " line */
555 if (*lp_preexec(SNUM(conn))) {
556 int ret;
557 pstring cmd;
558 pstrcpy(cmd,lp_preexec(SNUM(conn)));
559 standard_sub_conn(conn,cmd,sizeof(cmd));
560 ret = smbrun(cmd,NULL);
561 if (ret != 0 && lp_preexec_close(SNUM(conn))) {
562 DEBUG(1,("preexec gave %d - failing connection\n", ret));
563 change_to_root_user();
564 yield_connection(conn, lp_servicename(SNUM(conn)));
565 conn_free(conn);
566 *status = NT_STATUS_ACCESS_DENIED;
567 return NULL;
571 #ifdef WITH_FAKE_KASERVER
572 if (lp_afs_share(SNUM(conn))) {
573 afs_login(conn);
575 #endif
577 #if CHECK_PATH_ON_TCONX
578 /* win2000 does not check the permissions on the directory
579 during the tree connect, instead relying on permission
580 check during individual operations. To match this behaviour
581 I have disabled this chdir check (tridge) */
582 if (vfs_ChDir(conn,conn->connectpath) != 0) {
583 DEBUG(0,("%s (%s) Can't change directory to %s (%s)\n",
584 get_remote_machine_name(), conn->client_address,
585 conn->connectpath,strerror(errno)));
586 change_to_root_user();
587 yield_connection(conn, lp_servicename(SNUM(conn)));
588 conn_free(conn);
589 *status = NT_STATUS_BAD_NETWORK_NAME;
590 return NULL;
592 #else
593 /* the alternative is just to check the directory exists */
594 if (stat(conn->connectpath, &st) != 0 || !S_ISDIR(st.st_mode)) {
595 DEBUG(0,("'%s' does not exist or is not a directory, when connecting to [%s]\n", conn->connectpath, lp_servicename(SNUM(conn))));
596 change_to_root_user();
597 yield_connection(conn, lp_servicename(SNUM(conn)));
598 conn_free(conn);
599 *status = NT_STATUS_BAD_NETWORK_NAME;
600 return NULL;
602 #endif
604 string_set(&conn->origpath,conn->connectpath);
606 #if SOFTLINK_OPTIMISATION
607 /* resolve any soft links early if possible */
608 if (vfs_ChDir(conn,conn->connectpath) == 0) {
609 pstring s;
610 pstrcpy(s,conn->connectpath);
611 vfs_GetWd(conn,s);
612 string_set(&conn->connectpath,s);
613 vfs_ChDir(conn,conn->connectpath);
615 #endif
618 * Print out the 'connected as' stuff here as we need
619 * to know the effective uid and gid we will be using
620 * (at least initially).
623 if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
624 dbgtext( "%s (%s) ", get_remote_machine_name(), conn->client_address );
625 dbgtext( "%s", srv_is_signing_active() ? "signed " : "");
626 dbgtext( "connect to service %s ", lp_servicename(SNUM(conn)) );
627 dbgtext( "initially as user %s ", user );
628 dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
629 dbgtext( "(pid %d)\n", (int)sys_getpid() );
632 /* Add veto/hide lists */
633 if (!IS_IPC(conn) && !IS_PRINT(conn)) {
634 set_namearray( &conn->veto_list, lp_veto_files(SNUM(conn)));
635 set_namearray( &conn->hide_list, lp_hide_files(SNUM(conn)));
636 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(SNUM(conn)));
639 /* Invoke VFS make connection hook */
641 if (SMB_VFS_CONNECT(conn, lp_servicename(snum), user) < 0) {
642 DEBUG(0,("make_connection: VFS make connection failed!\n"));
643 change_to_root_user();
644 conn_free(conn);
645 *status = NT_STATUS_UNSUCCESSFUL;
646 return NULL;
649 /* we've finished with the user stuff - go back to root */
650 change_to_root_user();
652 return(conn);
655 /***************************************************************************************
656 Simple wrapper function for make_connection() to include a call to
657 vfs_chdir()
658 **************************************************************************************/
660 connection_struct *make_connection_with_chdir(const char *service_in, DATA_BLOB password,
661 const char *dev, uint16 vuid, NTSTATUS *status)
663 connection_struct *conn = NULL;
665 conn = make_connection(service_in, password, dev, vuid, status);
668 * make_connection() does not change the directory for us any more
669 * so we have to do it as a separate step --jerry
672 if ( conn && vfs_ChDir(conn,conn->connectpath) != 0 ) {
673 DEBUG(0,("move_driver_to_download_area: Can't change directory to %s for [print$] (%s)\n",
674 conn->connectpath,strerror(errno)));
675 yield_connection(conn, lp_servicename(SNUM(conn)));
676 conn_free(conn);
677 *status = NT_STATUS_UNSUCCESSFUL;
678 return NULL;
681 return conn;
684 /****************************************************************************
685 Make a connection to a service.
687 * @param service
688 ****************************************************************************/
690 connection_struct *make_connection(const char *service_in, DATA_BLOB password,
691 const char *pdev, uint16 vuid, NTSTATUS *status)
693 uid_t euid;
694 user_struct *vuser = NULL;
695 fstring service;
696 fstring dev;
697 int snum = -1;
699 fstrcpy(dev, pdev);
701 /* This must ONLY BE CALLED AS ROOT. As it exits this function as root. */
702 if (!non_root_mode() && (euid = geteuid()) != 0) {
703 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot (%u)\n", (unsigned int)euid ));
704 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
707 if(lp_security() != SEC_SHARE) {
708 vuser = get_valid_user_struct(vuid);
709 if (!vuser) {
710 DEBUG(1,("make_connection: refusing to connect with no session setup\n"));
711 *status = NT_STATUS_ACCESS_DENIED;
712 return NULL;
716 /* Logic to try and connect to the correct [homes] share, preferably without too many
717 getpwnam() lookups. This is particulary nasty for winbind usernames, where the
718 share name isn't the same as unix username.
720 The snum of the homes share is stored on the vuser at session setup time.
723 if (strequal(service_in,HOMES_NAME)) {
724 if(lp_security() != SEC_SHARE) {
725 DATA_BLOB no_pw = data_blob(NULL, 0);
726 if (vuser->homes_snum == -1) {
727 DEBUG(2, ("[homes] share not available for this user because it was not found or created at session setup time\n"));
728 *status = NT_STATUS_BAD_NETWORK_NAME;
729 return NULL;
731 DEBUG(5, ("making a connection to [homes] service created at session setup time\n"));
732 return make_connection_snum(vuser->homes_snum,
733 vuser, no_pw,
734 dev, status);
735 } else {
736 /* Security = share. Try with current_user_info.smb_name
737 * as the username. */
738 if (*current_user_info.smb_name) {
739 fstring unix_username;
740 fstrcpy(unix_username,
741 current_user_info.smb_name);
742 map_username(unix_username);
743 snum = find_service(unix_username);
745 if (snum != -1) {
746 DEBUG(5, ("making a connection to 'homes' service %s based on security=share\n", service_in));
747 return make_connection_snum(snum, NULL,
748 password,
749 dev, status);
752 } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
753 && strequal(service_in, lp_servicename(vuser->homes_snum))) {
754 DATA_BLOB no_pw = data_blob(NULL, 0);
755 DEBUG(5, ("making a connection to 'homes' service [%s] created at session setup time\n", service_in));
756 return make_connection_snum(vuser->homes_snum,
757 vuser, no_pw,
758 dev, status);
761 fstrcpy(service, service_in);
763 strlower_m(service);
765 snum = find_service(service);
767 if (snum < 0) {
768 if (strequal(service,"IPC$") || strequal(service,"ADMIN$")) {
769 DEBUG(3,("refusing IPC connection to %s\n", service));
770 *status = NT_STATUS_ACCESS_DENIED;
771 return NULL;
774 DEBUG(0,("%s (%s) couldn't find service %s\n",
775 get_remote_machine_name(), client_addr(), service));
776 *status = NT_STATUS_BAD_NETWORK_NAME;
777 return NULL;
780 /* Handle non-Dfs clients attempting connections to msdfs proxy */
781 if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0')) {
782 DEBUG(3, ("refusing connection to dfs proxy '%s'\n", service));
783 *status = NT_STATUS_BAD_NETWORK_NAME;
784 return NULL;
787 DEBUG(5, ("making a connection to 'normal' service %s\n", service));
789 return make_connection_snum(snum, vuser,
790 password,
791 dev, status);
794 /****************************************************************************
795 close a cnum
796 ****************************************************************************/
797 void close_cnum(connection_struct *conn, uint16 vuid)
799 DirCacheFlush(SNUM(conn));
801 change_to_root_user();
803 DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
804 get_remote_machine_name(),conn->client_address,
805 lp_servicename(SNUM(conn))));
807 /* Call VFS disconnect hook */
808 SMB_VFS_DISCONNECT(conn);
810 yield_connection(conn, lp_servicename(SNUM(conn)));
812 file_close_conn(conn);
813 dptr_closecnum(conn);
815 /* make sure we leave the directory available for unmount */
816 vfs_ChDir(conn, "/");
818 /* execute any "postexec = " line */
819 if (*lp_postexec(SNUM(conn)) &&
820 change_to_user(conn, vuid)) {
821 pstring cmd;
822 pstrcpy(cmd,lp_postexec(SNUM(conn)));
823 standard_sub_conn(conn,cmd,sizeof(cmd));
824 smbrun(cmd,NULL);
825 change_to_root_user();
828 change_to_root_user();
829 /* execute any "root postexec = " line */
830 if (*lp_rootpostexec(SNUM(conn))) {
831 pstring cmd;
832 pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
833 standard_sub_conn(conn,cmd,sizeof(cmd));
834 smbrun(cmd,NULL);
837 conn_free(conn);