Leaked source code of windows server 2003
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.

633 lines
18 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. LocalFree(PropertyValueString);
  247. }
  248. // UserParms is already null terminated. We don't need to set the
  249. // end of UserParms to be NULL since we zero init the buffer already.
  250. return( status );
  251. } // SetUserProperty
  252. #define MAPHEXTODIGIT(x) ( x >= '0' && x <= '9' ? (x-'0') : \
  253. x >= 'A' && x <= 'F' ? (x-'A'+10) : \
  254. x >= 'a' && x <= 'f' ? (x-'a'+10) : 0 )
  255. NTSTATUS
  256. QueryUserProperty (
  257. IN LPWSTR UserParms,
  258. IN LPWSTR PropertyName,
  259. OUT PWCHAR PropertyFlag,
  260. OUT PUNICODE_STRING PropertyValue
  261. )
  262. /*
  263. This routine returns a user definable property value as it is stored
  264. in the user's Parameters field. Note that the RAS/MAC fields are
  265. stripped before we start processing user properties.
  266. */
  267. {
  268. USHORT PropertyNameLength;
  269. USHORT Count;
  270. PUSER_PROPERTY UserProperty;
  271. WCHAR *Value;
  272. UINT i;
  273. CHAR *PropertyValueString;
  274. CHAR *pchValue;
  275. // Set PropertyValue->Length to 0 initially. If the property is not found
  276. // it will still be 0 on exit.
  277. PropertyValue->Length = 0;
  278. PropertyValue->Buffer = NULL;
  279. PropertyNameLength = (USHORT)(lstrlenW(PropertyName) * sizeof(WCHAR));
  280. // Check if UserParms have the right structure.
  281. if (FindUserProperty ((PUSER_PROPERTIES) UserParms,
  282. PropertyName,
  283. &UserProperty,
  284. &Count) )
  285. {
  286. Value = (LPWSTR)(LPSTR)((LPSTR) &(UserProperty->Property[0]) +
  287. PropertyNameLength);
  288. //
  289. // Found the requested property
  290. //
  291. //
  292. // Copy the property flag.
  293. //
  294. if (PropertyFlag)
  295. *PropertyFlag = UserProperty->PropertyFlag;
  296. // Allocate memory for PropertyValue->Buffer
  297. PropertyValueString = LocalAlloc ( LPTR, UserProperty->ValueLength+1);
  298. if (PropertyValueString == NULL) {
  299. return STATUS_INSUFFICIENT_RESOURCES;
  300. }
  301. PropertyValue->Buffer = LocalAlloc ( LPTR, UserProperty->ValueLength/sizeof(WCHAR));
  302. //
  303. // Make sure the property value length is valid.
  304. //
  305. if (PropertyValue->Buffer == NULL)
  306. {
  307. LocalFree(PropertyValueString);
  308. return STATUS_INSUFFICIENT_RESOURCES;
  309. }
  310. //
  311. // Copy the property value to the buffer.
  312. //
  313. RtlCopyMemory( PropertyValueString,
  314. Value,
  315. UserProperty->ValueLength );
  316. pchValue = (CHAR *) PropertyValue->Buffer;
  317. // Convert from value unicode string to value.
  318. for (i = 0; i < UserProperty->ValueLength/sizeof(WCHAR) ; i++)
  319. {
  320. // sscanf will trash memory.
  321. // sscanf( PropertyValueString+2*i, "%2x", pchValue+i);
  322. pchValue[i] = MAPHEXTODIGIT( PropertyValueString[2*i]) * 16 +
  323. MAPHEXTODIGIT( PropertyValueString[2*i+1]);
  324. }
  325. PropertyValue->Length = UserProperty->ValueLength/sizeof(WCHAR);
  326. PropertyValue->MaximumLength = UserProperty->ValueLength/sizeof(WCHAR);
  327. LocalFree( PropertyValueString);
  328. }
  329. else
  330. {
  331. // if the property name does not exist we then load the default value
  332. // for this property
  333. return STATUS_OBJECT_NAME_NOT_FOUND;
  334. }
  335. return STATUS_SUCCESS;
  336. } // QueryUserProperty
  337. // Common routine used by QueryUserProperty() and SetUserProperty().
  338. BOOL
  339. FindUserProperty (
  340. PUSER_PROPERTIES UserProperties,
  341. LPWSTR Property,
  342. PUSER_PROPERTY *pUserProperty,
  343. USHORT *pCount
  344. )
  345. {
  346. BOOL fFound = FALSE;
  347. USHORT PropertyLength;
  348. //
  349. // Check if user has valid property structure attached,
  350. // pointed to by UserProperties.
  351. //
  352. if ( ( UserProperties != NULL )
  353. && ( lstrlenW( (LPWSTR) UserProperties) * sizeof(WCHAR) >
  354. sizeof(UserProperties->Header.BacklevelParms))
  355. && ( UserProperties->Header.PropertySignature == USER_PROPERTY_SIGNATURE)
  356. )
  357. {
  358. //
  359. // user has valid property structure.
  360. //
  361. *pUserProperty = &(UserProperties->FirstProperty);
  362. PropertyLength = (USHORT)(lstrlenW( Property ) * sizeof(WCHAR));
  363. for ( *pCount = 1; *pCount <= UserProperties->Header.PropertyCount;
  364. (*pCount)++ )
  365. {
  366. if ( ( PropertyLength == (*pUserProperty)->PropertyLength )
  367. && ( RtlCompareMemory( &((*pUserProperty)->Property[0]),
  368. Property,
  369. PropertyLength ) == PropertyLength )
  370. )
  371. {
  372. fFound = TRUE;
  373. break;
  374. }
  375. *pUserProperty = (PUSER_PROPERTY)
  376. ((LPSTR) (*pUserProperty)
  377. + sizeof( USER_PROPERTY )
  378. + (*pUserProperty)->PropertyLength
  379. + (*pUserProperty)->ValueLength
  380. - sizeof(WCHAR)); // for Property[0]
  381. }
  382. }
  383. return( fFound );
  384. } // FindUserProperty
  385. // Remove a property field from the User Parms.
  386. VOID
  387. RemoveUserProperty (
  388. UNICODE_STRING *puniUserParms,
  389. PUSER_PROPERTY UserProperty,
  390. USHORT Count,
  391. BOOL *Update
  392. )
  393. {
  394. PUSER_PROPERTIES UserProperties;
  395. PUSER_PROPERTY NextProperty;
  396. USHORT OldParmLength;
  397. UserProperties = (PUSER_PROPERTIES) puniUserParms->Buffer;
  398. OldParmLength = sizeof( USER_PROPERTY ) +
  399. UserProperty->PropertyLength +
  400. UserProperty->ValueLength -
  401. sizeof(WCHAR); // for Property[0]
  402. NextProperty = (PUSER_PROPERTY)(LPSTR)((LPSTR) UserProperty + OldParmLength);
  403. //
  404. // if we're not on the last one, copy the remaining buffer up
  405. //
  406. if (Count < UserProperties->Header.PropertyCount)
  407. {
  408. /*
  409. * Side note, remember it's not moving one property over
  410. * but it's removing one property by moving the entire set
  411. * of the userparamblk but we need to include the nullterminator
  412. * sizeof( wchar )
  413. */
  414. RtlMoveMemory( UserProperty,
  415. NextProperty,
  416. sizeof( WCHAR ) + puniUserParms->Length -
  417. ((LPSTR) NextProperty -
  418. (LPSTR) puniUserParms->Buffer ));
  419. }
  420. //
  421. // Now reduce the length of the buffer by the amount we pulled out
  422. //
  423. puniUserParms->Length -= OldParmLength;
  424. UserProperties->Header.PropertyCount--;
  425. *Update = TRUE;
  426. } // RemoveUserProperty
  427. NTSTATUS
  428. UserPropertyAllocBlock (
  429. IN PUNICODE_STRING Existing,
  430. IN ULONG DesiredLength,
  431. IN OUT PUNICODE_STRING New
  432. )
  433. /*
  434. This allocates a larger block for user's parameters and copies the old
  435. block in.
  436. */
  437. {
  438. PUSER_PROPERTIES UserProperties;
  439. CLONG Count;
  440. WCHAR *pNewBuff;
  441. //
  442. // We will allocate a new buffer to store the new parameters
  443. // and copy the existing parameters into it.
  444. //
  445. New->Buffer = LocalAlloc (LPTR, DesiredLength);
  446. if ( New->Buffer == NULL)
  447. {
  448. return STATUS_INSUFFICIENT_RESOURCES;
  449. }
  450. New->MaximumLength = (USHORT) DesiredLength;
  451. if (Existing != NULL)
  452. {
  453. New->Length = Existing->Length;
  454. RtlCopyMemory( New->Buffer,
  455. Existing->Buffer,
  456. Existing->Length );
  457. }
  458. else
  459. {
  460. New->Length = 0;
  461. }
  462. //
  463. // Ensure that we don't have any nulls in our string.
  464. //
  465. for ( Count = 0;
  466. Count < New->Length / sizeof(WCHAR);
  467. Count++ )
  468. {
  469. if (*(New->Buffer + Count) == L'\0')
  470. {
  471. New->Length = (USHORT) Count * sizeof(WCHAR);
  472. break;
  473. }
  474. }
  475. //
  476. // now pad it out with spaces until reached Mac+Ras reserved length
  477. //
  478. pNewBuff = (WCHAR *) New->Buffer + ( New->Length / sizeof(WCHAR) );
  479. while ( New->Length < sizeof(UserProperties->Header.BacklevelParms))
  480. {
  481. *( pNewBuff++ ) = L' ';
  482. New->Length += sizeof(WCHAR);
  483. }
  484. //
  485. // If the signature isn't there, stick it in and set prop count to 0
  486. //
  487. UserProperties = (PUSER_PROPERTIES) New->Buffer;
  488. if (New->Length < sizeof(USER_PROPERTIES_HDR) ||
  489. UserProperties->Header.PropertySignature != USER_PROPERTY_SIGNATURE)
  490. {
  491. UserProperties->Header.PropertySignature = USER_PROPERTY_SIGNATURE;
  492. UserProperties->Header.PropertyCount = 0;
  493. New->Length = sizeof(USER_PROPERTIES_HDR);
  494. }
  495. return STATUS_SUCCESS;
  496. } // UserPropertyAllocBlock
  497. // usrprop.c eof.