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.

592 lines
16 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 "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. OUT LPWSTR *pNewUserParms, // memory has to be freed afer use.
  98. OUT BOOL *Update
  99. )
  100. /*
  101. This function sets a property field in the user's Parameters field.
  102. */
  103. {
  104. NTSTATUS status;
  105. UNICODE_STRING uniUserParms;
  106. UNICODE_STRING uniNewUserParms;
  107. USHORT Count = 0;
  108. USHORT PropertyLength;
  109. USHORT ValueLength;
  110. PUSER_PROPERTIES UserProperties;
  111. PUSER_PROPERTY UserProperty;
  112. LPWSTR PropertyValueString = NULL;
  113. INT i;
  114. UCHAR *pchValue = NULL;
  115. // Check if parameters are correct.
  116. if (Property == NULL)
  117. {
  118. return( STATUS_INVALID_PARAMETER );
  119. }
  120. // Initialize output variables.
  121. *Update = FALSE;
  122. *pNewUserParms = NULL;
  123. // Converty UserParms to unicode string.
  124. uniUserParms.Buffer = UserParms;
  125. uniUserParms.Length = UserParms? (lstrlenW(UserParms) + 1)* sizeof (WCHAR)
  126. : 0;
  127. uniUserParms.MaximumLength = uniUserParms.Length;
  128. /** Get the length of the property name **/
  129. PropertyLength = (USHORT)(lstrlenW( Property ) * sizeof(WCHAR));
  130. /** Get the length of the property value **/
  131. ValueLength = PropertyValue.Length;
  132. if (ValueLength != 0)
  133. {
  134. // Converty property value to asci string so that
  135. // if property value is 0, it can be stored correctly.
  136. PropertyValueString = (LPWSTR) LocalAlloc (LPTR, (ValueLength+1)*sizeof (WCHAR));
  137. pchValue = (UCHAR *) PropertyValue.Buffer;
  138. // BUGBUG. Since wsprint converts 0x00 to 20 30 (20 is
  139. // space and 30 is 0), sscanf converts 20 30 to 0. If the
  140. // value is uncode string, this convertsion would not
  141. // convert back to original value. So if we want to store
  142. // some value in the UserParms, we have to pass in ansi
  143. // string.
  144. for (i = 0; i < ValueLength; i++)
  145. {
  146. wsprintfA ((PCHAR)(PropertyValueString+i), "%02x", *(pchValue+i));
  147. }
  148. *(PropertyValueString+ValueLength) = 0;
  149. ValueLength = ValueLength * sizeof (WCHAR);
  150. }
  151. //
  152. // check that user has valid property structure , if not, create one
  153. //
  154. if (UserParms != NULL)
  155. {
  156. Count = (USHORT)((lstrlenW (UserParms) + 1)* sizeof(WCHAR));
  157. }
  158. if (Count < sizeof( USER_PROPERTIES))
  159. {
  160. Count = sizeof( USER_PROPERTIES_HDR ) + sizeof(WCHAR);
  161. }
  162. if (ValueLength > 0)
  163. {
  164. Count += sizeof( USER_PROPERTY ) + PropertyLength + ValueLength;
  165. }
  166. if (Count > 0x7FFF)
  167. {
  168. // can't be bigger than 32K of user parms.
  169. return (STATUS_BUFFER_OVERFLOW);
  170. }
  171. status = UserPropertyAllocBlock( &uniUserParms,
  172. Count,
  173. &uniNewUserParms );
  174. if ( !NT_SUCCESS(status) )
  175. {
  176. return status;
  177. }
  178. // Make the output pNewUserParms point to uniNewUserPams's buffer
  179. // which is the new UserParms string.
  180. *pNewUserParms = uniNewUserParms.Buffer;
  181. UserProperties = (PUSER_PROPERTIES) uniNewUserParms.Buffer;
  182. if (FindUserProperty (UserProperties,
  183. Property,
  184. &UserProperty,
  185. &Count))
  186. {
  187. RemoveUserProperty ( &uniNewUserParms,
  188. UserProperty,
  189. Count,
  190. Update);
  191. }
  192. //
  193. // If the new value of the property is not null, add it.
  194. //
  195. if (ValueLength > 0) {
  196. // find the end of the parameters list
  197. UserProperty = &(UserProperties->FirstProperty);
  198. for (Count = 1; Count <= UserProperties->Header.PropertyCount; Count++)
  199. {
  200. UserProperty = (PUSER_PROPERTY)
  201. ((LPSTR)((LPSTR) UserProperty +
  202. sizeof(USER_PROPERTY) + // length of entry
  203. UserProperty->PropertyLength +
  204. UserProperty->ValueLength -
  205. sizeof(WCHAR))); // for Property[0]
  206. }
  207. //
  208. // append it to the end and update length of string
  209. //
  210. UserProperty->PropertyFlag = (PropertyFlag & NCP_SET) ?
  211. USER_PROPERTY_TYPE_SET :
  212. USER_PROPERTY_TYPE_ITEM;
  213. UserProperty->PropertyLength = PropertyLength;
  214. UserProperty->ValueLength = ValueLength;
  215. RtlCopyMemory( &(UserProperty->Property[0]),
  216. Property,
  217. PropertyLength );
  218. RtlCopyMemory( &(UserProperty->Property[PropertyLength / sizeof(WCHAR)]),
  219. PropertyValueString,
  220. ValueLength );
  221. uniNewUserParms.Length +=
  222. sizeof(USER_PROPERTY) + // length of entry
  223. PropertyLength + // length of property name string
  224. ValueLength - // length of value string
  225. sizeof(WCHAR); // account for WCHAR Property[1]
  226. UserProperties->Header.PropertyCount++;
  227. *Update = TRUE;
  228. }
  229. // UserParms is already null terminated. We don't need to set the
  230. // end of UserParms to be NULL since we zero init the buffer already.
  231. return( status );
  232. } // SetUserProperty
  233. #define MAPHEXTODIGIT(x) ( x >= '0' && x <= '9' ? (x-'0') : \
  234. x >= 'A' && x <= 'F' ? (x-'A'+10) : \
  235. x >= 'a' && x <= 'f' ? (x-'a'+10) : 0 )
  236. NTSTATUS
  237. QueryUserProperty (
  238. IN LPWSTR UserParms,
  239. IN LPWSTR PropertyName,
  240. OUT PWCHAR PropertyFlag,
  241. OUT PUNICODE_STRING PropertyValue
  242. )
  243. /*
  244. This routine returns a user definable property value as it is stored
  245. in the user's Parameters field. Note that the RAS/MAC fields are
  246. stripped before we start processing user properties.
  247. */
  248. {
  249. USHORT PropertyNameLength;
  250. USHORT Count;
  251. PUSER_PROPERTY UserProperty;
  252. WCHAR *Value;
  253. UINT i;
  254. CHAR *PropertyValueString;
  255. CHAR *pchValue;
  256. // Set PropertyValue->Length to 0 initially. If the property is not found
  257. // it will still be 0 on exit.
  258. PropertyValue->Length = 0;
  259. PropertyValue->Buffer = NULL;
  260. PropertyNameLength = (USHORT)(lstrlenW(PropertyName) * sizeof(WCHAR));
  261. // Check if UserParms have the right structure.
  262. if (FindUserProperty ((PUSER_PROPERTIES) UserParms,
  263. PropertyName,
  264. &UserProperty,
  265. &Count) )
  266. {
  267. Value = (LPWSTR)(LPSTR)((LPSTR) &(UserProperty->Property[0]) +
  268. PropertyNameLength);
  269. //
  270. // Found the requested property
  271. //
  272. //
  273. // Copy the property flag.
  274. //
  275. if (PropertyFlag)
  276. *PropertyFlag = UserProperty->PropertyFlag;
  277. // Allocate memory for PropertyValue->Buffer
  278. PropertyValueString = LocalAlloc ( LPTR, UserProperty->ValueLength+1);
  279. PropertyValue->Buffer = LocalAlloc ( LPTR, UserProperty->ValueLength/sizeof(WCHAR));
  280. //
  281. // Make sure the property value length is valid.
  282. //
  283. if ((PropertyValue->Buffer == NULL) || (PropertyValueString == NULL))
  284. {
  285. return STATUS_INSUFFICIENT_RESOURCES;
  286. }
  287. //
  288. // Copy the property value to the buffer.
  289. //
  290. RtlCopyMemory( PropertyValueString,
  291. Value,
  292. UserProperty->ValueLength );
  293. pchValue = (CHAR *) PropertyValue->Buffer;
  294. // Convert from value unicode string to value.
  295. for (i = 0; i < UserProperty->ValueLength/sizeof(WCHAR) ; i++)
  296. {
  297. // sscanf will trash memory.
  298. // sscanf( PropertyValueString+2*i, "%2x", pchValue+i);
  299. pchValue[i] = MAPHEXTODIGIT( PropertyValueString[2*i]) * 16 +
  300. MAPHEXTODIGIT( PropertyValueString[2*i+1]);
  301. }
  302. PropertyValue->Length = UserProperty->ValueLength/sizeof(WCHAR);
  303. PropertyValue->MaximumLength = UserProperty->ValueLength/sizeof(WCHAR);
  304. LocalFree( PropertyValueString);
  305. }
  306. return STATUS_SUCCESS;
  307. } // QueryUserProperty
  308. // Common routine used by QueryUserProperty() and SetUserProperty().
  309. BOOL
  310. FindUserProperty (
  311. PUSER_PROPERTIES UserProperties,
  312. LPWSTR Property,
  313. PUSER_PROPERTY *pUserProperty,
  314. USHORT *pCount
  315. )
  316. {
  317. BOOL fFound = FALSE;
  318. USHORT PropertyLength;
  319. //
  320. // Check if user has valid property structure attached,
  321. // pointed to by UserProperties.
  322. //
  323. if ( ( UserProperties != NULL )
  324. && ( lstrlenW( (LPWSTR) UserProperties) * sizeof(WCHAR) >
  325. sizeof(UserProperties->Header.BacklevelParms))
  326. && ( UserProperties->Header.PropertySignature == USER_PROPERTY_SIGNATURE)
  327. )
  328. {
  329. //
  330. // user has valid property structure.
  331. //
  332. *pUserProperty = &(UserProperties->FirstProperty);
  333. PropertyLength = (USHORT)(lstrlenW( Property ) * sizeof(WCHAR));
  334. for ( *pCount = 1; *pCount <= UserProperties->Header.PropertyCount;
  335. (*pCount)++ )
  336. {
  337. if ( ( PropertyLength == (*pUserProperty)->PropertyLength )
  338. && ( RtlCompareMemory( &((*pUserProperty)->Property[0]),
  339. Property,
  340. PropertyLength ) == PropertyLength )
  341. )
  342. {
  343. fFound = TRUE;
  344. break;
  345. }
  346. *pUserProperty = (PUSER_PROPERTY)
  347. ((LPSTR) (*pUserProperty)
  348. + sizeof( USER_PROPERTY )
  349. + (*pUserProperty)->PropertyLength
  350. + (*pUserProperty)->ValueLength
  351. - sizeof(WCHAR)); // for Property[0]
  352. }
  353. }
  354. return( fFound );
  355. } // FindUserProperty
  356. // Remove a property field from the User Parms.
  357. VOID
  358. RemoveUserProperty (
  359. UNICODE_STRING *puniUserParms,
  360. PUSER_PROPERTY UserProperty,
  361. USHORT Count,
  362. BOOL *Update
  363. )
  364. {
  365. PUSER_PROPERTIES UserProperties;
  366. PUSER_PROPERTY NextProperty;
  367. USHORT OldParmLength;
  368. UserProperties = (PUSER_PROPERTIES) puniUserParms->Buffer;
  369. OldParmLength = sizeof( USER_PROPERTY ) +
  370. UserProperty->PropertyLength +
  371. UserProperty->ValueLength -
  372. sizeof(WCHAR); // for Property[0]
  373. NextProperty = (PUSER_PROPERTY)(LPSTR)((LPSTR) UserProperty + OldParmLength);
  374. //
  375. // if we're not on the last one, copy the remaining buffer up
  376. //
  377. if (Count < UserProperties->Header.PropertyCount) {
  378. RtlMoveMemory( UserProperty,
  379. NextProperty,
  380. puniUserParms->Length -
  381. ((LPSTR) NextProperty -
  382. (LPSTR) puniUserParms->Buffer ));
  383. }
  384. //
  385. // Now reduce the length of the buffer by the amount we pulled out
  386. //
  387. puniUserParms->Length -= OldParmLength;
  388. UserProperties->Header.PropertyCount--;
  389. *Update = TRUE;
  390. } // RemoveUserProperty
  391. NTSTATUS
  392. UserPropertyAllocBlock (
  393. IN PUNICODE_STRING Existing,
  394. IN ULONG DesiredLength,
  395. IN OUT PUNICODE_STRING New
  396. )
  397. /*
  398. This allocates a larger block for user's parameters and copies the old
  399. block in.
  400. */
  401. {
  402. PUSER_PROPERTIES UserProperties;
  403. CLONG Count;
  404. WCHAR *pNewBuff;
  405. //
  406. // We will allocate a new buffer to store the new parameters
  407. // and copy the existing parameters into it.
  408. //
  409. New->Buffer = LocalAlloc (LPTR, DesiredLength);
  410. if ( New->Buffer == NULL)
  411. {
  412. return STATUS_INSUFFICIENT_RESOURCES;
  413. }
  414. New->MaximumLength = (USHORT) DesiredLength;
  415. if (Existing != NULL)
  416. {
  417. New->Length = Existing->Length;
  418. RtlCopyMemory( New->Buffer,
  419. Existing->Buffer,
  420. Existing->Length );
  421. }
  422. else
  423. {
  424. New->Length = 0;
  425. }
  426. //
  427. // Ensure that we don't have any nulls in our string.
  428. //
  429. for ( Count = 0;
  430. Count < New->Length / sizeof(WCHAR);
  431. Count++ )
  432. {
  433. if (*(New->Buffer + Count) == L'\0')
  434. {
  435. New->Length = (USHORT) Count * sizeof(WCHAR);
  436. break;
  437. }
  438. }
  439. //
  440. // now pad it out with spaces until reached Mac+Ras reserved length
  441. //
  442. pNewBuff = (WCHAR *) New->Buffer + ( New->Length / sizeof(WCHAR) );
  443. while ( New->Length < sizeof(UserProperties->Header.BacklevelParms))
  444. {
  445. *( pNewBuff++ ) = L' ';
  446. New->Length += sizeof(WCHAR);
  447. }
  448. //
  449. // If the signature isn't there, stick it in and set prop count to 0
  450. //
  451. UserProperties = (PUSER_PROPERTIES) New->Buffer;
  452. if (New->Length < sizeof(USER_PROPERTIES_HDR) ||
  453. UserProperties->Header.PropertySignature != USER_PROPERTY_SIGNATURE)
  454. {
  455. UserProperties->Header.PropertySignature = USER_PROPERTY_SIGNATURE;
  456. UserProperties->Header.PropertyCount = 0;
  457. New->Length = sizeof(USER_PROPERTIES_HDR);
  458. }
  459. return STATUS_SUCCESS;
  460. } // UserPropertyAllocBlock
  461. // usrprop.c eof.