home *** CD-ROM | disk | FTP | other *** search
- /*
- Unix SMB/Netbios implementation.
- Version 1.8.
- Copyright (C) Andrew Tridgell 1992,1993,1994
-
- 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;
-
- /* users from session setup */
- pstring session_users="";
-
-
- /* this holds info on user ids that are already validated for this VC */
- user_struct *validated_users = NULL;
- int num_validated_users = 0;
-
- /****************************************************************************
- check if a uid has been validated, and return an index if it has. -1 if not
- ****************************************************************************/
- int valid_uid(int uid)
- {
- int i;
- for (i=0;i<num_validated_users;i++)
- if (validated_users[i].uid == uid)
- {
- DEBUG(3,("valid uid %d mapped to vuid %d\n",uid,i));
- return(i);
- }
- return(-1);
- }
-
- /****************************************************************************
- return a validated username
- ****************************************************************************/
- char *validated_username(int vuid)
- {
- return(validated_users[vuid].name);
- }
-
- /****************************************************************************
- register a uid/name pair as being valid and that a valid password
- has been given.
- ****************************************************************************/
- void register_uid(int uid,char *name,BOOL guest)
- {
- if (valid_uid(uid) >= 0)
- return;
- if (!validated_users)
- validated_users = (user_struct *)malloc(sizeof(user_struct));
- else
- validated_users = (user_struct *)realloc(validated_users,
- sizeof(user_struct)*
- (num_validated_users+1));
-
- if (!validated_users)
- {
- DEBUG(0,("Failed to realloc users struct!\n"));
- return;
- }
-
- validated_users[num_validated_users].uid = uid;
- validated_users[num_validated_users].guest = guest;
- validated_users[num_validated_users].name = strdup(name);
-
- DEBUG(3,("uid %d registered to name %s\n",uid,name));
-
- num_validated_users++;
- }
-
-
- /****************************************************************************
- add a name to the session users list
- ****************************************************************************/
- void add_session_user(char *user)
- {
- if (user && *user && !in_list(user,session_users,False))
- {
- if (strlen(user) + strlen(session_users) + 2 >= sizeof(pstring))
- DEBUG(1,("Too many session users??\n"));
- else
- {
- strcat(session_users," ");
- strcat(session_users,user);
- }
- }
- }
-
-
- #ifdef NO_GETSPNAM
- /* a fake shadow password routine which just fills a fake spwd struct
- * with the sp_pwdp field. (sreiz@aie.nl)
- */
- struct spwd *getspnam(char *username) /* fake shadow password routine */
- {
- FILE *f;
- char line[1024];
- static char pw[20];
- static struct spwd static_spwd;
-
- static_spwd.sp_pwdp=0;
- if (!(f=fopen("/etc/master.passwd", "r")))
- return 0;
- while (fgets(line, 1024, f)) {
- if (!strncmp(line, username, strlen(username)) &&
- line[strlen(username)]==':') { /* found entry */
- char *p, *q;
-
- p=line+strlen(username)+1;
- if (q=strchr(p, ':')) {
- *q=0;
- if (q-p+1>20)
- break;
- strcpy(pw, p);
- static_spwd.sp_pwdp=pw;
- }
- break;
- }
- }
- fclose(f);
- if (static_spwd.sp_pwdp)
- return &static_spwd;
- return 0;
- }
- #endif
-
-
- #ifdef OSF1_ENH_SEC
- /****************************************************************************
- an enhanced crypt for OSF1
- ****************************************************************************/
- char *osf1_bigcrypt(char *password,char *salt1)
- {
- static char result[AUTH_MAX_PASSWD_LENGTH] = "";
- char *p1;
- char *p2=password;
- char salt[3];
- int i;
- int parts = strlen(password) / AUTH_CLEARTEXT_SEG_CHARS;
- if (strlen(password)%AUTH_CLEARTEXT_SEG_CHARS)
- parts++;
-
- strcpy(salt,salt1);
- strcpy(result,salt1);
-
- for (i=0; i<parts;i++)
- {
- p1 = crypt(p2,salt);
- strcat(result,p1+2);
- StrnCpy(salt,&result[2+i*AUTH_CIPHERTEXT_SEG_CHARS],2);
- p2 += AUTH_CLEARTEXT_SEG_CHARS;
- }
-
- return(result);
- }
- #endif
-
-
- /****************************************************************************
- update the enhanced security database. Only relevant for OSF1 at the moment.
- ****************************************************************************/
- void update_protected_database( char *user, BOOL result)
- {
- #ifdef OSF1_ENH_SEC
- struct pr_passwd *mypasswd;
- time_t starttime;
- long tz;
-
- mypasswd = getprpwnam (user);
- starttime = time (NULL);
- tz = mktime ( localtime ( &starttime ) );
-
- if (result)
- {
- mypasswd->ufld.fd_slogin = tz;
- mypasswd->ufld.fd_nlogins = 0;
-
- putprpwnam(user,mypasswd);
-
- DEBUG(3,("Update protected database for Account %s after succesful connection\n",user));
- }
- else
- {
- mypasswd->ufld.fd_ulogin = tz;
- mypasswd->ufld.fd_nlogins = mypasswd->ufld.fd_nlogins + 1;
- if ( mypasswd->ufld.fd_max_tries != 0 && mypasswd->ufld.fd_nlogins > mypasswd->ufld.fd_max_tries )
- {
- mypasswd->uflg.fg_lock = 0;
- DEBUG(3,("Account is disabled -- see Account Administrator.\n"));
- }
- putprpwnam ( user , mypasswd );
- DEBUG(3,("Update protected database for Account %s after refusing connection\n",user));
- }
- #else
- DEBUG(6,("Updated database with %s %s\n",user,BOOLSTR(result)));
- #endif
- }
-
-
-
- /* these are kept here to keep the string_combinations function simple */
- char this_user[100]="";
- char this_salt[10]="";
- char this_crypted[100]="";
-
-
- /****************************************************************************
- core of password checking routine
- ****************************************************************************/
- BOOL password_check(char *password)
- {
- DEBUG(4,("Checking password for user %s\n", this_user));
- #ifdef PWDAUTH
- if (pwdauth(this_user,password) == 0)
- return(True);
- #endif
- #ifdef OSF1_ENH_SEC
- return(strcmp(osf1_bigcrypt(password,this_salt),this_crypted) == 0);
- #endif
- #ifdef ULTRIX_AUTH
- return (strcmp((char *)crypt16(password, this_salt ),this_crypted) == 0);
- #endif
- return(strcmp((char *)crypt(password,this_salt),this_crypted) == 0);
- }
-
- /****************************************************************************
- check if a username/password is OK
- ****************************************************************************/
- BOOL password_ok(char *user,char *password, struct passwd *pwd)
- {
- int level = lp_passwordlevel();
- struct passwd *pass;
-
- if (!password || !*password)
- return(False);
-
- if (pwd && !user)
- {
- pass = (struct passwd *) pwd;
- user = pass->pw_name;
- }
- else
- pass = Get_Pwnam(user);
-
- DEBUG(4,("Checking password for user %s\n",user));
-
- if (!pass)
- {
- DEBUG(3,("Couldn't find user %s\n",user));
- return(False);
- }
-
- #ifdef SHADOW_PWD
- {
- struct spwd *spass = getspnam(pass->pw_name);
- if (spass && spass->sp_pwdp)
- pass->pw_passwd = spass->sp_pwdp;
- }
- #endif
-
- #ifdef SecureWare
- {
- struct pr_passwd *pr_pw = getprpwnam(pass->pw_name);
- if (pr_pw && pr_pw->ufld.fd_encrypt)
- pass->pw_passwd = pr_pw->ufld.fd_encrypt;
- }
- #endif
-
- #ifdef OSF1_ENH_SEC
- {
- struct pr_passwd *mypasswd;
- DEBUG(5,("Checking password for user %s in OSF1_ENH_SEC\n",user));
- mypasswd = getprpwnam (user);
- if ( mypasswd )
- {
- strcpy(pass->pw_name,mypasswd->ufld.fd_name);
- strcpy(pass->pw_passwd,mypasswd->ufld.fd_encrypt);
- }
- else
- {
- DEBUG(5,("No entry for user %s in protected database !\n",user));
- return(False);
- }
- }
- #endif
-
- #ifdef ULTRIX_AUTH
- {
- AUTHORIZATION *ap = getauthuid( pass->pw_uid );
- if (ap)
- {
- strcpy( pass->pw_passwd, ap->a_password );
- endauthent();
- }
- }
- #endif
-
- /* extract relevant info */
- strcpy(this_user,pass->pw_name);
- StrnCpy(this_salt,pass->pw_passwd,2); this_salt[2] = 0;
- strcpy(this_crypted,pass->pw_passwd);
-
- if (*this_crypted == 0 && !lp_null_passwords())
- {
- DEBUG(2,("Disallowing access to %s due to null password\n",this_user));
- return(False);
- }
-
-
- /* try it as it came to us */
- if (password_check(password))
- {
- update_protected_database(user,True);
- return(True);
- }
-
- /* try all lowercase */
- strlower(password);
- if (password_check(password))
- {
- update_protected_database(user,True);
- return(True);
- }
-
- /* give up? */
- if(level < 1)
- {
- update_protected_database(user,False);
- return(False);
- }
-
- /* last chance - all combinations of up to level chars upper! */
- strlower(password);
-
- if (string_combinations(password,0,password_check,level))
- {
- update_protected_database(user,True);
- return(True);
- }
-
- update_protected_database(user,False);
- return(False);
- }
-
-
- /****************************************************************************
- check if a user is in a user list
- ****************************************************************************/
- BOOL user_in_list(char *user,char *list)
- {
- pstring list2;
- char *p;
-
- strcpy(list2,list);
-
-
-
- for (p = strtok(list2,LIST_SEP); p; p = strtok(NULL,LIST_SEP))
- {
- if (strequal(user,p))
- return(True);
- #if HAVE_GETGRNAM
- if (*p == '@')
- {
- struct group *gptr = (struct group *)getgrnam(p+1);
- char **member;
- if (gptr)
- {
- member = gptr->gr_mem;
- while (member && *member)
- {
- if (strequal(*member,user))
- return(True);
- member++;
- }
- }
- }
- #endif
- }
- return(False);
- }
-
-
-
- /****************************************************************************
- check if a username is valid
- ****************************************************************************/
- BOOL user_ok(char *user,int snum)
- {
- char *valid = lp_valid_users(snum);
- char *invalid = lp_invalid_users(snum);
- BOOL ret = !user_in_list(user,invalid);
- if (ret && valid && *valid)
- ret = user_in_list(user,valid);
- return(ret);
- }
-
-
-
-
- /****************************************************************************
- validate a group username entry. Return the username or NULL
- ****************************************************************************/
- char *validate_group(char *group,char *password,int snum)
- {
- #if HAVE_GETGRNAM
- struct group *gptr = (struct group *)getgrnam(group);
- char **member;
- if (gptr)
- {
- member = gptr->gr_mem;
- while (member && *member)
- {
- if (user_ok(*member,snum) &&
- password_ok(*member,password,NULL))
- return(*member);
- member++;
- }
- #ifdef GROUP_CHECK_PWENT
- {
- struct passwd *pwd;
- static char tm[200];
-
- setpwent ();
- while (pwd = getpwent ()) {
- if (*(pwd->pw_passwd) && *password && pwd->pw_gid == gptr->gr_gid) {
- /* This Entry have PASSWORD and same GID then check pwd */
- if (password_ok (0, password, pwd)) {
- strcpy (tm, pwd->pw_name);
- endpwent ();
- return tm;
- }
- }
- }
- endpwent ();
- }
- #endif /* GROUP_CHECK_PWENT */
- }
- #endif
- return(NULL);
- }
-
-
-
- /****************************************************************************
- check for authority to login to a service with a given username/password
- ****************************************************************************/
- BOOL authorise_login(int snum,char *user,char *password,BOOL *guest,int vuid)
- {
- BOOL ok = False;
- pstring user_list;
- char *auser;
-
- *guest = False;
-
- /* there are several possabilities:
- 1) login as the given user with given password
- 2) login as a previously registered username with the given password
- 3) login as a session list username with the given password
- 4) login as a previously validated user/password pair
- 5) login as the "user =" user with given password
- 6) login as the "user =" user with no password (guest connection)
- 7) login as guest user with no password
-
- if the service is guest_only then steps 1 to 5 are skipped
- */
-
- if (!(GUEST_ONLY(snum) && GUEST_OK(snum)))
- {
-
- if (!lp_onlyuser(snum))
- {
-
- /* check the given username and password */
- if (!ok && (*password) && (*user) && user_ok(user,snum))
- {
- ok = password_ok(user,password, NULL);
- if (ok) DEBUG(3,("ACCEPTED: given username password ok\n"));
- }
-
- /* check for a previous registered username */
- if (!ok && *password && (vuid >= 0) && validated_users[vuid].guest)
- {
-
- if (user_ok(validated_users[vuid].name,snum) &&
- password_ok(validated_users[vuid].name, password, NULL))
- {
- strcpy(user, validated_users[vuid].name);
- validated_users[vuid].guest = False;
- DEBUG(3,("ACCEPTED: given password with registered user %s\n", user));
- ok = True;
- }
- }
-
-
- /* now check the list of session users */
- if (!ok && *password && !lp_onlyuser(snum))
- {
- strcpy(user_list,session_users);
-
- for (auser=strtok(user_list,LIST_SEP);
- !ok && auser;
- auser = strtok(NULL,LIST_SEP))
- {
- if (!user_ok(auser,snum)) continue;
-
- if (password_ok(auser,password, NULL))
- {
- ok = True;
- strcpy(user,auser);
- DEBUG(3,("ACCEPTED: session list username and given password ok\n"));
- }
- }
- }
-
- /* check for a previously validated username/password pair */
- if (!ok && !lp_onlyuser(snum) &&
- (vuid >= 0) && !validated_users[vuid].guest &&
- user_ok(validated_users[vuid].name,snum))
- {
- strcpy(user,validated_users[vuid].name);
- *guest = False;
- DEBUG(3,("ACCEPTED: validated uid ok as non-guest\n"));
- ok = True;
- }
-
- /* check for a rhosts entry */
- if (!ok && user_ok(user,snum) && check_hosts_equiv(user))
- {
- ok = True;
- DEBUG(3,("ACCEPTED: hosts equiv or rhosts entry\n"));
- }
- }
-
- /* check the user= fields and the given password */
- if (!ok && *password && USER(snum))
- {
- strcpy(user_list,USER(snum));
-
- for (auser=strtok(user_list,LIST_SEP);
- auser && !ok;
- auser = strtok(NULL,LIST_SEP))
- {
- if (*auser == '@')
- {
- auser = validate_group(auser+1,password,snum);
- if (auser)
- {
- ok = True;
- strcpy(user,auser);
- DEBUG(3,("ACCEPTED: group username and given password ok\n"));
- }
- }
- else
- {
- if (user_ok(auser,snum) && password_ok(auser,password,NULL))
- {
- ok = True;
- strcpy(user,auser);
- DEBUG(3,("ACCEPTED: user list username and given password ok\n"));
- }
- }
- }
- }
-
- } /* not guest only */
-
- /* check for a user= with no password (guest connection) */
- if (!ok && USER(snum) && (*USER(snum)) && GUEST_OK(snum))
- {
- strcpy(user_list,USER(snum));
- auser = strtok(user_list,LIST_SEP);
- if (*auser == '@')
- DEBUG(2,("can't use group as guest user\n"));
- else
- {
- if (auser && Get_Pwnam(auser))
- {
- ok = True;
- strcpy(user,auser);
- DEBUG(3,("ACCEPTED: user list username and guest ok\n"));
- }
- else
- DEBUG(0,("Invalid user account %s??\n",auser?auser:"NULL"));
- }
- *guest = True;
- }
-
- /* check for a normal guest connection */
- if (!ok && GUEST && (*GUEST) && GUEST_OK(snum))
- {
- if (Get_Pwnam(GUEST))
- {
- strcpy(user,GUEST);
- ok = True;
- DEBUG(3,("ACCEPTED: guest account and guest ok\n"));
- }
- else
- DEBUG(0,("Invalid guest account %s??\n",GUEST?GUEST:"NULL"));
- *guest = True;
- }
-
- if (ok && !user_ok(user,snum))
- {
- DEBUG(0,("rejected invalid user %s\n",user));
- ok = False;
- }
-
- return(ok);
- }
-
- /****************************************************************************
- read the a hosts.equiv or .rhosts file and check if it
- allows this user from this machine
- ****************************************************************************/
- BOOL check_user_equiv(char *user, char *remote, char *equiv_file)
- {
- pstring buf;
- int plus_allowed = 1;
- char *file_host;
- char *file_user;
- FILE *fp = fopen(equiv_file, "r");
- DEBUG(5, ("check_user_equiv %s %s %s\n", user, remote, equiv_file));
- if (! fp) return False;
- while(fgets(buf, sizeof(buf), fp))
- {
- trim_string(buf," "," ");
-
- if (buf[0] != '#' && buf[0] != '\n')
- {
- BOOL is_group = False;
- int plus = 1;
- char *bp = buf;
- if (strcmp(buf, "NO_PLUS\n") == 0)
- {
- DEBUG(6, ("check_user_equiv NO_PLUS\n"));
- plus_allowed = 0;
- }
- else {
- if (buf[0] == '+')
- {
- bp++;
- if (*bp == '\n' && plus_allowed)
- {
- /* a bare plus means everbody allowed */
- DEBUG(6, ("check_user_equiv everybody allowed\n"));
- fclose(fp);
- return True;
- }
- }
- else if (buf[0] == '-')
- {
- bp++;
- plus = 0;
- }
- if (*bp == '@')
- {
- is_group = True;
- bp++;
- }
- file_host = strtok(bp, " \t\n");
- file_user = strtok(NULL, " \t\n");
- DEBUG(7, ("check_user_equiv %s %s\n", file_host, file_user));
- if (file_host && *file_host)
- {
- BOOL host_ok = False;
-
- #ifdef NETGROUP
- /* THIS IS UNTESTED!! */
- if (is_group)
- {
- static char *mydomain = NULL;
- if (!mydomain)
- yp_get_default_domain(&mydomain);
- if (mydomain && innetgr(remote,file_host,user,mydomain))
- host_ok = True;
- }
- #else
- if (is_group)
- {
- DEBUG(1,("Netgroups not configured - add -DNETGROUP and recompile\n"));
- continue;
- }
- #endif
-
- /* is it this host */
- /* the fact that remote has come from a call of gethostbyaddr
- * means that it may have the fully qualified domain name
- * so we could look up the file version to get it into
- * a canonical form, but I would rather just type it
- * in full in the equiv file
- */
- if (!host_ok && !is_group && strequal(remote, file_host))
- host_ok = True;
-
- if (!host_ok)
- continue;
-
- /* is it this user */
- if (file_user == 0 || strequal(user, file_user))
- {
- fclose(fp);
- DEBUG(5, ("check_user_equiv matched %s%s %s\n",
- (plus ? "+" : "-"), file_host,
- (file_user ? file_user : "")));
- return (plus ? True : False);
- }
- }
- }
- }
- }
- fclose(fp);
- return False;
- }
-
-
- /****************************************************************************
- check for a possible hosts equiv or rhosts entry for the user
- ****************************************************************************/
- BOOL check_hosts_equiv(char *user)
- {
- char *fname = NULL;
- pstring rhostsfile;
- struct passwd *pass = Get_Pwnam(user);
-
- extern struct from_host Client_info;
- extern int Client;
-
- if (!pass)
- return(False);
-
- fromhost(Client,&Client_info);
-
- fname = lp_hosts_equiv();
-
- /* note: don't allow hosts.equiv on root */
- if (fname && *fname && (pass->pw_uid != 0))
- {
- if (check_user_equiv(user,Client_info.name,fname))
- return(True);
- }
-
- if (lp_use_rhosts())
- {
- char *home = get_home_dir(user);
- if (home)
- {
- sprintf(rhostsfile, "%s/.rhosts", home);
- if (check_user_equiv(user,Client_info.name,rhostsfile))
- return(True);
- }
- }
-
- return(False);
- }
-
-
- /*******************************************************************
- set a user password. Assumes the oldpass is already validated.
- ********************************************************************/
- BOOL set_user_password(char *user,char *oldpass,char *newpass)
- {
- #ifdef ALLOW_CHANGE_PASSWORD
- DEBUG(1,("Setting user password for: %s\n",user));
- return (chgpasswd(user,oldpass,newpass));
- #else
- DEBUG(3,("Change password is not supported: %s\n",user));
- return (False);
- #endif
- }
-