OSDN Git Service

Enhance all settings encryption.
[ffftp/ffftp.git] / putty / CONTRIB / CYGTERMD / PTY.C
1 /*\r
2  * pty.c - pseudo-terminal handling\r
3  */\r
4 \r
5 #define _XOPEN_SOURCE\r
6 #include <features.h>\r
7 \r
8 #include <stdio.h>\r
9 #include <stdlib.h>\r
10 #include <string.h>\r
11 #include <assert.h>\r
12 \r
13 #include <unistd.h>\r
14 #include <fcntl.h>\r
15 #include <termios.h>\r
16 #include <sys/ioctl.h>\r
17 #include <sys/types.h>\r
18 #include <pwd.h>\r
19 \r
20 #include "pty.h"\r
21 #include "malloc.h"\r
22 \r
23 static char ptyname[FILENAME_MAX];\r
24 int master = -1;\r
25 \r
26 void pty_preinit(void)\r
27 {\r
28     /*\r
29      * Allocate the pty.\r
30      */\r
31     master = open("/dev/ptmx", O_RDWR);\r
32     if (master < 0) {\r
33         perror("/dev/ptmx: open");\r
34         exit(1);\r
35     }\r
36 \r
37     if (grantpt(master) < 0) {\r
38         perror("grantpt");\r
39         exit(1);\r
40     }\r
41     \r
42     if (unlockpt(master) < 0) {\r
43         perror("unlockpt");\r
44         exit(1);\r
45     }\r
46 }\r
47 \r
48 void pty_resize(int w, int h)\r
49 {\r
50     struct winsize sz;\r
51 \r
52     assert(master >= 0);\r
53 \r
54     sz.ws_row = h;\r
55     sz.ws_col = w;\r
56     sz.ws_xpixel = sz.ws_ypixel = 0;\r
57     ioctl(master, TIOCSWINSZ, &sz);\r
58 }\r
59 \r
60 int run_program_in_pty(const struct shell_data *shdata,\r
61                        char *directory, char **program_args)\r
62 {\r
63     int slave, pid;\r
64     char *fallback_args[2];\r
65 \r
66     assert(master >= 0);\r
67 \r
68     ptyname[FILENAME_MAX-1] = '\0';\r
69     strncpy(ptyname, ptsname(master), FILENAME_MAX-1);\r
70 \r
71 #if 0\r
72     {\r
73         struct winsize ws;\r
74         struct termios ts;\r
75 \r
76         /*\r
77          * FIXME: think up some good defaults here\r
78          */\r
79 \r
80         if (!ioctl(0, TIOCGWINSZ, &ws))\r
81             ioctl(master, TIOCSWINSZ, &ws);\r
82         if (!tcgetattr(0, &ts))\r
83             tcsetattr(master, TCSANOW, &ts);\r
84     }\r
85 #endif\r
86 \r
87     slave = open(ptyname, O_RDWR | O_NOCTTY);\r
88     if (slave < 0) {\r
89         perror("slave pty: open");\r
90         return 1;\r
91     }\r
92 \r
93     /*\r
94      * Fork and execute the command.\r
95      */\r
96     pid = fork();\r
97     if (pid < 0) {\r
98         perror("fork");\r
99         return 1;\r
100     }\r
101 \r
102     if (pid == 0) {\r
103         int i, fd;\r
104 \r
105         /*\r
106          * We are the child.\r
107          */\r
108         close(master);\r
109 \r
110         fcntl(slave, F_SETFD, 0);    /* don't close on exec */\r
111         dup2(slave, 0);\r
112         dup2(slave, 1);\r
113         if (slave != 0 && slave != 1)\r
114             close(slave);\r
115         dup2(1, 2);\r
116         setsid();\r
117         setpgrp();\r
118         i = 0;\r
119 #ifdef TIOCNOTTY\r
120         if ((fd = open("/dev/tty", O_RDWR)) >= 0) {\r
121             ioctl(fd, TIOCNOTTY, &i);\r
122             close(fd);\r
123         }\r
124 #endif\r
125         /*\r
126          * Make the new pty our controlling terminal. On some OSes\r
127          * this is done with TIOCSCTTY; Cygwin doesn't have that, so\r
128          * instead it's done by simply opening the pty without\r
129          * O_NOCTTY. This code is primarily intended for Cygwin, but\r
130          * it's useful to have it work in other contexts for testing\r
131          * purposes, so I leave the TIOCSCTTY here anyway.\r
132          */\r
133         if ((fd = open(ptyname, O_RDWR)) >= 0) {\r
134 #ifdef TIOCSCTTY\r
135             ioctl(fd, TIOCSCTTY, &i);\r
136 #endif\r
137             close(fd);\r
138         } else {\r
139             perror("slave pty: open");\r
140             exit(127);\r
141         }\r
142         tcsetpgrp(0, getpgrp());\r
143 \r
144         for (i = 0; i < shdata->nenvvars; i++)\r
145             putenv(shdata->envvars[i]);\r
146         if (shdata->termtype)\r
147             putenv(shdata->termtype);\r
148 \r
149         if (directory)\r
150             chdir(directory);\r
151 \r
152         /*\r
153          * Use the provided shell program name, if the user gave\r
154          * one. Failing that, use $SHELL; failing that, look up\r
155          * the user's default shell in the password file; failing\r
156          * _that_, revert to the bog-standard /bin/sh.\r
157          */\r
158         if (!program_args) {\r
159             char *shell;\r
160             \r
161             shell = getenv("SHELL");\r
162             if (!shell) {\r
163                 const char *login;\r
164                 uid_t uid;\r
165                 struct passwd *pwd;\r
166 \r
167                 /*\r
168                  * For maximum generality in the face of multiple\r
169                  * /etc/passwd entries with different login names and\r
170                  * shells but a shared uid, we start by using\r
171                  * getpwnam(getlogin()) if it's available - but we\r
172                  * insist that its uid must match our real one, or we\r
173                  * give up and fall back to getpwuid(getuid()).\r
174                  */\r
175                 uid = getuid();\r
176                 login = getlogin();\r
177                 if (login && (pwd = getpwnam(login)) && pwd->pw_uid == uid)\r
178                     shell = pwd->pw_shell;\r
179                 else if ((pwd = getpwuid(uid)))\r
180                     shell = pwd->pw_shell;\r
181             }\r
182             if (!shell)\r
183                 shell = "/bin/sh";\r
184 \r
185             fallback_args[0] = shell;\r
186             fallback_args[1] = NULL;\r
187             program_args = fallback_args;\r
188         }\r
189 \r
190         execv(program_args[0], program_args);\r
191 \r
192         /*\r
193          * If we're here, exec has gone badly foom.\r
194          */\r
195         perror("exec");\r
196         exit(127);\r
197     }\r
198 \r
199     close(slave);\r
200 \r
201     return master;\r
202 }\r