标题: net user查询命令的自行实现、兼谈学习方法
日期: 2003-12-11 13:09
"net user username"命令可以查看本机用户信息,比如密码是否过期,但无法查看指定服务器上指定用户信息。如果做为域用户登录,情况有变化。现在的需求是不想做为域用户登录,又想查看域控制器上的用户信息。
Samba所带的rpcclient满足需求:
--------------------------------------------------------------------------
$ ./rpcclient -U scz <target>
Password:
rpcclient $> lookupnames scz
scz S-
rpcclient $> queryuser 1173
User Name : scz
Logon Time : Thu, 11 Dec 2003 09:23:33
GMT
Password last set Time : Wed, 24 Sep 2003 13:27:03 GMT
Password can change Time : Wed, 24 Sep 2003 13:27:03 GMT
Password must change Time : Tue, 23 Dec 2003 13:27:03 GMT
user_rid : 0x495
group_rid : 0x201
rpcclient $>
--------------------------------------------------------------------------
先用lookupnames获取目标用户的RID,然后用queryuser查询之。上述信息处理过,只保留了我们感兴趣的部分。
MSDN里找到NetUserGetInfo()函数,附了一个例子,查询USER_INFO_10信息。我们需要查询USER_INFO_3信息。
如果已经存在到目标服务器的SMB会话,直接利用之。也可指定用户、密码重新建立
SMB会话。MSDN的例子太简单,基本不实用。
USER_INFO_3结构中没有密码过期的直接信息,只有usri3_password_age成员用于记录最后一次设置密码到"当前时刻"之间的秒数。显然只用NetUserGetInfo()不能满足原始需求。
在lusrmgr.msc中没有密码何时过期的设置。但在gpedit.msc中有:
本地计算机策略
计算机配置
Windows设置
安全设置
帐户策略
密码策略
密码最短存留期
密码最长存留期
闹了半天这是全局设置,不是用户名相关的设置。如果我对Windows使用熟悉的话,早该想到不能只依赖USER_INFO_3结构。看样子net user scz、rpcclient这些命令报告密码何时过期是结合了组策略信息、服务器当前时间的。
取服务器当前时间,减去usri3_password_age,就是最后一次设置密码的时刻。然后分别加上密码最短存留期、密码最长存留期,就是何时可以修改密码、何时必须修改密码的时刻。
取服务器当前时间,需要区分目标是远程还是本地。远程时用NetRemoteTOD()获取,本地时用C运行时库函数time()获取。
queryuser.c没有使用ctime(),因其使用了静态缓冲区,多线程编程时不太妙。尽管queryuser.c本身是单线程程序,但是在时间允许的前提下,不应该降低编程要求,为此自行实现了PrintTimeString(),这个过程也比较困难,缺乏sample。MSDN中的例子总是跟不上需求。
USER_INFO_3结构中的时间是RtlTime。C运行时库计算时间以1970年以基准,Win32
API计算时间以1601年为基准。这就涉及一个转换问题:
( RtlTime + 11644473600 ) * 10000000 -> FILETIME
MSDN垃圾到连这点都不提,我是测试最初的queryuser.c发现问题后用Google搜出来
的。
剩下就是如何获取组策略信息。tk提到过net.exe最终调用了net1.exe。用dumpbin察
看之:
> dumpbin /imports %systemroot%system32
et1.exe | find
"Net"
NetRemoteTOD
NetUserGetInfo
NetServiceEnum
有些已经很熟悉了,有些还很陌生,注意到NetUserModalsGet()。在MSDN中确认要找的就是它,查询USER_MODALS_INFO_0信息即可。
以上就是解决原始需求的整个过程,记录备忘,学习方法本身也需要不断总结。经验
积累得多了,就越容易发现问题、解决问题。
操作系统的不同永远不应该成为老虎吃天、无处下爪的理由。做为程序员,依据已有知识、经验,配合正确的学习方法、学习手段以及不可或缺的勤奋快速向陌生领域的纵深挺进,这是最基本的"素质"要求,否则不适合做程序员。数学史上的希尔伯特、军事史上的古德里安都是这种快速向陌生领域纵深挺进的典范。虽然无法望及大师们的项背,但学点精神总是可以的。
有几点学习经验:
1) 勇于、勤于Google,看到一切陌生但可能有意思的关键字,勇敢地将它们丢到互
联网上去搜索。不要放过一丝可能相关的信息。我曾经将Google的页面点击到45
页以后。
在一个txt文件中记录URL,而不是在浏览器提供的收藏夹中保存URL。不要只记录
跟当前工作相关的URL,而应该记录那些自己曾经感兴趣、正在感兴趣、即将感兴
趣的URL。
2) 有空的时候,不要看跟当前工作紧密相关的书籍,而应该看看不相关的方向。精
一个方向是正确的,但不能局限在这个视界里。
要避免贪多导致的最终一事无成。
不要陷入辩论中。辩论是口头上的巨人,对自己没什么好处。带着思辩的哲学观
点静观其"辩",可能对自己更有帮助些。各种操作系统的优劣,其辩论者十之七
八是跟风者。各种语言的比较,其辩论者十之七八是跟风者。
因时因地做出选择,没有亘古不变的选择。
3) 不要狂妄自大,但也不可妄自菲薄。每个人有自己擅长的,也有自己一窍不通的。
保持良好的学习心态,对自己写出来的疑问、猜测、回答、建议负责。提问的时
候,不应显得卑下,但保持必要的对陌生人的小学生守则上就有的礼节。回答的
时候,尽可能提供有帮助的信息,而不是"炫"。
一定要多交流,顾步自封显然会有麻烦。要不耻下问、上问。
4) 理论->实践->再理论,这条方法论至今不过时。学习理论,不迷信理论,大胆做
出科学的猜测,即使将来推翻了自己的猜测,也应记录下这个过程。如果实践肯
定了自己的猜测,更要立即整理、抽象、升华。
要勤于记录学习过程,结果固然重要,解决问题的过程同样重要。如果不是为了
树立一贯正确的高大形象,不想造个神出来,不妨将自己无数次失败的瞬间记录
下来,以后就可以少走很多弯路。
上述每一条背后都有真实的故事,以后有机会了,可以写写这些故事。经验是与人相
关的,仅仅是个人的经验,不代表真理,不代表指导思想。写出来,是为了交流学习
方法本身,没有别的意思。我也只是很普通的程序员,还好,不是太丢CS的人。
没有评论:
发表评论