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.

625 lines
17 KiB

  1. /*++
  2. Copyright (c) 1998 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 "usrprop.h"
  27. #define NCP_SET 0x02 /* Series of Object ID numbers, each 4
  28. bytes long */
  29. //
  30. // All internal (opaque) structures are listed here since no one else
  31. // needs to reference them.
  32. //
  33. //
  34. // The user's Parameter field is mapped out to a structure that contains
  35. // the backlevel 48 WCHARs for Mac/Ras compatibility plus a new structure
  36. // that is basically an array of chars that make up a property name plus
  37. // a property value.
  38. //
  39. //
  40. // This is the structure for an individual property. Note that there are
  41. // no null terminators in this.
  42. //
  43. typedef struct _USER_PROPERTY {
  44. WCHAR PropertyLength; // length of property name
  45. WCHAR ValueLength; // length of property value
  46. WCHAR PropertyFlag; // type of property (1 = set, 2 = item)
  47. WCHAR Property[1]; // start of property name, followed by value
  48. } USER_PROPERTY, *PUSER_PROPERTY;
  49. //
  50. // This is the structure that maps the beginning of the user's Parameters
  51. // field. It is only separate so that we can do a sizeof() without including
  52. // the first property, which may or may not be there.
  53. //
  54. typedef struct _USER_PROPERTIES_HDR {
  55. WCHAR BacklevelParms[48]; // RAS & Mac data stored here.
  56. WCHAR PropertySignature; // signature that we can look for.
  57. WCHAR PropertyCount; // number of properties present.
  58. } USER_PROPERTIES_HDR, *PUSER_PROPERTIES_HDR;
  59. //
  60. // This structure maps out the whole of the user's Parameters field when
  61. // the user properties structure is present and at least one property is
  62. // defined.
  63. //
  64. typedef struct _USER_PROPERTIES {
  65. USER_PROPERTIES_HDR Header;
  66. USER_PROPERTY FirstProperty;
  67. } USER_PROPERTIES, *PUSER_PROPERTIES;
  68. //
  69. // forward references
  70. //
  71. NTSTATUS
  72. UserPropertyAllocBlock (
  73. IN PUNICODE_STRING Existing,
  74. IN ULONG DesiredLength,
  75. IN OUT PUNICODE_STRING New
  76. );
  77. BOOL
  78. FindUserProperty (
  79. PUSER_PROPERTIES UserProperties,
  80. LPWSTR Property,
  81. PUSER_PROPERTY *pUserProperty,
  82. USHORT *pCount
  83. );
  84. VOID
  85. RemoveUserProperty (
  86. UNICODE_STRING *puniUserParms,
  87. PUSER_PROPERTY UserProperty,
  88. USHORT Count,
  89. BOOL *Update
  90. );
  91. NTSTATUS
  92. SetUserProperty (
  93. IN LPWSTR UserParms,
  94. IN LPWSTR Property,
  95. IN UNICODE_STRING PropertyValue,
  96. IN WCHAR PropertyFlag,
  97. IN BOOL fDefaultValue, // *
  98. OUT LPWSTR *pNewUserParms, // memory has to be freed afer use.
  99. OUT BOOL *Update
  100. )
  101. /*
  102. This function sets a property field in the user's Parameters field.
  103. */
  104. {
  105. NTSTATUS status;
  106. UNICODE_STRING uniUserParms;
  107. UNICODE_STRING uniNewUserParms;
  108. USHORT Count = 0;
  109. USHORT PropertyLength;
  110. USHORT ValueLength;
  111. PUSER_PROPERTIES UserProperties;
  112. PUSER_PROPERTY UserProperty;
  113. LPWSTR PropertyValueString = NULL;
  114. INT i;
  115. UCHAR *pchValue = NULL;
  116. // Check if parameters are correct.
  117. if (Property == NULL)
  118. {
  119. return( STATUS_INVALID_PARAMETER );
  120. }
  121. // Initialize output variables.
  122. *Update = FALSE;
  123. *pNewUserParms = NULL;
  124. // Converty UserParms to unicode string.
  125. uniUserParms.Buffer = UserParms;
  126. uniUserParms.Length = UserParms? (lstrlenW(UserParms) + 1)* sizeof (WCHAR)
  127. : 0;
  128. uniUserParms.MaximumLength = uniUserParms.Length;
  129. /** Get the length of the property name **/
  130. PropertyLength = (USHORT)(lstrlenW( Property ) * sizeof(WCHAR));
  131. /** Get the length of the property value **/
  132. ValueLength = PropertyValue.Length;
  133. if (ValueLength != 0)
  134. {
  135. // Converty property value to asci string so that
  136. // if property value is 0, it can be stored correctly.
  137. PropertyValueString = (LPWSTR) LocalAlloc (LPTR, (ValueLength+1)*sizeof (WCHAR));
  138. if ( !PropertyValueString ) {
  139. return( STATUS_INSUFFICIENT_RESOURCES );
  140. }
  141. pchValue = (UCHAR *) PropertyValue.Buffer;
  142. // Since wsprint converts 0x00 to 20 30 (20 is
  143. // space and 30 is 0), sscanf converts 20 30 to 0. If the
  144. // value is uncode string, this convertsion would not
  145. // convert back to original value. So if we want to store
  146. // some value in the UserParms, we have to pass in ansi
  147. // string.
  148. //
  149. // The reader does the proper counter to this, so the code is
  150. // symetrical.
  151. //
  152. //
  153. for (i = 0; i < ValueLength; i++)
  154. {
  155. wsprintfA ((PCHAR)(PropertyValueString+i), "%02x", *(pchValue+i));
  156. }
  157. *(PropertyValueString+ValueLength) = 0;
  158. ValueLength = ValueLength * sizeof (WCHAR);
  159. }
  160. //
  161. // check that user has valid property structure , if not, create one
  162. //
  163. if (UserParms != NULL)
  164. {
  165. Count = (USHORT)((lstrlenW (UserParms) + 1)* sizeof(WCHAR));
  166. }
  167. if (Count < sizeof( USER_PROPERTIES))
  168. {
  169. Count = sizeof( USER_PROPERTIES_HDR ) + sizeof(WCHAR);
  170. }
  171. if (ValueLength > 0)
  172. {
  173. Count += sizeof( USER_PROPERTY ) + PropertyLength + ValueLength;
  174. }
  175. if (Count > 0x7FFF)
  176. {
  177. // can't be bigger than 32K of user parms.
  178. return (STATUS_BUFFER_OVERFLOW);
  179. }
  180. status = UserPropertyAllocBlock( &uniUserParms,
  181. Count,
  182. &uniNewUserParms );
  183. if ( !NT_SUCCESS(status) )
  184. {
  185. return status;
  186. }
  187. // Make the output pNewUserParms point to uniNewUserPams's buffer
  188. // which is the new UserParms string.
  189. *pNewUserParms = uniNewUserParms.Buffer;
  190. UserProperties = (PUSER_PROPERTIES) uniNewUserParms.Buffer;
  191. if (FindUserProperty (UserProperties,
  192. Property,
  193. &UserProperty,
  194. &Count))
  195. {
  196. RemoveUserProperty ( &uniNewUserParms,
  197. UserProperty,
  198. Count,
  199. Update);
  200. }
  201. // We don't add the new property at all if FindUserProperty failed then
  202. // the property did not exist, if property did exist then RemoveUserProperty
  203. // would have removed it from the list.
  204. if( fDefaultValue )
  205. {
  206. *Update = TRUE;
  207. return STATUS_SUCCESS;
  208. }
  209. //
  210. // If the new value of the property is not null, add it.
  211. //
  212. if (ValueLength > 0)
  213. {
  214. // find the end of the parameters list
  215. UserProperty = &(UserProperties->FirstProperty);
  216. for (Count = 1; Count <= UserProperties->Header.PropertyCount; Count++)
  217. {
  218. UserProperty = (PUSER_PROPERTY)
  219. ((LPSTR)((LPSTR) UserProperty +
  220. sizeof(USER_PROPERTY) + // length of entry
  221. UserProperty->PropertyLength +
  222. UserProperty->ValueLength -
  223. sizeof(WCHAR))); // for Property[0]
  224. }
  225. //
  226. // append it to the end and update length of string
  227. //
  228. UserProperty->PropertyFlag = (PropertyFlag & NCP_SET) ?
  229. USER_PROPERTY_TYPE_SET :
  230. USER_PROPERTY_TYPE_ITEM;
  231. UserProperty->PropertyLength = PropertyLength;
  232. UserProperty->ValueLength = ValueLength;
  233. RtlCopyMemory( &(UserProperty->Property[0]),
  234. Property,
  235. PropertyLength );
  236. RtlCopyMemory( &(UserProperty->Property[PropertyLength / sizeof(WCHAR)]),
  237. PropertyValueString,
  238. ValueLength );
  239. uniNewUserParms.Length +=
  240. sizeof(USER_PROPERTY) + // length of entry
  241. PropertyLength + // length of property name string
  242. ValueLength - // length of value string
  243. sizeof(WCHAR); // account for WCHAR Property[1]
  244. UserProperties->Header.PropertyCount++;
  245. *Update = TRUE;
  246. }
  247. // UserParms is already null terminated. We don't need to set the
  248. // end of UserParms to be NULL since we zero init the buffer already.
  249. return( status );
  250. } // SetUserProperty
  251. #define MAPHEXTODIGIT(x) ( x >= '0' && x <= '9' ? (x-'0') : \
  252. x >= 'A' && x <= 'F' ? (x-'A'+10) : \
  253. x >= 'a' && x <= 'f' ? (x-'a'+10) : 0 )
  254. NTSTATUS
  255. QueryUserProperty (
  256. IN LPWSTR UserParms,
  257. IN LPWSTR PropertyName,
  258. OUT PWCHAR PropertyFlag,
  259. OUT PUNICODE_STRING PropertyValue
  260. )
  261. /*
  262. This routine returns a user definable property value as it is stored
  263. in the user's Parameters field. Note that the RAS/MAC fields are
  264. stripped before we start processing user properties.
  265. */
  266. {
  267. USHORT PropertyNameLength;
  268. USHORT Count;
  269. PUSER_PROPERTY UserProperty;
  270. WCHAR *Value;
  271. UINT i;
  272. CHAR *PropertyValueString;
  273. CHAR *pchValue;
  274. // Set PropertyValue->Length to 0 initially. If the property is not found
  275. // it will still be 0 on exit.
  276. PropertyValue->Length = 0;
  277. PropertyValue->Buffer = NULL;
  278. PropertyNameLength = (USHORT)(lstrlenW(PropertyName) * sizeof(WCHAR));
  279. // Check if UserParms have the right structure.
  280. if (FindUserProperty ((PUSER_PROPERTIES) UserParms,
  281. PropertyName,
  282. &UserProperty,
  283. &Count) )
  284. {
  285. Value = (LPWSTR)(LPSTR)((LPSTR) &(UserProperty->Property[0]) +
  286. PropertyNameLength);
  287. //
  288. // Found the requested property
  289. //
  290. //
  291. // Copy the property flag.
  292. //
  293. if (PropertyFlag)
  294. *PropertyFlag = UserProperty->PropertyFlag;
  295. // Allocate memory for PropertyValue->Buffer
  296. PropertyValueString = LocalAlloc ( LPTR, UserProperty->ValueLength+1);
  297. PropertyValue->Buffer = LocalAlloc ( LPTR, UserProperty->ValueLength/sizeof(WCHAR));
  298. //
  299. // Make sure the property value length is valid.
  300. //
  301. if ((PropertyValue->Buffer == NULL) || (PropertyValueString == NULL))
  302. {
  303. return STATUS_INSUFFICIENT_RESOURCES;
  304. }
  305. //
  306. // Copy the property value to the buffer.
  307. //
  308. RtlCopyMemory( PropertyValueString,
  309. Value,
  310. UserProperty->ValueLength );
  311. pchValue = (CHAR *) PropertyValue->Buffer;
  312. // Convert from value unicode string to value.
  313. for (i = 0; i < UserProperty->ValueLength/sizeof(WCHAR) ; i++)
  314. {
  315. // sscanf will trash memory.
  316. // sscanf( PropertyValueString+2*i, "%2x", pchValue+i);
  317. pchValue[i] = MAPHEXTODIGIT( PropertyValueString[2*i]) * 16 +
  318. MAPHEXTODIGIT( PropertyValueString[2*i+1]);
  319. }
  320. PropertyValue->Length = UserProperty->ValueLength/sizeof(WCHAR);
  321. PropertyValue->MaximumLength = UserProperty->ValueLength/sizeof(WCHAR);
  322. LocalFree( PropertyValueString);
  323. }
  324. else
  325. {
  326. // if the property name does not exist we then load the default value
  327. // for this property
  328. return STATUS_OBJECT_NAME_NOT_FOUND;
  329. }
  330. return STATUS_SUCCESS;
  331. } // QueryUserProperty
  332. // Common routine used by QueryUserProperty() and SetUserProperty().
  333. BOOL
  334. FindUserProperty (
  335. PUSER_PROPERTIES UserProperties,
  336. LPWSTR Property,
  337. PUSER_PROPERTY *pUserProperty,
  338. USHORT *pCount
  339. )
  340. {
  341. BOOL fFound = FALSE;
  342. USHORT PropertyLength;
  343. //
  344. // Check if user has valid property structure attached,
  345. // pointed to by UserProperties.
  346. //
  347. if ( ( UserProperties != NULL )
  348. && ( lstrlenW( (LPWSTR) UserProperties) * sizeof(WCHAR) >
  349. sizeof(UserProperties->Header.BacklevelParms))
  350. && ( UserProperties->Header.PropertySignature == USER_PROPERTY_SIGNATURE)
  351. )
  352. {
  353. //
  354. // user has valid property structure.
  355. //
  356. *pUserProperty = &(UserProperties->FirstProperty);
  357. PropertyLength = (USHORT)(lstrlenW( Property ) * sizeof(WCHAR));
  358. for ( *pCount = 1; *pCount <= UserProperties->Header.PropertyCount;
  359. (*pCount)++ )
  360. {
  361. if ( ( PropertyLength == (*pUserProperty)->PropertyLength )
  362. && ( RtlCompareMemory( &((*pUserProperty)->Property[0]),
  363. Property,
  364. PropertyLength ) == PropertyLength )
  365. )
  366. {
  367. fFound = TRUE;
  368. break;
  369. }
  370. *pUserProperty = (PUSER_PROPERTY)
  371. ((LPSTR) (*pUserProperty)
  372. + sizeof( USER_PROPERTY )
  373. + (*pUserProperty)->PropertyLength
  374. + (*pUserProperty)->ValueLength
  375. - sizeof(WCHAR)); // for Property[0]
  376. }
  377. }
  378. return( fFound );
  379. } // FindUserProperty
  380. // Remove a property field from the User Parms.
  381. VOID
  382. RemoveUserProperty (
  383. UNICODE_STRING *puniUserParms,
  384. PUSER_PROPERTY UserProperty,
  385. USHORT Count,
  386. BOOL *Update
  387. )
  388. {
  389. PUSER_PROPERTIES UserProperties;
  390. PUSER_PROPERTY NextProperty;
  391. USHORT OldParmLength;
  392. UserProperties = (PUSER_PROPERTIES) puniUserParms->Buffer;
  393. OldParmLength = sizeof( USER_PROPERTY ) +
  394. UserProperty->PropertyLength +
  395. UserProperty->ValueLength -
  396. sizeof(WCHAR); // for Property[0]
  397. NextProperty = (PUSER_PROPERTY)(LPSTR)((LPSTR) UserProperty + OldParmLength);
  398. //
  399. // if we're not on the last one, copy the remaining buffer up
  400. //
  401. if (Count < UserProperties->Header.PropertyCount)
  402. {
  403. /*
  404. * Side note, remember it's not moving one property over
  405. * but it's removing one property by moving the entire set
  406. * of the userparamblk but we need to include the nullterminator
  407. * sizeof( wchar )
  408. */
  409. RtlMoveMemory( UserProperty,
  410. NextProperty,
  411. sizeof( WCHAR ) + puniUserParms->Length -
  412. ((LPSTR) NextProperty -
  413. (LPSTR) puniUserParms->Buffer ));
  414. }
  415. //
  416. // Now reduce the length of the buffer by the amount we pulled out
  417. //
  418. puniUserParms->Length -= OldParmLength;
  419. UserProperties->Header.PropertyCount--;
  420. *Update = TRUE;
  421. } // RemoveUserProperty
  422. NTSTATUS
  423. UserPropertyAllocBlock (
  424. IN PUNICODE_STRING Existing,
  425. IN ULONG DesiredLength,
  426. IN OUT PUNICODE_STRING New
  427. )
  428. /*
  429. This allocates a larger block for user's parameters and copies the old
  430. block in.
  431. */
  432. {
  433. PUSER_PROPERTIES UserProperties;
  434. CLONG Count;
  435. WCHAR *pNewBuff;
  436. //
  437. // We will allocate a new buffer to store the new parameters
  438. // and copy the existing parameters into it.
  439. //
  440. New->Buffer = LocalAlloc (LPTR, DesiredLength);
  441. if ( New->Buffer == NULL)
  442. {
  443. return STATUS_INSUFFICIENT_RESOURCES;
  444. }
  445. New->MaximumLength = (USHORT) DesiredLength;
  446. if (Existing != NULL)
  447. {
  448. New->Length = Existing->Length;
  449. RtlCopyMemory( New->Buffer,
  450. Existing->Buffer,
  451. Existing->Length );
  452. }
  453. else
  454. {
  455. New->Length = 0;
  456. }
  457. //
  458. // Ensure that we don't have any nulls in our string.
  459. //
  460. for ( Count = 0;
  461. Count < New->Length / sizeof(WCHAR);
  462. Count++ )
  463. {
  464. if (*(New->Buffer + Count) == L'\0')
  465. {
  466. New->Length = (USHORT) Count * sizeof(WCHAR);
  467. break;
  468. }
  469. }
  470. //
  471. // now pad it out with spaces until reached Mac+Ras reserved length
  472. //
  473. pNewBuff = (WCHAR *) New->Buffer + ( New->Length / sizeof(WCHAR) );
  474. while ( New->Length < sizeof(UserProperties->Header.BacklevelParms))
  475. {
  476. *( pNewBuff++ ) = L' ';
  477. New->Length += sizeof(WCHAR);
  478. }
  479. //
  480. // If the signature isn't there, stick it in and set prop count to 0
  481. //
  482. UserProperties = (PUSER_PROPERTIES) New->Buffer;
  483. if (New->Length < sizeof(USER_PROPERTIES_HDR) ||
  484. UserProperties->Header.PropertySignature != USER_PROPERTY_SIGNATURE)
  485. {
  486. UserProperties->Header.PropertySignature = USER_PROPERTY_SIGNATURE;
  487. UserProperties->Header.PropertyCount = 0;
  488. New->Length = sizeof(USER_PROPERTIES_HDR);
  489. }
  490. return STATUS_SUCCESS;
  491. } // UserPropertyAllocBlock
  492. // usrprop.c eof.