荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: jjk (Linux Device Driver), 信区: InstallBBS
标  题: [转寄] 为FB2000增加密码保护机制[转载]
发信站: 荔园晨风BBS站 (Mon Jun 17 17:02:02 2002), 转信

【 以下文字转载自 jjk 的信箱 】
【 原文由 jjk.bbs@bbs.nju.edu.cn 所发表 】
发信人: quickmouse (碰猫死翘翘★偷得浮生半日闲), 信区: BBSDev
标  题: 为FB2000增加密码保护机制
发信站: 南京大学小百合站 (Sun Jun 16 13:14:50 2002), 站内信件

版本:FB2000
修改类型:功能增强
说明:这是一个在整理FB2000->FB2002时增加的一个功能,用于向用户提供帐号的保护
      机制。该机制类似于普通email注册时要求填写的密码丢失提示问题和答案。所
      不同的是由于bbs密码的单向加密功能使其无法反馈用户原有的密码而只能是重
      新设定用户密码。
      这套机制提供用户80字符密码提示问题和40字符密码问题回答的存储能力,其中
      40字符密码回答问题采取加密方式,拥有主机权限的人员也无法获取该问题答案。

补充说明:该机制目前仅在fb2002测试站通过测试,作者不负担由于程序原因导致的
          帐号安全问题。使用者可以修改该功能的提示信息以符合站点需要,
          但请保留提示中的版权信息。

