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.

1080 lines
26 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. Security.c
  5. Abstract:
  6. This module implements security related tasks in the
  7. NetWare redirector.
  8. Author:
  9. Colin Watson [ColinW] 05-Nov-1993
  10. Revision History:
  11. --*/
  12. #include "Procs.h"
  13. #include <stdio.h>
  14. PLOGON
  15. FindUserByName(
  16. IN PUNICODE_STRING UserName
  17. );
  18. //
  19. // The local debug trace level
  20. //
  21. #define Dbg (DEBUG_TRACE_SECURITY)
  22. #ifdef ALLOC_PRAGMA
  23. #pragma alloc_text( PAGE, CreateAnsiUid )
  24. #pragma alloc_text( PAGE, MakeUidServer )
  25. #pragma alloc_text( PAGE, FindUser )
  26. #pragma alloc_text( PAGE, FindUserByName )
  27. #pragma alloc_text( PAGE, GetUid )
  28. #pragma alloc_text( PAGE, FreeLogon )
  29. #pragma alloc_text( PAGE, Logon )
  30. #pragma alloc_text( PAGE, Logoff )
  31. #pragma alloc_text( PAGE, GetDriveMapTable )
  32. #endif
  33. VOID
  34. CreateAnsiUid(
  35. OUT PCHAR aUid,
  36. IN PLARGE_INTEGER Uid
  37. )
  38. /*++
  39. Routine Description:
  40. This routine converts the Uid into an array of ansi characters,
  41. preserving the uniqueness and allocating the buffer in the process.
  42. Note: aUid needs to be 17 bytes long.
  43. Arguments:
  44. OUT PCHAR aUid,
  45. IN PLARGE_INTEGER Uid
  46. Return Value:
  47. Status
  48. --*/
  49. {
  50. PAGED_CODE();
  51. if (Uid->HighPart != 0) {
  52. sprintf( aUid, "%lx%08lx\\", Uid->HighPart, Uid->LowPart );
  53. } else {
  54. sprintf( aUid, "%lx\\", Uid->LowPart );
  55. }
  56. return;
  57. }
  58. NTSTATUS
  59. MakeUidServer(
  60. PUNICODE_STRING UidServer,
  61. PLARGE_INTEGER Uid,
  62. PUNICODE_STRING Server
  63. )
  64. /*++
  65. Routine Description:
  66. This routine makes a Unicode string of the form 3e7\servername
  67. Arguments:
  68. OUT PUNICODE_STRING UidServer,
  69. IN PLARGE_INTEGER Uid,
  70. IN PUNICODE_STRING Server
  71. Return Value:
  72. Status
  73. --*/
  74. {
  75. //
  76. // Translate the servername into the form 3e7\Server where 3e7
  77. // is the value of the Uid.
  78. //
  79. UCHAR aUid[17];
  80. ANSI_STRING AnsiString;
  81. ULONG UnicodeLength;
  82. NTSTATUS Status;
  83. PAGED_CODE();
  84. CreateAnsiUid( aUid, Uid);
  85. RtlInitAnsiString( &AnsiString, aUid );
  86. UnicodeLength = RtlAnsiStringToUnicodeSize(&AnsiString);
  87. //
  88. // Ensuring we don't cause overflow, corrupting memory
  89. //
  90. if ( (UnicodeLength + (ULONG)Server->Length) > 0xFFFF ) {
  91. return STATUS_INSUFFICIENT_RESOURCES;
  92. }
  93. UidServer->MaximumLength = (USHORT)UnicodeLength + Server->Length;
  94. UidServer->Buffer = ALLOCATE_POOL(PagedPool,UidServer->MaximumLength);
  95. if (UidServer->Buffer == NULL) {
  96. DebugTrace(-1, Dbg, "MakeUidServer -> %08lx\n", STATUS_INSUFFICIENT_RESOURCES);
  97. return STATUS_INSUFFICIENT_RESOURCES;
  98. }
  99. Status = RtlAnsiStringToUnicodeString( UidServer, &AnsiString, FALSE);
  100. ASSERT(NT_SUCCESS(Status) && "MakeUidServer failed!");
  101. Status = RtlAppendStringToString( (PSTRING)UidServer, (PSTRING)Server);
  102. ASSERT(NT_SUCCESS(Status) && "MakeUidServer part 2 failed!");
  103. return STATUS_SUCCESS;
  104. }
  105. PLOGON
  106. FindUser(
  107. IN PLARGE_INTEGER Uid,
  108. IN BOOLEAN ExactMatch
  109. )
  110. /*++
  111. Routine Description:
  112. This routine searches the LogonList for the user entry corresponding
  113. to Uid.
  114. Note: Rcb must be held to prevent LogonList being changed.
  115. Arguments:
  116. IN PLARGE_INTEGER Uid
  117. IN BOOLEAN ExactMatch - if TRUE, don't return a default
  118. Return Value:
  119. None
  120. --*/
  121. {
  122. PLIST_ENTRY LogonQueueEntry = LogonList.Flink;
  123. PLOGON DefaultLogon = NULL;
  124. PAGED_CODE();
  125. DebugTrace(+1, Dbg, "FindUser...\n", 0);
  126. DebugTrace( 0, Dbg, " ->UserUidHigh = %08lx\n", Uid->HighPart);
  127. DebugTrace( 0, Dbg, " ->UserUidLow = %08lx\n", Uid->LowPart);
  128. while ( LogonQueueEntry != &LogonList ) {
  129. PLOGON Logon = CONTAINING_RECORD( LogonQueueEntry, LOGON, Next );
  130. if ( (*Uid).QuadPart == Logon->UserUid.QuadPart ) {
  131. DebugTrace(-1, Dbg, " ... %x\n", Logon );
  132. return Logon;
  133. }
  134. LogonQueueEntry = Logon->Next.Flink;
  135. }
  136. if (ExactMatch) {
  137. DebugTrace(-1, Dbg, " ... DefaultLogon NULL\n", 0 );
  138. return NULL;
  139. }
  140. LogonQueueEntry = LogonList.Flink;
  141. while ( LogonQueueEntry != &LogonList ) {
  142. PLOGON Logon = CONTAINING_RECORD( LogonQueueEntry, LOGON, Next );
  143. if (Logon->UserUid.QuadPart == DefaultLuid.QuadPart) {
  144. //
  145. // This is the first Default Logon entry. If this UID is not
  146. // in the table then this is the one to use.
  147. //
  148. DebugTrace(-1, Dbg, " ... DefaultLogon %lx\n", Logon );
  149. return Logon;
  150. }
  151. LogonQueueEntry = Logon->Next.Flink;
  152. }
  153. ASSERT( FALSE && "Couldn't find the Id" );
  154. DebugTrace(-1, Dbg, " ... DefaultLogon NULL\n", 0 );
  155. return NULL;
  156. }
  157. PLOGON
  158. FindUserByName(
  159. IN PUNICODE_STRING UserName
  160. )
  161. /*++
  162. Routine Description:
  163. This routine searches the LogonList for the user entry corresponding
  164. to Username.
  165. Note: Rcb must be held to prevent LogonList being changed.
  166. Arguments:
  167. UserName - The user name to find.
  168. Return Value:
  169. If found, a pointer to the logon structure
  170. NULL, if no match
  171. --*/
  172. {
  173. PLIST_ENTRY LogonQueueEntry = LogonList.Flink;
  174. PLOGON Logon;
  175. PAGED_CODE();
  176. DebugTrace(+1, Dbg, "FindUserByName...\n", 0);
  177. DebugTrace( 0, Dbg, " ->UserName = %wZ\n", UserName);
  178. while ( LogonQueueEntry != &LogonList ) {
  179. Logon = CONTAINING_RECORD( LogonQueueEntry, LOGON, Next );
  180. if ( RtlEqualUnicodeString( UserName, &Logon->UserName, TRUE ) ) {
  181. DebugTrace(-1, Dbg, " ... %x\n", Logon );
  182. return Logon;
  183. }
  184. LogonQueueEntry = Logon->Next.Flink;
  185. }
  186. DebugTrace(-1, Dbg, " ... NULL\n", 0 );
  187. return NULL;
  188. }
  189. PVCB *
  190. GetDriveMapTable (
  191. IN LARGE_INTEGER Uid
  192. )
  193. /*++
  194. Routine Description:
  195. This routine searches the LogonList for the user entry corresponding
  196. to Uid and returns the drive map table.
  197. Note: Rcb must be held to prevent LogonList being changed.
  198. Arguments:
  199. Uid - The user ID to find.
  200. Return Value:
  201. Always returns a value, even if the default
  202. --*/
  203. {
  204. PLOGON Logon;
  205. PAGED_CODE();
  206. Logon = FindUser(&Uid, TRUE);
  207. if ( Logon != NULL )
  208. return Logon->DriveMapTable;
  209. else {
  210. DebugTrace(+1, Dbg, "Using Global Drive Map Table.\n", 0);
  211. return GlobalDriveMapTable;
  212. }
  213. }
  214. LARGE_INTEGER
  215. GetUid(
  216. IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext
  217. )
  218. /*++
  219. Routine Description:
  220. This routine gets the effective UID to be used for this create.
  221. Arguments:
  222. SubjectSecurityContext - Supplies the information from IrpSp.
  223. Return Value:
  224. None
  225. --*/
  226. {
  227. LARGE_INTEGER LogonId;
  228. PAGED_CODE();
  229. DebugTrace(+1, Dbg, "GetUid ... \n", 0);
  230. // Is the thread currently impersonating someone else?
  231. if (SubjectSecurityContext->ClientToken != NULL) {
  232. //
  233. // If its impersonating someone that is logged in locally then use
  234. // the local id.
  235. //
  236. SeQueryAuthenticationIdToken(SubjectSecurityContext->ClientToken, (PLUID)&LogonId);
  237. if (FindUser(&LogonId, TRUE) == NULL) {
  238. //
  239. // Not logged on locally, use the processes LogonId so that the
  240. // gateway will work.
  241. //
  242. SeQueryAuthenticationIdToken(SubjectSecurityContext->PrimaryToken, (PLUID)&LogonId);
  243. }
  244. } else {
  245. //
  246. // Use the processes LogonId
  247. //
  248. SeQueryAuthenticationIdToken(SubjectSecurityContext->PrimaryToken, (PLUID)&LogonId);
  249. }
  250. DebugTrace( 0, Dbg, " ->UserUidHigh = %08lx\n", LogonId.HighPart);
  251. DebugTrace(-1, Dbg, " ->UserUidLow = %08lx\n", LogonId.LowPart);
  252. return LogonId;
  253. }
  254. VOID
  255. FreeLogon(
  256. IN PLOGON Logon
  257. )
  258. /*++
  259. Routine Description:
  260. This routine free's all the strings inside Logon and the structure itself.
  261. Arguments:
  262. IN PLOGON Logon
  263. Return Value:
  264. None
  265. --*/
  266. {
  267. PLIST_ENTRY pListEntry;
  268. PNDS_SECURITY_CONTEXT pContext;
  269. PAGED_CODE();
  270. if ((Logon == NULL) ||
  271. (Logon == &Guest)) {
  272. return;
  273. }
  274. if ( Logon->UserName.Buffer != NULL ) {
  275. FREE_POOL( Logon->UserName.Buffer );
  276. }
  277. if ( Logon->PassWord.Buffer != NULL ) {
  278. FREE_POOL( Logon->PassWord.Buffer );
  279. }
  280. if ( Logon->ServerName.Buffer != NULL ) {
  281. FREE_POOL( Logon->ServerName.Buffer );
  282. }
  283. while ( !IsListEmpty(&Logon->NdsCredentialList) ) {
  284. pListEntry = RemoveHeadList( &Logon->NdsCredentialList );
  285. pContext = CONTAINING_RECORD(pListEntry, NDS_SECURITY_CONTEXT, Next );
  286. FreeNdsContext( pContext );
  287. }
  288. ExDeleteResourceLite( &Logon->CredentialListResource );
  289. FREE_POOL( Logon );
  290. }
  291. NTSTATUS
  292. Logon(
  293. IN PIRP_CONTEXT IrpContext
  294. )
  295. /*++
  296. Routine Description:
  297. This routine takes the username and password supplied and makes
  298. them the default to be used for all connections.
  299. Arguments:
  300. IN PIRP_CONTEXT IrpContext - Io Request Packet for request
  301. Return Value:
  302. NTSTATUS
  303. --*/
  304. {
  305. NTSTATUS Status = STATUS_SUCCESS;
  306. PLOGON Logon = NULL;
  307. PIRP Irp = IrpContext->pOriginalIrp;
  308. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  309. PNWR_REQUEST_PACKET InputBuffer = Irp->AssociatedIrp.SystemBuffer;
  310. ULONGLONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  311. UNICODE_STRING ServerName;
  312. PNDS_SECURITY_CONTEXT pNdsContext;
  313. PAGED_CODE();
  314. DebugTrace(+1, Dbg, "Logon\n", 0);
  315. try {
  316. //
  317. // Check some fields in the input buffer.
  318. //
  319. if (InputBufferLength < sizeof(NWR_REQUEST_PACKET)) {
  320. try_return(Status = STATUS_BUFFER_TOO_SMALL);
  321. }
  322. if (InputBuffer->Version != REQUEST_PACKET_VERSION) {
  323. try_return(Status = STATUS_INVALID_PARAMETER);
  324. }
  325. if (InputBufferLength <
  326. (ULONGLONG)(FIELD_OFFSET(NWR_REQUEST_PACKET,Parameters.Logon.UserName)) +
  327. (ULONGLONG)InputBuffer->Parameters.Logon.UserNameLength +
  328. (ULONGLONG)InputBuffer->Parameters.Logon.PasswordLength +
  329. (ULONGLONG)InputBuffer->Parameters.Logon.ServerNameLength +
  330. (ULONGLONG)InputBuffer->Parameters.Logon.ReplicaAddrLength) {
  331. try_return(Status = STATUS_INVALID_PARAMETER);
  332. }
  333. if ((InputBuffer->Parameters.Logon.UserNameLength % 2) ||
  334. (InputBuffer->Parameters.Logon.PasswordLength % 2) ||
  335. (InputBuffer->Parameters.Logon.ServerNameLength % 2) ||
  336. (InputBuffer->Parameters.Logon.ReplicaAddrLength % 2)) {
  337. try_return(Status = STATUS_INVALID_PARAMETER);
  338. }
  339. Logon = ALLOCATE_POOL(NonPagedPool,sizeof(LOGON));
  340. if (Logon == NULL) {
  341. try_return( Status = STATUS_INSUFFICIENT_RESOURCES );
  342. }
  343. RtlZeroMemory(Logon, sizeof(LOGON));
  344. Logon->NodeTypeCode = NW_NTC_LOGON;
  345. Logon->NodeByteSize = sizeof(LOGON);
  346. InitializeListHead( &Logon->NdsCredentialList );
  347. ExInitializeResourceLite( &Logon->CredentialListResource );
  348. Status = SetUnicodeString(&Logon->UserName,
  349. InputBuffer->Parameters.Logon.UserNameLength,
  350. InputBuffer->Parameters.Logon.UserName);
  351. if (!NT_SUCCESS(Status)) {
  352. try_return( Status );
  353. }
  354. Status = SetUnicodeString(&Logon->PassWord,
  355. InputBuffer->Parameters.Logon.PasswordLength,
  356. (PWCHAR)
  357. ((PUCHAR)InputBuffer->Parameters.Logon.UserName +
  358. InputBuffer->Parameters.Logon.UserNameLength));
  359. if (!NT_SUCCESS(Status)) {
  360. try_return( Status );
  361. }
  362. ServerName.Buffer =
  363. (PWCHAR)
  364. ((PUCHAR)InputBuffer->Parameters.Logon.UserName +
  365. InputBuffer->Parameters.Logon.UserNameLength +
  366. InputBuffer->Parameters.Logon.PasswordLength);
  367. ServerName.Length =
  368. (USHORT)InputBuffer->Parameters.Logon.ServerNameLength;
  369. ServerName.MaximumLength =
  370. (USHORT)InputBuffer->Parameters.Logon.ServerNameLength;
  371. if ( ServerName.Length &&
  372. ServerName.Buffer[0] != L'*' ) {
  373. //
  374. // Only set this as the preferred server if it's not
  375. // a default tree. Default tree requests start with a '*'.
  376. //
  377. Status = SetUnicodeString(&Logon->ServerName,
  378. ServerName.Length,
  379. ServerName.Buffer );
  380. if (!NT_SUCCESS(Status)) {
  381. try_return( Status );
  382. }
  383. }
  384. //
  385. // Store the unique userid in both unicode and large integer form
  386. // the unicode form is used as a prefix to the servername in all
  387. // paths so that each userid gets their own connection to the server.
  388. //
  389. *((PLUID)(&Logon->UserUid)) = InputBuffer->Parameters.Logon.LogonId;
  390. Logon->NwPrintOptions = InputBuffer->Parameters.Logon.PrintOption;
  391. // Save Uid for CreateScb
  392. *((PLUID)(&IrpContext->Specific.Create.UserUid)) =
  393. InputBuffer->Parameters.Logon.LogonId;
  394. try_exit:NOTHING;
  395. } except (EXCEPTION_EXECUTE_HANDLER) {
  396. Status = GetExceptionCode();
  397. }
  398. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  399. if (NT_SUCCESS(Status)) {
  400. DebugTrace( 0, Dbg, " ->UserName = %wZ\n", &Logon->UserName );
  401. DebugTrace( 0, Dbg, " ->PassWord = %wZ\n", &Logon->PassWord );
  402. if ( ServerName.Length && ServerName.Buffer[0] == L'*' ) {
  403. DebugTrace( 0, Dbg, " ->DefaultTree = %wZ\n", &ServerName );
  404. } else {
  405. DebugTrace( 0, Dbg, " ->ServerName = %wZ\n", &Logon->ServerName );
  406. }
  407. DebugTrace( 0, Dbg, " ->UserUidHigh = %08lx\n", Logon->UserUid.HighPart);
  408. DebugTrace( 0, Dbg, " ->UserUidLow = %08lx\n", Logon->UserUid.LowPart);
  409. InsertHeadList( &LogonList, &Logon->Next );
  410. NwReleaseRcb( &NwRcb );
  411. if ( ServerName.Length &&
  412. ServerName.Buffer[0] != L'*' ) {
  413. PSCB Scb;
  414. // See if we can login as this user.
  415. Status = CreateScb(
  416. &Scb,
  417. IrpContext,
  418. &ServerName,
  419. NULL,
  420. NULL,
  421. NULL,
  422. FALSE,
  423. FALSE );
  424. if (NT_SUCCESS(Status)) {
  425. //
  426. // CreateScb has already boosted the reference count
  427. // because this is a preferred server so it will not go
  428. // away. We need to dereference it here because there is
  429. // no handle associated with the CreateScb
  430. //
  431. NwDereferenceScb(Scb->pNpScb);
  432. }
  433. }
  434. if ( ServerName.Length &&
  435. ServerName.Buffer[0] == L'*' ) {
  436. PSCB Scb;
  437. BOOL SetContext;
  438. UINT ContextLength;
  439. UNICODE_STRING DefaultContext;
  440. IPXaddress *ReplicaAddr;
  441. //
  442. // Ok, this is a little confusing. On Login, the provider can
  443. // specify the address of the replica that we should use to log
  444. // in. If this is the case, then we do pre-connect that replica.
  445. // Otherwise, we do the standard login to any replica. The
  446. // reason for this is that standard replica location uses the
  447. // bindery and doesn't always get us the nearest dir server.
  448. //
  449. if ( InputBuffer->Parameters.Logon.ReplicaAddrLength ==
  450. sizeof( TDI_ADDRESS_IPX ) ) {
  451. ReplicaAddr = (IPXaddress*)
  452. ((PUCHAR) InputBuffer->Parameters.Logon.UserName +
  453. InputBuffer->Parameters.Logon.UserNameLength +
  454. InputBuffer->Parameters.Logon.PasswordLength +
  455. InputBuffer->Parameters.Logon.ServerNameLength);
  456. ReplicaAddr->Socket = NCP_SOCKET;
  457. Status =
  458. CreateScb( &Scb,
  459. IrpContext,
  460. NULL, // anonymous create
  461. ReplicaAddr, // nearest replica add
  462. NULL, // no user name
  463. NULL, // no password
  464. TRUE, // defer the login
  465. FALSE ); // we are not deleting the connection
  466. if (NT_SUCCESS(Status)) {
  467. //
  468. // CreateScb has already boosted the reference count
  469. // because this is a preferred server so it will not go
  470. // away. We need to dereference it here because there is
  471. // no handle associated with the CreateScb
  472. //
  473. NwDereferenceScb(Scb->pNpScb);
  474. }
  475. }
  476. //
  477. // Set if this includes a default context.
  478. //
  479. ServerName.Buffer += 1;
  480. ServerName.Length -= sizeof( WCHAR );
  481. ServerName.MaximumLength -= sizeof( WCHAR );
  482. SetContext = FALSE;
  483. ContextLength = 0;
  484. while ( ContextLength < ServerName.Length / sizeof( WCHAR ) ) {
  485. if ( ServerName.Buffer[ContextLength] == L'\\' ) {
  486. SetContext = TRUE;
  487. ContextLength++;
  488. //
  489. // Skip any leading periods.
  490. //
  491. if ( ServerName.Buffer[ContextLength] == L'.' ) {
  492. DefaultContext.Buffer = &ServerName.Buffer[ContextLength + 1];
  493. ServerName.Length -= sizeof ( WCHAR ) ;
  494. ServerName.MaximumLength -= sizeof ( WCHAR );
  495. } else {
  496. DefaultContext.Buffer = &ServerName.Buffer[ContextLength];
  497. }
  498. ContextLength *= sizeof( WCHAR );
  499. DefaultContext.Length = ServerName.Length - ContextLength;
  500. DefaultContext.MaximumLength = ServerName.MaximumLength - ContextLength;
  501. ServerName.Length -= ( DefaultContext.Length + sizeof( WCHAR ) );
  502. ServerName.MaximumLength -= ( DefaultContext.Length + sizeof( WCHAR ) );
  503. }
  504. ContextLength++;
  505. }
  506. //
  507. // Verify that this context is valid before we acquire
  508. // the credentials and really set the context.
  509. //
  510. if ( SetContext ) {
  511. Status = NdsVerifyContext( IrpContext, &ServerName, &DefaultContext );
  512. if ( !NT_SUCCESS( Status )) {
  513. SetContext = FALSE;
  514. }
  515. }
  516. //
  517. // Generate the credential shell for the default tree and
  518. // set the context if appropriate.
  519. //
  520. Status = NdsLookupCredentials( IrpContext,
  521. &ServerName,
  522. Logon,
  523. &pNdsContext,
  524. CREDENTIAL_WRITE,
  525. TRUE );
  526. if ( NT_SUCCESS( Status ) ) {
  527. //
  528. // Set the context. It doesn't matter if the
  529. // credential is locked or not.
  530. //
  531. if ( SetContext ) {
  532. RtlCopyUnicodeString( &pNdsContext->CurrentContext,
  533. &DefaultContext );
  534. DebugTrace( 0, Dbg, "Default Context: %wZ\n", &DefaultContext );
  535. }
  536. NwReleaseCredList( Logon, IrpContext );
  537. //
  538. // RELAX! The credential list is free.
  539. //
  540. DebugTrace( 0, Dbg, "Default Tree: %wZ\n", &ServerName );
  541. Status = NdsCreateTreeScb( IrpContext,
  542. &Scb,
  543. &ServerName,
  544. NULL,
  545. NULL,
  546. FALSE,
  547. FALSE );
  548. if (NT_SUCCESS(Status)) {
  549. NwDereferenceScb(Scb->pNpScb);
  550. }
  551. }
  552. }
  553. //
  554. // No login requested.
  555. //
  556. } else {
  557. FreeLogon( Logon );
  558. NwReleaseRcb( &NwRcb );
  559. }
  560. DebugTrace(-1, Dbg, "Logon %lx\n", Status);
  561. return Status;
  562. }
  563. NTSTATUS
  564. Logoff(
  565. IN PIRP_CONTEXT IrpContext
  566. )
  567. /*++
  568. Routine Description:
  569. This routine sets the username back to guest and removes the password.
  570. Arguments:
  571. IN PIRP_CONTEXT IrpContext - Io Request Packet for request
  572. Return Value:
  573. NTSTATUS
  574. --*/
  575. {
  576. BOOLEAN Locked = FALSE;
  577. NTSTATUS Status = STATUS_SUCCESS;
  578. PIRP Irp = IrpContext->pOriginalIrp;
  579. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  580. PNWR_REQUEST_PACKET InputBuffer = Irp->AssociatedIrp.SystemBuffer;
  581. ULONG InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  582. LARGE_INTEGER User;
  583. PLOGON Logon;
  584. PAGED_CODE();
  585. DebugTrace(+1, Dbg, "Logoff...\n", 0);
  586. try {
  587. //
  588. // Check some fields in the input buffer.
  589. //
  590. if (InputBufferLength < sizeof(NWR_REQUEST_PACKET)) {
  591. try_return(Status = STATUS_BUFFER_TOO_SMALL);
  592. }
  593. if (InputBuffer->Version != REQUEST_PACKET_VERSION) {
  594. try_return(Status = STATUS_INVALID_PARAMETER);
  595. }
  596. *((PLUID)(&User)) = InputBuffer->Parameters.Logoff.LogonId;
  597. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  598. Locked = TRUE;
  599. Logon = FindUser(&User, TRUE);
  600. if ( Logon != NULL ) {
  601. LARGE_INTEGER Uid = Logon->UserUid;
  602. //
  603. // We have found the right user.
  604. //
  605. ASSERT( Logon != &Guest);
  606. NwReleaseRcb( &NwRcb );
  607. Locked = FALSE;
  608. DebugTrace( 0, Dbg, " ->UserName = %wZ\n", &Logon->UserName );
  609. DebugTrace( 0, Dbg, " ->ServerName = %wZ\n", &Logon->ServerName );
  610. DebugTrace( 0, Dbg, " ->UserUidHigh = %08lx\n", Logon->UserUid.HighPart);
  611. DebugTrace( 0, Dbg, " ->UserUidLow = %08lx\n", Logon->UserUid.LowPart);
  612. //
  613. // Invalidating all the handles for this user will also cause logoffs
  614. // to all the servers in question.
  615. //
  616. NwInvalidateAllHandles(&Uid, IrpContext);
  617. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  618. Locked = TRUE;
  619. Logon = FindUser(&User, TRUE);
  620. if (Logon != NULL) {
  621. RemoveEntryList( &Logon->Next );
  622. FreeLogon( Logon );
  623. } else {
  624. ASSERT( FALSE && "Double logoff!");
  625. }
  626. Status = STATUS_SUCCESS;
  627. } else {
  628. Status = STATUS_UNSUCCESSFUL;
  629. }
  630. try_exit:NOTHING;
  631. } finally {
  632. if (Locked == TRUE ) {
  633. NwReleaseRcb( &NwRcb );
  634. }
  635. }
  636. DebugTrace(-1, Dbg, "Logoff %lx\n", Status);
  637. return Status;
  638. }
  639. NTSTATUS
  640. UpdateUsersPassword(
  641. IN PUNICODE_STRING UserName,
  642. IN PUNICODE_STRING Password,
  643. OUT PLARGE_INTEGER Uid
  644. )
  645. /*++
  646. Routine Description:
  647. This routine updates the cached password for a given user.
  648. If the named user is not logged in, an error is returned.
  649. Arguments:
  650. UserName - Supplies the name of the user
  651. Password - Supplies the new password
  652. Uid - Returns the LUID of the updated user.
  653. Return Value:
  654. NTSTATUS
  655. --*/
  656. {
  657. PLOGON Logon;
  658. NTSTATUS Status;
  659. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  660. Logon = FindUserByName( UserName );
  661. if ( Logon != NULL ) {
  662. if ( Logon->PassWord.Buffer != NULL ) {
  663. FREE_POOL( Logon->PassWord.Buffer );
  664. }
  665. Status = SetUnicodeString(
  666. &Logon->PassWord,
  667. Password->Length,
  668. Password->Buffer );
  669. *Uid = Logon->UserUid;
  670. } else {
  671. Status = STATUS_UNSUCCESSFUL;
  672. }
  673. NwReleaseRcb( &NwRcb );
  674. return( Status );
  675. }
  676. NTSTATUS
  677. UpdateServerPassword(
  678. PIRP_CONTEXT IrpContext,
  679. IN PUNICODE_STRING ServerName,
  680. IN PUNICODE_STRING UserName,
  681. IN PUNICODE_STRING Password,
  682. IN PLARGE_INTEGER Uid
  683. )
  684. /*++
  685. Routine Description:
  686. This routine updates the cached password for a named server connection.
  687. If the server does not exist in the server table, an error is returned.
  688. Arguments:
  689. ServerName - Supplies the name of the server
  690. UserName - Supplies the name of the user
  691. Password - Supplies the new password
  692. Uid - The LUID of the user.
  693. Return Value:
  694. NTSTATUS
  695. --*/
  696. {
  697. UNICODE_STRING UidServer;
  698. NTSTATUS Status;
  699. PUNICODE_PREFIX_TABLE_ENTRY PrefixEntry;
  700. PSCB pScb;
  701. PNONPAGED_SCB pNpScb;
  702. PVOID Buffer;
  703. Status = MakeUidServer(
  704. &UidServer,
  705. Uid,
  706. ServerName );
  707. if ( !NT_SUCCESS( Status )) {
  708. return( Status );
  709. }
  710. DebugTrace( 0, Dbg, " ->UidServer = %wZ\n", &UidServer );
  711. NwAcquireExclusiveRcb( &NwRcb, TRUE );
  712. PrefixEntry = RtlFindUnicodePrefix( &NwRcb.ServerNameTable, &UidServer, 0 );
  713. if ( PrefixEntry != NULL ) {
  714. pScb = CONTAINING_RECORD( PrefixEntry, SCB, PrefixEntry );
  715. pNpScb = pScb->pNpScb;
  716. NwReferenceScb( pNpScb );
  717. //
  718. // Release the RCB.
  719. //
  720. NwReleaseRcb( &NwRcb );
  721. } else {
  722. NwReleaseRcb( &NwRcb );
  723. FREE_POOL(UidServer.Buffer);
  724. return( STATUS_BAD_NETWORK_PATH );
  725. }
  726. IrpContext->pNpScb = pNpScb;
  727. NwAppendToQueueAndWait( IrpContext );
  728. //
  729. // Free the old username password, allocate a new one.
  730. //
  731. if ( pScb->UserName.Buffer != NULL ) {
  732. FREE_POOL( pScb->UserName.Buffer );
  733. }
  734. Buffer = ALLOCATE_POOL_EX( NonPagedPool, UserName->Length + Password->Length );
  735. pScb->UserName.Buffer = Buffer;
  736. pScb->UserName.Length = pScb->UserName.MaximumLength = UserName->Length;
  737. RtlMoveMemory( pScb->UserName.Buffer, UserName->Buffer, UserName->Length );
  738. pScb->Password.Buffer = (PWCHAR)((PCHAR)Buffer + UserName->Length);
  739. pScb->Password.Length = pScb->Password.MaximumLength = Password->Length;
  740. RtlMoveMemory( pScb->Password.Buffer, Password->Buffer, Password->Length );
  741. FREE_POOL(UidServer.Buffer);
  742. return( STATUS_SUCCESS );
  743. }