Added all of the MH sources, including RCS files, in
[mmh] / docs / historical / mh-6.8.5 / zotnet / mts / client.c
1 /* client.c - connect to a server */
2 #ifndef lint
3 static char ident[] = "@(#)$Id: client.c,v 1.22 1995/12/06 22:15:26 jromine Exp shettich $";
4 #endif  /* lint */
5
6 #if     defined(SYS5) && defined(AUX)
7 #define u_short ushort
8 #define u_long  ulong
9 #endif
10
11
12 #if     defined(BSD42) || defined(SOCKETS)
13 #include "../h/strings.h"
14 #include <stdio.h>
15 #include "mts.h"
16 #include <errno.h>
17 #include <sys/types.h>
18 #include <sys/socket.h>
19 #include <netinet/in.h>
20 #include <netdb.h>
21 #ifndef hpux
22 #include <arpa/inet.h>
23 #endif
24
25 #ifdef  HESIOD
26 #include <hesiod.h>
27 #endif
28
29 #ifdef KPOP
30 #include <krb.h>
31 #include <ctype.h>
32
33 static CREDENTIALS cred;
34 static MSG_DAT msg_data;
35 static KTEXT ticket = (KTEXT)NULL;
36 static Key_schedule schedule;
37 #endif  /* KPOP */
38
39 #define NOTOK   (-1)
40 #define OK      0
41 #define DONE    1
42
43 #define TRUE    1
44 #define FALSE   0
45
46 #define OOPS1   (-2)
47 #define OOPS2   (-3)
48
49 #define MAXARGS         1000
50 #define MAXNETS         5
51 #define MAXHOSTS        25
52
53 /* \f */
54
55 extern int errno;
56 #ifndef BSD44
57 extern int  sys_nerr;
58 extern char *sys_errlist[];
59 #endif
60
61
62 struct addrent {
63     int     a_addrtype;         /* assumes AF_INET for inet_netof () */
64
65     union {
66         int     un_net;
67         char    un_addr[14];
68     } un;
69 #define a_net   un.un_net
70 #define a_addr  un.un_addr
71 };
72
73 static struct addrent *ne, *nz;
74 static struct addrent nets[MAXNETS];
75
76 static struct addrent *he, *hz;
77 static struct addrent hosts[MAXHOSTS];
78
79 #ifdef KPOP
80 char krb_realm[REALM_SZ];
81 char *PrincipalHostname();
82 static char *kservice;          /* "pop" if using kpop */
83 #endif /* KPOP */
84
85 #ifdef __STDC__
86 static int rcaux (struct servent *, struct hostent *, char *);
87 static int getport (int, char *);
88 static int inet (struct hostent *, int);
89 #else
90 static int rcaux (), getport (), inet ();
91 #endif
92
93
94 #if     defined(BIND) && !defined(h_addr)
95 #define h_addr  h_addr_list[0]
96 #endif
97
98 #define inaddr_copy(hp,sin) \
99     bcopy ((hp) -> h_addr, (char *) &((sin) -> sin_addr), (hp) -> h_length)
100
101
102 struct hostent *gethostbystring ();
103
104
105 static int brkany ();
106 static char *getcpy (), **copyip (), **brkstring ();
107
108 /* \f */
109
110 int     client (args, protocol, service,  response)
111 char   *args,
112        *protocol,
113        *service,        /* "pop" or "pop/kpop" */
114        *response;
115 {
116     int     sd;
117     register char **ap;
118     char   *arguments[MAXARGS];
119     register struct hostent *hp;
120 #ifndef BIND
121     register struct netent *np;
122 #endif
123     register struct servent *sp;
124 #ifdef  KPOP
125     char *cp;
126
127     if (cp = index (kservice = service, '/')) { /* "pop/kpop" */
128         *cp++ = '\0';           /* kservice = "pop" */
129         service = cp;           /* service  = "kpop" */
130     }
131     else
132         kservice = NULL;        /* not using KERBEROS */
133 #endif  /* KPOP */
134     
135
136     if ((sp = getservbyname (service, protocol)) == NULL) {
137 #ifdef  HESIOD
138         if ((sp = hes_getservbyname (service, protocol)) == NULL) {
139             (void) sprintf (response, "%s/%s: unknown service",
140                     protocol, service);
141             return NOTOK;
142         }
143 #else
144         (void) sprintf (response, "%s/%s: unknown service", protocol, service);
145         return NOTOK;
146 #endif
147     }
148
149     ap = arguments;
150     if (args != NULL && *args != 0)
151         ap = copyip (brkstring (getcpy (args), " ", "\n"), ap);
152     else
153         if (servers != NULL && *servers != 0)
154             ap = copyip (brkstring (getcpy (servers), " ", "\n"), ap);
155     if (ap == arguments) {
156         *ap++ = getcpy ("localhost");
157         *ap = NULL;
158     }
159
160     nz = (ne = nets) + sizeof nets / sizeof nets[0];
161     hz = (he = hosts) + sizeof hosts / sizeof hosts[0];
162
163     for (ap = arguments; *ap; ap++) {
164         if (**ap == '\01') {
165 #ifndef BIND
166             if (np = getnetbyname (*ap + 1)) {
167                 sethostent (1);
168                 while (hp = gethostent ())
169                     if (np -> n_addrtype == hp -> h_addrtype
170                             && inet (hp, np -> n_net)) {
171                         switch (sd = rcaux (sp, hp, response)) {
172                             case NOTOK: 
173                                 continue;
174                             case OOPS1: 
175                                 break;
176                             case OOPS2: 
177                                 return NOTOK;
178
179                             default: 
180                                 return sd;
181                         }
182                         break;
183                     }
184             }
185 #endif
186             continue;
187         }
188
189         if (hp = gethostbystring (*ap)) {
190             switch (sd = rcaux (sp, hp, response)) {
191                 case NOTOK: 
192                 case OOPS1: 
193                     break;
194                 case OOPS2: 
195                     return NOTOK;
196
197                 default: 
198                     return sd;
199             }
200             continue;
201         }
202     }
203
204     (void) strcpy (response, "no servers available");
205     return NOTOK;
206 }
207
208 /* \f */
209
210 static int  rcaux (sp, hp, response)
211 register struct servent *sp;
212 register struct hostent *hp;
213 register char *response;
214 {
215     int     sd;
216     struct in_addr  in;
217     register struct addrent *ap;
218     struct sockaddr_in  in_socket;
219     register struct sockaddr_in *isock = &in_socket;
220 #ifdef KPOP
221     int rem;
222 #endif  /* KPOP */
223
224     for (ap = nets; ap < ne; ap++)
225         if (ap -> a_addrtype == hp -> h_addrtype && inet (hp, ap -> a_net))
226             return NOTOK;
227
228     for (ap = hosts; ap < he; ap++)
229         if (ap -> a_addrtype == hp -> h_addrtype
230                 && bcmp (ap -> a_addr, hp -> h_addr, hp -> h_length) == 0)
231             return NOTOK;
232
233     if ((sd = getport (hp -> h_addrtype, response)) == NOTOK)
234         return OOPS2;
235
236     bzero ((char *) isock, sizeof *isock);
237     isock -> sin_family = hp -> h_addrtype;
238     inaddr_copy (hp, isock);
239     isock -> sin_port = sp -> s_port;
240
241     if (connect (sd, (struct sockaddr *) isock, sizeof *isock) == NOTOK)
242         switch (errno) {
243             case ENETDOWN: 
244             case ENETUNREACH: 
245                 (void) close (sd);
246                 if (ne < nz) {
247                     ne -> a_addrtype = hp -> h_addrtype;
248                     bcopy (hp -> h_addr, (char *) &in, sizeof in);
249                     ne -> a_net = inet_netof (in);
250                     ne++;
251                 }
252                 return OOPS1;
253
254             case ETIMEDOUT: 
255             case ECONNREFUSED: 
256             default: 
257                 (void) close (sd);
258                 if (he < hz) {
259                     he -> a_addrtype = hp -> h_addrtype;
260                     bcopy (hp -> h_addr, he -> a_addr, hp -> h_length);
261                     he++;
262                 }
263                 return NOTOK;
264         }
265
266 #ifdef KPOP
267     if (kservice) {     /* "pop" */
268         ticket = (KTEXT)malloc( sizeof(KTEXT_ST) );
269         rem = krb_sendauth(0L, sd, ticket, kservice, hp->h_name,
270                            (char *) krb_realmofhost(hp->h_name),
271                            (unsigned long)0, &msg_data, &cred, schedule,
272                            (struct sockaddr_in *)NULL,
273                            (struct sockaddr_in *)NULL,
274                            "KPOPV0.1");
275         if (rem != KSUCCESS) {
276             close(sd);
277             (void) strcpy(response, "Post office refused connection: ");
278             (void) strcat(response, krb_err_txt[rem]);
279             return OOPS2;
280         }
281     }
282 #endif  /* KPOP */
283
284     return sd;
285 }
286
287 /* \f */
288
289 static int getport (addrtype, response)
290 int      addrtype;
291 register char *response;
292 {
293     int     sd,
294             port;
295     struct sockaddr_in  in_socket,
296                        *isock = &in_socket;
297
298
299     if ((sd = socket (AF_INET, SOCK_STREAM, 0)) == NOTOK) {
300         (void) sprintf (response, "unable to create socket: %s",
301                 errno > 0 && errno < sys_nerr ? sys_errlist[errno]
302                 : "unknown error");
303         return NOTOK;
304     }
305 #ifdef KPOP
306     if (kservice)       /* "pop" */
307         return(sd);
308 #endif  /* KPOP */
309         return sd;
310
311 }
312
313 /* \f */
314
315 static int  inet (hp, net)
316 register struct hostent *hp;
317 int     net;
318 {
319     struct in_addr  in;
320
321     bcopy (hp -> h_addr, (char *) &in, sizeof in);
322     return (inet_netof (in) == net);
323 }
324
325 /* \f */
326
327 /* taken from ISODE's compat/internet.c */
328
329 #ifndef OSF1
330 #ifndef DG
331 u_long  inet_addr ();
332 #else
333 struct in_addr inet_addr ();
334 #endif
335 #endif
336
337 static char *empty = NULL;
338 #ifdef  h_addr
339 static char *addrs[2] = { NULL };
340 #endif
341
342 struct hostent *gethostbystring (s)
343 char   *s;
344 {
345     register struct hostent *h;
346 #ifndef DG
347     static u_long iaddr;
348 #else
349     static struct in_addr iaddr;
350 #endif
351     static struct hostent   hs;
352
353     iaddr = inet_addr (s);
354 #ifndef DG
355     if ((int)iaddr == NOTOK && strcmp (s, "255.255.255.255"))
356 #else
357     if (iaddr.s_addr == NOTOK && strcmp (s, "255.255.255.255"))
358 #endif
359         return gethostbyname (s);
360
361     h = &hs;
362     h -> h_name = s;
363     h -> h_aliases = &empty;
364     h -> h_addrtype = AF_INET;
365     h -> h_length = sizeof (iaddr);
366 #ifdef  h_addr
367     h -> h_addr_list = addrs;
368     bzero ((char *) addrs, sizeof addrs);
369 #endif
370     h -> h_addr = (char *) &iaddr;
371
372     return h;
373 }
374
375 /* \f */
376
377 /* static copies of three MH subroutines... (sigh) */
378
379 static char *broken[MAXARGS + 1];
380
381
382 static char **brkstring (strg, brksep, brkterm)
383 register char  *strg;
384 register char  *brksep,
385                *brkterm;
386 {
387     register int    bi;
388     register char   c,
389                    *sp;
390
391     sp = strg;
392
393     for (bi = 0; bi < MAXARGS; bi++) {
394         while (brkany (c = *sp, brksep))
395             *sp++ = 0;
396         if (!c || brkany (c, brkterm)) {
397             *sp = 0;
398             broken[bi] = 0;
399             return broken;
400         }
401
402         broken[bi] = sp;
403         while ((c = *++sp) && !brkany (c, brksep) && !brkany (c, brkterm))
404             continue;
405     }
406     broken[MAXARGS] = 0;
407
408     return broken;
409 }
410
411
412 static  brkany (chr, strg)
413 register char   chr,
414                *strg;
415 {
416     register char  *sp;
417
418     if (strg)
419         for (sp = strg; *sp; sp++)
420             if (chr == *sp)
421                 return 1;
422     return 0;
423 }
424
425
426 static char **copyip (p, q)
427 register char **p,
428               **q;
429 {
430     while (*p)
431         *q++ = *p++;
432     *q = 0;
433
434     return q;
435 }
436
437
438 static char *getcpy (str)
439 register char  *str;
440 {
441     register char  *cp;
442
443     if ((cp = malloc ((unsigned) (strlen (str) + 1))) == NULL)
444         return NULL;
445
446     (void) strcpy (cp, str);
447     return cp;
448 }
449 #endif  /* BSD42 or SOCKETS */