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.

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