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.

610 lines
19 KiB

  1. /*++
  2. The original filename was created in RuiM's EFS common library.
  3. I have since changed it severely.
  4. * FileName: delegation.c
  5. * Author: RuiM
  6. * Copyright (c) 1998 Microsoft Corp.
  7. *
  8. CONTENTS: U(QueryAccountControlFlags)
  9. U(SetAccountControlFlags)
  10. U(LdapFindAttributeInMessage)
  11. U(LdapSearchForUniqueDn)
  12. --*/
  13. #pragma warning(disable:4057) /* indirection to slightly different
  14. base types. Useless warning that hits
  15. thousands of times in this file. */
  16. #pragma warning(disable:4221) /* allow nonstandard extension (automatic
  17. initialization of a variable with
  18. address of another automatic variable) */
  19. #include "unimacro.h"
  20. #include <nt.h>
  21. #include <ntrtl.h>
  22. #include <nturtl.h>
  23. #include <ntdef.h> // required to keep winbase.h from breaking
  24. #include <ntpoapi.h> // required to keep winbase.h from breaking
  25. #include <windows.h>
  26. #include <winbase.h>
  27. #include <lmaccess.h>
  28. #include <winldap.h>
  29. #include <tchar.h>
  30. #include <stdlib.h>
  31. #include <stdio.h>
  32. #include "delegation.h"
  33. #include "delegtools.h"
  34. // These constants are required for queries below.
  35. TCHAR U(SamAccountAttribute) [] = TEXT("samAccountName");
  36. TCHAR U(UserAccountAttribute) [] = TEXT("userAccountControl");
  37. TCHAR U(NamingContextAttribute)[] = TEXT("defaultNamingContext");
  38. /*++**************************************************************
  39. NAME: U(LdapFindAttributeInMessage)
  40. This searches for a given attribute in a message (via
  41. ldap_get_values_len) and returns the value. Note that this function
  42. will fail if the attribute has multiple values.
  43. MODIFIES: pcbData -- receives length of the data (in bytes)
  44. ppvData -- receives pointer to the data
  45. TAKES: pLdap -- ldap connection handle
  46. pMessage -- message to search
  47. PropertyName -- property to find in the message
  48. RETURNS: TRUE when the function succeeds.
  49. FALSE otherwise.
  50. LASTERROR: not set
  51. LOGGING: printf on error
  52. CALLED BY: anyone
  53. FREE WITH: ppvdata should be freed with free()
  54. **************************************************************--*/
  55. BOOL
  56. U(LdapFindAttributeInMessage)( IN PLDAP pLdap,
  57. IN PLDAPMessage pMessage,
  58. IN LPTSTR PropertyName,
  59. OUT OPTIONAL PULONG pcbData,
  60. OUT OPTIONAL PVOID *ppvData ) {
  61. PLDAP_BERVAL *ppBerVals;
  62. BOOL ret = FALSE;
  63. ppBerVals = ldap_get_values_len( pLdap,
  64. pMessage,
  65. PropertyName );
  66. if ( ppBerVals ) {
  67. if ( ppBerVals[ 0 ] == NULL ) {
  68. printf( "ERROR: empty berval structure returned when parsing "
  69. STRING_FMTA " attribute.\n",
  70. PropertyName );
  71. SetLastError( ERROR_INVALID_DATA );
  72. } else if ( ppBerVals[ 1 ] != NULL ) {
  73. printf( "ERROR: nonunique berval structure returned "
  74. "when parsing " STRING_FMTA " attribute.\n",
  75. PropertyName );
  76. SetLastError( ERROR_DS_NAME_ERROR_NOT_UNIQUE );
  77. } else {
  78. /* this sequence is arranged in such a way that
  79. the important stuff comes last, keeping us
  80. from having to free ppvData after we've alloc'd it. */
  81. ret = TRUE;
  82. if ( pcbData ) {
  83. *pcbData = ppBerVals[ 0 ]->bv_len;
  84. }
  85. if ( ppvData ) {
  86. *ppvData = malloc( ppBerVals[ 0 ]->bv_len );
  87. if ( *ppvData ) {
  88. memcpy( *ppvData,
  89. ppBerVals[ 0 ]->bv_val,
  90. ppBerVals[ 0 ]->bv_len );
  91. } else {
  92. printf( "Failed to allocate %ld bytes.\n",
  93. ppBerVals[ 0 ]->bv_len );
  94. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  95. ret = FALSE;
  96. }
  97. }
  98. }
  99. ldap_value_free_len( ppBerVals );
  100. } else {
  101. printf( "Failed to retrieve values for property " STRING_FMTA
  102. ": 0x%x.\n",
  103. PropertyName,
  104. pLdap->ld_errno );
  105. SetLastError( pLdap->ld_errno );
  106. }
  107. return ret;
  108. }
  109. /*++**************************************************************
  110. NAME: U(LdapSearchForUniqueDn)
  111. Searches the DS for a DN with a match for the given search term.
  112. MODIFIES: pDnOfObject -- if requested, receives the object's DN
  113. ppMessage -- if requested, receives the message data
  114. TAKES: pLdap -- ldap handle returned by ldap_open
  115. SearchTerm -- what to search, e.g. "(foo=bar)"
  116. rzRequestedAttributes -- attributes to return in ppMessage
  117. RETURNS: TRUE when the function succeeds.
  118. FALSE otherwise or if the result is nonunique (WASBUG 73899).
  119. LASTERROR: not set
  120. LOGGING: printf on failure
  121. CALLED BY: anyone
  122. FREE WITH: free pDnOfObject with ldap_memfree
  123. free ppMessage with ldap_msgfree
  124. **************************************************************--*/
  125. BOOL
  126. U(LdapSearchForUniqueDn)( IN PLDAP pLdap,
  127. IN LPTSTR SearchTerm,
  128. IN LPTSTR *rzRequestedAttributes,
  129. OUT OPTIONAL LPTSTR *pDnOfObject,
  130. OUT OPTIONAL PLDAPMessage *ppMessage ) {
  131. DWORD dwErr;
  132. PLDAPMessage pMessage = NULL;
  133. PLDAPMessage pResult = NULL;
  134. LPTSTR pDn = NULL;
  135. LPTSTR *ppAttrs = NULL;
  136. BOOL ret = FALSE;
  137. LPTSTR Attrs[] = { U(NamingContextAttribute), NULL };
  138. /* First, determine the default naming context property for the base
  139. of the DSA. */
  140. dwErr = ldap_search_s( pLdap,
  141. NULL,
  142. LDAP_SCOPE_BASE,
  143. TEXT("objectClass=*"),
  144. Attrs,
  145. FALSE,
  146. &pResult );
  147. if ( dwErr == LDAP_SUCCESS ) {
  148. ppAttrs = ldap_get_values( pLdap,
  149. pResult,
  150. U(NamingContextAttribute) );
  151. if ( ppAttrs ) {
  152. dwErr = ldap_search_s( pLdap,
  153. ppAttrs[ 0 ],
  154. LDAP_SCOPE_SUBTREE, // search the whole tree
  155. SearchTerm,
  156. rzRequestedAttributes,
  157. FALSE, // don't only return attr names
  158. &pMessage );
  159. /* ldap_search_s can return a whole bunch of potential
  160. "success" errors. So, I'll check to see that pMessage
  161. is nonnull. This may or may not be a good thing to do,
  162. but it's bound to be safer than checking the error output. */
  163. if ( pMessage != NULL ) {
  164. // make sure the response is unique
  165. if ( !ldap_first_entry( pLdap,
  166. pMessage ) ) {
  167. printf( "WARNING: search term \"" STRING_FMTA "\" "
  168. "produced no results.\n",
  169. SearchTerm );
  170. } else if ( ldap_next_entry( pLdap,
  171. ldap_first_entry( pLdap,
  172. pMessage ) ) ) {
  173. /* Nonunique search result. Warn the user and
  174. drop out. */
  175. PLDAPMessage p = pMessage;
  176. ULONG i = 1;
  177. printf( "WARNING: search term \"" STRING_FMTA "\" returns "
  178. "multiple results (should be unique).\n"
  179. "\n"
  180. "The results follow:\n",
  181. SearchTerm );
  182. for ( p = ldap_first_entry( pLdap,
  183. pMessage );
  184. p != NULL ;
  185. p = ldap_next_entry( pLdap,
  186. p ),
  187. i++ ) {
  188. pDn = ldap_get_dn( pLdap,
  189. p );
  190. if ( !pDn ) {
  191. printf( "%2ld. <Unknown DN: 0x%x>\n",
  192. i,
  193. pLdap->ld_errno );
  194. } else {
  195. printf( "%2ld. %hs\n",
  196. i,
  197. pDn );
  198. ldap_memfreeA( pDn );
  199. }
  200. }
  201. } else {
  202. ret = TRUE; // go optimistic
  203. if ( pDnOfObject ) {
  204. pDn = ldap_get_dn( pLdap,
  205. pMessage );
  206. if ( pDn ) {
  207. *pDnOfObject = pDn;
  208. } else {
  209. printf( "Failed to get DN from search result: 0x%x\n",
  210. pLdap->ld_errno );
  211. SetLastError( pLdap->ld_errno );
  212. ret = FALSE;
  213. }
  214. }
  215. if ( ret && ppMessage ) {
  216. *ppMessage = pMessage;
  217. pMessage = NULL;
  218. }
  219. }
  220. if ( pMessage ) {
  221. ldap_msgfree( pMessage );
  222. }
  223. } else {
  224. printf( "FAILED: ldap_search_s failed for search term \""
  225. STRING_FMTA "\": 0x%x",
  226. SearchTerm,
  227. dwErr );
  228. SetLastError( dwErr );
  229. }
  230. } else {
  231. printf( "FAILED: default naming context does not include"
  232. " requisite attribute " STRING_FMTA ".\n",
  233. U(NamingContextAttribute) );
  234. SetLastError( ERROR_CLASS_DOES_NOT_EXIST );
  235. }
  236. ldap_msgfree( pResult );
  237. } else {
  238. printf( "FAILED: unable to query default naming context: 0x%x.\n",
  239. dwErr );
  240. SetLastError( dwErr );
  241. }
  242. return ret;
  243. }
  244. #pragma warning(disable:4100) /* unreferenced formal parameter */
  245. BOOL
  246. U(LdapQueryUlongAttribute)( IN OPTIONAL PLDAP pLdap,
  247. IN OPTIONAL LPTSTR DomainName, // ignored
  248. IN LPTSTR SamAccountName,
  249. IN LPTSTR AttributeName,
  250. OUT PULONG pulAttributeContents ) {
  251. BOOL CloseLdap = FALSE;
  252. BOOL ret = FALSE;
  253. LPTSTR Query = NULL;
  254. LPTSTR StringAttr = NULL;
  255. LPTSTR ArrayOfAttributes[] = { AttributeName, NULL };
  256. PLDAPMessage pMessage = NULL;
  257. #if 1
  258. ASSERT( pLdap != NULL ); /* Change from the spec. */
  259. #else
  260. if ( !pLdap ) {
  261. CloseLdap = ConnectAndBindToDefaultDsa( &pLdap );
  262. }
  263. #endif
  264. if ( pLdap ) {
  265. #define EXTRA_STUFF TEXT("(objectClass=*)")
  266. Query = (LPTSTR) malloc( ( lstrlen( SamAccountName ) +
  267. sizeof( "( & (=) )") /* remaining
  268. components */ )
  269. * sizeof( TCHAR ) +
  270. sizeof( U(SamAccountAttribute )) +
  271. sizeof( EXTRA_STUFF ) );
  272. if ( Query ) {
  273. wsprintf( Query,
  274. TEXT("(& ")
  275. EXTRA_STUFF
  276. TEXT("(%s=%s))"),
  277. U(SamAccountAttribute),
  278. SamAccountName );
  279. if ( U(LdapSearchForUniqueDn)( pLdap,
  280. Query,
  281. ArrayOfAttributes,
  282. NULL, // don't need the DN back.
  283. &pMessage )) {
  284. if ( U(LdapFindAttributeInMessage)( pLdap,
  285. pMessage,
  286. AttributeName,
  287. NULL, // don't care about length
  288. &StringAttr ) ) {
  289. *pulAttributeContents = _tcstoul( StringAttr,
  290. NULL, // no endpoint
  291. 0 /* use hex or dec as
  292. appropriate */ );
  293. ret = TRUE;
  294. } // else message already printed
  295. ldap_msgfree( pMessage );
  296. } // else message already printed.
  297. free( Query );
  298. } else {
  299. printf( "FAILED: couldn't allocate memory.\n" );
  300. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  301. }
  302. // close the ldap handle if we opened it.
  303. if ( CloseLdap ) ldap_unbind( pLdap );
  304. } // else printf'd already.
  305. return ret;
  306. }
  307. /*++**************************************************************
  308. NAME: U(QueryAccountControlFlags)
  309. Opens a user and retrieves the user account control flags for it,
  310. using the DS.
  311. MODIFIES: pulControlFlags - returned control flags on the user.
  312. TAKES: pLdap -- optional LDAP connection; if null, we'll
  313. make our own and close it when finished.
  314. DomainName -- domain in which to search for that account.
  315. This is not currently implemented-- for
  316. future use in order to support nonunique
  317. accountnames that differ only by domain name.
  318. SamAccountName -- accountname to query (with $ for computers)
  319. RETURNS: TRUE when the function succeeds.
  320. FALSE otherwise.
  321. LASTERROR: set.
  322. LOGGING: printf on failure.
  323. CALLED BY: anyone
  324. FREE WITH: n/a
  325. **************************************************************--*/
  326. BOOL
  327. U(QueryAccountControlFlags)( IN OPTIONAL PLDAP pLdap,
  328. IN OPTIONAL LPTSTR DomainName, // ignored
  329. IN LPTSTR SamAccountName,
  330. OUT PULONG pulControlFlags ) {
  331. return U(LdapQueryUlongAttribute)( pLdap,
  332. DomainName,
  333. SamAccountName,
  334. U(UserAccountAttribute),
  335. pulControlFlags );
  336. }
  337. /*++**************************************************************
  338. NAME: U(SetAccountControlFlags)
  339. Sets the accountcontrolflags on a specified account.
  340. Pretty much what the function name says.
  341. MODIFIES: account's control flags
  342. TAKES: pLdap -- if specified, DS handle to use
  343. DomainName -- account's domain (mbz)
  344. SamAccountName -- account for which to search
  345. AccountControlFlags -- flags to set on the account
  346. RETURNS: TRUE when the function succeeds.
  347. FALSE otherwise.
  348. LASTERROR: set
  349. LOGGING: printf on failure
  350. CALLED BY: anyone
  351. FREE WITH: n/a
  352. **************************************************************--*/
  353. BOOL
  354. U(SetAccountControlFlags)( IN OPTIONAL PLDAP pLdap,
  355. IN OPTIONAL LPTSTR DomainName,
  356. IN LPTSTR SamAccountName,
  357. IN ULONG AccountControlFlags ) {
  358. BOOL CloseLdap = FALSE;
  359. BOOL ret = FALSE;
  360. LPTSTR Query = NULL;
  361. LPTSTR StringAttr = NULL;
  362. LPTSTR ArrayOfAttributes[] = { U(UserAccountAttribute), NULL };
  363. LPTSTR Dn;
  364. DWORD dwErr;
  365. #if 1
  366. ASSERT( pLdap != NULL ); /* Change from the spec. */
  367. #else
  368. if ( !pLdap ) {
  369. CloseLdap = ConnectAndBindToDefaultDsa( &pLdap );
  370. }
  371. #endif
  372. if ( pLdap ) {
  373. Query = (LPTSTR) malloc( ( lstrlen( SamAccountName ) +
  374. sizeof( "( & (=) )") /* remaining
  375. components */ )
  376. * sizeof( TCHAR ) +
  377. sizeof( U(SamAccountAttribute )) +
  378. sizeof( EXTRA_STUFF ) );
  379. if ( Query ) {
  380. wsprintf( Query,
  381. TEXT("(& ")
  382. EXTRA_STUFF
  383. TEXT("(%s=%s))"),
  384. U(SamAccountAttribute),
  385. SamAccountName );
  386. if ( U(LdapSearchForUniqueDn)( pLdap,
  387. Query,
  388. ArrayOfAttributes,
  389. &Dn,
  390. NULL /* don't need the message
  391. back */ ) ) {
  392. #pragma warning(disable:4204) /* nonstandard extension:
  393. non-constant aggregate initializer
  394. (e.g. assign an array in the initialization
  395. of a structure) */
  396. TCHAR Buffer[ 50 ]; // arbitrary
  397. LPTSTR Strings[] = { Buffer, NULL };
  398. LDAPMod TheMod = {
  399. LDAP_MOD_REPLACE,
  400. U(UserAccountAttribute),
  401. Strings,
  402. };
  403. PLDAPMod rzMods[] = {
  404. &TheMod,
  405. NULL
  406. };
  407. wsprintf( Buffer,
  408. TEXT("%ld"),
  409. AccountControlFlags );
  410. dwErr = ldap_modify_s( pLdap,
  411. Dn,
  412. rzMods );
  413. if ( dwErr == LDAP_SUCCESS ) {
  414. ret = TRUE;
  415. } else {
  416. printf( "Failed to modify " STRING_FMTA
  417. " attribute to %ld (0x%x)"
  418. " on " STRING_FMTA
  419. ": 0x%x\n",
  420. U(UserAccountAttribute),
  421. AccountControlFlags,
  422. AccountControlFlags,
  423. Dn,
  424. dwErr );
  425. SetLastError( dwErr );
  426. }
  427. ldap_memfree( Dn );
  428. } // else message already printed.
  429. free( Query );
  430. } else {
  431. printf( "FAILED: couldn't allocate memory.\n" );
  432. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  433. }
  434. // close the ldap handle if we opened it.
  435. if ( CloseLdap ) ldap_unbind( pLdap );
  436. } // else printf'd already.
  437. return ret;
  438. }