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 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 fstring remote_machine;
31 extern userdom_struct current_user_info;
32 extern fstring remote_machine;
35 /****************************************************************************
36 Load parameters specific to a connection/service.
37 ****************************************************************************/
39 BOOL set_current_service(connection_struct *conn,BOOL do_chdir)
41 extern char magic_char;
42 static connection_struct *last_conn;
50 conn->lastused = smb_last_time.tv_sec;
55 vfs_ChDir(conn,conn->connectpath) != 0 &&
56 vfs_ChDir(conn,conn->origpath) != 0) {
57 DEBUG(0,("chdir (%s) failed\n",
62 if (conn == last_conn)
67 case_default = lp_defaultcase(snum);
68 case_preserve = lp_preservecase(snum);
69 short_case_preserve = lp_shortpreservecase(snum);
70 case_mangle = lp_casemangle(snum);
71 case_sensitive = lp_casesensitive(snum);
72 magic_char = lp_magicchar(snum);
73 use_mangled_map = (*lp_mangled_map(snum) ? True:False);
77 /****************************************************************************
78 Add a home service. Returns the new service number or -1 if fail.
79 ****************************************************************************/
81 int add_home_service(const char *service, const char *username, const char *homedir)
85 if (!service || !homedir)
88 if ((iHomeService = lp_servicenumber(HOMES_NAME)) < 0)
92 * If this is a winbindd provided username, remove
93 * the domain component before adding the service.
94 * Log a warning if the "path=" parameter does not
99 const char *p = strchr(service,*lp_winbind_separator());
101 /* We only want the 'user' part of the string */
107 lp_add_home(service, iHomeService, username, homedir);
109 return lp_servicenumber(service);
115 * Find a service entry. service is always in dos codepage.
117 * @param service is modified (to canonical form??)
119 int find_service(fstring service)
123 all_string_sub(service,"\\","/",0);
125 iService = lp_servicenumber(service);
127 /* now handle the special case of a home directory */
130 char *phome_dir = get_user_home_dir(service);
135 * Try mapping the servicename, it may
136 * be a Windows to unix mapped user name.
138 if(map_username(service))
139 phome_dir = get_user_home_dir(service);
142 DEBUG(3,("checking for home directory %s gave %s\n",service,
143 phome_dir?phome_dir:"(NULL)"));
145 iService = add_home_service(service,service /* 'username' */, phome_dir);
148 /* If we still don't have a service, attempt to add it as a printer. */
153 if ((iPrinterService = lp_servicenumber(PRINTERS_NAME)) >= 0)
157 DEBUG(3,("checking whether %s is a valid printer name...\n", service));
159 if ((pszTemp != NULL) && pcap_printername_ok(service, pszTemp))
161 DEBUG(3,("%s is a valid printer name\n", service));
162 DEBUG(3,("adding %s as a printer service\n", service));
163 lp_add_printer(service, iPrinterService);
164 iService = lp_servicenumber(service);
166 DEBUG(0,("failed to add %s as a printer service!\n", service));
169 DEBUG(3,("%s is not a valid printer name\n", service));
173 /* Check for default vfs service? Unsure whether to implement this */
178 /* just possibly it's a default service? */
181 char *pdefservice = lp_defaultservice();
182 if (pdefservice && *pdefservice &&
183 !strequal(pdefservice,service) &&
184 !strstr(service,".."))
187 * We need to do a local copy here as lp_defaultservice()
188 * returns one of the rotating lp_string buffers that
189 * could get overwritten by the recursive find_service() call
190 * below. Fix from Josef Hinteregger <joehtg@joehtg.co.at>.
193 pstrcpy(defservice, pdefservice);
194 iService = find_service(defservice);
197 all_string_sub(service, "_","/",0);
198 iService = lp_add_service(service, iService);
204 if (!VALID_SNUM(iService))
206 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 ****************************************************************************/
221 static NTSTATUS share_sanity_checks(int snum, pstring dev)
224 if (!lp_snum_ok(snum) ||
225 !check_access(smbd_server_fd(),
226 lp_hostsallow(snum), lp_hostsdeny(snum))) {
227 return NT_STATUS_ACCESS_DENIED;
230 /* you can only connect to the IPC$ service as an ipc device */
231 if (strequal(lp_fstype(snum), "IPC"))
234 if (dev[0] == '?' || !dev[0]) {
235 if (lp_print_ok(snum)) {
236 pstrcpy(dev,"LPT1:");
242 /* if the request is as a printer and you can't print then refuse */
244 if (!lp_print_ok(snum) && (strncmp(dev,"LPT",3) == 0)) {
245 DEBUG(1,("Attempt to connect to non-printer as a printer\n"));
246 return NT_STATUS_BAD_DEVICE_TYPE;
249 /* Behave as a printer if we are supposed to */
250 if (lp_print_ok(snum) && (strcmp(dev, "A:") == 0)) {
251 pstrcpy(dev, "LPT1:");
258 /****************************************************************************
260 ****************************************************************************/
261 static void set_read_only(connection_struct *conn)
264 char *service = lp_servicename(conn->service);
265 conn->read_only = lp_readonly(conn->service);
267 if (!service) return;
269 str_list_copy(&list, lp_readlist(conn->service));
271 if (!str_list_substitute(list, "%S", service)) {
272 DEBUG(0, ("ERROR: read list substitution failed\n"));
274 if (user_in_list(conn->user, list))
275 conn->read_only = True;
276 str_list_free(&list);
279 str_list_copy(&list, lp_writelist(conn->service));
281 if (!str_list_substitute(list, "%S", service)) {
282 DEBUG(0, ("ERROR: write list substitution failed\n"));
284 if (user_in_list(conn->user, list))
285 conn->read_only = False;
286 str_list_free(&list);
291 /****************************************************************************
293 ****************************************************************************/
294 static void set_admin_user(connection_struct *conn)
296 /* admin user check */
298 /* JRA - original code denied admin user if the share was
299 marked read_only. Changed as I don't think this is needed,
300 but old code left in case there is a problem here.
302 if (user_in_list(conn->user,lp_admin_users(conn->service))
307 conn->admin_user = True;
308 DEBUG(0,("%s logged in as admin user (root privileges)\n",conn->user));
310 conn->admin_user = False;
313 #if 0 /* This done later, for now */
314 /* admin users always run as uid=0 */
315 if (conn->admin_user) {
321 /****************************************************************************
322 Make a connection, given the snum to connect to, and the vuser of the
323 connecting user if appropriate.
324 ****************************************************************************/
326 static connection_struct *make_connection_snum(int snum, user_struct *vuser,
328 char *dev, NTSTATUS *status)
330 struct passwd *pass = NULL;
333 connection_struct *conn;
338 if (NT_STATUS_IS_ERR(*status = share_sanity_checks(snum, dev))) {
344 DEBUG(0,("Couldn't find free connection.\n"));
345 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
349 if (lp_guest_only(snum)) {
350 char *guestname = lp_guestaccount();
353 pass = getpwnam_alloc(guestname);
355 DEBUG(0,("authorise_login: Invalid guest account %s??\n",guestname));
357 *status = NT_STATUS_NO_SUCH_USER;
360 fstrcpy(user,pass->pw_name);
361 conn->force_user = True;
362 string_set(&conn->user,pass->pw_name);
364 DEBUG(3,("Guest only user %s\n",user));
367 if (!lp_guest_ok(snum)) {
368 DEBUG(2, ("guest user (from session setup) not permitted to access this share (%s)", lp_servicename(snum)));
370 *status = NT_STATUS_ACCESS_DENIED;
374 if (!user_ok(vuser->user.unix_name, snum)) {
375 DEBUG(2, ("user '%s' (from session setup) not permitted to access this share (%s)", vuser->user.unix_name, lp_servicename(snum)));
377 *status = NT_STATUS_ACCESS_DENIED;
381 conn->vuid = vuser->vuid;
382 conn->uid = vuser->uid;
383 conn->gid = vuser->gid;
384 string_set(&conn->user,vuser->user.unix_name);
385 fstrcpy(user,vuser->user.unix_name);
386 guest = vuser->guest;
387 } else if (lp_security() == SEC_SHARE) {
388 /* add it as a possible user name if we
389 are in share mode security */
390 add_session_user(lp_servicename(snum));
391 /* shall we let them in? */
392 if (!authorise_login(snum,user,password,&guest)) {
393 DEBUG( 2, ( "Invalid username/password for [%s]\n",
394 lp_servicename(snum)) );
396 *status = NT_STATUS_WRONG_PASSWORD;
399 pass = Get_Pwnam(user);
400 conn->force_user = force;
401 conn->uid = pass->pw_uid;
402 conn->gid = pass->pw_gid;
403 string_set(&conn->user, pass->pw_name);
404 fstrcpy(user, pass->pw_name);
407 DEBUG(0, ("invalid VUID (vuser) but not in security=share\n"));
409 *status = NT_STATUS_ACCESS_DENIED;
413 add_session_user(user);
415 safe_strcpy(conn->client_address, client_addr(),
416 sizeof(conn->client_address)-1);
417 conn->num_files_open = 0;
418 conn->lastused = time(NULL);
419 conn->service = snum;
421 conn->printer = (strncmp(dev,"LPT",3) == 0);
422 conn->ipc = ((strncmp(dev,"IPC",3) == 0) || strequal(dev,"ADMIN$"));
424 conn->veto_list = NULL;
425 conn->hide_list = NULL;
426 conn->veto_oplock_list = NULL;
427 string_set(&conn->dirpath,"");
428 string_set(&conn->user,user);
429 conn->nt_user_token = NULL;
433 set_admin_user(conn);
436 * If force user is true, then store the
437 * given userid and also the primary groupid
438 * of the user we're forcing.
441 if (*lp_force_user(snum)) {
442 struct passwd *pass2;
444 pstrcpy(fuser,lp_force_user(snum));
446 /* Allow %S to be used by force user. */
447 pstring_sub(fuser,"%S",lp_servicename(snum));
449 pass2 = (struct passwd *)Get_Pwnam(fuser);
451 conn->uid = pass2->pw_uid;
452 conn->gid = pass2->pw_gid;
453 string_set(&conn->user,pass2->pw_name);
454 fstrcpy(user,pass2->pw_name);
455 conn->force_user = True;
456 DEBUG(3,("Forced user %s\n",user));
458 DEBUG(1,("Couldn't find user %s\n",fuser));
460 *status = NT_STATUS_NO_SUCH_USER;
465 /* admin users always run as uid=0 */
466 if (conn->admin_user) {
472 * If force group is true, then override
473 * any groupid stored for the connecting user.
476 if (*lp_force_group(snum)) {
480 BOOL user_must_be_member = False;
482 StrnCpy(tmp_gname,lp_force_group(snum),sizeof(pstring)-1);
484 if (tmp_gname[0] == '+') {
485 user_must_be_member = True;
486 StrnCpy(gname,&tmp_gname[1],sizeof(pstring)-2);
488 StrnCpy(gname,tmp_gname,sizeof(pstring)-1);
490 /* default service may be a group name */
491 pstring_sub(gname,"%S",lp_servicename(snum));
492 gid = nametogid(gname);
494 if (gid != (gid_t)-1) {
496 * If the user has been forced and the forced group starts
497 * with a '+', then we only set the group to be the forced
498 * group if the forced user is a member of that group.
499 * Otherwise, the meaning of the '+' would be ignored.
501 if (conn->force_user && user_must_be_member) {
502 if (user_in_group_list( user, gname )) {
504 DEBUG(3,("Forced group %s for member %s\n",gname,user));
508 DEBUG(3,("Forced group %s\n",gname));
511 DEBUG(1,("Couldn't find group %s\n",gname));
513 *status = NT_STATUS_NO_SUCH_GROUP;
517 #endif /* HAVE_GETGRNAM */
521 pstrcpy(s,lp_pathname(snum));
522 standard_sub_conn(conn,s,sizeof(s));
523 string_set(&conn->connectpath,s);
524 DEBUG(3,("Connect path is %s\n",s));
527 /* groups stuff added by ih */
531 /* Find all the groups this uid is in and
532 store them. Used by change_to_user() */
533 initialise_groups(conn->user, conn->uid, conn->gid);
534 get_current_groups(conn->gid, &conn->ngroups,&conn->groups);
536 conn->nt_user_token = create_nt_token(conn->uid, conn->gid,
537 conn->ngroups, conn->groups,
541 * New code to check if there's a share security descripter
542 * added from NT server manager. This is done after the
543 * smb.conf checks are done as we need a uid and token. JRA.
547 BOOL can_write = share_access_check(conn, snum, vuser, FILE_WRITE_DATA);
550 if (!share_access_check(conn, snum, vuser, FILE_READ_DATA)) {
551 /* No access, read or write. */
552 DEBUG(0,( "make_connection: connection to %s denied due to security descriptor.\n",
553 lp_servicename(snum)));
555 *status = NT_STATUS_ACCESS_DENIED;
558 conn->read_only = True;
562 /* Initialise VFS function pointers */
564 if (!smbd_vfs_init(conn)) {
565 DEBUG(0, ("vfs_init failed for service %s\n", lp_servicename(SNUM(conn))));
567 *status = NT_STATUS_UNSUCCESSFUL;
571 /* ROOT Activities: */
572 /* check number of connections */
573 if (!claim_connection(conn,
574 lp_servicename(SNUM(conn)),
575 lp_max_connections(SNUM(conn)),
577 DEBUG(1,("too many connections - rejected\n"));
579 *status = NT_STATUS_INSUFFICIENT_RESOURCES;
583 /* Preexecs are done here as they might make the dir we are to ChDir to below */
584 /* execute any "root preexec = " line */
585 if (*lp_rootpreexec(SNUM(conn))) {
588 pstrcpy(cmd,lp_rootpreexec(SNUM(conn)));
589 standard_sub_conn(conn,cmd,sizeof(cmd));
590 DEBUG(5,("cmd=%s\n",cmd));
591 ret = smbrun(cmd,NULL);
592 if (ret != 0 && lp_rootpreexec_close(SNUM(conn))) {
593 DEBUG(1,("root preexec gave %d - failing connection\n", ret));
594 yield_connection(conn, lp_servicename(SNUM(conn)));
596 *status = NT_STATUS_UNSUCCESSFUL;
601 /* USER Activites: */
602 if (!change_to_user(conn, conn->vuid)) {
603 /* No point continuing if they fail the basic checks */
604 DEBUG(0,("Can't become connected user!\n"));
606 *status = NT_STATUS_LOGON_FAILURE;
610 /* Remember that a different vuid can connect later without these checks... */
612 /* Preexecs are done here as they might make the dir we are to ChDir to below */
613 /* execute any "preexec = " line */
614 if (*lp_preexec(SNUM(conn))) {
617 pstrcpy(cmd,lp_preexec(SNUM(conn)));
618 standard_sub_conn(conn,cmd,sizeof(cmd));
619 ret = smbrun(cmd,NULL);
620 if (ret != 0 && lp_preexec_close(SNUM(conn))) {
621 DEBUG(1,("preexec gave %d - failing connection\n", ret));
622 change_to_root_user();
623 yield_connection(conn, lp_servicename(SNUM(conn)));
625 *status = NT_STATUS_UNSUCCESSFUL;
630 #if CHECK_PATH_ON_TCONX
631 /* win2000 does not check the permissions on the directory
632 during the tree connect, instead relying on permission
633 check during individual operations. To match this behaviour
634 I have disabled this chdir check (tridge) */
635 if (vfs_ChDir(conn,conn->connectpath) != 0) {
636 DEBUG(0,("%s (%s) Can't change directory to %s (%s)\n",
637 remote_machine, conn->client_address,
638 conn->connectpath,strerror(errno)));
639 change_to_root_user();
640 yield_connection(conn, lp_servicename(SNUM(conn)));
642 *status = NT_STATUS_BAD_NETWORK_NAME;
646 /* the alternative is just to check the directory exists */
647 if (stat(conn->connectpath, &st) != 0 || !S_ISDIR(st.st_mode)) {
648 DEBUG(0,("'%s' is not a directory, when connecting to [%s]\n", conn->connectpath, lp_servicename(SNUM(conn))));
649 change_to_root_user();
650 yield_connection(conn, lp_servicename(SNUM(conn)));
652 *status = NT_STATUS_BAD_NETWORK_NAME;
657 string_set(&conn->origpath,conn->connectpath);
659 #if SOFTLINK_OPTIMISATION
660 /* resolve any soft links early if possible */
661 if (vfs_ChDir(conn,conn->connectpath) == 0) {
663 pstrcpy(s,conn->connectpath);
665 string_set(&conn->connectpath,s);
666 vfs_ChDir(conn,conn->connectpath);
671 * Print out the 'connected as' stuff here as we need
672 * to know the effective uid and gid we will be using
673 * (at least initially).
676 if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) {
677 dbgtext( "%s (%s) ", remote_machine, conn->client_address );
678 dbgtext( "connect to service %s ", lp_servicename(SNUM(conn)) );
679 dbgtext( "initially as user %s ", user );
680 dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
681 dbgtext( "(pid %d)\n", (int)sys_getpid() );
684 /* Add veto/hide lists */
685 if (!IS_IPC(conn) && !IS_PRINT(conn)) {
686 set_namearray( &conn->veto_list, lp_veto_files(SNUM(conn)));
687 set_namearray( &conn->hide_list, lp_hide_files(SNUM(conn)));
688 set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(SNUM(conn)));
691 /* Invoke VFS make connection hook */
693 if (conn->vfs_ops.connect) {
694 if (conn->vfs_ops.connect(conn, lp_servicename(snum), user) < 0) {
695 DEBUG(0,("make_connection: VFS make connection failed!\n"));
696 change_to_root_user();
698 *status = NT_STATUS_UNSUCCESSFUL;
703 /* we've finished with the user stuff - go back to root */
704 change_to_root_user();
709 /***************************************************************************************
710 Simple wrapper function for make_connection() to include a call to
712 **************************************************************************************/
714 connection_struct *make_connection_with_chdir(const char *service_in, DATA_BLOB password,
715 char *dev, uint16 vuid, NTSTATUS *status)
717 connection_struct *conn = NULL;
719 conn = make_connection(service_in, password, dev, vuid, status);
722 * make_connection() does not change the directory for us any more
723 * so we have to do it as a separate step --jerry
726 if ( conn && vfs_ChDir(conn,conn->connectpath) != 0 ) {
727 DEBUG(0,("move_driver_to_download_area: Can't change directory to %s for [print$] (%s)\n",
728 conn->connectpath,strerror(errno)));
729 yield_connection(conn, lp_servicename(SNUM(conn)));
731 *status = NT_STATUS_UNSUCCESSFUL;
738 /****************************************************************************
739 Make a connection to a service.
742 ****************************************************************************/
744 connection_struct *make_connection(const char *service_in, DATA_BLOB password,
745 char *dev, uint16 vuid, NTSTATUS *status)
748 user_struct *vuser = NULL;
752 /* This must ONLY BE CALLED AS ROOT. As it exits this function as root. */
753 if (!non_root_mode() && (euid = geteuid()) != 0) {
754 DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot (%u)\n", (unsigned int)euid ));
755 smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
758 if(lp_security() != SEC_SHARE) {
759 vuser = get_valid_user_struct(vuid);
761 DEBUG(1,("make_connection: refusing to connect with no session setup\n"));
766 /* Logic to try and connect to the correct [homes] share, preferably without too many
767 getpwnam() lookups. This is particulary nasty for winbind usernames, where the
768 share name isn't the same as unix username.
770 The snum of the homes share is stored on the vuser at session setup time.
773 if (strequal(service_in,HOMES_NAME)) {
774 if(lp_security() != SEC_SHARE) {
775 DATA_BLOB no_pw = data_blob(NULL, 0);
776 if (vuser->homes_snum != -1) {
777 DEBUG(5, ("making a connection to [homes] service created at session setup time\n"));
778 return make_connection_snum(vuser->homes_snum,
783 /* Security = share. Try with current_user_info.smb_name
784 * as the username. */
785 if (*current_user_info.smb_name) {
786 fstring unix_username;
787 fstrcpy(unix_username,
788 current_user_info.smb_name);
789 map_username(unix_username);
790 snum = find_service(unix_username);
793 DEBUG(5, ("making a connection to 'homes' service %s based on security=share\n", service_in));
794 return make_connection_snum(snum, NULL,
799 } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
800 && strequal(service_in, lp_servicename(vuser->homes_snum))) {
801 DATA_BLOB no_pw = data_blob(NULL, 0);
802 DEBUG(5, ("making a connection to 'homes' service [%s] created at session setup time\n", service));
803 return make_connection_snum(vuser->homes_snum,
808 pstrcpy(service, service_in);
812 snum = find_service(service);
815 if (strequal(service,"IPC$") || strequal(service,"ADMIN$")) {
816 DEBUG(3,("refusing IPC connection to %s\n", service));
817 *status = NT_STATUS_ACCESS_DENIED;
821 DEBUG(0,("%s (%s) couldn't find service %s\n",
822 remote_machine, client_addr(), service));
823 *status = NT_STATUS_BAD_NETWORK_NAME;
827 DEBUG(5, ("making a connection to 'normal' service %s\n", service));
829 return make_connection_snum(snum, vuser,
834 /****************************************************************************
836 ****************************************************************************/
837 void close_cnum(connection_struct *conn, uint16 vuid)
839 DirCacheFlush(SNUM(conn));
841 change_to_root_user();
843 DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n",
844 remote_machine,conn->client_address,
845 lp_servicename(SNUM(conn))));
847 if (conn->vfs_ops.disconnect != NULL) {
849 /* Call VFS disconnect hook */
851 conn->vfs_ops.disconnect(conn);
855 yield_connection(conn, lp_servicename(SNUM(conn)));
857 file_close_conn(conn);
858 dptr_closecnum(conn);
860 /* execute any "postexec = " line */
861 if (*lp_postexec(SNUM(conn)) &&
862 change_to_user(conn, vuid)) {
864 pstrcpy(cmd,lp_postexec(SNUM(conn)));
865 standard_sub_conn(conn,cmd,sizeof(cmd));
867 change_to_root_user();
870 change_to_root_user();
871 /* execute any "root postexec = " line */
872 if (*lp_rootpostexec(SNUM(conn))) {
874 pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
875 standard_sub_conn(conn,cmd,sizeof(cmd));
879 /* make sure we leave the directory available for unmount */
880 vfs_ChDir(conn, "/");