imapext-2007
diff src/osdep/unix/tcp_unix.c @ 0:ada5e610ab86
imap-2007e
author | yuuji@gentei.org |
---|---|
date | Mon, 14 Sep 2009 15:17:45 +0900 |
parents | |
children | 28a55bc1110c 5cecc027b845 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/osdep/unix/tcp_unix.c Mon Sep 14 15:17:45 2009 +0900 1.3 @@ -0,0 +1,1043 @@ 1.4 +/* ======================================================================== 1.5 + * Copyright 1988-2008 University of Washington 1.6 + * 1.7 + * Licensed under the Apache License, Version 2.0 (the "License"); 1.8 + * you may not use this file except in compliance with the License. 1.9 + * You may obtain a copy of the License at 1.10 + * 1.11 + * http://www.apache.org/licenses/LICENSE-2.0 1.12 + * 1.13 + * 1.14 + * ======================================================================== 1.15 + */ 1.16 + 1.17 +/* 1.18 + * Program: UNIX TCP/IP routines 1.19 + * 1.20 + * Author: Mark Crispin 1.21 + * Networks and Distributed Computing 1.22 + * Computing & Communications 1.23 + * University of Washington 1.24 + * Administration Building, AG-44 1.25 + * Seattle, WA 98195 1.26 + * Internet: MRC@CAC.Washington.EDU 1.27 + * 1.28 + * Date: 1 August 1988 1.29 + * Last Edited: 13 January 2008 1.30 + */ 1.31 + 1.32 +#include "ip_unix.c" 1.33 + 1.34 +#undef write /* don't use redefined write() */ 1.35 + 1.36 +static tcptimeout_t tmoh = NIL; /* TCP timeout handler routine */ 1.37 +static long ttmo_open = 0; /* TCP timeouts, in seconds */ 1.38 +static long ttmo_read = 0; 1.39 +static long ttmo_write = 0; 1.40 +static long rshtimeout = 15; /* rsh timeout */ 1.41 +static char *rshcommand = NIL; /* rsh command */ 1.42 +static char *rshpath = NIL; /* rsh path */ 1.43 +static long sshtimeout = 15; /* ssh timeout */ 1.44 +static char *sshcommand = NIL; /* ssh command */ 1.45 +static char *sshpath = NIL; /* ssh path */ 1.46 +static long allowreversedns = T;/* allow reverse DNS lookup */ 1.47 +static long tcpdebug = NIL; /* extra TCP debugging telemetry */ 1.48 +static char *myClientAddr = NIL;/* client IP address */ 1.49 +static char *myClientHost = NIL;/* client DNS name */ 1.50 +static long myClientPort = -1; /* client port number */ 1.51 +static char *myServerAddr = NIL;/* server IP address */ 1.52 +static char *myServerHost = NIL;/* server DNS name */ 1.53 +static long myServerPort = -1; /* server port number */ 1.54 + 1.55 +extern long maxposint; /* get this from write.c */ 1.56 + 1.57 +/* Local function prototypes */ 1.58 + 1.59 +int tcp_socket_open (int family,void *adr,size_t adrlen,unsigned short port, 1.60 + char *tmp,int *ctr,char *hst); 1.61 +static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size, 1.62 + long *contd); 1.63 +long tcp_abort (TCPSTREAM *stream); 1.64 +char *tcp_name (struct sockaddr *sadr,long flag); 1.65 +char *tcp_name_valid (char *s); 1.66 + 1.67 +/* TCP/IP manipulate parameters 1.68 + * Accepts: function code 1.69 + * function-dependent value 1.70 + * Returns: function-dependent return value 1.71 + */ 1.72 + 1.73 +void *tcp_parameters (long function,void *value) 1.74 +{ 1.75 + void *ret = NIL; 1.76 + switch ((int) function) { 1.77 + case SET_TIMEOUT: 1.78 + tmoh = (tcptimeout_t) value; 1.79 + case GET_TIMEOUT: 1.80 + ret = (void *) tmoh; 1.81 + break; 1.82 + case SET_OPENTIMEOUT: 1.83 + ttmo_open = (long) value; 1.84 + case GET_OPENTIMEOUT: 1.85 + ret = (void *) ttmo_open; 1.86 + break; 1.87 + case SET_READTIMEOUT: 1.88 + ttmo_read = (long) value; 1.89 + case GET_READTIMEOUT: 1.90 + ret = (void *) ttmo_read; 1.91 + break; 1.92 + case SET_WRITETIMEOUT: 1.93 + ttmo_write = (long) value; 1.94 + case GET_WRITETIMEOUT: 1.95 + ret = (void *) ttmo_write; 1.96 + break; 1.97 + case SET_ALLOWREVERSEDNS: 1.98 + allowreversedns = (long) value; 1.99 + case GET_ALLOWREVERSEDNS: 1.100 + ret = (void *) allowreversedns; 1.101 + break; 1.102 + case SET_TCPDEBUG: 1.103 + tcpdebug = (long) value; 1.104 + case GET_TCPDEBUG: 1.105 + ret = (void *) tcpdebug; 1.106 + break; 1.107 + 1.108 + case SET_RSHTIMEOUT: 1.109 + rshtimeout = (long) value; 1.110 + case GET_RSHTIMEOUT: 1.111 + ret = (void *) rshtimeout; 1.112 + break; 1.113 + case SET_RSHCOMMAND: 1.114 + if (rshcommand) fs_give ((void **) &rshcommand); 1.115 + rshcommand = cpystr ((char *) value); 1.116 + case GET_RSHCOMMAND: 1.117 + ret = (void *) rshcommand; 1.118 + break; 1.119 + case SET_RSHPATH: 1.120 + if (rshpath) fs_give ((void **) &rshpath); 1.121 + rshpath = cpystr ((char *) value); 1.122 + case GET_RSHPATH: 1.123 + ret = (void *) rshpath; 1.124 + break; 1.125 + case SET_SSHTIMEOUT: 1.126 + sshtimeout = (long) value; 1.127 + case GET_SSHTIMEOUT: 1.128 + ret = (void *) sshtimeout; 1.129 + break; 1.130 + case SET_SSHCOMMAND: 1.131 + if (sshcommand) fs_give ((void **) &sshcommand); 1.132 + sshcommand = cpystr ((char *) value); 1.133 + case GET_SSHCOMMAND: 1.134 + ret = (void *) sshcommand; 1.135 + break; 1.136 + case SET_SSHPATH: 1.137 + if (sshpath) fs_give ((void **) &sshpath); 1.138 + sshpath = cpystr ((char *) value); 1.139 + case GET_SSHPATH: 1.140 + ret = (void *) sshpath; 1.141 + break; 1.142 + } 1.143 + return ret; 1.144 +} 1.145 + 1.146 +/* TCP/IP open 1.147 + * Accepts: host name 1.148 + * contact service name 1.149 + * contact port number and optional silent flag 1.150 + * Returns: TCP/IP stream if success else NIL 1.151 + */ 1.152 + 1.153 +TCPSTREAM *tcp_open (char *host,char *service,unsigned long port) 1.154 +{ 1.155 + TCPSTREAM *stream = NIL; 1.156 + int family; 1.157 + int sock = -1; 1.158 + int ctr = 0; 1.159 + int silent = (port & NET_SILENT) ? T : NIL; 1.160 + int *ctrp = (port & NET_NOOPENTIMEOUT) ? NIL : &ctr; 1.161 + char *s,*hostname,tmp[MAILTMPLEN]; 1.162 + void *adr; 1.163 + size_t adrlen; 1.164 + struct servent *sv = NIL; 1.165 + blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); 1.166 + void *data,*next; 1.167 + port &= 0xffff; /* erase flags */ 1.168 + /* lookup service */ 1.169 + if (service && (sv = getservbyname (service,"tcp"))) 1.170 + port = ntohs (sv->s_port); 1.171 + /* The domain literal form is used (rather than simply the dotted decimal 1.172 + as with other Unix programs) because it has to be a valid "host name" 1.173 + in mailsystem terminology. */ 1.174 + /* look like domain literal? */ 1.175 + if (host[0] == '[' && host[(strlen (host))-1] == ']') { 1.176 + strcpy (tmp,host+1); /* yes, copy number part */ 1.177 + tmp[(strlen (tmp))-1] = '\0'; 1.178 + if (adr = ip_stringtoaddr (tmp,&adrlen,&family)) { 1.179 + (*bn) (BLOCK_TCPOPEN,NIL); 1.180 + /* get an open socket for this system */ 1.181 + sock = tcp_socket_open (family,adr,adrlen,port,tmp,ctrp,hostname = host); 1.182 + (*bn) (BLOCK_NONE,NIL); 1.183 + fs_give ((void **) &adr); 1.184 + } 1.185 + else sprintf (tmp,"Bad format domain-literal: %.80s",host); 1.186 + } 1.187 + 1.188 + else { /* lookup host name */ 1.189 + if (tcpdebug) { 1.190 + sprintf (tmp,"DNS resolution %.80s",host); 1.191 + mm_log (tmp,TCPDEBUG); 1.192 + } 1.193 + (*bn) (BLOCK_DNSLOOKUP,NIL);/* quell alarms */ 1.194 + data = (*bn) (BLOCK_SENSITIVE,NIL); 1.195 + if (!(s = ip_nametoaddr (host,&adrlen,&family,&hostname,&next))) 1.196 + sprintf (tmp,"No such host as %.80s",host); 1.197 + (*bn) (BLOCK_NONSENSITIVE,data); 1.198 + (*bn) (BLOCK_NONE,NIL); 1.199 + if (s) { /* DNS resolution won? */ 1.200 + if (tcpdebug) mm_log ("DNS resolution done",TCPDEBUG); 1.201 + do { 1.202 + (*bn) (BLOCK_TCPOPEN,NIL); 1.203 + if (((sock = tcp_socket_open (family,s,adrlen,port,tmp,ctrp, 1.204 + hostname)) < 0) && 1.205 + (s = ip_nametoaddr (NIL,&adrlen,&family,&hostname,&next)) && 1.206 + !silent) mm_log (tmp,WARN); 1.207 + (*bn) (BLOCK_NONE,NIL); 1.208 + } while ((sock < 0) && s);/* repeat until success or no more addreses */ 1.209 + } 1.210 + } 1.211 + if (sock >= 0) { /* won */ 1.212 + stream = (TCPSTREAM *) memset (fs_get (sizeof (TCPSTREAM)),0, 1.213 + sizeof (TCPSTREAM)); 1.214 + stream->port = port; /* port number */ 1.215 + /* init sockets */ 1.216 + stream->tcpsi = stream->tcpso = sock; 1.217 + /* stash in the snuck-in byte */ 1.218 + if (stream->ictr = ctr) *(stream->iptr = stream->ibuf) = tmp[0]; 1.219 + /* copy official host name */ 1.220 + stream->host = cpystr (hostname); 1.221 + if (tcpdebug) mm_log ("Stream open and ready for read",TCPDEBUG); 1.222 + } 1.223 + else if (!silent) mm_log (tmp,ERROR); 1.224 + return stream; /* return success */ 1.225 +} 1.226 + 1.227 +/* Open a TCP socket 1.228 + * Accepts: protocol family 1.229 + * address to connect to 1.230 + * address length 1.231 + * port 1.232 + * scratch buffer 1.233 + * pointer to "first byte read in" storage or NIL 1.234 + * host name for error message 1.235 + * Returns: socket if success, else -1 with error string in scratch buffer 1.236 + */ 1.237 + 1.238 +int tcp_socket_open (int family,void *adr,size_t adrlen,unsigned short port, 1.239 + char *tmp,int *ctr,char *hst) 1.240 +{ 1.241 + int i,ti,sock,flgs; 1.242 + size_t len; 1.243 + time_t now; 1.244 + struct protoent *pt = getprotobyname ("tcp"); 1.245 + fd_set fds,efds; 1.246 + struct timeval tmo; 1.247 + struct sockaddr *sadr = ip_sockaddr (family,adr,adrlen,port,&len); 1.248 + blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); 1.249 + /* fetid Solaris */ 1.250 + void *data = (*bn) (BLOCK_SENSITIVE,NIL); 1.251 + sprintf (tmp,"Trying IP address [%s]",ip_sockaddrtostring (sadr)); 1.252 + mm_log (tmp,NIL); 1.253 + /* make a socket */ 1.254 + if ((sock = socket (sadr->sa_family,SOCK_STREAM,pt ? pt->p_proto : 0)) < 0) { 1.255 + sprintf (tmp,"Unable to create TCP socket: %s",strerror (errno)); 1.256 + (*bn) (BLOCK_NONSENSITIVE,data); 1.257 + } 1.258 + else if (sock >= FD_SETSIZE) {/* unselectable sockets are useless */ 1.259 + sprintf (tmp,"Unable to create selectable TCP socket (%d >= %d)", 1.260 + sock,FD_SETSIZE); 1.261 + (*bn) (BLOCK_NONSENSITIVE,data); 1.262 + close (sock); 1.263 + sock = -1; 1.264 + errno = EMFILE; 1.265 + } 1.266 + 1.267 + else { /* get current socket flags */ 1.268 + flgs = fcntl (sock,F_GETFL,0); 1.269 + /* set non-blocking if want open timeout */ 1.270 + if (ctr) fcntl (sock,F_SETFL,flgs | FNDELAY); 1.271 + /* open connection */ 1.272 + while ((i = connect (sock,sadr,len)) < 0 && (errno == EINTR)); 1.273 + (*bn) (BLOCK_NONSENSITIVE,data); 1.274 + if (i < 0) switch (errno) { /* failed? */ 1.275 + case EAGAIN: /* DG brain damage */ 1.276 + case EINPROGRESS: /* what we expect to happen */ 1.277 + case EALREADY: /* or another form of it */ 1.278 + case EISCONN: /* restart after interrupt? */ 1.279 + case EADDRINUSE: /* restart after interrupt? */ 1.280 + break; /* well, not really, it was interrupted */ 1.281 + default: 1.282 + sprintf (tmp,"Can't connect to %.80s,%u: %s",hst,(unsigned int) port, 1.283 + strerror (errno)); 1.284 + close (sock); /* flush socket */ 1.285 + sock = -1; 1.286 + } 1.287 + if ((sock >= 0) && ctr) { /* want open timeout? */ 1.288 + now = time (0); /* open timeout */ 1.289 + ti = ttmo_open ? now + ttmo_open : 0; 1.290 + tmo.tv_usec = 0; 1.291 + FD_ZERO (&fds); /* initialize selection vector */ 1.292 + FD_ZERO (&efds); /* handle errors too */ 1.293 + FD_SET (sock,&fds); /* block for error or readable */ 1.294 + FD_SET (sock,&efds); 1.295 + do { /* block under timeout */ 1.296 + tmo.tv_sec = ti ? ti - now : 0; 1.297 + i = select (sock+1,&fds,NIL,&efds,ti ? &tmo : NIL); 1.298 + now = time (0); /* fake timeout if interrupt & time expired */ 1.299 + if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0; 1.300 + } while ((i < 0) && (errno == EINTR)); 1.301 + if (i > 0) { /* success, make sure really connected */ 1.302 + /* restore blocking status */ 1.303 + fcntl (sock,F_SETFL,flgs); 1.304 + /* This used to be a zero-byte read(), but that crashes Solaris */ 1.305 + /* get socket status */ 1.306 + while (((i = *ctr = read (sock,tmp,1)) < 0) && (errno == EINTR)); 1.307 + } 1.308 + if (i <= 0) { /* timeout or error? */ 1.309 + i = i ? errno : ETIMEDOUT;/* determine error code */ 1.310 + close (sock); /* flush socket */ 1.311 + sock = -1; 1.312 + errno = i; /* return error code */ 1.313 + sprintf (tmp,"Connection failed to %.80s,%lu: %s",hst, 1.314 + (unsigned long) port,strerror (errno)); 1.315 + } 1.316 + } 1.317 + } 1.318 + fs_give ((void **) &sadr); 1.319 + return sock; /* return the socket */ 1.320 +} 1.321 + 1.322 +/* TCP/IP authenticated open 1.323 + * Accepts: host name 1.324 + * service name 1.325 + * returned user name buffer 1.326 + * Returns: TCP/IP stream if success else NIL 1.327 + */ 1.328 + 1.329 +#define MAXARGV 20 1.330 + 1.331 +TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf) 1.332 +{ 1.333 + TCPSTREAM *stream = NIL; 1.334 + void *adr; 1.335 + char host[MAILTMPLEN],tmp[MAILTMPLEN],*path,*argv[MAXARGV+1],*r; 1.336 + int i,ti,pipei[2],pipeo[2]; 1.337 + size_t len; 1.338 + time_t now; 1.339 + struct timeval tmo; 1.340 + fd_set fds,efds; 1.341 + blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); 1.342 +#ifdef SSHPATH /* ssh path defined yet? */ 1.343 + if (!sshpath) sshpath = cpystr (SSHPATH); 1.344 +#endif 1.345 +#ifdef RSHPATH /* rsh path defined yet? */ 1.346 + if (!rshpath) rshpath = cpystr (RSHPATH); 1.347 +#endif 1.348 + if (*service == '*') { /* want ssh? */ 1.349 + /* return immediately if ssh disabled */ 1.350 + if (!(sshpath && (ti = sshtimeout))) return NIL; 1.351 + /* ssh command prototype defined yet? */ 1.352 + if (!sshcommand) sshcommand = cpystr ("%s %s -l %s exec /etc/r%sd"); 1.353 + } 1.354 + /* want rsh? */ 1.355 + else if (rshpath && (ti = rshtimeout)) { 1.356 + /* rsh command prototype defined yet? */ 1.357 + if (!rshcommand) rshcommand = cpystr ("%s %s -l %s exec /etc/r%sd"); 1.358 + } 1.359 + else return NIL; /* rsh disabled */ 1.360 + /* look like domain literal? */ 1.361 + if (mb->host[0] == '[' && mb->host[i = (strlen (mb->host))-1] == ']') { 1.362 + strcpy (host,mb->host+1); /* yes, copy without brackets */ 1.363 + host[i-1] = '\0'; 1.364 + /* validate domain literal */ 1.365 + if (adr = ip_stringtoaddr (host,&len,&i)) fs_give ((void **) &adr); 1.366 + else { 1.367 + sprintf (tmp,"Bad format domain-literal: %.80s",host); 1.368 + mm_log (tmp,ERROR); 1.369 + return NIL; 1.370 + } 1.371 + } 1.372 + else strcpy (host,tcp_canonical (mb->host)); 1.373 + 1.374 + if (*service == '*') /* build ssh command */ 1.375 + sprintf (tmp,sshcommand,sshpath,host, 1.376 + mb->user[0] ? mb->user : myusername (),service + 1); 1.377 + else sprintf (tmp,rshcommand,rshpath,host, 1.378 + mb->user[0] ? mb->user : myusername (),service); 1.379 + if (tcpdebug) { 1.380 + char msg[MAILTMPLEN]; 1.381 + sprintf (msg,"Trying %.100s",tmp); 1.382 + mm_log (msg,TCPDEBUG); 1.383 + } 1.384 + /* parse command into argv */ 1.385 + for (i = 1,path = argv[0] = strtok_r (tmp," ",&r); 1.386 + (i < MAXARGV) && (argv[i] = strtok_r (NIL," ",&r)); i++); 1.387 + argv[i] = NIL; /* make sure argv tied off */ 1.388 + /* make command pipes */ 1.389 + if (pipe (pipei) < 0) return NIL; 1.390 + if ((pipei[0] >= FD_SETSIZE) || (pipei[1] >= FD_SETSIZE) || 1.391 + (pipe (pipeo) < 0)) { 1.392 + close (pipei[0]); close (pipei[1]); 1.393 + return NIL; 1.394 + } 1.395 + (*bn) (BLOCK_TCPOPEN,NIL); /* quell alarm up here for NeXT */ 1.396 + if ((pipeo[0] >= FD_SETSIZE) || (pipeo[1] >= FD_SETSIZE) || 1.397 + ((i = fork ()) < 0)) { /* make inferior process */ 1.398 + close (pipei[0]); close (pipei[1]); 1.399 + close (pipeo[0]); close (pipeo[1]); 1.400 + (*bn) (BLOCK_NONE,NIL); 1.401 + return NIL; 1.402 + } 1.403 + if (!i) { /* if child */ 1.404 + alarm (0); /* never have alarms in children */ 1.405 + if (!fork ()) { /* make grandchild so it's inherited by init */ 1.406 + int cf; /* don't alter parent vars in case vfork() */ 1.407 + int maxfd = max (20,max (max(pipei[0],pipei[1]),max(pipeo[0],pipeo[1]))); 1.408 + dup2 (pipei[1],1); /* parent's input is my output */ 1.409 + dup2 (pipei[1],2); /* parent's input is my error output too */ 1.410 + dup2 (pipeo[0],0); /* parent's output is my input */ 1.411 + /* close all unnecessary descriptors */ 1.412 + for (cf = 3; cf <= maxfd; cf++) close (cf); 1.413 + setpgrp (0,getpid ()); /* be our own process group */ 1.414 + _exit (execv (path,argv));/* now run it */ 1.415 + } 1.416 + _exit (1); /* child is done */ 1.417 + } 1.418 + grim_pid_reap (i,NIL); /* reap child; grandchild now owned by init */ 1.419 + close (pipei[1]); /* close child's side of the pipes */ 1.420 + close (pipeo[0]); 1.421 + 1.422 + /* create TCP/IP stream */ 1.423 + stream = (TCPSTREAM *) memset (fs_get (sizeof (TCPSTREAM)),0, 1.424 + sizeof (TCPSTREAM)); 1.425 + /* copy remote host name from argument */ 1.426 + stream->remotehost = cpystr (stream->host = cpystr (host)); 1.427 + stream->tcpsi = pipei[0]; /* init sockets */ 1.428 + stream->tcpso = pipeo[1]; 1.429 + stream->ictr = 0; /* init input counter */ 1.430 + stream->port = 0xffffffff; /* no port number */ 1.431 + ti += now = time (0); /* open timeout */ 1.432 + tmo.tv_usec = 0; /* initialize usec timeout */ 1.433 + FD_ZERO (&fds); /* initialize selection vector */ 1.434 + FD_ZERO (&efds); /* handle errors too */ 1.435 + FD_SET (stream->tcpsi,&fds); /* set bit in selection vector */ 1.436 + FD_SET (stream->tcpsi,&efds); /* set bit in error selection vector */ 1.437 + FD_SET (stream->tcpso,&efds); /* set bit in error selection vector */ 1.438 + do { /* block under timeout */ 1.439 + tmo.tv_sec = ti - now; 1.440 + i = select (max (stream->tcpsi,stream->tcpso)+1,&fds,NIL,&efds,&tmo); 1.441 + now = time (0); /* fake timeout if interrupt & time expired */ 1.442 + if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0; 1.443 + } while ((i < 0) && (errno == EINTR)); 1.444 + if (i <= 0) { /* timeout or error? */ 1.445 + sprintf (tmp,i ? "error in %s to IMAP server" : 1.446 + "%s to IMAP server timed out",(*service == '*') ? "ssh" : "rsh"); 1.447 + mm_log (tmp,WARN); 1.448 + tcp_close (stream); /* punt stream */ 1.449 + stream = NIL; 1.450 + } 1.451 + (*bn) (BLOCK_NONE,NIL); 1.452 + /* return user name */ 1.453 + strcpy (usrbuf,mb->user[0] ? mb->user : myusername ()); 1.454 + return stream; /* return success */ 1.455 +} 1.456 + 1.457 +/* TCP receive line 1.458 + * Accepts: TCP stream 1.459 + * Returns: text line string or NIL if failure 1.460 + */ 1.461 + 1.462 +char *tcp_getline (TCPSTREAM *stream) 1.463 +{ 1.464 + unsigned long n,contd; 1.465 + char *ret = tcp_getline_work (stream,&n,&contd); 1.466 + if (ret && contd) { /* got a line needing continuation? */ 1.467 + STRINGLIST *stl = mail_newstringlist (); 1.468 + STRINGLIST *stc = stl; 1.469 + do { /* collect additional lines */ 1.470 + stc->text.data = (unsigned char *) ret; 1.471 + stc->text.size = n; 1.472 + stc = stc->next = mail_newstringlist (); 1.473 + ret = tcp_getline_work (stream,&n,&contd); 1.474 + } while (ret && contd); 1.475 + if (ret) { /* stash final part of line on list */ 1.476 + stc->text.data = (unsigned char *) ret; 1.477 + stc->text.size = n; 1.478 + /* determine how large a buffer we need */ 1.479 + for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size; 1.480 + ret = fs_get (n + 1); /* copy parts into buffer */ 1.481 + for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next) 1.482 + memcpy (ret + n,stc->text.data,stc->text.size); 1.483 + ret[n] = '\0'; 1.484 + } 1.485 + mail_free_stringlist (&stl);/* either way, done with list */ 1.486 + } 1.487 + return ret; 1.488 +} 1.489 + 1.490 +/* TCP receive line or partial line 1.491 + * Accepts: TCP stream 1.492 + * pointer to return size 1.493 + * pointer to return continuation flag 1.494 + * Returns: text line string, size and continuation flag, or NIL if failure 1.495 + */ 1.496 + 1.497 +static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size, 1.498 + long *contd) 1.499 +{ 1.500 + unsigned long n; 1.501 + char *s,*ret,c,d; 1.502 + *contd = NIL; /* assume no continuation */ 1.503 + /* make sure have data */ 1.504 + if (!tcp_getdata (stream)) return NIL; 1.505 + for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) { 1.506 + d = *stream->iptr++; /* slurp another character */ 1.507 + if ((c == '\015') && (d == '\012')) { 1.508 + ret = (char *) fs_get (n--); 1.509 + memcpy (ret,s,*size = n); /* copy into a free storage string */ 1.510 + ret[n] = '\0'; /* tie off string with null */ 1.511 + return ret; 1.512 + } 1.513 + } 1.514 + /* copy partial string from buffer */ 1.515 + memcpy ((ret = (char *) fs_get (n)),s,*size = n); 1.516 + /* get more data from the net */ 1.517 + if (!tcp_getdata (stream)) fs_give ((void **) &ret); 1.518 + /* special case of newline broken by buffer */ 1.519 + else if ((c == '\015') && (*stream->iptr == '\012')) { 1.520 + stream->iptr++; /* eat the line feed */ 1.521 + stream->ictr--; 1.522 + ret[*size = --n] = '\0'; /* tie off string with null */ 1.523 + } 1.524 + else *contd = LONGT; /* continuation needed */ 1.525 + return ret; 1.526 +} 1.527 + 1.528 +/* TCP/IP receive buffer 1.529 + * Accepts: TCP/IP stream 1.530 + * size in bytes 1.531 + * buffer to read into 1.532 + * Returns: T if success, NIL otherwise 1.533 + */ 1.534 + 1.535 +long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *s) 1.536 +{ 1.537 + unsigned long n; 1.538 + /* make sure socket still alive */ 1.539 + if (stream->tcpsi < 0) return NIL; 1.540 + /* can transfer bytes from buffer? */ 1.541 + if (n = min (size,stream->ictr)) { 1.542 + memcpy (s,stream->iptr,n); /* yes, slurp as much as we can from it */ 1.543 + s += n; /* update pointer */ 1.544 + stream->iptr +=n; 1.545 + size -= n; /* update # of bytes to do */ 1.546 + stream->ictr -=n; 1.547 + } 1.548 + if (size) { 1.549 + int i; 1.550 + fd_set fds,efds; 1.551 + struct timeval tmo; 1.552 + time_t t = time (0); 1.553 + blocknotify_t bn=(blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); 1.554 + (*bn) (BLOCK_TCPREAD,NIL); 1.555 + while (size > 0) { /* until request satisfied */ 1.556 + time_t tl = time (0); 1.557 + time_t now = tl; 1.558 + time_t ti = ttmo_read ? now + ttmo_read : 0; 1.559 + if (tcpdebug) mm_log ("Reading TCP buffer",TCPDEBUG); 1.560 + tmo.tv_usec = 0; 1.561 + FD_ZERO (&fds); /* initialize selection vector */ 1.562 + FD_ZERO (&efds); /* handle errors too */ 1.563 + /* set bit in selection vectors */ 1.564 + FD_SET (stream->tcpsi,&fds); 1.565 + FD_SET (stream->tcpsi,&efds); 1.566 + errno = NIL; /* initially no error */ 1.567 + do { /* block under timeout */ 1.568 + tmo.tv_sec = ti ? ti - now : 0; 1.569 + i = select (stream->tcpsi+1,&fds,NIL,&efds,ti ? &tmo : NIL); 1.570 + now = time (0); /* fake timeout if interrupt & time expired */ 1.571 + if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0; 1.572 + } while ((i < 0) && (errno == EINTR)); 1.573 + if (i) { /* non-timeout result from select? */ 1.574 + if (i > 0) /* read what we can */ 1.575 + while (((i = read (stream->tcpsi,s,(int) min (maxposint,size))) < 0) 1.576 + && (errno == EINTR)); 1.577 + if (i <= 0) { /* error seen? */ 1.578 + if (tcpdebug) { 1.579 + char tmp[MAILTMPLEN]; 1.580 + if (i) sprintf (s = tmp,"TCP buffer read I/O error %d",errno); 1.581 + else s = "TCP buffer read end of file"; 1.582 + mm_log (s,TCPDEBUG); 1.583 + } 1.584 + return tcp_abort (stream); 1.585 + } 1.586 + s += i; /* success, point at new place to write */ 1.587 + size -= i; /* reduce byte count */ 1.588 + if (tcpdebug) mm_log ("Successfully read TCP buffer",TCPDEBUG); 1.589 + } 1.590 + /* timeout, punt unless told not to */ 1.591 + else if (!tmoh || !(*tmoh) (now - t,now - tl)) { 1.592 + if (tcpdebug) mm_log ("TCP buffer read timeout",TCPDEBUG); 1.593 + return tcp_abort (stream); 1.594 + } 1.595 + } 1.596 + (*bn) (BLOCK_NONE,NIL); 1.597 + } 1.598 + *s = '\0'; /* tie off string */ 1.599 + return LONGT; 1.600 +} 1.601 + 1.602 +/* TCP/IP receive data 1.603 + * Accepts: TCP/IP stream 1.604 + * Returns: T if success, NIL otherwise 1.605 + */ 1.606 + 1.607 +long tcp_getdata (TCPSTREAM *stream) 1.608 +{ 1.609 + int i; 1.610 + fd_set fds,efds; 1.611 + struct timeval tmo; 1.612 + time_t t = time (0); 1.613 + blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); 1.614 + if (stream->tcpsi < 0) return NIL; 1.615 + (*bn) (BLOCK_TCPREAD,NIL); 1.616 + while (stream->ictr < 1) { /* if nothing in the buffer */ 1.617 + time_t tl = time (0); /* start of request */ 1.618 + time_t now = tl; 1.619 + time_t ti = ttmo_read ? now + ttmo_read : 0; 1.620 + if (tcpdebug) mm_log ("Reading TCP data",TCPDEBUG); 1.621 + tmo.tv_usec = 0; 1.622 + FD_ZERO (&fds); /* initialize selection vector */ 1.623 + FD_ZERO (&efds); /* handle errors too */ 1.624 + FD_SET (stream->tcpsi,&fds);/* set bit in selection vectors */ 1.625 + FD_SET (stream->tcpsi,&efds); 1.626 + errno = NIL; /* initially no error */ 1.627 + do { /* block under timeout */ 1.628 + tmo.tv_sec = ti ? ti - now : 0; 1.629 + i = select (stream->tcpsi+1,&fds,NIL,&efds,ti ? &tmo : NIL); 1.630 + now = time (0); /* fake timeout if interrupt & time expired */ 1.631 + if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0; 1.632 + } while ((i < 0) && (errno == EINTR)); 1.633 + if (i) { /* non-timeout result from select? */ 1.634 + /* read what we can */ 1.635 + if (i > 0) while (((i = read (stream->tcpsi,stream->ibuf,BUFLEN)) < 0) && 1.636 + (errno == EINTR)); 1.637 + if (i <= 0) { /* error seen? */ 1.638 + if (tcpdebug) { 1.639 + char *s,tmp[MAILTMPLEN]; 1.640 + if (i) sprintf (s = tmp,"TCP data read I/O error %d",errno); 1.641 + else s = "TCP data read end of file"; 1.642 + mm_log (s,TCPDEBUG); 1.643 + } 1.644 + return tcp_abort (stream); 1.645 + } 1.646 + stream->ictr = i; /* success, set new count and pointer */ 1.647 + stream->iptr = stream->ibuf; 1.648 + if (tcpdebug) mm_log ("Successfully read TCP data",TCPDEBUG); 1.649 + } 1.650 + /* timeout, punt unless told not to */ 1.651 + else if (!tmoh || !(*tmoh) (now - t,now - tl)) { 1.652 + if (tcpdebug) mm_log ("TCP data read timeout",TCPDEBUG); 1.653 + return tcp_abort (stream);/* error or timeout no-continue */ 1.654 + } 1.655 + } 1.656 + (*bn) (BLOCK_NONE,NIL); 1.657 + return T; 1.658 +} 1.659 + 1.660 +/* TCP/IP send string as record 1.661 + * Accepts: TCP/IP stream 1.662 + * string pointer 1.663 + * Returns: T if success else NIL 1.664 + */ 1.665 + 1.666 +long tcp_soutr (TCPSTREAM *stream,char *string) 1.667 +{ 1.668 + return tcp_sout (stream,string,(unsigned long) strlen (string)); 1.669 +} 1.670 + 1.671 + 1.672 +/* TCP/IP send string 1.673 + * Accepts: TCP/IP stream 1.674 + * string pointer 1.675 + * byte count 1.676 + * Returns: T if success else NIL 1.677 + */ 1.678 + 1.679 +long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size) 1.680 +{ 1.681 + int i; 1.682 + fd_set fds,efds; 1.683 + struct timeval tmo; 1.684 + time_t t = time (0); 1.685 + blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); 1.686 + if (stream->tcpso < 0) return NIL; 1.687 + (*bn) (BLOCK_TCPWRITE,NIL); 1.688 + while (size > 0) { /* until request satisfied */ 1.689 + time_t tl = time (0); /* start of request */ 1.690 + time_t now = tl; 1.691 + time_t ti = ttmo_write ? now + ttmo_write : 0; 1.692 + if (tcpdebug) mm_log ("Writing to TCP",TCPDEBUG); 1.693 + tmo.tv_usec = 0; 1.694 + FD_ZERO (&fds); /* initialize selection vector */ 1.695 + FD_ZERO (&efds); /* handle errors too */ 1.696 + FD_SET (stream->tcpso,&fds);/* set bit in selection vector */ 1.697 + FD_SET(stream->tcpso,&efds);/* set bit in error selection vector */ 1.698 + errno = NIL; /* block and write */ 1.699 + do { /* block under timeout */ 1.700 + tmo.tv_sec = ti ? ti - now : 0; 1.701 + i = select (stream->tcpso+1,NIL,&fds,&efds,ti ? &tmo : NIL); 1.702 + now = time (0); /* fake timeout if interrupt & time expired */ 1.703 + if ((i < 0) && (errno == EINTR) && ti && (ti <= now)) i = 0; 1.704 + } while ((i < 0) && (errno == EINTR)); 1.705 + if (i) { /* non-timeout result from select? */ 1.706 + /* write what we can */ 1.707 + if (i > 0) while (((i = write (stream->tcpso,string,size)) < 0) && 1.708 + (errno == EINTR)); 1.709 + if (i <= 0) { /* error seen? */ 1.710 + if (tcpdebug) { 1.711 + char tmp[MAILTMPLEN]; 1.712 + sprintf (tmp,"TCP write I/O error %d",errno); 1.713 + mm_log (tmp,TCPDEBUG); 1.714 + } 1.715 + return tcp_abort (stream); 1.716 + } 1.717 + string += i; /* how much we sent */ 1.718 + size -= i; /* count this size */ 1.719 + if (tcpdebug) mm_log ("successfully wrote to TCP",TCPDEBUG); 1.720 + } 1.721 + /* timeout, punt unless told not to */ 1.722 + else if (!tmoh || !(*tmoh) (now - t,now - tl)) { 1.723 + if (tcpdebug) mm_log ("TCP write timeout",TCPDEBUG); 1.724 + return tcp_abort (stream); 1.725 + } 1.726 + } 1.727 + (*bn) (BLOCK_NONE,NIL); 1.728 + return T; /* all done */ 1.729 +} 1.730 + 1.731 +/* TCP/IP close 1.732 + * Accepts: TCP/IP stream 1.733 + */ 1.734 + 1.735 +void tcp_close (TCPSTREAM *stream) 1.736 +{ 1.737 + tcp_abort (stream); /* nuke the stream */ 1.738 + /* flush host names */ 1.739 + if (stream->host) fs_give ((void **) &stream->host); 1.740 + if (stream->remotehost) fs_give ((void **) &stream->remotehost); 1.741 + if (stream->localhost) fs_give ((void **) &stream->localhost); 1.742 + fs_give ((void **) &stream); /* flush the stream */ 1.743 +} 1.744 + 1.745 + 1.746 +/* TCP/IP abort stream 1.747 + * Accepts: TCP/IP stream 1.748 + * Returns: NIL always 1.749 + */ 1.750 + 1.751 +long tcp_abort (TCPSTREAM *stream) 1.752 +{ 1.753 + blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); 1.754 + if (stream->tcpsi >= 0) { /* no-op if no socket */ 1.755 + (*bn) (BLOCK_TCPCLOSE,NIL); 1.756 + close (stream->tcpsi); /* nuke the socket */ 1.757 + if (stream->tcpsi != stream->tcpso) close (stream->tcpso); 1.758 + stream->tcpsi = stream->tcpso = -1; 1.759 + } 1.760 + (*bn) (BLOCK_NONE,NIL); 1.761 + return NIL; 1.762 +} 1.763 + 1.764 +/* TCP/IP get host name 1.765 + * Accepts: TCP/IP stream 1.766 + * Returns: host name for this stream 1.767 + */ 1.768 + 1.769 +char *tcp_host (TCPSTREAM *stream) 1.770 +{ 1.771 + return stream->host; /* use tcp_remotehost() if want guarantees */ 1.772 +} 1.773 + 1.774 + 1.775 +/* TCP/IP get remote host name 1.776 + * Accepts: TCP/IP stream 1.777 + * Returns: host name for this stream 1.778 + */ 1.779 + 1.780 +char *tcp_remotehost (TCPSTREAM *stream) 1.781 +{ 1.782 + if (!stream->remotehost) { 1.783 + size_t sadrlen; 1.784 + struct sockaddr *sadr = ip_newsockaddr (&sadrlen); 1.785 + stream->remotehost = /* get socket's peer name */ 1.786 + getpeername (stream->tcpsi,sadr,(void *) &sadrlen) ? 1.787 + cpystr (stream->host) : tcp_name (sadr,NIL); 1.788 + fs_give ((void **) &sadr); 1.789 + } 1.790 + return stream->remotehost; 1.791 +} 1.792 + 1.793 + 1.794 +/* TCP/IP return port for this stream 1.795 + * Accepts: TCP/IP stream 1.796 + * Returns: port number for this stream 1.797 + */ 1.798 + 1.799 +unsigned long tcp_port (TCPSTREAM *stream) 1.800 +{ 1.801 + return stream->port; /* return port number */ 1.802 +} 1.803 + 1.804 + 1.805 +/* TCP/IP get local host name 1.806 + * Accepts: TCP/IP stream 1.807 + * Returns: local host name 1.808 + */ 1.809 + 1.810 +char *tcp_localhost (TCPSTREAM *stream) 1.811 +{ 1.812 + if (!stream->localhost) { 1.813 + size_t sadrlen; 1.814 + struct sockaddr *sadr = ip_newsockaddr (&sadrlen); 1.815 + stream->localhost = /* get socket's name */ 1.816 + ((stream->port & 0xffff000) || 1.817 + getsockname (stream->tcpsi,sadr,(void *) &sadrlen)) ? 1.818 + cpystr (mylocalhost ()) : tcp_name (sadr,NIL); 1.819 + fs_give ((void **) &sadr); 1.820 + } 1.821 + return stream->localhost; /* return local host name */ 1.822 +} 1.823 + 1.824 +/* TCP/IP get client host address (server calls only) 1.825 + * Returns: client host address 1.826 + */ 1.827 + 1.828 +char *tcp_clientaddr () 1.829 +{ 1.830 + if (!myClientAddr) { 1.831 + size_t sadrlen; 1.832 + struct sockaddr *sadr = ip_newsockaddr (&sadrlen); 1.833 + if (getpeername (0,sadr,(void *) &sadrlen)) 1.834 + myClientAddr = cpystr ("UNKNOWN"); 1.835 + else { /* get stdin's peer name */ 1.836 + myClientAddr = cpystr (ip_sockaddrtostring (sadr)); 1.837 + if (myClientPort < 0) myClientPort = ip_sockaddrtoport (sadr); 1.838 + } 1.839 + fs_give ((void **) &sadr); 1.840 + } 1.841 + return myClientAddr; 1.842 +} 1.843 + 1.844 + 1.845 +/* TCP/IP get client host name (server calls only) 1.846 + * Returns: client host name 1.847 + */ 1.848 + 1.849 +char *tcp_clienthost () 1.850 +{ 1.851 + if (!myClientHost) { 1.852 + size_t sadrlen; 1.853 + struct sockaddr *sadr = ip_newsockaddr (&sadrlen); 1.854 + if (getpeername (0,sadr,(void *) &sadrlen)) { 1.855 + char *s,*t,*v,tmp[MAILTMPLEN]; 1.856 + if ((s = getenv (t = "SSH_CLIENT")) || 1.857 + (s = getenv (t = "KRB5REMOTEADDR")) || 1.858 + (s = getenv (t = "SSH2_CLIENT"))) { 1.859 + if (v = strchr (s,' ')) *v = '\0'; 1.860 + sprintf (v = tmp,"%.80s=%.80s",t,s); 1.861 + } 1.862 + else v = "UNKNOWN"; 1.863 + myClientHost = cpystr (v); 1.864 + } 1.865 + else { /* get stdin's peer name */ 1.866 + myClientHost = tcp_name (sadr,T); 1.867 + if (!myClientAddr) myClientAddr = cpystr (ip_sockaddrtostring (sadr)); 1.868 + if (myClientPort < 0) myClientPort = ip_sockaddrtoport (sadr); 1.869 + } 1.870 + fs_give ((void **) &sadr); 1.871 + } 1.872 + return myClientHost; 1.873 +} 1.874 + 1.875 + 1.876 +/* TCP/IP get client port number (server calls only) 1.877 + * Returns: client port number 1.878 + */ 1.879 + 1.880 +long tcp_clientport () 1.881 +{ 1.882 + if (!myClientHost && !myClientAddr) tcp_clientaddr (); 1.883 + return myClientPort; 1.884 +} 1.885 + 1.886 +/* TCP/IP get server host address (server calls only) 1.887 + * Returns: server host address 1.888 + */ 1.889 + 1.890 +char *tcp_serveraddr () 1.891 +{ 1.892 + if (!myServerAddr) { 1.893 + size_t sadrlen; 1.894 + struct sockaddr *sadr = ip_newsockaddr (&sadrlen); 1.895 + if (getsockname (0,sadr,(void *) &sadrlen)) 1.896 + myServerAddr = cpystr ("UNKNOWN"); 1.897 + else { /* get stdin's name */ 1.898 + myServerAddr = cpystr (ip_sockaddrtostring (sadr)); 1.899 + if (myServerPort < 0) myServerPort = ip_sockaddrtoport (sadr); 1.900 + } 1.901 + fs_give ((void **) &sadr); 1.902 + } 1.903 + return myServerAddr; 1.904 +} 1.905 + 1.906 + 1.907 +/* TCP/IP get server host name (server calls only) 1.908 + * Returns: server host name 1.909 + */ 1.910 + 1.911 +char *tcp_serverhost () 1.912 +{ 1.913 + if (!myServerHost) { /* once-only */ 1.914 + size_t sadrlen; 1.915 + struct sockaddr *sadr = ip_newsockaddr (&sadrlen); 1.916 + /* get stdin's name */ 1.917 + if (getsockname (0,sadr,(void *) &sadrlen)) 1.918 + myServerHost = cpystr (mylocalhost ()); 1.919 + else { /* get stdin's name */ 1.920 + myServerHost = tcp_name (sadr,NIL); 1.921 + if (!myServerAddr) myServerAddr = cpystr (ip_sockaddrtostring (sadr)); 1.922 + if (myServerPort < 0) myServerPort = ip_sockaddrtoport (sadr); 1.923 + } 1.924 + fs_give ((void **) &sadr); 1.925 + } 1.926 + return myServerHost; 1.927 +} 1.928 + 1.929 + 1.930 +/* TCP/IP get server port number (server calls only) 1.931 + * Returns: server port number 1.932 + */ 1.933 + 1.934 +long tcp_serverport () 1.935 +{ 1.936 + if (!myServerHost && !myServerAddr) tcp_serveraddr (); 1.937 + return myServerPort; 1.938 +} 1.939 + 1.940 +/* TCP/IP return canonical form of host name 1.941 + * Accepts: host name 1.942 + * Returns: canonical form of host name 1.943 + */ 1.944 + 1.945 +char *tcp_canonical (char *name) 1.946 +{ 1.947 + char *ret,host[MAILTMPLEN]; 1.948 + blocknotify_t bn = (blocknotify_t) mail_parameters (NIL,GET_BLOCKNOTIFY,NIL); 1.949 + void *data; 1.950 + /* look like domain literal? */ 1.951 + if (name[0] == '[' && name[strlen (name) - 1] == ']') return name; 1.952 + (*bn) (BLOCK_DNSLOOKUP,NIL); /* quell alarms */ 1.953 + data = (*bn) (BLOCK_SENSITIVE,NIL); 1.954 + if (tcpdebug) { 1.955 + sprintf (host,"DNS canonicalization %.80s",name); 1.956 + mm_log (host,TCPDEBUG); 1.957 + } 1.958 + /* get canonical name */ 1.959 + if (!ip_nametoaddr (name,NIL,NIL,&ret,NIL)) ret = name; 1.960 + (*bn) (BLOCK_NONSENSITIVE,data); 1.961 + (*bn) (BLOCK_NONE,NIL); /* alarms OK now */ 1.962 + if (tcpdebug) mm_log ("DNS canonicalization done",TCPDEBUG); 1.963 + return ret; 1.964 +} 1.965 + 1.966 +/* TCP/IP return name from socket 1.967 + * Accepts: socket 1.968 + * verbose flag 1.969 + * Returns: cpystr name 1.970 + */ 1.971 + 1.972 +char *tcp_name (struct sockaddr *sadr,long flag) 1.973 +{ 1.974 + char *ret,*t,adr[MAILTMPLEN],tmp[MAILTMPLEN]; 1.975 + sprintf (ret = adr,"[%.80s]",ip_sockaddrtostring (sadr)); 1.976 + if (allowreversedns) { 1.977 + blocknotify_t bn = (blocknotify_t)mail_parameters(NIL,GET_BLOCKNOTIFY,NIL); 1.978 + void *data; 1.979 + if (tcpdebug) { 1.980 + sprintf (tmp,"Reverse DNS resolution %s",adr); 1.981 + mm_log (tmp,TCPDEBUG); 1.982 + } 1.983 + (*bn) (BLOCK_DNSLOOKUP,NIL);/* quell alarms */ 1.984 + data = (*bn) (BLOCK_SENSITIVE,NIL); 1.985 + /* translate address to name */ 1.986 + if (t = tcp_name_valid (ip_sockaddrtoname (sadr))) { 1.987 + /* produce verbose form if needed */ 1.988 + if (flag) sprintf (ret = tmp,"%s %s",t,adr); 1.989 + else ret = t; 1.990 + } 1.991 + (*bn) (BLOCK_NONSENSITIVE,data); 1.992 + (*bn) (BLOCK_NONE,NIL); /* alarms OK now */ 1.993 + if (tcpdebug) mm_log ("Reverse DNS resolution done",TCPDEBUG); 1.994 + } 1.995 + return cpystr (ret); 1.996 +} 1.997 + 1.998 + 1.999 +/* TCP/IP validate name 1.1000 + * Accepts: domain name 1.1001 + * Returns: name if valid, NIL otherwise 1.1002 + */ 1.1003 + 1.1004 +char *tcp_name_valid (char *s) 1.1005 +{ 1.1006 + int c; 1.1007 + char *ret,*tail; 1.1008 + /* must be non-empty and not too long */ 1.1009 + if ((ret = (s && *s) ? s : NIL) && (tail = ret + NETMAXHOST)) { 1.1010 + /* must be alnum, dot, or hyphen */ 1.1011 + while ((c = *s++) && (s <= tail) && 1.1012 + (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) || 1.1013 + ((c >= '0') && (c <= '9')) || (c == '-') || (c == '.'))); 1.1014 + if (c) ret = NIL; 1.1015 + } 1.1016 + return ret; 1.1017 +} 1.1018 + 1.1019 +/* TCP/IP check if client is given host name 1.1020 + * Accepts: candidate host name 1.1021 + * Returns: T if match, NIL otherwise 1.1022 + */ 1.1023 + 1.1024 +long tcp_isclienthost (char *host) 1.1025 +{ 1.1026 + int family; 1.1027 + size_t adrlen,sadrlen,len; 1.1028 + void *adr,*next; 1.1029 + struct sockaddr *sadr; 1.1030 + long ret = NIL; 1.1031 + /* make sure that myClientAddr is set */ 1.1032 + if (tcp_clienthost () && myClientAddr) 1.1033 + /* get sockaddr of client */ 1.1034 + for (adr = ip_nametoaddr (host,&adrlen,&family,NIL,&next); adr && !ret; 1.1035 + adr = ip_nametoaddr (NIL,&adrlen,&family,NIL,&next)) { 1.1036 + /* build sockaddr of given address */ 1.1037 + sadr = ip_sockaddr (family,adr,adrlen,1,&len); 1.1038 + if (!strcmp (myClientAddr,ip_sockaddrtostring (sadr))) ret = LONGT; 1.1039 + fs_give ((void **) &sadr); /* done with client sockaddr */ 1.1040 + } 1.1041 + return ret; 1.1042 +} 1.1043 + 1.1044 +/* Following statement must be at end of this module */ 1.1045 + 1.1046 +#undef fork /* undo any use of vfork() */