1.2-beta4 pullup
[krb5.git] / src / appl / bsd / krlogind.c
1 /*
2  *      appl/bsd/krlogind.c
3  */
4
5 /*
6  * Copyright (c) 1983 The Regents of the University of California.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms are permitted
10  * provided that the above copyright notice and this paragraph are
11  * duplicated in all such forms and that any documentation,
12  * advertising materials, and other materials related to such
13  * distribution and use acknowledge that the software was developed
14  * by the University of California, Berkeley.  The name of the
15  * University may not be used to endorse or promote products derived
16  * from this software without specific prior written permission.
17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
19  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20  */
21
22 /*
23  * Copyright (C) 1998 by the FundsXpress, INC.
24  * 
25  * All rights reserved.
26  * 
27  * Export of this software from the United States of America may require
28  * a specific license from the United States Government.  It is the
29  * responsibility of any person or organization contemplating export to
30  * obtain such a license before exporting.
31  * 
32  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
33  * distribute this software and its documentation for any purpose and
34  * without fee is hereby granted, provided that the above copyright
35  * notice appear in all copies and that both that copyright notice and
36  * this permission notice appear in supporting documentation, and that
37  * the name of FundsXpress. not be used in advertising or publicity pertaining
38  * to distribution of the software without specific, written prior
39  * permission.  FundsXpress makes no representations about the suitability of
40  * this software for any purpose.  It is provided "as is" without express
41  * or implied warranty.
42  * 
43  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
44  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
45  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
46  */
47
48 #ifndef lint
49 char copyright[] =
50   "@(#) Copyright (c) 1983 The Regents of the University of California.\n\
51  All rights reserved.\n";
52 #endif /* not lint */
53
54 /* based on @(#)rlogind.c       5.17 (Berkeley) 8/31/88 */
55      
56      /*
57       * remote login server:
58       * remuser\0
59       * locuser\0
60       * terminal info\0
61       * data
62       */
63      
64 /*
65  * This is the rlogin daemon. The very basic protocol for checking 
66  * authentication and authorization is:
67  * 1) Check authentication.
68  * 2) Check authorization via the access-control files: 
69  *    ~/.k5login (using krb5_kuserok) and/or
70  * 3) Prompt for password if any checks fail, or if so configured.
71  * Allow login if all goes well either by calling the accompanying 
72  * login.krb5 or /bin/login, according to the definition of 
73  * DO_NOT_USE_K_LOGIN.l
74  * 
75  * The configuration is done either by command-line arguments passed by 
76  * inetd, or by the name of the daemon. If command-line arguments are
77  * present, they  take priority. The options are:
78  * -k means trust krb4 or krb5
79 * -5 means trust krb5
80 * -4 means trust krb4
81  * -p and -P means prompt for password.
82  *    If the -P option is passed, then the password is verified in 
83  * addition to all other checks. If -p is not passed with -k or -r,
84  * and both checks fail, then login permission is denied.
85  *    - -e means use encryption.
86  *
87  *    If no command-line arguments are present, then the presence of the 
88  * letters kKrRexpP in the program-name before "logind" determine the 
89  * behaviour of the program exactly as with the command-line arguments.
90  *
91  * If the ruserok check is to be used, then the client should connect
92  * from a privileged port, else deny permission.
93  */ 
94      
95 /* DEFINES:
96  *   KERBEROS - Define this if application is to be kerberised.
97  *   CRYPT    - Define this if encryption is to be an option.
98  *   DO_NOT_USE_K_LOGIN - Define this if you want to use /bin/login
99  *              instead  of the accompanying login.krb5. 
100  *   KRB5_KRB4_COMPAT - Define this if v4 rlogin clients are also to be served.
101  *   ALWAYS_V5_KUSEROK - Define this if you want .k5login to be
102  *              checked even for v4 clients (instead of .klogin).
103  *   LOG_ALL_LOGINS - Define this if you want to log all logins.
104  *   LOG_OTHER_USERS - Define this if you want to log all principals
105  *              that do not map onto the local user.
106  *   LOG_REMOTE_REALM - Define this if you want to log all principals from 
107  *              remote realms.
108  *       Note:  Root logins are always logged.
109  */
110
111 /*
112  * This is usually done in the Makefile.  Actually, these sources may
113  * not work without the KERBEROS #defined.
114  *
115  * #define KERBEROS
116  */
117 #define LOG_REMOTE_REALM
118 #define CRYPT
119 #define USE_LOGIN_F
120
121 #ifdef HAVE_UNISTD_H
122 #include <unistd.h>
123 #endif
124 #ifdef __SCO__
125 #include <sys/unistd.h>
126 #endif
127 #ifdef HAVE_STDLIB_H
128 #include <stdlib.h>
129 #endif
130
131 #include <stdio.h>
132 #include <sys/types.h>
133 #include <sys/stat.h>
134 #ifndef KERBEROS
135 /* Ultrix doesn't protect it vs multiple inclusion, and krb.h includes it */
136 #include <sys/socket.h>
137 #endif
138 #include <sys/ioctl.h>
139 #include <sys/wait.h>
140 #include <sys/file.h>
141 #include <sys/time.h>
142 #include <ctype.h>
143 #include <fcntl.h>
144 #include <netinet/in.h>
145 #include <errno.h>
146 #include <pwd.h>
147      
148 #ifdef HAVE_SYS_LABEL_H
149 /* only SunOS 4? */
150 #include <sys/label.h>
151 #include <sys/audit.h>
152 #include <pwdadj.h>
153 #endif
154      
155 #include <signal.h>
156
157 #if defined(hpux) || defined(__hpux)
158 #include <sys/ptyio.h>
159 #endif
160 #ifdef sysvimp
161 #include <compat.h>
162 #endif
163
164 #ifdef HAVE_SYS_SELECT_H
165 #include <sys/select.h>
166 #endif
167
168 #ifdef HAVE_STREAMS
169 #include <sys/stream.h>
170 #include <sys/stropts.h>
171 #endif
172
173 #if defined(POSIX_TERMIOS) && !defined(ultrix)
174 #include <termios.h>
175 #else
176 #include <sgtty.h>
177 #endif
178
179 #ifndef KERBEROS
180 /* Ultrix doesn't protect it vs multiple inclusion, and krb.h includes it */
181 #include <netdb.h>
182 #endif
183 #include <syslog.h>
184 #include <string.h>
185 #include <sys/param.h>
186
187 #ifdef HAVE_STREAMS
188 /* krlogin doesn't test sys/tty... */
189 #ifdef HAVE_SYS_TTY_H
190 #include <sys/tty.h>
191 #endif
192
193 #ifdef HAVE_SYS_PTYVAR_H
194 /* Solaris actually uses packet mode, so the real macros are needed too */
195 #include <sys/ptyvar.h>
196 #endif
197 #endif
198
199
200 #ifndef TIOCPKT_NOSTOP
201 /* These values are over-the-wire protocol, *not* local values */
202 #define TIOCPKT_NOSTOP          0x10
203 #define TIOCPKT_DOSTOP          0x20
204 #define TIOCPKT_FLUSHWRITE      0x02
205 #endif
206
207 #ifdef HAVE_SYS_FILIO_H
208 /* get FIONBIO from sys/filio.h, so what if it is a compatibility feature */
209 #include <sys/filio.h>
210 #endif
211
212 #ifndef HAVE_KILLPG
213 #define killpg(pid, sig) kill(-(pid), (sig))
214 #endif
215
216 #ifdef HAVE_PTSNAME
217 /* HP/UX 9.04 has but does not declare ptsname.  */
218 extern char *ptsname ();
219 #endif
220
221 #ifdef NO_WINSIZE
222 struct winsize {
223     unsigned short ws_row, ws_col;
224     unsigned short ws_xpixel, ws_ypixel;
225 };
226 #endif /* NO_WINSIZE */
227      
228 #ifndef roundup
229 #define roundup(x,y) ((((x)+(y)-1)/(y))*(y))
230 #endif
231
232 #ifdef KERBEROS
233      
234 #include <krb5.h>
235 #include <kerberosIV/krb.h>
236 #include <libpty.h>
237 #ifdef HAVE_UTMP_H
238 #include <utmp.h>
239 #endif
240
241 int auth_sys = 0;       /* Which version of Kerberos used to authenticate */
242
243 #define KRB5_RECVAUTH_V4        4
244 #define KRB5_RECVAUTH_V5        5
245
246 int non_privileged = 0; /* set when connection is seen to be from */
247                         /* a non-privileged port */
248
249 AUTH_DAT        *v4_kdata;
250 Key_schedule v4_schedule;
251
252 #include "com_err.h"
253 #include "defines.h"
254      
255 #define SECURE_MESSAGE  "This rlogin session is using DES encryption for all data transmissions.\r\n"
256
257 krb5_authenticator      *kdata;
258 krb5_ticket     *ticket = 0;
259 krb5_context bsd_context;
260 krb5_ccache ccache = NULL;
261
262 krb5_keytab keytab = NULL;
263
264 #define ARGSTR  "k54ciepPD:S:M:L:fw:?"
265 #else /* !KERBEROS */
266 #define ARGSTR  "rpPD:f?"
267 #endif /* KERBEROS */
268
269 #ifndef LOGIN_PROGRAM
270 #ifdef DO_NOT_USE_K_LOGIN
271 #ifdef sysvimp
272 #define LOGIN_PROGRAM "/bin/remlogin"
273 #else
274 #define LOGIN_PROGRAM "/bin/login"
275 #endif
276 #else /* DO_NOT_USE_K_LOGIN */
277 #define LOGIN_PROGRAM KRB5_PATH_LOGIN
278 #endif /* DO_NOT_USE_K_LOGIN */
279 #endif /* LOGIN_PROGRAM */
280
281 char *login_program = LOGIN_PROGRAM;
282
283 #define MAXRETRIES 4
284 #define MAX_PROG_NAME 16
285
286 #ifndef UT_NAMESIZE     /* linux defines it directly in <utmp.h> */
287 #define UT_NAMESIZE     sizeof(((struct utmp *)0)->ut_name)
288 #endif
289
290 #if HAVE_ARPA_NAMESER_H
291 #include <arpa/nameser.h>
292 #endif
293
294 #ifndef MAXDNAME
295 #define MAXDNAME 256 /*per the rfc*/
296 #endif
297
298 char            lusername[UT_NAMESIZE+1];
299 char            rusername[UT_NAMESIZE+1];
300 char            *krusername = 0;
301 char            term[64];
302 char            rhost_name[MAXDNAME];
303 char            rhost_addra[16];
304 krb5_principal  client;
305 int             do_inband = 0;
306
307 int     reapchild();
308 char    *progname;
309
310 static  int Pfd;
311
312 #if (defined(_AIX) && defined(i386)) || defined(ibm032) || (defined(vax) && !defined(ultrix)) || (defined(SunOS) && SunOS > 40) || defined(solaris20)
313 #define VHANG_FIRST
314 #endif
315
316 #if defined(ultrix)
317 #define VHANG_LAST              /* vhangup must occur on close, not open */
318 #endif
319
320 void    fatal(), fatalperror(), doit(), usage(), do_krb_login(), getstr();
321 void    protocol();
322 int     princ_maps_to_lname(), default_realm();
323 krb5_sigtype    cleanup();
324 krb5_error_code recvauth();
325
326 /* There are two authentication related masks:
327    * auth_ok and auth_sent.
328 * The auth_ok mask is the oring of authentication systems any one
329 * of which can be used.  
330 * The auth_sent mask is the oring of one or more authentication/authorization
331 * systems that succeeded.  If the anding
332 * of these two masks is true, then authorization is successful.
333 */
334 #define AUTH_KRB4 (0x1)
335 #define AUTH_KRB5 (0x2)
336 int auth_ok = 0, auth_sent = 0;
337 int do_encrypt = 0, passwd_if_fail = 0, passwd_req = 0;
338 int checksum_required = 0, checksum_ignored = 0;
339
340 int stripdomain = 1;
341 int maxhostlen = 0;
342 int always_ip = 0;
343
344 int main(argc, argv)
345      int argc;
346      char **argv;
347 {
348     extern int opterr, optind;
349     extern char * optarg;
350     int on = 1, fromlen, ch, i;
351     struct sockaddr_in from;
352     char *options;
353     int debug_port = 0;
354     int fd;
355     int do_fork = 0;
356 #ifdef KERBEROS
357     krb5_error_code status;
358 #endif
359     
360     progname = *argv;
361     
362     pty_init();
363     
364 #ifndef LOG_NDELAY
365 #define LOG_NDELAY 0
366 #endif
367     
368 #ifndef LOG_AUTH /* 4.2 syslog */
369     openlog(progname, LOG_PID | LOG_NDELAY);
370 #else
371     openlog(progname, LOG_PID | LOG_NDELAY, LOG_AUTH);
372 #endif /* 4.2 syslog */
373     
374 #ifdef KERBEROS
375     status = krb5_init_context(&bsd_context);
376     if (status) {
377             syslog(LOG_ERR, "Error initializing krb5: %s",
378                    error_message(status));
379             exit(1);
380     }
381 #endif
382     
383     /* Analyse parameters. */
384     opterr = 0;
385     while ((ch = getopt(argc, argv, ARGSTR)) != -1)
386       switch (ch) {
387 #ifdef KERBEROS
388         case 'k':
389 #ifdef KRB5_KRB4_COMPAT
390         auth_ok |= (AUTH_KRB5|AUTH_KRB4);
391 #else
392         auth_ok |= AUTH_KRB5;
393 #endif /* KRB5_KRB4_COMPAT*/
394         break;
395         
396       case '5':
397           auth_ok |= AUTH_KRB5;
398         break;
399       case 'c':
400         checksum_required = 1;
401         break;
402       case 'i':
403         checksum_ignored = 1;
404         break;
405         
406 #ifdef KRB5_KRB4_COMPAT
407       case '4':
408         auth_ok |= AUTH_KRB4;
409         break;
410 #endif
411 #ifdef CRYPT
412         case 'x':         /* Use encryption. */
413         case 'X':
414         case 'e':
415         case 'E':
416           do_encrypt = 1;
417           break;
418 #endif
419         case 'S':
420           if ((status = krb5_kt_resolve(bsd_context, optarg, &keytab))) {
421                   com_err(progname, status, "while resolving srvtab file %s",
422                           optarg);
423                   exit(2);
424           }
425           break;
426         case 'M':
427           krb5_set_default_realm(bsd_context, optarg);
428           break;
429 #endif
430         case 'p':
431           passwd_if_fail = 1; /* Passwd reqd if any check fails */
432           break;
433         case 'P':         /* passwd is a must */
434           passwd_req = 1;
435           break;
436         case 'D':
437           debug_port = atoi(optarg);
438           break;
439         case 'L':
440           login_program = optarg;
441           break;
442         case 'f':
443           do_fork = 1;
444           break;
445         case 'w':
446           if (!strcmp(optarg, "ip"))
447             always_ip = 1;
448           else {
449             char *cp;
450             cp = strchr(optarg, ',');
451             if (cp == NULL)
452               maxhostlen = atoi(optarg);
453             else if (*(++cp)) {
454               if (!strcmp(cp, "striplocal"))
455                 stripdomain = 1;
456               else if (!strcmp(cp, "nostriplocal"))
457                 stripdomain = 0;
458               else {
459                 usage();
460                 exit(1);
461               }
462               *(--cp) = '\0';
463               maxhostlen = atoi(optarg);
464             }
465           }
466           break;
467         case '?':
468         default:
469           usage();
470           exit(1);
471           break;
472       }
473     argc -= optind;
474     argv += optind;
475     
476     fromlen = sizeof (from);
477
478     if (debug_port || do_fork) {
479         int s;
480         struct servent *ent;
481         struct sockaddr_in sin;
482
483         if (!debug_port) {
484             if (do_encrypt) {
485                 ent = getservbyname("eklogin", "tcp");
486                 if (ent == NULL)
487                     debug_port = 2105;
488                 else
489                     debug_port = ent->s_port;
490             } else {
491                 ent = getservbyname("klogin", "tcp");
492                 if (ent == NULL)
493                     debug_port = 543;
494                 else
495                     debug_port = ent->s_port;
496             }
497         }
498         if ((s = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0) {
499             fprintf(stderr, "Error in socket: %s\n", strerror(errno));
500             exit(2);
501         }
502         memset((char *) &sin, 0,sizeof(sin));
503         sin.sin_family = AF_INET;
504         sin.sin_port = htons(debug_port);
505         sin.sin_addr.s_addr = INADDR_ANY;
506
507         if (!do_fork)
508             (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
509                               (char *)&on, sizeof(on));
510
511         if ((bind(s, (struct sockaddr *) &sin, sizeof(sin))) < 0) {
512             fprintf(stderr, "Error in bind: %s\n", strerror(errno));
513             exit(2);
514         }
515
516         if ((listen(s, 5)) < 0) {
517             fprintf(stderr, "Error in listen: %s\n", strerror(errno));
518             exit(2);
519         }
520
521         if (do_fork) {
522             if (daemon(0, 0)) {
523                 fprintf(stderr, "daemon() failed\n");
524                 exit(2);
525             }
526             while (1) {
527                 int child_pid;
528
529                 fd = accept(s, (struct sockaddr *) &from, &fromlen);
530                 if (s < 0) {
531                     if (errno != EINTR)
532                         syslog(LOG_ERR, "accept: %s", error_message(errno));
533                     continue;
534                 }
535                 child_pid = fork();
536                 switch (child_pid) {
537                 case -1:
538                     syslog(LOG_ERR, "fork: %s", error_message(errno));
539                 case 0:
540                     (void) close(s);
541                     doit(fd, &from);
542                     close(fd);
543                     exit(0);
544                 default:
545                     wait(0);
546                     close(fd);
547                 }
548             }
549         }
550
551         if ((fd = accept(s, (struct sockaddr *) &from, &fromlen)) < 0) {
552             fprintf(stderr, "Error in accept: %s\n", strerror(errno));
553             exit(2);
554         }
555
556         close(s);
557     } else {                    /* !do_fork && !debug_port */
558         if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
559             syslog(LOG_ERR,"Can't get peer name of remote host: %m");
560 #ifdef STDERR_FILENO
561             fatal(STDERR_FILENO, "Can't get peer name of remote host", 1);
562 #else
563             fatal(2, "Can't get peer name of remote host", 1);
564 #endif
565         }
566         fd = 0;
567     }
568
569     doit(fd, &from);
570     return 0;
571 }
572
573
574
575 #ifndef LOG_AUTH
576 #define LOG_AUTH 0
577 #endif
578
579 int     child;
580 int     netf;
581 char    line[MAXPATHLEN];
582 extern  char    *inet_ntoa();
583
584 #ifdef TIOCSWINSZ
585 struct winsize win = { 0, 0, 0, 0 };
586 #endif
587
588 int pid; /* child process id */
589
590 void doit(f, fromp)
591   int f;
592   struct sockaddr_in *fromp;
593 {
594     int p, t, on = 1;
595     register struct hostent *hp;
596     char c;
597     char buferror[255];
598     struct passwd *pwd;
599 #ifdef POSIX_SIGNALS
600     struct sigaction sa;
601 #endif
602     int retval;
603     char *rhost_sane;
604     int syncpipe[2];
605
606     netf = -1;
607     if (setsockopt(f, SOL_SOCKET, SO_KEEPALIVE,
608                    (const char *) &on, sizeof (on)) < 0)
609         syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
610     if (auth_ok == 0) {
611         syslog(LOG_CRIT, "No authentication systems were enabled; all connections will be refused.");
612         fatal(f, "All authentication systems disabled; connection refused.");
613     }
614
615     if (checksum_required&&checksum_ignored) {
616         syslog( LOG_CRIT, "Checksums are required and ignored; these options are mutually exclusive--check the documentation.");
617         fatal(f, "Configuration error: mutually exclusive options specified");
618     }
619     
620     alarm(60);
621     read(f, &c, 1);
622     
623     if (c != 0){
624         exit(1);
625     }
626
627     alarm(0);
628     /* Initialize syncpipe */
629     if (pipe( syncpipe ) < 0 )
630         fatalperror ( f , "");
631     
632
633 #ifdef POSIX_SIGNALS
634     /* Initialize "sa" structure. */
635     (void) sigemptyset(&sa.sa_mask);
636     sa.sa_flags = 0;
637 #endif
638
639     fromp->sin_port = ntohs((u_short)fromp->sin_port);
640     hp = gethostbyaddr((char *) &fromp->sin_addr, sizeof (struct in_addr),
641                        fromp->sin_family);
642     strncpy(rhost_addra, inet_ntoa(fromp->sin_addr), sizeof (rhost_addra));
643     rhost_addra[sizeof (rhost_addra) -1] = '\0';
644     if (hp != NULL) {
645         /* Save hostent information.... */
646         strncpy(rhost_name,hp->h_name,sizeof (rhost_name));
647         rhost_name[sizeof (rhost_name) - 1] = '\0';
648     } else
649         rhost_name[0] = '\0';
650     
651     if (fromp->sin_family != AF_INET)
652       fatal(f, "Permission denied - Malformed from address\n");
653     
654 #ifndef KERBEROS
655     if (fromp->sin_port >= IPPORT_RESERVED ||
656         fromp->sin_port < IPPORT_RESERVED/2)
657       fatal(f, "Permission denied - Connection from bad port");
658 #endif /* KERBEROS */
659     
660     /* Set global netf to f now : we may need to drop everything
661        in do_krb_login. */
662     netf = f;
663     
664 #if defined(KERBEROS)
665     /* All validation, and authorization goes through do_krb_login() */
666     do_krb_login(rhost_addra, rhost_name);
667 #else
668     getstr(f, rusername, sizeof(rusername), "remuser");
669     getstr(f, lusername, sizeof(lusername), "locuser");
670     getstr(f, term, sizeof(term), "Terminal type");
671     rcmd_stream_init_normal();
672 #endif
673     
674     write(f, "", 1);
675     if ((retval = pty_getpty(&p,line, sizeof(line)))) {
676         com_err(progname, retval, "while getting master pty");
677         exit(2);
678     }
679     
680     Pfd = p;
681 #ifdef TIOCSWINSZ
682     (void) ioctl(p, TIOCSWINSZ, &win);
683 #endif
684     
685 #ifdef POSIX_SIGNALS
686     sa.sa_handler = cleanup;
687     (void) sigaction(SIGCHLD, &sa, (struct sigaction *)0);
688     (void) sigaction(SIGTERM, &sa, (struct sigaction *)0);
689 #else
690     signal(SIGCHLD, cleanup);
691     signal(SIGTERM, cleanup);
692 #endif
693     pid = fork();
694     if (pid < 0)
695       fatalperror(f, "");
696     if (pid == 0) {
697 #if defined(POSIX_TERMIOS) && !defined(ultrix)
698         struct termios new_termio;
699 #else
700         struct sgttyb b;
701 #endif /* POSIX_TERMIOS */
702         if ((retval = pty_open_slave(line, &t))) {
703             fatal(f, error_message(retval));
704             exit(1);
705         }
706         
707
708 #if defined(POSIX_TERMIOS) && !defined(ultrix)
709         tcgetattr(t,&new_termio);
710 #if !defined(USE_LOGIN_F)
711         new_termio.c_lflag &= ~(ICANON|ECHO|ISIG|IEXTEN);
712         new_termio.c_iflag &= ~(IXON|IXANY|BRKINT|INLCR|ICRNL);
713 #else
714         new_termio.c_lflag |= (ICANON|ECHO|ISIG|IEXTEN);
715         new_termio.c_oflag |= (ONLCR|OPOST);
716         new_termio.c_iflag |= (IXON|IXANY|BRKINT|INLCR|ICRNL);
717 #endif /*Do we need binary stream?*/
718         new_termio.c_iflag &= ~(ISTRIP);
719         /* new_termio.c_iflag = 0; */
720         /* new_termio.c_oflag = 0; */
721         new_termio.c_cc[VMIN] = 1;
722         new_termio.c_cc[VTIME] = 0;
723         tcsetattr(t,TCSANOW,&new_termio);
724 #else
725         (void)ioctl(t, TIOCGETP, &b);
726         b.sg_flags = RAW|ANYP;
727         (void)ioctl(t, TIOCSETP, &b);
728 #endif /* POSIX_TERMIOS */
729
730         pid = 0;                        /*reset pid incase exec fails*/
731             
732         /*
733          **      signal the parent that we have turned off echo
734          **      on the slave side of the pty ... he's waiting
735          **      because otherwise the rlogin protocol junk gets
736          **      echo'd to the user (locuser^@remuser^@term/baud)
737          **      and we don't get the right tty affiliation, and
738          **      other kinds of hell breaks loose ...
739          */
740         (void) write(syncpipe[1], &c, 1);
741         (void) close(syncpipe[1]);
742         (void) close(syncpipe[0]);
743                 
744         close(f), close(p);
745         dup2(t, 0), dup2(t, 1), dup2(t, 2);
746         if (t > 2)
747           close(t);
748         
749 #if defined(sysvimp)
750         setcompat (COMPAT_CLRPGROUP | (getcompat() & ~COMPAT_BSDTTY));
751 #endif
752         
753         /* Log access to account */
754         pwd = (struct passwd *) getpwnam(lusername);
755         if (pwd && (pwd->pw_uid == 0)) {
756             if (passwd_req)
757               syslog(LOG_NOTICE, "ROOT login by %s (%s@%s (%s)) forcing password access",
758                      krusername ? krusername : "",
759                      rusername, rhost_addra, rhost_name);
760             else
761               syslog(LOG_NOTICE, "ROOT login by %s (%s@%s (%s))", 
762                      krusername ? krusername : "",
763                      rusername, rhost_addra, rhost_name);
764         }
765 #ifdef KERBEROS
766 #if defined(LOG_REMOTE_REALM) && !defined(LOG_OTHER_USERS) && !defined(LOG_ALL_LOGINS)
767         /* Log if principal is from a remote realm */
768         else if (client && !default_realm(client))
769 #endif /* LOG_REMOTE_REALM */
770   
771 #if defined(LOG_OTHER_USERS) && !defined(LOG_ALL_LOGINS) 
772         /* Log if principal name does not map to local username */
773         else if (client && !princ_maps_to_lname(client, lusername))
774 #endif /* LOG_OTHER_USERS */
775
776 #if defined(LOG_ALL_LOGINS)
777         else
778 #endif /* LOG_ALL_LOGINS */
779
780 #if defined(LOG_REMOTE_REALM) || defined(LOG_OTHER_USERS) || defined(LOG_ALL_LOGINS)
781         {
782             if (passwd_req)
783               syslog(LOG_NOTICE,
784                      "login by %s (%s@%s (%s)) as %s forcing password access",
785                      krusername ? krusername : "", rusername,
786                      rhost_addra, rhost_name, lusername);
787             else 
788               syslog(LOG_NOTICE,
789                      "login by %s (%s@%s (%s)) as %s",
790                      krusername ? krusername : "", rusername,
791                      rhost_addra, rhost_name, lusername); 
792         }
793 #endif /* LOG_REMOTE_REALM || LOG_OTHER_USERS || LOG_ALL_LOGINS */
794 #endif /* KERBEROS */
795
796 #ifndef NO_UT_PID
797         {
798
799             pty_update_utmp(PTY_LOGIN_PROCESS, getpid(), "rlogin", line,
800                             ""/*host*/, PTY_TTYSLOT_USABLE);
801         }
802 #endif
803
804 #ifdef USE_LOGIN_F
805 /* use the vendors login, which has -p and -f. Tested on 
806  * AIX 4.1.4 and HPUX 10 
807  */
808     {
809         char *cp;
810         if ((cp = strchr(term,'/')))
811             *cp = '\0';
812         setenv("TERM",term, 1);
813     }
814
815     retval = pty_make_sane_hostname(fromp, maxhostlen,
816                                     stripdomain, always_ip,
817                                     &rhost_sane);
818     if (retval)
819         fatalperror(f, "failed make_sane_hostname");
820     if (passwd_req)
821         execl(login_program, "login", "-p", "-h", rhost_sane,
822           lusername, 0);
823     else
824         execl(login_program, "login", "-p", "-h", rhost_sane,
825              "-f", lusername, 0);
826 #else /* USE_LOGIN_F */
827         execl(login_program, "login", "-r", rhost_sane, 0);
828 #endif /* USE_LOGIN_F */
829         syslog(LOG_ERR, "failed exec of %s: %s",
830                login_program, error_message(errno));
831         fatalperror(f, login_program);
832         /*NOTREACHED*/
833     } /* if (pid == 0) */
834
835     /*
836      **      wait for child to start ... read one byte
837      **      -- see the child, who writes one byte after
838      **      turning off echo on the slave side ...
839      **      The master blocks here until it reads a byte.
840      */
841     
842 (void) close(syncpipe[1]);
843     if (read(syncpipe[0], &c, 1) != 1) {
844         /*
845          * Problems read failed ...
846          */
847         sprintf(buferror, "Cannot read slave pty %s ",line);
848         fatalperror(p,buferror);
849     }
850     close(syncpipe[0]);
851
852     
853 #if defined(KERBEROS) 
854     if (do_encrypt) {
855         if (rcmd_stream_write(f, SECURE_MESSAGE, sizeof(SECURE_MESSAGE), 0) < 0){
856             sprintf(buferror, "Cannot encrypt-write network.");
857             fatal(p,buferror);
858         }
859     }
860     else 
861       /*
862        * if encrypting, don't turn on NBIO, else the read/write routines
863        * will fail to work properly
864        */
865 #endif /* KERBEROS */
866       ioctl(f, FIONBIO, &on);
867     ioctl(p, FIONBIO, &on);
868
869     /* FIONBIO doesn't always work on ptys, use fcntl to set O_NDELAY? */
870     (void) fcntl(p,F_SETFL,fcntl(p,F_GETFL,0) | O_NDELAY);
871
872 #ifdef POSIX_SIGNALS
873     sa.sa_handler = SIG_IGN;
874     (void) sigaction(SIGTSTP, &sa, (struct sigaction *)0);
875 #else
876     signal(SIGTSTP, SIG_IGN);
877 #endif
878
879     
880 #if !defined(USE_LOGIN_F)
881     /* Pass down rusername and lusername to login. */
882     (void) write(p, rusername, strlen(rusername) +1);
883     (void) write(p, lusername, strlen(lusername) +1);
884     /* stuff term info down to login */
885     if ((write(p, term, strlen(term)+1) != (int) strlen(term)+1)) {
886         /*
887          * Problems write failed ...
888          */
889         sprintf(buferror,"Cannot write slave pty %s ",line);
890         fatalperror(f,buferror);
891     }
892
893 #endif
894     protocol(f, p);
895     signal(SIGCHLD, SIG_IGN);
896     cleanup();
897 }
898
899 unsigned char   magic[2] = { 0377, 0377 };
900 #ifdef TIOCSWINSZ
901 #ifndef TIOCPKT_WINDOW
902 #define TIOCPKT_WINDOW 0x80
903 #endif
904 unsigned char   oobdata[] = {TIOCPKT_WINDOW};
905 #else
906 char    oobdata[] = {0};
907 #endif
908
909 int sendoob(fd, byte)
910      int fd;
911      char *byte;
912 {
913     char message[5];
914     int cc;
915
916     if (do_inband) {
917         message[0] = '\377';
918         message[1] = '\377';
919         message[2] = 'o';
920         message[3] = 'o';
921         message[4] = *byte;
922
923         cc = rcmd_stream_write(fd, message, sizeof(message), 0);
924         while (cc < 0 && ((errno == EWOULDBLOCK) || (errno == EAGAIN))) {
925             /* also shouldn't happen */
926             sleep(5);
927             cc = rcmd_stream_write(fd, message, sizeof(message), 0);
928         }
929     } else {
930         send(fd, byte, 1, MSG_OOB);
931     }
932 }
933
934 /*
935  * Handle a "control" request (signaled by magic being present)
936  * in the data stream.  For now, we are only willing to handle
937  * window size changes.
938  */
939 int control(pty, cp, n)
940      int pty;
941      unsigned char *cp;
942      int n;
943 {
944     struct winsize w;
945     int pgrp, got_pgrp;
946     
947     if (n < (int) 4+sizeof (w) || cp[2] != 's' || cp[3] != 's')
948       return (0);
949 #ifdef TIOCSWINSZ
950     oobdata[0] &= ~TIOCPKT_WINDOW;      /* we know he heard */
951     memcpy((char *)&w,cp+4, sizeof(w));
952     w.ws_row = ntohs(w.ws_row);
953     w.ws_col = ntohs(w.ws_col);
954     w.ws_xpixel = ntohs(w.ws_xpixel);
955     w.ws_ypixel = ntohs(w.ws_ypixel);
956     (void)ioctl(pty, TIOCSWINSZ, &w);
957 #ifdef HAVE_TCGETPGRP
958     pgrp = tcgetpgrp (pty);
959     got_pgrp = pgrp != -1;
960 #else
961     got_pgrp = ioctl(pty, TIOCGPGRP, &pgrp) >= 0;
962 #endif
963     if (got_pgrp)
964       (void) killpg(pgrp, SIGWINCH);
965 #endif
966     return (4+sizeof (w));
967 }
968
969
970
971 /*
972  * rlogin "protocol" machine.
973  */
974 void protocol(f, p)
975      int f, p;
976 {
977     unsigned char pibuf[BUFSIZ], qpibuf[BUFSIZ*2], fibuf[BUFSIZ], *pbp, *fbp;
978     register pcc = 0, fcc = 0;
979     int cc;
980     char cntl;
981 #ifdef POSIX_SIGNALS
982     struct sigaction sa;
983 #endif
984 #ifdef TIOCPKT
985     register tiocpkt_on = 0;
986     int on = 1;
987 #endif
988     
989 #if defined(TIOCPKT) && !defined(__svr4__) || defined(solaris20)
990     /* if system has TIOCPKT, try to turn it on. Some drivers
991      * may not support it. Save flag for later. 
992      */
993    if ( ioctl(p, TIOCPKT, &on) < 0)
994         tiocpkt_on = 0;
995    else tiocpkt_on = 1;
996 #endif
997
998     /*
999      * Must ignore SIGTTOU, otherwise we'll stop
1000      * when we try and set slave pty's window shape
1001      * (our controlling tty is the master pty).
1002      */
1003 #ifdef POSIX_SIGNALS
1004     (void) sigemptyset(&sa.sa_mask);
1005     sa.sa_flags = 0;
1006     sa.sa_handler = SIG_IGN;
1007     (void) sigaction(SIGTTOU, &sa, (struct sigaction *)0);
1008 #else
1009     signal(SIGTTOU, SIG_IGN);
1010 #endif
1011 #ifdef TIOCSWINSZ
1012     sendoob(f, oobdata);
1013 #endif
1014     for (;;) {
1015         fd_set ibits, obits, ebits;
1016
1017         FD_ZERO(&ibits);
1018         FD_ZERO(&obits);
1019         FD_ZERO(&ebits);
1020
1021         if (fcc)
1022             FD_SET(p, &obits);
1023         else
1024             FD_SET(f, &ibits);
1025         if (pcc >= 0)
1026             if (pcc)
1027                 FD_SET(f, &obits);
1028             else
1029                 FD_SET(p, &ibits);
1030         
1031         if (select(8*sizeof(ibits), &ibits, &obits, &ebits, 0) < 0) {
1032             if (errno == EINTR)
1033               continue;
1034             fatalperror(f, "select");
1035         }
1036 #define pkcontrol(c)    ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
1037         if (FD_ISSET(f, &ibits)) {
1038             fcc = rcmd_stream_read(f, fibuf, sizeof (fibuf), 0);
1039             if (fcc < 0 && ((errno == EWOULDBLOCK) || (errno == EAGAIN))) {
1040                 fcc = 0;
1041             } else {
1042                 register unsigned char *cp;
1043                 int left, n;
1044                 
1045                 if (fcc <= 0)
1046                     break;
1047                 fbp = fibuf;
1048                 
1049                 for (cp = fibuf; cp < fibuf+fcc-1; cp++) {
1050                     if (cp[0] == magic[0] &&
1051                         cp[1] == magic[1]) {
1052                         left = (fibuf+fcc) - cp;
1053                         n = control(p, cp, left);
1054                         if (n) {
1055                             left -= n;
1056                             fcc -= n;
1057                             if (left > 0)
1058                                 memmove(cp, cp+n, left);
1059                             cp--;
1060                         }
1061                     }
1062                 }
1063             }
1064         }
1065         
1066         if (FD_ISSET(p, &obits) && fcc > 0) {
1067             cc = write(p, fbp, fcc);
1068             if (cc > 0) {
1069                 fcc -= cc;
1070                 fbp += cc;
1071             }
1072         }
1073         
1074         if (FD_ISSET(p, &ibits)) {
1075             pcc = read(p, pibuf, sizeof (pibuf));
1076             pbp = pibuf;
1077             if (pcc < 0 && ((errno == EWOULDBLOCK) || (errno == EAGAIN))) {
1078                 pcc = 0;
1079             } else if (pcc <= 0) {
1080                 break;
1081             }
1082 #ifdef TIOCPKT
1083             else if (tiocpkt_on) {
1084                 if (pibuf[0] == 0) {
1085                     pbp++, pcc--;
1086                 } else {
1087                     if (pkcontrol(pibuf[0])) {
1088                         pibuf[0] |= oobdata[0];
1089                         sendoob(f, pibuf);
1090                     }
1091                     pcc = 0;
1092                 }
1093             }
1094 #endif
1095
1096             /* quote any double-\377's if necessary */
1097
1098             if (do_inband) {
1099                 unsigned char *qpbp;
1100                 int qpcc, i;
1101
1102                 qpbp = qpibuf;
1103                 qpcc = 0;
1104
1105                 for (i=0; i<pcc;) {
1106                     if (pbp[i] == 0377u && (i+1)<pcc && pbp[i+1] == 0377u) {
1107                         qpbp[qpcc] = '\377';
1108                         qpbp[qpcc+1] = '\377';
1109                         qpbp[qpcc+2] = 'q';
1110                         qpbp[qpcc+3] = 'q';
1111                         i += 2;
1112                         qpcc += 4;
1113                     } else {
1114                         qpbp[qpcc] = pbp[i];
1115                         i++;
1116                         qpcc++;
1117                     }
1118                 }
1119
1120                 pbp = qpbp;
1121                 pcc = qpcc;
1122             }
1123         }
1124
1125         if (FD_ISSET(f, &obits) && pcc > 0) {
1126             cc = rcmd_stream_write(f, pbp, pcc, 0);
1127             if (cc < 0 && ((errno == EWOULDBLOCK) || (errno == EAGAIN))) {
1128                 /* also shouldn't happen */
1129                 sleep(5);
1130                 continue;
1131             }
1132             if (cc > 0) {
1133                 pcc -= cc;
1134                 pbp += cc;
1135             }
1136         }
1137     }
1138 }
1139
1140
1141
1142 krb5_sigtype cleanup()
1143 {
1144     pty_cleanup (line, pid, 1);
1145     shutdown(netf, 2);
1146     if (ccache)
1147         krb5_cc_destroy(bsd_context, ccache);
1148     exit(1);
1149 }
1150
1151
1152 void fatal(f, msg)
1153      int f;
1154      char *msg;
1155 {
1156     char buf[512];
1157     int out = 1 ;          /* Output queue of f */
1158 #ifdef POSIX_SIGNALS
1159     struct sigaction sa;
1160 #endif
1161     
1162     buf[0] = '\01';             /* error indicator */
1163     (void) sprintf(buf + 1, "%s: %s.\r\n",progname, msg);
1164     if ((f == netf) && (pid > 0))
1165       (void) rcmd_stream_write(f, buf, strlen(buf), 0);
1166     else
1167       (void) write(f, buf, strlen(buf));
1168     syslog(LOG_ERR,"%s\n",msg);
1169     if (pid > 0) {
1170 #ifdef POSIX_SIGNALS
1171         (void) sigemptyset(&sa.sa_mask);
1172         sa.sa_flags = 0;
1173         sa.sa_handler = SIG_IGN;
1174         (void) sigaction(SIGCHLD, &sa, (struct sigaction *)0);
1175 #else
1176         signal(SIGCHLD,SIG_IGN);
1177 #endif
1178         kill(pid,SIGKILL);
1179 #ifdef  TIOCFLUSH
1180         (void) ioctl(f, TIOCFLUSH, (char *)&out);
1181 #else
1182         (void) ioctl(f, TCFLSH, out);
1183 #endif
1184         cleanup();
1185     }
1186     exit(1);
1187 }
1188
1189
1190
1191 void fatalperror(f, msg)
1192      int f;
1193      char *msg;
1194 {
1195     char buf[512];
1196     
1197     (void) sprintf(buf, "%s: %s", msg, error_message(errno));
1198     fatal(f, buf);
1199 }
1200
1201 #ifdef KERBEROS
1202
1203 void
1204 do_krb_login(host_addr, hostname)
1205      char *host_addr, *hostname;
1206 {
1207     krb5_error_code status;
1208     struct passwd *pwd;
1209     char *msg_fail = NULL;
1210     int valid_checksum;
1211
1212     if (getuid()) {
1213         exit(1);
1214     }
1215
1216     /* Check authentication. This can be either Kerberos V5, */
1217     /* Kerberos V4, or host-based. */
1218     if ((status = recvauth(&valid_checksum))) {
1219         if (ticket)
1220           krb5_free_ticket(bsd_context, ticket);
1221         if (status != 255)
1222           syslog(LOG_ERR,
1223                  "Authentication failed from %s (%s): %s\n",host_addr,
1224                  hostname,error_message(status));
1225         fatal(netf, "Kerberos authentication failed");
1226         return;
1227     }
1228     
1229     /* OK we have authenticated this user - now check authorization. */
1230     /* The Kerberos authenticated programs must use krb5_kuserok or kuserok*/
1231     
1232 #ifndef KRB5_KRB4_COMPAT
1233     if (auth_sys == KRB5_RECVAUTH_V4) {
1234           fatal(netf, "This server does not support Kerberos V4");
1235   }
1236 #endif
1237     
1238
1239 #if (defined(ALWAYS_V5_KUSEROK) || !defined(KRB5_KRB4_COMPAT))
1240         /* krb5_kuserok returns 1 if OK */
1241         if (client && krb5_kuserok(bsd_context, client, lusername))
1242           auth_sent |= ((auth_sys == KRB5_RECVAUTH_V4)?AUTH_KRB4:AUTH_KRB5);
1243 #else
1244         if (auth_sys == KRB5_RECVAUTH_V4) {
1245             /* kuserok returns 0 if OK */
1246             if (!kuserok(v4_kdata, lusername))
1247               auth_sent |= AUTH_KRB4;
1248         } else {
1249             /* krb5_kuserok returns 1 if OK */
1250             if (client && krb5_kuserok(bsd_context, client, lusername))
1251               auth_sent |= AUTH_KRB5;
1252         }
1253 #endif
1254
1255     
1256
1257     if (checksum_required && !valid_checksum) {
1258         if (auth_sent & AUTH_KRB5) {
1259             syslog(LOG_WARNING, "Client did not supply required checksum--connection rejected.");
1260         
1261             fatal(netf, "You are using an old Kerberos5 without initial connection support; only newer clients are authorized.");
1262         } else {
1263           syslog(LOG_WARNING,
1264                  "Configuration error: Requiring checksums with -c is inconsistent with allowing Kerberos V4 connections.");
1265         }
1266     }
1267     if (auth_ok&auth_sent) /* This should be bitwise.*/
1268         return;
1269     
1270     if (ticket)
1271         krb5_free_ticket(bsd_context, ticket);
1272
1273     if (krusername)
1274         msg_fail = (char *)malloc(strlen(krusername) + strlen(lusername) + 80);
1275     if (!msg_fail)
1276         fatal(netf, "User is not authorized to login to specified account");
1277
1278     if (auth_sent)
1279         sprintf(msg_fail, "Access denied because of improper credentials");
1280     else
1281         sprintf(msg_fail, "User %s is not authorized to login to account %s",
1282                 krusername, lusername);
1283     
1284     fatal(netf, msg_fail);
1285     /* NOTREACHED */
1286 }
1287
1288 #endif /* KERBEROS */
1289
1290
1291
1292 void getstr(fd, buf, cnt, err)
1293      int fd;
1294      char *buf;
1295      int cnt;
1296      char *err;
1297 {
1298     
1299     char c;
1300     
1301     do {
1302         if (read(fd, &c, 1) != 1) {
1303             exit(1);
1304         }
1305         if (--cnt < 0) {
1306             printf("%s too long\r\n", err);
1307             exit(1);
1308         }
1309         *buf++ = c;
1310     } while (c != 0);
1311 }
1312
1313
1314
1315 void usage()
1316 {
1317 #ifdef KERBEROS
1318     syslog(LOG_ERR, 
1319            "usage: klogind [-ke45pPf] [-D port] [-w[ip|maxhostlen[,[no]striplocal]]] or [r/R][k/K][x/e][p/P]logind");
1320 #else
1321     syslog(LOG_ERR, 
1322            "usage: rlogind [-rpPf] [-D port] or [r/R][p/P]logind");
1323 #endif
1324 }
1325
1326
1327
1328 #ifdef KERBEROS
1329 int princ_maps_to_lname(principal, luser)       
1330      krb5_principal principal;
1331      char *luser;
1332 {
1333     char kuser[10];
1334     if (!(krb5_aname_to_localname(bsd_context, principal,
1335                                   sizeof(kuser), kuser))
1336         && (strcmp(kuser, luser) == 0)) {
1337         return 1;
1338     }
1339     return 0;
1340 }
1341
1342 int default_realm(principal)
1343      krb5_principal principal;
1344 {
1345     char *def_realm;
1346     int realm_length;
1347     int retval;
1348     
1349     realm_length = krb5_princ_realm(bsd_context, principal)->length;
1350     
1351     if ((retval = krb5_get_default_realm(bsd_context, &def_realm))) {
1352         return 0;
1353     }
1354     
1355     if ((realm_length != strlen(def_realm)) ||
1356         (memcmp(def_realm, krb5_princ_realm(bsd_context, principal)->data, realm_length))) {
1357         free(def_realm);
1358         return 0;
1359     }   
1360     free(def_realm);
1361     return 1;
1362 }
1363
1364
1365 #ifndef KRB_SENDAUTH_VLEN
1366 #define KRB_SENDAUTH_VLEN 8         /* length for version strings */
1367 #endif
1368
1369 #define KRB_SENDAUTH_VERS       "AUTHV0.1" /* MUST be KRB_SENDAUTH_VLEN
1370                                               chars */
1371
1372 krb5_error_code
1373 recvauth(valid_checksum)
1374     int *valid_checksum;
1375 {
1376     krb5_auth_context auth_context = NULL;
1377     krb5_error_code status;
1378     struct sockaddr_in peersin, laddr;
1379     int len;
1380     krb5_data inbuf;
1381     char v4_instance[INST_SZ];  /* V4 Instance */
1382     krb5_data version;
1383     krb5_authenticator *authenticator;
1384     krb5_rcache rcache;
1385     enum kcmd_proto kcmd_proto;
1386     krb5_keyblock *key;
1387
1388     *valid_checksum = 0;
1389     len = sizeof(laddr);
1390     if (getsockname(netf, (struct sockaddr *)&laddr, &len)) {
1391             exit(1);
1392     }
1393         
1394     len = sizeof(peersin);
1395     if (getpeername(netf, (struct sockaddr *)&peersin, &len)) {
1396         syslog(LOG_ERR, "get peer name failed %d", netf);
1397         exit(1);
1398     }
1399
1400     strcpy(v4_instance, "*");
1401
1402     if ((status = krb5_auth_con_init(bsd_context, &auth_context)))
1403         return status;
1404  
1405     /* Only need remote address for rd_cred() to verify client */
1406     if ((status = krb5_auth_con_genaddrs(bsd_context, auth_context, netf,
1407                  KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR)))
1408         return status;
1409
1410     status = krb5_auth_con_getrcache(bsd_context, auth_context, &rcache);
1411     if (status) return status;
1412
1413     if (! rcache) {
1414         krb5_principal server;
1415
1416         status = krb5_sname_to_principal(bsd_context, 0, 0,
1417                                          KRB5_NT_SRV_HST, &server);
1418         if (status) return status;
1419
1420         status = krb5_get_server_rcache(bsd_context,
1421                                 krb5_princ_component(bsd_context, server, 0),
1422                                 &rcache);
1423         krb5_free_principal(bsd_context, server);
1424         if (status) return status;
1425
1426         status = krb5_auth_con_setrcache(bsd_context, auth_context, rcache);
1427         if (status) return status;
1428     }
1429
1430     if ((status = krb5_compat_recvauth_version(bsd_context, &auth_context,
1431                                                &netf,
1432                                   NULL,         /* Specify daemon principal */
1433                                   0,            /* no flags */
1434                                   keytab, /* normally NULL to use v5srvtab */
1435
1436                                   do_encrypt ? KOPT_DO_MUTUAL : 0, /*v4_opts*/
1437                                   "rcmd",       /* v4_service */
1438                                   v4_instance,  /* v4_instance */
1439                                   &peersin,     /* foriegn address */
1440                                   &laddr,       /* our local address */
1441                                   "",           /* use default srvtab */
1442
1443                                   &ticket,      /* return ticket */
1444                                   &auth_sys,    /* which authentication system*/
1445                                   &v4_kdata, v4_schedule,
1446                                                &version))) {
1447         if (auth_sys == KRB5_RECVAUTH_V5) {
1448             /*
1449              * clean up before exiting
1450              */
1451             getstr(netf, lusername, sizeof (lusername), "locuser");
1452             getstr(netf, term, sizeof(term), "Terminal type");
1453             getstr(netf, rusername, sizeof(rusername), "remuser");
1454         }
1455         return status;
1456     }
1457
1458     getstr(netf, lusername, sizeof (lusername), "locuser");
1459     getstr(netf, term, sizeof(term), "Terminal type");
1460
1461     kcmd_proto = KCMD_UNKNOWN_PROTOCOL;
1462     if (auth_sys == KRB5_RECVAUTH_V5) {
1463         if (version.length != 9) {
1464             fatal (netf, "bad application version length");
1465         }
1466         if (!memcmp (version.data, "KCMDV0.1", 9))
1467             kcmd_proto = KCMD_OLD_PROTOCOL;
1468         else if (!memcmp (version.data, "KCMDV0.2", 9))
1469             kcmd_proto = KCMD_NEW_PROTOCOL;
1470     }
1471 #ifdef KRB5_KRB4_COMPAT
1472     if (auth_sys == KRB5_RECVAUTH_V4)
1473         kcmd_proto = KCMD_V4_PROTOCOL;
1474 #endif
1475
1476     if ((auth_sys == KRB5_RECVAUTH_V5)
1477         && !(checksum_ignored
1478              && kcmd_proto == KCMD_OLD_PROTOCOL)) {
1479       
1480       if ((status = krb5_auth_con_getauthenticator(bsd_context, auth_context,
1481                                                    &authenticator)))
1482         return status;
1483     
1484       if (authenticator->checksum) {
1485         struct sockaddr_in adr;
1486         int adr_length = sizeof(adr);
1487         char * chksumbuf = (char *) malloc(strlen(term)+strlen(lusername)+32);
1488         if (getsockname(netf, (struct sockaddr *) &adr, &adr_length) != 0)
1489             goto error_cleanup;
1490         if (chksumbuf == 0)
1491             goto error_cleanup;
1492
1493         sprintf(chksumbuf,"%u:", ntohs(adr.sin_port));
1494         strcat(chksumbuf,term);
1495         strcat(chksumbuf,lusername);
1496
1497         status = krb5_verify_checksum(bsd_context,
1498                                       authenticator->checksum->checksum_type,
1499                                       authenticator->checksum,
1500                                       chksumbuf, strlen(chksumbuf),
1501                                       ticket->enc_part2->session->contents, 
1502                                       ticket->enc_part2->session->length);
1503     error_cleanup:
1504         if (chksumbuf)
1505             free(chksumbuf);
1506         if (status) {
1507           krb5_free_authenticator(bsd_context, authenticator);
1508           return status;
1509         }
1510         *valid_checksum = 1;
1511       }
1512       krb5_free_authenticator(bsd_context, authenticator);
1513     }
1514
1515
1516 #ifdef KRB5_KRB4_COMPAT
1517     if (auth_sys == KRB5_RECVAUTH_V4) {
1518
1519         rcmd_stream_init_krb4(v4_kdata->session, do_encrypt, 1, 1);
1520
1521         /* We do not really know the remote user's login name.
1522          * Assume it to be the same as the first component of the
1523          * principal's name. 
1524          */
1525         strncpy(rusername, v4_kdata->pname, sizeof(rusername) - 1);
1526         rusername[sizeof(rusername) - 1] = '\0';
1527
1528         status = krb5_425_conv_principal(bsd_context, v4_kdata->pname,
1529                                          v4_kdata->pinst, v4_kdata->prealm,
1530                                          &client);
1531         if (status) return status;
1532
1533         status = krb5_unparse_name(bsd_context, client, &krusername);
1534         
1535         return status;
1536     }
1537 #endif
1538
1539     /* Must be V5  */
1540         
1541     if ((status = krb5_copy_principal(bsd_context, ticket->enc_part2->client, 
1542                                       &client)))
1543         return status;
1544
1545     key = 0;
1546     status = krb5_auth_con_getremotesubkey (bsd_context, auth_context, &key);
1547     if (status)
1548         fatal (netf, "Server can't get session subkey");
1549     if (!key && do_encrypt && kcmd_proto == KCMD_NEW_PROTOCOL)
1550         fatal (netf, "No session subkey sent");
1551     if (key && kcmd_proto == KCMD_OLD_PROTOCOL)
1552         fatal (netf, "Session subkey not permitted under old kcmd protocol");
1553     if (key == 0)
1554         key = ticket->enc_part2->session;
1555
1556     rcmd_stream_init_krb5 (key, do_encrypt, 1, 0, kcmd_proto);
1557
1558     do_inband = (kcmd_proto == KCMD_NEW_PROTOCOL);
1559
1560     getstr(netf, rusername, sizeof(rusername), "remuser");
1561
1562     if ((status = krb5_unparse_name(bsd_context, client, &krusername)))
1563         return status;
1564     
1565     if ((status = krb5_read_message(bsd_context, (krb5_pointer)&netf, &inbuf)))
1566         fatal(netf, "Error reading message");
1567
1568     if ((inbuf.length) && /* Forwarding being done, read creds */
1569         (status = rd_and_store_for_creds(bsd_context, auth_context, &inbuf, 
1570                                           ticket, &ccache))) {
1571          fatal(netf, "Can't get forwarded credentials");
1572     }
1573     return 0;
1574 }
1575
1576 #endif /* KERBEROS */