修改分多个部分:
userinfo.c:
//struct used for passwd recall, add by quickmouse 2002-6
struct ResetPass
{
 unsigned int failed;
 char question[STRLEN];
 char answer[5][ENCPASSLEN];
};
// check passwd-recall passwd, which is 40B length,
// add by quickmouse 2002-6
int CheckResetPass(char *username)
{
 char filename[STRLEN];
 FILE *fp;
 struct ResetPass strp;
 struct stat st;
 int returnvalue = -1;
 int randomnum, i;
 char answer[STRLEN], pass[9];
 sethomefile(filename, username, "resetpasswd");
 if(stat(filename, &st) < 0)
  return 0;
 pass[8] = 0;
 if((fp = fopen(filename, "r")) != NULL)
 {
  fread(&strp, sizeof(strp), 1, fp);
  fclose(fp);
  srand(time(0) % getpid());
  while(1)
  {
   move(3, 0);
   clrtobot();
   prints("序列号:%d", (randomnum = random()&0x7fff));
   getdata(4, 0, "请输入上面显示的序列号(回车退出):", answer, 8, DOECHO, YEA
);
   if(atoi(answer) != randomnum)
   {
    prints("输入错误!");
    pressanykey();
    break;
   }
   if(strp.failed >= 3)
    if(st.st_mtime < time(0) - (3600 + (time(0)%10) * 360))
     strp.failed = 0;
    else
    {
     prints("尝试密码次数太多,请稍后再来\n");
     pressanykey();
     sleep(1);
     break;
    }
   prints("密码提示问题:%s", strp.question);
   getdata(6, 0, "请回答:", answer, STRLEN - 1, DOECHO, YEA);
   if( answer[0] == 0 )
    break;
   strp.failed ++;
   returnvalue = 1;
   for(i = 0; i < 5 && strp.answer[i][0] != 0; i++)
   {
    strncpy(pass, answer + (i * 8), 8);
    if(!checkpasswd(strp.answer[i], pass))
    {
     prints("回答错误!\n");
     returnvalue = -1;
     refresh();
     sleep(1 << strp.failed);
     break;
    }
   }
   if( returnvalue == 1)
    strp.failed = 0;
   if((fp = fopen(filename, "w")) != NULL)
   {
    fwrite(&strp, sizeof(strp), 1, fp);
    fclose(fp);
    if(returnvalue)
     break;
   }
  }
 }
 return returnvalue;
}
//set passwd-recall passwd,which is a 40B length passwd,
// the passwd is crypt, add by quickmouse, 2002-6
void SetResetPass(char *username)
{
 struct ResetPass strp;
 char buf[STRLEN], pass[9], buf1[STRLEN];
 int i = 0, askdel = 0, tmp;
 FILE *fp;
 pass[8] = 0;
 memset(&strp, 0 , sizeof(strp));
 clear();
 sethomefile(buf1, username, "resetpasswd");
 askdel = dashf(buf1);
 do
 {
  getdata(1, 0, "请输入密码提示问题(<80字符):", buf, STRLEN - 1, DOECHO, YEA
);
  if(buf[0] == 0)
   break;
  strncpy(strp.question, buf, STRLEN-1);
  getdata(2, 0, "请输入密码问题的回答(<40字符):", buf, 40, DOECHO, YEA);
  if(buf[0] == 0)
   break;
  buf[40] = 0;
  getdata(3, 0, "请再次输入密码问题的回答(<40字符):", buf1, 40, DOECHO, YEA)
;
  if(strcmp(buf, buf1))
  {
   prints("两次输入不一致,设置无效");
   pressanykey();
   askdel = 0;
   break;
  }
  tmp = strlen(buf);
  for( i = 0; i < 5 && i*8 <tmp; i++ )
  {
   strncpy(pass, buf + i * 8 , 8);
#ifdef ENCPASSLEN
   strncpy(strp.answer[i], genpasswd(pass), ENCPASSLEN);
#else
   strncpy(strp.answer[i], genpasswd(pass), PASSLEN);
#endif
  }
  sethomefile(buf, username, "resetpasswd");
  if((fp = fopen(buf, "w")) != NULL)
  {
   fwrite(&strp, sizeof(strp), 1, fp);
   fclose(fp);
  }
  prints("密码提示问题设置完毕!");
  pressanykey();
  return;
 }while(0);
 if(askdel)
 {
  if(askyn("您想删除原有的密码提示问题吗?", 0, 0) == 1)
  {
   unlink(buf1);
   prints("旧的密码提示问题已经删除");
   pressanykey();
  }
 }
 else
 {
  prints("未改变/设置密码提示问题及答案");
  pressanykey();
 }
 return;
}
// passwd recall main function, add a link to it
// in the comm_lists.c, add by quickmouse 2002-6
int GetLostPass(void)
{
 // 首先清屏,接着询问选项,如果为guest用户,则只有取回id密码
 // 普通用户有设置遗忘密码功能和取回id密码功能
 char ans[ENCPASSLEN], buf[STRLEN];
 int temp;
 struct userec record;
 //此处增加功能说明
 modify_user_mode(RESETPASS);
 clear();
 prints("设置密码丢失提示问题/重置丢失密码功能说明:\n");
 prints("用户可自行设置最大80字符长度的密码提示问题和最大40字符长度的回答\n"
);
 prints("用于在用户密码遗忘时通过其他帐号重置遗忘的密码。\n");
 prints("未设置提示问题及回答的帐号将无法通过此手段重置密码\n");
 prints("修改密码提示问题及答案需要输入帐号密码,及原有提示答案(没有可忽略)\
n");
 prints("所以请妥善保管密码丢失提示问题的答案\n\nDeveloped by quickmouse, co
pyright, 2002");
 pressanykey();
 clear();
 if(!strcmp(currentuser.userid, "guest"))  // guest user
 {
  getdata(1, 0, "请选择 (0)结束 (1)重置其他id的密码==> [0]" , ans, 2, DOECHO
, YEA);
  if(ans[0] > '1' || ans[0] < '0')
   ans[0] = '0';
 }
 else
  getdata(1, 0, "请选择 (0)结束 (1)重置其他id的密码 (2) 设置当前id重置密码问
题==> [0]", ans, 2, DOECHO, YEA);
 switch(ans[0])
 {
  case '2':
   getdata(2, 0, "请输入登陆密码: ", ans, PASSLEN, NOECHO, YEA);
   if (ans[0] == 0 || !checkpasswd(currentuser.passwd, ans))
   {
    prints("\n\n很抱歉, 您输入的密码不正确。\n");
    pressanykey();
    break;
   }
   if(CheckResetPass(currentuser.userid) >= 0)
    SetResetPass(currentuser.userid);
   break;
  case '1':
   if (!gettheuserid(2,"请输入要重置密码的用户名: ",&temp))
    break;
   record = lookupuser;
   if(CheckResetPass(record.userid) <= 0)
   {
    prints("该用户未设置密码丢失问题或回答错误");
    sprintf(buf, "by %s from %s", currentuser.userid, fromhost);
    logattempt(record.userid, buf);
    pressanykey();
    break;
   }
   prints("重置用户%s的密码\n", record.userid);
   if(ChangePasswd(NULL, record.passwd, record.userid, 8) < 0)
   {
    prints("密码设置失败,请重新来过");
   }
   else
   {
    if(substitute_record(PASSFILE, &record, sizeof(record), temp)< 0)
     prints("密码设置失败,请重新来过");
    else
    {
     sprintf(buf, "%s 重置 %s 的密码", currentuser.userid, record.userid);
     securityreport(buf);
     prints("密码设置成功!");
    }
   }
   pressanykey();
   break;
  case '0':
  default:
   break;
 }
 return 0;
}
// change user passwd in PASSWD file
// this is a standard routine for set user passwd
// it may be used in register.c and userinfo.c in
// which would set user passwd
int ChangePasswd(char *oldpass, char *newpass, char *userid, int line)
{
 char buf[PASSLEN], buf1[PASSLEN];
 if(oldpass != NULL)
 {
  getdata(line++, 0, "请输入原密码: ", buf, PASSLEN, NOECHO, YEA);
  if (*buf == '\0' || !checkpasswd(oldpass, buf))
  {
         prints("\n\n很抱歉, 您输入的密码不正确。\n");
         return -1;
  }
 }
 while(1)
 {
  getdata(line, 0, "请设定您的密码 (Setup Password): ", buf, PASSLEN, NOECHO
, YEA);
  if (strlen(buf) < 4 || !strcasecmp(buf, userid))
  {
   prints("密码太短或与使用者代号相同, 请重新输入\n");
   continue;
  }
  getdata(line+1, 0, "请再次输入您的密码 (Reconfirm Password): ", buf1, PASS
LEN, NOECHO, YEA);
  if(strcmp(buf1, buf))
  {
   prints("密码输入错误!\n");
   return -1;
  }
  else
  {
#ifdef ENCPASSLEN
   strncpy(newpass, genpasswd(buf), ENCPASSLEN);
#else
   strncpy(newpass, genpasswd(buf), PASSLEN);
#endif
   break;
  }
 }
 return 0;
}
// end of add, by quickmouse 2002-6

comm_lists.c:

在前面声明
int   GetLostPass(void); // by quickmouse 2002-6 密码查询问题

在sysconf_cmdlist[]里面增加
        {"GetLostPd", GetLostPass, 0},  // passwd recall function by quickmouse

modes.h

#define RESETPASS 56


modetype.c:

        case RESETPASS:
                  return "忘了密码?:)";

修改menu.ini
在I个人工具箱当中增加:
如果希望guest用户也能看到这个功能,则:
@GetLostPd     0, 0, 0, "GetPass",       "(G)etPass     密码丢失帮助"
否则,把这个         ^^改为PERM_BASIC或者其他限制权限

编译之后刷新菜单即可。

--
             ☆两个人相互辉映,光芒胜过夜晚繁星☆

                QuickMouse_China@yahoo.com.cn

※ 修改:.quickmouse 於 Jun 16 13:15:29 修改本文.[FROM: 211.69.197.73]
※ 来源:.南京大学小百合站 bbs.nju.edu.cn.[FROM: 211.69.197.73]
--
※ 转寄:.南京大学小百合站 bbs.nju.edu.cn.[FROM: 深圳大学BBS]

--
※ 转载:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.0.146]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店