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.

656 lines
16 KiB

  1. /*++
  2. Copyright (C) 1999 Microsoft Corporation
  3. Module Name:
  4. merge.c
  5. Abstract:
  6. this module merges the configurations provided via a pair of
  7. MM datastructures..
  8. --*/
  9. #include <precomp.h>
  10. #include "server\uniqid.h"
  11. BOOL
  12. ClassesConflict(
  13. IN PM_CLASSDEF Class1,
  14. IN PM_CLASSDEF Class2
  15. )
  16. {
  17. LPWSTR Comment1, Comment2;
  18. if( Class1->IsVendor != Class2->IsVendor ) return TRUE;
  19. if( wcscmp(Class1->Name, Class2->Name) ) return TRUE;
  20. Comment1 = Class1->Comment; Comment2 = Class2->Comment;
  21. if( NULL == Comment1 ) Comment1 = L"";
  22. if( NULL == Comment2 ) Comment2 = L"";
  23. if( wcscmp(Comment1, Comment2) ) return TRUE;
  24. if( Class1->nBytes != Class2->nBytes ) return TRUE;
  25. if( memcmp(Class1->ActualBytes, Class2->ActualBytes,
  26. Class1->nBytes ) ) {
  27. return TRUE;
  28. }
  29. return FALSE;
  30. }
  31. DWORD
  32. AddClassesCallback(
  33. IN OUT PMM_ITERATE_CTXT Ctxt
  34. )
  35. {
  36. DWORD Error;
  37. PM_SERVER Server = Ctxt->ExtraCtxt;
  38. PM_CLASSDEF ClassDef;
  39. Error = MemServerGetClassDef(
  40. Server, 0,
  41. Ctxt->ClassDef->Name,
  42. Ctxt->ClassDef->nBytes,
  43. Ctxt->ClassDef->ActualBytes,
  44. &ClassDef );
  45. if( NO_ERROR == Error ) {
  46. //
  47. // Check if the classdef matches
  48. //
  49. if( ClassesConflict( ClassDef, Ctxt->ClassDef ) ) {
  50. Tr("Class %ws conflicts with class %ws\n",
  51. ClassDef->Name, Ctxt->ClassDef->Name );
  52. DhcpEximErrorClassConflicts(
  53. ClassDef->Name, Ctxt->ClassDef->Name );
  54. return ERROR_CAN_NOT_COMPLETE;
  55. }
  56. return NO_ERROR;
  57. }
  58. return MemServerAddClassDef(
  59. Server, MemNewClassId(),
  60. Ctxt->ClassDef->IsVendor,
  61. Ctxt->ClassDef->Name,
  62. Ctxt->ClassDef->Comment,
  63. Ctxt->ClassDef->nBytes,
  64. Ctxt->ClassDef->ActualBytes,
  65. INVALID_UNIQ_ID );
  66. }
  67. DWORD
  68. GetClassIdByName(
  69. IN PM_SERVER Server,
  70. IN LPWSTR Name
  71. )
  72. {
  73. PM_CLASSDEF ClassDef;
  74. DWORD Error;
  75. Error = MemServerGetClassDef(
  76. Server, 0, Name, 0, NULL, &ClassDef );
  77. if( NO_ERROR != Error ) return 0;
  78. return ClassDef->ClassId;
  79. }
  80. BOOL
  81. OptDefsConflict(
  82. IN PM_OPTDEF OptDef1,
  83. IN PM_OPTDEF OptDef2
  84. )
  85. {
  86. LPWSTR Comment1, Comment2;
  87. if( OptDef1->OptId != OptDef2->OptId ) return TRUE;
  88. if( wcscmp(OptDef1->OptName, OptDef2->OptName ) ) return TRUE;
  89. Comment1 = OptDef1->OptComment; Comment2 = OptDef2->OptComment;
  90. if( NULL == Comment1 ) Comment1 = L"";
  91. if( NULL == Comment2 ) Comment2 = L"";
  92. if( wcscmp(Comment1, Comment2) ) return TRUE;
  93. if( OptDef1->OptValLen != OptDef2->OptValLen ) return TRUE;
  94. if( memcmp(OptDef1->OptVal, OptDef2->OptVal,
  95. OptDef1->OptValLen)) return TRUE;
  96. return FALSE;
  97. }
  98. DWORD
  99. AddOptdefsCallback(
  100. IN OUT PMM_ITERATE_CTXT Ctxt
  101. )
  102. {
  103. DWORD Error, ClassId, VendorId;
  104. PM_SERVER Server = Ctxt->ExtraCtxt;
  105. PM_OPTDEF OptDef;
  106. //
  107. // Get the user and vendor class id's
  108. //
  109. if( Ctxt->UserClass == NULL ) ClassId = 0;
  110. else {
  111. ClassId = GetClassIdByName( Server, Ctxt->UserClass->Name );
  112. if( 0 == ClassId ) {
  113. Tr("Class %ws doesnt exist\n", Ctxt->UserClass->Name );
  114. return ERROR_DHCP_CLASS_NOT_FOUND;
  115. }
  116. }
  117. if( Ctxt->VendorClass == NULL ) VendorId = 0;
  118. else {
  119. VendorId = GetClassIdByName( Server, Ctxt->VendorClass->Name );
  120. if( 0 == VendorId ) {
  121. Tr("Class %ws doesnt exist\n", Ctxt->VendorClass->Name );
  122. return ERROR_DHCP_CLASS_NOT_FOUND;
  123. }
  124. }
  125. //
  126. // Next check if the specified optdef exists already
  127. //
  128. Error = MemServerGetOptDef(
  129. Server, ClassId, VendorId, Ctxt->OptDef->OptId,
  130. Ctxt->OptDef->OptName, &OptDef );
  131. if( NO_ERROR == Error ) {
  132. if( OptDefsConflict( OptDef, Ctxt->OptDef ) ) {
  133. Tr("Optdef %ws conflicts with %ws\n",
  134. OptDef->OptName, Ctxt->OptDef->OptName );
  135. //
  136. // attempt to overwrite existing optdef
  137. //
  138. //DhcpEximErrorOptdefConflicts(
  139. // OptDef->OptName, Ctxt->OptDef->OptName );
  140. // return ERROR_CAN_NOT_COMPLETE;
  141. return NO_ERROR;
  142. }
  143. return NO_ERROR;
  144. }
  145. //
  146. // Now add the optdef
  147. //
  148. return MemServerAddOptDef(
  149. Server, ClassId, VendorId, Ctxt->OptDef->OptId,
  150. Ctxt->OptDef->OptName, Ctxt->OptDef->OptComment,
  151. Ctxt->OptDef->Type, Ctxt->OptDef->OptVal,
  152. Ctxt->OptDef->OptValLen, INVALID_UNIQ_ID );
  153. }
  154. DWORD static
  155. SetOptionValue(
  156. IN PM_SERVER Server,
  157. IN PM_SUBNET Subnet OPTIONAL,
  158. IN PM_RESERVATION Res OPTIONAL,
  159. IN ULONG OptId,
  160. IN LPWSTR UserClass,
  161. IN LPWSTR VendorClass,
  162. IN LPBYTE Val,
  163. IN ULONG Len
  164. )
  165. {
  166. DWORD Error, ClassId, VendorId;
  167. PM_OPTCLASS OptClass;
  168. PM_OPTION Option, DeletedOption;
  169. //
  170. // Get the user and vendor class id's
  171. //
  172. if( UserClass == NULL ) ClassId = 0;
  173. else {
  174. ClassId = GetClassIdByName( Server, UserClass );
  175. if( 0 == ClassId ) {
  176. Tr("Class %ws doesnt exist\n", UserClass );
  177. return ERROR_DHCP_CLASS_NOT_FOUND;
  178. }
  179. }
  180. if( VendorClass == NULL ) VendorId = 0;
  181. else {
  182. VendorId = GetClassIdByName( Server, VendorClass );
  183. if( 0 == VendorId ) {
  184. Tr("Class %ws doesnt exist\n", VendorClass );
  185. return ERROR_DHCP_CLASS_NOT_FOUND;
  186. }
  187. }
  188. Error = MemOptInit( &Option, OptId, Len, Val );
  189. if( ERROR_SUCCESS != Error ) return Error;
  190. DeletedOption = NULL;
  191. if( NULL != Res ) {
  192. OptClass = &Res->Options;
  193. } else if( NULL != Subnet ) {
  194. OptClass = &Subnet->Options;
  195. } else {
  196. OptClass = &Server->Options;
  197. }
  198. Error = MemOptClassAddOption(
  199. OptClass, Option, ClassId, VendorId, &DeletedOption, INVALID_UNIQ_ID );
  200. if( ERROR_SUCCESS == Error && DeletedOption ) {
  201. MemFree(DeletedOption); // if we did replace, free the old option
  202. }
  203. if( ERROR_SUCCESS != Error ) { // something went wrong, clean up
  204. ULONG LocalError = MemOptCleanup(Option);
  205. ASSERT(ERROR_SUCCESS == LocalError);
  206. }
  207. return Error;
  208. }
  209. DWORD
  210. GetOptionValue(
  211. IN PM_SERVER Server,
  212. IN PM_SUBNET Subnet OPTIONAL,
  213. IN PM_RESERVATION Res OPTIONAL,
  214. IN ULONG OptId,
  215. IN LPWSTR UserClass,
  216. IN LPWSTR VendorClass,
  217. OUT LPBYTE *Val,
  218. OUT ULONG *Len
  219. )
  220. {
  221. DWORD Error, ClassId, VendorId;
  222. PM_OPTCLASS OptClass;
  223. PM_OPTLIST OptList;
  224. PM_OPTION Opt;
  225. //
  226. // Get the user and vendor class id's
  227. //
  228. if( UserClass == NULL ) ClassId = 0;
  229. else {
  230. ClassId = GetClassIdByName( Server, UserClass );
  231. if( 0 == ClassId ) {
  232. Tr("Class %ws doesnt exist\n", UserClass );
  233. return ERROR_DHCP_CLASS_NOT_FOUND;
  234. }
  235. }
  236. if( VendorClass == NULL ) VendorId = 0;
  237. else {
  238. VendorId = GetClassIdByName( Server, VendorClass );
  239. if( 0 == VendorId ) {
  240. Tr("Class %ws doesnt exist\n", VendorClass );
  241. return ERROR_DHCP_CLASS_NOT_FOUND;
  242. }
  243. }
  244. //
  245. // get the options
  246. //
  247. if( NULL != Res ) {
  248. OptClass = &Res->Options;
  249. } else if( NULL != Subnet ) {
  250. OptClass = &Subnet->Options;
  251. } else {
  252. OptClass = &Server->Options;
  253. }
  254. //
  255. // Check if option exists
  256. //
  257. Error = MemOptClassFindClassOptions(
  258. OptClass, ClassId, VendorId, &OptList );
  259. if( NO_ERROR == Error ) {
  260. Error = MemOptListFindOption( OptList, OptId, &Opt );
  261. if( NO_ERROR == Error ) {
  262. *Val = Opt->Val;
  263. *Len = Opt->Len;
  264. return NO_ERROR;
  265. }
  266. }
  267. return ERROR_DHCP_OPTION_NOT_PRESENT;
  268. }
  269. DWORD
  270. AddOptionsCallbackEx(
  271. IN OUT PMM_ITERATE_CTXT Ctxt,
  272. IN PM_SUBNET Subnet OPTIONAL,
  273. IN PM_RESERVATION Res OPTIONAL
  274. )
  275. {
  276. DWORD Error, Len;
  277. PM_SERVER Server = Ctxt->ExtraCtxt;
  278. LPBYTE Val;
  279. WCHAR Buff1[10], Buf2[30];
  280. LPWSTR ResAddress = NULL, OptId, SubnetName = NULL;
  281. //
  282. // Check for option conflict
  283. //
  284. wsprintf(Buff1, L"%ld", Ctxt->Option->OptId );
  285. OptId = (LPWSTR)Buff1;
  286. if( Res ) {
  287. Subnet = (PM_SUBNET) Res->SubnetPtr;
  288. IpAddressToStringW( Res->Address, Buf2);
  289. ResAddress = (LPWSTR)Buf2;
  290. }
  291. if( Subnet ) {
  292. Server = (PM_SERVER) Subnet->ServerPtr;
  293. SubnetName = Subnet->Name;
  294. }
  295. Error = GetOptionValue(
  296. Server, Subnet, Res, Ctxt->Option->OptId,
  297. Ctxt->UserClass ? Ctxt->UserClass->Name : NULL,
  298. Ctxt->VendorClass ? Ctxt->VendorClass->Name : NULL,
  299. &Val , &Len );
  300. if( NO_ERROR == Error ) {
  301. if( Len != Ctxt->Option->Len ||
  302. memcmp( Ctxt->Option->Val, Val, Len ) ) {
  303. Tr("Options conflict for opt id %ld\n", Ctxt->Option->OptId );
  304. DhcpEximErrorOptionConflits(
  305. SubnetName, ResAddress, OptId,
  306. Ctxt->UserClass ? Ctxt->UserClass->Name : NULL,
  307. Ctxt->VendorClass ? Ctxt->VendorClass->Name : NULL
  308. );
  309. return ERROR_CAN_NOT_COMPLETE;
  310. }
  311. return NO_ERROR;
  312. } else if( ERROR_DHCP_OPTION_NOT_PRESENT != Error ) {
  313. Tr("GetOptionValue: %ld\n", Error );
  314. return Error;
  315. }
  316. //
  317. // Create option
  318. //
  319. return SetOptionValue(
  320. Server, Subnet, Res, Ctxt->Option->OptId,
  321. Ctxt->UserClass ? Ctxt->UserClass->Name : NULL,
  322. Ctxt->VendorClass ? Ctxt->VendorClass->Name : NULL,
  323. Ctxt->Option->Val, Ctxt->Option->Len );
  324. }
  325. DWORD
  326. AddOptionsCallback(
  327. IN OUT PMM_ITERATE_CTXT Ctxt
  328. )
  329. {
  330. return AddOptionsCallbackEx(
  331. Ctxt, NULL, NULL );
  332. }
  333. DWORD
  334. AddSubnetOptionsCallback(
  335. IN OUT PMM_ITERATE_CTXT Ctxt
  336. )
  337. {
  338. return AddOptionsCallbackEx(
  339. Ctxt, (PM_SUBNET)Ctxt->ExtraCtxt, NULL );
  340. }
  341. DWORD
  342. AddReservationOptionsCallback(
  343. IN PMM_ITERATE_CTXT Ctxt
  344. )
  345. {
  346. return AddOptionsCallbackEx(
  347. Ctxt, NULL, (PM_RESERVATION)Ctxt->ExtraCtxt );
  348. }
  349. DWORD
  350. AddReservationsCallback(
  351. IN OUT PMM_ITERATE_CTXT Ctxt
  352. )
  353. {
  354. DWORD Error;
  355. PM_SERVER Server;
  356. PM_SUBNET Subnet;
  357. PM_RESERVATION Res;
  358. //
  359. // Create the reservations
  360. //
  361. Server = ((PM_SUBNET)Ctxt->ExtraCtxt)->ServerPtr;
  362. Error = MemServerGetAddressInfo(
  363. Server, Ctxt->Res->Address, &Subnet, NULL, NULL, NULL );
  364. ASSERT( NO_ERROR == Error );
  365. Error = MemReserveAdd(
  366. &Subnet->Reservations, Ctxt->Res->Address,
  367. Ctxt->Res->Flags, Ctxt->Res->ClientUID, Ctxt->Res->nBytes,
  368. INVALID_UNIQ_ID );
  369. if( NO_ERROR != Error ) return Error;
  370. Error = MemServerGetAddressInfo(
  371. Server, Ctxt->Res->Address, NULL, NULL, NULL, &Res );
  372. ASSERT( NO_ERROR == Error );
  373. //
  374. // Now add subnet options
  375. //
  376. Res->SubnetPtr = Subnet;
  377. Error = IterateReservationOptions(
  378. Ctxt->Server, Ctxt->Res, Res, AddReservationOptionsCallback );
  379. if( NO_ERROR != Error ) {
  380. Tr("AddReservationOptionsCallback: %ld\n", Error );
  381. return Error;
  382. }
  383. return NO_ERROR;
  384. }
  385. DWORD
  386. AddSubnetsCallback(
  387. IN OUT PMM_ITERATE_CTXT Ctxt
  388. )
  389. {
  390. DWORD Error, SScopeId;
  391. PM_SUBNET Subnet;
  392. PM_SSCOPE SScope;
  393. PM_SERVER Server = Ctxt->ExtraCtxt;
  394. WCHAR SubnetIpAdress[30];
  395. IpAddressToStringW(Ctxt->Scope->Address, (LPWSTR)SubnetIpAdress);
  396. //
  397. // First locate the superscope and create it if needed
  398. //
  399. SScopeId = 0;
  400. if( NULL != Ctxt->SScope ) {
  401. Error = MemServerFindSScope(
  402. Server, 0, Ctxt->SScope->Name, &SScope );
  403. if( ERROR_FILE_NOT_FOUND == Error ) {
  404. Error = MemSScopeInit(
  405. &SScope, 0, Ctxt->SScope->Name );
  406. if( NO_ERROR != Error ) return Error;
  407. Error = MemServerAddSScope(Server,SScope);
  408. ASSERT( NO_ERROR == Error );
  409. if( NO_ERROR != Error ) return Error;
  410. } else if( NO_ERROR != Error ) {
  411. Tr("FindSScope(%ws):%ld\n", Ctxt->SScope->Name, Error);
  412. return Error;
  413. }
  414. SScopeId = SScope->SScopeId;
  415. }
  416. //
  417. // Create the subnet..
  418. //
  419. Error = MemSubnetInit(
  420. &Subnet,
  421. Ctxt->Scope->Address,
  422. Ctxt->Scope->Mask,
  423. Ctxt->Scope->State,
  424. SScopeId,
  425. Ctxt->Scope->Name,
  426. Ctxt->Scope->Description
  427. );
  428. if( ERROR_SUCCESS != Error ) return Error;
  429. //
  430. // Add the subnet..
  431. //
  432. Error = MemServerAddSubnet( Server, Subnet, INVALID_UNIQ_ID );
  433. if( NO_ERROR != Error ) {
  434. MemSubnetCleanup( Subnet );
  435. if( ERROR_OBJECT_ALREADY_EXISTS == Error ) {
  436. //
  437. // Subnet already exists -- this is a conflict
  438. //
  439. DhcpEximErrorSubnetAlreadyPresent(
  440. (LPWSTR)SubnetIpAdress, Ctxt->Scope->Name );
  441. Error = ERROR_CAN_NOT_COMPLETE;
  442. }
  443. Tr("AddSubnet %ws failed: %ld\n", Ctxt->Scope->Name, Error );
  444. return Error;
  445. }
  446. //
  447. // Before adding the options, first copy the ranges and
  448. // exclusions..
  449. //
  450. Subnet->Ranges = Ctxt->Scope->Ranges;
  451. Subnet->Exclusions = Ctxt->Scope->Exclusions;
  452. MemArrayInit( &Ctxt->Scope->Ranges );
  453. MemArrayInit( &Ctxt->Scope->Exclusions );
  454. //
  455. // now add the other stuff
  456. //
  457. Error = IterateScopeOptions(
  458. Ctxt->Scope, Subnet, AddSubnetOptionsCallback );
  459. if( NO_ERROR != Error ) {
  460. Tr("AddSubnetOptionsCallback: %ld\n", Error );
  461. return Error;
  462. }
  463. Error = IterateScopeReservations(
  464. Ctxt->Scope, Subnet, AddReservationsCallback );
  465. if( NO_ERROR != Error ) {
  466. Tr("AddReservationsCallback: %ld\n", Error );
  467. return Error;
  468. }
  469. return NO_ERROR;
  470. }
  471. DWORD
  472. MergeConfigurations(
  473. IN OUT PM_SERVER DestServer,
  474. IN OUT PM_SERVER Server
  475. )
  476. /*++
  477. Routine Description:
  478. This routine merges the configuration provided in "Server"
  479. onto the configuration already present in "DestServer".
  480. Rule 1. The subnets that exist in DestServer should not
  481. conflict with the subnets that are to be merged from Server.
  482. Rule 2. The classes that exist in DestServer should not
  483. conflict the classes that are to be added from Server.
  484. Rule 3. The optdefs that exist in DestServer should not
  485. conflict the optdefs that are to be added from Server.
  486. Rule 4. The options that exist in DestServer shoult not
  487. conflict with the options that are to be added from Server.
  488. For all but the first rule, exact duplicates are not
  489. considered conflicts.
  490. Note: When subnet ranges and exclusions are merged in, they
  491. are also removed from "Server"...
  492. --*/
  493. {
  494. DWORD Error;
  495. Tr("Entering MergeConfigurations\n");
  496. //
  497. // Add the class defs first
  498. //
  499. Error = IterateClasses(
  500. Server, DestServer, AddClassesCallback );
  501. if( NO_ERROR != Error ) {
  502. Tr("AddClassesCallback: %ld\n", Error );
  503. return Error;
  504. }
  505. //
  506. // Add the optdefs
  507. //
  508. Error = IterateOptDefs(
  509. Server, DestServer, AddOptdefsCallback );
  510. if( NO_ERROR != Error ) {
  511. Tr("AddOptdefsCallback: %ld\n", Error );
  512. return Error;
  513. }
  514. //
  515. // Add the global options..
  516. //
  517. Error = IterateServerOptions(
  518. Server, DestServer, AddOptionsCallback );
  519. if( NO_ERROR != Error ) {
  520. Tr("AddOptionsCallback: %ld\n", Error );
  521. return Error;
  522. }
  523. //
  524. // Add the subnets
  525. //
  526. Error = IterateScopes(
  527. Server, DestServer, AddSubnetsCallback );
  528. if( NO_ERROR != Error ) {
  529. Tr("IterateScopes: %ld\n", Error );
  530. return Error;
  531. }
  532. //
  533. // done..
  534. //
  535. return NO_ERROR;
  536. }