Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

546 lines
15 KiB

  1. /*++
  2. Copyright (c) 1987-1994 Microsoft Corporation
  3. Module Name:
  4. notify.c
  5. Abstract:
  6. Sample SubAuthentication Package.
  7. Author:
  8. Yi-Hsin Sung (yihsins) 27-Feb-1995
  9. Revisions:
  10. Environment:
  11. User mode only.
  12. Contains NT-specific code.
  13. Requires ANSI C extensions: slash-slash comments, long external names.
  14. Revision History:
  15. --*/
  16. #include <nt.h>
  17. #include <ntrtl.h>
  18. #include <nturtl.h>
  19. #include <ntsam.h>
  20. #include <ntlsa.h>
  21. #include <windef.h>
  22. #include <winbase.h>
  23. #include <winuser.h>
  24. #include <lmaccess.h>
  25. #include <lmapibuf.h>
  26. #include <nwsutil.h>
  27. #include <fpnwcomm.h>
  28. #include <usrprop.h>
  29. #include <fpnwapi.h>
  30. #include <nwsutil.h>
  31. #define SW_DLL_NAME L"swclnt.dll"
  32. #define PASSWORD_PROC_NAME "SwPasswordChangeNotify"
  33. #define NOTIFY_PROC_NAME "SwDeltaChangeNotify"
  34. #define NO_GRACE_LOGIN_LIMIT 0xFF
  35. typedef DWORD (*PWPROC)( LPWSTR pUserName,
  36. ULONG RelativeId,
  37. LPWSTR pPassword );
  38. DWORD
  39. GetNCPLSASecret(
  40. VOID
  41. );
  42. BOOL fTriedToGetSW = FALSE;
  43. BOOL fTriedToGetNCP = FALSE;
  44. HINSTANCE hinstSW = NULL;
  45. PWPROC ProcPasswordChange = NULL;
  46. PSAM_DELTA_NOTIFICATION_ROUTINE ProcDeltaChange = NULL;
  47. BOOL fGotSecret = FALSE;
  48. char szNWSecretValue[NCP_LSA_SECRET_LENGTH] = "";
  49. NTSTATUS
  50. PasswordChangeNotify(
  51. PUNICODE_STRING UserName,
  52. ULONG RelativeId,
  53. PUNICODE_STRING Password
  54. )
  55. {
  56. DWORD err = NO_ERROR;
  57. PUSER_INFO_2 pUserInfo2 = NULL;
  58. LPWSTR pszUser = NULL;
  59. LPWSTR pszPassword = NULL;
  60. //
  61. // If password is NULL, we can't get the cleartext password. Hence,
  62. // ignore this notification. Same for UserName.
  63. //
  64. if ( (Password == NULL) || (Password->Buffer == NULL) )
  65. return STATUS_SUCCESS;
  66. if ( (UserName == NULL) || (UserName->Buffer == NULL) )
  67. return STATUS_SUCCESS;
  68. //
  69. // if neither DSMN nor FPNW are installed, blow out of here as there's
  70. // nothing to do.
  71. //
  72. if ( ( fTriedToGetSW && hinstSW == NULL ) &&
  73. ( fTriedToGetNCP && fGotSecret == FALSE) )
  74. {
  75. return STATUS_SUCCESS;
  76. }
  77. //
  78. // Make sure user name and password are null terminated
  79. //
  80. pszUser = LocalAlloc( LMEM_ZEROINIT, UserName->Length + sizeof(WCHAR));
  81. if ( pszUser == NULL )
  82. return STATUS_NO_MEMORY;
  83. pszPassword = LocalAlloc( LMEM_ZEROINIT, Password->Length + sizeof(WCHAR));
  84. if ( pszPassword == NULL )
  85. {
  86. LocalFree( pszUser );
  87. return STATUS_NO_MEMORY;
  88. }
  89. memcpy( pszUser, UserName->Buffer, UserName->Length );
  90. memcpy( pszPassword, Password->Buffer, Password->Length );
  91. CharUpper( pszPassword );
  92. //
  93. // First, try to change the small world password if it is installed.
  94. //
  95. if ( !fTriedToGetSW )
  96. {
  97. hinstSW = LoadLibrary( SW_DLL_NAME );
  98. fTriedToGetSW = TRUE;
  99. }
  100. if (( hinstSW != NULL ) && ( ProcPasswordChange == NULL ))
  101. {
  102. ProcPasswordChange = (PWPROC) GetProcAddress( hinstSW,
  103. PASSWORD_PROC_NAME );
  104. }
  105. if ( ProcPasswordChange != NULL )
  106. {
  107. err = (ProcPasswordChange)( pszUser, RelativeId, pszPassword );
  108. }
  109. #if DBG
  110. if ( err )
  111. {
  112. KdPrint(("[FPNWCLNT] SwPasswordChangeNotify of user %ws changing returns %d.\n", pszUser, err ));
  113. }
  114. #endif
  115. //
  116. // we require that the PDC be rebooted after either DSMN or FPNW is
  117. // installed anywhere in the domain for the first server... if we
  118. // decide we shouldn't require a reboot, change the code such that
  119. // it looks for the LSA secret everytime, not just first time through.
  120. //
  121. if ( !fTriedToGetNCP ) {
  122. fTriedToGetNCP = TRUE;
  123. //
  124. // Get the LSA secret used to encrypt the password
  125. //
  126. err = GetNCPLSASecret();
  127. }
  128. if ( !fGotSecret ) {
  129. goto CleanUp;
  130. }
  131. //
  132. // Next, change the netware password residue in the user parms field
  133. //
  134. err = NetUserGetInfo( NULL,
  135. pszUser,
  136. 2,
  137. (LPBYTE *) &pUserInfo2 );
  138. if ( !err )
  139. {
  140. WCHAR PropertyFlag;
  141. UNICODE_STRING PropertyValue;
  142. err = RtlNtStatusToDosError(
  143. NetpParmsQueryUserProperty( pUserInfo2->usri2_parms,
  144. NWPASSWORD,
  145. &PropertyFlag,
  146. &PropertyValue ));
  147. if ( !err && PropertyValue.Length != 0 )
  148. {
  149. //
  150. // This is a netware-enabled user, we need to store
  151. // the new password residue into the user parms
  152. //
  153. NT_PRODUCT_TYPE ProductType;
  154. WCHAR szEncryptedNWPassword[NWENCRYPTEDPASSWORDLENGTH];
  155. DWORD dwUserId;
  156. WORD wGraceLoginRemaining;
  157. WORD wGraceLoginAllowed;
  158. LocalFree( PropertyValue.Buffer );
  159. //
  160. // Get the grace login allowed and remaining value
  161. //
  162. err = RtlNtStatusToDosError(
  163. NetpParmsQueryUserProperty( pUserInfo2->usri2_parms,
  164. GRACELOGINREMAINING,
  165. &PropertyFlag,
  166. &PropertyValue ));
  167. if ( !err && ( PropertyValue.Length != 0 ))
  168. {
  169. wGraceLoginRemaining = (WORD) *(PropertyValue.Buffer);
  170. LocalFree( PropertyValue.Buffer );
  171. if ( wGraceLoginRemaining != NO_GRACE_LOGIN_LIMIT )
  172. {
  173. // If the grace login remaining is not unlimited,
  174. // then we need to reset grace login remaining to
  175. // the value in grace login allowed. Hence, read the
  176. // grace login allowed value.
  177. err = RtlNtStatusToDosError(
  178. NetpParmsQueryUserProperty( pUserInfo2->usri2_parms,
  179. GRACELOGINALLOWED,
  180. &PropertyFlag,
  181. &PropertyValue ));
  182. if ( !err && ( PropertyValue.Length != 0 ))
  183. {
  184. wGraceLoginAllowed = (WORD) *(PropertyValue.Buffer);
  185. LocalFree( PropertyValue.Buffer );
  186. }
  187. }
  188. }
  189. if ( !err )
  190. {
  191. RtlGetNtProductType( &ProductType );
  192. dwUserId = MapRidToObjectId(
  193. RelativeId,
  194. pszUser,
  195. ProductType == NtProductLanManNt,
  196. FALSE );
  197. err = RtlNtStatusToDosError(
  198. ReturnNetwareForm(
  199. szNWSecretValue,
  200. dwUserId,
  201. pszPassword,
  202. (UCHAR *) szEncryptedNWPassword ));
  203. }
  204. if ( !err )
  205. {
  206. LPWSTR pNewUserParms = NULL;
  207. BOOL fUpdate;
  208. UNICODE_STRING uPropertyValue;
  209. uPropertyValue.Buffer = szEncryptedNWPassword;
  210. uPropertyValue.Length = uPropertyValue.MaximumLength
  211. = sizeof( szEncryptedNWPassword );
  212. err = RtlNtStatusToDosError(
  213. NetpParmsSetUserProperty(
  214. pUserInfo2->usri2_parms,
  215. NWPASSWORD,
  216. uPropertyValue,
  217. PropertyFlag,
  218. &pNewUserParms,
  219. &fUpdate ));
  220. if ( !err && fUpdate )
  221. {
  222. USER_INFO_1013 userInfo1013;
  223. LPWSTR pNewUserParms2 = NULL;
  224. LPWSTR pNewUserParms3 = NULL;
  225. LARGE_INTEGER currentTime;
  226. //
  227. // Since we're resetting the user's password, let's
  228. // also clear the flag saying the password has
  229. // expired. We do this by putting the current
  230. // time into the NWPasswordSet.
  231. //
  232. NtQuerySystemTime (&currentTime);
  233. uPropertyValue.Buffer = (PWCHAR) &currentTime;
  234. uPropertyValue.Length = sizeof (LARGE_INTEGER);
  235. uPropertyValue.MaximumLength = sizeof (LARGE_INTEGER);
  236. NetpParmsSetUserProperty( pNewUserParms,
  237. NWTIMEPASSWORDSET,
  238. uPropertyValue,
  239. (SHORT) 0, // not a set
  240. &pNewUserParms2,
  241. &fUpdate );
  242. if (pNewUserParms2 != NULL) {
  243. userInfo1013.usri1013_parms = pNewUserParms2;
  244. } else {
  245. userInfo1013.usri1013_parms = pNewUserParms;
  246. }
  247. if ( wGraceLoginRemaining != NO_GRACE_LOGIN_LIMIT )
  248. {
  249. // If the grace login remaining is not unlimited,
  250. // then we need to reset grace login remaining to
  251. // the value in grace login allowed.
  252. uPropertyValue.Buffer = (PWCHAR) &wGraceLoginAllowed;
  253. uPropertyValue.Length = uPropertyValue.MaximumLength
  254. = sizeof(wGraceLoginAllowed);
  255. NetpParmsSetUserProperty( userInfo1013.usri1013_parms,
  256. GRACELOGINREMAINING,
  257. uPropertyValue,
  258. (SHORT) 0, // not a set
  259. &pNewUserParms3,
  260. &fUpdate );
  261. if (pNewUserParms3 != NULL)
  262. userInfo1013.usri1013_parms = pNewUserParms3;
  263. }
  264. err = NetUserSetInfo( NULL,
  265. pszUser,
  266. USER_PARMS_INFOLEVEL,
  267. (LPBYTE) &userInfo1013,
  268. NULL );
  269. if (pNewUserParms2 != NULL)
  270. NetpParmsUserPropertyFree( pNewUserParms2 );
  271. if (pNewUserParms3 != NULL)
  272. NetpParmsUserPropertyFree( pNewUserParms3 );
  273. }
  274. if ( pNewUserParms != NULL )
  275. NetpParmsUserPropertyFree( pNewUserParms );
  276. }
  277. }
  278. NetApiBufferFree( pUserInfo2 );
  279. }
  280. #if DBG
  281. if ( err )
  282. {
  283. KdPrint(("[FPNWCLNT] Password of user %ws changing returns %d.\n",
  284. pszUser, err ));
  285. }
  286. #endif
  287. CleanUp:
  288. LocalFree( pszUser );
  289. // Need to clear all memory that contains password
  290. memset( pszPassword, 0, Password->Length + sizeof( WCHAR ));
  291. LocalFree( pszPassword );
  292. return STATUS_SUCCESS;
  293. }
  294. BOOLEAN
  295. InitializeChangeNotify (
  296. VOID
  297. )
  298. {
  299. DWORD err = NO_ERROR;
  300. //
  301. // First, check to see if small world is installed.
  302. //
  303. if ( !fTriedToGetSW )
  304. {
  305. hinstSW = LoadLibrary( SW_DLL_NAME );
  306. fTriedToGetSW = TRUE;
  307. }
  308. if (( hinstSW != NULL )) {
  309. return TRUE;
  310. }
  311. if ( !fTriedToGetNCP ) {
  312. fTriedToGetNCP = TRUE;
  313. //
  314. // Get the LSA secret used to encrypt the password
  315. //
  316. err = GetNCPLSASecret();
  317. }
  318. return (fGotSecret != 0);
  319. }
  320. DWORD
  321. GetNCPLSASecret(
  322. VOID
  323. )
  324. {
  325. DWORD err;
  326. LSA_HANDLE hlsaPolicy;
  327. OBJECT_ATTRIBUTES oa;
  328. SECURITY_QUALITY_OF_SERVICE sqos;
  329. LSA_HANDLE hlsaSecret;
  330. UNICODE_STRING uSecretName;
  331. UNICODE_STRING *puSecretValue;
  332. LARGE_INTEGER lintCurrentSetTime, lintOldSetTime;
  333. sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  334. sqos.ImpersonationLevel = SecurityImpersonation;
  335. sqos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  336. sqos.EffectiveOnly = FALSE;
  337. //
  338. // Set up the object attributes prior to opening the LSA.
  339. //
  340. InitializeObjectAttributes( &oa, NULL, 0L, NULL, NULL );
  341. //
  342. // The InitializeObjectAttributes macro presently store NULL for
  343. // the psqos field, so we must manually copy that
  344. // structure for now.
  345. //
  346. oa.SecurityQualityOfService = &sqos;
  347. err = RtlNtStatusToDosError( LsaOpenPolicy( NULL,
  348. &oa,
  349. GENERIC_EXECUTE,
  350. &hlsaPolicy ));
  351. if ( !err )
  352. {
  353. RtlInitUnicodeString( &uSecretName, NCP_LSA_SECRET_KEY );
  354. err = RtlNtStatusToDosError( LsaOpenSecret( hlsaPolicy,
  355. &uSecretName,
  356. SECRET_QUERY_VALUE,
  357. &hlsaSecret ));
  358. if ( !err )
  359. {
  360. err = RtlNtStatusToDosError(
  361. LsaQuerySecret( hlsaSecret,
  362. &puSecretValue,
  363. &lintCurrentSetTime,
  364. NULL,
  365. &lintOldSetTime ));
  366. if ( !err )
  367. {
  368. memcpy( szNWSecretValue,
  369. puSecretValue->Buffer,
  370. NCP_LSA_SECRET_LENGTH );
  371. fGotSecret = TRUE;
  372. (VOID) LsaFreeMemory( puSecretValue );
  373. }
  374. (VOID) LsaClose( hlsaSecret );
  375. }
  376. (VOID) LsaClose( hlsaPolicy );
  377. }
  378. return err;
  379. }
  380. NTSTATUS
  381. DeltaNotify(
  382. IN PSID DomainSid,
  383. IN SECURITY_DB_DELTA_TYPE DeltaType,
  384. IN SECURITY_DB_OBJECT_TYPE ObjectType,
  385. IN ULONG ObjectRid,
  386. IN PUNICODE_STRING ObjectName OPTIONAL,
  387. IN PLARGE_INTEGER ModifiedCount,
  388. IN PSAM_DELTA_DATA DeltaData OPTIONAL
  389. )
  390. {
  391. NTSTATUS err = NO_ERROR;
  392. //
  393. // Try to notify small world of SAM changes if it is installed.
  394. //
  395. if ( !fTriedToGetSW )
  396. {
  397. hinstSW = LoadLibrary( SW_DLL_NAME );
  398. fTriedToGetSW = TRUE;
  399. }
  400. if ( ( hinstSW != NULL ) && ( ProcDeltaChange == NULL ))
  401. {
  402. ProcDeltaChange = (PSAM_DELTA_NOTIFICATION_ROUTINE)
  403. GetProcAddress( hinstSW, NOTIFY_PROC_NAME );
  404. }
  405. if ( ProcDeltaChange != NULL )
  406. {
  407. err = (ProcDeltaChange)( DomainSid,
  408. DeltaType,
  409. ObjectType,
  410. ObjectRid,
  411. ObjectName,
  412. ModifiedCount,
  413. DeltaData );
  414. }
  415. #if DBG
  416. if ( err )
  417. {
  418. KdPrint(("[FPNWCLNT] SwDeltaChangeNotify of type %d on rid 0x%x returns %d.\n", DeltaType, ObjectRid, err ));
  419. }
  420. #endif
  421. return(STATUS_SUCCESS);
  422. }