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