home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume26 / ns2tab / part02 / main.c < prev   
Encoding:
C/C++ Source or Header  |  1993-04-04  |  16.8 KB  |  699 lines

  1. #ifndef lint
  2. char copyright[] =
  3. "@(#) Portions Copyright (c) 1985,1989\n\
  4. Regents of the University of California.\n\
  5.  All rights reserved.\n";
  6. #endif /* not lint */
  7.  
  8. /*
  9.  *******************************************************************************
  10.  *  
  11.  *   main.c --
  12.  *  
  13.  *    Main routine and some action routines for the name server
  14.  *    lookup program.
  15.  *
  16.  *    Andrew Cherenson
  17.  *    U.C. Berkeley Computer Science Div.
  18.  *    CS298-26, Fall 1985
  19.  *  
  20.  *******************************************************************************
  21.  */
  22.  
  23. #include <sys/types.h>
  24. #include <sys/param.h>
  25. #include <netdb.h>
  26. #include <sys/socket.h>
  27. #include <netinet/in.h>
  28. #include <stdio.h>
  29. #include <arpa/nameser.h>
  30. #include <arpa/inet.h>
  31. #include <resolv.h>
  32. #include <signal.h>
  33. #include <setjmp.h>
  34. #include <ctype.h>
  35. #include <stdlib.h>
  36. #include <string.h>
  37. #include "res.h"
  38.  
  39. #ifdef ultrix
  40. #define nsaddr_list(i)  ns_list[(i)].addr
  41. #else
  42. #define nsaddr_list(i)  nsaddr_list[(i)]
  43. #endif
  44. /*
  45.  *  Default Internet address of the current host.
  46.  */
  47.  
  48. #if BSD < 43
  49. #define LOCALHOST "127.0.0.1"
  50. #endif
  51.  
  52.  
  53. /*
  54.  * Name of a top-level name server. Can be changed with 
  55.  * the "set root" command.
  56.  */
  57.  
  58. #ifndef ROOT_SERVER
  59. #define        ROOT_SERVER "ns.nic.ddn.mil."
  60. #endif
  61. char        rootServerName[NAME_LEN] = ROOT_SERVER;
  62.  
  63.  
  64. /*
  65.  *  Import the state information from the resolver library.
  66.  */
  67.  
  68. extern struct state _res;
  69.  
  70.  
  71. /*
  72.  *  Info about the most recently queried host.
  73.  */
  74.  
  75. HostInfo    curHostInfo;
  76.  
  77.  
  78. /*
  79.  *  Info about the default name server.
  80.  */
  81.  
  82. HostInfo    *defaultPtr = NULL;
  83. char        defaultServer[NAME_LEN];
  84. struct in_addr    defaultAddr;
  85.  
  86. int hasprinted = 0;
  87. int hasloaded = 0;
  88. int explicitserver = 0;
  89. char *vdomain;
  90. /*
  91.  *  Initial name server query type is Address.
  92.  */
  93.  
  94. int        queryType = T_ANY;
  95. int        queryClass = C_IN;
  96.  
  97. /*
  98.  * Stuff for Interrupt (control-C) signal handler.
  99.  */
  100.  
  101. FILE        *filePtr = stdout;
  102.  
  103. static void CvtAddrToPtr();
  104.  
  105.  
  106. /*
  107.  *******************************************************************************
  108.  *
  109.  *  main --
  110.  *
  111.  *    Initializes the resolver library and determines the address
  112.  *    of the initial name server.
  113.  *
  114.  *******************************************************************************
  115.  */
  116.  
  117. main(argc, argv)
  118.     int        argc;
  119.     char    **argv;
  120. {
  121.     char    *wantedHost = NULL;
  122.     int        result;
  123.     int        i;
  124.     extern int    h_errno;
  125.  
  126.     /*
  127.      *  Initialize the resolver library routines.
  128.      */
  129.  
  130.     if (res_init() == -1) {
  131.     fprintf(stderr,"*** Can't initialize resolver.\n");
  132.     exit(1);
  133.     }
  134.  
  135.     /*
  136.      *  Allocate space for the default server's host info and
  137.      *  find the server's address and name. If the resolver library
  138.      *  already has some addresses for a potential name server,
  139.      *  then use them. Otherwise, see if the current host has a server.
  140.      *  Command line arguments may override the choice of initial server. 
  141.      */
  142.  
  143.     defaultPtr = (HostInfo *) calloc(1, sizeof(HostInfo));
  144.  
  145.     ++argv; --argc;        /* skip prog name */
  146.  
  147.  
  148.     if (_res.nscount == 0) {
  149.     LocalServer(defaultPtr);
  150.     } else {
  151.     for (i = 0; i < _res.nscount; i++) {
  152.         if (_res.nsaddr_list(i).sin_addr.s_addr == INADDR_ANY) {
  153.             LocalServer(defaultPtr);
  154.         break;
  155.         } else {
  156.         result = GetHostInfoByAddr(&(_res.nsaddr_list(i).sin_addr), 
  157.                     &(_res.nsaddr_list(i).sin_addr), 
  158.                     defaultPtr);
  159.         if (result != SUCCESS) {
  160.             fprintf(stderr,
  161.             "*** Can't find server name for address %s: %s\n", 
  162.                inet_ntoa(_res.nsaddr_list(i).sin_addr), 
  163.                DecodeError(result));
  164.         } else {
  165.             defaultAddr = _res.nsaddr_list(i).sin_addr;
  166.             break;
  167.         }
  168.         }
  169.     }
  170.  
  171.     /*
  172.      *  If we have exhausted the list, tell the user about the
  173.      *  command line argument to specify an address.
  174.      */
  175.  
  176.     if (i == _res.nscount) {
  177.         fprintf(stderr, "*** Default servers are not available\n");
  178.         exit(1);
  179.     }
  180.  
  181.     }
  182.     strcpy(defaultServer, defaultPtr->name);
  183.  
  184.  
  185. #ifdef DEBUG
  186. #ifdef DEBUG2
  187.     _res.options |= RES_DEBUG2;
  188. #endif
  189.     _res.options |= RES_DEBUG;
  190.     _res.retry    = 2;
  191. #endif
  192.     
  193.     (void)InitTables();
  194.     vdomain = _res.defdname;
  195.  
  196.     while (argc)
  197.     {
  198.     (void) DoCommand (*argv);
  199.     ++argv; --argc;
  200.     }
  201.     if(!hasprinted)
  202.     DoCommand("print");
  203.  
  204.     exit(0);
  205. }
  206.  
  207.  
  208. LocalServer(defaultPtr)
  209.     HostInfo *defaultPtr;
  210. {
  211.     char    hostName[NAME_LEN];
  212. #if BSD < 43
  213.     int        result;
  214. #endif
  215.  
  216.     gethostname(hostName, sizeof(hostName));
  217.  
  218. #if BSD < 43
  219.     defaultAddr.s_addr = inet_addr(LOCALHOST);
  220.     result = GetHostInfoByName(&defaultAddr, C_IN, T_A, 
  221.         hostName, defaultPtr, 1);
  222.     if (result != SUCCESS) {
  223.     fprintf(stderr,
  224.     "*** Can't find initialize address for server %s: %s\n",
  225.             defaultServer, DecodeError(result));
  226.     exit(1);
  227.     }
  228. #else
  229.     defaultAddr.s_addr = htonl(INADDR_ANY);
  230.     (void) GetHostInfoByName(&defaultAddr, C_IN, T_A, "0.0.0.0", defaultPtr, 1);
  231.     free(defaultPtr->name);
  232.     defaultPtr->name = calloc(1, sizeof(hostName)+1);
  233.     strcpy(defaultPtr->name, hostName);
  234. #endif
  235. }
  236.  
  237.  
  238. /*
  239.  *******************************************************************************
  240.  *
  241.  *  Usage --
  242.  *
  243.  *    Lists the proper methods to run the program and exits.
  244.  *
  245.  *******************************************************************************
  246.  */
  247.  
  248. Usage()
  249. {
  250.     fprintf(stderr, "Usage:\n");
  251.     fprintf(stderr,
  252. "   ns2tab [style={aliases,elm,group,hosts,lelm,nrgroup,pwupd}] [domain=...]\n");
  253.     fprintf(stderr,
  254. "              [load] [print]\n");
  255.     exit(1);
  256. }
  257.  
  258. /*
  259.  *******************************************************************************
  260.  *
  261.  * IsAddr --
  262.  *
  263.  *    Returns TRUE if the string looks like an Internet address.
  264.  *    A string with a trailing dot is not an address, even if it looks
  265.  *    like one.
  266.  *
  267.  *    XXX doesn't treat 255.255.255.255 as an address.
  268.  *
  269.  *******************************************************************************
  270.  */
  271.  
  272. Boolean
  273. IsAddr(host, addrPtr)
  274.     char *host;
  275.     unsigned long *addrPtr;    /* If return TRUE, contains IP address */
  276. {
  277.     register char *cp;
  278.     unsigned long addr;
  279.  
  280.     if (isdigit(host[0])) {
  281.         /* Make sure it has only digits and dots. */
  282.         for (cp = host; *cp; ++cp) {
  283.         if (!isdigit(*cp) && *cp != '.') 
  284.             return FALSE;
  285.         }
  286.         /* If it has a trailing dot, don't treat it as an address. */
  287.         if (*--cp != '.') { 
  288.         if ((addr = inet_addr(host)) != (unsigned long) -1) {
  289.             *addrPtr = addr;
  290.             return TRUE;
  291. #if 0
  292.         } else {
  293.             /* XXX Check for 255.255.255.255 case */
  294. #endif
  295.         }
  296.         }
  297.     }
  298.     return FALSE;
  299. }
  300.  
  301.  
  302. /*
  303.  *******************************************************************************
  304.  *
  305.  *  DOCommand -- 
  306.  *
  307.  *    This routine is used to change the state information
  308.  *    that affect the lookups. The command format is
  309.  *       keyword[=value]
  310.  *    Most keywords can be abbreviated. Parsing is very simplistic--
  311.  *    A value must not be separated from its keyword by white space.
  312.  *
  313.  *    Valid keywords:        Meaning:
  314.  *    [no]d2            turn on/off extra debugging mode.
  315.  *    [no]debug        turn on/off debugging mode.
  316.  *    [no]defname        use/don't use default domain name.
  317.  *    [no]search        use/don't use domain search list.
  318.  *    domain=NAME        set default domain name to NAME.
  319.  *    [no]ignore        ignore/don't ignore trunc. errors.
  320.  *    query=value        set default query type to value,
  321.  *                value is one of the query types in RFC883
  322.  *                without the leading T_.    (e.g., A, HINFO)
  323.  *    [no]recurse        use/don't use recursive lookup.
  324.  *    retry=#            set number of retries to #.
  325.  *    root=NAME        change root server to NAME.
  326.  *    time=#            set timeout length to #.
  327.  *    [no]vc            use/don't use virtual circuit.
  328.  *    port            TCP/UDP port to server.
  329.  *
  330.  *     Deprecated:
  331.  *    [no]primary        use/don't use primary server.
  332.  *
  333.  *  Results:
  334.  *    SUCCESS        the command was parsed correctly.
  335.  *    ERROR        the command was not parsed correctly.
  336.  *
  337.  *******************************************************************************
  338.  */
  339.  
  340. int
  341. DoCommand(option)
  342.     register char *option;
  343. {
  344.     char    type[NAME_LEN];
  345.     char    *ptr;
  346.     int        tmp;
  347.  
  348.     if (*option == 0) {
  349.     fprintf(stderr, "*** Invalid flag\n");
  350.     return(ERROR);
  351.     } else {
  352.     if (strncmp(option, "out", 3) == 0) {
  353.         ptr = strchr(option, '=');
  354.         if (ptr != NULL) {
  355.         if(filePtr != stdout) fclose(filePtr);
  356.         if(!(filePtr = fopen(++ptr,"w")))
  357.            filePtr = stdout;
  358.         }
  359.     } else if (strncmp(option, "ser", 3) == 0) {
  360.         ptr = strchr(option, '=');
  361.         if (ptr != NULL) {
  362.         SetDefaultServer(++ptr,1);
  363.         explicitserver = 0;
  364.         }
  365.     } else if (strncmp(option, "expli", 3) == 0) {
  366.         ptr = strchr(option, '=');
  367.         if (ptr != NULL) {
  368.         SetDefaultServer(++ptr,1);
  369.         explicitserver = 1;
  370.         }
  371.     } else if (strncmp(option, "d2", 2) == 0) {    /* d2 (more debug) */
  372.         _res.options |= (RES_DEBUG | RES_DEBUG2);
  373.     } else if (strncmp(option, "nod2", 4) == 0) {
  374.         _res.options &= ~RES_DEBUG2;
  375.         printf("d2 mode disabled; still in debug mode\n");
  376.     } else if (strncmp(option, "def", 3) == 0) {    /* defname */
  377.         _res.options |= RES_DEFNAMES;
  378.     } else if (strncmp(option, "nodef", 5) == 0) {
  379.         _res.options &= ~RES_DEFNAMES;
  380.     } else if (strncmp(option, "domain", 3) == 0) {    /* domain */
  381.         ptr = strchr(option, '=');
  382.         if (ptr != NULL) {
  383.         sscanf(++ptr, "%s", _res.defdname);
  384.         res_re_init();
  385.         vdomain = _res.defdname;
  386.         hasloaded = 0;
  387. #if 0
  388.         DoCommand("load");
  389. #endif
  390.         }
  391.     } else if (strncmp(option, "suffix", 3) == 0) {    /* domain */
  392.         ptr = strchr(option, '=');
  393.         if (ptr != NULL) {
  394.         vdomain = ++ptr;
  395.         }
  396.     } else if (strncmp(option, "loa", 3) == 0) {    /* load! */
  397.         LoadHosts(_res.defdname);
  398.         hasloaded = 1;
  399.     } else if (strncmp(option, "prin", 4) == 0) {    /* print! */
  400.         if(!hasloaded)
  401.         DoCommand("load");
  402.         PrintStyle(filePtr);
  403.     } else if (strncmp(option, "sty", 3) == 0) {    /* style */
  404.         ptr = strchr(option, '=');
  405.         if (ptr != NULL)
  406.         {
  407.         SetStyle(++ptr);
  408.         } /* if */
  409.     } else if (strncmp(option, "deb", 1) == 0) {    /* debug */
  410.         _res.options |= RES_DEBUG;
  411.     } else if (strncmp(option, "nodeb", 5) == 0) {
  412.         _res.options &= ~(RES_DEBUG | RES_DEBUG2);
  413.     } else if (strncmp(option, "ig", 2) == 0) {    /* ignore */
  414.         _res.options |= RES_IGNTC;
  415.     } else if (strncmp(option, "noig", 4) == 0) {
  416.         _res.options &= ~RES_IGNTC;
  417. #ifdef deprecated
  418.     } else if (strncmp(option, "pri", 3) == 0) {    /* primary */
  419.         _res.options |= RES_PRIMARY;
  420.     } else if (strncmp(option, "nopri", 5) == 0) {
  421.         _res.options &= ~RES_PRIMARY;
  422. #endif
  423.     } else if (strncmp(option, "cl", 2) == 0) {    /* query class */
  424.         ptr = strchr(option, '=');
  425.         if (ptr != NULL) {
  426.         sscanf(++ptr, "%s", type);
  427.         queryClass = StringToClass(type, queryClass);
  428.         }
  429.     } else if (strncmp(option, "rec", 3) == 0) {    /* recurse */
  430.         _res.options |= RES_RECURSE;
  431.     } else if (strncmp(option, "norec", 5) == 0) {
  432.         _res.options &= ~RES_RECURSE;
  433.     } else if (strncmp(option, "ret", 3) == 0) {    /* retry */
  434.         ptr = strchr(option, '=');
  435.         if (ptr != NULL) {
  436.         sscanf(++ptr, "%d", &tmp);
  437.         if (tmp >= 0) {
  438.             _res.retry = tmp;
  439.         }
  440.         }
  441.     } else if (strncmp(option, "ro", 2) == 0) {    /* root */
  442.         ptr = strchr(option, '=');
  443.         if (ptr != NULL) {
  444.         sscanf(++ptr, "%s", rootServerName);
  445.         }
  446.     } else if (strncmp(option, "sea", 3) == 0) {    /* search list */
  447.         _res.options |= RES_DNSRCH;
  448.     } else if (strncmp(option, "nosea", 5) == 0) {
  449.         _res.options &= ~RES_DNSRCH;
  450.     } else if (strncmp(option, "srchl", 5) == 0) {    /* domain search list */
  451.         ptr = strchr(option, '=');
  452.         if (ptr != NULL) {
  453.         res_dnsrch(++ptr);
  454.         }
  455.     } else if (strncmp(option, "ti", 2) == 0) {    /* timeout */
  456.         ptr = strchr(option, '=');
  457.         if (ptr != NULL) {
  458.         sscanf(++ptr, "%d", &tmp);
  459.         if (tmp >= 0) {
  460.             _res.retrans = tmp;
  461.         }
  462.         }
  463.     } else {
  464.         fprintf(stderr, "*** Invalid option: %s\n",  option);
  465.         return(ERROR);
  466.     }
  467.     }
  468.     return(SUCCESS);
  469. }
  470.  
  471. #ifndef MAXDFLSRCH 
  472. #define MAXDFLSRCH 3
  473. #endif
  474. /*
  475.  * Fake a reinitialization when the domain is changed.
  476.  */
  477. res_re_init()
  478. {
  479.     register char *cp, **pp;
  480.     int n;
  481.  
  482.     /* find components of local domain that might be searched */
  483.     pp = _res.dnsrch;
  484.     *pp++ = _res.defdname;
  485.     for (cp = _res.defdname, n = 0; *cp; cp++)
  486.     if (*cp == '.')
  487.         n++;
  488.     cp = _res.defdname;
  489.     for (; n >= LOCALDOMAINPARTS && pp < _res.dnsrch + MAXDFLSRCH; n--) {
  490.     cp = strchr(cp, '.');
  491.     *pp++ = ++cp;
  492.     }
  493.     *pp = 0;
  494.     _res.options |= RES_INIT;
  495. }
  496.  
  497. #define SRCHLIST_SEP '/'
  498.  
  499. res_dnsrch(cp)
  500.     register char *cp;
  501. {
  502.     register char **pp;
  503.     int n;
  504.  
  505.     (void)strncpy(_res.defdname, cp, sizeof(_res.defdname) - 1);
  506.     if ((cp = strchr(_res.defdname, '\n')) != NULL)
  507.         *cp = '\0';
  508.     /*
  509.      * Set search list to be blank-separated strings
  510.      * on rest of line.
  511.      */
  512.     cp = _res.defdname;
  513.     pp = _res.dnsrch;
  514.     *pp++ = cp;
  515.     for (n = 0; *cp && pp < _res.dnsrch + MAXDNSRCH; cp++) {
  516.         if (*cp == SRCHLIST_SEP) {
  517.             *cp = '\0';
  518.             n = 1;
  519.         } else if (n) {
  520.             *pp++ = cp;
  521.             n = 0;
  522.         }
  523.     }
  524.     if ((cp = strchr(pp[-1], SRCHLIST_SEP)) != NULL) {
  525.     *cp = '\0';
  526.     }
  527.     *pp = NULL;
  528. }
  529.  
  530. #undef SRCHLIST_SEP
  531.  
  532. /*
  533.  *******************************************************************************
  534.  *
  535.  * CvtAddrToPtr --
  536.  *
  537.  *    Convert a dotted-decimal Internet address into the standard
  538.  *    PTR format (reversed address with .in-arpa. suffix).
  539.  *
  540.  *    Assumes the argument buffer is large enougth to hold the result.
  541.  *
  542.  *******************************************************************************
  543.  */
  544.  
  545. static void
  546. CvtAddrToPtr(name)
  547.     char *name;
  548. {
  549.     char *p;
  550.     int ip[4];
  551.     struct in_addr addr;
  552.  
  553.     if (IsAddr(name, &addr.s_addr)) {
  554.     p = inet_ntoa(addr);
  555.     if (sscanf(p, "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3]) == 4) {
  556.         sprintf(name, "%d.%d.%d.%d.in-addr.arpa.", 
  557.         ip[3], ip[2], ip[1], ip[0]);
  558.     }
  559.     }
  560. }
  561.  
  562. #if 0
  563. int
  564. SetServer(serv)
  565.    char *serv;
  566. {
  567.     int i;
  568.     struct in_addr addr;
  569.     struct hostent *hp;
  570.  
  571.     /*
  572.      * Use an explicit name server. If the hostname lookup fails,
  573.      * default to the server(s) in resolv.conf.
  574.      */ 
  575.  
  576.     addr.s_addr = inet_addr(serv);
  577.     if (addr.s_addr != (unsigned long)-1) {
  578.     _res.nscount = 1;
  579.     _res.nsaddr.sin_addr = addr;
  580.     } else {
  581.     hp = gethostbyname(serv);
  582.     if (hp == NULL) {
  583.         fprintf(stderr, "*** Can't find server address for '%s': ", 
  584.             serv);
  585.         herror((char *)NULL);
  586.         fputc('\n', stderr);
  587.         return 0;
  588.     }
  589.     else
  590.     {
  591. #if BSD < 43
  592.         bcopy(hp->h_addr, (char *)&_res.nsaddr.sin_addr, hp->h_length);
  593.         _res.nscount = 1;
  594. #else
  595.         for (i = 0; i < MAXNS && hp->h_addr_list[i] != NULL; i++) {
  596.         bcopy(hp->h_addr_list[i], 
  597.             (char *)&_res.nsaddr_list(i).sin_addr, 
  598.             hp->h_length);
  599.         }
  600.         _res.nscount = i;
  601. #endif
  602.     } 
  603.     }
  604.     return 1;
  605. }
  606. #endif
  607. /*
  608.  *******************************************************************************
  609.  *
  610.  *  SetDefaultServer --
  611.  *
  612.  *    Changes the default name server to the one specified by
  613.  *    the first argument. The command "server name" uses the current 
  614.  *    default server to lookup the info for "name". The command
  615.  *    "lserver name" uses the original server to lookup "name".
  616.  *
  617.  *  Side effects:
  618.  *    This routine will cause a core dump if the allocation requests fail.
  619.  *
  620.  *  Results:
  621.  *    SUCCESS        The default server was changed successfully.
  622.  *    NONAUTH        The server was changed but addresses of
  623.  *            other servers who know about the requested server
  624.  *            were returned.
  625.  *    Errors        No info about the new server was found or
  626.  *            requests to the current server timed-out.
  627.  *
  628.  *******************************************************************************
  629.  */
  630.  
  631. int
  632. SetDefaultServer(string, local)
  633.     char    *string;
  634.     Boolean    local;
  635. {
  636.     register HostInfo    *newDefPtr;
  637.     struct in_addr    *servAddrPtr;
  638.     struct in_addr    addr;
  639.     char        newServer[NAME_LEN];
  640.     int            result;
  641.     int            i;
  642.  
  643.     strcpy(newServer,string);
  644.     /*
  645.      * Allocate space for a HostInfo variable for the new server. Don't
  646.      * overwrite the old HostInfo struct because info about the new server
  647.      * might not be found and we need to have valid default server info.
  648.      */
  649.  
  650.     newDefPtr = (HostInfo *) calloc(1, sizeof(HostInfo));
  651.  
  652.  
  653.     /*
  654.      *    A 'local' lookup uses the original server that the program was
  655.      *  initialized with.
  656.      *
  657.      *  Check to see if we have the address of the server or the
  658.      *  address of a server who knows about this domain.
  659.      *  XXX For now, just use the first address in the list.
  660.      */
  661.  
  662.     if (local) {
  663.     servAddrPtr = &defaultAddr;
  664.     } else if (defaultPtr->addrList != NULL) {
  665.     servAddrPtr = (struct in_addr *) defaultPtr->addrList[0];
  666.     } else {
  667.     servAddrPtr = (struct in_addr *) defaultPtr->servers[0]->addrList[0];
  668.     }
  669.  
  670.     result = ERROR;
  671.     if (IsAddr(newServer, &addr.s_addr)) {
  672.     result = GetHostInfoByAddr(servAddrPtr, &addr, newDefPtr);
  673.     /* If we can't get the name, fall through... */
  674.     } 
  675.     if (result != SUCCESS && result != NONAUTH) {
  676.     result = GetHostInfoByName(servAddrPtr, C_IN, T_A, 
  677.             newServer, newDefPtr, 1);
  678.     }
  679.  
  680.     if (result == SUCCESS || result == NONAUTH) {
  681.         /*
  682.          *  Found info about the new server. Free the resources for
  683.          *  the old server.
  684.          */
  685.  
  686.         FreeHostInfoPtr(defaultPtr);
  687.         free((char *)defaultPtr);
  688.         defaultPtr = newDefPtr;
  689.         strcpy(defaultServer, defaultPtr->name);
  690.         return(SUCCESS);
  691.     } else {
  692.         fprintf(stderr, "*** Can't find address for server %s: %s\n",
  693.             newServer, DecodeError(result));
  694.         free((char *)newDefPtr);
  695.  
  696.         return(result);
  697.     }
  698. }
  699.