当前位置: 技术问答>linux和unix
UNIX的master.passwd文件中的密码问题,急
来源: 互联网 发布时间:2014-11-17
本文导语: 现在因需要,一程序需要读取master.passwd用户名后面的加密密码,将用户输入密码使用和系统同样的方式加密后比较,判断是否可以登录,但是找来找去就是不知道UNIX系统的该密码是用何方法加密?哈森,MD5都试过了...
现在因需要,一程序需要读取master.passwd用户名后面的加密密码,将用户输入密码使用和系统同样的方式加密后比较,判断是否可以登录,但是找来找去就是不知道UNIX系统的该密码是用何方法加密?哈森,MD5都试过了就是加密出来和UNIX系统的不一样,adduser.c,pw.c,passwd.c的源代码全部分析过了,就是没有一点头绪,谁能帮我?
|
/*
* Copyright (c) 1992/3 Theo de Raadt
* Copyright (c) 1994 Olaf Kirch
* Copyright (c) 1995 Bill Paul
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifdef YP
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "yppasswd_private.h"
extern char *getnewpasswd __P(( struct passwd * , int ));
int
yp_passwd(char *user)
{
struct yppasswd yppasswd;
struct master_yppasswd master_yppasswd;
struct passwd *pw;
CLIENT *clnt;
struct rpc_err err;
char *master;
int *status = NULL;
uid_t uid;
char *sockname = YP_SOCKNAME;
_use_yp = 1;
uid = getuid();
if ((master = get_yp_master(1)) == NULL) {
warnx("failed to find NIS master server");
return(1);
}
/*
* It is presumed that by the time we get here, use_yp()
* has been called and that we have verified that the user
* actually exists. This being the case, the yp_password
* stucture has already been filled in for us.
*/
/* Use the correct password */
pw = (struct passwd *)&yp_password;
if (pw->pw_uid != uid && uid != 0) {
warnx("only the super-user may change account information
for other users");
return(1);
}
pw->pw_change = 0;
/* Initialize password information */
if (suser_override) {
master_yppasswd.newpw.pw_passwd = strdup(pw->pw_passwd);
master_yppasswd.newpw.pw_name = strdup(pw->pw_name);
master_yppasswd.newpw.pw_uid = pw->pw_uid;
master_yppasswd.newpw.pw_gid = pw->pw_gid;
master_yppasswd.newpw.pw_expire = pw->pw_expire;
master_yppasswd.newpw.pw_change = pw->pw_change;
master_yppasswd.newpw.pw_fields = pw->pw_fields;
master_yppasswd.newpw.pw_gecos = strdup(pw->pw_gecos);
master_yppasswd.newpw.pw_dir = strdup(pw->pw_dir);
master_yppasswd.newpw.pw_shell = strdup(pw->pw_shell);
master_yppasswd.newpw.pw_class = pw->pw_class != NULL ?
strdup(pw->pw_class) : "";
master_yppasswd.oldpass = "";
master_yppasswd.domain = yp_domain;
} else {
yppasswd.newpw.pw_passwd = strdup(pw->pw_passwd);
yppasswd.newpw.pw_name = strdup(pw->pw_name);
yppasswd.newpw.pw_uid = pw->pw_uid;
yppasswd.newpw.pw_gid = pw->pw_gid;
yppasswd.newpw.pw_gecos = strdup(pw->pw_gecos);
yppasswd.newpw.pw_dir = strdup(pw->pw_dir);
yppasswd.newpw.pw_shell = strdup(pw->pw_shell);
yppasswd.oldpass = "";
}
if (suser_override)
printf("Changing NIS password for %s on %s in domain %s.n",
pw->pw_name, master, yp_domain);
else
printf("Changing NIS password for %s on %s.n",
pw->pw_name, master);
/* Get old password */
if(pw->pw_passwd[0] && !suser_override) {
yppasswd.oldpass = strdup(getpass("Old Password: "));
if (strcmp(crypt(yppasswd.oldpass, pw->pw_passwd),
pw->pw_passwd))
//仔细看清楚这里,strcmp是一个字符串比较函数,因为UNIX系统所用的加密方法是单向算法,是不可逆的,所以重新加密用户输入的密码与现在密码字串进行比较,php4.1.1(我用过的版本中间也有一个这样的函数)
{
errx(1, "sorry");
}
}
if (suser_override) {
if ((master_yppasswd.newpw.pw_passwd = getnewpasswd(pw, 1)) == NULL)
return(1);
} else {
if ((yppasswd.newpw.pw_passwd = getnewpasswd(pw, 1)) == NULL)
return(1);
}
if (suser_override) {
if ((clnt = clnt_create(sockname, MASTER_YPPASSWDPROG,
MASTER_YPPASSWDVERS, "unix")) == NULL) {
warnx("failed to contact rpc.yppasswdd on host %s: %s",
master, clnt_spcreateerror(""));
return(1);
}
} else {
if ((clnt = clnt_create(master, YPPASSWDPROG,
YPPASSWDVERS, "udp")) == NULL) {
warnx("failed to contact rpc.yppasswdd on host %s: %s",
master, clnt_spcreateerror(""));
return(1);
}
}
/*
* The yppasswd.x file said `unix authentication required',
* so I added it. This is the only reason it is in here.
* My yppasswdd doesn't use it, but maybe some others out there
* do. --okir
*/
clnt->cl_auth = authunix_create_default();
if (suser_override)
status = yppasswdproc_update_master_1(&master_yppasswd, clnt);
else
status = yppasswdproc_update_1(&yppasswd, clnt);
clnt_geterr(clnt, &err);
auth_destroy(clnt->cl_auth);
clnt_destroy(clnt);
if (err.re_status != RPC_SUCCESS || status == NULL || *status) {
errx(1, "failed to change NIS password: %s",
clnt_sperrno(err.re_status));
}
printf("nNIS password has%s been changed on %s.n",
(err.re_status != RPC_SUCCESS || status == NULL || *status) ?
" not" : "", master);
return ((err.re_status || status == NULL || *status));
}
#endif /* YP */
* Copyright (c) 1992/3 Theo de Raadt
* Copyright (c) 1994 Olaf Kirch
* Copyright (c) 1995 Bill Paul
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifdef YP
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "yppasswd_private.h"
extern char *getnewpasswd __P(( struct passwd * , int ));
int
yp_passwd(char *user)
{
struct yppasswd yppasswd;
struct master_yppasswd master_yppasswd;
struct passwd *pw;
CLIENT *clnt;
struct rpc_err err;
char *master;
int *status = NULL;
uid_t uid;
char *sockname = YP_SOCKNAME;
_use_yp = 1;
uid = getuid();
if ((master = get_yp_master(1)) == NULL) {
warnx("failed to find NIS master server");
return(1);
}
/*
* It is presumed that by the time we get here, use_yp()
* has been called and that we have verified that the user
* actually exists. This being the case, the yp_password
* stucture has already been filled in for us.
*/
/* Use the correct password */
pw = (struct passwd *)&yp_password;
if (pw->pw_uid != uid && uid != 0) {
warnx("only the super-user may change account information
for other users");
return(1);
}
pw->pw_change = 0;
/* Initialize password information */
if (suser_override) {
master_yppasswd.newpw.pw_passwd = strdup(pw->pw_passwd);
master_yppasswd.newpw.pw_name = strdup(pw->pw_name);
master_yppasswd.newpw.pw_uid = pw->pw_uid;
master_yppasswd.newpw.pw_gid = pw->pw_gid;
master_yppasswd.newpw.pw_expire = pw->pw_expire;
master_yppasswd.newpw.pw_change = pw->pw_change;
master_yppasswd.newpw.pw_fields = pw->pw_fields;
master_yppasswd.newpw.pw_gecos = strdup(pw->pw_gecos);
master_yppasswd.newpw.pw_dir = strdup(pw->pw_dir);
master_yppasswd.newpw.pw_shell = strdup(pw->pw_shell);
master_yppasswd.newpw.pw_class = pw->pw_class != NULL ?
strdup(pw->pw_class) : "";
master_yppasswd.oldpass = "";
master_yppasswd.domain = yp_domain;
} else {
yppasswd.newpw.pw_passwd = strdup(pw->pw_passwd);
yppasswd.newpw.pw_name = strdup(pw->pw_name);
yppasswd.newpw.pw_uid = pw->pw_uid;
yppasswd.newpw.pw_gid = pw->pw_gid;
yppasswd.newpw.pw_gecos = strdup(pw->pw_gecos);
yppasswd.newpw.pw_dir = strdup(pw->pw_dir);
yppasswd.newpw.pw_shell = strdup(pw->pw_shell);
yppasswd.oldpass = "";
}
if (suser_override)
printf("Changing NIS password for %s on %s in domain %s.n",
pw->pw_name, master, yp_domain);
else
printf("Changing NIS password for %s on %s.n",
pw->pw_name, master);
/* Get old password */
if(pw->pw_passwd[0] && !suser_override) {
yppasswd.oldpass = strdup(getpass("Old Password: "));
if (strcmp(crypt(yppasswd.oldpass, pw->pw_passwd),
pw->pw_passwd))
//仔细看清楚这里,strcmp是一个字符串比较函数,因为UNIX系统所用的加密方法是单向算法,是不可逆的,所以重新加密用户输入的密码与现在密码字串进行比较,php4.1.1(我用过的版本中间也有一个这样的函数)
{
errx(1, "sorry");
}
}
if (suser_override) {
if ((master_yppasswd.newpw.pw_passwd = getnewpasswd(pw, 1)) == NULL)
return(1);
} else {
if ((yppasswd.newpw.pw_passwd = getnewpasswd(pw, 1)) == NULL)
return(1);
}
if (suser_override) {
if ((clnt = clnt_create(sockname, MASTER_YPPASSWDPROG,
MASTER_YPPASSWDVERS, "unix")) == NULL) {
warnx("failed to contact rpc.yppasswdd on host %s: %s",
master, clnt_spcreateerror(""));
return(1);
}
} else {
if ((clnt = clnt_create(master, YPPASSWDPROG,
YPPASSWDVERS, "udp")) == NULL) {
warnx("failed to contact rpc.yppasswdd on host %s: %s",
master, clnt_spcreateerror(""));
return(1);
}
}
/*
* The yppasswd.x file said `unix authentication required',
* so I added it. This is the only reason it is in here.
* My yppasswdd doesn't use it, but maybe some others out there
* do. --okir
*/
clnt->cl_auth = authunix_create_default();
if (suser_override)
status = yppasswdproc_update_master_1(&master_yppasswd, clnt);
else
status = yppasswdproc_update_1(&yppasswd, clnt);
clnt_geterr(clnt, &err);
auth_destroy(clnt->cl_auth);
clnt_destroy(clnt);
if (err.re_status != RPC_SUCCESS || status == NULL || *status) {
errx(1, "failed to change NIS password: %s",
clnt_sperrno(err.re_status));
}
printf("nNIS password has%s been changed on %s.n",
(err.re_status != RPC_SUCCESS || status == NULL || *status) ?
" not" : "", master);
return ((err.re_status || status == NULL || *status));
}
#endif /* YP */
|
It's very easy!
刚才把所有关于密码的源代码全部看了一次,我捡几个最关键的说一说:
以FreeBSD 4.5为例:
sub salt {
local($salt); # initialization
local($i, $rand);
local(@itoa64) = ( '0' .. '9', 'a' .. 'z', 'A' .. 'Z' ); # 0 .. 63
warn "calculate saltn" if $verbose > 1;
# to64
for ($i = 0; $i 1;
return $salt;
}
上面的代码是/usr/sbin/adduser的PERL源代码,从上面可以看出,返回的salt实际上是一个应用64个字符组成的随机数,然后循环26次,让该密钥(书名:干扰字串)更变态(不同版本的UNIX不同,查了一下资料,HP-UX使用25次循环),然后使用用户输入字串,使用随机生成的该密钥作为干扰字串使用crypt函数生成密码字串。
$cryptpwd = crypt($password, &salt) if $password ne "";
上面的代码过程中password变量为用户输入密码。
在用户登录验证的过程中,将master.passwd每个用户的第二个字段密码字串拿出来作为干扰字串,重新加密用户输入的密码然后再与该密码字串比较,如果相同,即可通过身份认证,呵呵
用PHP的语言来做的话可以这样
使用super(一种工具),让nobody可以以ROOT的身份执行chown
先将master.passwd中的密码字串读出,变量名为$biantai
用户输入密码为$sb
if (crypt($sb,$biantai)==$biantai)
{
echo "ok!";
}
最后重新使用chown把master.passwd文件所有权更改为ROOT,更新用户数据库pwd.db文件,搞定!
刚才把所有关于密码的源代码全部看了一次,我捡几个最关键的说一说:
以FreeBSD 4.5为例:
sub salt {
local($salt); # initialization
local($i, $rand);
local(@itoa64) = ( '0' .. '9', 'a' .. 'z', 'A' .. 'Z' ); # 0 .. 63
warn "calculate saltn" if $verbose > 1;
# to64
for ($i = 0; $i 1;
return $salt;
}
上面的代码是/usr/sbin/adduser的PERL源代码,从上面可以看出,返回的salt实际上是一个应用64个字符组成的随机数,然后循环26次,让该密钥(书名:干扰字串)更变态(不同版本的UNIX不同,查了一下资料,HP-UX使用25次循环),然后使用用户输入字串,使用随机生成的该密钥作为干扰字串使用crypt函数生成密码字串。
$cryptpwd = crypt($password, &salt) if $password ne "";
上面的代码过程中password变量为用户输入密码。
在用户登录验证的过程中,将master.passwd每个用户的第二个字段密码字串拿出来作为干扰字串,重新加密用户输入的密码然后再与该密码字串比较,如果相同,即可通过身份认证,呵呵
用PHP的语言来做的话可以这样
使用super(一种工具),让nobody可以以ROOT的身份执行chown
先将master.passwd中的密码字串读出,变量名为$biantai
用户输入密码为$sb
if (crypt($sb,$biantai)==$biantai)
{
echo "ok!";
}
最后重新使用chown把master.passwd文件所有权更改为ROOT,更新用户数据库pwd.db文件,搞定!