r4904: sync up with 3.0 for 3.0.11pre2
[Samba.git] / source / smbd / service.c
blob2e60adc63663d2454afc72e7c1ec6094c3096ef1
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 userdom_struct current_user_info;
27 /****************************************************************************
28 Load parameters specific to a connection/service.
29 ****************************************************************************/
31 BOOL set_current_service(connection_struct *conn, uint16 flags, BOOL do_chdir)
33 extern char magic_char;
34 static connection_struct *last_conn;
35 static uint16 last_flags;
36 int snum;
38 if (!conn) {
39 last_conn = NULL;
40 return(False);
43 conn->lastused = smb_last_time.tv_sec;
45 snum = SNUM(conn);
47 if (do_chdir &&
48 vfs_ChDir(conn,conn->connectpath) != 0 &&
49 vfs_ChDir(conn,conn->origpath) != 0) {
50 DEBUG(0,("chdir (%s) failed\n",
51 conn->connectpath));
52 return(False);
55 if ((conn == last_conn) && (last_flags == flags)) {
56 return(True);
59 last_conn = conn;
60 last_flags = flags;
62 /* Obey the client case sensitivity requests - only for clients that support it. */
63 if (lp_casesensitive(snum) == Auto) {
64 /* We need this uglyness due to DOS/Win9x clients that lie about case insensitivity. */
65 enum remote_arch_types ra_type = get_remote_arch();
66 if ((ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
67 /* Client can't support per-packet case sensitive pathnames. */
68 conn->case_sensitive = False;
69 } else {
70 conn->case_sensitive = !(flags & FLAG_CASELESS_PATHNAMES);
74 magic_char = lp_magicchar(snum);
75 return(True);
78 /****************************************************************************
79 Add a home service. Returns the new service number or -1 if fail.
80 ****************************************************************************/
82 int add_home_service(const char *service, const char *username, const char *homedir)
84 int iHomeService;
86 if (!service || !homedir)
87 return -1;
89 if ((iHomeService = lp_servicenumber(HOMES_NAME)) < 0)
90 return -1;
93 * If this is a winbindd provided username, remove
94 * the domain component before adding the service.
95 * Log a warning if the "path=" parameter does not
96 * include any macros.
100 const char *p = strchr(service,*lp_winbind_separator());
102 /* We only want the 'user' part of the string */
103 if (p) {
104 service = p + 1;
108 if (!lp_add_home(service, iHomeService, username, homedir)) {
109 return -1;
112 return lp_servicenumber(service);
118 * Find a service entry.
120 * @param service is modified (to canonical form??)
123 int find_service(fstring service)
125 int iService;
127 all_string_sub(service,"\\","/",0);
129 iService = lp_servicenumber(service);
131 /* now handle the special case of a home directory */
132 if (iService < 0) {
133 char *phome_dir = get_user_home_dir(service);
135 if(!phome_dir) {
137 * Try mapping the servicename, it may
138 * be a Windows to unix mapped user name.
140 if(map_username(service))
141 phome_dir = get_user_home_dir(service);
144 DEBUG(3,("checking for home directory %s gave %s\n",service,
145 phome_dir?phome_dir:"(NULL)"));
147 iService = add_home_service(service,service /* 'username' */, phome_dir);
150 /* If we still don't have a service, attempt to add it as a printer. */
151 if (iService < 0) {
152 int iPrinterService;
154 if ((iPrinterService = lp_servicenumber(PRINTERS_NAME)) >= 0) {
155 DEBUG(3,("checking whether %s is a valid printer name...\n", service));
156 if (pcap_printername_ok(service)) {
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;
361 /* Case options for the share. */
362 if (lp_casesensitive(snum) == Auto) {
363 /* We will be setting this per packet. Set to be case insensitive for now. */
364 conn->case_sensitive = False;
365 } else {
366 conn->case_sensitive = (BOOL)lp_casesensitive(snum);
369 conn->case_preserve = lp_preservecase(snum);
370 conn->short_case_preserve = lp_shortpreservecase(snum);
372 conn->veto_list = NULL;
373 conn->hide_list = NULL;
374 conn->veto_oplock_list = NULL;
375 string_set(&conn->dirpath,"");
376 string_set(&conn->user,user);
377 conn->nt_user_token = NULL;
379 conn->read_only = lp_readonly(conn->service);
380 conn->admin_user = False;
383 * If force user is true, then store the
384 * given userid and also the groups
385 * of the user we're forcing.
388 if (*lp_force_user(snum)) {
389 struct passwd *pass2;
390 pstring fuser;
391 pstrcpy(fuser,lp_force_user(snum));
393 /* Allow %S to be used by force user. */
394 pstring_sub(fuser,"%S",lp_servicename(snum));
396 pass2 = (struct passwd *)Get_Pwnam(fuser);
397 if (pass2) {
398 conn->uid = pass2->pw_uid;
399 conn->gid = pass2->pw_gid;
400 string_set(&conn->user,pass2->pw_name);
401 fstrcpy(user,pass2->pw_name);
402 conn->force_user = True;
403 DEBUG(3,("Forced user %s\n",user));
404 } else {
405 DEBUG(1,("Couldn't find user %s\n",fuser));
406 conn_free(conn);
407 *status = NT_STATUS_NO_SUCH_USER;
408 return NULL;
412 #ifdef HAVE_GETGRNAM
414 * If force group is true, then override
415 * any groupid stored for the connecting user.
418 if (*lp_force_group(snum)) {
419 gid_t gid;
420 pstring gname;
421 pstring tmp_gname;
422 BOOL user_must_be_member = False;
424 pstrcpy(tmp_gname,lp_force_group(snum));
426 if (tmp_gname[0] == '+') {
427 user_must_be_member = True;
428 /* even now, tmp_gname is null terminated */
429 pstrcpy(gname,&tmp_gname[1]);
430 } else {
431 pstrcpy(gname,tmp_gname);
433 /* default service may be a group name */
434 pstring_sub(gname,"%S",lp_servicename(snum));
435 gid = nametogid(gname);
437 if (gid != (gid_t)-1) {
440 * If the user has been forced and the forced group starts
441 * with a '+', then we only set the group to be the forced
442 * group if the forced user is a member of that group.
443 * Otherwise, the meaning of the '+' would be ignored.
445 if (conn->force_user && user_must_be_member) {
446 if (user_in_group_list( user, gname, NULL, 0)) {
447 conn->gid = gid;
448 DEBUG(3,("Forced group %s for member %s\n",gname,user));
450 } else {
451 conn->gid = gid;
452 DEBUG(3,("Forced group %s\n",gname));
454 conn->force_group = True;
455 } else {
456 DEBUG(1,("Couldn't find group %s\n",gname));
457 conn_free(conn);
458 *status = NT_STATUS_NO_SUCH_GROUP;
459 return NULL;
462 #endif /* HAVE_GETGRNAM */
465 pstring s;
466 pstrcpy(s,lp_pathname(snum));
467 standard_sub_conn(conn,s,sizeof(s));
468 string_set(&conn->connectpath,s);
469 DEBUG(3,("Connect path is '%s' for service [%s]\n",s, lp_servicename(snum)));
472 if (conn->force_user || conn->force_group) {
474 /* groups stuff added by ih */
475 conn->ngroups = 0;
476 conn->groups = NULL;
478 /* Find all the groups this uid is in and
479 store them. Used by change_to_user() */
480 initialise_groups(conn->user, conn->uid, conn->gid);
481 get_current_groups(conn->gid, &conn->ngroups,&conn->groups);
483 conn->nt_user_token = create_nt_token(conn->uid, conn->gid,
484 conn->ngroups, conn->groups,
485 guest);
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.
496 BOOL can_write = share_access_check(conn, snum, vuser, FILE_WRITE_DATA);
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;
511 /* Initialise VFS function pointers */
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;
521 * If widelinks are disallowed we need to canonicalise the
522 * connect path here to ensure we don't have any symlinks in
523 * the connectpath. We will be checking all paths on this
524 * connection are below this directory. We must do this after
525 * the VFS init as we depend on the realpath() pointer in the vfs table. JRA.
527 if (!lp_widelinks(snum)) {
528 pstring s;
529 pstrcpy(s,conn->connectpath);
530 canonicalize_path(conn, s);
531 string_set(&conn->connectpath,s);
534 /* ROOT Activities: */
535 /* check number of connections */
536 if (!claim_connection(conn,
537 lp_servicename(SNUM(conn)),
538 lp_max_connections(SNUM(conn)),
539 False,0)) {
540 DEBUG(1,("too many connections - rejected\n"));
541 conn_free(conn);
542 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
543 return NULL;
546 /* Preexecs are done here as they might make the dir we are to ChDir to below */
547 /* execute any "root preexec = " line */
548 if (*lp_rootpreexec(SNUM(conn))) {
549 int ret;
550 pstring cmd;
551 pstrcpy(cmd,lp_rootpreexec(SNUM(conn)));
552 standard_sub_conn(conn,cmd,sizeof(cmd));
553 DEBUG(5,("cmd=%s\n",cmd));
554 ret = smbrun(cmd,NULL);
555 if (ret != 0 && lp_rootpreexec_close(SNUM(conn))) {
556 DEBUG(1,("root preexec gave %d - failing connection\n", ret));
557 yield_connection(conn, lp_servicename(SNUM(conn)));
558 conn_free(conn);
559 *status = NT_STATUS_ACCESS_DENIED;
560 return NULL;
564 /* USER Activites: */
565 if (!change_to_user(conn, conn->vuid)) {
566 /* No point continuing if they fail the basic checks */
567 DEBUG(0,("Can't become connected user!\n"));
568 conn_free(conn);
569 *status = NT_STATUS_LOGON_FAILURE;
570 return NULL;
573 /* Remember that a different vuid can connect later without these checks... */
575 /* Preexecs are done here as they might make the dir we are to ChDir to below */
576 /* execute any "preexec = " line */
577 if (*lp_preexec(SNUM(conn))) {
578 int ret;
579 pstring cmd;
580 pstrcpy(cmd,lp_preexec(SNUM(conn)));
581 standard_sub_conn(conn,cmd,sizeof(cmd));
582 ret = smbrun(cmd,NULL);
583 if (ret != 0 && lp_preexec_close(SNUM(conn))) {
584 DEBUG(1,("preexec gave %d - failing connection\n", ret));
585 change_to_root_user();
586 yield_connection(conn, lp_servicename(SNUM(conn)));
587 conn_free(conn);
588 *status = NT_STATUS_ACCESS_DENIED;
589 return NULL;
593 #ifdef WITH_FAKE_KASERVER
594 if (lp_afs_share(SNUM(conn))) {
595 afs_login(conn);
597 #endif
599 #if CHECK_PATH_ON_TCONX
600 /* win2000 does not check the permissions on the directory
601 during the tree connect, instead relying on permission
602 check during individual operations. To match this behaviour
603 I have disabled this chdir check (tridge) */
604 if (vfs_ChDir(conn,conn->connectpath) != 0) {
605 DEBUG(0,("%s (%s) Can't change directory to %s (%s)\n",
606 get_remote_machine_name(), conn->client_address,
607 conn->connectpath,strerror(errno)));
608 change_to_root_user();
609 yield_connection(conn, lp_servicename(SNUM(conn)));
610 conn_free(conn);
611 *status = NT_STATUS_BAD_NETWORK_NAME;
612 return NULL;
614 #else
615 /* the alternative is just to check the directory exists */
616 if (stat(conn->connectpath, &st) != 0 || !S_ISDIR(st.st_mode)) {
617 DEBUG(0,("'%s' does not exist or is not a directory, when connecting to [%s]\n", conn->connectpath, lp_servicename(SNUM(conn))));
618 change_to_root_user();
619 yield_connection(conn, lp_servicename(SNUM(conn)));
620 conn_free(conn);
621 *status = NT_STATUS_BAD_NETWORK_NAME;
622 return NULL;
624 #endif
626 string_set(&conn->origpath,conn->connectpath);
628 #if SOFTLINK_OPTIMISATION
629 /* resolve any soft links early if possible */
630 if (vfs_ChDir(conn,conn->connectpath) == 0) {
631 pstring s;
632 pstrcpy(s,conn->connectpath);
633 vfs_GetWd(conn,s);
634 string_set(&conn->connectpath,s);
635 vfs_ChDir(conn,conn->connectpath);
637 #endif
640 * Print out the 'connected as' stuff here as we need
641 * to know the effective uid and gid we will be using
642 * (at least initially).
645 if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
646 dbgtext( "%s (%s) ", get_remote_machine_name(), conn->client_address );
647 dbgtext( "%s", srv_is_signing_active() ? "signed " : "");
648 dbgtext( "connect to service %s ", lp_servicename(SNUM(conn)) );
649 dbgtext( "initially as user %s ", user );
650 dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
651 dbgtext( "(pid %d)\n", (int)sys_getpid() );
654 /* Add veto/hide lists */
655 if (!IS_IPC(conn) && !IS_PRINT(conn)) {
656 set_namearray( &conn->veto_list, lp_veto_files(SNUM(conn)));
657 set_namearray( &conn->hide_list, lp_hide_files(SNUM(conn)));
658 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(SNUM(conn)));
661 /* Invoke VFS make connection hook */
663 if (SMB_VFS_CONNECT(conn, lp_servicename(snum), user) < 0) {
664 DEBUG(0,("make_connection: VFS make connection failed!\n"));
665 change_to_root_user();
666 conn_free(conn);
667 *status = NT_STATUS_UNSUCCESSFUL;
668 return NULL;
671 /* we've finished with the user stuff - go back to root */
672 change_to_root_user();
674 return(conn);
677 /***************************************************************************************
678 Simple wrapper function for make_connection() to include a call to
679 vfs_chdir()
680 **************************************************************************************/
682 connection_struct *make_connection_with_chdir(const char *service_in, DATA_BLOB password,
683 const char *dev, uint16 vuid, NTSTATUS *status)
685 connection_struct *conn = NULL;
687 conn = make_connection(service_in, password, dev, vuid, status);
690 * make_connection() does not change the directory for us any more
691 * so we have to do it as a separate step --jerry
694 if ( conn && vfs_ChDir(conn,conn->connectpath) != 0 ) {
695 DEBUG(0,("move_driver_to_download_area: Can't change directory to %s for [print$] (%s)\n",
696 conn->connectpath,strerror(errno)));
697 yield_connection(conn, lp_servicename(SNUM(conn)));
698 conn_free(conn);
699 *status = NT_STATUS_UNSUCCESSFUL;
700 return NULL;
703 return conn;
706 /****************************************************************************
707 Make a connection to a service.
709 * @param service
710 ****************************************************************************/
712 connection_struct *make_connection(const char *service_in, DATA_BLOB password,
713 const char *pdev, uint16 vuid, NTSTATUS *status)
715 uid_t euid;
716 user_struct *vuser = NULL;
717 fstring service;
718 fstring dev;
719 int snum = -1;
721 fstrcpy(dev, pdev);
723 /* This must ONLY BE CALLED AS ROOT. As it exits this function as root. */
724 if (!non_root_mode() && (euid = geteuid()) != 0) {
725 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot (%u)\n", (unsigned int)euid ));
726 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
729 if(lp_security() != SEC_SHARE) {
730 vuser = get_valid_user_struct(vuid);
731 if (!vuser) {
732 DEBUG(1,("make_connection: refusing to connect with no session setup\n"));
733 *status = NT_STATUS_ACCESS_DENIED;
734 return NULL;
738 /* Logic to try and connect to the correct [homes] share, preferably without too many
739 getpwnam() lookups. This is particulary nasty for winbind usernames, where the
740 share name isn't the same as unix username.
742 The snum of the homes share is stored on the vuser at session setup time.
745 if (strequal(service_in,HOMES_NAME)) {
746 if(lp_security() != SEC_SHARE) {
747 DATA_BLOB no_pw = data_blob(NULL, 0);
748 if (vuser->homes_snum == -1) {
749 DEBUG(2, ("[homes] share not available for this user because it was not found or created at session setup time\n"));
750 *status = NT_STATUS_BAD_NETWORK_NAME;
751 return NULL;
753 DEBUG(5, ("making a connection to [homes] service created at session setup time\n"));
754 return make_connection_snum(vuser->homes_snum,
755 vuser, no_pw,
756 dev, status);
757 } else {
758 /* Security = share. Try with current_user_info.smb_name
759 * as the username. */
760 if (*current_user_info.smb_name) {
761 fstring unix_username;
762 fstrcpy(unix_username,
763 current_user_info.smb_name);
764 map_username(unix_username);
765 snum = find_service(unix_username);
767 if (snum != -1) {
768 DEBUG(5, ("making a connection to 'homes' service %s based on security=share\n", service_in));
769 return make_connection_snum(snum, NULL,
770 password,
771 dev, status);
774 } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
775 && strequal(service_in, lp_servicename(vuser->homes_snum))) {
776 DATA_BLOB no_pw = data_blob(NULL, 0);
777 DEBUG(5, ("making a connection to 'homes' service [%s] created at session setup time\n", service_in));
778 return make_connection_snum(vuser->homes_snum,
779 vuser, no_pw,
780 dev, status);
783 fstrcpy(service, service_in);
785 strlower_m(service);
787 snum = find_service(service);
789 if (snum < 0) {
790 if (strequal(service,"IPC$") || strequal(service,"ADMIN$")) {
791 DEBUG(3,("refusing IPC connection to %s\n", service));
792 *status = NT_STATUS_ACCESS_DENIED;
793 return NULL;
796 DEBUG(0,("%s (%s) couldn't find service %s\n",
797 get_remote_machine_name(), client_addr(), service));
798 *status = NT_STATUS_BAD_NETWORK_NAME;
799 return NULL;
802 /* Handle non-Dfs clients attempting connections to msdfs proxy */
803 if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0')) {
804 DEBUG(3, ("refusing connection to dfs proxy share '%s' (pointing to %s)\n",
805 service, lp_msdfs_proxy(snum)));
806 *status = NT_STATUS_BAD_NETWORK_NAME;
807 return NULL;
810 DEBUG(5, ("making a connection to 'normal' service %s\n", service));
812 return make_connection_snum(snum, vuser,
813 password,
814 dev, status);
817 /****************************************************************************
818 close a cnum
819 ****************************************************************************/
820 void close_cnum(connection_struct *conn, uint16 vuid)
822 if (IS_IPC(conn)) {
823 pipe_close_conn(conn);
824 } else {
825 file_close_conn(conn);
826 dptr_closecnum(conn);
829 change_to_root_user();
831 DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
832 get_remote_machine_name(),conn->client_address,
833 lp_servicename(SNUM(conn))));
835 /* Call VFS disconnect hook */
836 SMB_VFS_DISCONNECT(conn);
838 yield_connection(conn, lp_servicename(SNUM(conn)));
840 /* make sure we leave the directory available for unmount */
841 vfs_ChDir(conn, "/");
843 /* execute any "postexec = " line */
844 if (*lp_postexec(SNUM(conn)) &&
845 change_to_user(conn, vuid)) {
846 pstring cmd;
847 pstrcpy(cmd,lp_postexec(SNUM(conn)));
848 standard_sub_conn(conn,cmd,sizeof(cmd));
849 smbrun(cmd,NULL);
850 change_to_root_user();
853 change_to_root_user();
854 /* execute any "root postexec = " line */
855 if (*lp_rootpostexec(SNUM(conn))) {
856 pstring cmd;
857 pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
858 standard_sub_conn(conn,cmd,sizeof(cmd));
859 smbrun(cmd,NULL);
862 conn_free(conn);