diff options
Diffstat (limited to 'source3/lib/username.c')
-rw-r--r-- | source3/lib/username.c | 542 |
1 files changed, 119 insertions, 423 deletions
diff --git a/source3/lib/username.c b/source3/lib/username.c index 23bdb54faf..9a189980d5 100644 --- a/source3/lib/username.c +++ b/source3/lib/username.c @@ -27,306 +27,31 @@ static struct passwd *uname_string_combinations(char *s, struct passwd * (*fn) ( static struct passwd *uname_string_combinations2(char *s, int offset, struct passwd * (*fn) (char *), int N); /**************************************************************************** - Since getpwnam() makes samba really slow with the NT-domain code - (reading /etc/passwd again and again and again), here is an implementation - of very simple passwd cache + Get a users home directory. ****************************************************************************/ -#define PASSWD_HASH_SIZE 1009 -/* The hashtable is rebuild every 15 seconds */ -#define PASSWD_HASH_AGE 15 -struct passwd_hash_entry { - int entry; - int next; -}; - -struct passwd_hash_table_s { - struct passwd *passwds; - int passwds_size; - int *names; - int *uids; - struct passwd_hash_entry *entries; - int entries_size; - struct timeval build_time; -} passwd_hash_table = { - NULL,0,NULL,NULL,NULL,0,{0,0} -}; - -static int name_hash_function(const char *name) -{ - /* I guess that there must be better hash functions. This one was the - * first to come into mind :) */ - unsigned int value=0; - while (*name) { - value=(value<<8)|(unsigned char)(*name); - if (value>1048576) value=value%PASSWD_HASH_SIZE; - name++; - } - value=value%PASSWD_HASH_SIZE; - return value; -} - -static int uid_hash_function(uid_t uid) -{ - return uid%PASSWD_HASH_SIZE; -} - -static BOOL build_passwd_hash_table(void) +char *get_user_home_dir(char *user) { - struct passwd_hash_table_s *pht=&passwd_hash_table; /* Convenience */ - int num_passwds=0; - int num_entries=0; - struct passwd *pass; - int i; - int name_i,uid_i; - - DEBUG(3,("Building passwd hash table\n")); - /* Free the allocated strings in old hash table */ - for (i=0;i<pht->passwds_size;i++) { - free(pht->passwds[i].pw_name); - free(pht->passwds[i].pw_passwd); - free(pht->passwds[i].pw_gecos); - free(pht->passwds[i].pw_dir); - free(pht->passwds[i].pw_shell); - } - - /* Initialize hash table if first table build */ - if (pht->passwds_size==0) { - DEBUG(3,("Building passwd hash table for the first time\n")); - pht->passwds=malloc(sizeof(struct passwd)*64); /* A reasonable default */ - pht->passwds_size=64; - } - if (pht->names==NULL) { - pht->names=malloc(sizeof(struct passwd_hash_entry *)*PASSWD_HASH_SIZE); - } - if (pht->uids==NULL) { - pht->uids=malloc(sizeof(struct passwd_hash_entry *)*PASSWD_HASH_SIZE); - } - if (pht->entries==NULL) { - pht->entries=malloc(sizeof(struct passwd_hash_entry)*128); - pht->entries_size=128; - } - if (pht->passwds==NULL || pht->names==NULL || - pht->uids==NULL || pht->entries==NULL) { - goto fail; - } - - /* Clear out the hash table */ - for(i=0;i<PASSWD_HASH_SIZE;i++) pht->uids[i]=-1; - for(i=0;i<PASSWD_HASH_SIZE;i++) pht->names[i]=-1; - - /* Now do the build */ - setpwent(); - - while((pass=getpwent())) { - - /* Check that we have enough space */ - if (num_passwds==pht->passwds_size) { - struct passwd *new_passwds=NULL; - pht->passwds_size+=pht->passwds_size/2; - new_passwds=realloc(pht->passwds, - sizeof(struct passwd)*pht->passwds_size); - if (new_passwds==NULL) goto fail; - pht->passwds=new_passwds; - } - if (num_entries+1>=pht->entries_size) { - pht->entries_size+=pht->entries_size/2; - pht->entries=realloc(pht->entries, - sizeof(struct passwd_hash_entry)*pht->entries_size); - if (pht->entries==NULL) goto fail; - } + static struct passwd *pass; - /* Copy the passwd struct */ - memset(&pht->passwds[num_passwds],0,sizeof(struct passwd)); - pht->passwds[num_passwds].pw_uid=pass->pw_uid; - pht->passwds[num_passwds].pw_gid=pass->pw_gid; - if ( - (pht->passwds[num_passwds].pw_name=strdup(pass->pw_name))==NULL || - (pht->passwds[num_passwds].pw_passwd=strdup(pass->pw_passwd))==NULL || - (pht->passwds[num_passwds].pw_gecos=strdup(pass->pw_gecos))==NULL || - (pht->passwds[num_passwds].pw_dir=strdup(pass->pw_dir))==NULL || - (pht->passwds[num_passwds].pw_shell=strdup(pass->pw_shell))==NULL ) { - num_passwds++; - goto fail; - } - - /* Add to the hash table */ - /* Add the name */ - pht->entries[num_entries].entry=num_passwds; - name_i=name_hash_function(pass->pw_name); - pht->entries[num_entries].next=pht->names[name_i]; - pht->names[name_i]=num_entries; - num_entries++; - /* Add the uid */ - pht->entries[num_entries].entry=num_passwds; - uid_i=uid_hash_function(pass->pw_uid); - pht->entries[num_entries].next=pht->uids[uid_i]; - pht->uids[uid_i]=num_entries; - num_entries++; - - /* This entry has been done */ - num_passwds++; - } - endpwent(); - - if (pht->passwds_size>num_passwds) { - struct passwd *passwds; - passwds=realloc(pht->passwds,sizeof(pht->passwds[0])*num_passwds); - if (passwds==NULL) goto fail; - pht->passwds=passwds; - pht->passwds_size=num_passwds; - } - if (pht->entries_size>num_entries) { - struct passwd_hash_entry *entries; - entries=realloc(pht->entries,sizeof(pht->entries[0])*num_entries); - if (entries==NULL) goto fail; - pht->entries=entries; - pht->entries_size=num_entries; - } + pass = Get_Pwnam(user, False); - /* Mark the creation time */ - GetTimeOfDay(&pht->build_time); - /* Everything went smoothly. */ - return True; - - fail: - DEBUG(0,("Failed to create passwd hash table: %s",strerror(errno))); - /* OK: now the untested part. Normally this should never happen: - * Only running out of memory could cause this and even then - * we have enough trouble already. */ - while (num_passwds>0) { - num_passwds--; - free(pht->passwds[num_passwds].pw_name); - free(pht->passwds[num_passwds].pw_passwd); - free(pht->passwds[num_passwds].pw_gecos); - free(pht->passwds[num_passwds].pw_dir); - free(pht->passwds[num_passwds].pw_shell); - } - free(pht->entries); - free(pht->uids); - free(pht->names); - free(pht->passwds); - pht->passwds_size=0; - pht->entries_size=0; - /* Also mark fail time, so that retry will happen after PASSWD_HASH_AGE */ - GetTimeOfDay(&pht->build_time); - return False; + if (!pass) return(NULL); + return(pass->pw_dir); } -static BOOL have_passwd_hash(void) -{ - struct passwd_hash_table_s *pht=&passwd_hash_table; - struct timeval tv; - GetTimeOfDay(&tv); - /* I'm ignoring microseconds. If you think they matter, go ahead - * and implement them */ - if (tv.tv_sec - pht->build_time.tv_sec > PASSWD_HASH_AGE) { - return build_passwd_hash_table(); - } - return pht->passwds_size>0; -} - -struct passwd *hashed_getpwnam(const char *name) -{ - struct passwd_hash_table_s *pht=&passwd_hash_table; - - DEBUG(5,("getpwnam(%s)\n", name)); - - if (have_passwd_hash()) - { - int name_i=name_hash_function(name); - int hash_index=pht->names[name_i]; - while(hash_index!=-1) { - struct passwd *pass=&pht->passwds[pht->entries[hash_index].entry]; - if (strcmp(name,pass->pw_name)==0) { - DEBUG(5,("Found: %s:%s:%d:%d:%s:%s:%s\n", - pass->pw_name, - pass->pw_passwd, - pass->pw_uid, - pass->pw_gid, - pass->pw_gecos, - pass->pw_dir, - pass->pw_shell)); - return copy_passwd_struct(pass); - } - hash_index=pht->entries[hash_index].next; - } - - /* Not found */ - DEBUG(5,("%s not found\n",name)); - return NULL; - } - - /* Fall back to real getpwnam() */ - return sys_getpwnam(name); -} /******************************************************************* -turn a uid into a user name + Map a username from a dos name to a unix name by looking in the username + map. Note that this modifies the name in place. + This is the main function that should be called *once* on + any incoming or new username - in order to canonicalize the name. + This is being done to de-couple the case conversions from the user mapping + function. Previously, the map_username was being called + every time Get_Pwnam was called. + Returns True if username was changed, false otherwise. ********************************************************************/ -char *uidtoname(uid_t uid) -{ - static char name[40]; - struct passwd_hash_table_s *pht=&passwd_hash_table; - struct passwd *pass=NULL; - - DEBUG(5,("uidtoname(%d)\n",uid)); - if (have_passwd_hash()) { - int hash_index=pht->uids[uid_hash_function(uid)]; - while(hash_index!=-1) { - pass=&pht->passwds[pht->entries[hash_index].entry]; - if (pass->pw_uid==uid) { - DEBUG(5,("Found: %s:%s:%d:%d:%s:%s:%s\n", - pass->pw_name, - pass->pw_passwd, - pass->pw_uid, - pass->pw_gid, - pass->pw_gecos, - pass->pw_dir, - pass->pw_shell)); - return pass->pw_name; - } - hash_index=pht->entries[hash_index].next; - } - DEBUG(5,("Hash miss")); - pass=NULL; - } else { - /* No hash table, fall back to getpwuid */ - pass = getpwuid(uid); - } - if (pass) return(pass->pw_name); - slprintf(name, sizeof(name) - 1, "%d",(int)uid); - return(name); -} - -/**************************************************************************** -get a users home directory. -****************************************************************************/ -char *get_unixhome_dir(char *user) -{ - const struct passwd *pass; - static pstring home_dir; - pass = Get_Pwnam(user, False); - - if (pass == NULL || pass->pw_dir == NULL) return(NULL); - - pstrcpy(home_dir, pass->pw_dir); - DEBUG(10,("get_smbhome_dir: returning %s for user %s\n", home_dir, user)); - return home_dir; -} - - -/******************************************************************* -map a username from a dos name to a unix name by looking in the username -map. Note that this modifies the name in place. -This is the main function that should be called *once* on -any incoming or new username - in order to canonicalize the name. -This is being done to de-couple the case conversions from the user mapping -function. Previously, the map_username was being called -every time Get_Pwnam was called. -Returns True if username was changed, false otherwise. -********************************************************************/ BOOL map_username(char *user) { static BOOL initialised=False; @@ -420,38 +145,36 @@ BOOL map_username(char *user) return mapped_user; } - /**************************************************************************** Get_Pwnam wrapper ****************************************************************************/ + static struct passwd *_Get_Pwnam(char *s) { - struct passwd *ret; + struct passwd *ret; - ret = hashed_getpwnam(s); + ret = sys_getpwnam(s); + if (ret) { #ifdef HAVE_GETPWANAM - if (ret) - { - struct passwd_adjunct *pwret; - pwret = getpwanam(s); - if (pwret != NULL && pwret->pwa_passwd != NULL) - { - pstrcpy(ret->pw_passwd, pwret->pwa_passwd); - } - } + struct passwd_adjunct *pwret; + pwret = getpwanam(s); + if (pwret && pwret->pwa_passwd) { + pstrcpy(ret->pw_passwd,pwret->pwa_passwd); + } #endif + } - return ret; + return(ret); } + /**************************************************************************** -a wrapper for getpwnam() that tries with all lower and all upper case -if the initial name fails. Also tried with first letter capitalised -Note that this can change user! Function returns const to emphasise -the fact that most of the members of the struct passwd * returned are -dynamically allocated. + A wrapper for getpwnam() that tries with all lower and all upper case + if the initial name fails. Also tried with first letter capitalised + Note that this can change user! ****************************************************************************/ -const struct passwd *Get_Pwnam(char *user,BOOL allow_change) + +struct passwd *Get_Pwnam(char *user,BOOL allow_change) { fstring user2; int last_char; @@ -469,33 +192,39 @@ const struct passwd *Get_Pwnam(char *user,BOOL allow_change) } ret = _Get_Pwnam(user); - if (ret) return(ret); + if (ret) + return(ret); strlower(user); ret = _Get_Pwnam(user); - if (ret) return(ret); + if (ret) + return(ret); strupper(user); ret = _Get_Pwnam(user); - if (ret) return(ret); + if (ret) + return(ret); - /* try with first letter capitalised */ + /* Try with first letter capitalised. */ if (strlen(user) > 1) strlower(user+1); ret = _Get_Pwnam(user); - if (ret) return(ret); + if (ret) + return(ret); /* try with last letter capitalised */ strlower(user); last_char = strlen(user)-1; user[last_char] = toupper(user[last_char]); ret = _Get_Pwnam(user); - if (ret) return(ret); + if (ret) + return(ret); - /* try all combinations up to usernamelevel */ + /* Try all combinations up to usernamelevel. */ strlower(user); ret = uname_string_combinations(user, _Get_Pwnam, usernamelevel); - if (ret) return(ret); + if (ret) + return(ret); if (allow_change) fstrcpy(user,user2); @@ -504,8 +233,9 @@ const struct passwd *Get_Pwnam(char *user,BOOL allow_change) } /**************************************************************************** -check if a user is in a netgroup user list + Check if a user is in a netgroup user list. ****************************************************************************/ + static BOOL user_in_netgroup_list(char *user,char *ngname) { #ifdef HAVE_NETGROUP @@ -513,12 +243,9 @@ static BOOL user_in_netgroup_list(char *user,char *ngname) if (mydomain == NULL) yp_get_default_domain(&mydomain); - if(mydomain == NULL) - { + if(mydomain == NULL) { DEBUG(5,("Unable to get default yp domain\n")); - } - else - { + } else { DEBUG(5,("looking for user %s of domain %s in netgroup %s\n", user, mydomain, ngname)); DEBUG(5,("innetgr is %s\n", @@ -533,78 +260,51 @@ static BOOL user_in_netgroup_list(char *user,char *ngname) } /**************************************************************************** -check if a user is in a UNIX user list + Check if a user is in a UNIX user list. ****************************************************************************/ + static BOOL user_in_group_list(char *user,char *gname) { -#ifdef HAVE_GETGRNAM - struct group *gptr; - char **member; - const struct passwd *pass = Get_Pwnam(user,False); - - if (pass) - { - gptr = getgrgid(pass->pw_gid); - if (gptr && strequal(gptr->gr_name,gname)) - return(True); - } - - gptr = (struct group *)getgrnam(gname); - - if (gptr) - { - member = gptr->gr_mem; - while (member && *member) - { - if (strequal(*member,user)) - return(True); - member++; - } - } +#ifdef HAVE_GETGRENT + struct group *gptr; + char **member; + struct passwd *pass = Get_Pwnam(user,False); + + if (pass) { + gptr = getgrgid(pass->pw_gid); + if (gptr && strequal(gptr->gr_name,gname)) + return(True); + } + + while ((gptr = (struct group *)getgrent())) { + if (!strequal(gptr->gr_name,gname)) + continue; + member = gptr->gr_mem; + while (member && *member) { + if (strequal(*member,user)) { + endgrent(); + return(True); + } + member++; + } + } + + endgrent(); #endif /* HAVE_GETGRNAM */ - return False; + return False; } /**************************************************************************** -check if a username is valid + Check if a user is in a user list - can check combinations of UNIX + and netgroup lists. ****************************************************************************/ -BOOL user_ok(char *user,int snum) -{ - pstring valid, invalid; - BOOL ret; - - StrnCpy(valid, lp_valid_users(snum), sizeof(pstring)); - StrnCpy(invalid, lp_invalid_users(snum), sizeof(pstring)); - - string_sub(valid,"%S",lp_servicename(snum)); - string_sub(invalid,"%S",lp_servicename(snum)); - - ret = !user_in_list(user,invalid); - - if (ret && valid && *valid) { - ret = user_in_list(user,valid); - } - - if (ret && lp_onlyuser(snum)) { - char *user_list = lp_username(snum); - string_sub(user_list,"%S",lp_servicename(snum)); - ret = user_in_list(user,user_list); - } - return(ret); -} - -/**************************************************************************** -check if a user is in a user list - can check combinations of UNIX -and netgroup lists. -****************************************************************************/ BOOL user_in_list(char *user,char *list) { pstring tok; char *p=list; - while (next_token(&p,tok,LIST_SEP, sizeof(tok))) - { + while (next_token(&p,tok,LIST_SEP, sizeof(tok))) { /* * Check raw username. */ @@ -616,8 +316,7 @@ BOOL user_in_list(char *user,char *list) * of UNIX and netgroups has been specified. */ - if(*tok == '@') - { + if(*tok == '@') { /* * Old behaviour. Check netgroup list * followed by UNIX list. @@ -626,11 +325,9 @@ BOOL user_in_list(char *user,char *list) return True; if(user_in_group_list(user,&tok[1])) return True; - } - else if (*tok == '+') - { - if(tok[1] == '&') - { + } else if (*tok == '+') { + + if(tok[1] == '&') { /* * Search UNIX list followed by netgroup. */ @@ -638,20 +335,20 @@ BOOL user_in_list(char *user,char *list) return True; if(user_in_netgroup_list(user,&tok[2])) return True; - } - else - { + + } else { + /* * Just search UNIX list. */ + if(user_in_group_list(user,&tok[1])) return True; } - } - else if (*tok == '&') - { - if(tok[1] == '&') - { + + } else if (*tok == '&') { + + if(tok[1] == '+') { /* * Search netgroup list followed by UNIX list. */ @@ -659,9 +356,7 @@ BOOL user_in_list(char *user,char *list) return True; if(user_in_group_list(user,&tok[2])) return True; - } - else - { + } else { /* * Just search netgroup list. */ @@ -675,15 +370,16 @@ BOOL user_in_list(char *user,char *list) /* The functions below have been taken from password.c and slightly modified */ /**************************************************************************** -apply a function to upper/lower case combinations -of a string and return true if one of them returns true. -try all combinations with N uppercase letters. -offset is the first char to try and change (start with 0) -it assumes the string starts lowercased + Apply a function to upper/lower case combinations + of a string and return true if one of them returns true. + Try all combinations with N uppercase letters. + offset is the first char to try and change (start with 0) + it assumes the string starts lowercased ****************************************************************************/ + static struct passwd *uname_string_combinations2(char *s,int offset,struct passwd *(*fn)(char *),int N) { - int len = strlen(s); + ssize_t len = (ssize_t)strlen(s); int i; struct passwd *ret; @@ -694,36 +390,36 @@ static struct passwd *uname_string_combinations2(char *s,int offset,struct passw if (N <= 0 || offset >= len) return(fn(s)); - - for (i=offset;i<(len-(N-1));i++) - - { - char c = s[i]; - if (!islower(c)) continue; - s[i] = toupper(c); - ret = uname_string_combinations2(s,i+1,fn,N-1); - if(ret) return(ret); - s[i] = c; - } + for (i=offset;i<(len-(N-1));i++) { + char c = s[i]; + if (!islower(c)) + continue; + s[i] = toupper(c); + ret = uname_string_combinations2(s,i+1,fn,N-1); + if(ret) + return(ret); + s[i] = c; + } return(NULL); } /**************************************************************************** -apply a function to upper/lower case combinations -of a string and return true if one of them returns true. -try all combinations with up to N uppercase letters. -offset is the first char to try and change (start with 0) -it assumes the string starts lowercased + Apply a function to upper/lower case combinations + of a string and return true if one of them returns true. + Try all combinations with up to N uppercase letters. + offset is the first char to try and change (start with 0) + it assumes the string starts lowercased ****************************************************************************/ + static struct passwd * uname_string_combinations(char *s,struct passwd * (*fn)(char *),int N) { int n; struct passwd *ret; - for (n=1;n<=N;n++) - { + for (n=1;n<=N;n++) { ret = uname_string_combinations2(s,0,fn,n); - if(ret) return(ret); + if(ret) + return(ret); } return(NULL); } |