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.

852 lines
23 KiB

  1. /*++
  2. Copyright (c) 1993-1993 Microsoft Corporation
  3. Module Name:
  4. usrprop.c
  5. Abstract:
  6. This module implements QueryUserProperty() and SetUserProperty()
  7. which read and write NetWare Properties to the UserParms field.
  8. Author:
  9. Andy Herron (andyhe) 24-May-1993
  10. Congpa You (CongpaY) 28-Oct-1993 Seperated SetUserProperty() and
  11. QueryUserProperty() out from usrprop.c
  12. in ncpsrv\svcdlls\ncpsvc\libbind,
  13. modified the code and fixed a few
  14. existing problems.
  15. Revision History:
  16. --*/
  17. #include "nt.h"
  18. #include "ntrtl.h"
  19. #include "nturtl.h"
  20. #include "ntioapi.h"
  21. #include "windef.h"
  22. #include "winbase.h"
  23. #include "stdio.h"
  24. #include "stdlib.h"
  25. #include "winuser.h"
  26. #include <fpnwcomm.h>
  27. #include <usrprop.h>
  28. //
  29. // All internal (opaque) structures are listed here since no one else
  30. // needs to reference them.
  31. //
  32. //
  33. // The user's Parameter field is mapped out to a structure that contains
  34. // the backlevel 48 WCHARs for Mac/Ras compatibility plus a new structure
  35. // that is basically an array of chars that make up a property name plus
  36. // a property value.
  37. //
  38. //
  39. // This is the structure for an individual property. Note that there are
  40. // no null terminators in this.
  41. //
  42. typedef struct _USER_PROPERTY {
  43. WCHAR PropertyLength; // length of property name
  44. WCHAR ValueLength; // length of property value
  45. WCHAR PropertyFlag; // type of property (1 = set, 2 = item)
  46. WCHAR Property[1]; // start of property name, followed by value
  47. } USER_PROPERTY, *PUSER_PROPERTY;
  48. //
  49. // This is the structure that maps the beginning of the user's Parameters
  50. // field. It is only separate so that we can do a sizeof() without including
  51. // the first property, which may or may not be there.
  52. //
  53. typedef struct _USER_PROPERTIES_HDR {
  54. WCHAR BacklevelParms[48]; // RAS & Mac data stored here.
  55. WCHAR PropertySignature; // signature that we can look for.
  56. WCHAR PropertyCount; // number of properties present.
  57. } USER_PROPERTIES_HDR, *PUSER_PROPERTIES_HDR;
  58. //
  59. // This structure maps out the whole of the user's Parameters field when
  60. // the user properties structure is present and at least one property is
  61. // defined.
  62. //
  63. typedef struct _USER_PROPERTIES {
  64. USER_PROPERTIES_HDR Header;
  65. USER_PROPERTY FirstProperty;
  66. } USER_PROPERTIES, *PUSER_PROPERTIES;
  67. //
  68. // forward references
  69. //
  70. NTSTATUS
  71. UserPropertyAllocBlock (
  72. IN PUNICODE_STRING Existing,
  73. IN ULONG DesiredLength,
  74. IN OUT PUNICODE_STRING New
  75. );
  76. BOOL
  77. FindUserProperty (
  78. PUSER_PROPERTIES UserProperties,
  79. LPWSTR Property,
  80. PUSER_PROPERTY *pUserProperty,
  81. USHORT *pCount
  82. );
  83. VOID
  84. RemoveUserProperty (
  85. UNICODE_STRING *puniUserParms,
  86. PUSER_PROPERTY UserProperty,
  87. USHORT Count,
  88. BOOL *Update
  89. );
  90. VOID
  91. NetpParmsUserPropertyFree (
  92. LPWSTR NewUserParms
  93. )
  94. {
  95. LocalFree( NewUserParms );
  96. return;
  97. }
  98. NTSTATUS
  99. NetpParmsSetUserProperty (
  100. IN LPWSTR UserParms,
  101. IN LPWSTR Property,
  102. IN UNICODE_STRING PropertyValue,
  103. IN WCHAR PropertyFlag,
  104. OUT LPWSTR *pNewUserParms, // memory has to be freed afer use.
  105. OUT BOOL *Update
  106. )
  107. /*
  108. This function sets a property field in the user's Parameters field.
  109. */
  110. {
  111. NTSTATUS status;
  112. UNICODE_STRING uniUserParms;
  113. UNICODE_STRING uniNewUserParms;
  114. USHORT Count = 0;
  115. USHORT PropertyLength;
  116. USHORT ValueLength;
  117. PUSER_PROPERTIES UserProperties;
  118. PUSER_PROPERTY UserProperty;
  119. LPWSTR PropertyValueString = NULL;
  120. USHORT oldUserParmsLength;
  121. INT i;
  122. UCHAR *pchValue = NULL;
  123. // Check if parameters are correct.
  124. if (Property == NULL)
  125. {
  126. return( STATUS_INVALID_PARAMETER );
  127. }
  128. // Initialize output variables.
  129. *Update = FALSE;
  130. *pNewUserParms = NULL;
  131. try {
  132. oldUserParmsLength = (USHORT)((lstrlenW(UserParms) + 1) * sizeof(WCHAR));
  133. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  134. //
  135. // if we can't get the length of the current UserParameters, we loose
  136. // the whole thing.
  137. //
  138. UserParms = NULL;
  139. }
  140. // Convert UserParms to unicode string.
  141. uniUserParms.Buffer = UserParms;
  142. uniUserParms.Length = UserParms ? oldUserParmsLength : 0;
  143. uniUserParms.MaximumLength = uniUserParms.Length;
  144. /** Get the length of the property name **/
  145. PropertyLength = (USHORT)(lstrlenW( Property ) * sizeof(WCHAR));
  146. /** Get the length of the property value **/
  147. ValueLength = PropertyValue.Length;
  148. if (ValueLength != 0)
  149. {
  150. PCHAR hexValues = "0123456789abcdef";
  151. // Convert property value to asci string so that
  152. // if property value is 0, it can be stored correctly.
  153. PropertyValueString = (LPWSTR) LocalAlloc (LPTR, (ValueLength+1)*sizeof (WCHAR));
  154. if (!PropertyValueString)
  155. {
  156. return(STATUS_NO_MEMORY) ;
  157. }
  158. pchValue = (UCHAR *) PropertyValue.Buffer;
  159. // Since we don't want to pull in user32.dll, we'll roll our own
  160. // byte to hex code.
  161. for (i = 0; i < ValueLength; i++)
  162. {
  163. *((PCHAR)(PropertyValueString+i)) = hexValues[((*(pchValue+i)) & 0xF0) >> 4];
  164. *((PCHAR)((PCHAR)(PropertyValueString+i)+1)) = hexValues[((*(pchValue+i)) & 0x0F)];
  165. }
  166. *(PropertyValueString+ValueLength) = 0;
  167. ValueLength = ValueLength * sizeof (WCHAR);
  168. }
  169. //
  170. // check that user has valid property structure , if not, create one
  171. //
  172. if (UserParms != NULL)
  173. {
  174. Count = oldUserParmsLength;
  175. }
  176. if (Count < sizeof( USER_PROPERTIES))
  177. {
  178. Count = sizeof( USER_PROPERTIES_HDR ) + sizeof(WCHAR);
  179. }
  180. if (ValueLength > 0)
  181. {
  182. Count += sizeof( USER_PROPERTY ) + PropertyLength + ValueLength;
  183. }
  184. if (Count > 0x7FFF)
  185. {
  186. // can't be bigger than 32K of user parms.
  187. if (PropertyValueString) {
  188. LocalFree( PropertyValueString );
  189. }
  190. return (STATUS_BUFFER_OVERFLOW);
  191. }
  192. try {
  193. status = UserPropertyAllocBlock( &uniUserParms,
  194. Count,
  195. &uniNewUserParms );
  196. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  197. //
  198. // if we can't copy the current UserParameters, we loose the whole thing.
  199. //
  200. UserParms = NULL;
  201. uniUserParms.Buffer = UserParms;
  202. uniUserParms.Length = 0;
  203. uniUserParms.MaximumLength = uniUserParms.Length;
  204. Count = sizeof( USER_PROPERTIES_HDR ) + sizeof(WCHAR);
  205. if (ValueLength > 0) {
  206. Count += sizeof( USER_PROPERTY ) + PropertyLength + ValueLength;
  207. }
  208. status = UserPropertyAllocBlock( &uniUserParms,
  209. Count,
  210. &uniNewUserParms );
  211. }
  212. if ( !NT_SUCCESS(status) ) {
  213. if (PropertyValueString) {
  214. LocalFree( PropertyValueString );
  215. }
  216. return status;
  217. }
  218. // Make the output pNewUserParms point to uniNewUserPams's buffer
  219. // which is the new UserParms string.
  220. *pNewUserParms = uniNewUserParms.Buffer;
  221. UserProperties = (PUSER_PROPERTIES) uniNewUserParms.Buffer;
  222. try {
  223. if (FindUserProperty (UserProperties,
  224. Property,
  225. &UserProperty,
  226. &Count))
  227. {
  228. RemoveUserProperty ( &uniNewUserParms,
  229. UserProperty,
  230. Count,
  231. Update);
  232. }
  233. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  234. //
  235. // we have corrupted user parms here... get rid of them.
  236. //
  237. *Update = TRUE;
  238. if (*pNewUserParms != NULL) {
  239. LocalFree( *pNewUserParms );
  240. }
  241. *pNewUserParms = NULL;
  242. status = STATUS_INVALID_PARAMETER;
  243. }
  244. if ( !NT_SUCCESS(status) ) {
  245. if (PropertyValueString) {
  246. LocalFree( PropertyValueString );
  247. }
  248. return status;
  249. }
  250. //
  251. // If the new value of the property is not null, add it.
  252. //
  253. if (ValueLength > 0) {
  254. try {
  255. // find the end of the parameters list
  256. UserProperty = &(UserProperties->FirstProperty);
  257. for (Count = 1; Count <= UserProperties->Header.PropertyCount; Count++)
  258. {
  259. UserProperty = (PUSER_PROPERTY)
  260. ((LPSTR)((LPSTR) UserProperty +
  261. sizeof(USER_PROPERTY) + // length of entry
  262. UserProperty->PropertyLength +
  263. UserProperty->ValueLength -
  264. sizeof(WCHAR))); // for Property[0]
  265. }
  266. //
  267. // append it to the end and update length of string
  268. //
  269. UserProperty->PropertyFlag = (PropertyFlag & NCP_SET) ?
  270. USER_PROPERTY_TYPE_SET :
  271. USER_PROPERTY_TYPE_ITEM;
  272. UserProperty->PropertyLength = PropertyLength;
  273. UserProperty->ValueLength = ValueLength;
  274. RtlCopyMemory( &(UserProperty->Property[0]),
  275. Property,
  276. PropertyLength );
  277. RtlCopyMemory( &(UserProperty->Property[PropertyLength / sizeof(WCHAR)]),
  278. PropertyValueString,
  279. ValueLength );
  280. uniNewUserParms.Length +=
  281. sizeof(USER_PROPERTY) + // length of entry
  282. PropertyLength + // length of property name string
  283. ValueLength - // length of value string
  284. sizeof(WCHAR); // account for WCHAR Property[1]
  285. UserProperties->Header.PropertyCount++;
  286. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  287. //
  288. // we have corrupted user parms here... get rid of them.
  289. //
  290. if (*pNewUserParms != NULL) {
  291. LocalFree( *pNewUserParms );
  292. }
  293. *pNewUserParms = NULL;
  294. status = STATUS_INVALID_PARAMETER;
  295. }
  296. *Update = TRUE;
  297. }
  298. // UserParms is already null terminated. We don't need to set the
  299. // end of UserParms to be NULL since we zero init the buffer already.
  300. if (PropertyValueString) {
  301. LocalFree( PropertyValueString );
  302. }
  303. return( status );
  304. }
  305. NTSTATUS
  306. NetpParmsSetUserPropertyWithLength (
  307. IN PUNICODE_STRING UserParms,
  308. IN LPWSTR Property,
  309. IN UNICODE_STRING PropertyValue,
  310. IN WCHAR PropertyFlag,
  311. OUT LPWSTR *pNewUserParms, // memory has to be freed afer use.
  312. OUT BOOL *Update
  313. )
  314. /*
  315. This function sets a property field in the user's Parameters field.
  316. */
  317. {
  318. NTSTATUS status;
  319. UNICODE_STRING newUserParms;
  320. ULONG length;
  321. PWCHAR ptr;
  322. length = UserParms->Length;
  323. if (UserParms->MaximumLength < length + sizeof(WCHAR)) {
  324. //
  325. // have to realloc
  326. //
  327. newUserParms.Buffer = UserParms->Buffer;
  328. newUserParms.Length =
  329. newUserParms.MaximumLength =
  330. (USHORT) ( length + sizeof(WCHAR) );
  331. newUserParms.Buffer = LocalAlloc (LPTR, newUserParms.Length);
  332. if (newUserParms.Buffer == NULL) {
  333. return STATUS_INSUFFICIENT_RESOURCES;
  334. }
  335. RtlCopyMemory( newUserParms.Buffer,
  336. UserParms->Buffer,
  337. length );
  338. } else {
  339. newUserParms.Buffer = UserParms->Buffer;
  340. newUserParms.Length = (USHORT) length;
  341. newUserParms.MaximumLength = UserParms->MaximumLength;
  342. }
  343. //
  344. // Slap in null terminator
  345. //
  346. ptr = newUserParms.Buffer + ( length / sizeof(WCHAR) );
  347. *ptr = L'\0';
  348. status = NetpParmsSetUserProperty( newUserParms.Buffer,
  349. Property,
  350. PropertyValue,
  351. PropertyFlag,
  352. pNewUserParms,
  353. Update );
  354. if (newUserParms.Buffer != UserParms->Buffer) {
  355. LocalFree( newUserParms.Buffer );
  356. }
  357. return(status);
  358. }
  359. #define MAPHEXTODIGIT(x) ( x >= '0' && x <= '9' ? (x-'0') : \
  360. x >= 'A' && x <= 'F' ? (x-'A'+10) : \
  361. x >= 'a' && x <= 'f' ? (x-'a'+10) : 0 )
  362. NTSTATUS
  363. NetpParmsQueryUserProperty (
  364. IN LPWSTR UserParms,
  365. IN LPWSTR PropertyName,
  366. OUT PWCHAR PropertyFlag,
  367. OUT PUNICODE_STRING PropertyValue
  368. )
  369. /*
  370. This routine returns a user definable property value as it is stored
  371. in the user's Parameters field. Note that the RAS/MAC fields are
  372. stripped before we start processing user properties.
  373. */
  374. {
  375. NTSTATUS status = STATUS_SUCCESS;
  376. USHORT PropertyNameLength;
  377. USHORT Count;
  378. PUSER_PROPERTY UserProperty;
  379. WCHAR *Value;
  380. UINT i;
  381. CHAR *PropertyValueString = NULL;
  382. CHAR *pchValue;
  383. // Set PropertyValue->Length to 0 initially. If the property is not found
  384. // it will still be 0 on exit.
  385. PropertyValue->Length = 0;
  386. PropertyValue->Buffer = NULL;
  387. try {
  388. PropertyNameLength = (USHORT)(lstrlenW(PropertyName) * sizeof(WCHAR));
  389. // Check if UserParms have the right structure.
  390. if (FindUserProperty ((PUSER_PROPERTIES) UserParms,
  391. PropertyName,
  392. &UserProperty,
  393. &Count) ) {
  394. Value = (LPWSTR)(LPSTR)((LPSTR) &(UserProperty->Property[0]) +
  395. PropertyNameLength);
  396. //
  397. // Found the requested property
  398. //
  399. //
  400. // Copy the property flag.
  401. //
  402. if (PropertyFlag) {
  403. *PropertyFlag = UserProperty->PropertyFlag;
  404. }
  405. // Allocate memory for PropertyValue->Buffer
  406. PropertyValueString = LocalAlloc ( LPTR, UserProperty->ValueLength+1);
  407. PropertyValue->Buffer = LocalAlloc ( LPTR, UserProperty->ValueLength/sizeof(WCHAR));
  408. //
  409. // Make sure the property value length is valid.
  410. //
  411. if ((PropertyValue->Buffer == NULL) || (PropertyValueString == NULL)) {
  412. status = STATUS_INSUFFICIENT_RESOURCES;
  413. if (PropertyValue->Buffer != NULL) {
  414. LocalFree( PropertyValue->Buffer );
  415. PropertyValue->Buffer = NULL;
  416. }
  417. } else {
  418. //
  419. // Copy the property value to the buffer.
  420. //
  421. RtlCopyMemory( PropertyValueString,
  422. Value,
  423. UserProperty->ValueLength );
  424. pchValue = (CHAR *) PropertyValue->Buffer;
  425. // Convert from value unicode string to value.
  426. for (i = 0; i < UserProperty->ValueLength/sizeof(WCHAR) ; i++)
  427. {
  428. // sscanf will trash memory.
  429. // sscanf( PropertyValueString+2*i, "%2x", pchValue+i);
  430. pchValue[i] = MAPHEXTODIGIT( PropertyValueString[2*i]) * 16 +
  431. MAPHEXTODIGIT( PropertyValueString[2*i+1]);
  432. }
  433. PropertyValue->Length = UserProperty->ValueLength/sizeof(WCHAR);
  434. PropertyValue->MaximumLength = UserProperty->ValueLength/sizeof(WCHAR);
  435. }
  436. }
  437. } except ( EXCEPTION_EXECUTE_HANDLER ) {
  438. //
  439. // we have corrupted user parms here... can't return a decent value
  440. //
  441. if (PropertyValue->Buffer != NULL) {
  442. LocalFree( PropertyValue->Buffer );
  443. PropertyValue->Buffer = NULL;
  444. }
  445. PropertyValue->Length = 0;
  446. status = STATUS_INVALID_PARAMETER;
  447. }
  448. if ( PropertyValueString != NULL ) {
  449. LocalFree( PropertyValueString);
  450. }
  451. return status;
  452. }
  453. NTSTATUS
  454. NetpParmsQueryUserPropertyWithLength (
  455. IN PUNICODE_STRING UserParms,
  456. IN LPWSTR PropertyName,
  457. OUT PWCHAR PropertyFlag,
  458. OUT PUNICODE_STRING PropertyValue
  459. )
  460. /*
  461. This routine returns a user definable property value as it is stored
  462. in the user's Parameters field. Note that the RAS/MAC fields are
  463. stripped before we start processing user properties.
  464. */
  465. {
  466. NTSTATUS status;
  467. UNICODE_STRING newUserParms;
  468. ULONG length;
  469. PWCHAR ptr;
  470. length = UserParms->Length;
  471. if (UserParms->MaximumLength < length + sizeof(WCHAR)) {
  472. //
  473. // have to realloc
  474. //
  475. newUserParms.Buffer = UserParms->Buffer;
  476. newUserParms.Length =
  477. newUserParms.MaximumLength =
  478. (USHORT) (length + sizeof(WCHAR) );
  479. newUserParms.Buffer = LocalAlloc (LPTR, newUserParms.Length);
  480. if (newUserParms.Buffer == NULL) {
  481. return STATUS_INSUFFICIENT_RESOURCES;
  482. }
  483. RtlCopyMemory( newUserParms.Buffer,
  484. UserParms->Buffer,
  485. length );
  486. } else {
  487. newUserParms.Buffer = UserParms->Buffer;
  488. newUserParms.Length = (USHORT) length;
  489. newUserParms.MaximumLength = UserParms->MaximumLength;
  490. }
  491. //
  492. // Slap in null terminator
  493. //
  494. ptr = newUserParms.Buffer + ( length / sizeof(WCHAR) );
  495. *ptr = L'\0';
  496. status = NetpParmsQueryUserProperty( newUserParms.Buffer,
  497. PropertyName,
  498. PropertyFlag,
  499. PropertyValue );
  500. if (newUserParms.Buffer != UserParms->Buffer) {
  501. LocalFree( newUserParms.Buffer );
  502. }
  503. return(status);
  504. }
  505. // Common routine used by QueryUserProperty() and SetUserProperty().
  506. BOOL
  507. FindUserProperty (
  508. PUSER_PROPERTIES UserProperties,
  509. LPWSTR Property,
  510. PUSER_PROPERTY *pUserProperty,
  511. USHORT *pCount
  512. )
  513. {
  514. BOOL fFound = FALSE;
  515. USHORT PropertyLength;
  516. //
  517. // Check if user has valid property structure attached,
  518. // pointed to by UserProperties.
  519. //
  520. if ( ( UserProperties != NULL )
  521. && ( lstrlenW( (LPWSTR) UserProperties) * sizeof(WCHAR) >
  522. sizeof(UserProperties->Header.BacklevelParms))
  523. && ( UserProperties->Header.PropertySignature == USER_PROPERTY_SIGNATURE)
  524. )
  525. {
  526. //
  527. // user has valid property structure.
  528. //
  529. *pUserProperty = &(UserProperties->FirstProperty);
  530. PropertyLength = (USHORT)(lstrlenW( Property ) * sizeof(WCHAR));
  531. for ( *pCount = 1; *pCount <= UserProperties->Header.PropertyCount;
  532. (*pCount)++ )
  533. {
  534. if ( ( PropertyLength == (*pUserProperty)->PropertyLength )
  535. && ( RtlCompareMemory( &((*pUserProperty)->Property[0]),
  536. Property,
  537. PropertyLength ) == PropertyLength )
  538. )
  539. {
  540. fFound = TRUE;
  541. break;
  542. }
  543. *pUserProperty = (PUSER_PROPERTY)
  544. ((LPSTR) (*pUserProperty)
  545. + sizeof( USER_PROPERTY )
  546. + (*pUserProperty)->PropertyLength
  547. + (*pUserProperty)->ValueLength
  548. - sizeof(WCHAR)); // for Property[0]
  549. }
  550. }
  551. return( fFound );
  552. }
  553. // Remove a property field from the User Parms.
  554. VOID
  555. RemoveUserProperty (
  556. UNICODE_STRING *puniUserParms,
  557. PUSER_PROPERTY UserProperty,
  558. USHORT Count,
  559. BOOL *Update
  560. )
  561. {
  562. PUSER_PROPERTIES UserProperties;
  563. PUSER_PROPERTY NextProperty;
  564. USHORT OldParmLength;
  565. UserProperties = (PUSER_PROPERTIES) puniUserParms->Buffer;
  566. OldParmLength = sizeof( USER_PROPERTY ) +
  567. UserProperty->PropertyLength +
  568. UserProperty->ValueLength -
  569. sizeof(WCHAR); // for Property[0]
  570. NextProperty = (PUSER_PROPERTY)(LPSTR)((LPSTR) UserProperty + OldParmLength);
  571. //
  572. // if we're not on the last one, copy the remaining buffer up
  573. //
  574. if (Count < UserProperties->Header.PropertyCount) {
  575. RtlMoveMemory( UserProperty,
  576. NextProperty,
  577. puniUserParms->Length -
  578. ((LPSTR) NextProperty -
  579. (LPSTR) puniUserParms->Buffer ));
  580. }
  581. //
  582. // Now reduce the length of the buffer by the amount we pulled out
  583. //
  584. puniUserParms->Length -= OldParmLength;
  585. UserProperties->Header.PropertyCount--;
  586. *Update = TRUE;
  587. }
  588. NTSTATUS
  589. UserPropertyAllocBlock (
  590. IN PUNICODE_STRING Existing,
  591. IN ULONG DesiredLength,
  592. IN OUT PUNICODE_STRING New
  593. )
  594. /*
  595. This allocates a larger block for user's parameters and copies the old
  596. block in.
  597. */
  598. {
  599. PUSER_PROPERTIES UserProperties;
  600. CLONG Count;
  601. WCHAR *pNewBuff;
  602. //
  603. // We will allocate a new buffer to store the new parameters
  604. // and copy the existing parameters into it.
  605. //
  606. New->Buffer = LocalAlloc (LPTR, DesiredLength);
  607. if ( New->Buffer == NULL)
  608. {
  609. return STATUS_INSUFFICIENT_RESOURCES;
  610. }
  611. New->MaximumLength = (USHORT) DesiredLength;
  612. if (Existing != NULL)
  613. {
  614. New->Length = Existing->Length;
  615. RtlCopyMemory( New->Buffer,
  616. Existing->Buffer,
  617. Existing->Length );
  618. }
  619. else
  620. {
  621. New->Length = 0;
  622. }
  623. //
  624. // Ensure that we don't have any nulls in our string.
  625. //
  626. for ( Count = 0;
  627. Count < New->Length / sizeof(WCHAR);
  628. Count++ )
  629. {
  630. if (*(New->Buffer + Count) == L'\0')
  631. {
  632. New->Length = (USHORT) Count * sizeof(WCHAR);
  633. break;
  634. }
  635. }
  636. //
  637. // now pad it out with spaces until reached Mac+Ras reserved length
  638. //
  639. pNewBuff = (WCHAR *) New->Buffer + ( New->Length / sizeof(WCHAR) );
  640. while ( New->Length < sizeof(UserProperties->Header.BacklevelParms))
  641. {
  642. *( pNewBuff++ ) = L' ';
  643. New->Length += sizeof(WCHAR);
  644. }
  645. //
  646. // If the signature isn't there, stick it in and set prop count to 0
  647. //
  648. UserProperties = (PUSER_PROPERTIES) New->Buffer;
  649. if (New->Length < sizeof(USER_PROPERTIES_HDR) ||
  650. UserProperties->Header.PropertySignature != USER_PROPERTY_SIGNATURE)
  651. {
  652. UserProperties->Header.PropertySignature = USER_PROPERTY_SIGNATURE;
  653. UserProperties->Header.PropertyCount = 0;
  654. New->Length = sizeof(USER_PROPERTIES_HDR);
  655. }
  656. return STATUS_SUCCESS;
  657. }
  658. // usrprop.c eof.