diff options
Diffstat (limited to 'source3/smbd/service.c')
-rw-r--r-- | source3/smbd/service.c | 391 |
1 files changed, 123 insertions, 268 deletions
diff --git a/source3/smbd/service.c b/source3/smbd/service.c index df930575d30..0ae49b7adfa 100644 --- a/source3/smbd/service.c +++ b/source3/smbd/service.c @@ -78,9 +78,12 @@ BOOL set_current_service(connection_struct *conn,BOOL do_chdir) Add a home service. Returns the new service number or -1 if fail. ****************************************************************************/ -int add_home_service(const char *service, const char *username, const char *homedir) +int add_home_service(const char *service, const char *homedir) { int iHomeService; + int iService; + fstring new_service; + fstring domain; if (!service || !homedir) return -1; @@ -95,19 +98,11 @@ int add_home_service(const char *service, const char *username, const char *home * include any macros. */ - { - const char *p = strchr(service,*lp_winbind_separator()); - - /* We only want the 'user' part of the string */ - if (p) { - service = p + 1; - } - } - - lp_add_home(service, iHomeService, username, homedir); - - return lp_servicenumber(service); + split_domain_and_name(service, domain, new_service); + lp_add_home(new_service, iHomeService, homedir); + iService = lp_servicenumber(new_service); + return iService; } @@ -127,7 +122,7 @@ int find_service(fstring service) /* now handle the special case of a home directory */ if (iService < 0) { - char *phome_dir = get_user_home_dir(service); + char *phome_dir = get_user_service_home_dir(service); if(!phome_dir) { @@ -136,13 +131,13 @@ int find_service(fstring service) * be a Windows to unix mapped user name. */ if(map_username(service)) - phome_dir = get_user_home_dir(service); + phome_dir = get_user_service_home_dir(service); } DEBUG(3,("checking for home directory %s gave %s\n",service, phome_dir?phome_dir:"(NULL)")); - iService = add_home_service(service,service /* 'username' */, phome_dir); + iService = add_home_service(service,phome_dir); } /* If we still don't have a service, attempt to add it as a printer. */ @@ -218,7 +213,7 @@ int find_service(fstring service) do some basic sainity checks on the share. This function modifies dev, ecode. ****************************************************************************/ -static NTSTATUS share_sanity_checks(int snum, pstring dev) +static NTSTATUS share_sanity_checks(int snum, const char* service, pstring dev) { if (!lp_snum_ok(snum) || @@ -228,7 +223,7 @@ static NTSTATUS share_sanity_checks(int snum, pstring dev) } /* you can only connect to the IPC$ service as an ipc device */ - if (strequal(lp_fstype(snum), "IPC")) + if (strequal(service,"IPC$") || strequal(service,"ADMIN$")) pstrcpy(dev,"IPC"); if (dev[0] == '?' || !dev[0]) { @@ -266,24 +261,24 @@ static void set_read_only(connection_struct *conn) if (!service) return; - str_list_copy(&list, lp_readlist(conn->service)); + lp_list_copy(&list, lp_readlist(conn->service)); if (list) { - if (!str_list_substitute(list, "%S", service)) { + if (!lp_list_substitute(list, "%S", service)) { DEBUG(0, ("ERROR: read list substitution failed\n")); } if (user_in_list(conn->user, list)) conn->read_only = True; - str_list_free(&list); + lp_list_free(&list); } - str_list_copy(&list, lp_writelist(conn->service)); + lp_list_copy(&list, lp_writelist(conn->service)); if (list) { - if (!str_list_substitute(list, "%S", service)) { + if (!lp_list_substitute(list, "%S", service)) { DEBUG(0, ("ERROR: write list substitution failed\n")); } if (user_in_list(conn->user, list)) conn->read_only = False; - str_list_free(&list); + lp_list_free(&list); } } @@ -319,26 +314,89 @@ static void set_admin_user(connection_struct *conn) } /**************************************************************************** - Make a connection, given the snum to connect to, and the vuser of the - connecting user if appropriate. + Make a connection to a service. + * + * @param service (May be modified to canonical form???) ****************************************************************************/ -static connection_struct *make_connection_snum(int snum, user_struct *vuser, - DATA_BLOB password, - char *dev, NTSTATUS *status) +connection_struct *make_connection(char *service, DATA_BLOB password, + char *dev, uint16 vuid, NTSTATUS *status) { + int snum; struct passwd *pass = NULL; BOOL guest = False; BOOL force = False; connection_struct *conn; - struct stat st; + uid_t euid; + fstring user; - *user = 0; + ZERO_STRUCT(user); + + /* This must ONLY BE CALLED AS ROOT. As it exits this function as root. */ + if (!non_root_mode() && (euid = geteuid()) != 0) { + DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot (%u)\n", (unsigned int)euid )); + smb_panic("make_connection: PANIC ERROR. Called as nonroot\n"); + } + + strlower(service); + + snum = find_service(service); + + if (snum < 0) { + if (strequal(service,"IPC$") || strequal(service,"ADMIN$")) { + DEBUG(3,("refusing IPC connection\n")); + *status = NT_STATUS_ACCESS_DENIED; + return NULL; + } + + DEBUG(0,("%s (%s) couldn't find service %s\n", + remote_machine, client_addr(), service)); + *status = NT_STATUS_BAD_NETWORK_NAME; + return NULL; + } + + if (strequal(service,HOMES_NAME)) { + if(lp_security() != SEC_SHARE) { + if (validated_username(vuid)) { + fstring unix_username; + fstrcpy(unix_username,validated_username(vuid)); + return make_connection(unix_username, + password,dev,vuid,status); + } + } else { + /* Security = share. Try with current_user_info.smb_name + * as the username. */ + if (* current_user_info.smb_name) { + fstring unix_username; + fstrcpy(unix_username, + current_user_info.smb_name); + map_username(unix_username); + return make_connection(unix_username, + password,dev,vuid,status); + } + } + } - if (NT_STATUS_IS_ERR(*status = share_sanity_checks(snum, dev))) { + if (NT_STATUS_IS_ERR(*status = share_sanity_checks(snum, service, dev))) { return NULL; } + /* add it as a possible user name if we + are in share mode security */ + if (lp_security() == SEC_SHARE) { + add_session_user(service); + } + + + /* shall we let them in? */ + if (!authorise_login(snum,user,password,&guest,&force,vuid)) { + DEBUG( 2, ( "Invalid username/password for %s [%s]\n", service, user ) ); + *status = NT_STATUS_WRONG_PASSWORD; + return NULL; + } + + add_session_user(user); + conn = conn_new(); if (!conn) { DEBUG(0,("Couldn't find free connection.\n")); @@ -346,72 +404,20 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, return NULL; } - if (lp_guest_only(snum)) { - char *guestname = lp_guestaccount(); - guest = True; - force = True; - pass = getpwnam_alloc(guestname); - if (!pass) { - DEBUG(0,("authorise_login: Invalid guest account %s??\n",guestname)); - conn_free(conn); - *status = NT_STATUS_NO_SUCH_USER; - return NULL; - } - fstrcpy(user,pass->pw_name); - conn->force_user = True; - string_set(&conn->user,pass->pw_name); - passwd_free(&pass); - DEBUG(3,("Guest only user %s\n",user)); - } else if (vuser) { - if (vuser->guest) { - if (!lp_guest_ok(snum)) { - DEBUG(2, ("guest user (from session setup) not permitted to access this share (%s)", lp_servicename(snum))); - conn_free(conn); - *status = NT_STATUS_ACCESS_DENIED; - return NULL; - } - } else { - if (!user_ok(vuser->user.unix_name, snum)) { - DEBUG(2, ("user '%s' (from session setup) not permitted to access this share (%s)", vuser->user.unix_name, lp_servicename(snum))); - conn_free(conn); - *status = NT_STATUS_ACCESS_DENIED; - return NULL; - } - } - conn->vuid = vuser->vuid; - conn->uid = vuser->uid; - conn->gid = vuser->gid; - string_set(&conn->user,vuser->user.unix_name); - fstrcpy(user,vuser->user.unix_name); - guest = vuser->guest; - } else if (lp_security() == SEC_SHARE) { - /* add it as a possible user name if we - are in share mode security */ - add_session_user(lp_servicename(snum)); - /* shall we let them in? */ - if (!authorise_login(snum,user,password,&guest)) { - DEBUG( 2, ( "Invalid username/password for [%s]\n", - lp_servicename(snum)) ); - conn_free(conn); - *status = NT_STATUS_WRONG_PASSWORD; - return NULL; - } - pass = Get_Pwnam(user); - conn->force_user = force; - conn->uid = pass->pw_uid; - conn->gid = pass->pw_gid; - string_set(&conn->user, pass->pw_name); - fstrcpy(user, pass->pw_name); + /* find out some info about the user */ + pass = smb_getpwnam(user,True); - } else { - DEBUG(0, ("invalid VUID (vuser) but not in security=share\n")); + if (pass == NULL) { + DEBUG(0,( "Couldn't find account %s\n",user)); + *status = NT_STATUS_NO_SUCH_USER; conn_free(conn); - *status = NT_STATUS_ACCESS_DENIED; return NULL; } - add_session_user(user); - + conn->force_user = force; + conn->vuid = vuid; + conn->uid = pass->pw_uid; + conn->gid = pass->pw_gid; safe_strcpy(conn->client_address, client_addr(), sizeof(conn->client_address)-1); conn->num_files_open = 0; @@ -444,21 +450,18 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, pstrcpy(fuser,lp_force_user(snum)); /* Allow %S to be used by force user. */ - pstring_sub(fuser,"%S",lp_servicename(snum)); + pstring_sub(fuser,"%S",service); - pass2 = (struct passwd *)Get_Pwnam(fuser); + pass2 = (struct passwd *)Get_Pwnam_Modify(fuser); if (pass2) { conn->uid = pass2->pw_uid; conn->gid = pass2->pw_gid; - string_set(&conn->user,pass2->pw_name); - fstrcpy(user,pass2->pw_name); + string_set(&conn->user,fuser); + fstrcpy(user,fuser); conn->force_user = True; - DEBUG(3,("Forced user %s\n",user)); + DEBUG(3,("Forced user %s\n",fuser)); } else { DEBUG(1,("Couldn't find user %s\n",fuser)); - conn_free(conn); - *status = NT_STATUS_NO_SUCH_USER; - return NULL; } } @@ -480,7 +483,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, BOOL user_must_be_member = False; StrnCpy(tmp_gname,lp_force_group(snum),sizeof(pstring)-1); - + if (tmp_gname[0] == '+') { user_must_be_member = True; StrnCpy(gname,&tmp_gname[1],sizeof(pstring)-2); @@ -488,7 +491,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, StrnCpy(gname,tmp_gname,sizeof(pstring)-1); } /* default service may be a group name */ - pstring_sub(gname,"%S",lp_servicename(snum)); + pstring_sub(gname,"%S",service); gid = nametogid(gname); if (gid != (gid_t)-1) { @@ -509,9 +512,6 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, } } else { DEBUG(1,("Couldn't find group %s\n",gname)); - conn_free(conn); - *status = NT_STATUS_NO_SUCH_GROUP; - return NULL; } } #endif /* HAVE_GETGRNAM */ @@ -519,7 +519,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, { pstring s; pstrcpy(s,lp_pathname(snum)); - standard_sub_conn(conn,s,sizeof(s)); + standard_sub_conn(conn,s); string_set(&conn->connectpath,s); DEBUG(3,("Connect path is %s\n",s)); } @@ -544,15 +544,15 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, */ { - BOOL can_write = share_access_check(conn, snum, vuser, FILE_WRITE_DATA); + BOOL can_write = share_access_check(conn, snum, vuid, FILE_WRITE_DATA); if (!can_write) { - if (!share_access_check(conn, snum, vuser, FILE_READ_DATA)) { + if (!share_access_check(conn, snum, vuid, FILE_READ_DATA)) { /* No access, read or write. */ + *status = NT_STATUS_ACCESS_DENIED; DEBUG(0,( "make_connection: connection to %s denied due to security descriptor.\n", - lp_servicename(snum))); + service )); conn_free(conn); - *status = NT_STATUS_ACCESS_DENIED; return NULL; } else { conn->read_only = True; @@ -564,7 +564,6 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, if (!smbd_vfs_init(conn)) { DEBUG(0, ("vfs_init failed for service %s\n", lp_servicename(SNUM(conn)))); conn_free(conn); - *status = NT_STATUS_UNSUCCESSFUL; return NULL; } @@ -575,8 +574,8 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, lp_max_connections(SNUM(conn)), False)) { DEBUG(1,("too many connections - rejected\n")); - conn_free(conn); *status = NT_STATUS_INSUFFICIENT_RESOURCES; + conn_free(conn); return NULL; } @@ -586,7 +585,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, int ret; pstring cmd; pstrcpy(cmd,lp_rootpreexec(SNUM(conn))); - standard_sub_conn(conn,cmd,sizeof(cmd)); + standard_sub_conn(conn,cmd); DEBUG(5,("cmd=%s\n",cmd)); ret = smbrun(cmd,NULL); if (ret != 0 && lp_rootpreexec_close(SNUM(conn))) { @@ -606,16 +605,16 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, *status = NT_STATUS_LOGON_FAILURE; return NULL; } - + /* Remember that a different vuid can connect later without these checks... */ - + /* Preexecs are done here as they might make the dir we are to ChDir to below */ /* execute any "preexec = " line */ if (*lp_preexec(SNUM(conn))) { int ret; pstring cmd; pstrcpy(cmd,lp_preexec(SNUM(conn))); - standard_sub_conn(conn,cmd,sizeof(cmd)); + standard_sub_conn(conn,cmd); ret = smbrun(cmd,NULL); if (ret != 0 && lp_preexec_close(SNUM(conn))) { DEBUG(1,("preexec gave %d - failing connection\n", ret)); @@ -626,12 +625,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, return NULL; } } - -#if CHECK_PATH_ON_TCONX - /* win2000 does not check the permissions on the directory - during the tree connect, instead relying on permission - check during individual operations. To match this behaviour - I have disabled this chdir check (tridge) */ + if (vfs_ChDir(conn,conn->connectpath) != 0) { DEBUG(0,("%s (%s) Can't change directory to %s (%s)\n", remote_machine, conn->client_address, @@ -642,23 +636,12 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, *status = NT_STATUS_BAD_NETWORK_NAME; return NULL; } -#else - /* the alternative is just to check the directory exists */ - if (stat(conn->connectpath, &st) != 0 || !S_ISDIR(st.st_mode)) { - DEBUG(0,("%s is not a directory\n", conn->connectpath)); - change_to_root_user(); - yield_connection(conn, lp_servicename(SNUM(conn))); - conn_free(conn); - *status = NT_STATUS_BAD_NETWORK_NAME; - return NULL; - } -#endif string_set(&conn->origpath,conn->connectpath); #if SOFTLINK_OPTIMISATION - /* resolve any soft links early if possible */ - if (vfs_ChDir(conn,conn->connectpath) == 0) { + /* resolve any soft links early */ + { pstring s; pstrcpy(s,conn->connectpath); vfs_GetWd(conn,s); @@ -691,11 +674,11 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, /* Invoke VFS make connection hook */ if (conn->vfs_ops.connect) { - if (conn->vfs_ops.connect(conn, lp_servicename(snum), user) < 0) { + if (conn->vfs_ops.connect(conn, service, user) < 0) { DEBUG(0,("make_connection: VFS make connection failed!\n")); + *status = NT_STATUS_UNSUCCESSFUL; change_to_root_user(); conn_free(conn); - *status = NT_STATUS_UNSUCCESSFUL; return NULL; } } @@ -706,130 +689,6 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, return(conn); } -/*************************************************************************************** - Simple wrapper function for make_connection() to include a call to - vfs_chdir() - **************************************************************************************/ - -connection_struct *make_connection_with_chdir(const char *service_in, DATA_BLOB password, - char *dev, uint16 vuid, NTSTATUS *status) -{ - connection_struct *conn = NULL; - - conn = make_connection(service_in, password, dev, vuid, status); - - /* - * make_connection() does not change the directory for us any more - * so we have to do it as a separate step --jerry - */ - - if ( conn && vfs_ChDir(conn,conn->connectpath) != 0 ) { - DEBUG(0,("move_driver_to_download_area: Can't change directory to %s for [print$] (%s)\n", - conn->connectpath,strerror(errno))); - yield_connection(conn, lp_servicename(SNUM(conn))); - conn_free(conn); - *status = NT_STATUS_UNSUCCESSFUL; - return NULL; - } - - return conn; -} - -/**************************************************************************** - Make a connection to a service. - * - * @param service -****************************************************************************/ - -connection_struct *make_connection(const char *service_in, DATA_BLOB password, - char *dev, uint16 vuid, NTSTATUS *status) -{ - uid_t euid; - user_struct *vuser = NULL; - pstring service; - int snum = -1; - - /* This must ONLY BE CALLED AS ROOT. As it exits this function as root. */ - if (!non_root_mode() && (euid = geteuid()) != 0) { - DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot (%u)\n", (unsigned int)euid )); - smb_panic("make_connection: PANIC ERROR. Called as nonroot\n"); - } - - if(lp_security() != SEC_SHARE) { - vuser = get_valid_user_struct(vuid); - if (!vuser) { - DEBUG(1,("make_connection: refusing to connect with no session setup\n")); - return NULL; - } - } - - /* Logic to try and connect to the correct [homes] share, preferably without too many - getpwnam() lookups. This is particulary nasty for winbind usernames, where the - share name isn't the same as unix username. - - The snum of the homes share is stored on the vuser at session setup time. - */ - - if (strequal(service_in,HOMES_NAME)) { - if(lp_security() != SEC_SHARE) { - DATA_BLOB no_pw = data_blob(NULL, 0); - if (vuser->homes_snum != -1) { - DEBUG(5, ("making a connection to [homes] service created at session setup time\n")); - return make_connection_snum(vuser->homes_snum, - vuser, no_pw, - dev, status); - } - } else { - /* Security = share. Try with current_user_info.smb_name - * as the username. */ - if (*current_user_info.smb_name) { - fstring unix_username; - fstrcpy(unix_username, - current_user_info.smb_name); - map_username(unix_username); - snum = find_service(unix_username); - } - if (snum != -1) { - DEBUG(5, ("making a connection to 'homes' service %s based on security=share\n", service_in)); - return make_connection_snum(snum, NULL, - password, - dev, status); - } - } - } else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1) - && strequal(service, lp_servicename(vuser->homes_snum))) { - DATA_BLOB no_pw = data_blob(NULL, 0); - DEBUG(5, ("making a connection to 'homes' service [%s] created at session setup time\n", service)); - return make_connection_snum(vuser->homes_snum, - vuser, no_pw, - dev, status); - } - - pstrcpy(service, service_in); - - strlower(service); - - snum = find_service(service); - - if (snum < 0) { - if (strequal(service,"IPC$") || strequal(service,"ADMIN$")) { - DEBUG(3,("refusing IPC connection to %s\n", service)); - *status = NT_STATUS_ACCESS_DENIED; - return NULL; - } - - DEBUG(0,("%s (%s) couldn't find service %s\n", - remote_machine, client_addr(), service)); - *status = NT_STATUS_BAD_NETWORK_NAME; - return NULL; - } - - DEBUG(5, ("making a connection to 'normal' service %s\n", service)); - - return make_connection_snum(snum, vuser, - password, - dev, status); -} /**************************************************************************** close a cnum @@ -862,7 +721,7 @@ void close_cnum(connection_struct *conn, uint16 vuid) change_to_user(conn, vuid)) { pstring cmd; pstrcpy(cmd,lp_postexec(SNUM(conn))); - standard_sub_conn(conn,cmd,sizeof(cmd)); + standard_sub_conn(conn,cmd); smbrun(cmd,NULL); change_to_root_user(); } @@ -872,12 +731,8 @@ void close_cnum(connection_struct *conn, uint16 vuid) if (*lp_rootpostexec(SNUM(conn))) { pstring cmd; pstrcpy(cmd,lp_rootpostexec(SNUM(conn))); - standard_sub_conn(conn,cmd,sizeof(cmd)); + standard_sub_conn(conn,cmd); smbrun(cmd,NULL); } - - /* make sure we leave the directory available for unmount */ - vfs_ChDir(conn, "/"); - conn_free(conn); } |