diff options
Diffstat (limited to 'source/smbd/service.c')
-rw-r--r-- | source/smbd/service.c | 262 |
1 files changed, 118 insertions, 144 deletions
diff --git a/source/smbd/service.c b/source/smbd/service.c index 64abf3de1dd..92807e2d439 100644 --- a/source/smbd/service.c +++ b/source/smbd/service.c @@ -23,7 +23,7 @@ extern int DEBUGLEVEL; -extern time_t smb_last_time; +extern struct timeval smb_last_time; extern int case_default; extern BOOL case_preserve; extern BOOL short_case_preserve; @@ -49,7 +49,7 @@ BOOL become_service(connection_struct *conn,BOOL do_chdir) return(False); } - conn->lastused = smb_last_time; + conn->lastused = smb_last_time.tv_sec; snum = SNUM(conn); @@ -84,24 +84,23 @@ int find_service(char *service) { int iService; - string_sub(service,"\\","/"); + all_string_sub(service,"\\","/",0); iService = lp_servicenumber(service); /* now handle the special case of a home directory */ if (iService < 0) { - char *phome_dir = get_unixhome_dir(service); - pstring home_dir; + char *phome_dir = get_user_home_dir(service); - if(phome_dir == NULL) + if(!phome_dir) { /* * Try mapping the servicename, it may * be a Windows to unix mapped user name. */ if(map_username(service)) - phome_dir = get_unixhome_dir(service); + phome_dir = get_user_home_dir(service); } DEBUG(3,("checking for home directory %s gave %s\n",service, @@ -110,10 +109,9 @@ int find_service(char *service) if (phome_dir) { int iHomeService; - pstrcpy(home_dir, phome_dir); if ((iHomeService = lp_servicenumber(HOMES_NAME)) >= 0) { - lp_add_home(service,iHomeService,home_dir); + lp_add_home(service,iHomeService,phome_dir); iService = lp_servicenumber(service); } } @@ -144,11 +142,6 @@ int find_service(char *service) } } - /* Check for default vfs service? Unsure whether to implement this */ - if (iService < 0) - { - } - /* just possibly it's a default service? */ if (iService < 0) { @@ -168,7 +161,7 @@ int find_service(char *service) iService = find_service(defservice); if (iService >= 0) { - string_sub(service,"_","/"); + all_string_sub(service,"_","/",0); iService = lp_add_service(service,iService); } } @@ -194,11 +187,12 @@ int find_service(char *service) connection_struct *make_connection(char *service,char *user,char *password, int pwlen, char *dev,uint16 vuid, int *ecode) { int snum; - const struct passwd *pass = NULL; + struct passwd *pass = NULL; BOOL guest = False; BOOL force = False; extern int Client; connection_struct *conn; + int ret; strlower(service); @@ -218,21 +212,31 @@ connection_struct *make_connection(char *service,char *user,char *password, int } if (strequal(service,HOMES_NAME)) { - if (*user && Get_Pwnam(user,True)) - return(make_connection(user,user,password, + if (*user && Get_Pwnam(user,True)) { + fstring dos_username; + fstrcpy(dos_username, user); + unix_to_dos(dos_username, True); + return(make_connection(dos_username,user,password, pwlen,dev,vuid,ecode)); + } if(lp_security() != SEC_SHARE) { if (validated_username(vuid)) { - pstrcpy(user,validated_username(vuid)); - return(make_connection(user,user,password,pwlen,dev,vuid,ecode)); + fstring dos_username; + fstrcpy(user,validated_username(vuid)); + fstrcpy(dos_username, user); + unix_to_dos(dos_username, True); + return(make_connection(dos_username,user,password,pwlen,dev,vuid,ecode)); } } else { /* Security = share. Try with sesssetup_user * as the username. */ if(*sesssetup_user) { - pstrcpy(user,sesssetup_user); - return(make_connection(user,user,password,pwlen,dev,vuid,ecode)); + fstring dos_username; + fstrcpy(user,sesssetup_user); + fstrcpy(dos_username, user); + unix_to_dos(dos_username, True); + return(make_connection(dos_username,user,password,pwlen,dev,vuid,ecode)); } } } @@ -300,13 +304,13 @@ connection_struct *make_connection(char *service,char *user,char *password, int { pstring list; StrnCpy(list,lp_readlist(snum),sizeof(pstring)-1); - string_sub(list,"%S",service); + pstring_sub(list,"%S",service); if (user_in_list(user,list)) conn->read_only = True; StrnCpy(list,lp_writelist(snum),sizeof(pstring)-1); - string_sub(list,"%S",service); + pstring_sub(list,"%S",service); if (user_in_list(user,list)) conn->read_only = False; @@ -333,6 +337,7 @@ connection_struct *make_connection(char *service,char *user,char *password, int conn->vuid = vuid; conn->uid = pass->pw_uid; conn->gid = pass->pw_gid; + safe_strcpy(conn->client_address, client_addr(Client), sizeof(conn->client_address)-1); conn->num_files_open = 0; conn->lastused = time(NULL); conn->service = snum; @@ -345,65 +350,83 @@ connection_struct *make_connection(char *service,char *user,char *password, int conn->veto_oplock_list = NULL; string_set(&conn->dirpath,""); string_set(&conn->user,user); + + /* + * If force user is true, then store the + * given userid and also the primary groupid + * of the user we're forcing. + */ + + if (*lp_force_user(snum)) { + struct passwd *pass2; + pstring fuser; + pstrcpy(fuser,lp_force_user(snum)); - /* Initialise VFS function pointers */ - - if (*lp_vfsobj(SNUM(conn))) { - -#ifdef HAVE_LIBDL - - /* Loadable object file */ - - if (!vfs_init_custom(conn)) { - return NULL; - } -#else - DEBUG(0, ("No libdl present - cannot use VFS objects\n")); - conn_free(conn); - return NULL; -#endif - - } else { - - /* Normal share - initialise with disk access functions */ + /* Allow %S to be used by force user. */ + pstring_sub(fuser,"%S",service); - vfs_init_default(conn); + pass2 = (struct passwd *)Get_Pwnam(fuser,True); + if (pass2) { + conn->uid = pass2->pw_uid; + conn->gid = pass2->pw_gid; + string_set(&conn->user,fuser); + fstrcpy(user,fuser); + conn->force_user = True; + DEBUG(3,("Forced user %s\n",fuser)); + } else { + DEBUG(1,("Couldn't find user %s\n",fuser)); + } } #ifdef HAVE_GETGRNAM + /* + * If force group is true, then override + * any groupid stored for the connecting user. + */ + if (*lp_force_group(snum)) { struct group *gptr; pstring gname; + pstring tmp_gname; + BOOL user_must_be_member = False; - StrnCpy(gname,lp_force_group(snum),sizeof(pstring)-1); + 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); + } else { + StrnCpy(gname,tmp_gname,sizeof(pstring)-1); + } /* default service may be a group name */ - string_sub(gname,"%S",service); + pstring_sub(gname,"%S",service); gptr = (struct group *)getgrnam(gname); if (gptr) { - conn->gid = gptr->gr_gid; - DEBUG(3,("Forced group %s\n",gname)); + /* + * If the user has been forced and the forced group starts + * with a '+', then we only set the group to be the forced + * group if the forced user is a member of that group. + * Otherwise, the meaning of the '+' would be ignored. + */ + if (conn->force_user && user_must_be_member) { + int i; + for (i = 0; gptr->gr_mem[i] != NULL; i++) { + if (strcmp(user,gptr->gr_mem[i]) == 0) { + conn->gid = gptr->gr_gid; + DEBUG(3,("Forced group %s for member %s\n",gname,user)); + break; + } + } + } else { + conn->gid = gptr->gr_gid; + DEBUG(3,("Forced group %s\n",gname)); + } } else { DEBUG(1,("Couldn't find group %s\n",gname)); } } -#endif - - if (*lp_force_user(snum)) { - const struct passwd *pass2; - fstring fuser; - fstrcpy(fuser,lp_force_user(snum)); - pass2 = (const struct passwd *)Get_Pwnam(fuser,True); - if (pass2) { - conn->uid = pass2->pw_uid; - string_set(&conn->user,fuser); - fstrcpy(user,fuser); - conn->force_user = True; - DEBUG(3,("Forced user %s\n",fuser)); - } else { - DEBUG(1,("Couldn't find user %s\n",fuser)); - } - } +#endif /* HAVE_GETGRNAM */ { pstring s; @@ -420,7 +443,7 @@ connection_struct *make_connection(char *service,char *user,char *password, int if (!IS_IPC(conn)) { /* Find all the groups this uid is in and store them. Used by become_user() */ - get_unixgroups(conn->user,conn->uid,conn->gid, + setup_groups(conn->user,conn->uid,conn->gid, &conn->ngroups,&conn->groups); /* check number of connections */ @@ -445,7 +468,13 @@ connection_struct *make_connection(char *service,char *user,char *password, int pstrcpy(cmd,lp_rootpreexec(SNUM(conn))); standard_sub(conn,cmd); DEBUG(5,("cmd=%s\n",cmd)); - smbrun(cmd,NULL,False); + ret = smbrun(cmd,NULL,False); + if (ret != 0 && lp_rootpreexec_close(SNUM(conn))) { + DEBUG(1,("preexec gave %d - failing connection\n", ret)); + conn_free(conn); + *ecode = ERRsrverror; + return NULL; + } } if (!become_user(conn, conn->vuid)) { @@ -499,7 +528,26 @@ connection_struct *make_connection(char *service,char *user,char *password, int pstring cmd; pstrcpy(cmd,lp_preexec(SNUM(conn))); standard_sub(conn,cmd); - smbrun(cmd,NULL,False); + ret = smbrun(cmd,NULL,False); + if (ret != 0 && lp_preexec_close(SNUM(conn))) { + DEBUG(1,("preexec gave %d - failing connection\n", ret)); + conn_free(conn); + *ecode = ERRsrverror; + return NULL; + } + } + + /* + * Print out the 'connected as' stuff here as we need + * to know the effective uid and gid we will be using. + */ + + if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) { + dbgtext( "%s (%s) ", remote_machine, conn->client_address ); + dbgtext( "connect to service %s ", lp_servicename(SNUM(conn)) ); + dbgtext( "as user %s ", user ); + dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() ); + dbgtext( "(pid %d)\n", (int)getpid() ); } /* we've finished with the sensitive stuff */ @@ -512,61 +560,6 @@ connection_struct *make_connection(char *service,char *user,char *password, int set_namearray( &conn->veto_oplock_list, lp_veto_oplocks(SNUM(conn))); } - if( DEBUGLVL( IS_IPC(conn) ? 3 : 1 ) ) { - extern int Client; - - dbgtext( "%s (%s) ", remote_machine, client_addr(Client) ); - dbgtext( "connect to service %s ", lp_servicename(SNUM(conn))); - dbgtext( "as user %s ", user ); - dbgtext( "(uid=%d, gid=%d) ", (int)conn->uid, (int)conn->gid ); - dbgtext( "(pid %d)\n", (int)getpid() ); - } - - /* Invoke make connection hook */ - - if (conn->vfs_ops.connect) { - struct vfs_connection_struct *vconn; - - vconn = (struct vfs_connection_struct *) - malloc(sizeof(struct vfs_connection_struct)); - - if (vconn == NULL) { - DEBUG(0, ("No memory to create vfs_connection_struct")); - return NULL; - } - - ZERO_STRUCTP(vconn); - - /* Copy across relevant data from connection struct */ - - vconn->printer = conn->printer; - vconn->ipc = conn->ipc; - vconn->read_only = conn->read_only; - vconn->admin_user = conn->admin_user; - - pstrcpy(vconn->dirpath, conn->dirpath); - pstrcpy(vconn->connectpath, conn->connectpath); - pstrcpy(vconn->origpath, conn->origpath); - - pstrcpy(vconn->service, service); - pstrcpy(vconn->user, conn->user); - - vconn->uid = conn->uid; - vconn->gid = conn->gid; - vconn->ngroups = conn->ngroups; - vconn->groups = (gid_t *)malloc(conn->ngroups * sizeof(gid_t)); - if (vconn->groups != NULL) { - memcpy(vconn->groups, conn->groups, - conn->ngroups * sizeof(gid_t)); - } - - /* Call connect hook */ - - if (conn->vfs_ops.connect(vconn, service, user) < 0) { - return NULL; - } - } - return(conn); } @@ -576,31 +569,14 @@ close a cnum ****************************************************************************/ void close_cnum(connection_struct *conn, uint16 vuid) { - extern int Client; DirCacheFlush(SNUM(conn)); unbecome_user(); DEBUG(IS_IPC(conn)?3:1, ("%s (%s) closed connection to service %s\n", - remote_machine,client_addr(Client), + remote_machine,conn->client_address, lp_servicename(SNUM(conn)))); - if (conn->vfs_ops.disconnect != NULL) { - - /* Call disconnect hook */ - - conn->vfs_ops.disconnect(); - - /* Free vfs_connection_struct */ - - if (conn->vfs_conn != NULL) { - if (conn->vfs_conn->groups != NULL) { - free(conn->vfs_conn->groups); - } - free(conn->vfs_conn); - } - } - yield_connection(conn, lp_servicename(SNUM(conn)), lp_max_connections(SNUM(conn))); @@ -632,5 +608,3 @@ void close_cnum(connection_struct *conn, uint16 vuid) conn_free(conn); } - - |