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.
23 extern struct timeval smb_last_time;
24 extern userdom_struct current_user_info;
26 /****************************************************************************
27 Load parameters specific to a connection/service.
28 ****************************************************************************/
30 BOOL set_current_service(connection_struct *conn, uint16 flags, BOOL do_chdir)
32 static connection_struct *last_conn;
33 static uint16 last_flags;
41 conn->lastused = smb_last_time.tv_sec;
46 vfs_ChDir(conn,conn->connectpath) != 0 &&
47 vfs_ChDir(conn,conn->origpath) != 0) {
48 DEBUG(0,("chdir (%s) failed\n",
53 if ((conn == last_conn) && (last_flags == flags)) {
60 /* Obey the client case sensitivity requests - only for clients that support it. */
61 switch (lp_casesensitive(snum)) {
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;
70 conn->case_sensitive = !(flags & FLAG_CASELESS_PATHNAMES);
75 conn->case_sensitive = True;
78 conn->case_sensitive = False;
84 /****************************************************************************
85 Add a home service. Returns the new service number or -1 if fail.
86 ****************************************************************************/
88 int add_home_service(const char *service, const char *username, const char *homedir)
92 if (!service || !homedir)
95 if ((iHomeService = lp_servicenumber(HOMES_NAME)) < 0)
99 * If this is a winbindd provided username, remove
100 * the domain component before adding the service.
101 * Log a warning if the "path=" parameter does not
102 * include any macros.
106 const char *p = strchr(service,*lp_winbind_separator());
108 /* We only want the 'user' part of the string */
114 if (!lp_add_home(service, iHomeService, username, homedir)) {
118 return lp_servicenumber(service);
124 * Find a service entry.
126 * @param service is modified (to canonical form??)
129 int find_service(fstring service)
133 all_string_sub(service,"\\","/",0);
135 iService = lp_servicenumber(service);
137 /* now handle the special case of a home directory */
139 char *phome_dir = get_user_home_dir(service);
143 * Try mapping the servicename, it may
144 * be a Windows to unix mapped user name.
146 if(map_username(service))
147 phome_dir = get_user_home_dir(service);
150 DEBUG(3,("checking for home directory %s gave %s\n",service,
151 phome_dir?phome_dir:"(NULL)"));
153 iService = add_home_service(service,service /* 'username' */, phome_dir);
156 /* If we still don't have a service, attempt to add it as a printer. */
160 if ((iPrinterService = lp_servicenumber(PRINTERS_NAME)) >= 0) {
161 DEBUG(3,("checking whether %s is a valid printer name...\n", service));
162 if (pcap_printername_ok(service)) {
163 DEBUG(3,("%s is a valid printer name\n", service));
164 DEBUG(3,("adding %s as a printer service\n", service));
165 lp_add_printer(service, iPrinterService);
166 iService = lp_servicenumber(service);
168 DEBUG(0,("failed to add %s as a printer service!\n", service));
171 DEBUG(3,("%s is not a valid printer name\n", service));
176 /* Check for default vfs service? Unsure whether to implement this */
180 /* just possibly it's a default service? */
182 char *pdefservice = lp_defaultservice();
183 if (pdefservice && *pdefservice && !strequal(pdefservice,service) && !strstr_m(service,"..")) {
185 * We need to do a local copy here as lp_defaultservice()
186 * returns one of the rotating lp_string buffers that
187 * could get overwritten by the recursive find_service() call
188 * below. Fix from Josef Hinteregger <joehtg@joehtg.co.at>.
191 pstrcpy(defservice, pdefservice);
192 iService = find_service(defservice);
194 all_string_sub(service, "_","/",0);
195 iService = lp_add_service(service, iService);
201 if (!VALID_SNUM(iService)) {
202 DEBUG(0,("Invalid snum %d for %s\n",iService, service));
208 DEBUG(3,("find_service() failed to find service %s\n", service));
214 /****************************************************************************
215 do some basic sainity checks on the share.
216 This function modifies dev, ecode.
217 ****************************************************************************/
219 static NTSTATUS share_sanity_checks(int snum, fstring dev)
222 if (!lp_snum_ok(snum) ||
223 !check_access(smbd_server_fd(),
224 lp_hostsallow(snum), lp_hostsdeny(snum))) {
225 return NT_STATUS_ACCESS_DENIED;
228 if (dev[0] == '?' || !dev[0]) {
229 if (lp_print_ok(snum)) {
230 fstrcpy(dev,"LPT1:");
231 } else if (strequal(lp_fstype(snum), "IPC")) {
240 if (lp_print_ok(snum)) {
241 if (!strequal(dev, "LPT1:")) {
242 return NT_STATUS_BAD_DEVICE_TYPE;
244 } else if (strequal(lp_fstype(snum), "IPC")) {
245 if (!strequal(dev, "IPC")) {
246 return NT_STATUS_BAD_DEVICE_TYPE;
248 } else if (!strequal(dev, "A:")) {
249 return NT_STATUS_BAD_DEVICE_TYPE;
252 /* Behave as a printer if we are supposed to */
253 if (lp_print_ok(snum) && (strcmp(dev, "A:") == 0)) {
254 fstrcpy(dev, "LPT1:");
260 /****************************************************************************
261 Make a connection, given the snum to connect to, and the vuser of the
262 connecting user if appropriate.
263 ****************************************************************************/
265 static connection_struct *make_connection_snum(int snum, user_struct *vuser,
270 struct passwd *pass = NULL;
272 connection_struct *conn;
280 SET_STAT_INVALID(st);
282 if (NT_STATUS_IS_ERR(*status = share_sanity_checks(snum, dev))) {
288 DEBUG(0,("Couldn't find free connection.\n"));
289 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
293 if (lp_guest_only(snum)) {
294 const char *guestname = lp_guestaccount();
296 pass = getpwnam_alloc(guestname);
298 DEBUG(0,("make_connection_snum: Invalid guest "
299 "account %s??\n",guestname));
301 *status = NT_STATUS_NO_SUCH_USER;
304 fstrcpy(user,pass->pw_name);
305 conn->force_user = True;
306 conn->uid = pass->pw_uid;
307 conn->gid = pass->pw_gid;
308 string_set(&conn->user,pass->pw_name);
310 DEBUG(3,("Guest only user %s\n",user));
313 if (!lp_guest_ok(snum)) {
314 DEBUG(2, ("guest user (from session setup) "
315 "not permitted to access this share "
316 "(%s)\n", lp_servicename(snum)));
318 *status = NT_STATUS_ACCESS_DENIED;
322 if (!user_ok(vuser->user.unix_name, snum,
323 vuser->groups, vuser->n_groups)) {
324 DEBUG(2, ("user '%s' (from session setup) not "
325 "permitted to access this share "
326 "(%s)\n", vuser->user.unix_name,
327 lp_servicename(snum)));
329 *status = NT_STATUS_ACCESS_DENIED;
333 conn->vuid = vuser->vuid;
334 conn->uid = vuser->uid;
335 conn->gid = vuser->gid;
336 string_set(&conn->user,vuser->user.unix_name);
337 fstrcpy(user,vuser->user.unix_name);
338 guest = vuser->guest;
339 } else if (lp_security() == SEC_SHARE) {
340 /* add it as a possible user name if we
341 are in share mode security */
342 add_session_user(lp_servicename(snum));
343 /* shall we let them in? */
344 if (!authorise_login(snum,user,password,&guest)) {
345 DEBUG( 2, ( "Invalid username/password for [%s]\n",
346 lp_servicename(snum)) );
348 *status = NT_STATUS_WRONG_PASSWORD;
351 pass = Get_Pwnam(user);
352 conn->force_user = True;
353 conn->uid = pass->pw_uid;
354 conn->gid = pass->pw_gid;
355 string_set(&conn->user, pass->pw_name);
356 fstrcpy(user, pass->pw_name);
359 DEBUG(0, ("invalid VUID (vuser) but not in security=share\n"));
361 *status = NT_STATUS_ACCESS_DENIED;
365 add_session_user(user);
367 safe_strcpy(conn->client_address, client_addr(),
368 sizeof(conn->client_address)-1);
369 conn->num_files_open = 0;
370 conn->lastused = time(NULL);
371 conn->service = snum;
373 conn->printer = (strncmp(dev,"LPT",3) == 0);
374 conn->ipc = ( (strncmp(dev,"IPC",3) == 0) ||
375 ( lp_enable_asu_support() && strequal(dev,"ADMIN$")) );
378 /* Case options for the share. */
379 if (lp_casesensitive(snum) == Auto) {
380 /* We will be setting this per packet. Set to be case
381 * insensitive for now. */
382 conn->case_sensitive = False;
384 conn->case_sensitive = (BOOL)lp_casesensitive(snum);
387 conn->case_preserve = lp_preservecase(snum);
388 conn->short_case_preserve = lp_shortpreservecase(snum);
390 conn->veto_list = NULL;
391 conn->hide_list = NULL;
392 conn->veto_oplock_list = NULL;
393 conn->aio_write_behind_list = NULL;
394 string_set(&conn->dirpath,"");
395 string_set(&conn->user,user);
396 conn->nt_user_token = NULL;
398 conn->read_only = lp_readonly(conn->service);
399 conn->admin_user = False;
402 * If force user is true, then store the
403 * given userid and also the groups
404 * of the user we're forcing.
407 if (*lp_force_user(snum)) {
408 struct passwd *pass2;
410 pstrcpy(fuser,lp_force_user(snum));
412 /* Allow %S to be used by force user. */
413 pstring_sub(fuser,"%S",lp_servicename(snum));
415 pass2 = (struct passwd *)Get_Pwnam(fuser);
417 conn->uid = pass2->pw_uid;
418 conn->gid = pass2->pw_gid;
419 string_set(&conn->user,pass2->pw_name);
420 fstrcpy(user,pass2->pw_name);
421 conn->force_user = True;
422 DEBUG(3,("Forced user %s\n",user));
424 DEBUG(1,("Couldn't find user %s\n",fuser));
426 *status = NT_STATUS_NO_SUCH_USER;
433 * If force group is true, then override
434 * any groupid stored for the connecting user.
437 if (*lp_force_group(snum)) {
441 BOOL user_must_be_member = False;
443 pstrcpy(tmp_gname,lp_force_group(snum));
445 if (tmp_gname[0] == '+') {
446 user_must_be_member = True;
447 /* even now, tmp_gname is null terminated */
448 pstrcpy(gname,&tmp_gname[1]);
450 pstrcpy(gname,tmp_gname);
452 /* default service may be a group name */
453 pstring_sub(gname,"%S",lp_servicename(snum));
454 gid = nametogid(gname);
456 if (gid == (gid_t)-1) {
457 DEBUG(1,("Couldn't find group %s\n",gname));
459 *status = NT_STATUS_NO_SUCH_GROUP;
464 * If the user has been forced and the forced group starts
465 * with a '+', then we only set the group to be the forced
466 * group if the forced user is a member of that group.
467 * Otherwise, the meaning of the '+' would be ignored.
469 if (conn->force_user && user_must_be_member) {
470 if (user_in_group_list( user, gname, NULL, 0)) {
472 DEBUG(3,("Forced group %s for member %s\n",
477 DEBUG(3,("Forced group %s\n",gname));
479 conn->force_group = True;
481 #endif /* HAVE_GETGRNAM */
485 pstrcpy(s,lp_pathname(snum));
486 standard_sub_conn(conn,s,sizeof(s));
487 string_set(&conn->connectpath,s);
488 DEBUG(3,("Connect path is '%s' for service [%s]\n",s, lp_servicename(snum)));
491 if (conn->force_user || conn->force_group) {
493 /* groups stuff added by ih */
497 /* Find all the groups this uid is in and
498 store them. Used by change_to_user() */
499 initialise_groups(conn->user, conn->uid, conn->gid);
500 get_current_groups(conn->gid, &conn->ngroups,&conn->groups);
502 conn->nt_user_token = create_nt_token(conn->uid, conn->gid,
503 conn->ngroups, conn->groups,
508 * New code to check if there's a share security descripter
509 * added from NT server manager. This is done after the
510 * smb.conf checks are done as we need a uid and token. JRA.
515 BOOL can_write = share_access_check(conn, snum, vuser,
519 if (!share_access_check(conn, snum, vuser,
521 /* No access, read or write. */
522 DEBUG(0,("make_connection: connection to %s "
523 "denied due to security "
525 lp_servicename(snum)));
527 *status = NT_STATUS_ACCESS_DENIED;
530 conn->read_only = True;
534 /* Initialise VFS function pointers */
536 if (!smbd_vfs_init(conn)) {
537 DEBUG(0, ("vfs_init failed for service %s\n",
538 lp_servicename(snum)));
540 *status = NT_STATUS_BAD_NETWORK_NAME;
545 * If widelinks are disallowed we need to canonicalise the connect
546 * path here to ensure we don't have any symlinks in the
547 * connectpath. We will be checking all paths on this connection are
548 * below this directory. We must do this after the VFS init as we
549 * depend on the realpath() pointer in the vfs table. JRA.
551 if (!lp_widelinks(snum)) {
553 pstrcpy(s,conn->connectpath);
554 canonicalize_path(conn, s);
555 string_set(&conn->connectpath,s);
558 /* ROOT Activities: */
559 /* check number of connections */
560 if (!claim_connection(conn,
561 lp_servicename(snum),
562 lp_max_connections(snum),
564 DEBUG(1,("too many connections - rejected\n"));
566 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
570 /* Preexecs are done here as they might make the dir we are to ChDir
572 /* execute any "root preexec = " line */
573 if (*lp_rootpreexec(snum)) {
575 pstrcpy(cmd,lp_rootpreexec(snum));
576 standard_sub_conn(conn,cmd,sizeof(cmd));
577 DEBUG(5,("cmd=%s\n",cmd));
578 ret = smbrun(cmd,NULL);
579 if (ret != 0 && lp_rootpreexec_close(snum)) {
580 DEBUG(1,("root preexec gave %d - failing "
581 "connection\n", ret));
582 yield_connection(conn, lp_servicename(snum));
584 *status = NT_STATUS_ACCESS_DENIED;
589 /* USER Activites: */
590 if (!change_to_user(conn, conn->vuid)) {
591 /* No point continuing if they fail the basic checks */
592 DEBUG(0,("Can't become connected user!\n"));
593 yield_connection(conn, lp_servicename(snum));
595 *status = NT_STATUS_LOGON_FAILURE;
599 /* Remember that a different vuid can connect later without these
602 /* Preexecs are done here as they might make the dir we are to ChDir
605 /* execute any "preexec = " line */
606 if (*lp_preexec(snum)) {
608 pstrcpy(cmd,lp_preexec(snum));
609 standard_sub_conn(conn,cmd,sizeof(cmd));
610 ret = smbrun(cmd,NULL);
611 if (ret != 0 && lp_preexec_close(snum)) {
612 DEBUG(1,("preexec gave %d - failing connection\n",
614 change_to_root_user();
615 yield_connection(conn, lp_servicename(snum));
617 *status = NT_STATUS_ACCESS_DENIED;
622 #ifdef WITH_FAKE_KASERVER
623 if (lp_afs_share(snum)) {
628 /* Add veto/hide lists */
629 if (!IS_IPC(conn) && !IS_PRINT(conn)) {
630 set_namearray( &conn->veto_list, lp_veto_files(snum));
631 set_namearray( &conn->hide_list, lp_hide_files(snum));
632 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(snum));
635 /* Invoke VFS make connection hook - do this before the VFS_STAT call
636 to allow any filesystems needing user credentials to initialize
639 if (SMB_VFS_CONNECT(conn, lp_servicename(snum), user) < 0) {
640 DEBUG(0,("make_connection: VFS make connection failed!\n"));
641 change_to_root_user();
642 yield_connection(conn, lp_servicename(snum));
644 *status = NT_STATUS_UNSUCCESSFUL;
648 /* win2000 does not check the permissions on the directory
649 during the tree connect, instead relying on permission
650 check during individual operations. To match this behaviour
651 I have disabled this chdir check (tridge) */
652 /* the alternative is just to check the directory exists */
653 if ((ret = SMB_VFS_STAT(conn, conn->connectpath, &st)) != 0 ||
654 !S_ISDIR(st.st_mode)) {
655 if (ret == 0 && !S_ISDIR(st.st_mode)) {
656 DEBUG(0,("'%s' is not a directory, when connecting to "
657 "[%s]\n", conn->connectpath,
658 lp_servicename(snum)));
660 DEBUG(0,("'%s' does not exist or permission denied "
661 "when connecting to [%s] Error was %s\n",
662 conn->connectpath, lp_servicename(snum),
665 change_to_root_user();
666 /* Call VFS disconnect hook */
667 SMB_VFS_DISCONNECT(conn);
668 yield_connection(conn, lp_servicename(snum));
670 *status = NT_STATUS_BAD_NETWORK_NAME;
674 string_set(&conn->origpath,conn->connectpath);
676 #if SOFTLINK_OPTIMISATION
677 /* resolve any soft links early if possible */
678 if (vfs_ChDir(conn,conn->connectpath) == 0) {
680 pstrcpy(s,conn->connectpath);
682 string_set(&conn->connectpath,s);
683 vfs_ChDir(conn,conn->connectpath);
688 * Print out the 'connected as' stuff here as we need
689 * to know the effective uid and gid we will be using
690 * (at least initially).
693 if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
694 dbgtext( "%s (%s) ", get_remote_machine_name(),
695 conn->client_address );
696 dbgtext( "%s", srv_is_signing_active() ? "signed " : "");
697 dbgtext( "connect to service %s ", lp_servicename(snum) );
698 dbgtext( "initially as user %s ", user );
699 dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
700 dbgtext( "(pid %d)\n", (int)sys_getpid() );
703 /* we've finished with the user stuff - go back to root */
704 change_to_root_user();
708 /***************************************************************************************
709 Simple wrapper function for make_connection() to include a call to
711 **************************************************************************************/
713 connection_struct *make_connection_with_chdir(const char *service_in,
715 const char *dev, uint16 vuid,
718 connection_struct *conn = NULL;
720 conn = make_connection(service_in, password, dev, vuid, status);
723 * make_connection() does not change the directory for us any more
724 * so we have to do it as a separate step --jerry
727 if ( conn && vfs_ChDir(conn,conn->connectpath) != 0 ) {
728 DEBUG(0,("move_driver_to_download_area: Can't change "
729 "directory to %s for [print$] (%s)\n",
730 conn->connectpath,strerror(errno)));
731 yield_connection(conn, lp_servicename(SNUM(conn)));
733 *status = NT_STATUS_UNSUCCESSFUL;
740 /****************************************************************************
741 Make a connection to a service.
744 ****************************************************************************/
746 connection_struct *make_connection(const char *service_in, DATA_BLOB password,
747 const char *pdev, uint16 vuid,
751 user_struct *vuser = NULL;
758 /* This must ONLY BE CALLED AS ROOT. As it exits this function as
760 if (!non_root_mode() && (euid = geteuid()) != 0) {
761 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot "
762 "(%u)\n", (unsigned int)euid ));
763 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
766 if(lp_security() != SEC_SHARE) {
767 vuser = get_valid_user_struct(vuid);
769 DEBUG(1,("make_connection: refusing to connect with "
770 "no session setup\n"));
771 *status = NT_STATUS_ACCESS_DENIED;
776 /* Logic to try and connect to the correct [homes] share, preferably
777 without too many getpwnam() lookups. This is particulary nasty for
778 winbind usernames, where the share name isn't the same as unix
781 The snum of the homes share is stored on the vuser at session setup
785 if (strequal(service_in,HOMES_NAME)) {
786 if(lp_security() != SEC_SHARE) {
787 DATA_BLOB no_pw = data_blob(NULL, 0);
788 if (vuser->homes_snum == -1) {
789 DEBUG(2, ("[homes] share not available for "
790 "this user because it was not found "
791 "or created at session setup "
793 *status = NT_STATUS_BAD_NETWORK_NAME;
796 DEBUG(5, ("making a connection to [homes] service "
797 "created at session setup time\n"));
798 return make_connection_snum(vuser->homes_snum,
802 /* Security = share. Try with
803 * current_user_info.smb_name as the username. */
804 if (*current_user_info.smb_name) {
805 fstring unix_username;
806 fstrcpy(unix_username,
807 current_user_info.smb_name);
808 map_username(unix_username);
809 snum = find_service(unix_username);
812 DEBUG(5, ("making a connection to 'homes' "
813 "service %s based on "
814 "security=share\n", service_in));
815 return make_connection_snum(snum, NULL,
820 } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
821 && strequal(service_in,
822 lp_servicename(vuser->homes_snum))) {
823 DATA_BLOB no_pw = data_blob(NULL, 0);
824 DEBUG(5, ("making a connection to 'homes' service [%s] "
825 "created at session setup time\n", service_in));
826 return make_connection_snum(vuser->homes_snum,
831 fstrcpy(service, service_in);
835 snum = find_service(service);
838 if (strequal(service,"IPC$") ||
839 (lp_enable_asu_support() && strequal(service,"ADMIN$"))) {
840 DEBUG(3,("refusing IPC connection to %s\n", service));
841 *status = NT_STATUS_ACCESS_DENIED;
845 DEBUG(0,("%s (%s) couldn't find service %s\n",
846 get_remote_machine_name(), client_addr(), service));
847 *status = NT_STATUS_BAD_NETWORK_NAME;
851 /* Handle non-Dfs clients attempting connections to msdfs proxy */
852 if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0')) {
853 DEBUG(3, ("refusing connection to dfs proxy share '%s' "
854 "(pointing to %s)\n",
855 service, lp_msdfs_proxy(snum)));
856 *status = NT_STATUS_BAD_NETWORK_NAME;
860 DEBUG(5, ("making a connection to 'normal' service %s\n", service));
862 return make_connection_snum(snum, vuser,
867 /****************************************************************************
869 ****************************************************************************/
871 void close_cnum(connection_struct *conn, uint16 vuid)
874 pipe_close_conn(conn);
876 file_close_conn(conn);
877 dptr_closecnum(conn);
880 change_to_root_user();
882 DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
883 get_remote_machine_name(),
884 conn->client_address,
885 lp_servicename(SNUM(conn))));
887 /* Call VFS disconnect hook */
888 SMB_VFS_DISCONNECT(conn);
890 yield_connection(conn, lp_servicename(SNUM(conn)));
892 /* make sure we leave the directory available for unmount */
893 vfs_ChDir(conn, "/");
895 /* execute any "postexec = " line */
896 if (*lp_postexec(SNUM(conn)) &&
897 change_to_user(conn, vuid)) {
899 pstrcpy(cmd,lp_postexec(SNUM(conn)));
900 standard_sub_conn(conn,cmd,sizeof(cmd));
902 change_to_root_user();
905 change_to_root_user();
906 /* execute any "root postexec = " line */
907 if (*lp_rootpostexec(SNUM(conn))) {
909 pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
910 standard_sub_conn(conn,cmd,sizeof(cmd));