OSDN Git Service

1ee25ed534e1bc3a81c3adbb5f22666a9ac2fb33
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygwin / libc / rexec.cc
1 /*
2  * Copyright (c) 1980, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 4. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31
32 /* CV 2006-07-04: Tweaked for inclusion into Cygwin. */
33
34 #if defined(LIBC_SCCS) && !defined(lint)
35 static char sccsid[] = "@(#)rexec.c     8.1 (Berkeley) 6/4/93";
36 #endif /* LIBC_SCCS and not lint */
37
38 #ifdef __CYGWIN__
39 #include "winsup.h"
40 #include "sigproc.h"
41 #include "cygtls.h"
42 #include <wininet.h>
43 #endif
44
45 #include <sys/types.h>
46 #include <sys/uio.h>
47 #include <sys/socket.h>
48 #include <sys/param.h>
49 #include <sys/stat.h>
50
51 #include <netinet/in.h>
52
53 #include <stdio.h>
54 #include <unistd.h>
55 #include <string.h>
56 #include <netdb.h>
57 #include <errno.h>
58 #include <ctype.h>
59 #include <err.h>
60 #include <stdlib.h>
61 #include <unistd.h>
62
63 extern "C" {
64   int cygwin_accept (int, struct sockaddr *, socklen_t *);
65   int cygwin_connect (int, const struct sockaddr *, socklen_t);
66   int cygwin_getsockname (int, struct sockaddr *, socklen_t *);
67   void cygwin_herror (const char *);
68   int cygwin_listen (int, int);
69   int cygwin_socket (int, int, int);
70 }
71
72 /*
73  * Options and other state info.
74  */
75 struct macel {
76         char mac_name[9];       /* macro name */
77         char *mac_start;        /* start of macro in macbuf */
78         char *mac_end;          /* end of macro in macbuf */
79 };
80
81 int macnum;                     /* number of defined macros */
82 struct macel macros[16];
83 char macbuf[4096];
84
85 static  FILE *cfile;
86
87 #define DEFAULT 1
88 #define LOGIN   2
89 #define PASSWD  3
90 #define ACCOUNT 4
91 #define MACDEF  5
92 #define ID      10
93 #define MACH    11
94
95 static char tokval[100];
96
97 static struct toktab {
98         const char *tokstr;
99         int tval;
100 } toktab[]= {
101         { "default",    DEFAULT },
102         { "login",      LOGIN },
103         { "password",   PASSWD },
104         { "passwd",     PASSWD },
105         { "account",    ACCOUNT },
106         { "machine",    MACH },
107         { "macdef",     MACDEF },
108         { NULL,         0 }
109 };
110
111 static int
112 token()
113 {
114         char *cp;
115         int c;
116         struct toktab *t;
117
118         if (feof(cfile) || ferror(cfile))
119                 return (0);
120         while ((c = getc(cfile)) != EOF &&
121             (c == '\n' || c == '\t' || c == ' ' || c == ','))
122                 continue;
123         if (c == EOF)
124                 return (0);
125         cp = tokval;
126         if (c == '"') {
127                 while ((c = getc(cfile)) != EOF && c != '"') {
128                         if (c == '\\')
129                                 c = getc(cfile);
130                         *cp++ = c;
131                 }
132         } else {
133                 *cp++ = c;
134                 while ((c = getc(cfile)) != EOF
135                     && c != '\n' && c != '\t' && c != ' ' && c != ',') {
136                         if (c == '\\')
137                                 c = getc(cfile);
138                         *cp++ = c;
139                 }
140         }
141         *cp = 0;
142         if (tokval[0] == 0)
143                 return (0);
144         for (t = toktab; t->tokstr; t++)
145                 if (!strcmp(t->tokstr, tokval))
146                         return (t->tval);
147         return (ID);
148 }
149
150 static int
151 ruserpass(const char *host, char **aname, char **apass, char **aacct)
152 {
153         const char *hdir;
154         char buf[BUFSIZ], *tmp;
155         char myname[INTERNET_MAX_HOST_NAME_LENGTH + 1];
156         const char *mydomain;
157         int t, i, c, usedefault = 0;
158         struct __stat64 stb;
159
160         hdir = getenv("HOME");
161         if (hdir == NULL)
162                 hdir = ".";
163         if (strlen(hdir) + 8 > sizeof(buf))
164                 return (0);
165         (void) sprintf(buf, "%s/.netrc", hdir);
166         cfile = fopen(buf, "r");
167         if (cfile == NULL) {
168                 if (errno != ENOENT)
169                         warn("%s", buf);
170                 return (0);
171         }
172         if (cygwin_gethostname(myname, sizeof(myname)) < 0)
173                 myname[0] = '\0';
174         if ((mydomain = strchr(myname, '.')) == NULL)
175                 mydomain = "";
176 next:
177         while ((t = token())) switch(t) {
178
179         case DEFAULT:
180                 usedefault = 1;
181                 /* FALL THROUGH */
182
183         case MACH:
184                 if (!usedefault) {
185                         if (token() != ID)
186                                 continue;
187                         /*
188                          * Allow match either for user's input host name
189                          * or official hostname.  Also allow match of
190                          * incompletely-specified host in local domain.
191                          */
192                         if (strcasecmp(host, tokval) == 0)
193                                 goto match;
194                         if ((tmp = strchr(host, '.')) != NULL &&
195                             strcasecmp(tmp, mydomain) == 0 &&
196                             strncasecmp(host, tokval, tmp - host) == 0 &&
197                             tokval[tmp - host] == '\0')
198                                 goto match;
199                         continue;
200                 }
201         match:
202                 while ((t = token()) && t != MACH && t != DEFAULT) switch(t) {
203
204                 case LOGIN:
205                         if (token()) {
206                                 if (*aname == 0) {
207                                         *aname = (char *) malloc((unsigned) strlen(tokval) + 1);
208                                         (void) strcpy(*aname, tokval);
209                                 } else {
210                                         if (strcmp(*aname, tokval))
211                                                 goto next;
212                                 }
213                         }
214                         break;
215                 case PASSWD:
216                         if ((*aname == 0 || strcmp(*aname, "anonymous")) &&
217                             fstat64(fileno(cfile), &stb) >= 0 &&
218                             (stb.st_mode & 077) != 0) {
219         warnx("Error: .netrc file is readable by others.");
220         warnx("Remove password or make file unreadable by others.");
221                                 goto bad;
222                         }
223                         if (token() && *apass == 0) {
224                                 *apass = (char *) malloc((unsigned) strlen(tokval) + 1);
225                                 (void) strcpy(*apass, tokval);
226                         }
227                         break;
228                 case ACCOUNT:
229                         if (fstat64(fileno(cfile), &stb) >= 0
230                             && (stb.st_mode & 077) != 0) {
231         warnx("Error: .netrc file is readable by others.");
232         warnx("Remove account or make file unreadable by others.");
233                                 goto bad;
234                         }
235                         if (token() && aacct && *aacct == 0) {
236                                 *aacct = (char *) malloc((unsigned) strlen(tokval) + 1);
237                                 (void) strcpy(*aacct, tokval);
238                         }
239                         break;
240                 case MACDEF:
241                         while ((c=getc(cfile)) != EOF &&
242                                                 (c == ' ' || c == '\t'))
243                                 ;
244                         if (c == EOF || c == '\n') {
245                                 printf("Missing macdef name argument.\n");
246                                 goto bad;
247                         }
248                         if (macnum == 16) {
249                                 printf("Limit of 16 macros have already been defined\n");
250                                 goto bad;
251                         }
252                         tmp = macros[macnum].mac_name;
253                         *tmp++ = c;
254                         for (i=0; i < 8 && (c=getc(cfile)) != EOF &&
255                             !isspace(c); ++i) {
256                                 *tmp++ = c;
257                         }
258                         if (c == EOF) {
259                                 printf("Macro definition missing null line terminator.\n");
260                                 goto bad;
261                         }
262                         *tmp = '\0';
263                         if (c != '\n') {
264                                 while ((c=getc(cfile)) != EOF && c != '\n');
265                         }
266                         if (c == EOF) {
267                                 printf("Macro definition missing null line terminator.\n");
268                                 goto bad;
269                         }
270                         if (macnum == 0) {
271                                 macros[macnum].mac_start = macbuf;
272                         }
273                         else {
274                                 macros[macnum].mac_start = macros[macnum-1].mac_end + 1;
275                         }
276                         tmp = macros[macnum].mac_start;
277                         while (tmp != macbuf + 4096) {
278                                 if ((c=getc(cfile)) == EOF) {
279                                 printf("Macro definition missing null line terminator.\n");
280                                         goto bad;
281                                 }
282                                 *tmp = c;
283                                 if (*tmp == '\n') {
284                                         if (*(tmp-1) == '\0') {
285                                            macros[macnum++].mac_end = tmp - 1;
286                                            break;
287                                         }
288                                         *tmp = '\0';
289                                 }
290                                 tmp++;
291                         }
292                         if (tmp == macbuf + 4096) {
293                                 printf("4K macro buffer exceeded\n");
294                                 goto bad;
295                         }
296                         break;
297                 default:
298                         warnx("Unknown .netrc keyword %s", tokval);
299                         break;
300                 }
301                 goto done;
302         }
303 done:
304         (void) fclose(cfile);
305         return (0);
306 bad:
307         (void) fclose(cfile);
308         return (-1);
309 }
310
311 extern "C" int
312 cygwin_rexec (char **ahost, unsigned short rport, char *name, char *pass,
313               char *cmd, int *fd2p)
314 {
315         struct sockaddr_in sin, sin2, from;
316         struct hostent *hp;
317         u_short port = 0;
318         int s, timo = 1, s3;
319         char c;
320         char ahostbuf[INTERNET_MAX_HOST_NAME_LENGTH + 1];
321
322         sig_dispatch_pending ();
323         myfault efault;
324         if (efault.faulted (EFAULT))
325                 return -1;
326
327         hp = cygwin_gethostbyname(*ahost);
328         if (hp == 0) {
329                 cygwin_herror(*ahost);
330                 return (-1);
331         }
332         *ahost = strcpy (ahostbuf, hp->h_name);
333         ruserpass(hp->h_name, &name, &pass, NULL);
334         if (!name)
335                 name = getlogin ();
336         if (!pass)
337                 pass = almost_null;
338 retry:
339         s = cygwin_socket(AF_INET, SOCK_STREAM, 0);
340         if (s < 0) {
341                 perror("rexec: socket");
342                 return (-1);
343         }
344         sin.sin_family = hp->h_addrtype;
345         sin.sin_port = rport;
346         bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
347         if (cygwin_connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
348                 if (errno == ECONNREFUSED && timo <= 16) {
349                         (void) close(s);
350                         sleep(timo);
351                         timo *= 2;
352                         goto retry;
353                 }
354                 perror(hp->h_name);
355                 return (-1);
356         }
357         if (fd2p == 0) {
358                 (void) write(s, "", 1);
359         } else {
360                 char num[8];
361                 int s2, sin2len;
362
363                 s2 = cygwin_socket(AF_INET, SOCK_STREAM, 0);
364                 if (s2 < 0) {
365                         (void) close(s);
366                         return (-1);
367                 }
368                 cygwin_listen(s2, 1);
369                 sin2len = sizeof (sin2);
370                 if (cygwin_getsockname(s2, (struct sockaddr *)&sin2, &sin2len) < 0 ||
371                   sin2len != sizeof (sin2)) {
372                         perror("getsockname");
373                         (void) close(s2);
374                         goto bad;
375                 }
376                 port = ntohs((u_short)sin2.sin_port);
377                 (void) sprintf(num, "%u", port);
378                 (void) write(s, num, strlen(num)+1);
379                 { int len = sizeof (from);
380                   s3 = cygwin_accept(s2, (struct sockaddr *)&from, &len);
381                   close(s2);
382                   if (s3 < 0) {
383                         perror("accept");
384                         port = 0;
385                         goto bad;
386                   }
387                 }
388                 *fd2p = s3;
389         }
390         (void) write(s, name, strlen(name) + 1);
391         /* should public key encypt the password here */
392         (void) write(s, pass, strlen(pass) + 1);
393         (void) write(s, cmd, strlen(cmd) + 1);
394         if (read(s, &c, 1) != 1) {
395                 perror(*ahost);
396                 goto bad;
397         }
398         if (c != 0) {
399                 while (read(s, &c, 1) == 1) {
400                         (void) write(2, &c, 1);
401                         if (c == '\n')
402                                 break;
403                 }
404                 goto bad;
405         }
406         return (s);
407 bad:
408         if (port)
409                 (void) close(*fd2p);
410         (void) close(s);
411         return (-1);
412 }