summaryrefslogtreecommitdiff
path: root/source3/lib/username.c
diff options
context:
space:
mode:
Diffstat (limited to 'source3/lib/username.c')
-rw-r--r--source3/lib/username.c542
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);
}