関数 | |
static NTSTATUS | check_oem_password (const char *user, uchar password_encrypted_with_lm_hash[516], const uchar old_lm_hash_encrypted[16], uchar password_encrypted_with_nt_hash[516], const uchar old_nt_hash_encrypted[16], struct samu **hnd, char *new_passwd, int new_passwd_size) |
static int | findpty (char **slave) |
static int | dochild (int master, const char *slavedev, const struct passwd *pass, const char *passwordprogram, BOOL as_root) |
static int | expect (int master, char *issue, char *expected) |
static void | pwd_sub (char *buf) |
static int | talktochild (int master, const char *seq) |
static BOOL | chat_with_program (char *passwordprogram, const struct passwd *pass, char *chatsequence, BOOL as_root) |
BOOL | chgpasswd (const char *name, const struct passwd *pass, const char *oldpass, const char *newpass, BOOL as_root) |
BOOL | check_lanman_password (char *user, uchar *pass1, uchar *pass2, struct samu **hnd) |
BOOL | change_lanman_password (struct samu *sampass, uchar *pass2) |
NTSTATUS | pass_oem_change (char *user, uchar password_encrypted_with_lm_hash[516], const uchar old_lm_hash_encrypted[16], uchar password_encrypted_with_nt_hash[516], const uchar old_nt_hash_encrypted[16], uint32 *reject_reason) |
static BOOL | check_passwd_history (struct samu *sampass, const char *plaintext) |
NTSTATUS | change_oem_password (struct samu *hnd, char *old_passwd, char *new_passwd, BOOL as_root, uint32 *samr_reject_reason) |
変数 | |
passdb_ops | pdb_ops |
static NTSTATUS check_oem_password | ( | const char * | user, | |
uchar | password_encrypted_with_lm_hash[516], | |||
const uchar | old_lm_hash_encrypted[16], | |||
uchar | password_encrypted_with_nt_hash[516], | |||
const uchar | old_nt_hash_encrypted[16], | |||
struct samu ** | hnd, | |||
char * | new_passwd, | |||
int | new_passwd_size | |||
) | [static] |
chgpasswd.c の 763 行で定義されています。
参照先 samu::acct_ctrl・become_root()・decode_pw_buffer()・E_deshash()・E_md4hash()・E_old_pw_hash()・nt_lm_owf_gen()・samu::nt_pw・pdb_get_acct_ctrl()・pdb_get_lanman_passwd()・pdb_get_nt_passwd()・pdb_getsampwnam()・SamOEMhash()・samu_new()・unbecome_root().
参照元 pass_oem_change().
00770 { 00771 static uchar null_pw[16]; 00772 static uchar null_ntpw[16]; 00773 struct samu *sampass = NULL; 00774 uint8 *password_encrypted; 00775 const uint8 *encryption_key; 00776 const uint8 *lanman_pw, *nt_pw; 00777 uint32 acct_ctrl; 00778 uint32 new_pw_len; 00779 uchar new_nt_hash[16]; 00780 uchar new_lm_hash[16]; 00781 uchar verifier[16]; 00782 char no_pw[2]; 00783 BOOL ret; 00784 00785 BOOL nt_pass_set = (password_encrypted_with_nt_hash && old_nt_hash_encrypted); 00786 BOOL lm_pass_set = (password_encrypted_with_lm_hash && old_lm_hash_encrypted); 00787 00788 *hnd = NULL; 00789 00790 if ( !(sampass = samu_new( NULL )) ) { 00791 return NT_STATUS_NO_MEMORY; 00792 } 00793 00794 become_root(); 00795 ret = pdb_getsampwnam(sampass, user); 00796 unbecome_root(); 00797 00798 if (ret == False) { 00799 DEBUG(0, ("check_oem_password: getsmbpwnam returned NULL\n")); 00800 TALLOC_FREE(sampass); 00801 return NT_STATUS_NO_SUCH_USER; 00802 } 00803 00804 acct_ctrl = pdb_get_acct_ctrl(sampass); 00805 00806 if (acct_ctrl & ACB_DISABLED) { 00807 DEBUG(2,("check_lanman_password: account %s disabled.\n", user)); 00808 TALLOC_FREE(sampass); 00809 return NT_STATUS_ACCOUNT_DISABLED; 00810 } 00811 00812 if ((acct_ctrl & ACB_PWNOTREQ) && lp_null_passwords()) { 00813 /* construct a null password (in case one is needed */ 00814 no_pw[0] = 0; 00815 no_pw[1] = 0; 00816 nt_lm_owf_gen(no_pw, null_ntpw, null_pw); 00817 lanman_pw = null_pw; 00818 nt_pw = null_pw; 00819 00820 } else { 00821 /* save pointers to passwords so we don't have to keep looking them up */ 00822 if (lp_lanman_auth()) { 00823 lanman_pw = pdb_get_lanman_passwd(sampass); 00824 } else { 00825 lanman_pw = NULL; 00826 } 00827 nt_pw = pdb_get_nt_passwd(sampass); 00828 } 00829 00830 if (nt_pw && nt_pass_set) { 00831 /* IDEAL Case: passwords are in unicode, and we can 00832 * read use the password encrypted with the NT hash 00833 */ 00834 password_encrypted = password_encrypted_with_nt_hash; 00835 encryption_key = nt_pw; 00836 } else if (lanman_pw && lm_pass_set) { 00837 /* password may still be in unicode, but use LM hash version */ 00838 password_encrypted = password_encrypted_with_lm_hash; 00839 encryption_key = lanman_pw; 00840 } else if (nt_pass_set) { 00841 DEBUG(1, ("NT password change supplied for user %s, but we have no NT password to check it with\n", 00842 user)); 00843 TALLOC_FREE(sampass); 00844 return NT_STATUS_WRONG_PASSWORD; 00845 } else if (lm_pass_set) { 00846 if (lp_lanman_auth()) { 00847 DEBUG(1, ("LM password change supplied for user %s, but we have no LanMan password to check it with\n", 00848 user)); 00849 } else { 00850 DEBUG(1, ("LM password change supplied for user %s, but we have disabled LanMan authentication\n", 00851 user)); 00852 } 00853 TALLOC_FREE(sampass); 00854 return NT_STATUS_WRONG_PASSWORD; 00855 } else { 00856 DEBUG(1, ("password change requested for user %s, but no password supplied!\n", 00857 user)); 00858 TALLOC_FREE(sampass); 00859 return NT_STATUS_WRONG_PASSWORD; 00860 } 00861 00862 /* 00863 * Decrypt the password with the key 00864 */ 00865 SamOEMhash( password_encrypted, encryption_key, 516); 00866 00867 if ( !decode_pw_buffer(password_encrypted, new_passwd, new_passwd_size, &new_pw_len, 00868 nt_pass_set ? STR_UNICODE : STR_ASCII)) { 00869 TALLOC_FREE(sampass); 00870 return NT_STATUS_WRONG_PASSWORD; 00871 } 00872 00873 /* 00874 * To ensure we got the correct new password, hash it and 00875 * use it as a key to test the passed old password. 00876 */ 00877 00878 if (nt_pass_set) { 00879 /* NT passwords, verify the NT hash. */ 00880 00881 /* Calculate the MD4 hash (NT compatible) of the password */ 00882 memset(new_nt_hash, '\0', 16); 00883 E_md4hash(new_passwd, new_nt_hash); 00884 00885 if (nt_pw) { 00886 /* 00887 * check the NT verifier 00888 */ 00889 E_old_pw_hash(new_nt_hash, nt_pw, verifier); 00890 if (memcmp(verifier, old_nt_hash_encrypted, 16)) { 00891 DEBUG(0,("check_oem_password: old lm password doesn't match.\n")); 00892 TALLOC_FREE(sampass); 00893 return NT_STATUS_WRONG_PASSWORD; 00894 } 00895 00896 /* We could check the LM password here, but there is 00897 * little point, we already know the password is 00898 * correct, and the LM password might not even be 00899 * present. */ 00900 00901 /* Further, LM hash generation algorithms 00902 * differ with charset, so we could 00903 * incorrectly fail a perfectly valid password 00904 * change */ 00905 #ifdef DEBUG_PASSWORD 00906 DEBUG(100, 00907 ("check_oem_password: password %s ok\n", new_passwd)); 00908 #endif 00909 *hnd = sampass; 00910 return NT_STATUS_OK; 00911 } 00912 00913 if (lanman_pw) { 00914 /* 00915 * check the lm verifier 00916 */ 00917 E_old_pw_hash(new_nt_hash, lanman_pw, verifier); 00918 if (memcmp(verifier, old_lm_hash_encrypted, 16)) { 00919 DEBUG(0,("check_oem_password: old lm password doesn't match.\n")); 00920 TALLOC_FREE(sampass); 00921 return NT_STATUS_WRONG_PASSWORD; 00922 } 00923 #ifdef DEBUG_PASSWORD 00924 DEBUG(100, 00925 ("check_oem_password: password %s ok\n", new_passwd)); 00926 #endif 00927 *hnd = sampass; 00928 return NT_STATUS_OK; 00929 } 00930 } 00931 00932 if (lanman_pw && lm_pass_set) { 00933 00934 E_deshash(new_passwd, new_lm_hash); 00935 00936 /* 00937 * check the lm verifier 00938 */ 00939 E_old_pw_hash(new_lm_hash, lanman_pw, verifier); 00940 if (memcmp(verifier, old_lm_hash_encrypted, 16)) { 00941 DEBUG(0,("check_oem_password: old lm password doesn't match.\n")); 00942 TALLOC_FREE(sampass); 00943 return NT_STATUS_WRONG_PASSWORD; 00944 } 00945 00946 #ifdef DEBUG_PASSWORD 00947 DEBUG(100, 00948 ("check_oem_password: password %s ok\n", new_passwd)); 00949 #endif 00950 *hnd = sampass; 00951 return NT_STATUS_OK; 00952 } 00953 00954 /* should not be reached */ 00955 TALLOC_FREE(sampass); 00956 return NT_STATUS_WRONG_PASSWORD; 00957 }
static int findpty | ( | char ** | slave | ) | [static] |
chgpasswd.c の 63 行で定義されています。
参照先 line・readdirname()・sys_closedir()・sys_open()・sys_opendir().
参照元 chat_with_program().
00064 { 00065 int master; 00066 static fstring line; 00067 SMB_STRUCT_DIR *dirp; 00068 const char *dpname; 00069 00070 #if defined(HAVE_GRANTPT) 00071 /* Try to open /dev/ptmx. If that fails, fall through to old method. */ 00072 if ((master = sys_open("/dev/ptmx", O_RDWR, 0)) >= 0) 00073 { 00074 grantpt(master); 00075 unlockpt(master); 00076 *slave = (char *)ptsname(master); 00077 if (*slave == NULL) 00078 { 00079 DEBUG(0, 00080 ("findpty: Unable to create master/slave pty pair.\n")); 00081 /* Stop fd leak on error. */ 00082 close(master); 00083 return -1; 00084 } 00085 else 00086 { 00087 DEBUG(10, 00088 ("findpty: Allocated slave pty %s\n", *slave)); 00089 return (master); 00090 } 00091 } 00092 #endif /* HAVE_GRANTPT */ 00093 00094 fstrcpy(line, "/dev/ptyXX"); 00095 00096 dirp = sys_opendir("/dev"); 00097 if (!dirp) 00098 return (-1); 00099 while ((dpname = readdirname(dirp)) != NULL) 00100 { 00101 if (strncmp(dpname, "pty", 3) == 0 && strlen(dpname) == 5) 00102 { 00103 DEBUG(3, 00104 ("pty: try to open %s, line was %s\n", dpname, 00105 line)); 00106 line[8] = dpname[3]; 00107 line[9] = dpname[4]; 00108 if ((master = sys_open(line, O_RDWR, 0)) >= 0) 00109 { 00110 DEBUG(3, ("pty: opened %s\n", line)); 00111 line[5] = 't'; 00112 *slave = line; 00113 sys_closedir(dirp); 00114 return (master); 00115 } 00116 } 00117 } 00118 sys_closedir(dirp); 00119 return (-1); 00120 }
static int dochild | ( | int | master, | |
const char * | slavedev, | |||
const struct passwd * | pass, | |||
const char * | passwordprogram, | |||
BOOL | as_root | |||
) | [static] |
chgpasswd.c の 122 行で定義されています。
参照先 become_user_permanently()・gain_root_privilege()・sys_dup2()・sys_open()・tcgetattr()・tcsetattr().
参照元 chat_with_program().
00124 { 00125 int slave; 00126 struct termios stermios; 00127 gid_t gid; 00128 uid_t uid; 00129 char * const eptrs[1] = { NULL }; 00130 00131 if (pass == NULL) 00132 { 00133 DEBUG(0, 00134 ("dochild: user doesn't exist in the UNIX password database.\n")); 00135 return False; 00136 } 00137 00138 gid = pass->pw_gid; 00139 uid = pass->pw_uid; 00140 00141 gain_root_privilege(); 00142 00143 /* Start new session - gets rid of controlling terminal. */ 00144 if (setsid() < 0) 00145 { 00146 DEBUG(3, 00147 ("Weirdness, couldn't let go of controlling terminal\n")); 00148 return (False); 00149 } 00150 00151 /* Open slave pty and acquire as new controlling terminal. */ 00152 if ((slave = sys_open(slavedev, O_RDWR, 0)) < 0) 00153 { 00154 DEBUG(3, ("More weirdness, could not open %s\n", slavedev)); 00155 return (False); 00156 } 00157 #if defined(TIOCSCTTY) && !defined(SUNOS5) 00158 /* 00159 * On patched Solaris 10 TIOCSCTTY is defined but seems not to work, 00160 * see the discussion under 00161 * https://bugzilla.samba.org/show_bug.cgi?id=5366. 00162 */ 00163 if (ioctl(slave, TIOCSCTTY, 0) < 0) 00164 { 00165 DEBUG(3, ("Error in ioctl call for slave pty\n")); 00166 /* return(False); */ 00167 } 00168 #elif defined(I_PUSH) && defined(I_FIND) 00169 if (ioctl(slave, I_FIND, "ptem") == 0) { 00170 ioctl(slave, I_PUSH, "ptem"); 00171 } 00172 if (ioctl(slave, I_FIND, "ldterm") == 0) { 00173 ioctl(slave, I_PUSH, "ldterm"); 00174 } 00175 #endif 00176 00177 /* Close master. */ 00178 close(master); 00179 00180 /* Make slave stdin/out/err of child. */ 00181 00182 if (sys_dup2(slave, STDIN_FILENO) != STDIN_FILENO) 00183 { 00184 DEBUG(3, ("Could not re-direct stdin\n")); 00185 return (False); 00186 } 00187 if (sys_dup2(slave, STDOUT_FILENO) != STDOUT_FILENO) 00188 { 00189 DEBUG(3, ("Could not re-direct stdout\n")); 00190 return (False); 00191 } 00192 if (sys_dup2(slave, STDERR_FILENO) != STDERR_FILENO) 00193 { 00194 DEBUG(3, ("Could not re-direct stderr\n")); 00195 return (False); 00196 } 00197 if (slave > 2) 00198 close(slave); 00199 00200 /* Set proper terminal attributes - no echo, canonical input processing, 00201 no map NL to CR/NL on output. */ 00202 00203 if (tcgetattr(0, &stermios) < 0) 00204 { 00205 DEBUG(3, 00206 ("could not read default terminal attributes on pty\n")); 00207 return (False); 00208 } 00209 stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); 00210 stermios.c_lflag |= ICANON; 00211 #ifdef ONLCR 00212 stermios.c_oflag &= ~(ONLCR); 00213 #endif 00214 if (tcsetattr(0, TCSANOW, &stermios) < 0) 00215 { 00216 DEBUG(3, ("could not set attributes of pty\n")); 00217 return (False); 00218 } 00219 00220 /* make us completely into the right uid */ 00221 if (!as_root) 00222 { 00223 become_user_permanently(uid, gid); 00224 } 00225 00226 DEBUG(10, 00227 ("Invoking '%s' as password change program.\n", 00228 passwordprogram)); 00229 00230 /* execl() password-change application */ 00231 if (execle("/bin/sh", "sh", "-c", passwordprogram, NULL, eptrs) < 0) 00232 { 00233 DEBUG(3, ("Bad status returned from %s\n", passwordprogram)); 00234 return (False); 00235 } 00236 return (True); 00237 }
static int expect | ( | int | master, | |
char * | issue, | |||
char * | expected | |||
) | [static] |
chgpasswd.c の 239 行で定義されています。
参照先 errno・len・read_socket_with_timeout()・strequal()・strerror()・sys_write()・timeout・trim_char()・unix_wild_match().
参照元 _cleanup_failures()・talktochild().
00240 { 00241 pstring buffer; 00242 int attempts, timeout, nread, len; 00243 BOOL match = False; 00244 00245 for (attempts = 0; attempts < 2; attempts++) { 00246 if (!strequal(issue, ".")) { 00247 if (lp_passwd_chat_debug()) 00248 DEBUG(100, ("expect: sending [%s]\n", issue)); 00249 00250 if ((len = sys_write(master, issue, strlen(issue))) != strlen(issue)) { 00251 DEBUG(2,("expect: (short) write returned %d\n", len )); 00252 return False; 00253 } 00254 } 00255 00256 if (strequal(expected, ".")) 00257 return True; 00258 00259 /* Initial timeout. */ 00260 timeout = lp_passwd_chat_timeout() * 1000; 00261 nread = 0; 00262 buffer[nread] = 0; 00263 00264 while ((len = read_socket_with_timeout(master, buffer + nread, 1, 00265 sizeof(buffer) - nread - 1, 00266 timeout)) > 0) { 00267 nread += len; 00268 buffer[nread] = 0; 00269 00270 { 00271 /* Eat leading/trailing whitespace before match. */ 00272 pstring str; 00273 pstrcpy( str, buffer); 00274 trim_char( str, ' ', ' '); 00275 00276 if ((match = unix_wild_match(expected, str)) == True) { 00277 /* Now data has started to return, lower timeout. */ 00278 timeout = lp_passwd_chat_timeout() * 100; 00279 } 00280 } 00281 } 00282 00283 if (lp_passwd_chat_debug()) 00284 DEBUG(100, ("expect: expected [%s] received [%s] match %s\n", 00285 expected, buffer, match ? "yes" : "no" )); 00286 00287 if (match) 00288 break; 00289 00290 if (len < 0) { 00291 DEBUG(2, ("expect: %s\n", strerror(errno))); 00292 return False; 00293 } 00294 } 00295 00296 DEBUG(10,("expect: returning %s\n", match ? "True" : "False" )); 00297 return match; 00298 }
static void pwd_sub | ( | char * | buf | ) | [static] |
chgpasswd.c の 300 行で定義されています。
参照先 all_string_sub().
00301 { 00302 all_string_sub(buf, "\\n", "\n", 0); 00303 all_string_sub(buf, "\\r", "\r", 0); 00304 all_string_sub(buf, "\\s", " ", 0); 00305 all_string_sub(buf, "\\t", "\t", 0); 00306 }
static int talktochild | ( | int | master, | |
const char * | seq | |||
) | [static] |
chgpasswd.c の 308 行で定義されています。
参照先 expect()・next_token()・pwd_sub()・strequal().
参照元 chat_with_program().
00309 { 00310 int count = 0; 00311 fstring issue, expected; 00312 00313 fstrcpy(issue, "."); 00314 00315 while (next_token(&seq, expected, NULL, sizeof(expected))) 00316 { 00317 pwd_sub(expected); 00318 count++; 00319 00320 if (!expect(master, issue, expected)) 00321 { 00322 DEBUG(3, ("Response %d incorrect\n", count)); 00323 return False; 00324 } 00325 00326 if (!next_token(&seq, issue, NULL, sizeof(issue))) 00327 fstrcpy(issue, "."); 00328 00329 pwd_sub(issue); 00330 } 00331 if (!strequal(issue, ".")) { 00332 /* we have one final issue to send */ 00333 fstrcpy(expected, "."); 00334 if (!expect(master, issue, expected)) 00335 return False; 00336 } 00337 00338 return (count > 0); 00339 }
static BOOL chat_with_program | ( | char * | passwordprogram, | |
const struct passwd * | pass, | |||
char * | chatsequence, | |||
BOOL | as_root | |||
) | [static] |
chgpasswd.c の 341 行で定義されています。
参照先 become_root()・CatchChild()・CatchChildLeaveStatus()・DMAPI_ACCESS_CAPABILITY・dochild()・drop_effective_capability()・errno・findpty()・KERNEL_OPLOCK_CAPABILITY・sys_fork()・sys_waitpid()・talktochild()・unbecome_root().
参照元 chgpasswd().
00343 { 00344 char *slavedev; 00345 int master; 00346 pid_t pid, wpid; 00347 int wstat; 00348 BOOL chstat = False; 00349 00350 if (pass == NULL) { 00351 DEBUG(0, ("chat_with_program: user doesn't exist in the UNIX password database.\n")); 00352 return False; 00353 } 00354 00355 /* allocate a pseudo-terminal device */ 00356 if ((master = findpty(&slavedev)) < 0) { 00357 DEBUG(3, ("chat_with_program: Cannot Allocate pty for password change: %s\n", pass->pw_name)); 00358 return (False); 00359 } 00360 00361 /* 00362 * We need to temporarily stop CatchChild from eating 00363 * SIGCLD signals as it also eats the exit status code. JRA. 00364 */ 00365 00366 CatchChildLeaveStatus(); 00367 00368 if ((pid = sys_fork()) < 0) { 00369 DEBUG(3, ("chat_with_program: Cannot fork() child for password change: %s\n", pass->pw_name)); 00370 close(master); 00371 CatchChild(); 00372 return (False); 00373 } 00374 00375 /* we now have a pty */ 00376 if (pid > 0) { /* This is the parent process */ 00377 if ((chstat = talktochild(master, chatsequence)) == False) { 00378 DEBUG(3, ("chat_with_program: Child failed to change password: %s\n", pass->pw_name)); 00379 kill(pid, SIGKILL); /* be sure to end this process */ 00380 } 00381 00382 while ((wpid = sys_waitpid(pid, &wstat, 0)) < 0) { 00383 if (errno == EINTR) { 00384 errno = 0; 00385 continue; 00386 } 00387 break; 00388 } 00389 00390 if (wpid < 0) { 00391 DEBUG(3, ("chat_with_program: The process is no longer waiting!\n\n")); 00392 close(master); 00393 CatchChild(); 00394 return (False); 00395 } 00396 00397 /* 00398 * Go back to ignoring children. 00399 */ 00400 CatchChild(); 00401 00402 close(master); 00403 00404 if (pid != wpid) { 00405 DEBUG(3, ("chat_with_program: We were waiting for the wrong process ID\n")); 00406 return (False); 00407 } 00408 if (WIFEXITED(wstat) && (WEXITSTATUS(wstat) != 0)) { 00409 DEBUG(3, ("chat_with_program: The process exited with status %d \ 00410 while we were waiting\n", WEXITSTATUS(wstat))); 00411 return (False); 00412 } 00413 #if defined(WIFSIGNALLED) && defined(WTERMSIG) 00414 else if (WIFSIGNALLED(wstat)) { 00415 DEBUG(3, ("chat_with_program: The process was killed by signal %d \ 00416 while we were waiting\n", WTERMSIG(wstat))); 00417 return (False); 00418 } 00419 #endif 00420 } else { 00421 /* CHILD */ 00422 00423 /* 00424 * Lose any elevated privileges. 00425 */ 00426 drop_effective_capability(KERNEL_OPLOCK_CAPABILITY); 00427 drop_effective_capability(DMAPI_ACCESS_CAPABILITY); 00428 00429 /* make sure it doesn't freeze */ 00430 alarm(20); 00431 00432 if (as_root) 00433 become_root(); 00434 00435 DEBUG(3, ("chat_with_program: Dochild for user %s (uid=%d,gid=%d) (as_root = %s)\n", pass->pw_name, 00436 (int)getuid(), (int)getgid(), BOOLSTR(as_root) )); 00437 chstat = dochild(master, slavedev, pass, passwordprogram, as_root); 00438 00439 if (as_root) 00440 unbecome_root(); 00441 00442 /* 00443 * The child should never return from dochild() .... 00444 */ 00445 00446 DEBUG(0, ("chat_with_program: Error: dochild() returned %d\n", chstat)); 00447 exit(1); 00448 } 00449 00450 if (chstat) 00451 DEBUG(3, ("chat_with_program: Password change %ssuccessful for user %s\n", 00452 (chstat ? "" : "un"), pass->pw_name)); 00453 return (chstat); 00454 }
BOOL chgpasswd | ( | const char * | name, | |
const struct passwd * | pass, | |||
const char * | oldpass, | |||
const char * | newpass, | |||
BOOL | as_root | |||
) |
chgpasswd.c の 456 行で定義されています。
参照先 all_string_sub()・become_root()・chat_with_program()・len・pstring_sub()・smb_pam_passchange()・strstr_m()・unbecome_root().
参照元 change_oem_password()・set_user_info_23()・set_user_info_pw().
00458 { 00459 pstring passwordprogram; 00460 pstring chatsequence; 00461 size_t i; 00462 size_t len; 00463 00464 if (!oldpass) { 00465 oldpass = ""; 00466 } 00467 00468 DEBUG(3, ("chgpasswd: Password change (as_root=%s) for user: %s\n", BOOLSTR(as_root), name)); 00469 00470 #ifdef DEBUG_PASSWORD 00471 DEBUG(100, ("chgpasswd: Passwords: old=%s new=%s\n", oldpass, newpass)); 00472 #endif 00473 00474 /* Take the passed information and test it for minimum criteria */ 00475 00476 /* Password is same as old password */ 00477 if (strcmp(oldpass, newpass) == 0) { 00478 /* don't allow same password */ 00479 DEBUG(2, ("chgpasswd: Password Change: %s, New password is same as old\n", name)); /* log the attempt */ 00480 return (False); /* inform the user */ 00481 } 00482 00483 /* 00484 * Check the old and new passwords don't contain any control 00485 * characters. 00486 */ 00487 00488 len = strlen(oldpass); 00489 for (i = 0; i < len; i++) { 00490 if (iscntrl((int)oldpass[i])) { 00491 DEBUG(0, ("chgpasswd: oldpass contains control characters (disallowed).\n")); 00492 return False; 00493 } 00494 } 00495 00496 len = strlen(newpass); 00497 for (i = 0; i < len; i++) { 00498 if (iscntrl((int)newpass[i])) { 00499 DEBUG(0, ("chgpasswd: newpass contains control characters (disallowed).\n")); 00500 return False; 00501 } 00502 } 00503 00504 #ifdef WITH_PAM 00505 if (lp_pam_password_change()) { 00506 BOOL ret; 00507 #ifdef HAVE_SETLOCALE 00508 char *prevlocale = setlocale(LC_ALL, "C"); 00509 #endif 00510 00511 if (as_root) 00512 become_root(); 00513 00514 if (pass) { 00515 ret = smb_pam_passchange(pass->pw_name, oldpass, newpass); 00516 } else { 00517 ret = smb_pam_passchange(name, oldpass, newpass); 00518 } 00519 00520 if (as_root) 00521 unbecome_root(); 00522 00523 #ifdef HAVE_SETLOCALE 00524 setlocale(LC_ALL, prevlocale); 00525 #endif 00526 00527 return ret; 00528 } 00529 #endif 00530 00531 /* A non-PAM password change just doen't make sense without a valid local user */ 00532 00533 if (pass == NULL) { 00534 DEBUG(0, ("chgpasswd: user %s doesn't exist in the UNIX password database.\n", name)); 00535 return False; 00536 } 00537 00538 pstrcpy(passwordprogram, lp_passwd_program()); 00539 pstrcpy(chatsequence, lp_passwd_chat()); 00540 00541 if (!*chatsequence) { 00542 DEBUG(2, ("chgpasswd: Null chat sequence - no password changing\n")); 00543 return (False); 00544 } 00545 00546 if (!*passwordprogram) { 00547 DEBUG(2, ("chgpasswd: Null password program - no password changing\n")); 00548 return (False); 00549 } 00550 00551 if (as_root) { 00552 /* The password program *must* contain the user name to work. Fail if not. */ 00553 if (strstr_m(passwordprogram, "%u") == NULL) { 00554 DEBUG(0,("chgpasswd: Running as root the 'passwd program' parameter *MUST* contain \ 00555 the string %%u, and the given string %s does not.\n", passwordprogram )); 00556 return False; 00557 } 00558 } 00559 00560 pstring_sub(passwordprogram, "%u", name); 00561 /* note that we do NOT substitute the %o and %n in the password program 00562 as this would open up a security hole where the user could use 00563 a new password containing shell escape characters */ 00564 00565 pstring_sub(chatsequence, "%u", name); 00566 all_string_sub(chatsequence, "%o", oldpass, sizeof(pstring)); 00567 all_string_sub(chatsequence, "%n", newpass, sizeof(pstring)); 00568 return (chat_with_program 00569 (passwordprogram, pass, chatsequence, as_root)); 00570 }
chgpasswd.c の 586 行で定義されています。
参照先 samu::acct_ctrl・become_root()・D_P16()・pdb_get_acct_ctrl()・pdb_get_lanman_passwd()・pdb_getsampwnam()・samu_new()・unbecome_root().
00588 { 00589 uchar unenc_new_pw[16]; 00590 uchar unenc_old_pw[16]; 00591 struct samu *sampass = NULL; 00592 uint32 acct_ctrl; 00593 const uint8 *lanman_pw; 00594 BOOL ret; 00595 00596 if ( !(sampass = samu_new(NULL)) ) { 00597 DEBUG(0, ("samu_new() failed!\n")); 00598 return False; 00599 } 00600 00601 become_root(); 00602 ret = pdb_getsampwnam(sampass, user); 00603 unbecome_root(); 00604 00605 if (ret == False) { 00606 DEBUG(0,("check_lanman_password: getsampwnam returned NULL\n")); 00607 TALLOC_FREE(sampass); 00608 return False; 00609 } 00610 00611 acct_ctrl = pdb_get_acct_ctrl (sampass); 00612 lanman_pw = pdb_get_lanman_passwd (sampass); 00613 00614 if (acct_ctrl & ACB_DISABLED) { 00615 DEBUG(0,("check_lanman_password: account %s disabled.\n", user)); 00616 TALLOC_FREE(sampass); 00617 return False; 00618 } 00619 00620 if (lanman_pw == NULL) { 00621 if (acct_ctrl & ACB_PWNOTREQ) { 00622 /* this saves the pointer for the caller */ 00623 *hnd = sampass; 00624 return True; 00625 } else { 00626 DEBUG(0, ("check_lanman_password: no lanman password !\n")); 00627 TALLOC_FREE(sampass); 00628 return False; 00629 } 00630 } 00631 00632 /* Get the new lanman hash. */ 00633 D_P16(lanman_pw, pass2, unenc_new_pw); 00634 00635 /* Use this to get the old lanman hash. */ 00636 D_P16(unenc_new_pw, pass1, unenc_old_pw); 00637 00638 /* Check that the two old passwords match. */ 00639 if (memcmp(lanman_pw, unenc_old_pw, 16)) { 00640 DEBUG(0,("check_lanman_password: old password doesn't match.\n")); 00641 TALLOC_FREE(sampass); 00642 return False; 00643 } 00644 00645 /* this saves the pointer for the caller */ 00646 *hnd = sampass; 00647 return True; 00648 }
chgpasswd.c の 658 行で定義されています。
参照先 samu::acct_ctrl・D_P16()・E_P16()・PDB_CHANGED・pdb_get_acct_ctrl()・pdb_get_lanman_passwd()・pdb_get_username()・pdb_set_lanman_passwd()・pdb_set_nt_passwd()・pdb_set_pass_last_set_time()・pdb_update_sam_account().
00659 { 00660 static uchar null_pw[16]; 00661 uchar unenc_new_pw[16]; 00662 BOOL ret; 00663 uint32 acct_ctrl; 00664 const uint8 *pwd; 00665 00666 if (sampass == NULL) { 00667 DEBUG(0,("change_lanman_password: no smb password entry.\n")); 00668 return False; 00669 } 00670 00671 acct_ctrl = pdb_get_acct_ctrl(sampass); 00672 pwd = pdb_get_lanman_passwd(sampass); 00673 00674 if (acct_ctrl & ACB_DISABLED) { 00675 DEBUG(0,("change_lanman_password: account %s disabled.\n", 00676 pdb_get_username(sampass))); 00677 return False; 00678 } 00679 00680 if (pwd == NULL) { 00681 if (acct_ctrl & ACB_PWNOTREQ) { 00682 uchar no_pw[14]; 00683 memset(no_pw, '\0', 14); 00684 E_P16(no_pw, null_pw); 00685 00686 /* Get the new lanman hash. */ 00687 D_P16(null_pw, pass2, unenc_new_pw); 00688 } else { 00689 DEBUG(0,("change_lanman_password: no lanman password !\n")); 00690 return False; 00691 } 00692 } else { 00693 /* Get the new lanman hash. */ 00694 D_P16(pwd, pass2, unenc_new_pw); 00695 } 00696 00697 if (!pdb_set_lanman_passwd(sampass, unenc_new_pw, PDB_CHANGED)) { 00698 return False; 00699 } 00700 00701 if (!pdb_set_nt_passwd (sampass, NULL, PDB_CHANGED)) { 00702 return False; /* We lose the NT hash. Sorry. */ 00703 } 00704 00705 if (!pdb_set_pass_last_set_time (sampass, time(NULL), PDB_CHANGED)) { 00706 TALLOC_FREE(sampass); 00707 /* Not quite sure what this one qualifies as, but this will do */ 00708 return False; 00709 } 00710 00711 /* Now flush the sam_passwd struct to persistent storage */ 00712 ret = NT_STATUS_IS_OK(pdb_update_sam_account (sampass)); 00713 00714 return ret; 00715 }
NTSTATUS pass_oem_change | ( | char * | user, | |
uchar | password_encrypted_with_lm_hash[516], | |||
const uchar | old_lm_hash_encrypted[16], | |||
uchar | password_encrypted_with_nt_hash[516], | |||
const uchar | old_nt_hash_encrypted[16], | |||
uint32 * | reject_reason | |||
) |
chgpasswd.c の 721 行で定義されています。
参照先 become_root()・change_oem_password()・check_oem_password()・new_passwd・unbecome_root().
参照元 _samr_chgpasswd_user()・_samr_chgpasswd_user3()・api_SamOEMChangePassword().
00727 { 00728 pstring new_passwd; 00729 struct samu *sampass = NULL; 00730 NTSTATUS nt_status = check_oem_password(user, password_encrypted_with_lm_hash, 00731 old_lm_hash_encrypted, 00732 password_encrypted_with_nt_hash, 00733 old_nt_hash_encrypted, 00734 &sampass, new_passwd, sizeof(new_passwd)); 00735 00736 if (!NT_STATUS_IS_OK(nt_status)) 00737 return nt_status; 00738 00739 /* We've already checked the old password here.... */ 00740 become_root(); 00741 nt_status = change_oem_password(sampass, NULL, new_passwd, True, reject_reason); 00742 unbecome_root(); 00743 00744 memset(new_passwd, 0, sizeof(new_passwd)); 00745 00746 TALLOC_FREE(sampass); 00747 00748 return nt_status; 00749 }
chgpasswd.c の 965 行で定義されています。
参照先 current_salt・dump_data()・E_md4hash()・E_md5hash()・samu::nt_pw・pdb_get_account_policy()・pdb_get_nt_passwd()・pdb_get_pw_history()・pdb_get_username().
00966 { 00967 uchar new_nt_p16[NT_HASH_LEN]; 00968 uchar zero_md5_nt_pw[SALTED_MD5_HASH_LEN]; 00969 const uint8 *nt_pw; 00970 const uint8 *pwhistory; 00971 BOOL found = False; 00972 int i; 00973 uint32 pwHisLen, curr_pwHisLen; 00974 00975 pdb_get_account_policy(AP_PASSWORD_HISTORY, &pwHisLen); 00976 if (pwHisLen == 0) { 00977 return False; 00978 } 00979 00980 pwhistory = pdb_get_pw_history(sampass, &curr_pwHisLen); 00981 if (!pwhistory || curr_pwHisLen == 0) { 00982 return False; 00983 } 00984 00985 /* Only examine the minimum of the current history len and 00986 the stored history len. Avoids race conditions. */ 00987 pwHisLen = MIN(pwHisLen,curr_pwHisLen); 00988 00989 nt_pw = pdb_get_nt_passwd(sampass); 00990 00991 E_md4hash(plaintext, new_nt_p16); 00992 00993 if (!memcmp(nt_pw, new_nt_p16, NT_HASH_LEN)) { 00994 DEBUG(10,("check_passwd_history: proposed new password for user %s is the same as the current password !\n", 00995 pdb_get_username(sampass) )); 00996 return True; 00997 } 00998 00999 dump_data(100, (const char *)new_nt_p16, NT_HASH_LEN); 01000 dump_data(100, (const char *)pwhistory, PW_HISTORY_ENTRY_LEN*pwHisLen); 01001 01002 memset(zero_md5_nt_pw, '\0', SALTED_MD5_HASH_LEN); 01003 for (i=0; i<pwHisLen; i++) { 01004 uchar new_nt_pw_salted_md5_hash[SALTED_MD5_HASH_LEN]; 01005 const uchar *current_salt = &pwhistory[i*PW_HISTORY_ENTRY_LEN]; 01006 const uchar *old_nt_pw_salted_md5_hash = &pwhistory[(i*PW_HISTORY_ENTRY_LEN)+ 01007 PW_HISTORY_SALT_LEN]; 01008 if (!memcmp(zero_md5_nt_pw, old_nt_pw_salted_md5_hash, SALTED_MD5_HASH_LEN)) { 01009 /* Ignore zero valued entries. */ 01010 continue; 01011 } 01012 /* Create salted versions of new to compare. */ 01013 E_md5hash(current_salt, new_nt_p16, new_nt_pw_salted_md5_hash); 01014 01015 if (!memcmp(new_nt_pw_salted_md5_hash, old_nt_pw_salted_md5_hash, SALTED_MD5_HASH_LEN)) { 01016 DEBUG(1,("check_passwd_history: proposed new password for user %s found in history list !\n", 01017 pdb_get_username(sampass) )); 01018 found = True; 01019 break; 01020 } 01021 } 01022 return found; 01023 }
NTSTATUS change_oem_password | ( | struct samu * | hnd, | |
char * | old_passwd, | |||
char * | new_passwd, | |||
BOOL | as_root, | |||
uint32 * | samr_reject_reason | |||
) |
chgpasswd.c の 1032 行で定義されています。
参照先 check_passwd_history()・chgpasswd()・Get_Pwnam()・http_timestring()・pdb_get_account_policy()・pdb_get_pass_can_change()・pdb_get_pass_can_change_time()・pdb_get_username()・pdb_set_plaintext_passwd()・pdb_update_sam_account()・smbrunsecret()・str_charnum()・username.
参照元 api_SetUserPassword()・pass_oem_change().
01033 { 01034 uint32 min_len; 01035 struct passwd *pass = NULL; 01036 const char *username = pdb_get_username(hnd); 01037 time_t can_change_time = pdb_get_pass_can_change_time(hnd); 01038 01039 if (samr_reject_reason) { 01040 *samr_reject_reason = Undefined; 01041 } 01042 01043 /* check to see if the secdesc has previously been set to disallow */ 01044 if (!pdb_get_pass_can_change(hnd)) { 01045 DEBUG(1, ("user %s does not have permissions to change password\n", username)); 01046 if (samr_reject_reason) { 01047 *samr_reject_reason = REJECT_REASON_OTHER; 01048 } 01049 return NT_STATUS_ACCOUNT_RESTRICTION; 01050 } 01051 01052 /* removed calculation here, becuase passdb now calculates 01053 based on policy. jmcd */ 01054 if ((can_change_time != 0) && (time(NULL) < can_change_time)) { 01055 DEBUG(1, ("user %s cannot change password now, must " 01056 "wait until %s\n", username, 01057 http_timestring(can_change_time))); 01058 if (samr_reject_reason) { 01059 *samr_reject_reason = REJECT_REASON_OTHER; 01060 } 01061 return NT_STATUS_ACCOUNT_RESTRICTION; 01062 } 01063 01064 if (pdb_get_account_policy(AP_MIN_PASSWORD_LEN, &min_len) && (str_charnum(new_passwd) < min_len)) { 01065 DEBUG(1, ("user %s cannot change password - password too short\n", 01066 username)); 01067 DEBUGADD(1, (" account policy min password len = %d\n", min_len)); 01068 if (samr_reject_reason) { 01069 *samr_reject_reason = REJECT_REASON_TOO_SHORT; 01070 } 01071 return NT_STATUS_PASSWORD_RESTRICTION; 01072 /* return NT_STATUS_PWD_TOO_SHORT; */ 01073 } 01074 01075 if (check_passwd_history(hnd,new_passwd)) { 01076 if (samr_reject_reason) { 01077 *samr_reject_reason = REJECT_REASON_IN_HISTORY; 01078 } 01079 return NT_STATUS_PASSWORD_RESTRICTION; 01080 } 01081 01082 pass = Get_Pwnam(username); 01083 if (!pass) { 01084 DEBUG(1, ("change_oem_password: Username %s does not exist in system !?!\n", username)); 01085 return NT_STATUS_ACCESS_DENIED; 01086 } 01087 01088 /* Use external script to check password complexity */ 01089 if (lp_check_password_script() && *(lp_check_password_script())) { 01090 int check_ret; 01091 01092 check_ret = smbrunsecret(lp_check_password_script(), new_passwd); 01093 DEBUG(5, ("change_oem_password: check password script (%s) returned [%d]\n", lp_check_password_script(), check_ret)); 01094 01095 if (check_ret != 0) { 01096 DEBUG(1, ("change_oem_password: check password script said new password is not good enough!\n")); 01097 if (samr_reject_reason) { 01098 *samr_reject_reason = REJECT_REASON_NOT_COMPLEX; 01099 } 01100 return NT_STATUS_PASSWORD_RESTRICTION; 01101 } 01102 } 01103 01104 /* 01105 * If unix password sync was requested, attempt to change 01106 * the /etc/passwd database first. Return failure if this cannot 01107 * be done. 01108 * 01109 * This occurs before the oem change, because we don't want to 01110 * update it if chgpasswd failed. 01111 * 01112 * Conditional on lp_unix_password_sync() because we don't want 01113 * to touch the unix db unless we have admin permission. 01114 */ 01115 01116 if(lp_unix_password_sync() && 01117 !chgpasswd(username, pass, old_passwd, new_passwd, as_root)) { 01118 return NT_STATUS_ACCESS_DENIED; 01119 } 01120 01121 if (!pdb_set_plaintext_passwd (hnd, new_passwd)) { 01122 return NT_STATUS_ACCESS_DENIED; 01123 } 01124 01125 /* Now write it into the file. */ 01126 return pdb_update_sam_account (hnd); 01127 }
struct passdb_ops pdb_ops |