reindent-20030715
[openafs.git] / src / rlogind / rexecd.c
1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6
7 #include <afsconfig.h>
8 #include <afs/param.h>
9
10 RCSID
11     ("$Header$");
12
13 #include <afs/kautils.h>        /* for UserAuthGeneral */
14 #include <sys/types.h>
15 #ifdef  AFS_SUN5_ENV
16 #define BSD_COMP
17 #endif
18 #include <sys/ioctl.h>
19 #include <sys/param.h>
20 #include <sys/socket.h>
21 #include <sys/time.h>
22 #include <netinet/in.h>
23
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <errno.h>
27 #include <pwd.h>
28 #include <signal.h>
29 #include <netdb.h>
30 #ifdef  AFS_SUN5_ENV
31 #include <shadow.h>
32 #endif
33 #if defined(AFS_AIX_ENV)
34 #include <sys/syslog.h>
35 #include <usersec.h>
36 #endif
37
38 extern errno;
39 struct passwd *getpwnam();
40 char *crypt(), *strncat();
41 #if     !defined(AFS_AIX_ENV) && !defined(AFS_HPUX_ENV) && !defined(AFS_OSF_ENV) && !defined(AFS_SUN5_ENV)
42 char *sprintf();
43 #endif
44 /*VARARGS1*/
45 int error();
46
47 #include "AFS_component_version_number.c"
48
49 #ifdef  AFS_OSF_ENV
50 #include <sia.h>
51 SIAENTITY *entity = NULL;
52 int oargc;
53 char **oargv;
54 #endif
55
56 /*
57  * remote execute server:
58  *      username\0
59  *      password\0
60  *      command\0
61  *      data
62  */
63  /*ARGSUSED*/
64 main(argc, argv)
65      int argc;
66      char **argv;
67 {
68     struct sockaddr_in from;
69     int fromlen;
70
71     fromlen = sizeof(from);
72     if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
73         fprintf(stderr, "%s: ", argv[0]);
74         perror("getpeername");
75         exit(1);
76     }
77 #ifdef  AFS_OSF_ENV
78     oargc = argc;
79     oargv = argv;
80 #endif
81     doit(0, &from);
82 }
83
84 char env_user[20] = "USER=";
85 char env_home[64] = "HOME=";
86 char env_shell[64] = "SHELL=";
87 char env_logname[32] = "LOGNAME=";
88 char env_password_expires[64] = "PASSWORD_EXPIRES=";
89 afs_int32 password_expires = -1;
90 char pwd_expires_str[10];
91 /* make sure env_password_expires is always the last item in envinit array */
92 #if     defined(AFS_OSF_ENV) || defined(AFS_AIX_ENV)
93 char time_zone[20] = "TZ=";
94 char *envinit[] =
95     { env_home, env_shell, "PATH=:/usr/ucb:/bin:/usr/bin:/usr/sbin", env_user,
96     time_zone, env_logname, env_password_expires, 0
97 };
98 #else
99 char *envinit[] =
100     { env_home, env_shell, "PATH=:/usr/ucb:/bin:/usr/bin", env_user,
101     env_logname, env_password_expires, 0
102 };
103 #endif
104 #define PATHENV ":/usr/ucb:/bin:/usr/bin:/usr/bin/X11"
105 extern char **environ;
106
107 struct sockaddr_in asin = { AF_INET };
108
109 doit(f, fromp)
110      int f;
111      struct sockaddr_in *fromp;
112 {
113     char cmdbuf[NCARGS + 1], *cp, *namep;
114     char user[16], pass[16];
115     struct passwd *pwd;
116     char *password;
117     char **penvlist;
118     int s;
119     short port;
120     int pv[2], pid, cc;
121     fd_set ready, readfrom;
122     char buf[BUFSIZ], sig;
123     int one = 1;
124     int afsauthok = 1;
125 #ifdef  AFS_SUN5_ENV
126     struct spwd *shpwd;
127 #endif
128
129     (void)signal(SIGINT, SIG_DFL);
130     (void)signal(SIGQUIT, SIG_DFL);
131     (void)signal(SIGTERM, SIG_DFL);
132 #ifdef DEBUG
133     {
134         int t = open("/dev/tty", 2);
135         if (t >= 0) {
136             ioctl(t, TIOCNOTTY, NULL);
137             (void)close(t);
138         }
139     }
140 #endif
141     dup2(f, 0);
142     dup2(f, 1);
143     dup2(f, 2);
144     (void)alarm(60);
145     port = 0;
146     for (;;) {
147         char c;
148         if (read(f, &c, 1) != 1)
149             exit(1);
150         if (c == 0)
151             break;
152         port = port * 10 + c - '0';
153     }
154     (void)alarm(0);
155     if (port != 0) {
156         s = socket(AF_INET, SOCK_STREAM, 0);
157         if (s < 0)
158             exit(1);
159         if (bind(s, (struct sockaddr *)&asin, sizeof(asin)) < 0)
160             exit(1);
161         (void)alarm(60);
162         fromp->sin_port = htons((u_short) port);
163         if (connect(s, (struct sockaddr *)fromp, sizeof(*fromp)) < 0)
164             exit(1);
165         (void)alarm(0);
166     }
167     getstr(user, sizeof(user), "username");
168     getstr(pass, sizeof(pass), "password");
169     getstr(cmdbuf, sizeof(cmdbuf), "command");
170     setpwent();
171     pwd = getpwnam(user);
172 #ifdef  AFS_SUN5_ENV
173     (void)setspent();           /* Shadow password file */
174     shpwd = getspnam(user);
175     if (pwd == NULL || shpwd == NULL) {
176 #else
177     if (pwd == NULL) {
178 #endif
179         error("Login Incorrect..\n");
180         exit(1);
181     }
182     endpwent();
183 #ifdef  AFS_SUN5_ENV
184     endspent();
185     password = shpwd->sp_pwdp;
186 #else
187     password = pwd->pw_passwd;
188 #endif
189     if (*password != '\0') {
190         char *reason;
191
192         setpag();               /* Also set a pag */
193         /*
194          * If it's called as "root" we don't bother with afs authentication...
195          */
196         if (strcmp(user, "root")) {
197             /* changed from ka_UserAuthenticate *
198              * to get password_expires information */
199             if (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION + KA_USERAUTH_DOSETPAG, user,    /* kerberos name */
200                                            NULL,        /* instance */
201                                            NULL,        /* realm */
202                                            pass,        /* password */
203                                            0,   /* default lifetime */
204                                            &password_expires, 0,        /* spare 2 */
205                                            &reason      /* error string */
206                 )) {
207
208                 afsauthok = 0;
209             }
210         } else
211             afsauthok = 0;
212         /*
213          * if (strcmp(user, "root") &&
214          * strcmp(password, NO_VICE_AUTH_PWD)) {
215          * rc = U_Authenticate(user, pass, &cToken, &sToken);
216          * } else
217          * rc = AUTH_FAILED;
218          */
219         namep = crypt(pass, password);
220         if (strcmp(namep, password) && !afsauthok) {
221             error("Password Incorrect..\n");
222             exit(1);
223         }
224     }
225     if (chdir(pwd->pw_dir) < 0) {
226         error("No remote directory.\n");
227         exit(1);
228     }
229     (void)write(2, "\0", 1);
230     if (port) {
231         (void)pipe(pv);
232         pid = fork();
233         if (pid == (int)-1) {
234             error("Try again.\n");
235             exit(1);
236         }
237         if (pid) {
238             (void)close(0);
239             (void)close(1);
240             (void)close(2);
241             (void)close(f);
242             (void)close(pv[1]);
243             FD_ZERO(&readfrom);
244             FD_SET(s, &readfrom);
245             FD_SET(pv[0], &readfrom);
246             ioctl(pv[1], FIONBIO, (char *)&one);
247             /* should set s nbio! */
248             for (;;) {
249                 int maxfd;
250                 maxfd = -1;
251                 if (FD_ISSET(s, &readfrom) && maxfd < s)
252                     maxfd = s;
253                 if (FD_ISSET(pv[0], &readfrom) && maxfd < pv[0])
254                     maxfd = pv[0];
255                 if (maxfd == -1)
256                     break;
257                 ready = readfrom;
258                 (void)select(maxfd + 1, &ready, (fd_set *) 0, (fd_set *) 0,
259                              NULL);
260                 if (FD_ISSET(s, &ready)) {
261                     if (read(s, &sig, 1) <= 0)
262                         FD_CLR(s, &readfrom);
263                     else
264                         killpg(pid, sig);
265                 }
266                 if (FD_ISSET(pv[0], &ready)) {
267                     cc = read(pv[0], buf, sizeof(buf));
268                     if (cc <= 0) {
269                         shutdown(s, 1 + 1);
270                         FD_CLR(pv[0], &readfrom);
271                     } else
272                         (void)write(s, buf, cc);
273                 }
274             }
275             exit(0);
276         }
277         setpgid(0, getpid());
278         (void)close(s);
279         (void)close(pv[0]);
280         dup2(pv[1], 2);
281     }
282     if (*pwd->pw_shell == '\0')
283         pwd->pw_shell = "/bin/sh";
284     if (f > 2)
285         (void)close(f);
286
287 #ifdef AFS_AIX_ENV
288     /* For 7403 - try setting ulimit here */
289     /*
290      * Need to set user's ulimit, else system default
291      */
292     if (setpcred(pwd->pw_name, NULL) < 0) {
293         error("Can't set user credentials.\n");
294         exit(1);
295     }
296 #endif /* AFS_AIX_ENV */
297
298     /*
299      * For both setgid() and setuid() we should have checked for errors but we ignore them since
300      * they may fail in afs...
301      */
302     (void)setgid((gid_t) pwd->pw_gid);
303     initgroups(pwd->pw_name, pwd->pw_gid);
304     (void)setuid((uid_t) pwd->pw_uid);
305 #ifndef AFS_AIX_ENV
306     environ = envinit;
307     strncat(env_home, pwd->pw_dir, sizeof(env_home) - 6);
308     strncat(env_shell, pwd->pw_shell, sizeof(env_shell) - 7);
309     strncat(env_user, pwd->pw_name, sizeof(env_user) - 6);
310     strncat(env_logname, pwd->pw_name, sizeof(env_logname) - 9);
311     /* Determine if password expiration is used
312      * if not, take out env_password_expires string from envinit */
313     if ((password_expires >= 0) && (password_expires < 255)) {
314         sprintf(env_password_expires, "%s%d", env_password_expires,
315                 password_expires);
316     } else {
317         /* taking out PASSWORD_EXPIRES env var from array */
318 #if     defined(AFS_OSF_ENV)
319         envinit[6] = 0;
320 #else
321         envinit[5] = 0;
322 #endif /* AFS_OSF_ENV */
323     }
324 #else
325     penvlist = getpenv(PENV_USR);
326     environ = penvlist + 1;
327     addenvvar("HOME", pwd->pw_dir);
328     addenvvar("SHELL", pwd->pw_shell);
329     addenvvar("PATH", PATHENV);
330     addenvvar("LOGNAME", pwd->pw_name);
331     addenvvar("USER", pwd->pw_name);
332     /* Determine if password expiration is used
333      * if not, take out env_password_expires string from envinit */
334     if ((password_expires >= 0) && (password_expires < 255)) {
335         sprintf(pwd_expires_str, "%d", password_expires);
336         addenvvar("PASSWORD_EXPIRES", pwd_expires_str);
337     }
338 #endif
339     cp = strrchr(pwd->pw_shell, '/');
340     if (cp)
341         cp++;
342     else
343         cp = pwd->pw_shell;
344     execl(pwd->pw_shell, cp, "-c", cmdbuf, 0);
345     perror(pwd->pw_shell);
346     exit(1);
347 }
348
349 #ifdef  AFS_AIX_ENV
350 addenvvar(tag, value)
351      char *tag, *value;
352 {
353     char *penv;
354     unsigned int len = strlen(tag) + 1; /* allow for '=' */
355
356     if (!tag) {
357         errno = EINVAL;
358         perror("rexecd, addenvvar");
359         exit(1);
360     }
361     if (value)
362         len += strlen(value);
363     penv = malloc(len + 1);
364     strcpy(penv, tag);
365     strcat(penv, "=");
366     if (value)
367         strcat(penv, value);
368     if (putenv(penv) < 0) {
369         perror("rexecd, putenv");
370         exit(1);
371     }
372     return;
373 }
374 #endif
375
376
377 /*VARARGS1*/
378 error(fmt, a1, a2, a3)
379      char *fmt;
380      int a1, a2, a3;
381 {
382     char buf[BUFSIZ];
383
384     buf[0] = 1;
385     (void)sprintf(buf + 1, fmt, a1, a2, a3);
386     (void)write(2, buf, strlen(buf));
387 }
388
389 getstr(buf, cnt, err)
390      char *buf;
391      int cnt;
392      char *err;
393 {
394     char c;
395
396     do {
397         if (read(0, &c, 1) != 1)
398             exit(1);
399         *buf++ = c;
400         if (--cnt == 0) {
401             error("%s too long\n", (int)err, 0, 0);
402             exit(1);
403         }
404     } while (c != 0);
405 }