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;
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;
43 conn->lastused = smb_last_time.tv_sec;
48 vfs_ChDir(conn,conn->connectpath) != 0 &&
49 vfs_ChDir(conn,conn->origpath) != 0) {
50 DEBUG(0,("chdir (%s) failed\n",
55 if ((conn == last_conn) && (last_flags == flags)) {
62 /* Obey the client case sensitivity requests - only for clients that support it. */
63 switch (lp_casesensitive(snum)) {
66 /* We need this uglyness due to DOS/Win9x clients that lie about case insensitivity. */
67 enum remote_arch_types ra_type = get_remote_arch();
68 if ((ra_type != RA_SAMBA) && (ra_type != RA_CIFSFS)) {
69 /* Client can't support per-packet case sensitive pathnames. */
70 conn->case_sensitive = False;
72 conn->case_sensitive = !(flags & FLAG_CASELESS_PATHNAMES);
77 conn->case_sensitive = True;
80 conn->case_sensitive = False;
83 magic_char = lp_magicchar(snum);
87 /****************************************************************************
88 Add a home service. Returns the new service number or -1 if fail.
89 ****************************************************************************/
91 int add_home_service(const char *service, const char *username, const char *homedir)
95 if (!service || !homedir)
98 if ((iHomeService = lp_servicenumber(HOMES_NAME)) < 0)
102 * If this is a winbindd provided username, remove
103 * the domain component before adding the service.
104 * Log a warning if the "path=" parameter does not
105 * include any macros.
109 const char *p = strchr(service,*lp_winbind_separator());
111 /* We only want the 'user' part of the string */
117 if (!lp_add_home(service, iHomeService, username, homedir)) {
121 return lp_servicenumber(service);
127 * Find a service entry.
129 * @param service is modified (to canonical form??)
132 int find_service(fstring service)
136 all_string_sub(service,"\\","/",0);
138 iService = lp_servicenumber(service);
140 /* now handle the special case of a home directory */
142 char *phome_dir = get_user_home_dir(service);
146 * Try mapping the servicename, it may
147 * be a Windows to unix mapped user name.
149 if(map_username(service))
150 phome_dir = get_user_home_dir(service);
153 DEBUG(3,("checking for home directory %s gave %s\n",service,
154 phome_dir?phome_dir:"(NULL)"));
156 iService = add_home_service(service,service /* 'username' */, phome_dir);
159 /* If we still don't have a service, attempt to add it as a printer. */
163 if ((iPrinterService = lp_servicenumber(PRINTERS_NAME)) >= 0) {
164 DEBUG(3,("checking whether %s is a valid printer name...\n", service));
165 if (pcap_printername_ok(service)) {
166 DEBUG(3,("%s is a valid printer name\n", service));
167 DEBUG(3,("adding %s as a printer service\n", service));
168 lp_add_printer(service, iPrinterService);
169 iService = lp_servicenumber(service);
171 DEBUG(0,("failed to add %s as a printer service!\n", service));
174 DEBUG(3,("%s is not a valid printer name\n", service));
179 /* Check for default vfs service? Unsure whether to implement this */
183 /* just possibly it's a default service? */
185 char *pdefservice = lp_defaultservice();
186 if (pdefservice && *pdefservice && !strequal(pdefservice,service) && !strstr_m(service,"..")) {
188 * We need to do a local copy here as lp_defaultservice()
189 * returns one of the rotating lp_string buffers that
190 * could get overwritten by the recursive find_service() call
191 * below. Fix from Josef Hinteregger <joehtg@joehtg.co.at>.
194 pstrcpy(defservice, pdefservice);
195 iService = find_service(defservice);
197 all_string_sub(service, "_","/",0);
198 iService = lp_add_service(service, iService);
204 if (!VALID_SNUM(iService)) {
205 DEBUG(0,("Invalid snum %d for %s\n",iService, service));
211 DEBUG(3,("find_service() failed to find service %s\n", service));
217 /****************************************************************************
218 do some basic sainity checks on the share.
219 This function modifies dev, ecode.
220 ****************************************************************************/
222 static NTSTATUS share_sanity_checks(int snum, fstring dev)
225 if (!lp_snum_ok(snum) ||
226 !check_access(smbd_server_fd(),
227 lp_hostsallow(snum), lp_hostsdeny(snum))) {
228 return NT_STATUS_ACCESS_DENIED;
231 if (dev[0] == '?' || !dev[0]) {
232 if (lp_print_ok(snum)) {
233 fstrcpy(dev,"LPT1:");
234 } else if (strequal(lp_fstype(snum), "IPC")) {
243 if (lp_print_ok(snum)) {
244 if (!strequal(dev, "LPT1:")) {
245 return NT_STATUS_BAD_DEVICE_TYPE;
247 } else if (strequal(lp_fstype(snum), "IPC")) {
248 if (!strequal(dev, "IPC")) {
249 return NT_STATUS_BAD_DEVICE_TYPE;
251 } else if (!strequal(dev, "A:")) {
252 return NT_STATUS_BAD_DEVICE_TYPE;
255 /* Behave as a printer if we are supposed to */
256 if (lp_print_ok(snum) && (strcmp(dev, "A:") == 0)) {
257 fstrcpy(dev, "LPT1:");
263 /****************************************************************************
264 Make a connection, given the snum to connect to, and the vuser of the
265 connecting user if appropriate.
266 ****************************************************************************/
268 static connection_struct *make_connection_snum(int snum, user_struct *vuser,
270 const char *pdev, NTSTATUS *status)
272 struct passwd *pass = NULL;
274 connection_struct *conn;
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 account %s??\n",guestname));
300 *status = NT_STATUS_NO_SUCH_USER;
303 fstrcpy(user,pass->pw_name);
304 conn->force_user = True;
305 conn->uid = pass->pw_uid;
306 conn->gid = pass->pw_gid;
307 string_set(&conn->user,pass->pw_name);
309 DEBUG(3,("Guest only user %s\n",user));
312 if (!lp_guest_ok(snum)) {
313 DEBUG(2, ("guest user (from session setup) not permitted to access this share (%s)\n", lp_servicename(snum)));
315 *status = NT_STATUS_ACCESS_DENIED;
319 if (!user_ok(vuser->user.unix_name, snum, vuser->groups, vuser->n_groups)) {
320 DEBUG(2, ("user '%s' (from session setup) not permitted to access this share (%s)\n", vuser->user.unix_name, lp_servicename(snum)));
322 *status = NT_STATUS_ACCESS_DENIED;
326 conn->vuid = vuser->vuid;
327 conn->uid = vuser->uid;
328 conn->gid = vuser->gid;
329 string_set(&conn->user,vuser->user.unix_name);
330 fstrcpy(user,vuser->user.unix_name);
331 guest = vuser->guest;
332 } else if (lp_security() == SEC_SHARE) {
333 /* add it as a possible user name if we
334 are in share mode security */
335 add_session_user(lp_servicename(snum));
336 /* shall we let them in? */
337 if (!authorise_login(snum,user,password,&guest)) {
338 DEBUG( 2, ( "Invalid username/password for [%s]\n",
339 lp_servicename(snum)) );
341 *status = NT_STATUS_WRONG_PASSWORD;
344 pass = Get_Pwnam(user);
345 conn->force_user = True;
346 conn->uid = pass->pw_uid;
347 conn->gid = pass->pw_gid;
348 string_set(&conn->user, pass->pw_name);
349 fstrcpy(user, pass->pw_name);
352 DEBUG(0, ("invalid VUID (vuser) but not in security=share\n"));
354 *status = NT_STATUS_ACCESS_DENIED;
358 add_session_user(user);
360 safe_strcpy(conn->client_address, client_addr(),
361 sizeof(conn->client_address)-1);
362 conn->num_files_open = 0;
363 conn->lastused = time(NULL);
364 conn->service = snum;
366 conn->printer = (strncmp(dev,"LPT",3) == 0);
367 conn->ipc = ((strncmp(dev,"IPC",3) == 0) || strequal(dev,"ADMIN$"));
370 /* Case options for the share. */
371 if (lp_casesensitive(snum) == Auto) {
372 /* We will be setting this per packet. Set to be case insensitive for now. */
373 conn->case_sensitive = False;
375 conn->case_sensitive = (BOOL)lp_casesensitive(snum);
378 conn->case_preserve = lp_preservecase(snum);
379 conn->short_case_preserve = lp_shortpreservecase(snum);
381 conn->veto_list = NULL;
382 conn->hide_list = NULL;
383 conn->veto_oplock_list = NULL;
384 string_set(&conn->dirpath,"");
385 string_set(&conn->user,user);
386 conn->nt_user_token = NULL;
388 conn->read_only = lp_readonly(conn->service);
389 conn->admin_user = False;
392 * If force user is true, then store the
393 * given userid and also the groups
394 * of the user we're forcing.
397 if (*lp_force_user(snum)) {
398 struct passwd *pass2;
400 pstrcpy(fuser,lp_force_user(snum));
402 /* Allow %S to be used by force user. */
403 pstring_sub(fuser,"%S",lp_servicename(snum));
405 pass2 = (struct passwd *)Get_Pwnam(fuser);
407 conn->uid = pass2->pw_uid;
408 conn->gid = pass2->pw_gid;
409 string_set(&conn->user,pass2->pw_name);
410 fstrcpy(user,pass2->pw_name);
411 conn->force_user = True;
412 DEBUG(3,("Forced user %s\n",user));
414 DEBUG(1,("Couldn't find user %s\n",fuser));
416 *status = NT_STATUS_NO_SUCH_USER;
423 * If force group is true, then override
424 * any groupid stored for the connecting user.
427 if (*lp_force_group(snum)) {
431 BOOL user_must_be_member = False;
433 pstrcpy(tmp_gname,lp_force_group(snum));
435 if (tmp_gname[0] == '+') {
436 user_must_be_member = True;
437 /* even now, tmp_gname is null terminated */
438 pstrcpy(gname,&tmp_gname[1]);
440 pstrcpy(gname,tmp_gname);
442 /* default service may be a group name */
443 pstring_sub(gname,"%S",lp_servicename(snum));
444 gid = nametogid(gname);
446 if (gid != (gid_t)-1) {
449 * If the user has been forced and the forced group starts
450 * with a '+', then we only set the group to be the forced
451 * group if the forced user is a member of that group.
452 * Otherwise, the meaning of the '+' would be ignored.
454 if (conn->force_user && user_must_be_member) {
455 if (user_in_group_list( user, gname, NULL, 0)) {
457 DEBUG(3,("Forced group %s for member %s\n",gname,user));
461 DEBUG(3,("Forced group %s\n",gname));
463 conn->force_group = True;
465 DEBUG(1,("Couldn't find group %s\n",gname));
467 *status = NT_STATUS_NO_SUCH_GROUP;
471 #endif /* HAVE_GETGRNAM */
475 pstrcpy(s,lp_pathname(snum));
476 standard_sub_conn(conn,s,sizeof(s));
477 string_set(&conn->connectpath,s);
478 DEBUG(3,("Connect path is '%s' for service [%s]\n",s, lp_servicename(snum)));
481 if (conn->force_user || conn->force_group) {
483 /* groups stuff added by ih */
487 /* Find all the groups this uid is in and
488 store them. Used by change_to_user() */
489 initialise_groups(conn->user, conn->uid, conn->gid);
490 get_current_groups(conn->gid, &conn->ngroups,&conn->groups);
492 conn->nt_user_token = create_nt_token(conn->uid, conn->gid,
493 conn->ngroups, conn->groups,
498 * New code to check if there's a share security descripter
499 * added from NT server manager. This is done after the
500 * smb.conf checks are done as we need a uid and token. JRA.
505 BOOL can_write = share_access_check(conn, snum, vuser, FILE_WRITE_DATA);
508 if (!share_access_check(conn, snum, vuser, FILE_READ_DATA)) {
509 /* No access, read or write. */
510 DEBUG(0,( "make_connection: connection to %s denied due to security descriptor.\n",
511 lp_servicename(snum)));
513 *status = NT_STATUS_ACCESS_DENIED;
516 conn->read_only = True;
520 /* Initialise VFS function pointers */
522 if (!smbd_vfs_init(conn)) {
523 DEBUG(0, ("vfs_init failed for service %s\n", lp_servicename(SNUM(conn))));
525 *status = NT_STATUS_BAD_NETWORK_NAME;
530 * If widelinks are disallowed we need to canonicalise the
531 * connect path here to ensure we don't have any symlinks in
532 * the connectpath. We will be checking all paths on this
533 * connection are below this directory. We must do this after
534 * the VFS init as we depend on the realpath() pointer in the vfs table. JRA.
536 if (!lp_widelinks(snum)) {
538 pstrcpy(s,conn->connectpath);
539 canonicalize_path(conn, s);
540 string_set(&conn->connectpath,s);
543 /* ROOT Activities: */
544 /* check number of connections */
545 if (!claim_connection(conn,
546 lp_servicename(SNUM(conn)),
547 lp_max_connections(SNUM(conn)),
549 DEBUG(1,("too many connections - rejected\n"));
551 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
555 /* Preexecs are done here as they might make the dir we are to ChDir to below */
556 /* execute any "root preexec = " line */
557 if (*lp_rootpreexec(SNUM(conn))) {
560 pstrcpy(cmd,lp_rootpreexec(SNUM(conn)));
561 standard_sub_conn(conn,cmd,sizeof(cmd));
562 DEBUG(5,("cmd=%s\n",cmd));
563 ret = smbrun(cmd,NULL);
564 if (ret != 0 && lp_rootpreexec_close(SNUM(conn))) {
565 DEBUG(1,("root preexec gave %d - failing connection\n", ret));
566 yield_connection(conn, lp_servicename(SNUM(conn)));
568 *status = NT_STATUS_ACCESS_DENIED;
573 /* USER Activites: */
574 if (!change_to_user(conn, conn->vuid)) {
575 /* No point continuing if they fail the basic checks */
576 DEBUG(0,("Can't become connected user!\n"));
578 *status = NT_STATUS_LOGON_FAILURE;
582 /* Remember that a different vuid can connect later without these checks... */
584 /* Preexecs are done here as they might make the dir we are to ChDir to below */
585 /* execute any "preexec = " line */
586 if (*lp_preexec(SNUM(conn))) {
589 pstrcpy(cmd,lp_preexec(SNUM(conn)));
590 standard_sub_conn(conn,cmd,sizeof(cmd));
591 ret = smbrun(cmd,NULL);
592 if (ret != 0 && lp_preexec_close(SNUM(conn))) {
593 DEBUG(1,("preexec gave %d - failing connection\n", ret));
594 change_to_root_user();
595 yield_connection(conn, lp_servicename(SNUM(conn)));
597 *status = NT_STATUS_ACCESS_DENIED;
602 #ifdef WITH_FAKE_KASERVER
603 if (lp_afs_share(SNUM(conn))) {
608 #if CHECK_PATH_ON_TCONX
609 /* win2000 does not check the permissions on the directory
610 during the tree connect, instead relying on permission
611 check during individual operations. To match this behaviour
612 I have disabled this chdir check (tridge) */
613 if (vfs_ChDir(conn,conn->connectpath) != 0) {
614 DEBUG(0,("%s (%s) Can't change directory to %s (%s)\n",
615 get_remote_machine_name(), conn->client_address,
616 conn->connectpath,strerror(errno)));
617 change_to_root_user();
618 yield_connection(conn, lp_servicename(SNUM(conn)));
620 *status = NT_STATUS_BAD_NETWORK_NAME;
624 /* the alternative is just to check the directory exists */
625 if (stat(conn->connectpath, &st) != 0 || !S_ISDIR(st.st_mode)) {
626 DEBUG(0,("'%s' does not exist or is not a directory, when connecting to [%s]\n", conn->connectpath, lp_servicename(SNUM(conn))));
627 change_to_root_user();
628 yield_connection(conn, lp_servicename(SNUM(conn)));
630 *status = NT_STATUS_BAD_NETWORK_NAME;
635 string_set(&conn->origpath,conn->connectpath);
637 #if SOFTLINK_OPTIMISATION
638 /* resolve any soft links early if possible */
639 if (vfs_ChDir(conn,conn->connectpath) == 0) {
641 pstrcpy(s,conn->connectpath);
643 string_set(&conn->connectpath,s);
644 vfs_ChDir(conn,conn->connectpath);
649 * Print out the 'connected as' stuff here as we need
650 * to know the effective uid and gid we will be using
651 * (at least initially).
654 if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
655 dbgtext( "%s (%s) ", get_remote_machine_name(), conn->client_address );
656 dbgtext( "%s", srv_is_signing_active() ? "signed " : "");
657 dbgtext( "connect to service %s ", lp_servicename(SNUM(conn)) );
658 dbgtext( "initially as user %s ", user );
659 dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
660 dbgtext( "(pid %d)\n", (int)sys_getpid() );
663 /* Add veto/hide lists */
664 if (!IS_IPC(conn) && !IS_PRINT(conn)) {
665 set_namearray( &conn->veto_list, lp_veto_files(SNUM(conn)));
666 set_namearray( &conn->hide_list, lp_hide_files(SNUM(conn)));
667 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(SNUM(conn)));
670 /* Invoke VFS make connection hook */
672 if (SMB_VFS_CONNECT(conn, lp_servicename(snum), user) < 0) {
673 DEBUG(0,("make_connection: VFS make connection failed!\n"));
674 change_to_root_user();
676 *status = NT_STATUS_UNSUCCESSFUL;
680 /* we've finished with the user stuff - go back to root */
681 change_to_root_user();
686 /***************************************************************************************
687 Simple wrapper function for make_connection() to include a call to
689 **************************************************************************************/
691 connection_struct *make_connection_with_chdir(const char *service_in, DATA_BLOB password,
692 const char *dev, uint16 vuid, NTSTATUS *status)
694 connection_struct *conn = NULL;
696 conn = make_connection(service_in, password, dev, vuid, status);
699 * make_connection() does not change the directory for us any more
700 * so we have to do it as a separate step --jerry
703 if ( conn && vfs_ChDir(conn,conn->connectpath) != 0 ) {
704 DEBUG(0,("move_driver_to_download_area: Can't change directory to %s for [print$] (%s)\n",
705 conn->connectpath,strerror(errno)));
706 yield_connection(conn, lp_servicename(SNUM(conn)));
708 *status = NT_STATUS_UNSUCCESSFUL;
715 /****************************************************************************
716 Make a connection to a service.
719 ****************************************************************************/
721 connection_struct *make_connection(const char *service_in, DATA_BLOB password,
722 const char *pdev, uint16 vuid, NTSTATUS *status)
725 user_struct *vuser = NULL;
732 /* This must ONLY BE CALLED AS ROOT. As it exits this function as root. */
733 if (!non_root_mode() && (euid = geteuid()) != 0) {
734 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot (%u)\n", (unsigned int)euid ));
735 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
738 if(lp_security() != SEC_SHARE) {
739 vuser = get_valid_user_struct(vuid);
741 DEBUG(1,("make_connection: refusing to connect with no session setup\n"));
742 *status = NT_STATUS_ACCESS_DENIED;
747 /* Logic to try and connect to the correct [homes] share, preferably without too many
748 getpwnam() lookups. This is particulary nasty for winbind usernames, where the
749 share name isn't the same as unix username.
751 The snum of the homes share is stored on the vuser at session setup time.
754 if (strequal(service_in,HOMES_NAME)) {
755 if(lp_security() != SEC_SHARE) {
756 DATA_BLOB no_pw = data_blob(NULL, 0);
757 if (vuser->homes_snum == -1) {
758 DEBUG(2, ("[homes] share not available for this user because it was not found or created at session setup time\n"));
759 *status = NT_STATUS_BAD_NETWORK_NAME;
762 DEBUG(5, ("making a connection to [homes] service created at session setup time\n"));
763 return make_connection_snum(vuser->homes_snum,
767 /* Security = share. Try with current_user_info.smb_name
768 * as the username. */
769 if (*current_user_info.smb_name) {
770 fstring unix_username;
771 fstrcpy(unix_username,
772 current_user_info.smb_name);
773 map_username(unix_username);
774 snum = find_service(unix_username);
777 DEBUG(5, ("making a connection to 'homes' service %s based on security=share\n", service_in));
778 return make_connection_snum(snum, NULL,
783 } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
784 && strequal(service_in, lp_servicename(vuser->homes_snum))) {
785 DATA_BLOB no_pw = data_blob(NULL, 0);
786 DEBUG(5, ("making a connection to 'homes' service [%s] created at session setup time\n", service_in));
787 return make_connection_snum(vuser->homes_snum,
792 fstrcpy(service, service_in);
796 snum = find_service(service);
799 if (strequal(service,"IPC$") || strequal(service,"ADMIN$")) {
800 DEBUG(3,("refusing IPC connection to %s\n", service));
801 *status = NT_STATUS_ACCESS_DENIED;
805 DEBUG(0,("%s (%s) couldn't find service %s\n",
806 get_remote_machine_name(), client_addr(), service));
807 *status = NT_STATUS_BAD_NETWORK_NAME;
811 /* Handle non-Dfs clients attempting connections to msdfs proxy */
812 if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0')) {
813 DEBUG(3, ("refusing connection to dfs proxy share '%s' (pointing to %s)\n",
814 service, lp_msdfs_proxy(snum)));
815 *status = NT_STATUS_BAD_NETWORK_NAME;
819 DEBUG(5, ("making a connection to 'normal' service %s\n", service));
821 return make_connection_snum(snum, vuser,
826 /****************************************************************************
828 ****************************************************************************/
829 void close_cnum(connection_struct *conn, uint16 vuid)
832 pipe_close_conn(conn);
834 file_close_conn(conn);
835 dptr_closecnum(conn);
838 change_to_root_user();
840 DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
841 get_remote_machine_name(),conn->client_address,
842 lp_servicename(SNUM(conn))));
844 /* Call VFS disconnect hook */
845 SMB_VFS_DISCONNECT(conn);
847 yield_connection(conn, lp_servicename(SNUM(conn)));
849 /* make sure we leave the directory available for unmount */
850 vfs_ChDir(conn, "/");
852 /* execute any "postexec = " line */
853 if (*lp_postexec(SNUM(conn)) &&
854 change_to_user(conn, vuid)) {
856 pstrcpy(cmd,lp_postexec(SNUM(conn)));
857 standard_sub_conn(conn,cmd,sizeof(cmd));
859 change_to_root_user();
862 change_to_root_user();
863 /* execute any "root postexec = " line */
864 if (*lp_rootpostexec(SNUM(conn))) {
866 pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
867 standard_sub_conn(conn,cmd,sizeof(cmd));