]> git.sur5r.net Git - openldap/blob - servers/ldapd/main.c
merged with autoconf branch
[openldap] / servers / ldapd / main.c
1 /*
2  * Copyright (c) 1990-1996 Regents of the University of Michigan.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that this notice is preserved and that due credit is given
7  * to the University of Michigan at Ann Arbor. The name of the University
8  * may not be used to endorse or promote products derived from this
9  * software without specific prior written permission. This software
10  * is provided ``as is'' without express or implied warranty.
11  */
12 /*
13  * Some code fragments to run from inetd stolen from the University
14  * of Minnesota gopher distribution, which had this copyright on it:
15  *
16  * Part of the Internet Gopher program, copyright (C) 1991
17  * University of Minnesota Microcomputer Workstation and Networks Center
18  */
19
20 #include "portable.h"
21
22 #include <stdio.h>
23
24 #include <ac/signal.h>
25 #include <ac/socket.h>
26 #include <ac/string.h>
27 #include <ac/syslog.h>
28 #include <ac/time.h>
29 #include <ac/unistd.h>
30 #include <ac/wait.h>
31
32 #include <quipu/commonarg.h>
33 #include <quipu/ds_error.h>
34
35 #include "lber.h"
36 #include "ldap.h"
37 #include "common.h"
38
39 #ifdef HAVE_TCPD
40 #include <tcpd.h>
41
42 int allow_severity = LOG_INFO;
43 int deny_severity = LOG_NOTICE;
44 #endif /* TCP_WRAPPERS */
45
46 void log_and_exit();
47 static set_socket();
48 static do_queries();
49 static RETSIGTYPE wait4child();
50 #ifdef LDAP_CONNECTIONLESS
51 static udp_init();
52 #endif
53
54 #ifdef LDAP_DEBUG
55 int     ldap_debug;
56 #endif
57 int     version;
58 #ifdef LDAP_COMPAT
59 int     ldap_compat;
60 #endif
61 int     dosyslog;
62 int     do_tcp = 1;
63 #ifdef LDAP_CONNECTIONLESS
64 int     do_udp = 0;
65 #endif
66 int     idletime = DEFAULT_TIMEOUT;
67 int     referral_connection_timeout = DEFAULT_REFERRAL_TIMEOUT;
68 struct timeval  conn_start_tv;
69 #ifdef HAVE_KERBEROS
70 char    *krb_ldap_service = "ldapserver";
71 char    *krb_x500_service = "x500dsa";
72 char    *krb_x500_instance;
73 char    *krb_x500_nonce;
74 char    *kerberos_keyfile;
75 #endif
76
77 int     dtblsize;
78 int     RunFromInetd = 0;
79
80 extern char Versionstr[];
81
82 static usage( name )
83 char    *name;
84 {
85         fprintf( stderr, "usage: %s [-d debuglvl] [-p port] [-l] [-c dsa] [-r referraltimeout]", name );
86 #ifdef LDAP_CONNECTIONLESS
87         fprintf( stderr, " [ -U | -t timeout ]" );
88 #else
89         fprintf( stderr, " [ -t timeout ]" );
90 #endif
91         fprintf( stderr, " [-I]" );
92 #ifdef HAVE_KERBEROS
93         fprintf( stderr, " [-i dsainstance]" );
94 #endif
95         fprintf( stderr, "\n" );
96 }
97
98 main (argc, argv)
99 int     argc;
100 char    **argv;
101 {
102         int                     tcps, ns;
103 #ifdef LDAP_CONNECTIONLESS
104         int                     udps;
105 #endif
106         int                     myport = LDAP_PORT;
107         int                     i, pid, socktype;
108         char                    *myname;
109         fd_set                  readfds;
110         struct hostent          *hp;
111         struct sockaddr_in      from;
112         int                     len;
113         int                     dsapargc;
114         char                    **dsapargv;
115         RETSIGTYPE                      wait4child();
116 #ifndef NOSETPROCTITLE
117         char                    title[80];
118         extern char             **Argv;
119         extern int              Argc;
120 #endif
121         extern char             *optarg;
122         extern int              optind;
123
124 #ifdef VMS
125         /* Pick up socket from inetd-type server on VMS */
126         if ( (ns = socket_from_server( NULL )) > 0 )
127                 RunFromInetd = 1;
128 #else
129         /* Socket from inetd is usually 0 */
130         ns = 0;
131 #endif
132
133         /* for dsap_init */
134         if ( (dsapargv = (char **) malloc( 4 * sizeof(char *) )) == NULL ) {
135                 perror( "malloc" );
136                 exit( 1 );
137         }
138         dsapargv[0] = argv[0];
139         dsapargv[1] = 0;
140         dsapargv[2] = 0;
141         dsapargv[3] = 0;
142         dsapargc = 1;
143 #ifdef HAVE_KERBEROS
144         kerberos_keyfile = "";
145 #endif
146
147         /* process command line arguments */
148         while ( (i = getopt( argc, argv, "d:lp:f:i:c:r:t:IuU" )) != EOF ) {
149                 switch ( i ) {
150                 case 'c':       /* specify dsa to contact */
151                         dsapargv[1] = "-call";
152                         dsapargv[2] = strdup( optarg );
153                         dsapargc = 3;
154                         break;
155
156                 case 'd':       /* turn on debugging */
157 #ifdef LDAP_DEBUG
158                         ldap_debug = atoi( optarg );
159                         if ( ldap_debug & LDAP_DEBUG_PACKETS )
160                                 lber_debug = ldap_debug;
161 #else
162                         fprintf( stderr, "Not compiled with -DLDAP_DEBUG!\n" );
163 #endif
164                         break;
165
166                 case 'l':       /* do syslogging */
167                         dosyslog = 1;
168                         break;
169
170                 case 'p':       /* specify port number */
171                         myport = atoi( optarg );
172                         break;
173
174                 case 'r':       /* timeout for referral connections */
175                         referral_connection_timeout = atoi( optarg );
176                         break;
177
178                 case 't':       /* timeout for idle connections */
179                         idletime = atoi( optarg );
180                         break;
181
182 #ifdef HAVE_KERBEROS
183                 case 'f':       /* kerberos key file */
184                         kerberos_keyfile = strdup( optarg );
185                         break;
186
187                 case 'i':       /* x500 dsa kerberos instance */
188                         if ( krb_x500_instance != NULL )
189                                 free( krb_x500_instance );
190                         krb_x500_instance = strdup( optarg );
191                         break;
192 #endif
193
194                 case 'I':       /* Run from inetd */
195                         RunFromInetd = 1;
196                         break;
197
198 #ifdef LDAP_CONNECTIONLESS
199                 case 'U':       /* UDP only (no TCP) */
200                         do_tcp = 0;
201                         do_udp = 1;
202                         break;
203
204 #ifdef NOTYET
205                 case 'u':       /* allow UDP requests (CLDAP) */
206                         do_udp = 1;
207                         break;
208 #endif /* NOTYET */
209
210 #endif /* LDAP_CONNECTIONLESS */
211
212                 default:
213                         usage( argv[0] );
214                         exit( 1 );
215                 }
216         }
217
218         if ( optind < argc ) {
219                 usage( argv[ 0 ] );
220                 exit( 1 );
221         }
222
223 #ifdef LDAP_CONNECTIONLESS
224         if ( do_udp && !do_tcp && idletime != DEFAULT_TIMEOUT ) {
225                 usage( argv[ 0 ] );
226                 exit( 1 );
227         }
228 #endif
229
230         Debug( LDAP_DEBUG_TRACE, "%s", Versionstr, 0, 0 );
231
232 #ifdef HAVE_SYSCONF
233         dtblsize = sysconf( _SC_OPEN_MAX );
234 #elif HAVE_GETDTABLESIZE
235         dtblsize = getdtablesize();
236 #else
237         dtblsize = FD_SETSIZE;
238 #endif
239
240 #ifdef FD_SETSIZE
241         if( dtblsize > FD_SETSIZE ) {
242                 dtblsize = FD_SETSIZE;
243         }
244 #endif /* FD_SETSIZE */
245
246 #ifndef NOSETPROCTITLE
247         /* for setproctitle */
248         Argv = argv;
249         Argc = argc;
250 #endif
251
252         if ( (myname = strrchr( argv[0], '/' )) == NULL )
253                 myname = strdup( argv[0] );
254         else
255                 myname = strdup( myname + 1 );
256
257         /* 
258          * detach from the terminal if stderr is redirected or no
259          * debugging is wanted, and then arrange to reap children
260          * that have exited
261          */
262         if (!RunFromInetd) {
263 #ifndef NOSETPROCTITLE
264                 setproctitle( "initializing" );
265 #endif
266 #ifndef VMS
267                 (void) detach();
268 #endif
269                 (void) SIGNAL( SIGCHLD, (void *) wait4child );
270                 (void) SIGNAL( SIGINT, (void *) log_and_exit );
271         }
272
273         /* 
274          * set up syslogging (if desired)
275          */
276         if ( dosyslog ) {
277 #ifdef LOG_LOCAL4
278                 openlog( myname, OPENLOG_OPTIONS, LOG_LOCAL4 );
279 #else
280                 openlog( myname, OPENLOG_OPTIONS );
281 #endif
282         }
283
284         /* 
285          * load the syntax handlers, oidtables, and initialize some stuff,
286          * then start listening
287          */
288
289         (void) quipu_syntaxes();
290 #ifdef LDAP_USE_PP
291         (void) pp_quipu_init( argv[0] );
292 #endif
293 #if ISODEPACKAGE == IC
294 #if ICRELEASE > 2
295         dsa_operation_syntaxes();
296 #endif
297 #endif
298         (void) dsap_init( &dsapargc, &dsapargv );
299         (void) get_syntaxes();
300         if (RunFromInetd) {
301                 len = sizeof( socktype );
302                 getsockopt( ns, SOL_SOCKET, SO_TYPE, &socktype, &len );
303                 if ( socktype == SOCK_DGRAM ) {
304 #ifdef LDAP_CONNECTIONLESS
305                         Debug( LDAP_DEBUG_ARGS,
306                             "CLDAP request from unknown (%s)\n",
307                             inet_ntoa( from.sin_addr ), 0, 0 );
308                         conn_start_tv.tv_sec = 0;
309                         udp_init( 0, 0 );
310                         do_queries( ns, 1 );
311 #else /* LDAP_CONNECTIONLESS */
312                         Debug( LDAP_DEBUG_ARGS,
313                             "Compile with -DLDAP_CONNECTIONLESS for UDP support\n",0,0,0 );
314 #endif /* LDAP_CONNECTIONLESS */
315                         exit( 0 );
316                 }
317
318                 len = sizeof(from);
319                 if ( getpeername( ns, (struct sockaddr *) &from, &len )
320                     == 0 ) {
321                         hp = gethostbyaddr( (char *) &(from.sin_addr.s_addr),
322                         sizeof(from.sin_addr.s_addr), AF_INET );
323                         Debug( LDAP_DEBUG_ARGS, "connection from %s (%s)\n",
324                             (hp == NULL) ? "unknown" : hp->h_name,
325                             inet_ntoa( from.sin_addr ), 0 );
326
327                         if ( dosyslog ) {
328                                 syslog( LOG_INFO, "connection from %s (%s)",
329                                     (hp == NULL) ? "unknown" : hp->h_name,
330                                     inet_ntoa( from.sin_addr ) );
331                         }
332
333 #ifndef NOSETPROCTITLE
334                         sprintf( title, "%s %d\n", hp == NULL ?
335                             inet_ntoa( from.sin_addr ) : hp->h_name, myport );
336                         setproctitle( title );
337 #endif
338                 }
339                 gettimeofday( &conn_start_tv, (struct timezone *) NULL );
340                 do_queries( ns, 0 );
341
342                 exit( 0 );
343         }
344
345         if ( do_tcp )
346             tcps = set_socket( myport, 0 );
347
348 #ifdef LDAP_CONNECTIONLESS
349         if ( do_udp )
350                 udps = udp_init( myport, 1 );
351 #endif
352
353         /*
354          * loop, wait for a connection, then fork off a child to handle it
355          * if we are doing CLDAP as well, handle those requests on the fly
356          */
357
358 #ifndef NOSETPROCTITLE
359 #ifdef LDAP_CONNECTIONLESS
360         sprintf( title, "listening %s/%s %d", do_tcp ? "tcp" : "",
361             do_udp ? "udp" : "", myport );
362 #else
363         sprintf( title, "listening %s %d", do_tcp ? "tcp" : "", myport );
364 #endif
365         setproctitle( title );
366 #endif
367
368         for ( ;; ) {
369                 FD_ZERO( &readfds );
370                 if ( do_tcp )
371                         FD_SET( tcps, &readfds );
372 #ifdef LDAP_CONNECTIONLESS
373                 if ( do_udp )
374                         FD_SET( udps, &readfds );
375 #endif
376
377                 if ( select( dtblsize, &readfds, 0, 0, 0 ) < 1 ) {
378 #ifdef LDAP_DEBUG
379                         if ( ldap_debug ) perror( "main select" );
380 #endif
381                         continue;
382                 }
383
384 #ifdef LDAP_CONNECTIONLESS
385                 if ( do_udp && FD_ISSET( udps, &readfds ) ) {
386                         do_queries( udps, 1 );
387                 }
388 #endif
389
390                 if ( !do_tcp || ! FD_ISSET( tcps, &readfds ) ) {
391                         continue;
392                 }
393
394                 len = sizeof(from);
395                 if ( (ns = accept( tcps, (struct sockaddr *) &from, &len ))
396                     == -1 ) {
397 #ifdef LDAP_DEBUG
398                         if ( ldap_debug ) perror( "accept" );
399 #endif
400                         continue;
401                 }
402
403                 hp = gethostbyaddr( (char *) &(from.sin_addr.s_addr),
404                     sizeof(from.sin_addr.s_addr), AF_INET );
405
406 #ifdef HAVE_TCPD
407                 if ( !hosts_ctl("ldapd", (hp == NULL) ? "unknown" : hp->h_name,
408                         inet_ntoa( from.sin_addr ), STRING_UNKNOWN ) {
409
410                         Debug( LDAP_DEBUG_ARGS, "connection from %s (%s) denied.\n",
411                                 (hp == NULL) ? "unknown" : hp->h_name,
412                                 inet_ntoa( from.sin_addr ), 0 );
413
414                         if ( dosyslog ) {
415                                 syslog( LOG_NOTICE, "connection from %s (%s) denied.",
416                                     (hp == NULL) ? "unknown" : hp->h_name,
417                                     inet_ntoa( from.sin_addr ) );
418                         }
419
420                         close(ns);
421                         continue;
422                 }
423 #endif /* TCP_WRAPPERS */
424
425                 Debug( LDAP_DEBUG_ARGS, "connection from %s (%s)\n",
426                     (hp == NULL) ? "unknown" : hp->h_name,
427                     inet_ntoa( from.sin_addr ), 0 );
428
429
430                 if ( dosyslog ) {
431                         syslog( LOG_INFO, "connection from %s (%s)",
432                             (hp == NULL) ? "unknown" : hp->h_name,
433                             inet_ntoa( from.sin_addr ) );
434                 }
435
436 #ifdef VMS
437                 /* This is for debug on terminal on VMS */
438                 close( tcps );
439 #ifndef NOSETPROCTITLE
440                 setproctitle( hp == NULL ? inet_ntoa( from.sin_addr ) :
441                     hp->h_name );
442 #endif
443                 gettimeofday( &conn_start_tv, (struct timezone *) NULL );
444                 (void) SIGNAL( SIGPIPE, (void *) log_and_exit );
445
446                 do_queries( ns, 0 );
447                 /* NOT REACHED */
448 #endif
449
450                 switch( pid = fork() ) {
451                 case 0:         /* child */
452                         close( tcps );
453 #ifndef NOSETPROCTITLE
454                         sprintf( title, "%s (%d)\n", hp == NULL ?
455                                 inet_ntoa( from.sin_addr ) : hp->h_name,
456                                 myport );
457                         setproctitle( title );
458 #endif
459                         gettimeofday( &conn_start_tv, (struct timezone *) NULL );
460                         (void) SIGNAL( SIGPIPE, (void *) log_and_exit );
461
462                         do_queries( ns, 0 );
463                         break;
464
465                 case -1:        /* failed */
466 #ifdef LDAP_DEBUG
467                         if ( ldap_debug ) perror( "fork" );
468 #endif
469                         close( ns );
470                         syslog( LOG_ERR, "fork failed %m" );
471                         /* let things cool off */
472                         sleep( 15 );
473                         break;
474
475                 default:        /* parent */
476                         close( ns );
477                         Debug( LDAP_DEBUG_TRACE, "forked child %d\n", pid, 0,
478                             0 );
479                         break;
480                 }
481         }
482         /* NOT REACHED */
483 }
484
485 static
486 do_queries(
487     int clientsock,
488     int udp             /* is this a UDP (CLDAP) request? */
489 )
490 {
491         fd_set          readfds;
492         int             rc, i;
493         struct timeval  timeout;
494         Sockbuf         sb;
495 #ifdef LDAP_CONNECTIONLESS
496         struct sockaddr saddr, faddr;
497         struct sockaddr *saddrlist[ 1 ];
498 #endif /* LDAP_CONNECTIONLESS */
499
500         Debug( LDAP_DEBUG_TRACE, "do_queries%s\n",
501             udp ? " udp" : "", 0, 0 );
502
503         /*
504          * Loop, wait for a request from the client or a response from
505          * a dsa, then handle it.  Dsap_ad is always a connection to the
506          * "default" dsa.  Other connections can be made as a result of
507          * a referral being chased down.  These association descriptors
508          * are kept track of with the message that caused the referral.
509          * The set_dsa_fds() routine traverses the list of outstanding
510          * messages, setting the appropriate bits in readfds.
511          */
512
513         if ( !udp ) {
514                 conn_init();
515         }
516
517         (void) memset( (void *) &sb, '\0', sizeof( sb ) );
518         sb.sb_sd = clientsock;
519         sb.sb_naddr = ( udp ) ? 1 : 0;
520 #ifdef LDAP_CONNECTIONLESS
521         sb.sb_addrs = (void **)saddrlist;
522         sb.sb_fromaddr = &faddr;
523         sb.sb_useaddr = saddrlist[ 0 ] = &saddr;
524 #endif
525         sb.sb_ber.ber_buf = NULL;
526         sb.sb_ber.ber_ptr = NULL;
527         sb.sb_ber.ber_end = NULL;
528
529         timeout.tv_sec = idletime;
530         timeout.tv_usec = 0;
531         for ( ;; ) {
532                 struct conn             *dsaconn;
533                 extern struct conn      *conns;
534
535                 FD_ZERO( &readfds );
536                 FD_SET( clientsock, &readfds );
537                 conn_setfds( &readfds );
538
539 #ifdef LDAP_DEBUG
540                 if ( ldap_debug & LDAP_DEBUG_CONNS ) {
541                         Debug( LDAP_DEBUG_CONNS, "FDLIST:", 0, 0, 0 );
542                         for ( i = 0; i < dtblsize; i++ ) {
543                                 if ( FD_ISSET( i, &readfds ) ) {
544                                         Debug( LDAP_DEBUG_CONNS, " %d", i, 0,
545                                             0);
546                                 }
547                         }
548                         Debug( LDAP_DEBUG_CONNS, "\n", 0, 0, 0 );
549                 }
550 #endif
551
552                 /* 
553                  * hack - because of lber buffering, there might be stuff
554                  * already waiting for us on the client sock.
555                  */
556
557                 if ( sb.sb_ber.ber_ptr >= sb.sb_ber.ber_end ) {
558                         if ( (rc = select( dtblsize, &readfds, 0, 0,
559                             udp ? 0 : &timeout )) < 1 ) {
560 #ifdef LDAP_DEBUG
561                                 if ( ldap_debug ) perror( "do_queries select" );
562 #endif
563                                 if ( rc == 0 )
564                                         log_and_exit( 0 ); /* idle timeout */
565
566                                 Debug( LDAP_DEBUG_ANY, "select returns %d!\n",
567                                     rc, 0, 0 );
568
569                                 /* client gone away - we can too */
570                                 if ( isclosed( clientsock ) )
571                                         log_and_exit( 0 );
572
573                                 /*
574                                  * check if a dsa conn has gone away -
575                                  * mark it bad if so
576                                  */
577                                 conn_badfds();
578
579                                 continue;
580                         }
581                 }
582
583                 if ( sb.sb_ber.ber_ptr < sb.sb_ber.ber_end ||
584                     FD_ISSET( clientsock, &readfds ) ) {
585                         client_request( &sb, conns, udp );
586                 } else {
587                         if ( (dsaconn = conn_getfd( &readfds )) == NULL ) {
588                                 Debug( LDAP_DEBUG_ANY, "No DSA activity!\n",
589                                     0, 0, 0 );
590                                 continue;
591                         }
592
593                         dsa_response( dsaconn, &sb );
594                 }
595         }
596         /* NOT REACHED */
597 }
598
599 static set_socket(
600     int port,
601     int udp     /* UDP port? */
602 )
603 {
604         int                     s, i;
605         struct sockaddr_in      addr;
606
607         if ( (s = socket( AF_INET, udp ? SOCK_DGRAM:SOCK_STREAM, 0 )) == -1 ) {
608                 perror( "socket" );
609                 exit( 1 );
610         }
611
612         /* set option so clients can't keep us from coming back up */
613         i = 1;
614         if ( setsockopt( s, SOL_SOCKET, SO_REUSEADDR, (void *) &i, sizeof(i) )
615             < 0 ) {
616                 perror( "setsockopt" );
617                 exit( 1 );
618         }
619
620         /* bind to a name */
621         (void)memset( (void *)&addr, '\0', sizeof( addr ));
622         addr.sin_family = AF_INET;
623         addr.sin_addr.s_addr = INADDR_ANY;
624         addr.sin_port = htons( port );
625         if ( bind( s, (struct sockaddr *) &addr, sizeof(addr) ) ) {
626                 perror( "bind" );
627                 exit( 1 );
628         }
629
630         if ( !udp ) {
631                 /* listen for connections */
632                 if ( listen( s, 5 ) == -1 ) {
633                         perror( "listen" );
634                         exit( 1 );
635                 }
636         }
637  
638         Debug( LDAP_DEBUG_TRACE, "listening on %s port %d\n",
639                 udp ? "udp" : "tcp", port, 0 );
640
641         return( s );
642 }
643
644 static RETSIGTYPE wait4child()
645 {
646 #ifndef HAVE_WAITPID
647         WAITSTATUSTYPE     status;
648 #endif
649
650         Debug( LDAP_DEBUG_TRACE, "parent: catching child status\n", 0, 0, 0 );
651
652 #ifdef HAVE_WAITPID
653         while( waitpid( (pid_t) -1, NULL, WAIT_FLAGS ) > 0 )
654                 ;       /* NULL */
655 #else
656         while ( wait3( &status, WAIT_FLAGS, 0 ) > 0 )
657                 ;       /* NULL */
658 #endif
659
660         (void) SIGNAL( SIGCHLD, (void *) wait4child );
661 }
662
663
664 void
665 log_and_exit( int exitcode )
666 {
667         struct timeval  tv;
668
669         if ( dosyslog ) {
670                 if ( conn_start_tv.tv_sec == 0 ) {
671                         syslog( LOG_INFO, "UDP exit(%d)", exitcode );
672                 } else {
673                         gettimeofday( &tv, (struct timezone *)NULL );
674                         syslog( LOG_INFO, "TCP closed %d seconds,  exit(%d)",
675                             tv.tv_sec - conn_start_tv.tv_sec, exitcode );
676                 }
677         }
678
679         exit( exitcode );
680 }
681
682
683 #ifdef LDAP_CONNECTIONLESS
684 static int
685 udp_init(
686     int port,
687     int createsocket
688 )
689 {
690         int     s, bound;
691         char    *matched;
692         extern char             *dsa_address;
693         extern struct PSAPaddr  *psap_cpy();
694         extern struct conn      *conns;
695
696         if ( createsocket )
697                 s = set_socket( port, 1 );
698
699         conn_init();
700         conns->c_dn = strdup("");
701         conns->c_cred = strdup("");
702         conns->c_credlen = 0;
703         conns->c_method = LDAP_AUTH_SIMPLE;
704
705        if ( dsa_address == NULL || (conns->c_paddr = str2paddr( dsa_address ))
706             == NULLPA ) {
707                 fprintf(stderr, "Bad DSA address (%s)\n", dsa_address ?
708                     dsa_address : "NULL" );
709                 exit( 1 );
710         } else {
711                 conns->c_paddr = psap_cpy(conns->c_paddr);
712         }
713
714         if ( do_bind_real(conns, &bound, &matched) != LDAP_SUCCESS) {
715                 fprintf(stderr, "Cannot bind to directory\n");
716                 exit( 1 );
717         }
718         if ( matched != NULL )
719                 free( matched );
720
721         return( createsocket ? s : 0 );
722 }
723 #endif