Mathias.Wohlfarth@mw-eb.de
2004-Nov-30 11:41 UTC
[Samba] Securty hole (to Jeremy Allison):password chat
As you ar looking for security holes: With password chat it is easy to exchange the change password program and log to users passwords. Because on AIX password chat does not work we have implemented the unix password change with system calls directly from the samba code. We have a new parameter to switch this option on. It takes effect when unix password sync is yes. In this case password chat is never reached. The code is running with Samba 2.2.2 and 2.2.8 on AIX (80 locations each with about 80 to 300 users). I am going to implement this in 3.0.8 or 9 which will be our next production release. The code also has been tested with Linux, but only with few users. I have added the code and would be glad if you think it is worth to be implemented in a next release. regards Mathias ADD TO include/includes.h #include <userpw.h> #include <usersec.h> __________________________________________________________________________ ADD TO param/loadparm.c BOOL bDirectPasswdSync; Globals.bDirectPasswdSync = False; FN_GLOBAL_BOOL(lp_direct_password_sync, &Globals.bDirectPasswdSync) __________________________________________________________________________ ADD TO smbd/chgpasswd.c @@ -521,6 +542,43 @@ return ret; } #endif +/********************************************************************/ +/* ADDSTART security enhancement Mathias.Wohlfarth@m-wohlfarth.de */ +/********************************************************************/ + if (lp_direct_password_sync()) { + status = direct_password_sync(name,newpass,as_root); + if (!NT_STATUS_IS_OK(status)) { + /* we lose status here */ + /* confusing for the user - password is changed! */ + return False; + } + return True; /* forget the rest */ + } ___________________________________________________________________________ ADD NEW FUNCTION #include "includes.h" NTSTATUS direct_password_sync(const char *name,const char *newpass,BOOL as_root) { char salt[3]; #ifdef AIX #define PASSWD userpw #define GETPWNAM getuserpw #define PW_PASSWD upw_passwd #else /* tested on Linux */ #define PASSWD passwd #define GETPWNAM getpwnam #define PW_PASSWD pw_passwd #endif struct PASSWD *PASSWD; char *alpha "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890./"; if (as_root) become_root(); #ifdef AIX setpwdb(S_READ | S_WRITE); /* only AIX */ #endif if (! (PASSWD = GETPWNAM(name))) { DEBUG(0, ("Password Change: user %s unknown on operating system.\n", name)); #ifdef AIX endpwdb(); /* only for AIX */ #endif if (as_root) unbecome_root(); return NT_STATUS_INTERNAL_ERROR; } salt[0] = alpha[time(NULL) % strlen(alpha)]; salt[1] = alpha[getpid() % strlen(alpha)]; salt[2] = 0; PASSWD->PW_PASSWD = crypt(newpass,salt); #ifdef AIX userpw->upw_lastupdate = time(NULL); if (putuserpw(userpw)) { DEBUG(0, ("Password Change: could not change password for user %s on operating system.\n", name)); endpwdb(); if (as_root) unbecome_root(); return NT_STATUS_INTERNAL_ERROR; } endpwdb(); #else /* not AIX tested on Linux */ /* I like AIX */ #define PASSWD_MODE 0644 { FILE* tmp_file; FILE* sav_file; pstring passwd_name = "/etc/passwd"; pstring passwd_name_tmp = "/etc/passwd.smbd.tmp"; pstring passwd_name_sav = "/etc/opasswd.smbd"; struct passwd *passwd_tmp; tmp_file = sys_fopen(passwd_name_tmp,"w"); if (tmp_file == NULL) { DEBUG(0, ("Password Change: could not open %s (user:%s)", passwd_name_tmp,name)); if (as_root) unbecome_root(); return NT_STATUS_INTERNAL_ERROR; } sav_file = sys_fopen(passwd_name_sav,"w"); if (tmp_file == NULL) { DEBUG(0, ("Password Change: could not open %s (user:%s)", passwd_name_sav,name)); if (as_root) unbecome_root(); return NT_STATUS_INTERNAL_ERROR; } setpwent(); while ((passwd_tmp = getpwent()) != NULL) { if (strcmp(passwd_tmp->pw_name, PASSWD->pw_name) == 0) { if (putpwent(PASSWD,tmp_file) != 0) { DEBUG(0, ("Password Change: could not putpwent %s (user:%s)", passwd_name_tmp,name)); endpwent(); if (as_root) unbecome_root(); return NT_STATUS_INTERNAL_ERROR ; } } else { if (putpwent(passwd_tmp,tmp_file) != 0) { DEBUG(0, ("Password Change: could not putpwent %s (user:%s)", passwd_name_tmp,name)); endpwent(); if (as_root) unbecome_root(); return NT_STATUS_INTERNAL_ERROR; } } if (putpwent(passwd_tmp, sav_file) != 0) { DEBUG(0, ("Password Change: could not putpwent %s (user:%s)", passwd_name_sav,name)); endpwent(); if (as_root) unbecome_root(); return NT_STATUS_INTERNAL_ERROR; } } if (fclose(tmp_file) != 0) { DEBUG(0, ("Password Change: could not putpwent %s (user:%s)", passwd_name_tmp,name)); endpwent(); if (as_root) unbecome_root(); return NT_STATUS_INTERNAL_ERROR; } if (fclose(sav_file) != 0) { DEBUG(0, ("Password Change: could not putpwent %s (user:%s)", passwd_name_sav,name)); endpwent(); if (as_root) unbecome_root(); return NT_STATUS_INTERNAL_ERROR; } endpwent(); chmod(passwd_name_sav,0644); chmod(passwd_name_tmp,0644); if (rename(passwd_name_tmp, passwd_name) != 0) { DEBUG(0, ("Password Change: could not rename %s to %s (user:%s)", passwd_name_tmp,passwd_name,name)); endpwent(); if (as_root) unbecome_root(); return NT_STATUS_INTERNAL_ERROR; } } #endif /* not AIX */ /* all together now */ DEBUG(0, ("Password Change: changed password for user %s on operating system.\n", name)); if (as_root) unbecome_root(); return NT_STATUS_OK; /* forget the rest */ }