1 2/* 3Copyright 1996, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included 12in all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20OTHER DEALINGS IN THE SOFTWARE. 21 22Except as contained in this notice, the name of The Open Group shall 23not be used in advertising or otherwise to promote the sale, use or 24other dealings in this Software without prior written authorization 25from The Open Group. 26*/ 27 28#include "pmint.h" 29#include "pmdb.h" 30#include "config.h" 31#include <assert.h> 32#include <stdio.h> 33#include <stdlib.h> 34#include <signal.h> 35 36typedef void (*Signal_Handler)(int); 37 38static proxy_service *proxyServiceList = NULL; 39 40static Signal_Handler 41Signal (int sig, Signal_Handler handler) 42{ 43#ifndef X_NOT_POSIX 44 struct sigaction sigact, osigact; 45 sigact.sa_handler = handler; 46 sigemptyset(&sigact.sa_mask); 47 sigact.sa_flags = 0; 48 sigaction(sig, &sigact, &osigact); 49 return osigact.sa_handler; 50#else 51 return signal(sig, handler); 52#endif 53} 54 55proxy_service * 56FindProxyService ( 57 char *serviceName, 58 Bool createIf) 59 60{ 61 proxy_service *service = proxyServiceList; 62 int nameLen = strlen (serviceName); 63 64 while (service) 65 { 66 if (strcmp (service->serviceName, serviceName) == 0) 67 return service; 68 else if (ncasecmp (service->serviceName, serviceName, nameLen) == 0) 69 return service; 70 else 71 service = service->next; 72 } 73 74 if (createIf) { 75 service = malloc (sizeof (proxy_service)); 76 if (!service) 77 return NULL; 78 79 service->serviceName = strdup (serviceName); 80 if (!service->serviceName) 81 { 82 free (service); 83 return NULL; 84 } 85 86 service->proxyCount = 0; 87 service->proxyList = NULL; 88 89 if (proxyServiceList == NULL) 90 { 91 proxyServiceList = service; 92 service->next = NULL; 93 } 94 else 95 { 96 service->next = proxyServiceList; 97 proxyServiceList = service; 98 } 99 } 100 101 return service; 102 103} 104 105 106running_proxy * 107StartNewProxy ( 108 char *serviceName, 109 char *startCommand) 110 111{ 112 proxy_service *service = FindProxyService (serviceName, True); 113 running_proxy *proxy; 114 115 if (!service) 116 return NULL; 117 118 proxy = malloc (sizeof (running_proxy)); 119 if (!proxy) 120 return NULL; 121 122 proxy->active = 0; 123 proxy->pmConn = NULL; 124 proxy->requests = NULL; 125 proxy->servers = NULL; 126 proxy->refused_service = False; 127 128 if (service->proxyList == NULL) 129 { 130 service->proxyList = proxy; 131 proxy->next = NULL; 132 } 133 else 134 { 135 proxy->next = service->proxyList; 136 service->proxyList = proxy; 137 } 138 139 if (system (startCommand) == -1) 140 { 141 printf ("unable to start managed proxy: %s\n", startCommand); 142 service->proxyList = proxy->next; 143 free (proxy); 144 return NULL; 145 } 146 147 if (verbose) { 148 printf ("started managed proxy: %s\n", startCommand); 149 printf ("waiting for StartProxy message\n"); 150 } 151 152 service->proxyCount++; 153 154 return proxy; 155} 156 157/* 158 * ConnectToProxy( pmOpcode, serviceName, proxyAddress ) 159 * 160 * Connects to an unmanaged proxy to forward the GetProxyAddr request 161 * to it to handle. 162 * 163 * Ideally this would be non-blocking but there is no non-blocking 164 * variant of IceOpenConnection/IceProtocolSetup. So we sit here a while. 165 */ 166running_proxy * 167ConnectToProxy ( 168 int pmOpcode, 169 char *serviceName, 170 char *proxyAddress) 171 172{ 173 proxy_service *service = FindProxyService (serviceName, True); 174 running_proxy *proxy; 175 IceConn proxy_iceConn; 176 PMconn *pmConn; 177 178 if (!service) 179 return NULL; 180 181 { 182 int majorVersion, minorVersion; 183 char *vendor, *release; 184 char errorString[256]; 185 186 /* 187 * IceOpenConnection will do more than one write to the proxy. 188 * If the proxy closes the connection before the second write, 189 * the second write may generate a SIGPIPE (empirically this 190 * happens on at least AIX). So, temporarily ignore this signal. 191 */ 192 193 Signal (SIGPIPE, SIG_IGN); 194 195 proxy_iceConn = IceOpenConnection( proxyAddress, NULL, 196 False, pmOpcode, 197 sizeof(errorString), errorString); 198 199 Signal (SIGPIPE, SIG_DFL); 200 201 if (! proxy_iceConn) { 202 printf("unable to open connection to unmanaged proxy \"%s\" at %s\n", 203 serviceName, proxyAddress); 204 return NULL; 205 } 206 207 /* 208 * Mark this fd to be closed upon exec 209 */ 210 SetCloseOnExec (IceConnectionNumber (proxy_iceConn)); 211 212 /* See PMprotocolSetupProc */ 213 pmConn = malloc (sizeof (PMconn)); 214 215 if (pmConn == NULL) { 216 IceCloseConnection (proxy_iceConn); 217 return NULL; 218 } 219 220 if (IceProtocolSetup (proxy_iceConn, pmOpcode, 221 (IcePointer)pmConn, /* client_data */ 222 False, /* must_authenticate */ 223 &majorVersion, &minorVersion, 224 &vendor, &release, 225 sizeof(errorString), errorString) 226 != IceProtocolSetupSuccess) { 227 IceCloseConnection (proxy_iceConn); 228 free (pmConn); 229 printf ("Could not initialize proxy management protocol with\n unmanaged proxy \"%s\" at address %s:\n %s\n", 230 serviceName, proxyAddress, errorString); 231 return NULL; 232 } 233 234 pmConn->iceConn = proxy_iceConn; 235 pmConn->pmOpcode = pmOpcode; 236 pmConn->proto_major_version = majorVersion; 237 pmConn->proto_minor_version = minorVersion; 238 pmConn->vendor = vendor; 239 pmConn->release = release; 240 } 241 242 proxy = malloc (sizeof (running_proxy)); 243 if (!proxy) { 244 IceCloseConnection (proxy_iceConn); 245 free (pmConn); 246 return NULL; 247 } 248 249 proxy->active = 1; 250 proxy->pmConn = pmConn; 251 proxy->requests = NULL; 252 proxy->servers = NULL; 253 proxy->refused_service = False; 254 255 if (service->proxyList == NULL) 256 { 257 service->proxyList = proxy; 258 proxy->next = NULL; 259 } 260 else 261 { 262 proxy->next = service->proxyList; 263 service->proxyList = proxy; 264 } 265 266 if (verbose) 267 printf ("connected to unmanaged proxy: %s at %s\n", 268 serviceName, proxyAddress); 269 270 service->proxyCount++; 271 272 return proxy; 273} 274 275 276Status 277ActivateProxyService ( 278 char *serviceName, 279 PMconn *pmConn) 280 281{ 282 proxy_service *service = FindProxyService (serviceName, False); 283 running_proxy *proxy; 284 285 if (!service) 286 return 0; 287 288 proxy = service->proxyList; 289 290 while (proxy) 291 { 292 if (!proxy->active) 293 { 294 proxy->active = 1; 295 proxy->pmConn = pmConn; 296 return 1; 297 } 298 else 299 proxy = proxy->next; 300 } 301 302 return 0; 303} 304 305 306void 307ProxyGone ( 308 IceConn proxyIceConn, 309 Bool *activeReqs) 310 311{ 312 proxy_service *service = proxyServiceList; 313 314 while (service) 315 { 316 running_proxy *proxy = service->proxyList; 317 running_proxy *prevProxy = NULL; 318 319 while (proxy) 320 { 321 if (proxy->pmConn && (proxy->pmConn->iceConn == proxyIceConn)) 322 { 323 server_list *server; 324 request_list *req; 325 326 if (verbose) 327 printf ("Proxy disconnected on fd %d", 328 IceConnectionNumber(proxyIceConn)); 329 330 server = proxy->servers; 331 if (verbose && server) 332 fputs (" for server", stdout); 333 334 while (server) 335 { 336 server_list *next_server = server->next; 337 if (verbose) { 338 fputc (' ', stdout); 339 fputs (server->serverAddress, stdout); 340 } 341 free (server->serverAddress); 342 free (server); 343 server = next_server; 344 } 345 346 if (verbose) 347 fputc ('\n', stdout); 348 349 if (prevProxy == NULL) 350 service->proxyList = proxy->next; 351 else 352 prevProxy->next = proxy->next; 353 354 service->proxyCount--; 355 356 *activeReqs = proxy->requests != NULL; 357 req = proxy->requests; 358 while (req) 359 { 360 request_list *nextreq = req->next; 361 362 if (req->requestor) { 363 assert (req->requestor->iceConn != NULL); 364 if (verbose) 365 printf ("Reprocessing request from fd %d for service %s at %s\n", 366 IceConnectionNumber (req->requestor->iceConn), 367 req->serviceName, req->serverAddress); 368 369 ForwardRequest( req->requestor, 370 req->serviceName, req->serverAddress, 371 req->hostAddress, req->startOptions, 372 req->authLen, req->authName, 373 req->authData); 374 } 375 free (req->serviceName); 376 free (req->serverAddress); 377 free (req->hostAddress); 378 free (req->startOptions); 379 free (req->listData); /* proxyList */ 380 free (req->authName); 381 free (req->authData); 382 free (req); 383 req = nextreq; 384 } 385 386 free (proxy); 387 return; 388 } 389 else if (proxy->requests) { 390 /* 391 * If it wasn't a proxy that disconnected, so it might 392 * have been a requestor. Search through all the requests 393 * while we're here and look for a match. If found, delete 394 * the request. 395 */ 396 request_list **prev_reqP = &proxy->requests; 397 request_list *req = proxy->requests; 398 while (req) { 399 if (req->requestor->iceConn == proxyIceConn) { 400 if (verbose) { 401 printf ("Requestor disconnected on fd %d while awaiting reply\n for service %s (%s)", 402 IceConnectionNumber(proxyIceConn), 403 req->serviceName, req->serverAddress); 404 if (proxy->pmConn && proxy->pmConn->iceConn) { 405 printf (" from proxy on fd %d\n", 406 IceConnectionNumber(proxy->pmConn->iceConn)); 407 } 408 else 409 fputc ('\n', stdout); 410 } 411 412 *prev_reqP = req->next; 413 414 free (req->serviceName); 415 free (req->serverAddress); 416 free (req->hostAddress); 417 free (req->startOptions); 418 free (req->listData); /* proxyList */ 419 free (req->authName); 420 free (req->authData); 421 free (req); 422 423 /* return; */ /* should but only one req, but... */ 424 } 425 else 426 prev_reqP = &req->next; 427 428 req = *prev_reqP; 429 } 430 } 431 432 prevProxy = proxy; 433 proxy = proxy->next; 434 } 435 436 service = service->next; 437 } 438} 439 440 441/* 442 * GetRuningProxyList returns a list of current proxies for a given 443 * service. The list is ordered, with proxies serving an address that 444 * matches the argument appearing first on the list and all others 445 * appearing at the end. If a proxy ever refused a request for additional 446 * service then it is excluded from the list if it doesn't match the 447 * server address. 448 */ 449running_proxy_list * 450GetRunningProxyList ( 451 char *serviceName, char *serverAddress) 452 453{ 454 proxy_service *service = FindProxyService (serviceName, False); 455 running_proxy **proxyList, *proxy; 456 running_proxy_list *runList; 457 int headIndex, tailIndex; 458 459 if (!service || !service->proxyCount) 460 return NULL; 461 462 runList = malloc (sizeof (running_proxy_list) + 463 service->proxyCount * sizeof (running_proxy *)); 464 465 if (!runList) 466 return NULL; 467 468 runList->count = 0; 469 runList->current = 0; 470 runList->list = proxyList = (running_proxy **) (runList + 1); 471 472 proxy = service->proxyList; 473 headIndex = 0; 474 tailIndex = service->proxyCount - 1; 475 476 while (proxy) 477 { 478 server_list *server = proxy->servers; 479 int match = 0; 480 481 while (server) 482 { 483 if (strcmp (server->serverAddress, serverAddress) == 0) 484 { 485 match = 1; 486 break; 487 } 488 489 server = server->next; 490 } 491 492 if (match) { 493 proxyList[headIndex++] = proxy; 494 runList->count++; 495 } 496 else if (! proxy->refused_service) { 497 proxyList[tailIndex--] = proxy; 498 runList->count++; 499 } 500 501 proxy = proxy->next; 502 } 503 504 if (!runList->count) { 505 free ((char*)runList); 506 return NULL; 507 } 508 509 /* if we didn't fill the list due to skipping proxies that had previously 510 * refused to service a new address, then remove the gaps in the list 511 * between the matched and unmatched server names 512 */ 513 if (runList->count < service->proxyCount) { 514 while (tailIndex < service->proxyCount - 1) 515 proxyList[headIndex++] = proxyList[++tailIndex]; 516 } 517 518 return runList; 519} 520 521 522void 523FreeProxyList (running_proxy_list *list) 524 525{ 526 free (list); 527} 528 529 530Status 531PushRequestorQueue ( 532 running_proxy *proxy, 533 PMconn *requestor, 534 running_proxy_list *runList, 535 char *serviceName, 536 char *serverAddress, 537 char *hostAddress, 538 char *startOptions, 539 int authLen, 540 char *authName, 541 char *authData) 542 543{ 544 request_list *newreq = malloc (sizeof (request_list)); 545 546 if (!newreq) 547 return 0; 548 549 newreq->serviceName = strdup (serviceName); 550 newreq->serverAddress = strdup (serverAddress); 551 newreq->hostAddress = strdup (hostAddress); 552 newreq->startOptions = strdup (startOptions); 553 if (authLen > 0) 554 { 555 newreq->authName = strdup (authName); 556 newreq->authData = malloc (authLen); 557 } 558 else 559 newreq->authName = newreq->authData = NULL; 560 561 if (!newreq->serviceName || 562 !newreq->serverAddress || 563 !newreq->hostAddress || 564 !newreq->startOptions || 565 (authLen > 0 && (!newreq->authName || !newreq->authData))) 566 { 567 free (newreq->serviceName); 568 free (newreq->serverAddress); 569 free (newreq->hostAddress); 570 free (newreq->startOptions); 571 free (newreq->authName); 572 free (newreq->authData); 573 free (newreq); 574 return 0; 575 } 576 577 if (authLen > 0) 578 { 579 memcpy (newreq->authData, authData, authLen); 580 } 581 582 newreq->requestor = requestor; 583 newreq->listData = (char *) runList; 584 newreq->authLen = authLen; 585 newreq->next = NULL; 586 587 if (proxy->requests == NULL) 588 proxy->requests = newreq; 589 else 590 { 591 request_list *p = proxy->requests; 592 593 while (p->next) 594 p = p->next; 595 596 p->next = newreq; 597 } 598 599 return 1; 600} 601 602 603Status 604PeekRequestorQueue ( 605 PMconn *pmConn, 606 PMconn **requestor, 607 running_proxy_list **runList, 608 char **serviceName, 609 char **serverAddress, 610 char **hostAddress, 611 char **startOptions, 612 int *authLen, 613 char **authName, 614 char **authData) 615{ 616 running_proxy *proxy = ProxyForPMconn (pmConn); 617 618 if (proxy && proxy->requests) { 619 if (requestor) 620 *requestor = proxy->requests->requestor; 621 if (runList) 622 *runList = (running_proxy_list *) 623 proxy->requests->listData; 624 if (serviceName) 625 *serviceName = proxy->requests->serviceName; 626 if (serverAddress) 627 *serverAddress = proxy->requests->serverAddress; 628 if (hostAddress) 629 *hostAddress = proxy->requests->hostAddress; 630 if (startOptions) 631 *startOptions = proxy->requests->startOptions; 632 if (authLen) 633 *authLen = proxy->requests->authLen; 634 if (authName) 635 *authName = proxy->requests->authName; 636 if (authData) 637 *authData = proxy->requests->authData; 638 639 return 1; 640 } 641 else 642 return 0; 643} 644 645 646running_proxy * 647ProxyForPMconn ( 648 PMconn *pmConn) 649{ 650 proxy_service *service = proxyServiceList; 651 652 while (service) 653 { 654 running_proxy *proxy = service->proxyList; 655 656 while (proxy) 657 { 658 if (proxy->pmConn == pmConn) 659 return proxy; 660 else 661 proxy = proxy->next; 662 } 663 664 service = service->next; 665 } 666 667 return NULL; 668} 669 670 671PMconn* 672PopRequestorQueue ( 673 PMconn *pmConn, 674 Bool addServer, /* record this server address */ 675 Bool freeProxyList) 676{ 677 running_proxy *proxy = ProxyForPMconn (pmConn); 678 679 if (proxy) { 680 PMconn *requestor; 681 server_list *server; 682 request_list *nextreq; 683 Bool newServer = False; 684 685 if (addServer) { 686 newServer = True; 687 server = proxy->servers; 688 689 while (server) 690 { 691 if (strcmp (server->serverAddress, 692 proxy->requests->serverAddress) == 0) 693 { 694 newServer = False; 695 break; 696 } 697 698 server = server->next; 699 } 700 701 if (newServer) 702 { 703 server = malloc (sizeof (server_list)); 704 server->serverAddress = proxy->requests->serverAddress; 705 server->next = proxy->servers; 706 proxy->servers = server; 707 } 708 } 709 710 if (!newServer) 711 free (proxy->requests->serverAddress); 712 713 free (proxy->requests->serviceName); 714 free (proxy->requests->hostAddress); 715 free (proxy->requests->startOptions); 716 free (proxy->requests->listData); /* proxyList */ 717 free (proxy->requests->authName); 718 free (proxy->requests->authData); 719 720 requestor = proxy->requests->requestor; 721 722 nextreq = proxy->requests->next; 723 free (proxy->requests); 724 proxy->requests = nextreq; 725 726 return requestor; 727 } 728 729 return NULL; 730} 731