From 81e398963dbaed9c6661c336fe98329098576b94 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 1 Jun 1996 15:25:30 +0000 Subject: - moved the uid handling to uid.c - added setfsuid() support (for Linux) - started adding some of Lukes changes, just the loadparm and ipc ones so far (This used to be commit 72543810ce3eb5ea7b141f957edf38b4c46b1ea4) --- source3/include/includes.h | 1 + source3/include/smb.h | 2 + source3/lib/util.c | 31 +--- source3/loadparm.h | 2 + source3/param/loadparm.c | 9 +- source3/smbd/ipc.c | 217 +++++++++++++++++---------- source3/smbd/server.c | 287 +---------------------------------- source3/smbd/smbrun.c | 71 ++++----- source3/smbd/uid.c | 364 +++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 549 insertions(+), 435 deletions(-) create mode 100644 source3/smbd/uid.c diff --git a/source3/include/includes.h b/source3/include/includes.h index dc1fe57e71..8b2821948c 100644 --- a/source3/include/includes.h +++ b/source3/include/includes.h @@ -223,6 +223,7 @@ Here come some platform specific sections #define USE_SETSID #define HAVE_BZERO #define HAVE_MEMMOVE +#define USE_SETFS #ifdef SHADOW_PWD #ifndef crypt #define crypt pw_encrypt diff --git a/source3/include/smb.h b/source3/include/smb.h index 4d99529ef6..3e38f4c37e 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -583,6 +583,8 @@ struct from_host { }; /* and a few prototypes */ +BOOL become_guest(void); +void init_uid(void); BOOL user_ok(char *user,int snum); int sys_rename(char *from, char *to); int sys_select(fd_set *fds,struct timeval *tval); diff --git a/source3/lib/util.c b/source3/lib/util.c index 2ac64d0648..d2f0383532 100644 --- a/source3/lib/util.c +++ b/source3/lib/util.c @@ -3585,34 +3585,6 @@ int PutUniCode(char *dst,char *src) return(ret); } - -pstring smbrun_path = SMBRUN; - -/**************************************************************************** -run a command via system() using smbrun -****************************************************************************/ -int smbrun(char *cmd,char *outfile) -{ - int ret; - pstring syscmd; - - if (!file_exist(smbrun_path,NULL)) - { - DEBUG(0,("SMBRUN ERROR: Can't find %s. Installation problem?\n",smbrun_path)); - return(1); - } - - sprintf(syscmd,"%s \"(%s 2>&1) > %s\"", - smbrun_path,cmd, - outfile?outfile:"/dev/null"); - - DEBUG(5,("smbrun - running %s ",syscmd)); - ret = system(syscmd); - DEBUG(5,("gave %d\n",ret)); - return(ret); -} - - /**************************************************************************** a wrapper for gethostbyname() that tries with all lower and all upper case if the initial name fails @@ -3745,8 +3717,7 @@ my own panic function - not suitable for general use ********************************************************************/ void ajt_panic(void) { - pstring cmd = "/usr/bin/X11/xedit -display :0 /tmp/ERROR_FAULT &"; - smbrun(cmd,NULL); + system("/usr/bin/X11/xedit -display :0 /tmp/ERROR_FAULT &"); } #endif diff --git a/source3/loadparm.h b/source3/loadparm.h index 143c8a2fca..879ff25e67 100644 --- a/source3/loadparm.h +++ b/source3/loadparm.h @@ -43,6 +43,7 @@ extern char *lp_guestaccount(int iService); extern char *lp_printcapname(void); extern char *lp_lockdir(void); extern char *lp_logfile(void); +extern char *lp_smbrun(void); extern char *lp_configfile(void); extern char *lp_smb_passwd_file(void); extern char *lp_rootdir(void); @@ -55,6 +56,7 @@ extern char *lp_domain_controller(void); extern char *lp_username_map(void); extern char *lp_hosts_equiv(void); extern char *lp_logon_script(void); +extern char *lp_wins_server(void); extern char *lp_magicscript(int iService); extern char *lp_magicoutput(int iService); extern char *lp_mangled_map(int iService); diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index e7b9d2d9b8..3426a4022c 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -58,7 +58,6 @@ BOOL bLoaded = False; extern int DEBUGLEVEL; extern int ReadSize; extern pstring user_socket_options; -extern pstring smbrun_path; #ifndef GLOBAL_NAME #define GLOBAL_NAME "global" @@ -132,6 +131,8 @@ typedef struct char *szUsernameMap; char *szCharacterSet; char *szLogonScript; + char *szWINSserver; + char *szSmbrun; int max_log_size; int mangled_stack; int max_xmit; @@ -368,7 +369,7 @@ struct parm_struct {"strip dot", P_BOOL, P_GLOBAL, &Globals.bStripDot, NULL}, {"password server", P_STRING, P_GLOBAL, &Globals.szPasswordServer, NULL}, {"socket options", P_GSTRING, P_GLOBAL, user_socket_options, NULL}, - {"smbrun", P_GSTRING, P_GLOBAL, smbrun_path, NULL}, + {"smbrun", P_STRING, P_GLOBAL, &Globals.szSmbrun, NULL}, {"log file", P_STRING, P_GLOBAL, &Globals.szLogFile, NULL}, {"config file", P_STRING, P_GLOBAL, &Globals.szConfigFile, NULL}, {"smb passwd file", P_STRING, P_GLOBAL, &Globals.szSMBPasswdFile, NULL}, @@ -395,6 +396,7 @@ struct parm_struct {"username map", P_STRING, P_GLOBAL, &Globals.szUsernameMap, NULL}, {"character set", P_STRING, P_GLOBAL, &Globals.szCharacterSet, handle_character_set}, {"logon script", P_STRING, P_GLOBAL, &Globals.szLogonScript, NULL}, + {"wins server", P_STRING, P_GLOBAL, &Globals.szWINSserver, NULL}, {"max log size", P_INTEGER, P_GLOBAL, &Globals.max_log_size, NULL}, {"mangled stack", P_INTEGER, P_GLOBAL, &Globals.mangled_stack, NULL}, {"max mux", P_INTEGER, P_GLOBAL, &Globals.max_mux, NULL}, @@ -543,6 +545,7 @@ static void init_globals(void) string_set(&Globals.szPrintcapname, PRINTCAP_NAME); string_set(&Globals.szLockDir, LOCKDIR); string_set(&Globals.szRootdir, "/"); + string_set(&Globals.szSmbrun, SMBRUN); sprintf(s,"Samba %s",VERSION); string_set(&Globals.szServerString,s); Globals.bLoadPrinters = True; @@ -677,6 +680,7 @@ char *lp_string(char *s) int fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);} FN_GLOBAL_STRING(lp_logfile,&Globals.szLogFile) +FN_GLOBAL_STRING(lp_smbrun,&Globals.szSmbrun) FN_GLOBAL_STRING(lp_configfile,&Globals.szConfigFile) FN_GLOBAL_STRING(lp_smb_passwd_file,&Globals.szSMBPasswdFile) FN_GLOBAL_STRING(lp_serverstring,&Globals.szServerString) @@ -696,6 +700,7 @@ FN_GLOBAL_STRING(lp_domain_controller,&Globals.szDomainController) FN_GLOBAL_STRING(lp_username_map,&Globals.szUsernameMap) FN_GLOBAL_STRING(lp_character_set,&Globals.szCharacterSet) FN_GLOBAL_STRING(lp_logon_script,&Globals.szLogonScript) +FN_GLOBAL_STRING(lp_wins_server,&Globals.szWINSserver) FN_GLOBAL_BOOL(lp_domain_master,&Globals.bDomainMaster) FN_GLOBAL_BOOL(lp_domain_logons,&Globals.bDomainLogons) diff --git a/source3/smbd/ipc.c b/source3/smbd/ipc.c index 3b2c55dc46..25979d72f5 100644 --- a/source3/smbd/ipc.c +++ b/source3/smbd/ipc.c @@ -751,44 +751,64 @@ struct srv_info_struct filter out unwanted server info ******************************************************************/ static BOOL filter_server_info(struct srv_info_struct *server, - char *domain) + BOOL domains, + char *domain, uint32 request) { - if (*domain) - return(strequal(domain, server->domain)); - - return (True); /* be indiscriminate: get all servers! */ -} - -/******************************************************************* - find server in the files saved by nmbd. Return True if we find it. - ******************************************************************/ -static BOOL find_server(struct srv_info_struct *servers, int num_servers, - char *domain, char *name) -{ - int count; - - if (!servers || num_servers == 0) return (False); - - for (count = 0; count < num_servers; count++) { - struct srv_info_struct *s; - - s = &servers[count]; - - if (strequal(name, s->name)) { - StrnCpy(domain, s->domain, sizeof(pstring)-1); - return (True); + if (*domain == 0) + { + if (strequal(lp_workgroup(), server->domain)) { + return True; + } + else if (domains) + { + DEBUG(4,("primary domain:reject %8x %s %s\n",request,server->name,server->domain)); + return False; + } + else if ((request & SV_TYPE_DOMAIN_ENUM) && + (server->type & SV_TYPE_DOMAIN_ENUM)) + { + DEBUG(4,("rej:DOM %8x: %s %s\n",server->type,server->name,server->domain)); + return False; + } + + return True; + } + else + { + if (strequal(domain, server->domain)) + { + /* + if (request == SV_TYPE_LOCAL_LIST_ONLY && + !(server->type & SV_TYPE_LOCAL_LIST_ONLY)) + { + DEBUG(4,("rej:LOC %8x: ok %s %s\n",request,server->name,server->domain)); + return False; + } + */ + if ((request == (SV_TYPE_LOCAL_LIST_ONLY|SV_TYPE_DOMAIN_ENUM)) && + !(server->type&SV_TYPE_DOMAIN_ENUM)) + { + DEBUG(4,("rej:LOCDOM %8x: ok %s %s\n",request,server->name,server->domain)); + return False; + } + + return True; + } + else if (!domains) + { + DEBUG(4,("domain:%s %s %s\n",domain,server->name,server->domain)); + return False; + } + return True; } - } - return (False); } - /******************************************************************* get server info lists from the files saved by nmbd. Return the number of entries ******************************************************************/ static int get_server_info(uint32 servertype, - struct srv_info_struct **servers) + struct srv_info_struct **servers, BOOL domains, char *domain) { FILE *f; pstring fname; @@ -807,18 +827,23 @@ static int get_server_info(uint32 servertype, DEBUG(4,("Can't open %s - %s\n",fname,strerror(errno))); return(0); } + + /* request for everything is code for request all servers */ if (servertype == SV_TYPE_ALL) servertype &= ~SV_TYPE_DOMAIN_ENUM; + DEBUG(4, ("Servertype search: %8x domains:%s\n", servertype,BOOLSTR(domains))); + while (!feof(f)) { fstring stype; struct srv_info_struct *s; char *ptr = line; + BOOL ok = True; *ptr = 0; fgets(line,sizeof(line)-1,f); if (!*line) continue; - + if (count == alloced) { alloced += 10; (*servers) = (struct srv_info_struct *) @@ -827,32 +852,52 @@ static int get_server_info(uint32 servertype, bzero((char *)((*servers)+count),sizeof(**servers)*(alloced-count)); } s = &(*servers)[count]; - - s->server_added = True; - + if (!next_token(&ptr,s->name , NULL)) continue; if (!next_token(&ptr,stype , NULL)) continue; if (!next_token(&ptr,s->comment, NULL)) continue; if (!next_token(&ptr,s->domain , NULL)) { - /* this allows us to cop with an old nmbd */ + /* this allows us to cope with an old nmbd */ strcpy(s->domain,my_workgroup()); } - - if (sscanf(stype,"%X",&s->type) != 1) continue; - + + if (sscanf(stype,"%X",&s->type) != 1) { DEBUG(4,("r:host file ")); ok = False; } + /* doesn't match up: don't want it */ - if (!(servertype & s->type)) continue; - - /* server entry is a domain, we haven't asked for domains: don't want it */ - if ((s->type&SV_TYPE_DOMAIN_ENUM) && !(servertype&SV_TYPE_DOMAIN_ENUM)) - continue; - - DEBUG(4,("Server %20s %8x %25s %15s\n", - s->name, stype, s->comment, s->domain)); - - count++; + if (!(servertype & s->type)) { DEBUG(4,("r:serv type ")); ok = False; } + + if ((servertype == ~SV_TYPE_DOMAIN_ENUM) && + (s->type & SV_TYPE_DOMAIN_ENUM)) + { + DEBUG(4,("s:all x dom ")); + ok = False; + } + + if (domains && !(domain && *domain && strequal(domain, s->domain))) + { + if (!(s->type & SV_TYPE_DOMAIN_ENUM)) + { + DEBUG(4,("r:dom enum ")); + ok = False; + } + } + + if (ok) + { + DEBUG(4,("**SV** %20s %8x %25s %15s\n", + s->name, s->type, s->comment, s->domain)); + + s->type |= SV_TYPE_LOCAL_LIST_ONLY; + s->server_added = True; + count++; + } + else + { + DEBUG(4,("%20s %8x %25s %15s\n", + s->name, s->type, s->comment, s->domain)); + } } - + fclose(f); return(count); } @@ -957,8 +1002,14 @@ static BOOL api_RNetServerEnum(int cnum, int uid, char *param, char *data, int counted=0,total=0; int i; fstring domain; - BOOL domain_request = (servertype & SV_TYPE_DOMAIN_ENUM) && - !(servertype == SV_TYPE_ALL); + BOOL domains; + BOOL domain_request; + BOOL local_request = servertype & SV_TYPE_LOCAL_LIST_ONLY; + + /*if (servertype == SV_TYPE_ALL) servertype &= ~(SV_TYPE_DOMAIN_ENUM|SV_TYPE_LOCAL_LIST_ONLY);*/ + if (servertype == SV_TYPE_ALL) servertype &= ~SV_TYPE_DOMAIN_ENUM; + + domain_request = servertype & SV_TYPE_DOMAIN_ENUM; domain[0] = 0; p += 8; @@ -966,49 +1017,46 @@ static BOOL api_RNetServerEnum(int cnum, int uid, char *param, char *data, if (!prefix_ok(str1,"WrLehD")) return False; if (!check_server_info(uLevel,str2)) return False; - DEBUG(4, ("server request level: %s\n", str2)); + DEBUG(4, ("server request level: %s %8x ", str2, servertype)); + DEBUG(4, ("domains_req:%s ", BOOLSTR(domain_request))); + DEBUG(4, ("local_only:%s\n", BOOLSTR(local_request))); if (strcmp(str1, "WrLehDO") == 0) { - /* asking for servers. we will have to work out which workgroup was - requested, as we maintain lists for multiple workgroups */ + domains = False; } else if (strcmp(str1, "WrLehDz") == 0) { - /* asking for a specific workgroup */ + domains = True; StrnCpy(domain, p, sizeof(fstring)-1); } if (lp_browse_list()) { - total = get_server_info(servertype,&servers); - } - - if (!domain[0] && !domain_request) { - extern fstring remote_machine; - /* must be a server request with an assumed domain. find a domain */ - - if (find_server(servers, total, domain, remote_machine)) { - DEBUG(4, ("No domain specified: using %s for %s\n", - domain, remote_machine)); - } else { - /* default to soemthing sensible */ - strcpy(domain,my_workgroup()); - } + total = get_server_info(servertype,&servers,domains,domain); } data_len = fixed_len = string_len = 0; - for (i=0;iname, s->type, s->comment, s->domain)); + + if (data_len <= buf_len) + { + counted++; + fixed_len += f_len; + string_len += s_len; + } + } } + } *rdata_len = fixed_len + string_len; *rdata = REALLOC(*rdata,*rdata_len); @@ -1021,10 +1069,15 @@ static BOOL api_RNetServerEnum(int cnum, int uid, char *param, char *data, { int count2 = counted; - for (i = 0; i < total && count2;i++) { - if (filter_server_info(&servers[i],domain)) { - fill_srv_info(&servers[i],uLevel,&p,&f_len,&p2,&s_len,*rdata); - count2--; + for (i = 0; i < total && count2;i++) + { + struct srv_info_struct *s = &servers[i]; + if (filter_server_info(s,domains,domain,local_request|domain_request)) + { + fill_srv_info(s,uLevel,&p,&f_len,&p2,&s_len,*rdata); + DEBUG(4,("fill_srv_info %20s %8x %25s %15s\n", + s->name, s->type, s->comment, s->domain)); + count2--; } } } @@ -1657,7 +1710,7 @@ static BOOL api_RNetServerGetInfo(int cnum,int uid, char *param,char *data, strcpy(comment,lp_serverstring()); - if ((count=get_server_info(SV_TYPE_ALL,&servers))>0) { + if ((count=get_server_info(SV_TYPE_ALL,&servers,False,NULL))>0) { for (i=0;i 32000) - DEBUG(0,("Looks like your OS doesn't like high uid values - try using a different account\n")); - return(False); - } - - if (((uid == -1) || (uid == 65535)) && geteuid() != uid) - { - DEBUG(0,("Invalid uid -1. perhaps you have a account with uid 65535?\n")); - return(False); - } - - return(True); -} - - -/**************************************************************************** - become the specified gid -****************************************************************************/ -static BOOL become_gid(int gid) -{ - if (initial_uid != 0) - return(True); - -#ifdef USE_SETRES - if (setresgid(-1,gid,-1) != 0) -#else - if (setgid(gid) != 0) -#endif - { - DEBUG(0,("Couldn't set gid %d currently set to (%d,%d)\n", - gid,getgid(),getegid())); - if (gid > 32000) - DEBUG(0,("Looks like your OS doesn't like high gid values - try using a different account\n")); - return(False); - } - - return(True); -} - - -/**************************************************************************** - become the specified uid and gid -****************************************************************************/ -static BOOL become_id(int uid,int gid) -{ - return(become_gid(gid) && become_uid(uid)); -} - -/**************************************************************************** -become the guest user -****************************************************************************/ -static BOOL become_guest(void) -{ - BOOL ret; - static struct passwd *pass=NULL; - - if (initial_uid != 0) - return(True); - - if (!pass) - pass = Get_Pwnam(lp_guestaccount(-1),True); - if (!pass) return(False); - - ret = become_id(pass->pw_uid,pass->pw_gid); - - if (!ret) - DEBUG(1,("Failed to become guest. Invalid guest account?\n")); - - last_user.cnum = -2; - - return(ret); -} - -/******************************************************************* -check if a username is OK -********************************************************************/ -static BOOL check_user_ok(int cnum,user_struct *vuser,int snum) -{ - int i; - for (i=0;iuid) return(True); - - if (!user_ok(vuser->name,snum)) return(False); - - i = Connections[cnum].uid_cache.entries % UID_CACHE_SIZE; - Connections[cnum].uid_cache.list[i] = vuser->uid; - - if (Connections[cnum].uid_cache.entries < UID_CACHE_SIZE) - Connections[cnum].uid_cache.entries++; - - return(True); -} - - -/**************************************************************************** - become the user of a connection number -****************************************************************************/ -BOOL become_user(int cnum, int uid) -{ - int new_umask; - user_struct *vuser; - int snum,gid; - int ngroups; - gid_t *groups; - - if (last_user.cnum == cnum && last_user.uid == uid) { - DEBUG(4,("Skipping become_user - already user\n")); - return(True); - } - - unbecome_user(); - - if (!OPEN_CNUM(cnum)) { - DEBUG(2,("Connection %d not open\n",cnum)); - return(False); - } - - snum = Connections[cnum].service; - - if (Connections[cnum].force_user || - lp_security() == SEC_SHARE || - !(vuser = get_valid_user_struct(uid)) || - !check_user_ok(cnum,vuser,snum)) { - uid = Connections[cnum].uid; - gid = Connections[cnum].gid; - groups = Connections[cnum].groups; - ngroups = Connections[cnum].ngroups; - } else { - if (!vuser) { - DEBUG(2,("Invalid vuid used %d\n",uid)); - return(False); - } - uid = vuser->uid; - if(!*lp_force_group(snum)) - gid = vuser->gid; - else - gid = Connections[cnum].gid; - groups = vuser->user_groups; - ngroups = vuser->user_ngroups; - } - - if (initial_uid == 0) - { - if (!become_gid(gid)) return(False); - -#ifndef NO_SETGROUPS - if (!IS_IPC(cnum)) { - /* groups stuff added by ih/wreu */ - if (ngroups > 0) - if (setgroups(ngroups,groups)<0) - DEBUG(0,("setgroups call failed!\n")); - } -#endif - - if (!Connections[cnum].admin_user && !become_uid(uid)) - return(False); - } - - new_umask = 0777 & ~CREATE_MODE(cnum); - old_umask = umask(new_umask); - - last_user.cnum = cnum; - last_user.uid = uid; - - DEBUG(5,("become_user uid=(%d,%d) gid=(%d,%d) new_umask=0%o\n", - getuid(),geteuid(),getgid(),getegid(),new_umask)); - - return(True); -} - -/**************************************************************************** - unbecome the user of a connection number -****************************************************************************/ -BOOL unbecome_user(void ) -{ - if (last_user.cnum == -1) - return(False); - - ChDir(OriginalDir); - - umask(old_umask); - - if (initial_uid == 0) - { -#ifdef USE_SETRES - setresuid(-1,getuid(),-1); - setresgid(-1,getgid(),-1); -#else - if (seteuid(initial_uid) != 0) - setuid(initial_uid); - setgid(initial_gid); -#endif - } -#ifdef NO_EID - if (initial_uid == 0) - DEBUG(2,("Running with no EID\n")); - initial_uid = getuid(); - initial_gid = getgid(); -#else - if (geteuid() != initial_uid) - { - DEBUG(0,("Warning: You appear to have a trapdoor uid system\n")); - initial_uid = geteuid(); - } - if (getegid() != initial_gid) - { - DEBUG(0,("Warning: You appear to have a trapdoor gid system\n")); - initial_gid = getegid(); - } -#endif - - if (ChDir(OriginalDir) != 0) - DEBUG(0,("%s chdir(%s) failed in unbecome_user\n", - timestring(),OriginalDir)); - - DEBUG(5,("unbecome_user now uid=(%d,%d) gid=(%d,%d)\n", - getuid(),geteuid(),getgid(),getegid())); - - last_user.cnum = -1; - - return(True); -} - /**************************************************************************** find a service entry ****************************************************************************/ @@ -3677,8 +3411,6 @@ void process(void ) } #endif - last_user.cnum = -1; - while (True) { int32 len; @@ -3922,22 +3654,7 @@ int main(int argc,char *argv[]) umask(0777 & ~DEF_CREATE_MASK); - initial_uid = geteuid(); - initial_gid = getegid(); - - if (initial_gid != 0 && initial_uid == 0) - { -#ifdef HPUX - setresgid(0,0,0); -#else - setgid(0); - setegid(0); -#endif - } - - initial_uid = geteuid(); - initial_gid = getegid(); - + init_uid(); /* this is for people who can't start the program correctly */ while (argc > 1 && (*argv[1] != '-')) @@ -3999,8 +3716,6 @@ int main(int argc,char *argv[]) DEBUG(2,("%s smbd version %s started\n",timestring(),VERSION)); DEBUG(2,("Copyright Andrew Tridgell 1992-1995\n")); - GetWd(OriginalDir); - #ifndef NO_GETRLIMIT #ifdef RLIMIT_NOFILE { diff --git a/source3/smbd/smbrun.c b/source3/smbd/smbrun.c index df12ae1f85..6c9ba52b8b 100644 --- a/source3/smbd/smbrun.c +++ b/source3/smbd/smbrun.c @@ -44,53 +44,54 @@ static void close_fds(void) This is a wrapper around the system call to allow commands to run correctly as non root from a program which is switching between root and non-root -It takes one argument as argv[1] and runs it after becoming a non-root -user -*/ +It takes 3 arguments as uid,gid,command and runs command after +becoming a non-root user */ int main(int argc,char *argv[]) { + int uid,gid; + close_fds(); - if (getuid() != geteuid()) - { - int uid,gid; - - if (getuid() == 0) - uid = geteuid(); - else - uid = getuid(); - - if (getgid() == 0) - gid = getegid(); - else - gid = getgid(); - + if (argc != 4) exit(2); + + uid = atoi(argv[1]); + gid = atoi(argv[2]); + + /* first become root - we may need to do this in order to lose + our privilages! */ #ifdef USE_SETRES - setresgid(0,0,0); - setresuid(0,0,0); - setresgid(gid,gid,gid); - setresuid(uid,uid,uid); + setresgid(0,0,0); + setresuid(0,0,0); #else - setuid(0); - seteuid(0); - setgid(gid); - setegid(gid); - setuid(uid); - seteuid(uid); + setuid(0); + seteuid(0); #endif - if (getuid() != uid) - return(3); - } +#ifdef USE_SETFS + setfsuid(uid); + setfsgid(gid); +#endif + +#ifdef USE_SETRES + setresgid(gid,gid,gid); + setresuid(uid,uid,uid); +#else + setgid(gid); + setegid(gid); + setuid(uid); + seteuid(uid); +#endif - if (geteuid() != getuid()) - return(1); - if (argc < 2) - return(2); + /* paranoia :-) */ + if (getuid() != uid) + return(3); + + if (geteuid() != getuid()) + return(4); /* this is to make sure that the system() call doesn't run forever */ alarm(30); - return(system(argv[1])); + return(system(argv[3])); } diff --git a/source3/smbd/uid.c b/source3/smbd/uid.c new file mode 100644 index 0000000000..f287c733c4 --- /dev/null +++ b/source3/smbd/uid.c @@ -0,0 +1,364 @@ +/* + Unix SMB/Netbios implementation. + Version 1.9. + uid/user handling + Copyright (C) Andrew Tridgell 1992-1995 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "includes.h" +#include "loadparm.h" + +extern int DEBUGLEVEL; + +extern connection_struct Connections[]; + +static int initial_uid; +static int initial_gid; +static int old_umask = 022; + +int current_uid; +int current_gid; + +static pstring OriginalDir; + +/* have I done a become_user? */ +static struct { + int cnum, uid; +} last_user; + +/**************************************************************************** +initialise the uid routines +****************************************************************************/ +void init_uid(void) +{ + initial_uid = current_uid = geteuid(); + initial_gid = current_gid = getegid(); + + if (initial_gid != 0 && initial_uid == 0) + { +#ifdef HPUX + setresgid(0,0,0); +#else + setgid(0); + setegid(0); +#endif + } + + initial_uid = geteuid(); + initial_gid = getegid(); + + last_user.cnum = -1; + + GetWd(OriginalDir); +} + + +/**************************************************************************** + become the specified uid +****************************************************************************/ +static BOOL become_uid(int uid) +{ + if (initial_uid != 0) + return(True); + +#ifdef AIX + { + /* AIX 3 stuff - inspired by a code fragment in wu-ftpd */ + priv_t priv; + + priv.pv_priv[0] = 0; + priv.pv_priv[1] = 0; + if (setpriv(PRIV_SET|PRIV_INHERITED|PRIV_EFFECTIVE|PRIV_BEQUEATH, + &priv, sizeof(priv_t)) < 0 || + setuidx(ID_REAL|ID_EFFECTIVE, (uid_t)uid) < 0 || + seteuid((uid_t)uid) < 0) + DEBUG(1,("Can't set uid (AIX3)")); + } +#endif + +#ifdef USE_SETRES + if (setresuid(-1,uid,-1) != 0) +#elif defined(USE_SETFS) + if (setfsuid(uid) != 0) +#else + if ((seteuid(uid) != 0) && + (setuid(uid) != 0)) +#endif + { + DEBUG(0,("Couldn't set uid %d currently set to (%d,%d)\n", + uid,getuid(), geteuid())); + if (uid > 32000) + DEBUG(0,("Looks like your OS doesn't like high uid values - try using a different account\n")); + return(False); + } + + if (((uid == -1) || (uid == 65535)) && geteuid() != uid) { + DEBUG(0,("Invalid uid -1. perhaps you have a account with uid 65535?\n")); + return(False); + } + + current_uid = uid; + + return(True); +} + + +/**************************************************************************** + become the specified gid +****************************************************************************/ +static BOOL become_gid(int gid) +{ + if (initial_uid != 0) + return(True); + +#ifdef USE_SETRES + if (setresgid(-1,gid,-1) != 0) +#elif defined(USE_SETFS) + if (setfsgid(gid) != 0) +#else + if (setgid(gid) != 0) +#endif + { + DEBUG(0,("Couldn't set gid %d currently set to (%d,%d)\n", + gid,getgid(),getegid())); + if (gid > 32000) + DEBUG(0,("Looks like your OS doesn't like high gid values - try using a different account\n")); + return(False); + } + + current_gid = gid; + + return(True); +} + + +/**************************************************************************** + become the specified uid and gid +****************************************************************************/ +static BOOL become_id(int uid,int gid) +{ + return(become_gid(gid) && become_uid(uid)); +} + +/**************************************************************************** +become the guest user +****************************************************************************/ +BOOL become_guest(void) +{ + BOOL ret; + static struct passwd *pass=NULL; + + if (initial_uid != 0) + return(True); + + if (!pass) + pass = Get_Pwnam(lp_guestaccount(-1),True); + if (!pass) return(False); + + ret = become_id(pass->pw_uid,pass->pw_gid); + + if (!ret) + DEBUG(1,("Failed to become guest. Invalid guest account?\n")); + + last_user.cnum = -2; + + return(ret); +} + +/******************************************************************* +check if a username is OK +********************************************************************/ +static BOOL check_user_ok(int cnum,user_struct *vuser,int snum) +{ + int i; + for (i=0;iuid) return(True); + + if (!user_ok(vuser->name,snum)) return(False); + + i = Connections[cnum].uid_cache.entries % UID_CACHE_SIZE; + Connections[cnum].uid_cache.list[i] = vuser->uid; + + if (Connections[cnum].uid_cache.entries < UID_CACHE_SIZE) + Connections[cnum].uid_cache.entries++; + + return(True); +} + + +/**************************************************************************** + become the user of a connection number +****************************************************************************/ +BOOL become_user(int cnum, int uid) +{ + int new_umask; + user_struct *vuser; + int snum,gid; + int ngroups; + gid_t *groups; + + if (last_user.cnum == cnum && last_user.uid == uid) { + DEBUG(4,("Skipping become_user - already user\n")); + return(True); + } + + unbecome_user(); + + if (!OPEN_CNUM(cnum)) { + DEBUG(2,("Connection %d not open\n",cnum)); + return(False); + } + + snum = Connections[cnum].service; + + if (Connections[cnum].force_user || + lp_security() == SEC_SHARE || + !(vuser = get_valid_user_struct(uid)) || + !check_user_ok(cnum,vuser,snum)) { + uid = Connections[cnum].uid; + gid = Connections[cnum].gid; + groups = Connections[cnum].groups; + ngroups = Connections[cnum].ngroups; + } else { + if (!vuser) { + DEBUG(2,("Invalid vuid used %d\n",uid)); + return(False); + } + uid = vuser->uid; + if(!*lp_force_group(snum)) + gid = vuser->gid; + else + gid = Connections[cnum].gid; + groups = vuser->user_groups; + ngroups = vuser->user_ngroups; + } + + if (initial_uid == 0) + { + if (!become_gid(gid)) return(False); + +#ifndef NO_SETGROUPS + if (!IS_IPC(cnum)) { + /* groups stuff added by ih/wreu */ + if (ngroups > 0) + if (setgroups(ngroups,groups)<0) + DEBUG(0,("setgroups call failed!\n")); + } +#endif + + if (!Connections[cnum].admin_user && !become_uid(uid)) + return(False); + } + + new_umask = 0777 & ~CREATE_MODE(cnum); + old_umask = umask(new_umask); + + last_user.cnum = cnum; + last_user.uid = uid; + + DEBUG(5,("become_user uid=(%d,%d) gid=(%d,%d) new_umask=0%o\n", + getuid(),geteuid(),getgid(),getegid(),new_umask)); + + return(True); +} + +/**************************************************************************** + unbecome the user of a connection number +****************************************************************************/ +BOOL unbecome_user(void ) +{ + if (last_user.cnum == -1) + return(False); + + ChDir(OriginalDir); + + umask(old_umask); + + if (initial_uid == 0) + { +#ifdef USE_SETRES + setresuid(-1,getuid(),-1); + setresgid(-1,getgid(),-1); +#elif defined(USE_SETFS) + setfsuid(initial_uid); + setfsgid(initial_gid); +#else + if (seteuid(initial_uid) != 0) + setuid(initial_uid); + setgid(initial_gid); +#endif + } +#ifdef NO_EID + if (initial_uid == 0) + DEBUG(2,("Running with no EID\n")); + initial_uid = getuid(); + initial_gid = getgid(); +#else + if (geteuid() != initial_uid) + { + DEBUG(0,("Warning: You appear to have a trapdoor uid system\n")); + initial_uid = geteuid(); + } + if (getegid() != initial_gid) + { + DEBUG(0,("Warning: You appear to have a trapdoor gid system\n")); + initial_gid = getegid(); + } +#endif + + current_uid = initial_uid; + current_gid = initial_gid; + + if (ChDir(OriginalDir) != 0) + DEBUG(0,("%s chdir(%s) failed in unbecome_user\n", + timestring(),OriginalDir)); + + DEBUG(5,("unbecome_user now uid=(%d,%d) gid=(%d,%d)\n", + getuid(),geteuid(),getgid(),getegid())); + + last_user.cnum = -1; + + return(True); +} + + +/**************************************************************************** +run a command via system() using smbrun, being careful about uid/gid handling +****************************************************************************/ +int smbrun(char *cmd,char *outfile) +{ + int ret; + pstring syscmd; + char *path = lp_smbrun(); + + if (!file_exist(path,NULL)) + { + DEBUG(0,("SMBRUN ERROR: Can't find %s. Installation problem?\n",path)); + return(1); + } + + sprintf(syscmd,"%s %d %d \"(%s 2>&1) > %s\"", + path,current_uid,current_gid,cmd, + outfile?outfile:"/dev/null"); + + DEBUG(5,("smbrun - running %s ",syscmd)); + ret = system(syscmd); + DEBUG(5,("gave %d\n",ret)); + return(ret); +} + + -- cgit