*** empty log message ***
authorTheodore Tso <tytso@mit.edu>
Tue, 29 Sep 1992 14:51:34 +0000 (14:51 +0000)
committerTheodore Tso <tytso@mit.edu>
Tue, 29 Sep 1992 14:51:34 +0000 (14:51 +0000)
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@2444 dc483132-0cff-0310-8789-dd5450dbe970

48 files changed:
src/appl/bsd/Imakefile [new file with mode: 0644]
src/appl/bsd/kcmd.c [new file with mode: 0644]
src/appl/bsd/krcp.c [new file with mode: 0644]
src/appl/bsd/krlogin.c [new file with mode: 0644]
src/appl/bsd/krlogind.M [new file with mode: 0644]
src/appl/bsd/krlogind.c [new file with mode: 0644]
src/appl/bsd/krsh.c [new file with mode: 0644]
src/appl/bsd/krshd.M [new file with mode: 0644]
src/appl/bsd/krshd.c [new file with mode: 0644]
src/appl/bsd/login.c [new file with mode: 0644]
src/appl/bsd/logutil.c [new file with mode: 0644]
src/appl/bsd/rcp.M [new file with mode: 0644]
src/appl/bsd/rlogin.M [new file with mode: 0644]
src/appl/bsd/rsh.M [new file with mode: 0644]
src/kadmin/client/Imakefile [new file with mode: 0644]
src/kadmin/client/kadmin.M [new file with mode: 0644]
src/kadmin/client/kadmin.c [new file with mode: 0644]
src/kadmin/client/kadmin_add.c [new file with mode: 0644]
src/kadmin/client/kadmin_adr.c [new file with mode: 0644]
src/kadmin/client/kadmin_cpr.c [new file with mode: 0644]
src/kadmin/client/kadmin_cpw.c [new file with mode: 0644]
src/kadmin/client/kadmin_del.c [new file with mode: 0644]
src/kadmin/client/kadmin_done.c [new file with mode: 0644]
src/kadmin/client/kadmin_inq.c [new file with mode: 0644]
src/kadmin/client/kadmin_mod.c [new file with mode: 0644]
src/kadmin/client/kadmin_msnd.c [new file with mode: 0644]
src/kadmin/kpasswd/Imakefile [new file with mode: 0644]
src/kadmin/kpasswd/kpasswd.M [new file with mode: 0644]
src/kadmin/kpasswd/kpasswd.c [new file with mode: 0644]
src/kadmin/kpasswd/networked.c [new file with mode: 0644]
src/kadmin/server/Imakefile [new file with mode: 0644]
src/kadmin/server/adm_adm_func.c [new file with mode: 0644]
src/kadmin/server/adm_check.c [new file with mode: 0644]
src/kadmin/server/adm_extern.c [new file with mode: 0644]
src/kadmin/server/adm_extern.h [new file with mode: 0644]
src/kadmin/server/adm_fmt_inq.c [new file with mode: 0644]
src/kadmin/server/adm_funcs.c [new file with mode: 0644]
src/kadmin/server/adm_kadmin.c [new file with mode: 0644]
src/kadmin/server/adm_kpasswd.c [new file with mode: 0644]
src/kadmin/server/adm_listen.c [new file with mode: 0644]
src/kadmin/server/adm_nego.c [new file with mode: 0644]
src/kadmin/server/adm_network.c [new file with mode: 0644]
src/kadmin/server/adm_parse.c [new file with mode: 0644]
src/kadmin/server/adm_process.c [new file with mode: 0644]
src/kadmin/server/adm_server.c [new file with mode: 0644]
src/kadmin/server/adm_server.h [new file with mode: 0644]
src/kadmin/server/adm_v4_pwd.c [new file with mode: 0644]
src/kadmin/server/kadmind.M [new file with mode: 0644]

diff --git a/src/appl/bsd/Imakefile b/src/appl/bsd/Imakefile
new file mode 100644 (file)
index 0000000..fa3392e
--- /dev/null
@@ -0,0 +1,70 @@
+#      $Source$
+#      $Author$
+#      $Id$
+#
+#  Copyright 1990,1991 by the Massachusetts Institute of Technology.
+#  All Rights Reserved.
+# 
+# Export of this software from the United States of America is assumed
+#   to require a specific license from the United States Government.
+#   It is the responsibility of any person or organization contemplating
+#   export to obtain such a license before exporting.
+# 
+# WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+# distribute this software and its documentation for any purpose and
+# without fee is hereby granted, provided that the above copyright
+# notice appear in all copies and that both that copyright notice and
+# this permission notice appear in supporting documentation, and that
+# the name of M.I.T. not be used in advertising or publicity pertaining
+# to distribution of the software without specific, written prior
+# permission.  M.I.T. makes no representations about the suitability of
+# this software for any purpose.  It is provided "as is" without express
+# or implied warranty.
+# 
+# 
+
+        DEPLIBS = $(DEPKLIB)
+#ifdef CrayArchitecture
+LOCAL_LIBRARIES = $(KLIB) -lshare  -lm -lrsc
+#else
+LOCAL_LIBRARIES = $(KLIB)
+#endif
+        DEFINES = $(APPL_BSD_DEF)
+
+CLIENTSRCS= krcp.c krlogin.c krsh.c kcmd.c logutil.c
+CLIENTOBJS= krcp.o krlogin.o krsh.o kcmd.o logutil.o
+
+#ifdef CrayArchitecture
+SERVERSRCS= krshd.c
+SERVEROBJS= krshd.o
+#else
+SERVERSRCS= krlogind.c krshd.c
+SERVEROBJS= krlogind.o krshd.o
+#endif
+
+SRCS= $(CLIENTSRCS) $(SERVERSRCS)
+
+#ifdef CrayArchitecture
+all::  rsh rcp rlogin krshd 
+#else
+all::  rsh rcp rlogin krshd krlogind
+#endif
+
+NormalProgramTarget(rsh,krsh.o kcmd.o,$(DEPLIBS),$(LOCAL_LIBRARIES),)
+Krb5InstallClientProgram(rsh)
+
+NormalProgramTarget(rcp,krcp.o kcmd.o,$(DEPLIBS),$(LOCAL_LIBRARIES),)
+Krb5InstallClientProgram(rcp)
+
+NormalProgramTarget(rlogin,krlogin.o kcmd.o,$(DEPLIBS),$(LOCAL_LIBRARIES),)
+Krb5InstallClientProgram(rlogin)
+
+NormalProgramTarget(krshd,krshd.o kcmd.o logutil.o,$(DEPLIBS),$(LOCAL_LIBRARIES),)
+Krb5InstallServerProgram(krshd)
+
+#ifndef CrayArchitecture
+NormalProgramTarget(krlogind,krlogind.o logutil.o kcmd.o,$(DEPLIBS),$(LOCAL_LIBRARIES),)
+#endif
+Krb5InstallServerProgram(krlogind)
+
+DependTarget()
diff --git a/src/appl/bsd/kcmd.c b/src/appl/bsd/kcmd.c
new file mode 100644 (file)
index 0000000..a7b9f96
--- /dev/null
@@ -0,0 +1,611 @@
+/*
+ *    $Source$
+ *    $Id$
+ */
+
+#ifndef lint
+static char *rcsid_kcmd_c =
+  "$Id$";
+#endif /* lint */
+#define LIBC_SCCS
+
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "derived from @(#)rcmd.c        5.17 (Berkeley) 6/27/88";
+#endif /* LIBC_SCCS and not lint */
+     
+#include <stdio.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <sys/param.h>
+#ifndef _TYPES_
+#include <sys/types.h>
+#define _TYPES_
+#endif
+     
+     
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 1024
+#endif
+#include <sys/file.h>
+#include <sys/signal.h>
+#ifndef sigmask
+#define sigmask(m)    (1 << ((m)-1))
+#endif
+#include <sys/socket.h>
+#include <sys/stat.h>
+     
+#include <netinet/in.h>
+#include <netdb.h>
+     
+#include <errno.h>
+#include <krb5/krb5.h>
+#include <krb5/asn1.h>
+     
+#ifndef MAXHOSTNAMELEN 
+#define MAXHOSTNAMELEN 64
+#endif
+     
+extern errno;
+
+#define        START_PORT      5120     /* arbitrary */
+char *default_service = "host";
+
+
+
+kcmd(sock, ahost, rport, locuser, remuser, cmd, fd2p, service, realm,
+     cred, seqno, server_seqno, laddr, faddr, authopts)
+     int *sock;
+     char **ahost;
+     u_short rport;
+     char *locuser, *remuser, *cmd;
+     int *fd2p;
+     char *service;
+     char *realm;
+     krb5_creds **cred;
+     krb5_int32 *seqno;
+     krb5_int32 *server_seqno;
+     struct sockaddr_in *laddr, *faddr;
+     krb5_flags authopts;
+{
+    int s, timo = 1, pid;
+    long oldmask;
+    struct sockaddr_in sin, from, local_laddr;
+    krb5_creds *ret_cred = 0;
+    char c;
+    int lport = START_PORT;
+    struct hostent *hp;
+    int rc;
+    char *host_save;
+    krb5_error_code status;
+    krb5_error *err_ret;
+    krb5_ap_rep_enc_part *rep_ret;
+    krb5_checksum send_cksum;
+    krb5_principal server, client;
+    char *tmpstr = 0;
+    int sin_len;
+    krb5_ccache cc;
+    krb5_data outbuf;
+    
+    pid = getpid();
+    hp = gethostbyname(*ahost);
+    if (hp == 0) {
+       fprintf(stderr, "%s: unknown host\n", *ahost);
+       return (-1);
+    }
+    
+    host_save = malloc(strlen(hp->h_name) + 1);
+    if ( host_save == (char *) 0){
+        fprintf(stderr,"kcmd: no memory\n");
+        return(-1);
+    }
+
+    strcpy(host_save, hp->h_name);
+
+    *ahost = host_save;
+    
+    /* If no service is given set to the default service */
+    if (!service) service = default_service;
+    
+    sin_len = strlen(host_save) + strlen(service)
+      + (realm ? strlen(realm): 0) + 3;
+    if ( sin_len < 20 ) sin_len = 20;
+    tmpstr = malloc(sin_len);
+    if ( tmpstr == (char *) 0){
+       fprintf(stderr,"kcmd: no memory\n");
+       return(-1);
+    }
+    
+    if (!(ret_cred = (krb5_creds *)calloc(1,sizeof(*ret_cred)))){
+        fprintf(stderr,"kcmd: no memory\n");
+        return(-1);
+    }
+    if ((realm == NULL) || (realm[0] == '\0')) {
+       krb5_sname_to_principal(host_save,service,1,&ret_cred->server);
+    }
+    else {
+        sprintf(tmpstr,"%s/%s@%s",service,host_save,realm);
+        krb5_parse_name(tmpstr,&ret_cred->server);
+    }
+#ifdef sgi
+    oldmask = sigignore(sigmask(SIGURG));
+#else
+    oldmask = sigblock(sigmask(SIGURG));
+#endif
+    
+    for (;;) {
+        s = getport(&lport);
+       if (s < 0) {
+           if (errno == EAGAIN)
+             fprintf(stderr, "socket: All ports in use\n");
+           else
+             perror("kcmd: socket");
+#ifndef sgi
+           sigsetmask(oldmask);
+#endif
+           if (tmpstr) xfree(tmpstr);
+           if (host_save) xfree(host_save);
+           krb5_free_creds(ret_cred);
+           return (-1);
+       }
+#if defined (hpux) || defined (CRAY)  /*hpux does not handle async
+                                       io thus setown is disabled */
+#else
+       fcntl(s, F_SETOWN, pid);
+#endif /* hpux */
+       sin.sin_family = hp->h_addrtype;
+       memcpy((caddr_t)&sin.sin_addr,hp->h_addr, hp->h_length);
+       sin.sin_port = rport;
+       if (connect(s, (struct sockaddr *)&sin, sizeof (sin)) >= 0)
+         break;
+       (void) close(s);
+       if (errno == EADDRINUSE) {
+           lport--;
+           continue;
+       }
+       /*
+        * don't wait very long for Kerberos kcmd.
+        */
+       if (errno == ECONNREFUSED && timo <= 4) {
+           sleep(timo);
+           timo *= 2;
+           continue;
+       }
+#if !(defined(tek) || defined(ultrix) || defined(sun) || defined(SYSV))
+       if (hp->h_addr_list[1] != NULL) {
+           int oerrno = errno;
+           
+           fprintf(stderr,
+                   "connect to address %s: ", inet_ntoa(sin.sin_addr));
+           errno = oerrno;
+           perror(0);
+           hp->h_addr_list++;
+           memcpy((caddr_t)&sin.sin_addr,hp->h_addr_list[0],
+                  hp->h_length);
+           fprintf(stderr, "Trying %s...\n",
+                   inet_ntoa(sin.sin_addr));
+           continue;
+       }
+#endif /* !(defined(ultrix) || defined(sun)) */
+       perror(hp->h_name);
+#ifndef sgi
+       sigsetmask(oldmask);
+#endif
+       if (tmpstr) xfree(tmpstr);
+       if (host_save) xfree(host_save);
+       krb5_free_creds(ret_cred);
+       return (-1);
+    }
+    lport--;
+    if (fd2p == 0) {
+       write(s, "", 1);
+       lport = 0;
+    } else {
+       char num[8];
+       int s2 = getport(&lport), s3;
+       int len = sizeof (from);
+       
+       if (s2 < 0) {
+           status = -1;
+           goto bad;
+       }
+       listen(s2, 1);
+       (void) sprintf(num, "%d", lport);
+       if (write(s, num, strlen(num)+1) != strlen(num)+1) {
+           perror("write: setting up stderr");
+           (void) close(s2);
+           status = -1;
+           goto bad;
+       }
+       s3 = accept(s2, (struct sockaddr *)&from, &len);
+       (void) close(s2);
+       if (s3 < 0) {
+           perror("accept");
+           lport = 0;
+           status = -1;
+           goto bad;
+       }
+       *fd2p = s3;
+       from.sin_port = ntohs((u_short)from.sin_port);
+       if (from.sin_family != AF_INET ||
+           from.sin_port >= IPPORT_RESERVED) {
+           fprintf(stderr,
+                   "socket: protocol failure in circuit setup.\n");
+           goto bad2;
+       }
+    }
+    
+    if (!laddr) laddr = &local_laddr;
+    if (!faddr) faddr = &sin;
+    else 
+      memcpy(faddr,&sin,sizeof(sin));
+    
+    sin_len = sizeof (struct sockaddr_in);
+    if (getsockname(s, (struct sockaddr *)laddr, &sin_len) < 0) {
+        perror("getsockname");
+        status = -1;
+        goto bad2;
+    }
+    
+    /* compute checksum, using CRC-32 */
+    if (!(send_cksum.contents = (krb5_octet *)
+          malloc(krb5_checksum_size(CKSUMTYPE_CRC32)))) {
+        status = -1;
+        goto bad2;
+    }
+    /* choose some random stuff to compute checksum from */
+    sprintf(tmpstr,"%x %x",pid,pid);
+    if (status = krb5_calculate_checksum(CKSUMTYPE_CRC32,
+                                         tmpstr,
+                                         strlen(tmpstr),
+                                         0,
+                                         0, /* if length is 0, crc-32 doesn't
+                                               use the seed */
+                                         &send_cksum)) 
+      goto bad3;
+    
+    status = krb5_cc_default(&cc);
+    if (status) goto bad3;
+
+    status = krb5_cc_get_principal(cc, &ret_cred->client);
+    if (status) goto bad3;
+
+    /* Get ticket from credentials cache or kdc */
+    status = krb5_get_credentials(0, cc, ret_cred);
+    if (status) goto bad3;
+
+    krb5_cc_close(cc);
+
+   /* call Kerberos library routine to obtain an authenticator,
+       pass it over the socket to the server, and obtain mutual
+       authentication. */
+    status = krb5_sendauth((krb5_pointer) &s,
+                           "KCMDV0.1", ret_cred->client, ret_cred->server,
+                           AP_OPTS_MUTUAL_REQUIRED,
+                           &send_cksum,
+                           ret_cred,
+                           0,          /* We have the credentials */
+                           seqno,
+                           0,           /* don't need a subsession key */
+                           0,          /* No error return */
+                           &rep_ret);
+    
+    if (status) goto bad3;
+    if (rep_ret && server_seqno) {
+       *server_seqno = rep_ret->seq_number;
+       krb5_free_ap_rep_enc_part(rep_ret);
+    }
+    
+    outbuf.length = 0;
+
+    /* Send two empty messages. These will be used in a later release
+       to send a forwarded TGT and related info. */
+    if (status = krb5_write_message((krb5_pointer)&s, &outbuf))
+       goto bad3;
+    if (status = krb5_write_message((krb5_pointer)&s, &outbuf))
+       goto bad3;
+
+    (void) write(s, remuser, strlen(remuser)+1);
+    (void) write(s, cmd, strlen(cmd)+1);
+    (void) write(s, locuser, strlen(locuser)+1);
+    
+    if ((rc=read(s, &c, 1)) != 1) {
+       if (rc==-1) {
+           perror(*ahost);
+       } else {
+           fprintf(stderr,"kcmd: bad connection with remote host\n");
+       }
+       status = -1;
+       goto bad3;
+    }
+    if (c != 0) {
+       while (read(s, &c, 1) == 1) {
+           (void) write(2, &c, 1);
+           if (c == '\n')
+             break;
+       }
+       status = -1;
+       goto bad3;
+    }
+#ifndef sgi
+    sigsetmask(oldmask);
+#endif
+    *sock = s;
+    if (tmpstr) xfree(tmpstr);
+    if (host_save) xfree(host_save);
+    
+    /* Pass back credentials if wanted */
+    if (cred) krb5_copy_creds(ret_cred,cred);
+    krb5_free_creds(ret_cred);
+    
+    return (0);
+  bad3:
+    free(send_cksum.contents);
+  bad2:
+    if (lport)
+      (void) close(*fd2p);
+  bad:
+    (void) close(s);
+#ifndef sgi
+    sigsetmask(oldmask);
+#endif
+    if (tmpstr) xfree(tmpstr);
+    if (host_save) xfree(host_save);
+    if (ret_cred)
+      krb5_free_creds(ret_cred);
+    return (status);
+}
+
+
+
+getport(alport)
+     int *alport;
+{
+    struct sockaddr_in sin;
+    int s;
+    
+    sin.sin_family = AF_INET;
+    sin.sin_addr.s_addr = INADDR_ANY;
+    s = socket(AF_INET, SOCK_STREAM, 0);
+    if (s < 0)
+      return (-1);
+    for (;;) {
+       sin.sin_port = htons((u_short)*alport);
+       if (bind(s, (struct sockaddr *)&sin, sizeof (sin)) >= 0)
+         return (s);
+       if (errno != EADDRINUSE) {
+           (void) close(s);
+           return (-1);
+       }
+       (*alport)--;
+       if (*alport == IPPORT_RESERVED) {
+           (void) close(s);
+           errno = EAGAIN;             /* close */
+           return (-1);
+       }
+    }
+}
+
+
+
+#if defined(sun)
+/* The IMP  and ultrix do not like multiple defined routines 
+   and since it does not have users with NFS filesystems 
+   mounted, the ruserok on it's OS will work just fine. 
+   However that is not the case with SUNS who's ruserok which 
+   is provided with the OS has problems with it's seteuid
+   ( which will eventually be traced no doubt to using
+   setreuid(-1,pgid)).
+   Therefore we provide a version of ruserok with fixes
+   the seteuid problem....Drawback - it can only be used
+   by a root process.*/
+
+#ifndef convex
+ruserok(rhost, superuser, ruser, luser)
+     char *rhost;
+     int superuser;
+     char *ruser, *luser;
+{
+    FILE *hostf;
+    char fhost[MAXHOSTNAMELEN];
+    int first = 1;
+    register char *sp, *p;
+    int baselen = -1;
+    int euid = -1;
+    
+    sp = rhost;
+    p = fhost;
+    while (*sp) {
+       if (*sp == '.') {
+           if (baselen == -1)
+             baselen = sp - rhost;
+           *p++ = *sp++;
+       } else {
+           *p++ = islower(*sp) ? toupper(*sp++) : *sp++;
+       }
+    }
+    *p = '\0';
+    hostf = superuser ? (FILE *)0 : fopen("/etc/hosts.equiv", "r");
+  again:
+    if (hostf) {
+       if (!_validuser(hostf, fhost, luser, ruser, baselen)) {
+           (void) fclose(hostf);
+           if (euid != -1)
+             (void) setreuid ( 0,euid);
+           return(0);
+       }
+       (void) fclose(hostf);
+    }
+    if (first == 1) {
+       struct stat sbuf;
+       struct passwd *pwd;
+       char pbuf[MAXPATHLEN];
+       
+       first = 0;
+       if ((pwd = getpwnam(luser)) == NULL)
+         return(-1);
+       /*
+        * Read .rhosts as the local user to avoid NFS mapping the 
+        * root uid to something that can't read .rhosts.
+        */
+       euid = geteuid();
+       if (euid != -1)
+         (void) setreuid ( 0,pwd->pw_uid);
+       (void)strcpy(pbuf, pwd->pw_dir);
+       (void)strcat(pbuf, "/.rhosts");
+       if ((hostf = fopen(pbuf, "r")) == NULL){
+           if (euid != -1)
+             (void) setreuid ( 0,euid);
+           return(-1);
+       }
+       (void)fstat(fileno(hostf), &sbuf);
+       if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid) {
+           fclose(hostf);
+           if (euid != -1)
+             (void) setreuid ( 0,euid);
+           return(-1);
+       }
+       goto again;
+    }
+    if (euid != -1)
+      (void) setreuid ( 0,euid);
+    return (-1);
+}
+
+
+
+_validuser(hostf, rhost, luser, ruser, baselen)
+     char *rhost, *luser, *ruser;
+     FILE *hostf;
+     int baselen;
+{
+    char *user;
+    char ahost[MAXHOSTNAMELEN];
+    register char *p;
+    
+    while (fgets(ahost, sizeof (ahost), hostf)) {
+       p = ahost;
+       while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') {
+           *p = islower(*p) ? toupper(*p) : *p;
+           p++;
+       }
+       if (*p == ' ' || *p == '\t') {
+           *p++ = '\0';
+           while (*p == ' ' || *p == '\t')
+             p++;
+           user = p;
+           while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0')
+             p++;
+       } else
+         user = p;
+       *p = '\0';
+       if (_checkhost(rhost, ahost, baselen) &&
+           !strcmp(ruser, *user ? user : luser)) {
+           return (0);
+       }
+    }
+    return (-1);
+}
+#endif /* convex */
+
+
+
+_checkhost(rhost, lhost, len)
+     char *rhost, *lhost;
+     int len;
+{
+    static char ldomain[MAXHOSTNAMELEN + 1];
+    static char *domainp = NULL;
+    static int nodomain = 0;
+    register char *cp;
+    
+    if (len == -1)
+      return(!strcmp(rhost, lhost));
+    if (strncmp(rhost, lhost, len))
+      return(0);
+    if (!strcmp(rhost, lhost))
+      return(1);
+    if (*(lhost + len) != '\0')
+      return(0);
+    if (nodomain)
+      return(0);
+    if (!domainp) {
+       if (gethostname(ldomain, sizeof(ldomain)) == -1) {
+           nodomain = 1;
+           return(0);
+       }
+       ldomain[MAXHOSTNAMELEN] = NULL;
+       if ((domainp = index(ldomain, '.')) == (char *)NULL) {
+           nodomain = 1;
+           return(0);
+       }
+       for (cp = ++domainp; *cp; ++cp)
+         if (islower(*cp))
+           *cp = toupper(*cp);
+    }
+    return(!strcmp(domainp, rhost + len +1));
+    
+}
+#endif /* ! sysvimp */
+
+
+
+#if defined (hpux)
+int setreuid(real,eff)
+     int real,eff;
+{
+    int tmpint = -1;
+    return(setresuid(real,eff,tmpint));
+}
+#endif
+
+
+
+/* Strsave was a routine in the version 4 krb library: we put it here
+   for compatablilty with version 5 krb library, since kcmd.o is linked
+   into all programs. */
+
+char *
+  strsave(sp)
+char *sp;
+{
+    register char *ret;
+    
+    if((ret = malloc((unsigned) strlen(sp)+1)) == NULL) {
+       fprintf(stderr, "no memory for saving args\n");
+       exit(1);
+    }
+    (void) strcpy(ret,sp);
+    return(ret);
+}
+
+
+
+#ifdef SYSV
+
+int killpg(pid,sig)
+     int pid,sig;
+{
+    
+    if ( pid >= 0)
+      pid *= -1;
+    return(kill(pid,sig));
+}
+
+#endif
diff --git a/src/appl/bsd/krcp.c b/src/appl/bsd/krcp.c
new file mode 100644 (file)
index 0000000..a6ecf15
--- /dev/null
@@ -0,0 +1,1420 @@
+/*
+ *     $Source$
+ *     $Header$
+ */
+
+#ifndef lint
+static char *rcsid_rcp_c = "$Header$";
+#endif /* lint */
+
+/*
+ * Copyright (c) 1983 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+char copyright[] =
+  "@(#) Copyright (c) 1983 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)rcp.c      5.10 (Berkeley) 9/20/88";
+#endif /* not lint */
+
+#define KERBEROS
+     
+     /*
+      * rcp
+      */
+#include <sys/param.h>
+#ifndef _TYPES_
+#include <sys/types.h>
+#define _TYPES_
+#endif
+#include <sys/file.h>
+#ifdef CRAY
+#include <sys/fcntl.h>
+#endif
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+     
+#include <netinet/in.h>
+     
+#include <stdio.h>
+#include <signal.h>
+#include <pwd.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <errno.h>
+     
+#ifdef KERBEROS
+#include <krb5/krb5.h>
+#include <krb5/asn1.h>
+#include <krb5/crc-32.h>
+#include <krb5/mit-des.h>
+#include <krb5/los-proto.h>
+
+#include <com_err.h>
+     
+#ifdef BUFSIZ
+#undef BUFSIZ
+#endif
+#define BUFSIZ 4096
+     
+int sock;
+struct sockaddr_in foreign;       /* set up by kcmd used by send_auth */
+char *krb_realm = (char *)0;
+char des_inbuf[2*BUFSIZ];          /* needs to be > largest read size */
+char des_outbuf[2*BUFSIZ];         /* needs to be > largest write size */
+krb5_data desinbuf,desoutbuf;
+krb5_encrypt_block eblock;         /* eblock for encrypt/decrypt */
+krb5_keyblock *session_key;       /* static key for session */
+
+void   try_normal();
+char   **save_argv(), *strsave();
+int    des_write(), des_read();
+void   send_auth(), answer_auth();
+int    encryptflag = 0;
+
+#define        UCB_RCP "/bin/rcp"
+
+#ifdef CRAY
+#ifndef BITS64
+#define BITS64
+#endif
+#endif
+
+#else /* !KERBEROS */
+#define        des_read        read
+#define        des_write       write
+#endif /* KERBEROS */
+
+int    rem;
+char   *colon(), *index(), *rindex(), *strcpy();
+int    errs;
+krb5_sigtype   lostconn();
+int    errno;
+extern char    *sys_errlist[];
+int    iamremote, targetshouldbedirectory;
+int    iamrecursive;
+int    pflag;
+struct passwd *pwd;
+#ifndef convex
+struct passwd *getpwuid();
+#endif
+int    userid;
+int    port;
+
+struct buffer {
+    int        cnt;
+    char       *buf;
+} *allocbuf();
+
+#define        NULLBUF (struct buffer *) 0
+  
+  /*VARARGS*/
+  int  error();
+
+#define        ga()            (void) des_write(rem, "", 1)
+
+
+main(argc, argv)
+     int argc;
+     char **argv;
+{
+    char *targ, *host, *src;
+    char *suser, *tuser, *thost;
+    int i;
+    char buf[BUFSIZ], cmd[16];
+    struct servent *sp;
+    static char curhost[256];
+#ifdef KERBEROS
+    krb5_flags authopts;
+    krb5_error_code status;    
+    char **orig_argv = save_argv(argc, argv);
+    
+    sp = getservbyname("kshell", "tcp");
+    krb5_init_ets();
+    desinbuf.data = des_inbuf;
+    desoutbuf.data = des_outbuf;    /* Set up des buffers */
+    
+#else
+    sp = getservbyname("shell", "tcp");
+#endif /* KERBEROS */
+    if (sp == NULL) {
+#ifdef KERBEROS
+       fprintf(stderr, "rcp: kshell/tcp: unknown service\n");
+       try_normal(orig_argv);
+#else
+       fprintf(stderr, "rcp: shell/tcp: unknown service\n");
+       exit(1);
+#endif /* KERBEROS */
+    }
+    port = sp->s_port;
+    pwd = getpwuid(userid = getuid());
+    if (pwd == 0) {
+       fprintf(stderr, "who are you?\n");
+       exit(1);
+    }
+    
+    for (argc--, argv++; argc > 0 && **argv == '-'; argc--, argv++) {
+       (*argv)++;
+       while (**argv) switch (*(*argv)++) {
+           
+         case 'r':
+           iamrecursive++;
+           break;
+           
+         case 'p':             /* preserve mtimes and atimes */
+           pflag++;
+           break;
+           
+#ifdef KERBEROS
+         case 'x':
+           encryptflag++;
+           break;
+         case 'k':             /* Change kerberos realm */
+           argc--, argv++;
+           if (argc == 0) 
+             usage();
+           if(!(krb_realm = (char *)malloc(strlen(*argv) + 1))){
+               fprintf(stderr, "rcp: Cannot malloc.\n");
+               exit(1);
+           }
+           strcpy(krb_realm, *argv);   
+           goto next_arg;
+#endif /* KERBEROS */
+           /* The rest of these are not for users. */
+         case 'd':
+           targetshouldbedirectory = 1;
+           break;
+           
+         case 'f':             /* "from" */
+           iamremote = 1;
+#if defined(KERBEROS)
+           if (encryptflag)
+             answer_auth();
+#endif /* KERBEROS */
+           (void) response();
+           source(--argc, ++argv);
+           exit(errs);
+           
+         case 't':             /* "to" */
+           iamremote = 1;
+#if defined(KERBEROS) 
+           if (encryptflag)
+             answer_auth();
+#endif /* KERBEROS */
+           sink(--argc, ++argv);
+           exit(errs);
+           
+         default:
+           usage();
+       }
+#ifdef KERBEROS
+      next_arg: ;
+#endif /* KERBEROS */
+    }
+    
+    if (argc < 2)
+      usage();
+    if (argc > 2)
+      targetshouldbedirectory = 1;
+    rem = -1;
+#ifdef KERBEROS
+    (void) sprintf(cmd, "rcp%s%s%s%s",
+                  iamrecursive ? " -r" : "", pflag ? " -p" : "", 
+                  encryptflag ? " -x" : "",
+                  targetshouldbedirectory ? " -d" : "");
+#else /* !KERBEROS */
+    
+    (void) sprintf(cmd, "rcp%s%s%s",
+                  iamrecursive ? " -r" : "", pflag ? " -p" : "", 
+                  targetshouldbedirectory ? " -d" : "");
+#endif /* KERBEROS */
+    
+    (void) signal(SIGPIPE, lostconn);
+    targ = colon(argv[argc - 1]);
+    
+    /* Check if target machine is the current machine. */
+    
+    gethostname(curhost, sizeof(curhost));
+    if (targ) {                                /* ... to remote */
+       *targ++ = 0;
+       if (hosteq(argv[argc - 1], curhost)) {
+           
+           /* If so, pretend there wasn't even one given
+            * check for an argument of just "host:", it
+            * should become "."
+            */
+           
+           if (*targ == 0) {
+               targ = ".";
+               argv[argc - 1] = targ;
+           }
+           else
+             argv[argc - 1] = targ;
+           targ = 0;
+       }
+    }
+    if (targ) {
+       /* Target machine is some remote machine */
+       if (*targ == 0)
+         targ = ".";
+       thost = index(argv[argc - 1], '@');
+       if (thost) {
+           *thost++ = 0;
+           tuser = argv[argc - 1];
+           if (*tuser == '\0')
+             tuser = NULL;
+           else if (!okname(tuser))
+             exit(1);
+       } else {
+           thost = argv[argc - 1];
+           tuser = NULL;
+       }
+       for (i = 0; i < argc - 1; i++) {
+           src = colon(argv[i]);
+           if (src) {          /* remote to remote */
+               *src++ = 0;
+               if (*src == 0)
+                 src = ".";
+               host = index(argv[i], '@');
+               if (host) {
+                   *host++ = 0;
+                   suser = argv[i];
+                   if (*suser == '\0')
+                     suser = pwd->pw_name;
+                   else if (!okname(suser))
+                     continue;
+#ifdef hpux
+                   (void) sprintf(buf, "remsh %s -l %s -n %s %s '%s%s%s:%s'",
+#else
+                   (void) sprintf(buf, "rsh %s -l %s -n %s %s '%s%s%s:%s'",
+#endif
+                                  host, suser, cmd, src,
+                                  tuser ? tuser : "",
+                                  tuser ? "@" : "",
+                                  thost, targ);
+              } else
+#ifdef hpux
+                  (void) sprintf(buf, "remsh %s -n %s %s '%s%s%s:%s'",
+#else
+                   (void) sprintf(buf, "rsh %s -n %s %s '%s%s%s:%s'",
+#endif
+                                  argv[i], cmd, src,
+                                  tuser ? tuser : "",
+                                  tuser ? "@" : "",
+                                  thost, targ);
+               (void) susystem(buf);
+           } else {            /* local to remote */
+               if (rem == -1) {
+                   (void) sprintf(buf, "%s -t %s",
+                                  cmd, targ);
+                   host = thost;
+#ifdef KERBEROS
+                   authopts = AP_OPTS_MUTUAL_REQUIRED;
+                   status = kcmd(&sock, &host,
+                                 port,
+                                 pwd->pw_name,
+                                 tuser ? tuser :
+                                 pwd->pw_name,
+                                 buf,
+                                 0,
+                                 "host",
+                                 krb_realm,
+                                 0,  /* No return cred */
+                                 0,  /* No seq # */
+                                 0,  /* No server seq # */
+                                 (struct sockaddr_in *) 0,
+                                 &foreign,
+                                 authopts);
+                   if (status) {
+                       fprintf(stderr,
+                               "%s: kcmd to host %s failed - %s\n",
+                               orig_argv[0], host,
+                               error_message(status));
+                       try_normal(orig_argv);
+                   }
+                   else {
+                       rem = sock; 
+                       if (encryptflag)
+                         send_auth();
+                   }
+#else
+                   rem = rcmd(&host, port, pwd->pw_name,
+                              tuser ? tuser : pwd->pw_name,
+                              buf, 0);
+                   if (rem < 0)
+                     exit(1);
+#endif /* KERBEROS */
+                   if (response() < 0)
+                     exit(1);
+               }
+               source(1, argv+i);
+           }
+       }
+    } else {                           /* ... to local */
+       if (targetshouldbedirectory)
+         verifydir(argv[argc - 1]);
+       for (i = 0; i < argc - 1; i++) {
+           src = colon(argv[i]);
+           /* Check if source machine is current machine */
+           if (src) {
+               *src++ = 0;
+               if (hosteq(argv[i], curhost)) {
+                   
+                   /* If so, pretend src machine never given */
+                   
+                   if (*src == 0) {
+                       error("rcp: no path given in arg: %s:\n",
+                             argv[i]);
+                       errs++;
+                       continue;
+                   }
+                   argv[i] = src;
+                   src = 0;
+               } else {
+                   /* not equiv, return colon */
+                   *(--src) = ':';
+               }
+           }
+           if (src == 0) {             /* local to local */
+               (void) sprintf(buf, "/bin/cp%s%s %s %s",
+                              iamrecursive ? " -r" : "",
+                              pflag ? " -p" : "",
+                              argv[i], argv[argc - 1]);
+               (void) susystem(buf);
+           } else {            /* remote to local */
+               *src++ = 0;
+               if (*src == 0)
+                 src = ".";
+               host = index(argv[i], '@');
+               if (host) {
+                   *host++ = 0;
+                   suser = argv[i];
+                   if (*suser == '\0')
+                     suser = pwd->pw_name;
+                   else if (!okname(suser))
+                     continue;
+               } else {
+                   host = argv[i];
+                   suser = pwd->pw_name;
+               }
+               (void) sprintf(buf, "%s -f %s", cmd, src);
+#ifdef KERBEROS
+               authopts = AP_OPTS_MUTUAL_REQUIRED;
+               status = kcmd(&sock, &host,
+                             port,
+                             pwd->pw_name,  suser,
+                             buf,
+                             0,
+                             "host",
+                             krb_realm,
+                             0,  /* No return cred */
+                             0,  /* No seq # */
+                             0,  /* No server seq # */
+                             (struct sockaddr_in *) 0,
+                             &foreign,
+                             authopts);
+               if (status) {
+                   fprintf(stderr,
+                           "%s: kcmd to host %s failed - %s\n",
+                           orig_argv[0], host,
+                           error_message(status));
+                   try_normal(orig_argv);
+                   
+               } else {
+                   rem = sock; 
+                   if (encryptflag)
+                     send_auth();
+               }
+               sink(1, argv+argc-1);
+#else
+               rem = rcmd(&host, port, pwd->pw_name, suser,
+                          buf, 0);
+               if (rem < 0)
+                 continue;
+               (void) setreuid(0, userid);
+               sink(1, argv+argc-1);
+               (void) setreuid(userid, 0);
+#endif /* KERBEROS */
+               (void) close(rem);
+               rem = -1;
+           }
+       }
+    }
+    exit(errs);
+}
+
+
+
+verifydir(cp)
+     char *cp;
+{
+    struct stat stb;
+    
+    if (stat(cp, &stb) >= 0) {
+       if ((stb.st_mode & S_IFMT) == S_IFDIR)
+         return;
+       errno = ENOTDIR;
+    }
+    error("rcp: %s: %s.\n", cp, sys_errlist[errno]);
+    exit(1);
+}
+
+
+
+char *colon(cp)
+     char *cp;
+{
+    
+    while (*cp) {
+       if (*cp == ':')
+         return (cp);
+       if (*cp == '/')
+         return (0);
+       cp++;
+    }
+    return (0);
+}
+
+
+
+okname(cp0)
+     char *cp0;
+{
+    register char *cp = cp0;
+    register int c;
+    
+    do {
+       c = *cp;
+       if (c & 0200)
+         goto bad;
+       if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-')
+         goto bad;
+       cp++;
+    } while (*cp);
+    return (1);
+  bad:
+    fprintf(stderr, "rcp: invalid user name %s\n", cp0);
+    return (0);
+}
+
+
+
+susystem(s)
+     char *s;
+{
+    int status, pid, w;
+    register krb5_sigtype (*istat)(), (*qstat)();
+    
+    if ((pid = vfork()) == 0) {
+       execl("/bin/sh", "sh", "-c", s, (char *)0);
+       _exit(127);
+    }
+    istat = signal(SIGINT, SIG_IGN);
+    qstat = signal(SIGQUIT, SIG_IGN);
+    while ((w = wait(&status)) != pid && w != -1)
+      ;
+    if (w == -1)
+      status = -1;
+    (void) signal(SIGINT, istat);
+    (void) signal(SIGQUIT, qstat);
+    return (status);
+}
+
+
+
+source(argc, argv)
+     int argc;
+     char **argv;
+{
+    char *last, *name;
+    struct stat stb;
+    static struct buffer buffer;
+    struct buffer *bp;
+    int x, readerr, f, amt;
+    off_t i;
+    char buf[BUFSIZ];
+    
+    for (x = 0; x < argc; x++) {
+       name = argv[x];
+       if ((f = open(name, 0)) < 0) {
+           error("rcp: %s: %s\n", name, sys_errlist[errno]);
+           continue;
+       }
+       if (fstat(f, &stb) < 0)
+         goto notreg;
+       switch (stb.st_mode&S_IFMT) {
+           
+         case S_IFREG:
+           break;
+           
+         case S_IFDIR:
+           if (iamrecursive) {
+               (void) close(f);
+               rsource(name, &stb);
+               continue;
+           }
+           /* fall into ... */
+         default:
+         notreg:
+           (void) close(f);
+           error("rcp: %s: not a plain file\n", name);
+           continue;
+       }
+       last = rindex(name, '/');
+       if (last == 0)
+         last = name;
+       else
+         last++;
+       if (pflag) {
+           /*
+            * Make it compatible with possible future
+            * versions expecting microseconds.
+            */
+           (void) sprintf(buf, "T%ld 0 %ld 0\n",
+                          stb.st_mtime, stb.st_atime);
+           (void) des_write(rem, buf, strlen(buf));
+           if (response() < 0) {
+               (void) close(f);
+               continue;
+           }
+       }
+       (void) sprintf(buf, "C%04o %ld %s\n",
+                      stb.st_mode&07777, stb.st_size, last);
+       (void) des_write(rem, buf, strlen(buf));
+       if (response() < 0) {
+           (void) close(f);
+           continue;
+       }
+       if ((bp = allocbuf(&buffer, f, BUFSIZ)) == NULLBUF) {
+           (void) close(f);
+           continue;
+       }
+       readerr = 0;
+       for (i = 0; i < stb.st_size; i += bp->cnt) {
+           amt = bp->cnt;
+           if (i + amt > stb.st_size)
+             amt = stb.st_size - i;
+           if (readerr == 0 && read(f, bp->buf, amt) != amt)
+             readerr = errno;
+           (void) des_write(rem, bp->buf, amt);
+       }
+       (void) close(f);
+       if (readerr == 0)
+         ga();
+       else
+         error("rcp: %s: %s\n", name, sys_errlist[readerr]);
+       (void) response();
+    }
+}
+
+
+
+#if defined(SYSV) && !defined(sysvimp)
+#include <dirent.h>
+#else
+#ifdef sysvimp
+#include <ufs/fsdir.h>
+#else
+#include <sys/dir.h>
+#endif
+#endif
+
+rsource(name, statp)
+     char *name;
+     struct stat *statp;
+{
+    DIR *d = opendir(name);
+    char *last;
+#if defined(SYSV) && !defined(sysvimp)
+    struct dirent *dp;
+#else
+    struct direct *dp;
+#endif
+    char buf[BUFSIZ];
+    char *bufv[1];
+    
+    if (d == 0) {
+       error("rcp: %s: %s\n", name, sys_errlist[errno]);
+       return;
+    }
+    last = rindex(name, '/');
+    if (last == 0)
+      last = name;
+    else
+      last++;
+    if (pflag) {
+       (void) sprintf(buf, "T%ld 0 %ld 0\n",
+                      statp->st_mtime, statp->st_atime);
+       (void) des_write(rem, buf, strlen(buf));
+       if (response() < 0) {
+           closedir(d);
+           return;
+       }
+    }
+    (void) sprintf(buf, "D%04o %d %s\n", statp->st_mode&07777, 0, last);
+    (void) des_write(rem, buf, strlen(buf));
+    if (response() < 0) {
+       closedir(d);
+       return;
+    }
+    while (dp = readdir(d)) {
+       if (dp->d_ino == 0)
+         continue;
+       if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
+         continue;
+       if (strlen(name) + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
+           error("%s/%s: Name too long.\n", name, dp->d_name);
+           continue;
+       }
+       (void) sprintf(buf, "%s/%s", name, dp->d_name);
+       bufv[0] = buf;
+       source(1, bufv);
+    }
+    closedir(d);
+    (void) des_write(rem, "E\n", 2);
+    (void) response();
+}
+
+
+
+response()
+{
+    char resp, c, rbuf[BUFSIZ], *cp = rbuf;
+    if (des_read(rem, &resp, 1) != 1)
+      lostconn();
+    switch (resp) {
+       
+      case 0:                          /* ok */
+       return (0);
+       
+      default:
+       *cp++ = resp;
+       /* fall into... */
+      case 1:                          /* error, followed by err msg */
+      case 2:                          /* fatal error, "" */
+       do {
+           if (des_read(rem, &c, 1) != 1)
+             lostconn();
+           *cp++ = c;
+       } while (cp < &rbuf[BUFSIZ] && c != '\n');
+       if (iamremote == 0)
+         (void) write(2, rbuf, cp - rbuf);
+       errs++;
+       if (resp == 1)
+         return (-1);
+       exit(1);
+    }
+    /*NOTREACHED*/
+}
+
+
+
+krb5_sigtype
+  lostconn()
+{
+    if (iamremote == 0)
+      fprintf(stderr, "rcp: lost connection\n");
+    exit(1);
+}
+
+
+
+sink(argc, argv)
+     int argc;
+     char **argv;
+{
+    off_t i, j;
+    char *targ, *whopp, *cp;
+    int of, mode, wrerr, exists, first, count, amt, size;
+    struct buffer *bp;
+    static struct buffer buffer;
+    struct stat stb;
+    int targisdir = 0;
+    int mask = umask(0);
+    char *myargv[1];
+    char cmdbuf[BUFSIZ], nambuf[BUFSIZ];
+    int setimes = 0;
+    struct timeval tv[2];
+#define atime  tv[0]
+#define mtime  tv[1]
+#define        SCREWUP(str)    { whopp = str; goto screwup; }
+    
+    if (!pflag)
+      (void) umask(mask);
+    if (argc != 1) {
+       error("rcp: ambiguous target\n");
+       exit(1);
+    }
+    targ = *argv;
+    if (targetshouldbedirectory)
+      verifydir(targ);
+    ga();
+    if (stat(targ, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR)
+      targisdir = 1;
+    for (first = 1; ; first = 0) {
+       cp = cmdbuf;
+       if (des_read(rem, cp, 1) <= 0)
+         return;
+       if (*cp++ == '\n')
+         SCREWUP("unexpected '\\n'");
+       do {
+           if (des_read(rem, cp, 1) != 1)
+             SCREWUP("lost connection");
+       } while (*cp++ != '\n');
+       *cp = 0;
+       if (cmdbuf[0] == '\01' || cmdbuf[0] == '\02') {
+           if (iamremote == 0)
+             (void) write(2, cmdbuf+1, strlen(cmdbuf+1));
+           if (cmdbuf[0] == '\02')
+             exit(1);
+           errs++;
+           continue;
+       }
+       *--cp = 0;
+       cp = cmdbuf;
+       if (*cp == 'E') {
+           ga();
+           return;
+       }
+       
+#define getnum(t) (t) = 0; while (isdigit(*cp)) (t) = (t) * 10 + (*cp++ - '0');
+       if (*cp == 'T') {
+           setimes++;
+           cp++;
+           getnum(mtime.tv_sec);
+           if (*cp++ != ' ')
+             SCREWUP("mtime.sec not delimited");
+           getnum(mtime.tv_usec);
+           if (*cp++ != ' ')
+             SCREWUP("mtime.usec not delimited");
+           getnum(atime.tv_sec);
+           if (*cp++ != ' ')
+             SCREWUP("atime.sec not delimited");
+           getnum(atime.tv_usec);
+           if (*cp++ != '\0')
+             SCREWUP("atime.usec not delimited");
+           ga();
+           continue;
+       }
+       if (*cp != 'C' && *cp != 'D') {
+           /*
+            * Check for the case "rcp remote:foo\* local:bar".
+            * In this case, the line "No match." can be returned
+            * by the shell before the rcp command on the remote is
+            * executed so the ^Aerror_message convention isn't
+            * followed.
+            */
+           if (first) {
+               error("%s\n", cp);
+               exit(1);
+           }
+           SCREWUP("expected control record");
+       }
+       cp++;
+       mode = 0;
+       for (; cp < cmdbuf+5; cp++) {
+           if (*cp < '0' || *cp > '7')
+             SCREWUP("bad mode");
+           mode = (mode << 3) | (*cp - '0');
+       }
+       if (*cp++ != ' ')
+         SCREWUP("mode not delimited");
+       size = 0;
+       while (isdigit(*cp))
+         size = size * 10 + (*cp++ - '0');
+       if (*cp++ != ' ')
+         SCREWUP("size not delimited");
+       if (targisdir)
+         (void) sprintf(nambuf, "%s%s%s", targ,
+                        *targ ? "/" : "", cp);
+       else
+         (void) strcpy(nambuf, targ);
+       exists = stat(nambuf, &stb) == 0;
+       if (cmdbuf[0] == 'D') {
+           if (exists) {
+               if ((stb.st_mode&S_IFMT) != S_IFDIR) {
+                   errno = ENOTDIR;
+                   goto bad;
+               }
+               if (pflag)
+                 (void) chmod(nambuf, mode);
+           } else if (mkdir(nambuf, mode) < 0)
+             goto bad;
+           myargv[0] = nambuf;
+           sink(1, myargv);
+           if (setimes) {
+               setimes = 0;
+               if (utimes(nambuf, tv) < 0)
+                 error("rcp: can't set times on %s: %s\n",
+                       nambuf, sys_errlist[errno]);
+           }
+           continue;
+       }
+       if ((of = open(nambuf, O_WRONLY|O_CREAT, mode)) < 0) {
+         bad:
+           error("rcp: %s: %s\n", nambuf, sys_errlist[errno]);
+           continue;
+       }
+       if (exists && pflag)
+#ifdef NOFCHMOD
+         (void) chmod(nambuf, mode);
+#else
+       (void) fchmod(of, mode);
+#endif
+       ga();
+       if ((bp = allocbuf(&buffer, of, BUFSIZ)) == NULLBUF) {
+           (void) close(of);
+           continue;
+       }
+       cp = bp->buf;
+       count = 0;
+       wrerr = 0;
+       for (i = 0; i < size; i += BUFSIZ) {
+           amt = BUFSIZ;
+           if (i + amt > size)
+             amt = size - i;
+           count += amt;
+           do {
+               j = des_read(rem, cp, amt);
+               if (j <= 0) {
+                   if (j == 0)
+                     error("rcp: dropped connection");
+                   else
+                     error("rcp: %s\n",
+                           sys_errlist[errno]);
+                   exit(1);
+               }
+               amt -= j;
+               cp += j;
+           } while (amt > 0);
+           if (count == bp->cnt) {
+               if (wrerr == 0 &&
+                   write(of, bp->buf, count) != count)
+                 wrerr++;
+               count = 0;
+               cp = bp->buf;
+           }
+       }
+       if (count != 0 && wrerr == 0 &&
+           write(of, bp->buf, count) != count)
+         wrerr++;
+       if (ftruncate(of, size))
+         error("rcp: can't truncate %s: %s\n",
+               nambuf, sys_errlist[errno]);
+       (void) close(of);
+       (void) response();
+       if (setimes) {
+           setimes = 0;
+           if (utimes(nambuf, tv) < 0)
+             error("rcp: can't set times on %s: %s\n",
+                   nambuf, sys_errlist[errno]);
+       }                                  
+       if (wrerr)
+         error("rcp: %s: %s\n", nambuf, sys_errlist[errno]);
+       else
+         ga();
+    }
+  screwup:
+    error("rcp: protocol screwup: %s\n", whopp);
+    exit(1);
+}
+
+
+
+struct buffer *allocbuf(bp, fd, blksize)
+     struct buffer *bp;
+     int fd, blksize;
+{
+    struct stat stb;
+    int size;
+    
+    if (fstat(fd, &stb) < 0) {
+       error("rcp: fstat: %s\n", sys_errlist[errno]);
+       return (NULLBUF);
+    }
+#ifdef NOROUNDUP
+    size = 0;
+#else
+    size = roundup(stb.st_blksize, blksize);
+#endif
+    if (size == 0)
+      size = blksize;
+    if (bp->cnt < size) {
+       if (bp->buf != 0)
+         free(bp->buf);
+       bp->buf = (char *)malloc((unsigned) size);
+       if (bp->buf == 0) {
+           error("rcp: malloc: out of memory\n");
+           return (NULLBUF);
+       }
+    }
+    bp->cnt = size;
+    return (bp);
+}
+
+
+
+/*VARARGS1*/
+error(fmt, a1, a2, a3, a4, a5)
+     char *fmt;
+     int a1, a2, a3, a4, a5;
+{
+    char buf[BUFSIZ], *cp = buf;
+    
+    errs++;
+    *cp++ = 1;
+    (void) sprintf(cp, fmt, a1, a2, a3, a4, a5);
+    (void) des_write(rem, buf, strlen(buf));
+    if (iamremote == 0)
+      (void) write(2, buf+1, strlen(buf+1));
+}
+
+
+
+usage()
+{
+#ifdef KERBEROS
+    fprintf(stderr,
+           "Usage: \trcp [-p] [-x] [-k realm] f1 f2; or:\n\trcp [-r] [-p] [-x] [-k realm] f1 ... fn d2\n");
+#else /* !KERBEROS */
+    fputs("usage: rcp [-p] f1 f2; or: rcp [-rp] f1 ... fn d2\n", stderr);
+#endif
+    exit(1);
+}
+
+
+
+hosteq(h1, h2)
+     char *h1, *h2;
+{
+    struct hostent *h_ptr;
+    char hname1[256];
+    
+    /* get the official names for the two hosts */
+    
+    if ((h_ptr = gethostbyname(h1)) == NULL)
+      return(0);
+    strcpy(hname1, h_ptr->h_name);
+    if ((h_ptr = gethostbyname(h2)) == NULL)
+      return(0);
+    
+    /*return if they are equal (strcmp returns 0 for equal - I return 1) */
+    
+    return(!strcmp(hname1, h_ptr->h_name));
+}
+
+
+
+#ifdef KERBEROS
+void try_normal(argv)
+     char **argv;
+{
+    register int i;
+    
+    if (!encryptflag) {
+       fprintf(stderr,"trying normal rcp (%s)\n", UCB_RCP);
+       fflush(stderr);
+       /* close all but stdin, stdout, stderr */
+       for (i = getdtablesize(); i > 2; i--)
+         (void) close(i);
+       execv(UCB_RCP, argv);
+       perror("exec");
+    }
+    exit(1);
+}
+
+
+
+char **save_argv(argc, argv)
+     int argc;
+     char **argv;
+{
+    register int i;
+    
+    char **local_argv = (char **)calloc((unsigned) argc+1,
+                                       (unsigned) sizeof(char *));
+    /* allocate an extra pointer, so that it is initialized to NULL
+       and execv() will work */
+    for (i = 0; i < argc; i++)
+      local_argv[i] = strsave(argv[i]);
+    return(local_argv);
+}
+
+
+
+#ifdef unicos61
+#define SIZEOF_INADDR  SIZEOF_in_addr
+#else
+#define SIZEOF_INADDR sizeof(struct in_addr)
+#endif
+
+krb5_error_code tgt_keyproc(DECLARG(krb5_pointer, keyprocarg),
+                           DECLARG(krb5_principal, principal),
+                           DECLARG(krb5_kvno, vno),
+                           DECLARG(krb5_keyblock **, key))
+     OLDDECLARG(krb5_pointer, keyprocarg)
+     OLDDECLARG(krb5_principal, principal)
+     OLDDECLARG(krb5_kvno, vno)
+     OLDDECLARG(krb5_keyblock **, key)
+{
+    krb5_creds *creds = (krb5_creds *)keyprocarg;
+    
+    return krb5_copy_keyblock(&creds->keyblock, key);
+}
+
+
+
+void send_auth()
+{
+    int sin_len;
+    char *princ;          /* principal in credentials cache */
+    krb5_ccache cc;
+    krb5_creds creds;
+    krb5_principal sprinc;                /* principal of server */
+    krb5_data reply, msg, princ_data;
+    krb5_tkt_authent *authdat;
+    krb5_error_code status;
+    krb5_address faddr;
+    
+    
+    
+    if (status = krb5_cc_default(&cc)){
+       fprintf(stderr,"rcp: send_auth failed krb5_cc_default : %s\n",
+               error_message(status));
+       exit(1);
+    }
+    
+    memset ((char*)&creds, 0, sizeof(creds));
+    
+    if (status = krb5_cc_get_principal(cc, &creds.client)){
+       fprintf(stderr,
+               "rcp: send_auth failed krb5_cc_get_principal : %s\n",
+               error_message(status));
+       krb5_cc_close(cc);
+       exit(1);
+    }
+    
+    if (status = krb5_unparse_name(creds.client, &princ)){
+       fprintf(stderr,"rcp: send_auth failed krb5_parse_name : %s\n",
+               error_message(status));
+       krb5_cc_close(cc);
+       exit(1);
+    }
+    if (status = krb5_build_principal_ext(&sprinc,
+                                         krb5_princ_realm(creds.client)->length,
+                                         krb5_princ_realm(creds.client)->data,
+                                         6, "krbtgt",
+                                         krb5_princ_realm(creds.client)->length,
+                                         krb5_princ_realm(creds.client)->data,
+                                         0)){
+       fprintf(stderr,
+               "rcp: send_auth failed krb5_build_principal_ext : %s\n",
+               error_message(status));
+       krb5_cc_close(cc);
+       exit(1);
+    }
+    
+    creds.server = sprinc;
+    
+    /* Get TGT from credentials cache */
+    if (status = krb5_get_credentials(KRB5_GC_CACHED, cc, &creds)){
+       fprintf(stderr,
+                "rcp: send_auth failed krb5_get_credentials: %s\n",
+               error_message(status));
+       krb5_cc_close(cc);
+       exit(1);
+    }
+    krb5_cc_close(cc);
+    
+    krb5_free_principal(sprinc);          /* creds.server is replaced
+                                            upon retrieval */
+    
+    
+    princ_data.data = princ;
+    princ_data.length = strlen(princ_data.data) + 1; /* include null 
+                                                       terminator for
+                                                       server's convenience */
+    status = krb5_write_message((krb5_pointer) &rem, &princ_data);
+    if (status){
+       fprintf(stderr,
+                "rcp: send_auth failed krb5_write_message: %s\n",
+               error_message(status));
+       exit(1);
+    }
+    xfree(princ);
+    status = krb5_write_message((krb5_pointer) &rem, &creds.ticket);
+    if (status){
+       fprintf(stderr,
+                "rcp: send_auth failed krb5_write_message: %s\n",
+               error_message(status));
+       exit(1);
+    }
+    
+    status = krb5_read_message((krb5_pointer) &rem, &reply);
+    if (status){
+       fprintf(stderr,
+                "rcp: send_auth failed krb5_read_message: %s\n",
+               error_message(status));
+       exit(1);
+    }
+    
+    sin_len = SIZEOF_INADDR;
+    faddr.addrtype = foreign.sin_family;
+    faddr.length = SIZEOF_INADDR;
+    faddr.contents = (krb5_octet *) &foreign.sin_addr;
+    
+    /* read the ap_req to get the session key */
+    status = krb5_rd_req(&reply,
+                        0,               /* don't know server's name... */
+                        &faddr,
+                        0,               /* no fetchfrom */
+                        tgt_keyproc,
+                        (krb5_pointer)&creds, /* credentials as arg to
+                                                 keyproc */
+                        0,               /* no rcache for the moment XXX */
+                        &authdat);
+    xfree(reply.data);
+    if (status) {
+       fprintf(stderr, "rcp: send_auth failed krb5_rd_req: %s\n",
+               error_message(status));
+       exit(1);
+    }
+    
+    krb5_copy_keyblock(authdat->ticket->enc_part2->session,&session_key);
+    krb5_free_tkt_authent(authdat);
+    krb5_free_cred_contents(&creds);
+    
+    krb5_use_keytype(&eblock, session_key->keytype);
+    if ( status = krb5_process_key(&eblock, 
+                                  session_key)){
+       fprintf(stderr, "rcp: send_auth failed krb5_process_key: %s\n",
+               error_message(status));
+       exit(1);
+    }
+    
+}
+
+
+
+void
+  answer_auth()
+{
+    krb5_data pname_data, msg;
+    krb5_creds creds;
+    krb5_ccache cc;
+    krb5_error_code status;
+    extern krb5_flags krb5_kdc_default_options;
+    
+    
+    memset ((char*)&creds, 0, sizeof(creds));
+    
+    if (status = krb5_read_message((krb5_pointer) &rem, &pname_data)) {
+       exit(1);
+    }
+    
+    if (status = krb5_read_message((krb5_pointer) &rem,
+                                  &creds.second_ticket)) {
+       exit(1);
+    }
+    
+    if (status = krb5_cc_default(&cc)){
+       exit(1);
+    }
+    
+    if (status = krb5_cc_get_principal(cc, &creds.client)){
+       krb5_cc_destroy(cc);
+       krb5_cc_close(cc);
+       exit(1);
+    }
+    
+    if (status = krb5_parse_name(pname_data.data, &creds.server)){
+       krb5_cc_destroy(cc);
+       krb5_cc_close(cc);
+       exit(1);
+    }
+    xfree(pname_data.data);
+    
+    if (status = krb5_get_credentials(KRB5_GC_USER_USER, cc, &creds)){
+       krb5_cc_destroy(cc);
+       krb5_cc_close(cc);
+       exit(1);
+    }
+    
+    if (status = krb5_mk_req_extended(AP_OPTS_USE_SESSION_KEY,
+                                     0,       /* no application checksum here */
+                                     krb5_kdc_default_options,
+                                     0,
+                                     0,       /* no need for subkey */
+                                     cc,
+                                     &creds,
+                                     0,       /* don't need authenticator copy */
+                                     &msg)) {
+       krb5_cc_destroy(cc);
+       krb5_cc_close(cc);
+       exit(1);
+    }
+    krb5_cc_destroy(cc);
+    krb5_cc_close(cc);
+    status = krb5_write_message((krb5_pointer) &rem, &msg);
+    xfree(msg.data);
+    if (status){
+       exit(1);
+    }
+    
+    /* setup eblock for des_read and write */
+    krb5_copy_keyblock(&creds.keyblock,&session_key);
+    
+    /* cleanup */
+    krb5_free_cred_contents(&creds);
+    
+    /* OK process key */
+    krb5_use_keytype(&eblock, session_key->keytype);
+    if ( status = krb5_process_key(&eblock,session_key)) {
+       exit(1);
+    }
+    
+    return;
+}
+
+
+
+char storage[2*BUFSIZ];                        /* storage for the decryption */
+int nstored = 0;
+char *store_ptr = storage;
+
+int des_read(fd, buf, len)
+     int fd;
+     register char *buf;
+     int len;
+{
+    int nreturned = 0;
+    long net_len,rd_len;
+    int cc;
+    krb5_error_code status;
+    
+    if (!encryptflag)
+      return(read(fd, buf, len));
+    
+    if (nstored >= len) {
+       memcpy(buf, store_ptr, len);
+       store_ptr += len;
+       nstored -= len;
+       return(len);
+    } else if (nstored) {
+       memcpy(buf, store_ptr, nstored);
+       nreturned += nstored;
+       buf += nstored;
+       len -= nstored;
+       nstored = 0;
+    }
+    
+#ifdef BITS64
+    /*
+     * XXX Ick; this assumes a big-endian word order....  
+     */
+    rd_len = 0;
+    if ((cc = krb5_net_read(fd, (char *)&rd_len + 4, 4)) != 4) {
+#else
+    if ((cc = krb5_net_read(fd, (char *)&rd_len, sizeof(rd_len))) !=
+       sizeof(rd_len)) {
+#endif
+       /* XXX can't read enough, pipe
+          must have closed */
+       return(0);
+    }
+    rd_len = ntohl(rd_len);
+    net_len = krb5_encrypt_size(rd_len,eblock.crypto_entry);
+    if (net_len <= 0 || net_len > sizeof(des_inbuf)) {
+       /* preposterous length; assume out-of-sync; only
+          recourse is to close connection, so return 0 */
+       error( "rcp: Des_read size problem net_len %d rd_len %d %d.\n",
+             net_len,rd_len, len);
+       errno = E2BIG;
+       return(-1);
+    }
+    if ((cc = krb5_net_read(fd, desinbuf.data, net_len)) != net_len) {
+       /* pipe must have closed, return 0 */
+       error( "rcp: Des_read error: length received %d != expected %d.\n",
+             cc,net_len);
+       return(0);
+    }
+    /* decrypt info */
+    if ((status = krb5_decrypt(desinbuf.data,
+                              (krb5_pointer) storage,
+                              net_len,
+                              &eblock, 0))) {
+       error("rcp: Des_read cannot decrypt data from network %s.\n",
+             error_message(status));
+       return(0);
+    }
+    store_ptr = storage;
+    nstored = rd_len;
+    if (nstored > len) {
+       memcpy(buf, store_ptr, len);
+       nreturned += len;
+       store_ptr += len;
+       nstored -= len;
+    } else {
+       memcpy(buf, store_ptr, nstored);
+       nreturned += nstored;
+       nstored = 0;
+    }
+    
+    return(nreturned);
+}
+
+
+
+int des_write(fd, buf, len)
+     int fd;
+     char *buf;
+     int len;
+{
+    long net_len;
+    
+    if (!encryptflag)
+      return(write(fd, buf, len));
+    
+    desoutbuf.length = krb5_encrypt_size(len,eblock.crypto_entry);
+    if (desoutbuf.length > sizeof(des_outbuf)){
+       return(-1);
+    }
+    if (( krb5_encrypt((krb5_pointer)buf,
+                      desoutbuf.data,
+                      len,
+                      &eblock,
+                      0))){
+       return(-1);
+    }
+    
+    net_len = htonl(len);
+#ifdef BITS64
+    (void) write(fd,(char *)&net_len + 4, 4);
+#else
+    (void) write(fd, &net_len, sizeof(net_len));
+#endif
+    if (write(fd, desoutbuf.data,desoutbuf.length) != desoutbuf.length){
+       return(-1);
+    }
+    else return(len);
+}
+
+#endif /* KERBEROS */
diff --git a/src/appl/bsd/krlogin.c b/src/appl/bsd/krlogin.c
new file mode 100644 (file)
index 0000000..8191f57
--- /dev/null
@@ -0,0 +1,1468 @@
+/*
+ *    $Source$!  *    $Author$
+ *    $Header$
+ */
+#ifndef lint
+static char rcsid_rlogin_c[] = "$Header$";
+#endif /* lint */
+
+/*
+ * Copyright (c) 1983 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+char copyright[] =
+  "@(#) Copyright (c) 1983 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)rlogin.c   5.12 (Berkeley) 9/19/88";
+#endif /* not lint */
+
+#define KERBEROS
+     
+     /*
+      * rlogin - remote login
+      */
+     
+#include <sys/param.h>
+#include <sys/errno.h>
+#ifndef _TYPES
+#include <sys/types.h>
+#define _TYPES_
+#endif
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+     
+#include <netinet/in.h>
+     
+#include <stdio.h>
+     
+#ifdef SYSV
+#ifndef USE_TERMIO
+#define USE_TERMIO
+#endif
+#endif
+     
+#ifdef USE_TERMIO
+#ifdef CRAY
+#include <sys/ttold.h>
+#endif
+#include <sys/termio.h>
+#define sg_flags c_lflag
+#define sg_ospeed c_cflag&CBAUD
+     
+#ifndef TIOCGETP
+#define TIOCGETP TCGETA
+#endif
+#ifndef TIOCSETP
+#define TIOCSETP TCSETA
+#endif
+#ifndef TIOCSETN
+#define TIOCSETN TCSETAW
+#endif
+#else /* !USE_TERMIO */
+#include <sgtty.h>
+#endif /* USE_TERMIO */
+     
+#include <errno.h>
+#include <pwd.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <netdb.h>
+     
+#ifdef KERBEROS
+#include <krb5/krb5.h>
+#include <krb5/asn1.h>
+#include <krb5/crc-32.h>
+#include <krb5/mit-des.h>
+#include <krb5/los-proto.h>
+
+#include <com_err.h>
+     
+#ifdef BUFSIZ
+#undef BUFSIZ
+#endif
+#define BUFSIZ 4096
+     
+char des_inbuf[2*BUFSIZ];       /* needs to be > largest read size */
+char des_outbuf[2*BUFSIZ];      /* needs to be > largest write size */
+krb5_data desinbuf,desoutbuf;
+krb5_encrypt_block eblock;      /* eblock for encrypt/decrypt */
+
+void try_normal();
+char *krb_realm = (char *)0;
+int encrypt = 0;
+krb5_creds *cred;
+struct sockaddr_in local, foreign;
+
+#define      UCB_RLOGIN      "/usr/ucb/rlogin"
+
+#ifdef CRAY
+#ifndef BITS64
+#define BITS64
+#endif
+#endif
+
+#else /* !KERBEROS */
+#define des_read read
+#define des_write write
+#endif /* KERBEROS */
+
+
+# ifndef TIOCPKT_WINDOW
+# define TIOCPKT_WINDOW 0x80
+# endif /* TIOCPKT_WINDOW */
+
+/* concession to sun */
+# ifndef SIGUSR1
+# define SIGUSR1 30
+# endif /* SIGUSR1 */
+
+char   *index(), *rindex(), *getenv(), *strcat(), *strcpy();
+#ifndef convex
+struct passwd *getpwuid();
+#endif
+char   *name;
+int    rem = -1;               /* Remote socket fd */
+char   cmdchar = '~';
+int    eight = 1;              /* Default to 8 bit transmission */
+int    no_local_escape = 0;
+int    null_local_username = 0;
+int    flow = 1;                       /* Default is to allow flow
+                                          control at the local terminal */
+int    flowcontrol;                    /* Since emacs can alter the
+                                          flow control characteristics
+                                          of a session we need a
+                                          variable to keep track of
+                                          the original characteristics */
+int    confirm = 0;                    /* ask if ~. is given before dying. */
+int    litout;
+#ifdef hpux
+char    *speeds[] =
+{ "0", "50", "75", "110", "134", "150", "200", "300", "600",
+    "900", "1200", "1800", "2400", "3600", "4800", "7200", "9600",
+    "19200", "38400", "EXTA", "EXTB" };
+#else
+char    *speeds[] =
+{ "0", "50", "75", "110", "134", "150", "200", "300",
+    "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" };
+#endif
+char   term[256] = "network";
+extern int errno;
+krb5_sigtype   lostpeer();
+int    dosigwinch = 0;
+#ifndef sigmask
+#define sigmask(m)     (1 << ((m)-1))
+#endif
+#ifdef NO_WINSIZE
+struct winsize {
+    unsigned short ws_row, ws_col;
+    unsigned short ws_xpixel, ws_ypixel;
+};
+#endif /* NO_WINSIZE */
+struct winsize winsize;
+krb5_sigtype   sigwinch(), oob();
+char   *host;                          /* external, so it can be
+                                          reached from confirm_death() */
+
+
+
+/*
+ * The following routine provides compatibility (such as it is)
+ * between 4.2BSD Suns and others.  Suns have only a `ttysize',
+ * so we convert it to a winsize.
+ */
+#ifdef TIOCGWINSZ
+#define get_window_size(fd, wp)       ioctl(fd, TIOCGWINSZ, wp)
+#else
+#ifdef SYSV
+#ifndef SIGWINCH
+#define SIGWINCH SIGWINDOW
+#endif
+struct ttysize {
+    int ts_lines;
+    int ts_cols;
+};
+#define DEFAULT_LINES 24
+#define DEFAULT_COLS 80
+#endif
+
+
+
+int
+  get_window_size(fd, wp)
+int fd;
+struct winsize *wp;
+{
+    struct ttysize ts;
+    int error;
+#ifdef SYSV
+    char *envbuf;
+    ts.ts_lines = DEFAULT_LINES;
+    ts.ts_cols = DEFAULT_COLS;
+    if (( envbuf = getenv("LINES")) != (char *) 0)
+      ts.ts_lines = atoi(envbuf);
+    if (( envbuf = getenv("COLUMNS")) != (char *) 0)
+      ts.ts_cols = atoi(envbuf);
+#else
+    if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0)
+      return (error);
+#endif
+    
+    wp->ws_row = ts.ts_lines;
+    wp->ws_col = ts.ts_cols;
+    wp->ws_xpixel = 0;
+    wp->ws_ypixel = 0;
+    return (0);
+}
+#endif /* TIOCGWINSZ */
+
+
+#ifdef USE_TERMIO
+/* Globals for terminal modes and flow control */
+struct  termio defmodes;
+struct  termio ixon_state;
+#endif
+
+
+
+main(argc, argv)
+     int argc;
+     char **argv;
+{
+    char *cp = (char *) NULL;
+#ifdef USE_TERMIO
+    struct termio ttyb;
+#else
+    struct sgttyb ttyb;
+#endif
+    struct passwd *pwd;
+    struct servent *sp;
+    int uid, options = 0, oldmask;
+    int on = 1;
+#ifdef KERBEROS
+    char **orig_argv = argv;
+    int sock;
+    krb5_flags authopts;
+    krb5_error_code status;
+#endif /* KERBEROS */
+    
+    if ( argc < 2 ) goto usage;
+    host = argv[1];
+    argc -= 2;
+    argv +=2;
+  another:
+    if (argc > 0 && !strcmp(*argv, "-d")) {
+       argv++, argc--;
+       options |= SO_DEBUG;
+       goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-c")) {
+       confirm = 1;
+       argv++; argc--;
+       goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-a")) {       /* ask -- make remote */
+       argv++; argc--;                 /* machine ask for password */
+       null_local_username = 1;        /* by giving null local user */
+       goto another;                   /* id */
+    }
+    if (argc > 0 && !strcmp(*argv, "-t")) {
+       argv++; argc--;
+       if (argc == 0) goto usage;
+       cp = *argv++; argc--;
+       goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-n")) {
+       no_local_escape = 1;
+       argv++, argc--;
+       goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-7")) {  /* Pass only 7 bits */
+       eight = 0;
+       argv++, argc--;
+       goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-noflow")) {
+       flow = 0;               /* Turn off local flow control so
+                                  that ^S can be passed to emacs. */
+       argv++, argc--;
+       goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-l")) {
+       argv++, argc--;
+       if (argc == 0)
+         goto usage;
+       name = *argv++; argc--;
+       goto another;
+    }
+    if (argc > 0 && !strncmp(*argv, "-e", 2)) {
+       cmdchar = argv[0][2];
+       argv++, argc--;
+       goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-8")) {
+       eight = 1;
+       argv++, argc--;
+       goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-L")) {
+       litout = 1;
+       argv++, argc--;
+       goto another;
+    }
+#ifdef KERBEROS
+    if (argc > 0 && !strcmp(*argv, "-k")) {
+       argv++, argc--;
+       if (argc == 0) {
+           fprintf(stderr,
+                   "rlogin: -k flag must be followed with a realm name.\n");
+           exit (1);
+       }
+       if(!(krb_realm = (char *)malloc(strlen(*argv) + 1))){
+           fprintf(stderr, "rlogin: Cannot malloc.\n");
+           exit(1);
+       }
+       strcpy(krb_realm, *argv);
+       argv++, argc--;
+       goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-x")) {
+       encrypt++;
+       argv++, argc--;
+       goto another;
+    }
+#endif /* KERBEROS */
+    if (host == 0)
+      goto usage;
+    if (argc > 0)
+      goto usage;
+    pwd = getpwuid(getuid());
+    if (pwd == 0) {
+       fprintf(stderr, "Who are you?\n");
+       exit(1);
+    }
+#ifdef KERBEROS
+    krb5_init_ets();
+    desinbuf.data = des_inbuf;
+    desoutbuf.data = des_outbuf;       /* Set up des buffers */
+    /*
+     * if there is an entry in /etc/services for Kerberos login,
+     * attempt to login with Kerberos. 
+     * If we fail at any step,  use the standard rlogin
+     */
+    if (encrypt)
+      sp = getservbyname("eklogin","tcp");
+    else 
+      sp = getservbyname("klogin","tcp");
+    if (sp == 0) {
+       fprintf(stderr, "rlogin: %s/tcp: unknown service\n",
+               encrypt ? "eklogin" : "klogin");
+       
+       try_normal(orig_argv);
+    }
+#else
+    sp = getservbyname("login", "tcp");
+    if (sp == 0) {
+       fprintf(stderr, "rlogin: login/tcp: unknown service\n");
+       exit(2);
+    }
+#endif /* KERBEROS */
+    if (cp == (char *) NULL) cp = getenv("TERM");
+    if (cp)
+      (void) strcpy(term, cp);
+    if (ioctl(0, TIOCGETP, &ttyb) == 0) {
+       (void) strcat(term, "/");
+       (void) strcat(term, speeds[ttyb.sg_ospeed]);
+    }
+    (void) get_window_size(0, &winsize);
+    
+#ifdef USE_TERMIO
+    /**** moved before rcmd call so that if get a SIGPIPE in rcmd **/
+    /**** we will have the defmodes set already. ***/
+    (void)ioctl(fileno(stdin), TIOCGETP, &defmodes);
+    (void)ioctl(fileno(stdin), TIOCGETP,&ixon_state);
+#endif
+    (void) signal(SIGPIPE, lostpeer);
+    
+    /* will use SIGUSR1 for window size hack, so hold it off */
+#ifdef sgi
+    oldmask = sigignore(sigmask(SIGURG) | sigmask(SIGUSR1));
+#else
+    oldmask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1));
+#endif
+    
+#ifdef KERBEROS
+    authopts = AP_OPTS_MUTUAL_REQUIRED;
+    status = kcmd(&sock, &host, sp->s_port,
+                 null_local_username ? NULL : pwd->pw_name,
+                 name ? name : pwd->pw_name, term,
+                 0, "host", krb_realm,
+                 &cred,
+                 0,            /* No need for sequence number */
+                 0,            /* No need for server seq # */
+                 &local, &foreign,
+                 authopts);
+    if (status) {
+       fprintf(stderr,
+               "%s: kcmd to host %s failed - %s\n",orig_argv[0], host,
+               error_message(status));
+       try_normal(orig_argv);
+    }
+    rem = sock;
+    
+    /* setup eblock for des_read and write */
+    krb5_use_keytype(&eblock,cred->keyblock.keytype);
+    if ( status = krb5_process_key(&eblock,&cred->keyblock)) {
+       fprintf(stderr,
+               "%s: Cannot process session key : %s.\n",
+               orig_argv, error_message(status));
+       exit(1);
+    }
+#else
+    rem = rcmd(&host, sp->s_port,
+              null_local_username ? NULL : pwd->pw_name,
+              name ? name : pwd->pw_name, term, 0);
+#endif /* KERBEROS */
+    
+    if (rem < 0)
+      exit(1);
+    
+    /* we need to do the SETOWN here so that we get the SIGURG
+       registered if the URG data come in early, before the reader() gets
+       to do this for real (otherwise, the signal is never generated
+       by the kernel).  We block it above, so when it gets unblocked
+       it will get processed by the reader().
+       There is a possibility that the signal will get delivered to both
+       writer and reader, but that is harmless, since the writer reflects
+       it to the reader, and the oob() processing code in the reader will
+       work properly even if it is called when no oob() data is present.
+       */
+#ifndef SYSV
+    (void) fcntl(rem, F_SETOWN, getpid());
+#endif
+    if (options & SO_DEBUG &&
+       setsockopt(rem, SOL_SOCKET, SO_DEBUG, &on, sizeof (on)) < 0)
+      perror("rlogin: setsockopt (SO_DEBUG)");
+    uid = getuid();
+    if (setuid(uid) < 0) {
+       perror("rlogin: setuid");
+       exit(1);
+    }
+    flowcontrol = flow;  /* Set up really correct non-volatile variable */
+    doit(oldmask);
+    /*NOTREACHED*/
+  usage:
+#ifdef KERBEROS
+    fprintf (stderr,
+            "usage: rlogin host [-option] [-option...] [-k realm ] [-t ttytype] [-l username]\n");
+    fprintf (stderr, "     where option is e, 7, 8, noflow, n, a, x, or c\n");
+#else /* !KERBEROS */
+    fprintf (stderr,
+            "usage: rlogin host [-option] [-option...] [-t ttytype] [-l username]\n");
+    fprintf (stderr, "     where option is e, 7, 8, noflow, n, a, or c\n");
+#endif /* KERBEROS */
+    exit(1);
+}
+
+
+
+int confirm_death ()
+{
+    char hostname[33];
+    char input;
+    int answer;
+    if (!confirm) return (1);  /* no confirm, just die */
+    
+    if (gethostname (hostname, sizeof(hostname)-1) != 0)
+      strcpy (hostname, "???");
+    else
+      hostname[sizeof(hostname)-1] = '\0';
+    
+    fprintf (stderr, "\r\nKill session on %s from %s (y/n)?  ",
+            host, hostname);
+    fflush (stderr);
+    if (read(0, &input, 1) != 1)
+      answer = EOF;    /* read from stdin */
+    else
+      answer = (int) input;
+    fprintf (stderr, "%c\r\n", answer);
+    fflush (stderr);
+    return (answer == 'y' || answer == 'Y' || answer == EOF ||
+           answer == 4);       /* control-D */
+}
+
+
+
+#define CRLF "\r\n"
+
+int    child;
+krb5_sigtype   catchild();
+krb5_sigtype   copytochild(), writeroob();
+
+int    defflags, tabflag;
+int    deflflags;
+char   deferase, defkill;
+
+#ifdef USE_TERMIO
+char defvtim, defvmin;
+#ifdef hpux
+#include <sys/bsdtty.h>
+#include <sys/ptyio.h>
+#endif
+struct tchars {
+    char    t_intrc;        /* interrupt */
+    char    t_quitc;        /* quit */
+    char    t_startc;       /* start output */
+    char    t_stopc;        /* stop output */
+    char    t_eofc;         /* end-of-file */
+    char    t_brkc;         /* input delimiter (like nl) */
+};
+#endif
+
+struct tchars deftc;
+struct tchars notc =   { -1, -1, -1, -1, -1, -1 };
+struct ltchars defltc;
+struct ltchars noltc = { -1, -1, -1, -1, -1, -1 };
+
+
+
+doit(oldmask)
+{
+#ifdef USE_TERMIO
+    struct termio sb;
+#else
+    struct sgttyb sb;
+#endif
+    
+    (void) ioctl(0, TIOCGETP, (char *)&sb);
+    defflags = sb.sg_flags;
+#ifdef USE_TERMIO
+    tabflag = sb.c_oflag & TABDLY;
+    defflags |= ECHO;
+    deferase = sb.c_cc[VERASE];
+    defkill = sb.c_cc[VKILL];
+    sb.c_cc[VMIN] = 1;
+    sb.c_cc[VTIME] = 1;
+    defvtim = sb.c_cc[VTIME];
+    defvmin = sb.c_cc[VMIN];
+    deftc.t_quitc = CQUIT;
+    deftc.t_startc = CSTART;
+    deftc.t_stopc = CSTOP ;
+    deftc.t_eofc = CEOF;
+    deftc.t_brkc =  '\n';
+#else
+    tabflag = defflags & TBDELAY;
+    defflags &= ECHO | CRMOD;
+    deferase = sb.sg_erase;
+    defkill = sb.sg_kill;
+    (void) ioctl(0, TIOCLGET, (char *)&deflflags);
+    (void) ioctl(0, TIOCGETC, (char *)&deftc);
+#endif
+    
+    notc.t_startc = deftc.t_startc;
+    notc.t_stopc = deftc.t_stopc;
+    (void) ioctl(0, TIOCGLTC, (char *)&defltc);
+    (void) signal(SIGINT, SIG_IGN);
+    setsignal(SIGHUP, exit);
+    setsignal(SIGQUIT,exit);
+    child = fork();
+    if (child == -1) {
+       perror("rlogin: fork");
+       done(1);
+    }
+    if (child == 0) {
+       mode(1);
+       if (reader(oldmask) == 0) {
+           prf("Connection closed.");
+           exit(0);
+       }
+       sleep(1);
+       prf("\007Connection closed.");
+       exit(3);
+    }
+    
+    /*
+     * We may still own the socket, and may have a pending SIGURG
+     * (or might receive one soon) that we really want to send to
+     * the reader.  Set a trap that simply copies such signals to
+     * the child.
+     */
+    (void) signal(SIGURG, copytochild);
+    (void) signal(SIGUSR1, writeroob);
+#ifndef sgi
+    (void) sigsetmask(oldmask);
+#endif
+    (void) signal(SIGCHLD, catchild);
+    writer();
+    prf("Closed connection.");
+    done(0);
+}
+
+
+
+/*
+ * Trap a signal, unless it is being ignored.
+ */
+setsignal(sig, act)
+     int sig, (*act)();
+{
+#ifdef sgi
+    int omask = sigignore(sigmask(sig));
+#else
+    int omask = sigblock(sigmask(sig));
+#endif
+    
+    if (signal(sig, act) == SIG_IGN)
+      (void) signal(sig, SIG_IGN);
+#ifndef sgi
+    (void) sigsetmask(omask);
+#endif
+}
+
+
+
+done(status)
+     int status;
+{
+    int w;
+    
+    mode(0);
+    if (child > 0) {
+       /* make sure catchild does not snap it up */
+       (void) signal(SIGCHLD, SIG_DFL);
+       if (kill(child, SIGKILL) >= 0)
+         while ((w = wait((union wait *)0)) > 0 && w != child)
+           /*void*/;
+    }
+    exit(status);
+}
+
+
+
+/*
+ * Copy SIGURGs to the child process.
+ */
+krb5_sigtype
+  copytochild()
+{
+    
+    (void) kill(child, SIGURG);
+}
+
+
+
+/*
+ * This is called when the reader process gets the out-of-band (urgent)
+ * request to turn on the window-changing protocol.
+ */
+krb5_sigtype
+  writeroob()
+{
+    
+    if (dosigwinch == 0) {
+       sendwindow();
+       (void) signal(SIGWINCH, sigwinch);
+    }
+    dosigwinch = 1;
+}
+
+
+
+krb5_sigtype
+  catchild()
+{
+    union wait status;
+    int pid;
+    
+  again:
+    pid = wait3(&status, WNOHANG|WUNTRACED, (struct rusage *)0);
+    if (pid == 0)
+      return;
+    /*
+     * if the child (reader) dies, just quit
+     */
+#if defined(hpux)
+    if ((pid < 0) || ((pid == child) && (!WIFSTOPPED(status.w_stopval))))
+#else
+      if ((pid < 0) || ((pid == child) && (!WIFSTOPPED( status))))
+#endif
+       done((int)(status.w_termsig | status.w_retcode));
+    goto again;
+}
+
+
+
+/*
+ * writer: write to remote: 0 -> line.
+ * ~.  terminate
+ * ~^Z suspend rlogin process.
+ * ~^Y  suspend rlogin process, but leave reader alone.
+ */
+writer()
+{
+    char c;
+    register n;
+    register bol = 1;               /* beginning of line */
+    register local = 0;
+    
+#ifdef ultrix             
+    fd_set waitread;
+    
+    /* we need to wait until the reader() has set up the terminal, else
+       the read() below may block and not unblock when the terminal
+       state is reset.
+       */
+    for (;;) {
+       FD_ZERO(&waitread);
+       FD_SET(0, &waitread);
+       n = select(1, &waitread, 0, 0, 0, 0);
+       if (n < 0 && errno == EINTR)
+         continue;
+       if (n > 0)
+         break;
+       else
+         if (n < 0) {
+             perror("select");
+             break;
+         }
+    }
+#endif /* ultrix */
+    for (;;) {
+       n = read(0, &c, 1);
+       if (n <= 0) {
+           if (n < 0 && errno == EINTR)
+             continue;
+           break;
+       }
+       /*
+        * If we're at the beginning of the line
+        * and recognize a command character, then
+        * we echo locally.  Otherwise, characters
+        * are echo'd remotely.  If the command
+        * character is doubled, this acts as a 
+        * force and local echo is suppressed.
+        */
+       if (bol) {
+           bol = 0;
+           if (c == cmdchar) {
+               bol = 0;
+               local = 1;
+               continue;
+           }
+       } else if (local) {
+           local = 0;
+           if (c == '.' || c == deftc.t_eofc) {
+               if (confirm_death()) {
+                   echo(c);
+                   break;
+               }
+           }
+           if ((c == defltc.t_suspc || c == defltc.t_dsuspc)
+               && !no_local_escape) {
+               bol = 1;
+               echo(c);
+               stop(c);
+               continue;
+           }
+           if (c != cmdchar)
+             (void) des_write(rem, &cmdchar, 1);
+       }
+       if (des_write(rem, &c, 1) == 0) {
+           prf("line gone");
+           break;
+       }
+       bol = c == defkill || c == deftc.t_eofc ||
+         c == deftc.t_intrc || c == defltc.t_suspc ||
+           c == '\r' || c == '\n';
+    }
+}
+
+
+
+echo(c)
+     register char c;
+{
+    char buf[8];
+    register char *p = buf;
+    
+    c &= 0177;
+    *p++ = cmdchar;
+    if (c < ' ') {
+       *p++ = '^';
+       *p++ = c + '@';
+    } else if (c == 0177) {
+       *p++ = '^';
+       *p++ = '?';
+    } else
+      *p++ = c;
+    *p++ = '\r';
+    *p++ = '\n';
+    (void) write(1, buf, p - buf);
+}
+
+
+
+stop(cmdc)
+     char cmdc;
+{
+    mode(0);
+    (void) signal(SIGCHLD, SIG_IGN);
+    (void) kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP);
+    (void) signal(SIGCHLD, catchild);
+    mode(1);
+    sigwinch();                        /* check for size changes */
+}
+
+
+
+krb5_sigtype
+  sigwinch()
+{
+    struct winsize ws;
+    
+    if (dosigwinch && get_window_size(0, &ws) == 0 &&
+       memcmp(&winsize, &ws, sizeof (ws))) {
+       winsize = ws;
+       sendwindow();
+    }
+}
+
+
+
+/*
+ * Send the window size to the server via the magic escape
+ */
+sendwindow()
+{
+    char obuf[4 + sizeof (struct winsize)];
+    struct winsize *wp = (struct winsize *)(obuf+4);
+    
+    obuf[0] = 0377;
+    obuf[1] = 0377;
+    obuf[2] = 's';
+    obuf[3] = 's';
+    wp->ws_row = htons(winsize.ws_row);
+    wp->ws_col = htons(winsize.ws_col);
+    wp->ws_xpixel = htons(winsize.ws_xpixel);
+    wp->ws_ypixel = htons(winsize.ws_ypixel);
+    (void) des_write(rem, obuf, sizeof(obuf));
+}
+
+
+
+/*
+ * reader: read from remote: line -> 1
+ */
+#define        READING 1
+#define        WRITING 2
+
+char   rcvbuf[8 * 1024];
+int    rcvcnt;
+int    rcvstate;
+int    ppid;
+jmp_buf        rcvtop;
+
+krb5_sigtype
+  oob()
+{
+    int out = FWRITE, atmark, n;
+    int rcvd = 0;
+    char waste[BUFSIZ], mark;
+#ifdef USE_TERMIO
+    struct termio sb;
+#else
+    struct sgttyb sb;
+#endif
+    
+    while (recv(rem, &mark, 1, MSG_OOB) < 0)
+      switch (errno) {
+         
+       case EWOULDBLOCK:
+         /*
+          * Urgent data not here yet.
+          * It may not be possible to send it yet
+          * if we are blocked for output
+          * and our input buffer is full.
+          */
+         if (rcvcnt < sizeof(rcvbuf)) {
+             n = read(rem, rcvbuf + rcvcnt,
+                      sizeof(rcvbuf) - rcvcnt);
+             if (n <= 0)
+               return;
+             rcvd += n;
+         } else {
+             n = read(rem, waste, sizeof(waste));
+             if (n <= 0)
+               return;
+         }
+         continue;
+         
+       default:
+         return;
+      }
+    if (mark & TIOCPKT_WINDOW) {
+       /*
+        * Let server know about window size changes
+        */
+       (void) kill(ppid, SIGUSR1);
+    }
+    if (!eight && (mark & TIOCPKT_NOSTOP)) {
+       (void) ioctl(0, TIOCGETP, (char *)&sb);
+#ifdef USE_TERMIO
+       sb.c_iflag |= IXOFF;
+       sb.sg_flags &= ~ICANON;
+#else
+       sb.sg_flags &= ~CBREAK;
+       sb.sg_flags |= RAW;
+       notc.t_stopc = -1;
+       notc.t_startc = -1;
+       (void) ioctl(0, TIOCSETC, (char *)&notc);
+#endif
+       (void) ioctl(0, TIOCSETN, (char *)&sb);
+    }
+    if (!eight && (mark & TIOCPKT_DOSTOP)) {
+       (void) ioctl(0, TIOCGETP, (char *)&sb);
+#ifdef USE_TERMIO
+       sb.sg_flags  |= ICANON;
+       sb.c_iflag |= IXON;
+#else
+       sb.sg_flags &= ~RAW;
+       sb.sg_flags |= CBREAK;
+       notc.t_stopc = deftc.t_stopc;
+       notc.t_startc = deftc.t_startc;
+       (void) ioctl(0, TIOCSETC, (char *)&notc);
+#endif
+       (void) ioctl(0, TIOCSETN, (char *)&sb);
+    }
+    if (mark & TIOCPKT_FLUSHWRITE) {
+#ifdef  TIOCFLUSH
+       (void) ioctl(1, TIOCFLUSH, (char *)&out);
+#else
+       (void) ioctl(1, TCFLSH, 1);
+#endif
+       for (;;) {
+           if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
+               perror("ioctl");
+               break;
+           }
+           if (atmark)
+             break;
+           n = read(rem, waste, sizeof (waste));
+           if (n <= 0)
+             break;
+       }
+       /*
+        * Don't want any pending data to be output,
+        * so clear the recv buffer.
+        * If we were hanging on a write when interrupted,
+        * don't want it to restart.  If we were reading,
+        * restart anyway.
+        */
+       rcvcnt = 0;
+       longjmp(rcvtop, 1);
+    }
+    
+    /*
+     * oob does not do FLUSHREAD (alas!)
+     */
+    
+    /*
+     * If we filled the receive buffer while a read was pending,
+     * longjmp to the top to restart appropriately.  Don't abort
+     * a pending write, however, or we won't know how much was written.
+     */
+    if (rcvd && rcvstate == READING)
+      longjmp(rcvtop, 1);
+}
+
+
+
+/*
+ * reader: read from remote: line -> 1
+ */
+reader(oldmask)
+     int oldmask;
+{
+#if (defined(BSD) && BSD >= 43) || defined(ultrix)
+    int pid = getpid();
+#else
+    int pid = -getpid();
+#endif
+    int n, remaining;
+    char *bufp = rcvbuf;
+    
+    (void) signal(SIGTTOU, SIG_IGN);
+    (void) signal(SIGURG, oob);
+    ppid = getppid();
+#ifndef SYSV
+    (void) fcntl(rem, F_SETOWN, pid);
+#endif
+    (void) setjmp(rcvtop);
+#ifndef sgi
+    (void) sigsetmask(oldmask);
+#endif
+    for (;;) {
+       while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) {
+           rcvstate = WRITING;
+           n = write(1, bufp, remaining);
+           if (n < 0) {
+               if (errno != EINTR)
+                 return (-1);
+               continue;
+           }
+           bufp += n;
+       }
+       bufp = rcvbuf;
+       rcvcnt = 0;
+       rcvstate = READING;
+       rcvcnt = des_read(rem, rcvbuf, sizeof (rcvbuf));
+       if (rcvcnt == 0)
+         return (0);
+       if (rcvcnt < 0) {
+           if (errno == EINTR)
+             continue;
+           perror("read");
+           return (-1);
+       }
+    }
+}
+
+
+
+mode(f)
+{
+    struct ltchars *ltc;
+#ifdef USE_TERMIO
+    struct termio sb;
+#else
+    struct tchars *tc;
+    struct sgttyb sb;
+    int        lflags;
+    (void) ioctl(0, TIOCLGET, (char *)&lflags);
+#endif
+    
+    (void) ioctl(0, TIOCGETP, (char *)&sb);
+    switch (f) {
+       
+      case 0:
+#ifdef USE_TERMIO
+       /*
+        **      remember whether IXON was set, so it can be restored
+        **      when mode(1) is next done
+        */
+       (void) ioctl(fileno(stdin), TIOCGETP, &ixon_state);
+       /*
+        **      copy the initial modes we saved into sb; this is
+        **      for restoring to the initial state
+        */
+       (void)memcpy(&sb, &defmodes, sizeof(defmodes));
+       
+#else
+       sb.sg_flags &= ~(CBREAK|RAW|TBDELAY);
+       sb.sg_flags |= defflags|tabflag;
+       sb.sg_kill = defkill;
+       sb.sg_erase = deferase;
+       lflags = deflflags;
+       tc = &deftc;
+#endif
+       ltc = &defltc;
+       break;
+       
+      case 1:
+#ifdef USE_TERMIO
+       /*
+        **      turn off output mappings
+        */
+       sb.c_oflag &= ~(ONLCR|OCRNL);
+       /*
+        **      turn off canonical processing and character echo;
+        **      also turn off signal checking -- ICANON might be
+        **      enough to do this, but we're being careful
+        */
+       sb.c_lflag &= ~(ECHO|ICANON|ISIG);
+       sb.c_cc[VTIME] = 1;
+       sb.c_cc[VMIN] = 1;
+       if (eight)
+         sb.c_iflag &= ~(ISTRIP);
+       /* preserve tab delays, but turn off tab-to-space expansion */
+       if ((sb.c_oflag & TABDLY) == TAB3)
+         sb.c_oflag &= ~TAB3;
+       /*
+        **  restore current flow control state
+        */
+       if ((ixon_state.c_iflag & IXON) && flow ) {
+           sb.c_iflag |= IXON;
+       } else {
+           sb.c_iflag &= ~IXON;
+       }
+#else /* ! USE_TERMIO */
+       sb.sg_flags &= ~(CBREAK|RAW);
+       sb.sg_flags |= (!flow ? RAW : CBREAK);
+       /* preserve tab delays, but turn off XTABS */
+       if ((sb.sg_flags & TBDELAY) == XTABS)
+         sb.sg_flags &= ~TBDELAY;
+       sb.sg_kill = sb.sg_erase = -1;
+#ifdef LLITOUT
+       if (litout)
+         lflags |= LLITOUT;
+#endif
+#ifdef LPASS8
+       if (eight)
+         lflags |= LPASS8;
+#endif /* LPASS8 */
+       tc = &notc;
+       sb.sg_flags &= ~defflags;
+#endif /* USE_TERMIO */
+       
+       ltc = &noltc;
+       break;
+       
+      default:
+       return;
+    }
+    (void) ioctl(0, TIOCSLTC, (char *)ltc);
+#ifndef USE_TERMIO
+    (void) ioctl(0, TIOCSETC, (char *)tc);
+    (void) ioctl(0, TIOCLSET, (char *)&lflags);
+#endif
+    (void) ioctl(0, TIOCSETN, (char *)&sb);
+}
+
+
+
+/*VARARGS*/
+prf(f, a1, a2, a3, a4, a5)
+     char *f;
+{
+    fprintf(stderr, f, a1, a2, a3, a4, a5);
+    fprintf(stderr, CRLF);
+}
+
+
+
+#ifdef KERBEROS
+void try_normal(argv)
+     char **argv;
+{
+    register char *host;
+    
+    if (encrypt)
+      exit(1);
+    fprintf(stderr,"trying normal rlogin (%s)\n",
+           UCB_RLOGIN);
+    fflush(stderr);
+    
+    host = rindex(argv[0], '/');
+    if (host)
+      host++;
+    else
+      host = argv[0];
+    if (!strcmp(host, "rlogin"))
+      argv++;
+    
+    execv(UCB_RLOGIN, argv);
+    perror("exec");
+    exit(1);
+}
+
+
+
+char storage[2*BUFSIZ];                        /* storage for the decryption */
+int nstored = 0;
+char *store_ptr = storage;
+
+#ifndef OLD_VERSION
+
+int des_read(fd, buf, len)
+     int fd;
+     register char *buf;
+     int len;
+{
+    int nreturned = 0;
+    long net_len,rd_len;
+    int cc;
+    
+    if (!encrypt)
+      return(read(fd, buf, len));
+    
+    if (nstored >= len) {
+       memcpy(buf, store_ptr, len);
+       store_ptr += len;
+       nstored -= len;
+       return(len);
+    } else if (nstored) {
+       memcpy(buf, store_ptr, nstored);
+       nreturned += nstored;
+       buf += nstored;
+       len -= nstored;
+       nstored = 0;
+    }
+    
+#ifdef BITS64
+    /*
+     * XXX Ick.  This assumes big endian byte order.
+     */
+    rd_len = 0;
+    if ((cc = krb5_net_read(fd, (char *)&rd_len + 4, 4)) != 4) {
+#else
+    if ((cc = krb5_net_read(fd, (char *)&rd_len, sizeof(rd_len))) !=
+           sizeof(rd_len)) {
+#endif
+               /* XXX can't read enough, pipe
+                  must have closed */
+       return(0);
+    }
+    rd_len = ntohl(rd_len);
+    net_len = krb5_encrypt_size(rd_len,eblock.crypto_entry);
+    if (net_len <= 0 || net_len > sizeof(des_inbuf)) {
+       /* preposterous length; assume out-of-sync; only
+          recourse is to close connection, so return 0 */
+       fprintf(stderr,"Read size problem.\n");
+       return(0);
+    }
+    if ((cc = krb5_net_read(fd, desinbuf.data, net_len)) != net_len) {
+       /* pipe must have closed, return 0 */
+       fprintf(stderr,
+               "Read error: length received %d != expected %d.\n",
+               cc,net_len);
+       return(0);
+    }
+    /* decrypt info */
+    if ((krb5_decrypt(desinbuf.data,
+                     (krb5_pointer) storage,
+                     net_len,
+                     &eblock, 0))) {
+       fprintf(stderr,"Cannot decrypt data from network.\n");
+       return(0);
+    }
+    store_ptr = storage;
+    nstored = rd_len;
+    if (nstored > len) {
+       memcpy(buf, store_ptr, len);
+       nreturned += len;
+       store_ptr += len;
+       nstored -= len;
+    } else {
+       memcpy(buf, store_ptr, nstored);
+       nreturned += nstored;
+       nstored = 0;
+    }
+    
+    return(nreturned);
+}
+
+
+
+int des_write(fd, buf, len)
+     int fd;
+     char *buf;
+     int len;
+{
+    long net_len;
+    
+    if (!encrypt)
+      return(write(fd, buf, len));
+    
+    desoutbuf.length = krb5_encrypt_size(len,eblock.crypto_entry);
+    if (desoutbuf.length > sizeof(des_outbuf)){
+       fprintf(stderr,"Write size problem.\n");
+       return(-1);
+    }
+    if (( krb5_encrypt((krb5_pointer)buf,
+                      desoutbuf.data,
+                      len,
+                      &eblock,
+                      0))){
+       fprintf(stderr,"Write encrypt problem.\n");
+       return(-1);
+    }
+    
+    net_len = htonl(len);
+#ifdef BITS64
+    (void) write(fd,(char *)&net_len + 4, 4);
+#else
+    (void) write(fd, &net_len, sizeof(net_len));
+#endif
+    if (write(fd, desoutbuf.data,desoutbuf.length) != desoutbuf.length){
+       fprintf(stderr,"Could not write out all data.\n");
+       return(-1);
+    }
+    else return(len); 
+}
+
+
+
+#else /* Original version  placed here so that testing could be done
+        to determine why rlogin with encryption on is slower with
+        version 5 as compared to version 4. */
+
+#define ENCRYPT 1
+#define DECRYPT 0
+
+
+
+int des_read(fd, buf, len)
+     int fd;
+     register char *buf;
+     int len;
+{
+    int nreturned = 0;
+    long net_len, rd_len;
+    int cc;
+    
+    if (!encrypt)
+      return(read(fd, buf, len));
+    
+    if (nstored >= len) {
+       bcopy(store_ptr, buf, len);
+       store_ptr += len;
+       nstored -= len;
+       return(len);
+    } else if (nstored) {
+       bcopy(store_ptr, buf, nstored);
+       nreturned += nstored;
+       buf += nstored;
+       len -= nstored;
+       nstored = 0;
+    }
+#ifdef BITS64
+    net_len = 0;
+    if ((cc = krb5_net_read(fd, (char *)&net_len + 4, 4)) != 4) {
+#else
+    if ((cc = krb5_net_read(fd, &net_len, sizeof(net_len))) !=
+       sizeof(net_len)) {
+#endif
+       /* XXX can't read enough, pipe
+          must have closed */
+       return(0);
+    }
+    net_len = ntohl(net_len);
+    if (net_len < 0 || net_len > sizeof(des_inbuf)) {
+       /* XXX preposterous length, probably out of sync.
+          act as if pipe closed */
+       return(0);
+    }
+    /* the writer tells us how much real data we are getting, but
+       we need to read the pad bytes (8-byte boundary) */
+#ifdef NOROUNDUP
+    rd_len = ((((net_len)+((8)-1))/(8))*(8));
+#else
+    rd_len = roundup(net_len, 8);
+#endif
+    if ((cc = krb5_net_read(fd, des_inbuf, rd_len)) != rd_len) {
+       /* pipe must have closed, return 0 */
+       return(0);
+    }
+    (void) mit_des_cbc_encrypt(
+                              des_inbuf,
+                              storage,
+                              (net_len < 8) ? 8 : net_len,
+                              eblock.priv,
+                              eblock.key->contents,
+                              DECRYPT);
+    /*
+     * when the cleartext block is < 8 bytes, it is "right-justified"
+     * in the block, so we need to adjust the pointer to the data
+     */
+    if (net_len < 8)
+      store_ptr = storage + 8 - net_len;
+    else
+      store_ptr = storage;
+    nstored = net_len;
+    if (nstored > len) {
+       bcopy(store_ptr, buf, len);
+       nreturned += len;
+       store_ptr += len;
+       nstored -= len;
+    } else {
+       bcopy(store_ptr, buf, nstored);
+       nreturned += nstored;
+       nstored = 0;
+    }
+    return(nreturned);
+}
+
+
+
+int des_write(fd, buf, len)
+     int fd;
+     char *buf;
+     int len;
+{
+    long net_len;
+    static int seeded = 0;
+    static char garbage_buf[8];
+    long garbage;
+    
+    if (!encrypt)
+      return(write(fd, buf, len));
+    
+#define min(a,b) ((a < b) ? a : b)
+    
+    if (len < 8) {
+       if (!seeded) {
+           seeded = 1;
+           srandom((int) time((long *)0));
+       }
+       garbage = random();
+       /* insert random garbage */
+       (void) bcopy(&garbage, garbage_buf, min(sizeof(long),8));
+       
+       /* this "right-justifies" the data in the buffer */
+       (void) bcopy(buf, garbage_buf + 8 - len, len);
+    }
+    
+    (void) mit_des_cbc_encrypt((len < 8) ? garbage_buf : buf,
+                              des_outbuf,
+                              (len < 8) ? 8 : len,
+                              eblock.priv,
+                              eblock.key->contents,
+                              ENCRYPT);
+    
+    /* tell the other end the real amount, but send an 8-byte padded
+       packet */
+    net_len = htonl(len);
+#ifdef BITS64
+    (void) write(fd,(char *)&net_len + 4, 4);
+#else
+    (void) write(fd, &net_len, sizeof(net_len));
+#endif
+#ifdef NOROUNDUP
+    (void) write(fd, des_outbuf, ((((len)+((8)-1))/(8))*(8)));
+#else
+    (void) write(fd, des_outbuf, roundup(len,8));
+#endif
+    return(len);
+}
+
+#endif /* OLD_VERSION */
+#endif /* KERBEROS */
+
+
+
+krb5_sigtype lostpeer()
+{
+    
+    (void) signal(SIGPIPE, SIG_IGN);
+    prf("\007Connection closed.");
+    done(1);
+}
diff --git a/src/appl/bsd/krlogind.M b/src/appl/bsd/krlogind.M
new file mode 100644 (file)
index 0000000..4ceebd7
--- /dev/null
@@ -0,0 +1,102 @@
+.\" Copyright (c) 1983 Regents of the University of California.
+.\" All rights reserved.  The Berkeley software License Agreement
+.\" specifies the terms and conditions for redistribution.
+.\"
+.\"    @(#)rlogind.8c  6.3 (Berkeley) 5/24/86
+.\"
+.TH RLOGIND 8C "May 24, 1986"
+.UC 5
+.SH NAME
+rlogind \- remote login server
+.SH SYNOPSIS
+.B /etc/rlogind
+[
+.B \-d
+]
+.SH DESCRIPTION
+.I Rlogind
+is the server for the 
+.IR rlogin (1C)
+program.  The server provides a remote login facility
+with authentication based on privileged port numbers from trusted hosts.
+.PP
+.I Rlogind
+listens for service requests at the port indicated in
+the ``login'' service specification; see
+.IR services (5).
+When a service request is received the following protocol
+is initiated:
+.IP 1)
+The server checks the client's source port.
+If the port is not in the range 0-1023, the server
+aborts the connection.
+.IP 2)
+The server checks the client's source address
+and requests the corresponding host name (see
+.IR gethostbyaddr (3N),
+.IR hosts (5)
+and
+.IR named (8)).
+If the hostname cannot be determined,
+the dot-notation representation of the host address is used.
+.PP
+Once the source port and address have been checked, 
+.I rlogind
+allocates a pseudo terminal (see 
+.IR pty (4)),
+and manipulates file descriptors so that the slave
+half of the pseudo terminal becomes the 
+.B stdin ,
+.B stdout ,
+and
+.B stderr 
+for a login process.
+The login process is an instance of the
+.IR login (1)
+program, invoked with the
+.B \-r
+option.  The login process then proceeds with the authentication
+process as described in
+.IR rshd (8C),
+but if automatic authentication fails, it reprompts the user
+to login as one finds on a standard terminal line.
+.PP
+The parent of the login process manipulates the master side of
+the pseduo terminal, operating as an intermediary
+between the login process and the client instance of the
+.I rlogin
+program.  In normal operation, the packet protocol described
+in
+.IR pty (4)
+is invoked to provide ^S/^Q type facilities and propagate
+interrupt signals to the remote programs.  The login process
+propagates the client terminal's baud rate and terminal type,
+as found in the environment variable, ``TERM''; see
+.IR environ (7).
+The screen or window size of the terminal is requested from the client,
+and window size changes from the client are propagated to the pseudo terminal.
+.SH DIAGNOSTICS
+All diagnostic messages are returned on the connection
+associated with the
+.BR stderr ,
+after which any network connections are closed.
+An error is indicated by a leading byte with a value of 1.
+.PP
+.B ``Try again.''
+.br
+A
+.I fork
+by the server failed.
+.PP
+.B ``/bin/sh: ...''
+.br
+The user's login shell could not be started.
+.SH BUGS
+The authentication procedure used here assumes the integrity
+of each client machine and the connecting medium.  This is
+insecure, but is useful in an ``open'' environment.
+.PP
+A facility to allow all data exchanges to be encrypted should be
+present.
+.PP
+A more extensible protocol should be used.
diff --git a/src/appl/bsd/krlogind.c b/src/appl/bsd/krlogind.c
new file mode 100644 (file)
index 0000000..9360b6f
--- /dev/null
@@ -0,0 +1,1365 @@
+/*
+ *     $Source$
+ *     $Header$
+ */
+
+
+#ifndef lint
+static char *rcsid_rlogind_c = "$Header$";
+#endif /* lint */
+
+/*
+ * Copyright (c) 1983 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+char copyright[] =
+  "@(#) Copyright (c) 1983 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)rlogind.c  5.17 (Berkeley) 8/31/88";
+#endif /* not lint */
+     
+     /*
+      * remote login server:
+      *        remuser\0
+      *        locuser\0
+      *        terminal info\0
+      *        data
+      */
+     
+     /*
+      * This is the rlogin daemon. The very basic protocol for checking 
+      * authentication and authorization is:
+      * 1) Check authentication.
+      * 2) Check authorization via the access-control files: 
+      *    ~/.k5login (using krb5_kuserok) and/or
+      *    ~/.rhosts  (using ruserok).
+      * 3) Prompt for password if any checks fail, or if so configured.
+      * Allow login if all goes well either by calling the accompanying login.krb
+      * or /bin/login, according to the definition of DO_NOT_USE_K_LOGIN.
+      * 
+      * The configuration is done either by command-line arguments passed by inetd, 
+      * or by the name of the daemon. If command-line arguments are present, they 
+      * take priority. The options are:
+      * -k and -K means check .k5login (using krb5_kuserok).
+      * -r and -R means check .rhosts  (using ruserok).
+      * -p and -P means prompt for password.
+      * The difference between upper and lower case is as follows:
+      *    If lower case -r or -k, then as long as one of krb5_kuserok or ruserok 
+      * passes, allow login without password. If the -p option is passed with -r 
+      * or -k, then if both checks fail, allow login but only after password 
+      * verification. 
+      *    If uppercase -R or -K, then those checks must be passed, regardless of
+      * other checks, else no login with or without password.
+      *    If the -P option is passed, then the password is verified in 
+      * addition to all other checks. If -p is not passed with -k or -r, and both
+      * checks fail, then login permission is denied.
+      * -x and -e means use encryption.
+      *     If no command-line arguments are present, then the presence of the 
+      * letters kKrRexpP in the program-name before "logind" determine the 
+      * behaviour of the program exactly as with the command-line arguments.
+      *
+      * If the ruserok check is to be used, then the client should connect from a 
+      * privileged port, else deny permission.
+      */ 
+     
+     /* DEFINES:
+      *   KERBEROS - Define this if application is to be kerberised.
+      *   CRYPT    - Define this if encryption is to be an option.
+      *   DO_NOT_USE_K_LOGIN - Define this if you want to use /bin/login instead 
+      *              of the accompanying login.krb. In that case, the remote user's
+      *              name must be present in the local .rhosts file, regardless of
+      *              any options specified.
+      *   LOG_ALL_LOGINS - Define this if you want to log all logins.
+      *   LOG_OTHER_USERS - Define this if you want to log all principals that do
+      *              not map onto the local user.
+      *   LOG_REMOTE_REALM - Define this if you want to log all principals from 
+      *              remote realms.
+      *       Note:  Root logins are always logged.
+      */
+     
+#define LOG_REMOTE_REALM
+#define KERBEROS 
+     
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <sys/file.h>
+/* #include <sys/unistd.h>  ??? What system has a sys/unistd.h? */
+     
+#include <netinet/in.h>
+#include <errno.h>
+#include <pwd.h>
+     
+#ifdef sun
+#include <sys/label.h>
+#include <sys/audit.h>
+#include <pwdadj.h>
+#endif
+     
+#include <signal.h>
+#ifdef hpux
+#include <sys/ptyio.h>
+#endif
+     
+#ifdef sysvimp
+#include <compat.h>
+#define STREAMS
+#include <sys/stropts.h>
+#endif
+     
+#ifdef SYSV
+#define USE_TERMIO
+#endif
+     
+#ifdef USE_TERMIO
+#include <termio.h>
+#else
+#include <sgtty.h>
+#endif /* USE_TERMIO */
+     
+#include <netdb.h>
+#include <syslog.h>
+#include <strings.h>
+#include <sys/param.h>
+#include <utmp.h>
+     
+#ifdef NO_WINSIZE
+struct winsize {
+    unsigned short ws_row, ws_col;
+    unsigned short ws_xpixel, ws_ypixel;
+};
+#endif /* NO_WINSIZE */
+     
+#ifdef KERBEROS
+     
+#include <krb5/krb5.h>
+#include <krb5/asn1.h>
+#include <krb5/crc-32.h>
+#include <krb5/mit-des.h>
+#include <krb5/los-proto.h>
+
+#include <com_err.h>
+     
+#ifdef BUFSIZ
+#undef BUFSIZ
+#endif
+#define BUFSIZ 4096
+     
+#define SECURE_MESSAGE  "This rlogin session is using DES encryption for all data transmissions.\r\n"
+
+char des_inbuf[2*BUFSIZ];         /* needs to be > largest read size */
+char des_outbuf[2*BUFSIZ];        /* needs to be > largest write size */
+krb5_data desinbuf,desoutbuf;
+krb5_encrypt_block eblock;        /* eblock for encrypt/decrypt */
+
+krb5_authenticator      *kdata;
+krb5_ticket     *ticket = 0;
+
+#ifdef CRAY
+#ifndef BITS64
+#define BITS64
+#endif
+#endif
+
+#define ARGSTR "rRkKeExXpP?"
+#else /* !KERBEROS */
+#define ARGSTR "rRpP?"
+#define des_read        read
+#define des_write       write
+#endif /* KERBEROS */
+
+#ifdef DO_NOT_USE_K_LOGIN
+#ifdef sysvimp
+#define LOGIN_PROGRAM "/bin/remlogin"
+#else
+#define LOGIN_PROGRAM "/bin/login"
+#endif
+#else /* DO_NOT_USE_K_LOGIN */
+#define LOGIN_PROGRAM "/krb5/etc/login.krb5"
+#endif
+
+struct utmp    wtmp;
+#define NMAX    sizeof(wtmp.ut_name)
+#define MAXRETRIES 4
+#define        UT_HOSTSIZE     sizeof(((struct utmp *)0)->ut_host)
+#define MAX_PROG_NAME 16
+
+char           lusername[NMAX+1];
+char           *rusername  = 0;
+char            *krusername = 0;
+char           term[64];
+char            rhost_name[128];
+
+extern int errno;
+int    reapchild();
+struct passwd *getpwnam();
+#ifndef ultrix
+char   *malloc();
+#endif
+char   *progname;
+
+void   fatal(), fatalperror(), doit(), usage();
+int    princ_maps_to_lname(), default_realm();
+
+int must_pass_rhosts = 0, must_pass_k5 = 0, must_pass_one = 0;
+int do_encrypt = 0, passwd_if_fail = 0, passwd_req = 0;
+int failed_auth = 0, failed_k5 = 0, failed_rhosts = 0;
+
+main(argc, argv)
+     int argc;
+     char **argv;
+{
+    extern int opterr, optind;
+    int on = 1, fromlen, ch, i;
+    struct sockaddr_in from;
+    char *options;
+    
+    progname = *argv;
+    
+#ifdef KERBEROS
+    
+#ifndef LOG_NDELAY
+#define LOG_NDELAY 0
+#endif
+    
+    
+#ifndef LOG_AUTH /* 4.2 syslog */
+    openlog(progname, LOG_PID|LOG_NDELAY);
+#else
+    openlog(progname, LOG_PID | LOG_AUTH | LOG_NDELAY, LOG_AUTH);
+#endif /* 4.2 syslog */
+    
+#else /* ! KERBEROS */
+    
+#ifndef LOG_AUTH /* 4.2 syslog */
+    openlog("rlogind", LOG_PID| LOG_NDELAY);
+#else
+    openlog("rlogind", LOG_PID | LOG_AUTH | LOG_NDELAY, LOG_AUTH);
+#endif /* 4.2 syslog */
+    
+#endif /* KERBEROS */
+    
+    if (argc == 1) { /* Get parameters from program name. */
+       if (strlen(progname) > MAX_PROG_NAME) {
+           usage();
+           exit(1);
+       }
+       options = (char *) malloc(MAX_PROG_NAME+1);
+       options[0] = '\0';
+       for (i = 0; (progname[i] != '\0') && (i < MAX_PROG_NAME); i++)
+         if (!strcmp(progname+i, "logind")) {
+             strcpy(options, "-");
+             strncat(options, progname, i);
+             argc = 2;
+             argv[1] = options;
+             argv[2] = NULL;
+             break;
+         }
+       if (options[0] == '\0') {
+           usage();
+           exit(1);
+       }
+    }
+    
+    /* Analyse parameters. */
+    opterr = 0;
+    while ((ch = getopt(argc, argv, ARGSTR)) != EOF)
+      switch (ch) {
+       case 'r':         
+         must_pass_one = 1; /* If just 'r', any one check must succeed */
+         break;
+       case 'R':         /* If 'R', must pass .rhosts check*/
+         must_pass_rhosts = 1;
+         if (must_pass_one)
+           must_pass_one = 0;
+         break;
+#ifdef KERBEROS
+       case 'k':
+         must_pass_one = 1; /* If just 'k', any one check must succeed */
+         break;
+       case 'K':         /* If 'K', must pass .k5login check*/
+         must_pass_k5 = 1;
+         if (must_pass_one)
+           must_pass_one = 0;
+         break;
+#ifdef CRYPT
+       case 'x':         /* Use encryption. */
+       case 'X':
+       case 'e':
+       case 'E':
+         do_encrypt = 1;
+         break;
+#endif
+#endif
+       case 'p':
+         passwd_if_fail = 1; /* Passwd reqd if any check fails */
+         break;
+       case 'P':         /* passwd is a must */
+         passwd_req = 1;
+         break;
+       case '?':
+       default:
+         usage();
+         exit(1);
+         break;
+      }
+    argc -= optind;
+    argv += optind;
+    
+    fromlen = sizeof (from);
+    if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
+       syslog(LOG_ERR,"Can't get peer name of remote host: %m");
+#ifdef STDERR_FILENO
+       fatal(STDERR_FILENO, "Can't get peer name of remote host", 1);
+#else
+       fatal(3, "Can't get peer name of remote host", 1);
+#endif
+       
+    }
+    if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0)
+      syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
+    
+    doit(0, &from);
+}
+
+
+
+#ifndef LOG_AUTH
+#define LOG_AUTH 0
+#endif
+
+int    child;
+int    cleanup();
+int    netf;
+krb5_principal client;
+char   line[MAXPATHLEN];
+extern char    *inet_ntoa();
+
+#ifdef TIOCSWINSZ
+struct winsize win = { 0, 0, 0, 0 };
+#endif
+
+int pid; /* child process id */
+
+void doit(f, fromp)
+     int f;
+     struct sockaddr_in *fromp;
+{
+    int i, p, t, on = 1;
+    register struct hostent *hp;
+    char c;
+    char buferror[255];
+    struct passwd *pwd;
+    
+    netf = -1;
+    alarm(60);
+    read(f, &c, 1);
+    
+    if (c != 0){
+       exit(1);
+    }
+    
+    alarm(0);
+    fromp->sin_port = ntohs((u_short)fromp->sin_port);
+    hp = gethostbyaddr(&fromp->sin_addr, sizeof (struct in_addr),
+                      fromp->sin_family);
+    if (hp == 0) {
+       /*
+        * Only the name is used below.
+        */
+       sprintf(rhost_name,"%s",inet_ntoa(fromp->sin_addr));
+    }
+    
+    /* Save hostent information.... */
+    else strcpy(rhost_name,hp->h_name);
+    
+    if (fromp->sin_family != AF_INET)
+      fatal(f, "Permission denied - Malformed from address\n");
+    
+#ifdef KERBEROS
+    if (must_pass_k5 || must_pass_one) {
+       /* Init error messages and setup des buffers */
+       krb5_init_ets();
+       desinbuf.data = des_inbuf;
+       desoutbuf.data = des_outbuf;    /* Set up des buffers */
+    }
+    /* Must come from privileged port when .rhosts is being looked into */
+    if ((must_pass_rhosts || must_pass_one) 
+       && (fromp->sin_port >= IPPORT_RESERVED ||
+           fromp->sin_port < IPPORT_RESERVED/2))
+#else /* !KERBEROS */
+      if (fromp->sin_port >= IPPORT_RESERVED ||
+         fromp->sin_port < IPPORT_RESERVED/2)
+#endif /* KERBEROS */
+       fatal(f, "Permission denied - Connection from bad port");
+    
+    /* Set global netf to f now : we may need to drop everything
+       in do_krb_login. */
+    netf = f;
+    
+#if defined(KERBEROS)
+    /*
+     * If encrypting, we need to respond here, since we have to send
+     * the mutual authentication stuff before the response
+     *
+     * Do_krb_login has been modified to handle rlogin type requests
+     * also....
+     */
+    /* All validation, and authorization goes through do_krb_login() */
+    do_krb_login(rhost_name);
+    
+    if (failed_auth || (failed_k5 && failed_rhosts)) {
+       if (must_pass_one && passwd_if_fail)
+         passwd_req = 1;
+       else
+         fatal(netf, "Permission denied");
+    }
+#else
+    rusername = malloc(sizeof (lusername) + 1);
+    getstr(rusername, sizeof(lusername), "remuser");
+    getstr(lusername, sizeof(lusername), "locuser");
+    getstr(term, sizeof(term), "Terminal type");
+#endif
+    
+    write(f, "", 1);
+    if (getpty(&p,line))
+      fatal(f, "Out of ptys");
+#ifdef TIOCSWINSZ
+    (void) ioctl(p, TIOCSWINSZ, &win);
+#endif
+    
+#ifndef sysvimp  /* IMP has a problem with opening and closing
+                   it's stream pty by the parent process */
+    
+    /* Make sure we can open slave pty, then close it for system 5 so that 
+       the process group is set correctly..... */
+    t = open(line, O_RDWR);
+    if (t < 0)
+      fatalperror(f, line);
+#ifdef NOFCHMOD
+    if (chmod(t,0))
+#else
+      if (fchmod(t, 0))
+#endif
+       fatalperror(f, line);
+#ifndef SYSV
+    signal(SIGHUP, SIG_IGN);
+    vhangup();
+    signal(SIGHUP, SIG_DFL);
+#ifdef ultrix   /* Someone needs to cleanup all this and have a consistant
+                  way of associating controlling tty to a process. */
+    setpgrp();
+#endif
+    t = open(line, O_RDWR);
+    if (t < 0)
+      fatalperror(f, line);
+#endif
+#ifdef SYSV
+    close(t);
+#endif
+#endif  /* sysvimp */
+    signal(SIGCHLD, cleanup);
+    signal(SIGTERM, cleanup);
+    pid = fork();
+    if (pid < 0)
+      fatalperror(f, "", errno);
+    if (pid == 0) {
+       {
+#ifdef USE_TERMIO
+           struct termio b;
+#define TIOCGETP TCGETA
+#define TIOCSETP TCSETA
+#ifdef MIN
+#undef MIN
+#endif
+#define        MIN     1
+#define        TIME    0
+           
+#else
+           struct sgttyb b;
+#endif
+#ifdef SYSV
+           (void) setpgrp();
+           /* SYSV open slave device: We closed it above so pgrp
+              would be set correctly...*/
+           t = open(line, O_RDWR);
+           if (t < 0)
+             fatalperror(f, line);
+#endif
+#ifdef STREAMS
+           while (ioctl (t, I_POP, 0) == 0); /*Clear out any old lined's*/
+#endif
+           /* Under Ultrix 3.0, the pgrp of the slave pty terminal
+              needs to be set explicitly.  Why rlogind works at all
+              without this on 4.3BSD is a mystery.
+              It seems to work fine on 4.3BSD with this code enabled.
+              IMP's need both ioctl and setpgrp..
+              */
+#if !defined(SYSV) || defined(sysvimp)
+           /* SYSV set process group prior to opening pty */
+#ifdef sysvimp
+           pid = 0;
+#else
+#ifdef convex
+           pid = getpgrp();
+#else
+           pid = getpgrp(getpid());
+#endif
+#endif
+           ioctl(t, TIOCSPGRP, &pid);
+           pid = 0;                    /*reset pid incase exec fails*/
+#endif
+#ifdef STREAMS
+           if (line_push(t) < 0)
+             fatalperror(f, "IPUSH",errno);
+#endif
+           (void)ioctl(t, TIOCGETP, &b);
+#ifdef USE_TERMIO
+           /* The key here is to just turn off echo */
+           b.c_iflag &= ~(ICRNL|IUCLC);
+           b.c_iflag |= IXON;
+           b.c_cflag |= CS8;
+           b.c_lflag |= ICANON|ISIG;
+           b.c_lflag &= ~(ECHO);
+           b.c_cc[VMIN] = MIN;
+           b.c_cc[VTIME] = TIME;
+#else
+           b.sg_flags = RAW|ANYP;
+#endif
+           (void)ioctl(t, TIOCSETP, &b);
+           /*
+            **      signal the parent that we have turned off echo
+            **      on the slave side of the pty ... he's waiting
+            **      because otherwise the rlogin protocol junk gets
+            **      echo'd to the user (locuser^@remuser^@term/baud)
+            **      and we don't get the right tty affiliation, and
+            **      other kinds of hell breaks loose ...
+            */
+           (void) write(t, &c, 1);
+           
+       }
+       close(f), close(p);
+       dup2(t, 0), dup2(t, 1), dup2(t, 2);
+       if (t > 2)
+         close(t);
+#if defined(sysvimp)
+       setcompat (COMPAT_CLRPGROUP | (getcompat() & ~COMPAT_BSDTTY));
+#endif
+       
+       /* Log access to account */
+       pwd = (struct passwd *) getpwnam(lusername);
+       if (pwd && (pwd->pw_uid == 0)) {
+           if (passwd_req)
+             syslog(LOG_NOTICE, "ROOT login by %s (%s@%s) forcing password access",
+                    krusername, rusername, rhost_name);
+           else
+             syslog(LOG_NOTICE, "ROOT login by %s (%s@%s) ", 
+                    krusername, rusername, rhost_name);
+       }
+       
+#if defined(KERBEROS) && defined(LOG_REMOTE_REALM) && !defined(LOG_OTHER_USERS) && !defined(LOG_ALL_LOGINS)
+       /* Log if principal is from a remote realm */
+else if (!default_realm(client))
+#endif
+  
+#if defined(KERBEROS) && defined(LOG_OTHER_USERS) && !defined(LOG_ALL_LOGINS) 
+  /* Log if principal name does not map to local username */
+else if (!princ_maps_to_lname(client, lusername))
+#endif /* LOG_OTHER_USERS */
+  
+#ifdef LOG_ALL_LOGINS /* Log everything */
+else 
+#endif
+  
+#if defined(LOG_REMOTE_REALM) || defined(LOG_OTHER_USERS) || defined(LOG_ALL_LOGINS)
+  {
+      if (passwd_req)
+       syslog(LOG_NOTICE,
+              "login by %s (%s@%s) as %s forcing password access\n",
+              krusername, rusername, rhost_name, lusername);
+      else 
+       syslog(LOG_NOTICE,
+              "login by %s (%s@%s) as %s\n",
+              krusername, rusername, rhost_name, lusername); 
+  }
+#endif
+       
+#ifdef DO_NOT_USE_K_LOGIN
+       execl(LOGIN_PROGRAM, "login", "-r", rhost_name, 0);
+#else
+       if (passwd_req)
+         execl(LOGIN_PROGRAM, "login", rhost_name,0);
+       else
+         execl(LOGIN_PROGRAM, "login", "-f", rhost_name, 0);
+#endif
+       
+       fatalperror(2, LOGIN_PROGRAM, errno);
+       /*NOTREACHED*/
+    }
+    /*
+     **      wait for child to start ... read one byte
+     **      -- see the child, who writes one byte after
+     **      turning off echo on the slave side ...
+     **      The master blocks here until it reads a byte.
+     */
+    if (read(p, &c, 1) != 1) {
+       /*
+        * Problems read failed ...
+        */
+       sprintf(buferror, "Cannot read slave pty %s ",line);
+       fatalperror(p,buferror,errno);
+    }
+    
+#if defined(KERBEROS) 
+    if (do_encrypt)
+      if ((des_write(f, SECURE_MESSAGE, sizeof(SECURE_MESSAGE))) < 0){
+         sprintf(buferror, "Cannot encrypt-write network.");
+         fatal(p,buferror);
+      }
+      else 
+       /*
+        * if encrypting, don't turn on NBIO, else the read/write routines
+        * will fail to work properly
+        */
+#endif /* KERBEROS */
+       {
+           ioctl(f, FIONBIO, &on);
+           ioctl(p, FIONBIO, &on);
+       }
+#ifdef hpux
+    /******** FIONBIO doesn't currently work on ptys, should be O_NDELAY? **/
+    /*** get flags and add O_NDELAY **/
+    (void) fcntl(p,F_SETFL,fcntl(p,F_GETFL,0) | O_NDELAY);
+#endif
+    
+    ioctl(p, TIOCPKT, &on);
+    signal(SIGTSTP, SIG_IGN);
+#ifdef hpux
+    setpgrp2(0, 0);
+#else
+    setpgrp(0, 0);
+#endif
+    
+#if defined(KERBEROS) 
+    /* Pass down rusername and lusername which we have
+       obtained from ticket and authorized by PWC_ACCESS.
+       Note lusername's .rhost should have entry for rusername.
+       */
+    (void) write(p, rusername, strlen(rusername) +1);
+    (void) write(p, lusername, strlen(lusername) +1);
+    /* stuff term info down to login */
+    if( write(p, term, strlen(term)+1) <= 0 ){
+       /*
+        * Problems write failed ...
+        */
+       sprintf(buferror,"Cannot write slave pty %s ",line);
+       fatalperror(f,buferror,errno);
+    } 
+#endif /* KERBEROS */
+    
+    protocol(f, p);
+    signal(SIGCHLD, SIG_IGN);
+    cleanup();
+}
+
+
+
+char   magic[2] = { 0377, 0377 };
+#ifdef TIOCSWINSZ
+#ifndef TIOCPKT_WINDOW
+#define TIOCPKT_WINDOW 0x80
+#endif
+char   oobdata[] = {TIOCPKT_WINDOW};
+#else
+char    oobdata[] = {0};
+#endif
+
+/*
+ * Handle a "control" request (signaled by magic being present)
+ * in the data stream.  For now, we are only willing to handle
+ * window size changes.
+ */
+control(pty, cp, n)
+     int pty;
+     char *cp;
+     int n;
+{
+    struct winsize w;
+    int pgrp;
+    
+    if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's')
+      return (0);
+#ifdef TIOCSWINSZ
+    oobdata[0] &= ~TIOCPKT_WINDOW;     /* we know he heard */
+    memcpy((char *)&w,cp+4, sizeof(w));
+    w.ws_row = ntohs(w.ws_row);
+    w.ws_col = ntohs(w.ws_col);
+    w.ws_xpixel = ntohs(w.ws_xpixel);
+    w.ws_ypixel = ntohs(w.ws_ypixel);
+    (void)ioctl(pty, TIOCSWINSZ, &w);
+    if (ioctl(pty, TIOCGPGRP, &pgrp) >= 0)
+      (void) killpg(pgrp, SIGWINCH);
+#endif
+    return (4+sizeof (w));
+}
+
+
+
+/*
+ * rlogin "protocol" machine.
+ */
+protocol(f, p)
+     int f, p;
+{
+    char pibuf[1024], fibuf[1024], *pbp, *fbp;
+    register pcc = 0, fcc = 0;
+    int cc;
+    char cntl;
+    
+    /*
+     * Must ignore SIGTTOU, otherwise we'll stop
+     * when we try and set slave pty's window shape
+     * (our controlling tty is the master pty).
+     */
+    signal(SIGTTOU, SIG_IGN);
+#ifdef TIOCSWINSZ
+    send(f, oobdata, 1, MSG_OOB);      /* indicate new rlogin */
+#endif
+    for (;;) {
+       int ibits, obits, ebits;
+       
+       ibits = 0;
+       obits = 0;
+       if (fcc)
+         obits |= (1<<p);
+       else
+         ibits |= (1<<f);
+       if (pcc >= 0)
+         if (pcc)
+           obits |= (1<<f);
+         else
+           ibits |= (1<<p);
+       ebits = (1<<p);
+       if (select(16, &ibits, &obits, &ebits, 0) < 0) {
+           if (errno == EINTR)
+             continue;
+           fatalperror(f, "select");
+       }
+       if (ibits == 0 && obits == 0 && ebits == 0) {
+           /* shouldn't happen... */
+           sleep(5);
+           continue;
+       }
+#define        pkcontrol(c)    ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))
+       if (ebits & (1<<p)) {
+           cc = read(p, &cntl, 1);
+           if (cc == 1 && pkcontrol(cntl)) {
+               cntl |= oobdata[0];
+               send(f, &cntl, 1, MSG_OOB);
+               if (cntl & TIOCPKT_FLUSHWRITE) {
+                   pcc = 0;
+                   ibits &= ~(1<<p);
+               }
+           }
+       }
+       if (ibits & (1<<f)) {
+           fcc = des_read(f, fibuf, sizeof (fibuf));
+           if (fcc < 0 && errno == EWOULDBLOCK)
+             fcc = 0;
+           else {
+               register char *cp;
+               int left, n;
+               
+               if (fcc <= 0)
+                 break;
+               fbp = fibuf;
+               
+             top:
+               for (cp = fibuf; cp < fibuf+fcc-1; cp++)
+                 if (cp[0] == magic[0] &&
+                     cp[1] == magic[1]) {
+                     left = fcc - (cp-fibuf);
+                     n = control(p, cp, left);
+                     if (n) {
+                         left -= n;
+                         if (left > 0)
+                           memcpy(cp,
+                                  cp+n,
+                                  left);
+                         fcc -= n;
+                         goto top; /* n^2 */
+                     }
+                 }
+           }
+       }
+       
+       if ((obits & (1<<p)) && fcc > 0) {
+           cc = write(p, fbp, fcc);
+           if (cc > 0) {
+               fcc -= cc;
+               fbp += cc;
+           }
+       }
+       
+       if (ibits & (1<<p)) {
+           pcc = read(p, pibuf, sizeof (pibuf));
+           pbp = pibuf;
+           if (pcc < 0 && errno == EWOULDBLOCK)
+             pcc = 0;
+           else if (pcc <= 0)
+             break;
+           else if (pibuf[0] == 0)
+             pbp++, pcc--;
+           else {
+               if (pkcontrol(pibuf[0])) {
+                   pibuf[0] |= oobdata[0];
+                   send(f, &pibuf[0], 1, MSG_OOB);
+               }
+               pcc = 0;
+           }
+       }
+       if ((obits & (1<<f)) && pcc > 0) {
+           cc = des_write(f, pbp, pcc);
+           if (cc < 0 && errno == EWOULDBLOCK) {
+               /* also shouldn't happen */
+               sleep(5);
+               continue;
+           }
+           if (cc > 0) {
+               pcc -= cc;
+               pbp += cc;
+           }
+       }
+    }
+}
+
+
+
+int cleanup()
+{
+    char *p;
+    
+    /* 
+      I dont know why P starts with the character '/', but apparently it
+      has to do with the way login set line when the initial entry for this
+      line is made.
+      */
+    p = line + sizeof("/dev/") -1 ;
+    if (!logout(p)) {
+#ifdef SYSV
+       logwtmp(p, "", "", 0, 0);
+#else
+       logwtmp(p, "", "", 0);
+#endif
+    }
+    else 
+      syslog(LOG_ERR ,
+            "Cannot delete entry from utmp for %s\n",p);
+    
+    (void)chmod(line, 0666);
+    (void)chown(line, 0, 0);
+#ifndef STREAMS
+    *p = 'p';
+    (void)chmod(line, 0666);
+    (void)chown(line, 0, 0);
+#endif
+    shutdown(netf, 2);
+    exit(1);
+}
+
+
+void fatal(f, msg)
+     int f;
+     char *msg;
+{
+    char buf[512];
+    int out = 1 ;          /* Output queue of f */
+    
+    buf[0] = '\01';            /* error indicator */
+    (void) sprintf(buf + 1, "%s: %s.\r\n",progname, msg);
+    if ((f == netf) && (pid > 0))
+      (void) des_write(f, buf, strlen(buf));
+    else
+      (void) write(f, buf, strlen(buf));
+    syslog(LOG_ERR,"%s\n",msg);
+    if (pid > 0) {
+       signal(SIGCHLD,SIG_IGN);
+       kill(pid,SIGKILL);
+#ifdef  TIOCFLUSH
+       (void) ioctl(f, TIOCFLUSH, (char *)&out);
+#else
+       (void) ioctl(f, TCFLSH, out);
+#endif
+       cleanup();
+    }
+    exit(1);
+}
+
+
+
+void fatalperror(f, msg)
+     int f;
+     char *msg;
+{
+    char buf[512];
+    extern int sys_nerr;
+    extern char *sys_errlist[];
+    
+    if ((unsigned)errno < sys_nerr)
+      (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]);
+    else
+      (void) sprintf(buf, "%s: Error %d", msg, errno);
+    fatal(f, buf);
+}
+
+#ifdef KERBEROS
+
+
+do_krb_login(host)
+     char *host;
+{
+    int rc;
+    krb5_error_code status;
+    struct sockaddr_in peersin;
+    krb5_address peeraddr;
+    struct passwd *pwd;
+    krb5_principal server;
+    char srv_name[100];
+    char def_host[100];
+    krb5_data inbuf;
+    
+    if (getuid()) {
+       exit(1);
+    }
+    
+    /* we want mutual authentication */
+#ifdef unicos61
+#define SIZEOF_INADDR  SIZEOF_in_addr
+#else
+#define SIZEOF_INADDR sizeof(struct in_addr)
+#endif
+    
+    rc = sizeof(peersin);
+    if (getpeername(netf, (struct sockaddr *)&peersin, &rc)) {
+       syslog(LOG_ERR, "get peer name failed %d", netf);
+       exit(1);
+    }
+    
+    peeraddr.addrtype = peersin.sin_family;
+    peeraddr.length = SIZEOF_INADDR;
+    peeraddr.contents = (krb5_octet *)&peersin.sin_addr;
+    
+    strcpy(srv_name, "host/");
+    gethostname(def_host, 100);
+    strcat(srv_name, def_host);
+    if (status = krb5_parse_name(srv_name, &server)) {
+       syslog(LOG_ERR, "parse server name %s: %s", "host",
+              error_message(status));
+       exit(1);
+    }
+    krb5_princ_type(server) = KRB5_NT_SRV_HST;
+    
+    if (status = krb5_recvauth(&netf, 
+                              "KCMDV0.1",
+                              server,     /* no match on server 
+                                             incase we have are
+                                             serving multiple realms*/
+                              &peeraddr,  /* We do want to match this
+                                             against caddrs in the
+                                             ticket. */
+                              0,               /* use srv5tab */
+                              0,               /* no keyproc */
+                              0,               /* no keyproc arg */
+                              0,               /* no rc_type */
+                              0,               /* no seq number */
+                              &client, /* return client */
+                              &ticket, /* return ticket */
+                              &kdata        /* return authenticator */
+                              )) {
+       syslog(LOG_ERR,
+              "Kerberos authentication failed from %s: %s\n",
+              host,error_message(status));
+       
+       /* Dont exit out for klogin, but
+          grab locuser, terminal, and remuser.
+          */
+       
+       /* These two reads will be used in the next release to obtain
+          a forwarded TGT and related info. */
+       if (status = krb5_read_message((krb5_pointer)&netf, &inbuf))
+         fatal(netf, "Error reading message");
+       if (inbuf.length)
+         fatal(netf, "Forwarding is not yet supported");
+       if (status = krb5_read_message((krb5_pointer)&netf, &inbuf))
+         fatal(netf, "Error reading message");
+       if (inbuf.length)
+         fatal(netf, "Forwarding is not yet supported");
+       
+       getstr(lusername, sizeof(lusername), "locuser");
+       getstr(term, sizeof(term), "Terminal type");
+       rusername = malloc(sizeof (lusername) + 1);
+       getstr(rusername, sizeof(lusername), "remuser");
+       
+       failed_auth = 1;
+       if (ticket)
+         krb5_free_ticket(ticket);
+       return;
+    }
+    
+    /* Setup up eblock if encrypted login session */
+    /* otherwise zero out session key */
+    if (do_encrypt) {
+       krb5_use_keytype(&eblock,
+                        ticket->enc_part2->session->keytype);
+       if (status = krb5_process_key(&eblock,
+                                     ticket->enc_part2->session))
+         fatal(netf, "Permission denied");
+    }
+    
+    /* These two reads will be used in the next release to obtain
+       a forwarded TGT and related info. */
+    if (status = krb5_read_message((krb5_pointer)&netf, &inbuf))
+      fatal(netf, "Error reading message");
+    if (inbuf.length)
+      fatal(netf, "Forwarding is not yet supported");
+    if (status = krb5_read_message((krb5_pointer)&netf, &inbuf))
+      fatal(netf, "Error reading message");
+    if (inbuf.length)
+      fatal(netf, "Forwarding is not yet supported");
+
+    getstr(lusername, sizeof(lusername), "locuser");
+    getstr(term, sizeof(term), "Terminal type");
+    rusername = malloc(sizeof (lusername) + 1);
+    getstr(rusername, sizeof(lusername), "remuser");
+    
+    /* OK we have authenticated this user - now check authorization. */
+    /* We must do this here since we want the same functionality as */
+    /* the MIT version without having to provide the login.krb program.*/
+    
+    /* The Kerberos authenticated programs must use krb5_kuserok */
+    
+    krb5_unparse_name(kdata->client,&krusername);
+    
+    if (must_pass_k5 || must_pass_one) {
+       /* krb5_kuserok returns 1 if OK */
+       rc = !(krb5_kuserok(kdata->client,lusername));
+       
+       if (rc){
+           syslog(LOG_ERR,
+                  "Principal %s (%s@%s) logging in as %s failed krb5_kuserok.\n",
+                  krusername, rusername, host, lusername);
+           if (must_pass_k5)
+             fatal(netf, "Permission denied"); 
+           failed_k5 = 1;
+           if (ticket)
+             krb5_free_ticket(ticket);
+       }
+    }
+    
+    /*  The kerberos authenticated request must pass ruserok also
+       if asked for. */
+    
+    if (must_pass_rhosts || (failed_k5 && must_pass_one)) {
+       pwd = (struct passwd *) getpwnam(lusername);
+       if ((pwd == (struct passwd *) 0) ||
+           (ruserok(rhost_name, pwd->pw_uid == 0, rusername, lusername))) {
+           failed_rhosts = 1;
+           if (ticket)
+             krb5_free_ticket(ticket);
+           
+           if (pwd == (struct passwd *) 0) 
+             syslog(LOG_ERR,
+                    "Principal %s (%s@%s) logging in as %s has no account.\n",
+                    krusername, rusername, rhost_name, lusername);
+           else
+             syslog(LOG_ERR,
+                    "Principal %s (%s@%s) logging in as %s failed ruserok.\n",
+                    krusername, rusername, rhost_name, lusername);
+           
+           if (must_pass_rhosts)
+             fatal(netf, "Permission denied");
+       }
+    }
+    
+    return;
+}
+
+
+
+getstr(buf, cnt, err)
+     char *buf;
+     int cnt;
+     char *err;
+{
+    
+    char c;
+    
+    do {
+       if (read(0, &c, 1) != 1) {
+           exit(1);
+       }
+       if (--cnt < 0) {
+           printf("%s too long\r\n", err);
+           exit(1);
+       }
+       *buf++ = c;
+    } while (c != 0);
+}
+
+
+
+char storage[2*BUFSIZ];                    /* storage for the decryption */
+int nstored = 0;
+char *store_ptr = storage;
+
+
+des_read(fd, buf, len)
+     int fd;
+     register char *buf;
+     int len;
+{
+    int nreturned = 0;
+    long net_len,rd_len;
+    int cc,retry;
+    
+    if (!do_encrypt)
+      return(read(fd, buf, len));
+    
+    if (nstored >= len) {
+       memcpy(buf, store_ptr, len);
+       store_ptr += len;
+       nstored -= len;
+       return(len);
+    } else if (nstored) {
+       memcpy(buf, store_ptr, nstored);
+       nreturned += nstored;
+       buf += nstored;
+       len -= nstored;
+       nstored = 0;
+    }
+    
+#ifdef BITS64
+    rd_len = 0;
+    if ((cc = krb5_net_read(fd, (char *)&rd_len + 4, 4)) != 4) {
+#else  
+    if ((cc = krb5_net_read(fd, (char *)&rd_len, sizeof(rd_len))) !=
+       sizeof(rd_len)) {
+#endif
+       if ((cc < 0)  && (errno == EWOULDBLOCK)) return(cc);
+       /* XXX can't read enough, pipe
+          must have closed */
+       return(0);
+    }
+    rd_len = ntohl(rd_len);
+    net_len = krb5_encrypt_size(rd_len,eblock.crypto_entry);
+    if (net_len < 0 || net_len > sizeof(des_inbuf)) {
+       /* XXX preposterous length, probably out of sync.
+          act as if pipe closed */
+       syslog(LOG_ERR,"Read size problem.");
+       return(0);
+    }
+    retry = 0;
+  datard:
+    if ((cc = krb5_net_read(fd, desinbuf.data, net_len)) != net_len) {
+       /* XXX can't read enough, pipe
+          must have closed */
+       if ((cc < 0)  && (errno == EWOULDBLOCK)) {
+           retry++;
+           sleep(1);
+           if (retry > MAXRETRIES){
+               syslog(LOG_ERR,
+                      "des_read retry count exceeded %d\n",
+                      retry);
+               return(0);
+           }
+           goto datard;
+       }
+       syslog(LOG_ERR,
+              "Read data received %d != expected %d.",
+              cc, net_len);
+       return(0);
+    }
+    /* decrypt info */
+    if ((krb5_decrypt(desinbuf.data,
+                     (krb5_pointer) storage,
+                     net_len,
+                     &eblock, 0))) {
+       syslog(LOG_ERR,"Read decrypt problem.");
+       return(0);
+    }
+    store_ptr = storage;
+    nstored = rd_len;
+    if (nstored > len) {
+       memcpy(buf, store_ptr, len);
+       nreturned += len;
+       store_ptr += len;
+       nstored -= len;
+    } else {
+       memcpy(buf, store_ptr, nstored);
+       nreturned += nstored;
+       nstored = 0;
+    }
+    return(nreturned);
+}
+    
+
+
+des_write(fd, buf, len)
+     int fd;
+     char *buf;
+     int len;
+{
+    long net_len;
+    
+    if (!do_encrypt)
+      return(write(fd, buf, len));
+    
+    
+    desoutbuf.length = krb5_encrypt_size(len,eblock.crypto_entry);
+    if (desoutbuf.length > sizeof(des_outbuf)){
+       syslog(LOG_ERR,"Write size problem.");
+       return(-1);
+    }
+    if ((krb5_encrypt((krb5_pointer)buf,
+                     desoutbuf.data,
+                     len,
+                     &eblock,
+                     0))){
+       syslog(LOG_ERR,"Write encrypt problem.");
+       return(-1);
+    }
+    
+    net_len = htonl(len);      
+#ifdef BITS64
+    (void) write(fd,(char *)&net_len + 4, 4);
+#else
+    (void) write(fd, &net_len, sizeof(net_len));
+#endif
+    if (write(fd, desoutbuf.data,desoutbuf.length) != desoutbuf.length){
+       syslog(LOG_ERR,"Could not write out all data.");
+       return(-1);
+    }
+    else return(len);
+}
+
+#endif /* KERBEROS */
+
+
+
+getpty(fd,slave)
+     int *fd;
+     char *slave;
+{
+    char c;
+    int i,ptynum;
+    struct stat stb;
+#ifdef STREAMS
+#ifdef sysvimp
+    *fd = open("/dev/pty", O_RDWR|O_NDELAY);
+#else
+    *fd = open("/dev/ptc", O_RDWR|O_NDELAY);
+#endif
+    if (*fd >= 0) {
+       if (fstat(*fd, &stb) < 0) {
+           close(*fd);
+           return 1;
+       }
+       ptynum = (int)(stb.st_rdev&0xFF);
+#ifdef sysvimp
+       sprintf(slave, "/dev/ttyp%x", ptynum);
+#else
+       sprintf(slave, "/dev/ttyq%x", ptynum);
+#endif
+    }
+    return (0);
+    
+#else /* NOT STREAMS */
+    for (c = 'p'; c <= 's'; c++) {
+       sprintf(slave,"/dev/ptyXX");
+       slave[strlen("/dev/pty")] = c;
+       slave[strlen("/dev/ptyp")] = '0';
+       if (stat(slave, &stb) < 0)
+         break;
+       for (i = 0; i < 16; i++) {
+           slave[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i];
+           *fd = open(slave, O_RDWR);
+           if (*fd > 0)
+             goto gotpty;
+       }
+    }
+    return(1);
+  gotpty:
+    slave[strlen("/dev/")] = 't';
+    return(0);
+#endif /* STREAMS */
+}
+
+
+
+void usage()
+{
+#ifdef KERBEROS
+    syslog(LOG_ERR, 
+          "usage: klogind [-rRkKxpP] or [r/R][k/K][x/e][p/P]logind");
+#else
+    syslog(LOG_ERR, "usage: rlogind [-rRpP] or [r/R][p/P]logind");
+#endif
+}
+
+
+
+#ifdef KERBEROS
+int princ_maps_to_lname(principal, luser)      
+     krb5_principal principal;
+     char *luser;
+{
+    char kuser[10];
+    if (!(krb5_aname_to_localname(principal,
+                                 sizeof(kuser), kuser))
+       && (strcmp(kuser, luser) == 0)) {
+       return 1;
+    }
+    return 0;
+}
+
+int default_realm(principal)
+     krb5_principal principal;
+{
+    char *def_realm;
+    int realm_length;
+    int retval;
+    
+    realm_length = krb5_princ_realm(principal)->length;
+    
+    if (retval = krb5_get_default_realm(&def_realm)) {
+       return 0;
+    }
+    
+    if ((realm_length != strlen(def_realm)) ||
+       (memcmp(def_realm, krb5_princ_realm(principal)->data, realm_length))) {
+       free(def_realm);
+       return 0;
+    }  
+    free(def_realm);
+    return 1;
+}
+#endif
diff --git a/src/appl/bsd/krsh.c b/src/appl/bsd/krsh.c
new file mode 100644 (file)
index 0000000..57df62a
--- /dev/null
@@ -0,0 +1,416 @@
+/*
+ *     $Source$
+ *     $Header$
+ */
+
+#ifndef lint
+static char *rcsid_rsh_c = 
+  "$Header$";
+#endif /* lint */
+
+/*
+ * Copyright (c) 1983 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+char copyright[] =
+  "@(#) Copyright (c) 1983 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)rsh.c      5.7 (Berkeley) 9/20/88";
+#endif /* not lint */
+
+#define KERBEROS
+     
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+     
+#include <netinet/in.h>
+     
+#include <stdio.h>
+#include <errno.h>
+#include <signal.h>
+#include <pwd.h>
+#include <netdb.h>
+     
+#ifdef KERBEROS
+#include <krb5/krb5.h>
+#include <krb5/asn1.h>
+#include <krb5/crc-32.h>
+#include <krb5/mit-des.h>
+#endif /* KERBEROS */
+     
+     /*
+      * rsh - remote shell
+      */
+
+int    error();
+     
+#ifndef convex
+struct passwd *getpwuid();
+#endif
+
+int    errno;
+int    options;
+int    rfd2;
+int    nflag;
+krb5_sigtype  sendsig();
+
+#ifdef KERBEROS
+char   *krb_realm = (char *)0;
+     void      try_normal();
+#define UCB_RSH "/usr/ucb/rsh"
+#define RLOGIN_PROGRAM "/nfs/kerberos/bin/sun3/rlogin"
+#else /* KERBEROS */
+#define RLOGIN_PROGRAM "/usr/ucb/rlogin"
+#endif  /* KERBEROS */
+     
+#define        mask(s) (1 << ((s) - 1))
+     
+     main(argc, argv0)
+     int argc;
+     char **argv0;
+{
+    int rem, pid;
+    char *host, *cp, **ap, buf[BUFSIZ], *args, **argv = argv0, *user = 0;
+    register int cc;
+    int asrsh = 0;
+    struct passwd *pwd;
+    int readfrom, ready;
+    int one = 1;
+    struct servent *sp;
+    int omask;
+#ifdef KERBEROS
+    krb5_flags authopts;
+    krb5_error_code status;
+#endif  /* KERBEROS */
+    
+    if ( argc < 2 ) goto usage;
+    host = argv[1];
+    argc -= 2;
+    argv +=2;  
+    if (!strcmp(host, "rsh")) {
+       host = *argv++, --argc;
+       asrsh = 1;
+    }
+  another:
+    if (argc > 0 && !strcmp(*argv, "-l")) {
+       argv++, argc--;
+       if (argc > 0)
+         user = *argv++, argc--;
+       goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-n")) {
+       argv++, argc--;
+       nflag++;
+       goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-d")) {
+       argv++, argc--;
+       options |= SO_DEBUG;
+       goto another;
+    }
+#ifdef KERBEROS
+    if (argc > 0 && !strcmp(*argv, "-k")) {
+       argv++, argc--;
+       if (argc == 0) {
+           fprintf(stderr, "rsh(kerberos): -k flag must have a realm after it.\n");
+           exit (1);
+       }
+       if(!(krb_realm = (char *)malloc(strlen(*argv) + 1))){
+           fprintf(stderr, "rsh(kerberos): Cannot malloc.\n");
+           exit(1);
+       }
+       strcpy(krb_realm, *argv);
+       argv++, argc--;
+       goto another;
+    }
+    /*
+     * Ignore -x from kerberos rlogin
+     */
+    if (argc > 0 && !strncmp(*argv, "-x", 2)) {
+       argv++, argc--;
+       goto another;
+    }
+    
+#endif  /* KERBEROS */
+    /*
+     * Ignore the -L, -w, -e and -8 flags to allow aliases with rlogin
+     * to work
+     *
+     * There must be a better way to do this! -jmb
+     */
+    if (argc > 0 && !strncmp(*argv, "-L", 2)) {
+       argv++, argc--;
+       goto another;
+    }
+    if (argc > 0 && !strncmp(*argv, "-w", 2)) {
+       argv++, argc--;
+       goto another;
+    }
+    if (argc > 0 && !strncmp(*argv, "-e", 2)) {
+       argv++, argc--;
+       goto another;
+    }
+    if (argc > 0 && !strncmp(*argv, "-8", 2)) {
+       argv++, argc--;
+       goto another;
+    }
+#ifdef ATHENA
+    /* additional Athena flags to be ignored */
+    if (argc > 0 && !strcmp(*argv, "-noflow")) {       /* No local flow control option for rlogin */
+       argv++, argc--;
+       goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-7")) {
+       argv++, argc--;
+       goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-c")) {
+       argv++, argc--;
+       goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-a")) {
+       argv++, argc--;
+       goto another;
+    }
+    if (argc > 0 && !strcmp(*argv, "-n")) {
+       argv++, argc--;
+       goto another;
+    }
+    /*
+     ** Also ignore -t ttytype
+     */
+    if (argc > 0 && !strcmp(*argv, "-t")) {
+       argv++; argv++; argc--; argc--;
+       goto another;
+    }
+#endif /* ATHENA */
+    if (host == 0)
+      goto usage;
+    if (argv[0] == 0) {
+       if (asrsh)
+         *argv0 = "rlogin";
+       execv(RLOGIN_PROGRAM, argv0);
+       perror(RLOGIN_PROGRAM);
+       exit(1);
+    }
+    pwd = getpwuid(getuid());
+    if (pwd == 0) {
+       fprintf(stderr, "who are you?\n");
+       exit(1);
+    }
+    cc = 0;
+    for (ap = argv; *ap; ap++)
+      cc += strlen(*ap) + 1;
+    cp = args = malloc(cc);
+    for (ap = argv; *ap; ap++) {
+       (void) strcpy(cp, *ap);
+       while (*cp)
+         cp++;
+       if (ap[1])
+         *cp++ = ' ';
+    }
+#ifdef KERBEROS
+    sp = getservbyname("kshell", "tcp");
+#else 
+    sp = getservbyname("shell", "tcp");
+#endif  /* KERBEROS */
+    if (sp == 0) {
+#ifdef KERBEROS
+       fprintf(stderr, "rsh: kshell/tcp: unknown service\n");
+       try_normal(argv0);
+#else 
+       fprintf(stderr, "rsh: shell/tcp: unknown service\n");
+#endif /* KERBEROS */
+       exit(1);
+    }
+#ifdef KERBEROS
+    krb5_init_ets();
+    authopts = AP_OPTS_MUTUAL_REQUIRED;
+    status = kcmd(&rem, &host, sp->s_port,
+                 pwd->pw_name,
+                 user ? user : pwd->pw_name,
+                 args, &rfd2, "host", krb_realm,
+                 0,            /* No need for returned credentials */
+                 0,           /* No need for sequence number */
+                 0,           /* No need for server seq # */
+                 (struct sockaddr_in *) 0,
+                 (struct sockaddr_in *) 0,
+                 authopts);
+    if (status) {
+       fprintf(stderr,
+               "%s: kcmd to host %s failed - %s\n",argv[0], host,
+               error_message(status));
+       try_normal(argv0);
+    }
+#else /* !KERBEROS */
+    rem = rcmd(&host, sp->s_port, pwd->pw_name,
+              user ? user : pwd->pw_name, args, &rfd2);
+    if (rem < 0)
+      exit(1);
+#endif /* KERBEROS */
+    if (rfd2 < 0) {
+       fprintf(stderr, "rsh: can't establish stderr\n");
+       exit(2);
+    }
+    if (options & SO_DEBUG) {
+       if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof (one)) < 0)
+         perror("setsockopt (stdin)");
+       if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one, sizeof (one)) < 0)
+         perror("setsockopt (stderr)");
+    }
+    (void) setuid(getuid());
+#ifdef sgi
+    omask = sigignore(mask(SIGINT)|mask(SIGQUIT)|mask(SIGTERM));
+#else
+    omask = sigblock(mask(SIGINT)|mask(SIGQUIT)|mask(SIGTERM));
+#endif
+    if (signal(SIGINT, SIG_IGN) != SIG_IGN)
+      signal(SIGINT, sendsig);
+    if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
+      signal(SIGQUIT, sendsig);
+    if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
+      signal(SIGTERM, sendsig);
+    if (nflag == 0) {
+       pid = fork();
+       if (pid < 0) {
+           perror("fork");
+           exit(1);
+       }
+    }
+    ioctl(rfd2, FIONBIO, &one);
+    ioctl(rem, FIONBIO, &one);
+    if (nflag == 0 && pid == 0) {
+       char *bp; int rembits, wc;
+       (void) close(rfd2);
+      reread:
+       errno = 0;
+       cc = read(0, buf, sizeof buf);
+       if (cc <= 0)
+         goto done;
+       bp = buf;
+      rewrite:
+       rembits = 1<<rem;
+       if (select(16, 0, &rembits, 0, 0) < 0) {
+           if (errno != EINTR) {
+               perror("select");
+               exit(1);
+           }
+           goto rewrite;
+       }
+       if ((rembits & (1<<rem)) == 0)
+         goto rewrite;
+       wc = write(rem, bp, cc);
+       if (wc < 0) {
+           if (errno == EWOULDBLOCK)
+             goto rewrite;
+           goto done;
+       }
+       cc -= wc; bp += wc;
+       if (cc == 0)
+         goto reread;
+       goto rewrite;
+      done:
+       (void) shutdown(rem, 1);
+       exit(0);
+    }
+#ifndef sgi
+    sigsetmask(omask);
+#endif
+    readfrom = (1<<rfd2) | (1<<rem);
+    do {
+       ready = readfrom;
+       if (select(16, &ready, 0, 0, 0) < 0) {
+           if (errno != EINTR) {
+               perror("select");
+               exit(1);
+           }
+           continue;
+       }
+       if (ready & (1<<rfd2)) {
+           errno = 0;
+           cc = read(rfd2, buf, sizeof buf);
+           if (cc <= 0) {
+               if (errno != EWOULDBLOCK)
+                 readfrom &= ~(1<<rfd2);
+           } else
+             (void) write(2, buf, cc);
+       }
+       if (ready & (1<<rem)) {
+           errno = 0;
+           cc = read(rem, buf, sizeof buf);
+           if (cc <= 0) {
+               if (errno != EWOULDBLOCK)
+                 readfrom &= ~(1<<rem);
+           } else
+             (void) write(1, buf, cc);
+       }
+    } while (readfrom);
+    if (nflag == 0)
+      (void) kill(pid, SIGKILL);
+    exit(0);
+  usage:
+    fprintf(stderr,
+           "usage: rsh host [ -l login ] [ -n ] command\n");
+    exit(1);
+}
+
+
+
+krb5_sigtype sendsig(signo)
+     char signo;
+{
+    
+    (void) write(rfd2, &signo, 1);
+}
+
+
+
+#ifdef KERBEROS
+void try_normal(argv)
+     char **argv;
+{
+    char *host;
+    
+    /*
+     * if we were invoked as 'rsh host mumble', strip off the rsh
+     * from arglist.
+     *
+     * We always want to call the Berkeley rsh as 'host mumble'
+     */
+    
+    host = rindex(argv[0], '/');
+    if (host)
+      host++;
+    else
+      host = argv[0];
+    
+    if (!strcmp(host, "rsh"))
+      argv++;
+    
+    fprintf(stderr,"trying normal rsh (%s)\n",
+           UCB_RSH);
+    fflush(stderr);
+    execv(UCB_RSH, argv);
+    perror("exec");
+    exit(1);
+}
+#endif /* KERBEROS */
diff --git a/src/appl/bsd/krshd.M b/src/appl/bsd/krshd.M
new file mode 100644 (file)
index 0000000..e02480d
--- /dev/null
@@ -0,0 +1,164 @@
+.\" Copyright (c) 1983 Regents of the University of California.
+.\" All rights reserved.  The Berkeley software License Agreement
+.\" specifies the terms and conditions for redistribution.
+.\"
+.\"    @(#)rshd.8c     6.3 (Berkeley) 5/24/86
+.\"
+.TH RSHD 8C "May 24, 1986"
+.UC 5
+.SH NAME
+rshd \- remote shell server
+.SH SYNOPSIS
+.B /usr/etc/rshd
+.SH DESCRIPTION
+.I Rshd
+is the server for the 
+.IR rcmd (3X)
+routine and, consequently, for the
+.IR rsh (1C)
+program.  The server provides remote execution facilities
+with authentication based on privileged port numbers from trusted hosts.
+.PP
+.I Rshd
+listens for service requests at the port indicated in
+the ``cmd'' service specification; see
+.IR services (5).
+When a service request is received the following protocol
+is initiated:
+.IP 1)
+The server checks the client's source port.
+If the port is not in the range 0-1023, the server
+aborts the connection.
+.IP 2)
+The server reads characters from the socket up
+to a null (`\e0') byte.  The resultant string is
+interpreted as an ASCII number, base 10.
+.IP 3)
+If the number received in step 1 is non-zero,
+it is interpreted as the port number of a secondary
+stream to be used for the 
+.BR stderr .
+A second connection is then created to the specified
+port on the client's machine.  The source port of this
+second connection is also in the range 0-1023.
+.IP 4)
+The server checks the client's source address
+and requests the corresponding host name (see
+.IR gethostbyaddr (3N),
+.IR hosts (5)
+and
+.IR named (8)).
+If the hostname cannot be determined,
+the dot-notation representation of the host address is used.
+.IP 5)
+A null terminated user name of at most 16 characters
+is retrieved on the initial socket.  This user name
+is interpreted as the user identity on the
+.BR client 's
+machine.
+.IP 6)
+A null terminated user name of at most 16 characters
+is retrieved on the initial socket.  This user name
+is interpreted as a user identity to use on the
+.BR server 's
+machine.
+.IP 7)
+A null terminated command to be passed to a
+shell is retrieved on the initial socket.  The length of
+the command is limited by the upper bound on the size of
+the system's argument list.  
+.IP 8)
+.I Rshd
+then validates the user according to the following steps.
+The local (server-end) user name is looked up in the password file
+and a
+.I chdir
+is performed to the user's home directory.  If either
+the lookup or 
+.I chdir
+fail, the connection is terminated.
+If the user is not the super-user, (user id 0), the file 
+.I /etc/hosts.equiv
+is consulted for a list of hosts considered ``equivalent''.
+If the client's host name is present in this file, the
+authentication is considered successful.  If the lookup
+fails, or the user is the super-user, then the file
+.I .rhosts
+in the home directory of the remote user is checked for
+the machine name and identity of the user on the client's
+machine.  If this lookup fails, the connection is terminated.
+.IP 9)
+A null byte is returned on the initial socket
+and the command line is passed to the normal login
+shell of the user.  The
+shell inherits the network connections established
+by
+.IR rshd .
+.SH DIAGNOSTICS
+Except for the last one listed below,
+all diagnostic messages
+are returned on the initial socket,
+after which any network connections are closed.
+An error is indicated by a leading byte with a value of
+1 (0 is returned in step 9 above upon successful completion
+of all the steps prior to the execution of the login shell).
+.PP
+.B ``locuser too long''
+.br
+The name of the user on the client's machine is
+longer than 16 characters.
+.PP
+.B ``remuser too long''
+.br
+The name of the user on the remote machine is
+longer than 16 characters.
+.PP
+.B ``command too long ''
+.br
+The command line passed exceeds the size of the argument
+list (as configured into the system).
+.PP
+.B ``Login incorrect.''
+.br
+No password file entry for the user name existed.
+.PP
+.B ``No remote directory.''
+.br
+The 
+.I chdir
+command to the home directory failed.
+.PP
+.B ``Permission denied.''
+.br
+The authentication procedure described above failed.
+.PP
+.B ``Can't make pipe.''
+.br
+The pipe needed for the 
+.BR stderr ,
+wasn't created.
+.PP
+.B ``Try again.''
+.br
+A
+.I fork
+by the server failed.
+.PP
+.B ``<shellname>: ...''
+.br
+The user's login shell could not be started.  This message is returned
+on the connection associated with the
+.BR stderr ,
+and is not preceded by a flag byte.
+.SH SEE ALSO
+rsh(1C),
+rcmd(3X)
+.SH BUGS
+The authentication procedure used here assumes the integrity
+of each client machine and the connecting medium.  This is
+insecure, but is useful in an ``open'' environment.
+.PP
+A facility to allow all data exchanges to be encrypted should be
+present.
+.PP
+A more extensible protocol should be used.
diff --git a/src/appl/bsd/krshd.c b/src/appl/bsd/krshd.c
new file mode 100644 (file)
index 0000000..0654d54
--- /dev/null
@@ -0,0 +1,1340 @@
+/*
+ *     $Author$
+ *     $Header$
+ */
+
+#ifndef lint
+static char rcsid_rshd_c[] =
+  "$Header$";
+#endif /* lint */
+
+/*
+ * Copyright (c) 1983 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+char copyright[] =
+  "@(#) Copyright (c) 1983 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)rshd.c     5.12 (Berkeley) 9/12/88";
+#endif /* not lint */
+
+#define KERBEROS
+     
+     /*
+      * remote shell server:
+      *        remuser\0
+      *        locuser\0
+      *        command\0
+      *        data
+      */
+     
+     /*
+      * This is the rshell daemon. The very basic protocol for checking 
+      * authentication and authorization is:
+      * 1) Check authentication.
+      * 2) Check authorization via the access-control files: 
+      *    ~/.k5login (using krb5_kuserok) and/or
+      *    ~/.rhosts  (using ruserok).
+      * Execute command if configured authoriztion checks pass, else deny 
+      * permission.
+      *
+      * The configuration is done either by command-line arguments passed by inetd, 
+      * or by the name of the daemon. If command-line arguments are present, they 
+      * take priority. The options are:
+      * -k and -K means check .k5login (using krb5_kuserok).
+      * -r and -R means check .rhosts  (using ruserok).
+      * The difference between upper and lower case is as follows:
+      *    If lower case -r or -k, then as long as one of krb5_kuserok or ruserok 
+      * passes, allow access. If both fail, no access. The program does not fall
+      * back on password verification.
+      *    If uppercase -R or -K, then those checks must be passed, regardless of 
+      * other checks, else no access.
+      * 
+      *     If no command-line arguments are present, then the presence of the 
+      * letters kKrR in the program-name before "shd" determine the 
+      * behaviour of the program exactly as with the command-line arguments.
+      */
+     
+     /* DEFINES:
+      *   KERBEROS - Define this if application is to be kerberised.
+      *   LOG_ALL_LOGINS - Define this if you want to log all logins.
+      *   LOG_OTHER_USERS - Define this if you want to log all principals that do
+      *              not map onto the local user.
+      *   LOG_REMOTE_REALM - Define this if you want to log all principals from 
+      *              remote realms.
+      *   LOG_CMD - Define this if you want to log not only the user but also the
+      *             command executed. This only decides the type of information
+      *             logged. Whether or not to log is still decided by the above 
+      *             three DEFINES.
+      *       Note:  Root account access is always logged.
+      */
+     
+#define LOG_REMOTE_REALM
+#define LOG_CMD
+     
+#include <sys/ioctl.h>
+#include <sys/param.h>
+     
+#if defined(CRAY) || defined(sysvimp) || defined(aux20)
+#include <sys/types.h>
+#ifndef _TYPES_
+#define _TYPES_
+#endif
+#ifndef  F_OK
+#define F_OK 0
+#endif
+#endif
+     
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+     
+#include <netinet/in.h>
+     
+#ifndef SYSV
+#include <arpa/inet.h>
+#endif
+     
+#include <stdio.h>
+#include <errno.h>
+#include <pwd.h>
+     
+#ifdef sun
+#include <sys/label.h>
+#include <sys/audit.h>
+#include <pwdadj.h>
+#endif
+     
+#include <signal.h>
+#include <netdb.h>
+     
+#ifdef CRAY
+#ifndef NO_UDB
+#include <udb.h>
+#endif  /* !NO_UDB */
+#include <sys/category.h>
+#include <netinet/ip.h>
+#include <sys/tfm.h>
+#include <sys/nal.h>
+#include <sys/secparm.h>
+#include <sys/usrv.h>
+#include <sys/utsname.h>
+#include <sys/sysv.h>
+#include <sys/slrec.h>
+#include <sys/unistd.h>
+#include <path.h>
+#endif /* CRAY */
+     
+#include <syslog.h>
+     
+#ifdef KERBEROS
+#include <krb5/krb5.h>
+#include <krb5/asn1.h>
+#include <krb5/crc-32.h>
+#include <krb5/mit-des.h>
+
+#include <com_err.h>
+
+#define ARGSTR "rRkK?"
+#else /* !KERBEROS */
+#define ARGSTR "rR?"
+     
+char *strsave();
+#endif /* KERBEROS */
+     
+int must_pass_rhosts = 0, must_pass_krb = 0, must_pass_one = 0;
+int failed_krb = 0;
+char *progname;
+
+#define MAX_PROG_NAME 10
+
+#ifdef CRAY
+int     secflag;
+extern
+#endif /* CRAY */
+int     errno;
+
+char   *index(), *rindex(), *strncat();
+/*VARARGS1*/
+int    error();
+
+
+
+main(argc, argv)
+     int argc;
+     char **argv;
+{
+#if defined(BSD) && BSD >= 43
+    struct linger linger;
+#endif
+    int on = 1, fromlen;
+    struct sockaddr_in from;
+    extern int opterr, optind;
+    extern char *optarg;
+    char *options, ch;
+    int i;
+    
+#ifdef CRAY
+    secflag = sysconf(_SC_CRAY_SECURE_SYS);
+#endif
+    
+    progname = *argv;
+    
+#ifndef LOG_ODELAY /* 4.2 syslog */
+    openlog(progname, LOG_PID);
+#else
+#ifndef LOG_DAEMON
+#define LOG_DAEMON 0
+#endif
+    openlog(progname, LOG_PID | LOG_ODELAY, LOG_DAEMON);       
+#endif /* 4.2 syslog */
+    
+    if (argc == 1) { /* Get parameters from program name. */
+       if (strlen(progname) > MAX_PROG_NAME) {
+           usage();
+           exit(1);
+       }
+       options = (char *) malloc(MAX_PROG_NAME+1);
+       options[0] = '\0';
+       for (i = 0; (progname[i] != '\0') && (i < MAX_PROG_NAME); i++)
+         if (!strcmp(progname+i, "shd")) {
+             strcpy(options, "-");
+             strncat(options, progname, i);
+             argc = 2;
+             argv[1] = options;
+             argv[2] = NULL;
+             break;
+         }
+       if (options[0] == '\0') {
+           usage();
+           exit(1);
+       }
+    }
+    
+    /* Analyse parameters. */
+    opterr = 0;
+    while ((ch = getopt(argc, argv, ARGSTR)) != EOF)
+      switch (ch) {
+       case 'r':         
+         must_pass_one = 1; /* If just 'r', any one check must succeed */
+         break;
+       case 'R':         /* If 'R', must pass .rhosts check*/
+         must_pass_rhosts = 1;
+         if (must_pass_one)
+           must_pass_one = 0;
+         break;
+#ifdef KERBEROS
+       case 'k':
+         must_pass_one = 1; /* If just 'k', any one check must succeed */
+         break;
+       case 'K':         /* If 'K', must pass .k5login check*/
+         must_pass_krb = 1;
+         if (must_pass_one)
+           must_pass_one = 0;
+         break;
+#endif
+       case '?':
+       default:
+         usage();
+         exit(1);
+         break;
+      }
+    argc -= optind;
+    argv += optind;
+    
+    fromlen = sizeof (from);
+    if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
+       fprintf(stderr, "%s: ", progname);
+       perror("getpeername");
+       _exit(1);
+    }
+    if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
+                  sizeof (on)) < 0)
+      syslog(LOG_WARNING,
+            "setsockopt (SO_KEEPALIVE): %m");
+#if defined(BSD) && BSD >= 43
+    linger.l_onoff = 1;
+    linger.l_linger = 60;                      /* XXX */
+    if (setsockopt(0, SOL_SOCKET, SO_LINGER, (char *)&linger,
+                  sizeof (linger)) < 0)
+      syslog(LOG_WARNING , "setsockopt (SO_LINGER): %m");
+#endif
+    doit(dup(0), &from);
+}
+
+#ifdef CRAY
+char    username[32] = "LOGNAME=";
+#include <tmpdir.h>
+char tmpdir[64] = "TMPDIR=";
+#else
+char   username[20] = "USER=";
+#endif
+
+char   homedir[64] = "HOME=";
+char   shell[64] = "SHELL=";
+char    term[64] = "TERM=network";
+
+#ifdef KERBEROS
+char    *envinit[] =
+#ifdef CRAY
+{homedir, shell, PATH, username, "TZ=GMT0", tmpdir, term, 0};
+#define TZENV   4
+#define TMPDIRENV 5
+char    *getenv();
+extern
+#else
+{homedir, shell, "PATH=:/usr/ucb:/bin:/usr/bin:/usr/bin/kerberos",
+   username, term, 0};
+#endif /* CRAY */
+#else /* !KERBEROS */
+char   *envinit[] =
+#ifdef CRAY
+{homedir, shell, PATH, username, "TZ=GMT0", tmpdir, term, 0};
+#define TZENV   4
+#define TMPDIRENV 5
+char    *getenv();
+extern
+#else
+{homedir, shell, "PATH=:/usr/ucb:/bin:/usr/bin:/usr/bin/kerberos",
+   username, term, 0};
+#endif /* CRAY */
+#endif /* KERBEROS */
+
+char   **environ;
+char ttyn[12];         /* Line string for wtmp entries */
+
+#if defined (alliant) /* Alliant compiler complains of too many 
+                        local variables*/
+char cmdbuf[NCARGS+1];
+#endif
+
+#ifdef CRAY
+#define SIZEOF_INADDR  SIZEOF_in_addr
+int maxlogs;
+#else
+#define SIZEOF_INADDR sizeof(struct in_addr)
+#endif
+
+#define NMAX   16 
+
+int pid;
+char locuser[NMAX+1];
+
+
+
+doit(f, fromp)
+     int f;
+     struct sockaddr_in *fromp;
+{
+#if defined (alliant)
+    char *cp;
+#else
+    char cmdbuf[NCARGS+1], *cp;
+#endif
+    
+#ifdef KERBEROS
+    char *kremuser;
+    char  *remuser;
+    krb5_authenticator      *kdata;
+    krb5_ticket     *ticket = 0;
+    krb5_address peeraddr;
+    krb5_principal client;
+    krb5_error_code status;
+#else
+    char  remuser[NMAX +1];
+#endif
+    int tmpint;
+    
+    int ioctlval, cnt;
+    char *salt, *ttynm, *tty;
+    register char *p;
+    char *crypt();
+    
+#ifndef CRAY
+    struct passwd *pwd;
+#else
+    struct passwd *pwd;
+#ifndef NO_UDB
+    struct udb    *ue;
+    struct udb ue_static;
+    extern struct udb *getudbnam();
+#endif
+    extern struct passwd *getpwnam(), *getpwuid();
+    static int      jid;
+    int error();
+    int paddr;
+    struct  nal nal;
+    int     nal_error;
+    struct usrv usrv;
+    struct  sysv sysv;
+    char    *makejtmp(), *jtmpnam = 0;
+    int packet_level;               /* Packet classification level */
+    long packet_compart;            /* Packet compartments */
+#endif  /* CRAY */
+    
+    int s;
+    struct hostent *hp;
+    char *hostname;
+    short port;
+    int pv[2], cc;
+    long ready, readfrom;
+    char buf[BUFSIZ], sig;
+    int one = 1;
+    krb5_sigtype     cleanup();
+    int fd;
+    
+    krb5_principal server;
+    char srv_name[100];
+    char def_host[100];
+    krb5_data inbuf;
+#ifdef IP_TOS
+    struct tosent *tp;
+    if ((tp = gettosbyname("interactive", "tcp")) &&
+       (setsockopt(f, IPPROTO_IP, IP_TOS, &tp->t_tos, sizeof(int)) < 0))
+#ifdef  TOS_WARN
+      syslog(LOG_NOTICE, "setsockopt (IP_TOS): %m");
+#else
+    ;       /* silently ignore TOS errors in 6E */
+#endif
+#endif /* IP_TOS */
+    
+    signal(SIGINT, SIG_DFL);
+    signal(SIGQUIT, SIG_DFL);
+    signal(SIGTERM, SIG_DFL);
+#ifdef DEBUG
+    { int t = open("/dev/tty", 2);
+      if (t >= 0) {
+         ioctl(t, TIOCNOTTY, (char *)0);
+         (void) close(t);
+      }
+  }
+#endif
+    fromp->sin_port = ntohs((u_short)fromp->sin_port);
+    if (fromp->sin_family != AF_INET) {
+       syslog(LOG_ERR , "malformed from address\n");
+       exit(1);
+    }
+#ifdef KERBEROS
+    if ((must_pass_rhosts || must_pass_one)
+       && (fromp->sin_port >= IPPORT_RESERVED ||
+           fromp->sin_port < IPPORT_RESERVED/2)) {
+#else
+    if (fromp->sin_port >= IPPORT_RESERVED ||
+           fromp->sin_port < IPPORT_RESERVED/2) {
+#endif /* KERBEROS */
+       syslog(LOG_NOTICE , "connection from bad port\n");
+       exit(1);
+    }
+    
+#ifdef CRAY
+    
+    /* If this is a secure system then get the packet classification
+       of f.  ( Note IP_SECURITY is checked in get_packet_classification:
+       if it's not set then the user's (root) default
+       classification level and compartments are returned. )
+       Then set this process to that level/compart so that the stderr
+       connection will be labeled appropriately.
+       */
+    if (secflag) {
+       if (get_packet_classification(f,getuid(),
+                                     &packet_level,&packet_compart) < 0) {
+           syslog(LOG_ERR, "cannot get ip packet level\n");
+           exit(1);
+       }
+       if(secflag == TFM_UDB_5) {
+           if(setucmp(packet_compart, C_PROC) != 0) {
+               error("Unable to setucmp.\n");
+               exit(1);
+           }
+       } else if(secflag == TFM_UDB_6) {
+           if(setulvl(packet_level,C_PROC) != 0) {
+               error("Unable to setulvl.\n");
+               exit(1);
+           }
+           if(setucmp(packet_compart, C_PROC) != 0) {
+               error("Unable to setucmp.\n");
+               exit(1);
+           }
+       }
+       
+    }
+#endif /* CRAY */
+    
+    (void) alarm(60);
+    port = 0;
+    for (;;) {
+       char c;
+       if ((cc = read(f, &c, 1)) != 1) {
+           if (cc < 0)
+             syslog(LOG_NOTICE , "read: %m");
+           shutdown(f, 1+1);
+           exit(1);
+       }
+       if (c == 0)
+         break;
+       port = port * 10 + c - '0';
+    }
+    (void) alarm(0);
+    if (port != 0) {
+       int lport = IPPORT_RESERVED - 1;
+       s = rresvport(&lport);
+       if (s < 0) {
+           syslog(LOG_ERR ,
+                  "can't get stderr port: %m");
+           exit(1);
+       }
+#ifdef KERBEROS
+       if ((must_pass_rhosts || must_pass_one)
+           && port >= IPPORT_RESERVED) {
+#else
+       if (port >= IPPORT_RESERVED) {
+#endif /* KERBEROS */
+           syslog(LOG_ERR , "2nd port not reserved\n");
+           exit(1);
+       }
+       fromp->sin_port = htons((u_short)port);
+       if (connect(s, (struct sockaddr *)fromp, sizeof (*fromp)) < 0) {
+           syslog(LOG_INFO ,
+                  "connect second port: %m");
+           exit(1);
+       }
+    }
+    dup2(f, 0);
+    dup2(f, 1);
+    dup2(f, 2);
+    hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof (struct in_addr),
+                      fromp->sin_family);
+    if (hp){
+       hostname = malloc(strlen(hp->h_name) + 1);
+       strcpy(hostname,hp->h_name);
+    }
+    else {
+       hostname = malloc(strlen((char *)inet_ntoa(fromp->sin_addr)) + 1);
+       strcpy(hostname,(char *)inet_ntoa(fromp->sin_addr));
+    }
+#ifdef KERBEROS
+    if (must_pass_krb || must_pass_one) {
+       peeraddr.addrtype = fromp->sin_family;
+       peeraddr.length = SIZEOF_INADDR;
+       peeraddr.contents = (krb5_octet *)&fromp->sin_addr;
+       strcpy(srv_name, "host/");
+       
+       gethostname(def_host, 100);
+       strcat(srv_name, def_host);
+       if (status = krb5_parse_name(srv_name, &server)) {
+           syslog(LOG_ERR, "parse server name %s: %s", "host",
+                  error_message(status));
+           exit(1);
+       }
+       krb5_princ_type(server) = KRB5_NT_SRV_HST;
+       krb5_init_ets();
+       
+       if (status = krb5_recvauth(&f,
+                                  "KCMDV0.1",
+                                  server,
+                                  &peeraddr, /* We do want to match this
+                                                against caddrs in the
+                                                ticket. */
+                                  0,         /* use srv5tab */
+                                  0,         /* no keyproc */
+                                  0,         /* no keyproc arg */
+                                  0,         /* no rc_type */
+                                  0,         /* no seq number */
+                                  &client,   /* return client */
+                                  &ticket,   /* return ticket */
+                                  &kdata     /* return authenticator */
+                                  )) {
+           error("Kerberos rsh or rcp failed: %s\n",
+                 error_message(status));
+           exit(1);
+       }
+       krb5_unparse_name(kdata->client,&kremuser);
+    } else {
+       if (!(remuser = malloc(sizeof(locuser) + 1))){
+           error("Error no memory\n");
+           exit(1);
+       }
+       getstr(remuser, sizeof(locuser), "remuser");
+    }
+
+    /* These two reads will be used in the next release to obtain
+       a forwarded TGT and related info for the rlogin daemon.
+       Put here for compatibility, because both rsh and rlogin 
+       use the same kcmd which sends this out regardless.*/
+    if (status = krb5_read_message((krb5_pointer)&f, &inbuf)) {
+       error("Error reading message");
+       exit(1);
+    }
+    if (inbuf.length) {
+       error("Forwarding is not yet supported");
+       exit(1);
+    }
+    if (status = krb5_read_message((krb5_pointer)&f, &inbuf)) {
+       error("Error reading message");
+       exit(1);
+    }
+    if (inbuf.length) {
+       error("Forwarding is not yet supported");
+       exit(1);
+    }
+       
+#else
+    getstr(remuser, sizeof(remuser), "remuser");
+#endif /* KERBEROS */
+    getstr(locuser, sizeof(locuser), "locuser");
+    getstr(cmdbuf, sizeof(cmdbuf), "command");
+    
+#ifdef KERBEROS
+    if (!(remuser = malloc(sizeof(locuser) + 1))){
+       error("Error no memory\n");
+       exit(1);
+    }
+    getstr(remuser, sizeof(locuser), "remuser");
+#endif
+    
+#ifdef CRAY
+    paddr = inet_addr(inet_ntoa(fromp->sin_addr));
+    if(secflag){
+       /*
+        *      check network authorization list
+        */
+       if (fetchnal(paddr,&nal) < 0) {
+           /*
+            *      NAL file inaccessible, abort connection.
+            */
+           error("Permission denied.\n");
+           exit(1);
+       }
+    }
+#endif /* CRAY */
+    
+    pwd = getpwnam(locuser);
+    if (pwd == (struct passwd *) 0 ) {
+       syslog(LOG_ERR ,
+              "Principal %s (%s@%s) for local user %s has no account.\n",
+              kremuser, remuser, hostname, locuser);
+       error("Login incorrect.\n");
+       exit(1);
+    }
+    
+#ifdef CRAY
+    /* Setup job entry, and validate udb entry. 
+       ( against packet level also ) */
+    if ((jid = setjob(pwd->pw_uid, 0)) < 0) {
+       error("Unable to create new job.\n");
+       exit(1);
+    }
+    if ((jtmpnam = makejtmp(pwd->pw_uid, pwd->pw_gid, jid))) {
+       register int pid, tpid;
+       int status;
+       switch(pid = fork()) {
+         case -1:
+           cleanjtmp(locuser, jtmpnam);
+           envinit[TMPDIRENV] = 0;
+           break;
+         case 0:
+           break;
+         default:
+           close(0);
+           close(1);
+           close(2);
+           close(f);
+           if (port)
+             close(s);
+           while ((tpid = wait(&status)) != pid) {
+               if (tpid < 0)
+                 break;
+           }
+           cleanjtmp(locuser, jtmpnam);
+           exit(status>>8);
+           /* NOTREACHED */
+       }
+    } else {
+       envinit[TMPDIRENV] = 0;
+    }
+#ifndef NO_UDB
+    (void)getsysudb();
+    
+    if ((ue = getudbnam(pwd->pw_name)) == (struct udb *)NULL) {
+       error("Unable to fetch account id.\n");
+       exit(1);
+    }
+    ue_static = *ue;                /* save from setlimits call */
+    endudb();
+    if (secflag) {
+       if(getsysv(&sysv, sizeof(struct sysv)) != 0) {
+           loglogin(hostname, SLG_LLERR, 0, ue);
+           error("Permission denied.\n");
+           exit(1);
+       }
+       if ((packet_level != ue->ue_deflvl) ||
+           ((packet_compart & ue->ue_comparts) != packet_compart )){
+           loglogin(hostname, SLG_LLERR, 0, ue);
+           error("Permission denied.\n");
+           exit(1);
+       }
+       if (ue->ue_disabled != 0) {
+           loglogin(hostname,SLG_LOCK,ue->ue_logfails,ue);
+           error("Permission denied.\n");
+           exit(1);
+       }
+       maxlogs = sysv.sy_maxlogs;
+    }
+    if (acctid(getpid(), ue->ue_acids[0]) == -1) {
+       error("Unable to set account id.\n");
+       exit(1);
+    }
+    if (setshares(pwd->pw_uid, acctid(0, -1), error, 1, 0)) {
+       error("Unable to set shares.\n");
+       exit(1);
+    }
+    if (setlimits(pwd->pw_name, C_PROC, getpid(), UDBRC_INTER)) {
+       error("Unable to set limits.\n");
+       exit(1);
+    }
+    if (setlimits(pwd->pw_name, C_JOB, jid, UDBRC_INTER)) {
+       error("Unable to set limits.\n");
+       exit(1);
+    }
+    ue = &ue_static;                /* restore after setlimits call */
+    endudb();                  /* setlimits opens udb and leaves it
+                                  open so close it here. */
+#endif  /* !NO_UDB */
+#endif /*CRAY*/
+    
+    /* Setup wtmp entry : we do it here so that if this is a CRAY
+       the Process Id is correct and we have not lost our trusted
+       privileges. */
+    if (port) {
+       /* Place entry into wtmp */
+       sprintf(ttyn,"krsh%1d",getpid());
+#ifdef SYSV
+       logwtmp(ttyn,locuser,hostname,1,1); /*Leave wtmp open*/
+#else
+       logwtmp(ttyn,locuser,hostname,1);  /*Leave wtmp open*/
+#endif
+    }
+    /*      We are simply execing a program over rshd : log entry into wtmp,
+           as kexe(pid), then finish out the session right after that.
+           Syslog should have the information as to what was exec'd */
+    else {
+       sprintf(ttyn,"kexe%1d",getpid());
+#ifdef SYSV
+       logwtmp(ttyn,locuser,hostname,1,1);  /* Leave open wtmp */
+#else
+       logwtmp(ttyn,locuser,hostname,1);       /* Leave open wtmp */
+#endif
+    }
+    
+#ifdef CRAY
+    
+    /* If  we are a secure system then we need to get rid of our
+       trusted facility, so that MAC on the chdir we work. Before we
+       do this make an entry into wtmp, and any other audit recording. */
+    
+    if (secflag) {
+       if (getusrv(&usrv)){
+           syslog(LOG_ERR,"Cannot getusrv");
+           error("Permission denied.\n");
+           loglogin(hostname, SLG_LVERR, ue->ue_logfails,ue);
+           goto signout_please;
+       }
+       /*
+        *      6.0 no longer allows any form ofTRUSTED_PROCESS logins.
+        */
+       if((ue->ue_valcat & TFM_TRUSTED) ||
+          (sysv.sy_oldtfm &&
+           ((ue->ue_comparts & TRUSTED_SUBJECT) == TRUSTED_SUBJECT))) {
+           loglogin(hostname, SLG_TRSUB, ue->ue_logfails,ue);
+           error("Permission denied.\n");
+           goto signout_please;
+       }
+       
+       loglogin(hostname, SLG_OKLOG, ue->ue_logfails,ue);
+       
+       /*      Setup usrv structure with user udb info and 
+               packet_level and packet_compart. */
+       usrv.sv_actlvl = packet_level;
+       usrv.sv_actcmp = packet_compart; /*Note get_packet_level sets
+                                          compartment to users default
+                                          compartments....*/
+       usrv.sv_permit = ue->ue_permits;
+       usrv.sv_intcls = ue->ue_intcls;
+       usrv.sv_maxcls = ue->ue_maxcls;
+       usrv.sv_intcat = ue->ue_intcat;
+       usrv.sv_valcat = ue->ue_valcat;
+       usrv.sv_savcmp = 0;
+       usrv.sv_savlvl = 0;
+       
+       /*
+        *      Set user values to workstation boundaries
+        */
+#ifdef MIN
+#undef MIN
+#endif
+#ifdef MAX
+#undef MAX
+#endif
+       
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+       
+       nal_error = 0;
+       
+       if (nal.na_sort) {
+           if ((ue->ue_minlvl > nal.na_smax) ||
+               (ue->ue_maxlvl < nal.na_smin))
+             nal_error++;
+           else {
+               usrv.sv_minlvl=MAX(ue->ue_minlvl, nal.na_smin);
+               usrv.sv_maxlvl=MIN(ue->ue_maxlvl, nal.na_smax);
+               
+#ifndef IP_SECURITY
+
+               if (usrv.sv_actlvl < usrv.sv_minlvl)
+                   usrv.sv_actlvl = usrv.sv_minlvl;
+               if (usrv.sv_actlvl > usrv.sv_maxlvl)
+                 usrv.sv_actlvl = usrv.sv_maxlvl;
+               
+#else /*IP_SECURITY*/
+               if (usrv.sv_actlvl < usrv.sv_minlvl)
+                 nal_error++;
+               if (usrv.sv_actlvl > usrv.sv_maxlvl)
+                 nal_error++;
+               if (usrv.sv_actlvl != ue->ue_deflvl)
+                 nal_error++;
+               
+               usrv.sv_valcmp = ue->ue_comparts & nal.na_scmp;
+               usrv.sv_actcmp &= nal.na_scmp;
+#endif /*IP_SECURITY*/
+               usrv.sv_valcmp = ue->ue_comparts & nal.na_scmp;
+               usrv.sv_actcmp = (usrv.sv_valcmp &
+                                 ue->ue_defcomps);
+           }
+       } else {
+           /*
+            *      If the user's minimum level is greater than
+            *      zero, they cannot log on from this (ie. an
+            *      unclassified) host.
+            */
+           if (ue->ue_minlvl > 0)
+             nal_error++;
+           /*
+             /*
+              *      Address not in NAL, if EXEMPT_NAL is not
+              *      true, then even an unclassified user is
+              *      not allowed.
+              */
+             if (!EXEMPT_NAL)
+               nal_error++;
+             else {
+                 usrv.sv_minlvl = 0;
+                 usrv.sv_maxlvl = 0;
+                 usrv.sv_valcmp = 0;
+                 usrv.sv_actcmp = 0;
+                 usrv.sv_actlvl = 0;
+             }
+       }
+       if (nal_error) {
+           loglogin(hostname, SLG_LVERR, ue->ue_logfails,ue);
+           error("Permission denied.\n");
+           goto signout_please;
+       }
+#undef  MIN
+#undef  MAX
+       /* Before the setusrv is done then do a sethost for paddr */
+       sethost(paddr);
+       
+       if (setusrv(&usrv) == -1) {
+           loglogin(hostname, SLG_LVERR, ue->ue_logfails,ue);
+           error("Permission denied.\n");
+           goto signout_please;
+       }
+       if (getusrv(&usrv) == -1) {
+           error("Getusrv Permission denied.\n");
+           goto signout_please;
+       }
+       
+    }
+#endif /*CRAY*/
+    
+    if (chdir(pwd->pw_dir) < 0) {
+       syslog(LOG_ERR ,
+              "Principal %s  (%s@%s) for local user %s has no home directory.\n",
+              kremuser, remuser, hostname, locuser);
+       error("No remote directory.\n");
+       goto signout_please;
+    }
+#ifdef KERBEROS
+    if (must_pass_krb || must_pass_one) {
+       if ( !krb5_kuserok(kdata->client,locuser) ) {
+           syslog(LOG_ERR ,
+                  "Principal %s (%s@%s) for local user %s failed krb5_kuserok.\n",
+                  kremuser, remuser, hostname, locuser);
+           if (must_pass_krb) {
+               error("Permission denied.\n");
+               goto signout_please;
+           }
+           failed_krb = 1;
+       }
+    }
+    if (must_pass_rhosts || (failed_krb && must_pass_one)) {
+       if (ruserok(hostname, pwd->pw_uid == 0,
+                   remuser, locuser) < 0) {
+           syslog(LOG_ERR ,
+                  "Principal %s (%s@%s) for local user %s failed ruserok.\n",
+                  kremuser, remuser, hostname, locuser);
+           error("Permission denied.\n");
+           goto signout_please;
+       }
+    }
+#else
+    if (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' &&
+       ruserok(hostname, pwd->pw_uid == 0, remuser, locuser) < 0) {
+       error("Permission denied.\n");
+       goto signout_please;
+    }
+#endif /* KERBEROS */
+    
+    if (pwd->pw_uid && !access("/etc/nologin", F_OK)) {
+       error("Logins currently disabled.\n");
+       goto signout_please;
+    }
+    
+    /* Log access to account */
+    pwd = (struct passwd *) getpwnam(locuser);
+    if (pwd && (pwd->pw_uid == 0)) {
+#ifdef LOG_CMD
+       syslog(LOG_NOTICE, "Executing %s for principal %s (%s@%s) as ROOT", 
+              cmdbuf, kremuser, remuser, hostname);
+#else
+       syslog(LOG_NOTICE ,"Access as ROOT by principal %s (%s@%s)",
+              kremuser, remuser, hostname);
+#endif
+    }
+    
+#if defined(KERBEROS) && defined(LOG_REMOTE_REALM) && !defined(LOG_OTHER_USERS) && !defined(LOG_ALL_LOGINS)
+    /* Log if principal is from a remote realm */
+    else if (!default_realm(client))
+#endif
+  
+#if defined(KERBEROS) && defined(LOG_OTHER_USERS) && !defined(LOG_ALL_LOGINS) 
+    /* Log if principal name does not map to local username */
+    else if (!princ_maps_to_lname(client, lusername))
+#endif /* LOG_OTHER_USERS */
+  
+#ifdef LOG_ALL_LOGINS /* Log everything */
+    else 
+#endif 
+  
+#if defined(LOG_REMOTE_REALM) || defined(LOG_OTHER_USERS) || defined(LOG_ALL_LOGINS)
+      {
+#ifdef LOG_CMD
+         syslog(LOG_NOTICE, "Executing %s for principal %s (%s@%s) as local user %s", 
+                cmdbuf, kremuser, remuser, hostname, locuser);
+#else
+         syslog(LOG_NOTICE ,"Access as %s by principal %s (%s@%s)",
+                locuser, kremuser, remuser, hostname);
+#endif
+      }
+#endif
+    
+    (void) write(2, "\0", 1);
+    
+    if (port) {
+       if (pipe(pv) < 0) {
+           error("Can't make pipe.\n");
+           goto signout_please;
+       }
+       pid = fork();
+       if (pid == -1)  {
+           error("Try again.\n");
+           goto signout_please;
+       }
+       if (pid) {
+           signal(SIGINT, cleanup);
+           signal(SIGQUIT, cleanup);
+           signal(SIGTERM, cleanup);
+           signal(SIGPIPE, cleanup);
+           signal(SIGHUP, cleanup);
+           signal(SIGCHLD,SIG_IGN);
+           
+           (void) close(0); (void) close(1); (void) close(2);
+           (void) close(f); (void) close(pv[1]);
+           readfrom = (1L<<s) | (1L<<pv[0]);
+           ioctl(pv[0], FIONBIO, (char *)&one);
+           /* should set s nbio! */
+           do {
+               ready = readfrom;
+               if (select(16, &ready, (fd_set *)0,
+                          (fd_set *)0, (struct timeval *)0) < 0)
+                 break;
+               if (ready & (1L<<s)) {
+                   if (read(s, &sig, 1) <= 0)
+                     readfrom &= ~(1L<<s);
+                   else {
+                       signal(sig, cleanup);
+                       killpg(pid, sig);
+                   }
+               }
+               if (ready & (1L<<pv[0])) {
+                   errno = 0;
+                   cc = read(pv[0], buf, sizeof (buf));
+                   if (cc <= 0) {
+                       shutdown(s, 1+1);
+                       readfrom &= ~(1L<<pv[0]);
+                   } else
+                     (void) write(s, buf, cc);
+               }
+           } while (readfrom);
+#ifdef KERBEROS
+           syslog(LOG_INFO ,
+                  "Shell process completed.");
+#endif
+           /* Finish session in wmtp */
+#ifdef SYSV
+           logwtmp(ttyn,"","",0,0); /* Close wtmp */
+#else
+           logwtmp(ttyn,"","",0);   /* Close wtmp */
+#endif
+           exit(0);
+       }
+       setpgrp(0, getpid());
+       (void) close(s); (void) close(pv[0]);
+       dup2(pv[1], 2);
+       (void) close(pv[1]);
+    }
+    
+    /*      We are simply execing a program over rshd : log entry into wtmp, 
+           as kexe(pid), then finish out the session right after that.
+           Syslog should have the information as to what was exec'd */
+    else {
+#ifdef SYSV
+       logwtmp(ttyn,"","",0,0);                /* Close wtmp */
+#else
+       logwtmp(ttyn,"","",0);   /* Close wtmp */
+#endif
+    }
+    
+    if (*pwd->pw_shell == '\0')
+      pwd->pw_shell = "/bin/sh";
+    (void) close(f);
+    (void) setgid((gid_t)pwd->pw_gid);
+#ifndef sgi
+    initgroups(pwd->pw_name, pwd->pw_gid);
+#endif
+    (void) setuid((uid_t)pwd->pw_uid);
+    environ = envinit;
+    strncat(homedir, pwd->pw_dir, sizeof(homedir)-6);
+    strncat(shell, pwd->pw_shell, sizeof(shell)-7);
+    strncat(username, pwd->pw_name, sizeof(username)-6);
+    cp = rindex(pwd->pw_shell, '/');
+    if (cp)
+      cp++;
+    else
+      cp = pwd->pw_shell;
+    
+    execl(pwd->pw_shell, cp, "-c", cmdbuf, 0);
+    perror(pwd->pw_shell);
+    perror(cp);
+    exit(1);
+    
+  signout_please:
+#ifdef SYSV
+    logwtmp(ttyn,"","",0,0);                /* Close wtmp */
+#else
+    logwtmp(ttyn,"","",0);   /* Close wtmp */
+#endif
+    exit(1);
+}
+    
+
+
+/*VARARGS1*/
+error(fmt, a1, a2, a3)
+     char *fmt;
+     int a1, a2, a3;
+{
+    char buf[BUFSIZ];
+    
+    buf[0] = 1;
+    (void) sprintf(buf+1, fmt, a1, a2, a3);
+    (void) write(2, buf, strlen(buf));
+    syslog(LOG_ERR ,"%s",buf+1);
+}
+
+
+
+getstr(buf, cnt, err)
+     char *buf;
+     int cnt;
+     char *err;
+{
+    char c;
+    
+    do {
+       if (read(0, &c, 1) != 1)
+         exit(1);
+       *buf++ = c;
+       if (--cnt == 0) {
+           error("%s too long\n", err);
+           exit(1);
+       }
+    } while (c != 0);
+}
+
+
+
+krb5_sigtype 
+  cleanup()
+{
+    signal(SIGINT, SIG_IGN);
+    signal(SIGQUIT, SIG_IGN);
+    signal(SIGTERM, SIG_IGN);
+    signal(SIGPIPE, SIG_IGN);
+    signal(SIGHUP, SIG_IGN);
+    
+    killpg(pid, SIGTERM);
+    wait(0);
+    
+#ifdef SYSV
+    logwtmp(ttyn,"","",0,0); /* Close wtmp */
+#else
+    logwtmp(ttyn,"","",0);   /* Close wtmp */
+#endif
+    syslog(LOG_INFO ,"Shell process completed.");
+    exit(0);
+}
+
+
+
+#ifdef CRAY
+char *makejtmp(uid, gid, jid)
+     register int uid, gid, jid;
+{
+    extern int errno;
+    
+    register char *endc, *tdp = &tmpdir[strlen(tmpdir)];
+    register int i;
+    
+    sprintf(tdp, "%s/jtmp.%06d", JTMPDIR, jid);
+    endc = &tmpdir[strlen(tmpdir)];
+    
+    endc[1] = '\0';
+    for (i = 0; i < 26; i++) {
+       endc[0] = 'a' + i;
+       if (mkdir(tdp, JTMPMODE) != -1) {
+           chown(tdp, uid, gid);
+           return (tdp);
+       } else if (errno != EEXIST)
+         break;
+    }
+    return(NULL);
+}
+
+
+
+cleanjtmp(user, tpath)
+     register char *user, *tpath;
+{
+    switch(fork()) {
+      case -1:
+       break;
+      case 0:
+       if (secflag) {
+           execl("/bin/rm", "rm", "-rf", tpath, 0);
+           error("exec of %s failed; errno = %d\n",
+                 "/bin/rm", errno);
+       } else {
+           execl(CLEANTMPCMD, CLEANTMPCMD, user, tpath, 0);
+           error("exec of %s failed; errno = %d\n",
+                 CLEANTMPCMD, errno);
+       }
+       exit(1);
+       break;
+      default:
+       /*
+        * Just forget about the child, let init will pick it
+        * up after we exit.
+        */
+       break;
+    }
+}
+
+
+
+/***get_packet_classification
+ *
+ *
+ *      int get_packet_classification():
+ *      Obtain packet level and compartments from passed fd...
+ *
+ *      Returns:
+ *             -1: If could not get user defaults.
+ *              0: success
+ */
+#ifdef IP_SECURITY
+static int get_packet_classification(fd,useruid,level,comp)
+     int fd;
+     uid_t useruid;
+     int *level;
+     long *comp;
+{
+    struct socket_security pkt_sec;
+    struct udb *udb;
+    int retval;
+    int sockoptlen;
+    
+    retval = 0;
+    getsysudb ();
+    udb = getudbuid ((int) useruid);
+    endudb ();
+    if (udb == (struct udb *) 0) return(-1);
+    /* Get packet IP packet label */
+    sockoptlen = SIZEOF_sec;
+    if ( getsockopt(fd,SOL_SOCKET,SO_SECURITY,
+                   (char *) &pkt_sec,&sockoptlen)){  /* Failed */
+       return(-2);
+    }
+    *level = pkt_sec.sec_level;
+    *comp = udb->ue_defcomps;
+    return(0);
+}
+
+#else  /* If no IP_SECURITY set level to users default */
+
+static int get_packet_classification(fd,useruid,level,comp)
+     int fd;
+     uid_t useruid;
+     int *level;
+     long *comp;
+{
+    struct udb    *udb;
+    getsysudb ();
+    udb = getudbuid ((int) useruid);
+    endudb ();
+    if (udb == (struct udb *) 0) return(-1);
+    *level = udb->ue_deflvl;
+    *comp = udb->ue_defcomps;
+    return(0);
+}
+
+#endif /* IP_SECURITY */
+       
+       
+
+/*
+ * Make a security log entry for the login attempt.
+ *     host = pointer to host id
+ *     flag = status of login
+ *     failures = current losing streak in login attempts
+ */
+/* Make a security log entry for the login attempt.
+ *  host = pointer to host id
+ *  flag = status of login
+ *  failures = current losing streak in login attempts
+ */
+
+loglogin(host, flag, failures, ue)
+     char    *host;
+     int     flag;
+     int     failures;
+     struct udb * ue;
+{
+    char   urec[sizeof(struct slghdr) + sizeof(struct slglogin)];
+    struct slghdr   *uhdr = (struct slghdr *)urec;
+    struct slglogin *ulogin=(struct slglogin *)&urec[sizeof(struct slghdr)];
+    
+    strncpy(ulogin->sl_line, ttyn, sizeof(ulogin->sl_line));
+    strncpy(ulogin->sl_host, host, sizeof(ulogin->sl_host));
+    ulogin->sl_failures = failures;
+    if ( maxlogs && (failures >= maxlogs))
+      flag |= SLG_DSABL;
+    ulogin->sl_result = flag;
+    uhdr->sl_uid = ue->ue_uid;
+    uhdr->sl_ruid = ue->ue_uid;
+    uhdr->sl_juid = ue->ue_uid;
+    uhdr->sl_gid = ue->ue_gids[0];
+    uhdr->sl_rgid = ue->ue_gids[0];
+    uhdr->sl_slvl = ue->ue_deflvl;
+    /*      uhdr->sl_scls = ue->ue_defcls;  enable for integrity policy */
+    uhdr->sl_olvl = 0;
+    uhdr->sl_len = sizeof(urec);
+    
+#ifdef  CRAY2
+    slgentry(SLG_LOGN, (word *)urec);
+#else /*        ! CRAY2 */
+    slgentry(SLG_LOGN, (waddr_t)urec);
+#endif
+    return;
+}
+
+#endif CRAY
+       
+
+
+usage()
+{
+#ifdef KERBEROS
+    syslog(LOG_ERR, "usage: kshd [-rRkK] or [r/R][k/K]shd");
+#else
+    syslog(LOG_ERR, "usage: rshd");
+#endif
+}
+
+
+
+int princ_maps_to_lname(principal, luser)      
+     krb5_principal principal;
+     char *luser;
+{
+    char kuser[10];
+    if (!(krb5_aname_to_localname(principal,
+                                 sizeof(kuser), kuser))
+       && (strcmp(kuser, luser) == 0)) {
+       return 1;
+    }
+    return 0;
+}
+
+
+
+int default_realm(principal)
+     krb5_principal principal;
+{
+    char *def_realm;
+    int realm_length;
+    int retval;
+    
+    realm_length = krb5_princ_realm(principal)->length;
+    
+    if (retval = krb5_get_default_realm(&def_realm)) {
+       return 0;
+    }
+    
+    if ((realm_length != strlen(def_realm)) ||
+       (memcmp(def_realm, krb5_princ_realm(principal)->data, realm_length))) {
+       free(def_realm);
+       return 0;
+    }  
+    free(def_realm);
+    return 1;
+}
diff --git a/src/appl/bsd/login.c b/src/appl/bsd/login.c
new file mode 100644 (file)
index 0000000..36fc46f
--- /dev/null
@@ -0,0 +1,684 @@
+/*
+ *     $Source$
+ *     $Author$
+ *     $Id$
+ */
+
+#ifndef lint
+static char rcsid_login_c[] = "$Id$";
+#endif lint
+
+/*
+ * Copyright (c) 1980, 1987, 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+char copyright[] =
+  "@(#) Copyright (c) 1980, 1987, 1988 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)login.c    5.25 (Berkeley) 1/6/89";
+#endif /* not lint */
+
+#define KERBEROS
+     
+     /*
+      * login -f name  (for pre-authenticated login)
+      * login name           (for non-authenticated/non-authorized login)
+      */
+     
+#define VFS
+#define BYPASS_ROOT_CHK
+     
+#include <sys/param.h>
+#ifndef VFS
+#include <sys/quota.h>
+#endif VFS
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+     
+#include <utmp.h>
+#include <signal.h>
+#include <lastlog.h>
+#include <errno.h>
+#ifndef NOTTYENT
+#include <ttyent.h>
+#endif /* NOTTYENT */
+#include <syslog.h>
+#include <grp.h>
+#include <pwd.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <strings.h>
+     
+#ifdef UIDGID_T
+     uid_t getuid();
+#define uid_type uid_t
+#define gid_type gid_t
+#else
+     int getuid();
+#define uid_type int
+#define gid_type int
+#endif /* UIDGID_T */
+     
+#define        TTYGRPNAME      "tty"           /* name of group to own ttys */
+     
+#define        MOTDFILE        "/etc/motd"
+#define        MAILDIR         "/usr/spool/mail"
+#define        NOLOGIN         "/etc/nologin"
+#define        HUSHLOGIN       ".hushlogin"
+#define        LASTLOG         "/usr/adm/lastlog"
+#define        BSHELL          "/bin/sh"
+     
+#ifdef VFS
+#define QUOTAWARN      "/usr/ucb/quota" /* warn user about quotas */
+#endif VFS
+     
+#define        UT_HOSTSIZE     sizeof(((struct utmp *)0)->ut_host)
+#define        UT_NAMESIZE     sizeof(((struct utmp *)0)->ut_name)
+     
+/*
+ * This bounds the time given to login.  Not a define so it can
+ * be patched on machines where it's too small.
+ */
+int timeout = 300;
+
+struct passwd *pwd;
+char term[64], *hostname, *username = NULL;
+
+struct sgttyb sgttyb;
+struct tchars tc = {
+    CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK
+  };
+struct ltchars ltc = {
+    CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT
+  };
+
+extern int errno;
+
+char *getenv();
+int putenv();
+void setenv();
+void dofork();
+
+#ifdef POSIX
+typedef void sigtype;
+#else
+typedef int sigtype;
+#endif /* POSIX */
+
+#ifdef CRAY
+char    user[32] = "LOGNAME=";
+#include <tmpdir.h>
+char tmpdir[64] = "TMPDIR=";
+#else
+char   user[20] = "USER=";
+#endif
+
+char   homedir[64] = "HOME=";
+char   shell[64] = "SHELL=";
+
+
+#ifdef KERBEROS
+char    *envinit[] =
+#ifdef CRAY
+    {homedir, shell, PATH, user, "TZ=GMT0", tmpdir, 0};
+#define TZENV   4
+#define TMPDIRENV 5
+char    *getenv();
+extern
+#else
+    {homedir, shell, "PATH=:/usr/ucb:/bin:/usr/bin:/usr/bin/kerberos",
+   user, 0};
+#endif /* CRAY */
+#else /* !KERBEROS */
+char   *envinit[] =
+#ifdef CRAY
+    {homedir, shell, PATH, user, "TZ=GMT0", tmpdir, 0};
+#define TZENV   4
+#define TMPDIRENV 5
+char    *getenv();
+extern
+#else
+    {homedir, shell, "PATH=:/usr/ucb:/bin:/usr/bin:/usr/bin/kerberos",
+   user, 0};
+#endif /* CRAY */
+#endif /* KERBEROS */
+char **environ;
+
+main(argc, argv)
+     int argc;
+     char **argv;
+{
+    extern int optind;
+    extern char *optarg;
+    struct group *gr;
+    register int ch;
+    register char *p;
+    int fflag, pflag, cnt;
+    int quietlog, ioctlval;
+    sigtype timedout();
+    char *domain, *salt, *ttyn, *tty;
+    char tbuf[MAXPATHLEN + 2];
+    char *ttyname(), *stypeof(), *crypt(), *getpass();
+    time_t time();
+    off_t lseek();
+    int passwd_req = 1, preserve_env = 0;
+    
+    (void)signal(SIGALRM, timedout);
+    (void)alarm((u_int)timeout);
+    (void)signal(SIGQUIT, SIG_IGN);
+    (void)signal(SIGINT, SIG_IGN);
+    (void)setpriority(PRIO_PROCESS, 0, 0);
+#ifndef VFS
+    (void)quota(Q_SETUID, 0, 0, 0);
+#endif VFS
+    
+    (void)gethostname(tbuf, sizeof(tbuf));
+    domain = index(tbuf, '.');
+    
+    passwd_req = 1;
+    while ((ch = getopt(argc, argv, "fp")) != EOF)
+      switch (ch) {
+       case 'f':
+         passwd_req = 0;
+         break;
+       case 'p':
+         preserve_env = 1;
+         break;
+       case '?':
+       default:
+         fprintf(stderr, "usage: login [-fp] [username]\n");
+         exit(1);
+         break;
+      }
+    argc -= optind;
+    argv += optind;
+    if (*argv)
+      hostname = *argv;
+    
+    ioctlval = 0;
+    (void)ioctl(0, TIOCLSET, (char *)&ioctlval);
+    (void)ioctl(0, TIOCNXCL, (char *)0);
+    (void)fcntl(0, F_SETFL, ioctlval);
+    (void)ioctl(0, TIOCGETP, (char *)&sgttyb);
+    
+    doremotelogin();
+    
+    /*
+     * If talking to an rlogin process, propagate the terminal type and
+     * baud rate across the network.
+     */
+    doremoteterm(&sgttyb);     
+    sgttyb.sg_erase = CERASE;
+    sgttyb.sg_kill = CKILL;
+    (void)ioctl(0, TIOCSLTC, (char *)&ltc);
+    (void)ioctl(0, TIOCSETC, (char *)&tc);
+    (void)ioctl(0, TIOCSETP, (char *)&sgttyb);
+    
+    for (cnt = getdtablesize(); cnt > 2; cnt--)
+      (void) close(cnt);
+    
+    ttyn = ttyname(0);
+    if (ttyn == NULL || *ttyn == '\0')
+      ttyn = "/dev/tty??";
+    if (tty = rindex(ttyn, '/'))
+      ++tty;
+    else
+      tty = ttyn;
+    
+#ifndef LOG_ODELAY /* 4.2 syslog ... */                      
+    openlog("login", 0);
+#else
+    openlog("login", LOG_ODELAY, LOG_AUTH);
+#endif /* 4.2 syslog */
+    
+    for (cnt = 0;; username = NULL) {
+       ioctlval = 0;
+       (void)ioctl(0, TIOCSETD, (char *)&ioctlval);
+       
+       if (username == NULL) 
+         getloginname();
+       
+       if (pwd = getpwnam(username))
+         salt = pwd->pw_passwd;
+       else
+         salt = "xx";
+       
+       /* if user not super-user, check for disabled logins */
+       if (pwd == NULL || pwd->pw_uid)
+         checknologin();
+       
+       /*
+        * Disallow automatic login to root; if not invoked by
+        * root, disallow if the uid's differ.
+        */
+       if (!passwd_req && pwd) {
+           int uid = (int) getuid();
+           
+           passwd_req = (uid && uid != pwd->pw_uid)
+#ifndef BYPASS_ROOT_CHK
+             || (pwd->pw_uid == 0);
+#else
+           ;
+#endif
+       }
+       
+       /*
+        * If no remote login authentication and a password exists
+        * for this user, prompt for one and verify it.
+        */
+       if (!passwd_req || pwd && !*pwd->pw_passwd)
+         break;
+       
+       (void) setpriority(PRIO_PROCESS, 0, -4);
+       p = crypt(getpass("Password:"), salt);
+       (void) setpriority(PRIO_PROCESS, 0, 0);
+       if (pwd && !strcmp(p, pwd->pw_passwd))
+         break;
+       
+       printf("Login incorrect\n");
+       if (++cnt >= 5) {
+           if (hostname)
+             syslog(LOG_ERR,
+                    "REPEATED LOGIN FAILURES ON %s FROM %.*s, %.*s",
+                    tty, UT_HOSTSIZE, hostname, UT_NAMESIZE,
+                    username);
+           else
+             syslog(LOG_ERR,
+                    "REPEATED LOGIN FAILURES ON %s, %.*s",
+                    tty, UT_NAMESIZE, username);
+           (void)ioctl(0, TIOCHPCL, (char *)0);
+           sleepexit(1);
+       }
+    }
+    
+    /* committed to login -- turn off timeout */
+    (void)alarm((u_int)0);
+    
+    /*
+     * If valid so far and root is logging in, see if root logins on
+     * this terminal are permitted.
+     */
+#ifndef BYPASS_ROOT_CHK
+    if (pwd->pw_uid == 0 && !rootterm(tty)) {
+       if (hostname)
+         syslog(LOG_ERR, "ROOT LOGIN REFUSED ON %s FROM %.*s",
+                tty, UT_HOSTSIZE, hostname);
+       else
+         syslog(LOG_ERR, "ROOT LOGIN REFUSED ON %s", tty);
+       printf("Login incorrect\n");
+       sleepexit(1);
+    }
+#endif
+    
+#ifndef VFS
+    if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) {
+       switch(errno) {
+         case EUSERS:
+           fprintf(stderr,
+                   "Too many users logged on already.\nTry again later.\n");
+           break;
+         case EPROCLIM:
+           fprintf(stderr,
+                   "You have too many processes running.\n");
+           break;
+         default:
+           perror("quota (Q_SETUID)");
+       }
+       sleepexit(0);
+    }
+#endif /* !VFS */
+    
+    if (chdir(pwd->pw_dir) < 0) {
+       printf("No directory %s!\n", pwd->pw_dir);
+       if (chdir("/"))
+         exit(0);
+       pwd->pw_dir = "/";
+       printf("Logging in with home = \"/\".\n");
+    }
+    
+    /* nothing else left to fail -- really log in */
+    {
+       struct utmp utmp;
+       
+       (void)time(&utmp.ut_time);
+       (void) strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
+       if (hostname)
+         (void) strncpy(utmp.ut_host, hostname,
+                        sizeof(utmp.ut_host));
+       else
+         bzero(utmp.ut_host, sizeof(utmp.ut_host));
+       (void) strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
+       login(&utmp);
+    }
+    
+    quietlog = access(HUSHLOGIN, F_OK) == 0;
+    dolastlog(quietlog, tty);
+    
+    {
+       static struct winsize win = { 0, 0, 0, 0 };
+       
+       (void)ioctl(0, TIOCSWINSZ, (char *)&win);
+    }
+    
+    (void)chown(ttyn, pwd->pw_uid,
+               (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
+    
+    (void)chmod(ttyn, 0620);
+    
+    (void)setgid((gid_type) pwd->pw_gid);
+    
+    (void) initgroups(username, pwd->pw_gid);
+    
+#ifndef VFS
+    quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0);
+#endif
+    (void)setuid((uid_type) pwd->pw_uid);
+    
+    if (*pwd->pw_shell == '\0')
+      pwd->pw_shell = BSHELL;
+    /* turn on new line discipline for the csh */
+    else if (!strcmp(pwd->pw_shell, "/bin/csh")) {
+       ioctlval = NTTYDISC;
+       (void)ioctl(0, TIOCSETD, (char *)&ioctlval);
+    }
+    /* Destroy old environment unless requested. */ 
+    if (!preserve_env)
+      environ = envinit;
+    
+    setenv("HOME", pwd->pw_dir);
+    setenv("SHELL", pwd->pw_shell);
+    if (term[0] == '\0')
+      (void) strncpy(term, stypeof(tty), sizeof(term));
+    setenv("TERM", term);
+    setenv("USER", pwd->pw_name);
+    setenv("PATH", "/usr/ucb:/bin:/usr/bin:");
+    
+    if (tty[sizeof("tty")-1] == 'd')
+      syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
+    
+    if (!quietlog) {
+       struct stat st;
+       motd();
+       (void)sprintf(tbuf, "%s/%s", MAILDIR, pwd->pw_name);
+       if (stat(tbuf, &st) == 0 && st.st_size != 0)
+         printf("You have %smail.\n",
+                (st.st_mtime > st.st_atime) ? "new " : "");
+    }
+    
+#ifdef VFS
+    if (! access( QUOTAWARN, X_OK)) (void) system(QUOTAWARN);
+#endif VFS
+    (void)signal(SIGALRM, SIG_DFL);
+    (void)signal(SIGQUIT, SIG_DFL);
+    (void)signal(SIGINT, SIG_DFL);
+    (void)signal(SIGTSTP, SIG_IGN);
+    
+    tbuf[0] = '-';
+    (void) strcpy(tbuf + 1, (p = rindex(pwd->pw_shell, '/')) ?
+                 p + 1 : pwd->pw_shell);
+    execlp(pwd->pw_shell, tbuf, 0);
+    fprintf(stderr, "login: no shell: ");
+    perror(pwd->pw_shell);
+    exit(0);
+}
+
+
+
+getloginname()
+{
+    register int ch;
+    register char *p;
+    static char nbuf[UT_NAMESIZE + 1];
+    
+    for (;;) {
+       printf("login: ");
+       for (p = nbuf; (ch = getchar()) != '\n'; ) {
+           if (ch == EOF)
+             exit(0);
+           if (p < nbuf + UT_NAMESIZE)
+             *p++ = ch;
+       }
+       if (p > nbuf)
+         if (nbuf[0] == '-')
+           fprintf(stderr,
+                   "login names may not start with '-'.\n");
+         else {
+             *p = '\0';
+             username = nbuf;
+             break;
+         }
+    }
+}
+
+
+
+sigtype
+  timedout()
+{
+    fprintf(stderr, "Login timed out after %d seconds\n", timeout);
+    exit(0);
+}
+
+
+
+#ifdef NOTTYENT
+int root_tty_security = 0;
+#endif
+rootterm(tty)
+     char *tty;
+{
+#ifdef NOTTYENT
+    return(root_tty_security);
+#else
+    struct ttyent *t;
+    
+    return((t = getttynam(tty)) && t->ty_status&TTY_SECURE);
+#endif NOTTYENT
+}
+
+
+
+jmp_buf motdinterrupt;
+
+motd()
+{
+    register int fd, nchars;
+    sigtype (*oldint)(), sigint();
+    char tbuf[8192];
+    
+    if ((fd = open(MOTDFILE, O_RDONLY, 0)) < 0)
+      return;
+    oldint = (sigtype (*)()) signal(SIGINT, sigint);
+    if (setjmp(motdinterrupt) == 0)
+      while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
+       (void)write(fileno(stdout), tbuf, nchars);
+    (void)signal(SIGINT, oldint);
+    (void)close(fd);
+}
+
+
+
+sigtype
+  sigint()
+{
+    longjmp(motdinterrupt, 1);
+}
+
+
+
+checknologin()
+{
+    register int fd, nchars;
+    char tbuf[8192];
+    
+    if ((fd = open(NOLOGIN, O_RDONLY, 0)) >= 0) {
+       while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
+         (void)write(fileno(stdout), tbuf, nchars);
+       sleepexit(0);
+    }
+}
+
+
+
+dolastlog(quiet, tty)
+     int quiet;
+     char *tty;
+{
+    struct lastlog ll;
+    int fd;
+    
+    if ((fd = open(LASTLOG, O_RDWR, 0)) >= 0) {
+       (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
+       if (!quiet) {
+           if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
+               ll.ll_time != 0) {
+               printf("Last login: %.*s ",
+                      24-5, (char *)ctime(&ll.ll_time));
+               if (*ll.ll_host != '\0')
+                 printf("from %.*s\n",
+                        sizeof(ll.ll_host), ll.ll_host);
+               else
+                 printf("on %.*s\n",
+                        sizeof(ll.ll_line), ll.ll_line);
+           }
+           (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
+       }
+       (void)time(&ll.ll_time);
+       (void) strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
+       if (hostname)
+         (void) strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
+       else
+         (void) bzero(ll.ll_host, sizeof(ll.ll_host));
+       (void)write(fd, (char *)&ll, sizeof(ll));
+       (void)close(fd);
+    }
+}
+
+
+
+#undef UNKNOWN
+#define        UNKNOWN "su"
+
+char *stypeof(ttyid)
+     char *ttyid;
+{
+#ifdef NOTTYENT
+    return(UNKNOWN);
+#else
+    struct ttyent *t;
+    
+    return(ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN);
+#endif
+}
+
+
+
+getstr(buf, cnt, err)
+     char *buf, *err;
+     int cnt;
+{
+    char ch;
+    
+    do {
+       if (read(0, &ch, sizeof(ch)) != sizeof(ch))
+         exit(1);
+       if (--cnt < 0) {
+           fprintf(stderr, "%s too long\r\n", err);
+           sleepexit(1);
+       }
+       *buf++ = ch;
+    } while (ch);
+}
+
+
+
+doremotelogin()
+{
+    static char lusername[UT_NAMESIZE+1];
+    char rusername[UT_NAMESIZE+1];
+    
+    getstr(rusername, sizeof(rusername), "remuser");
+    getstr(lusername, sizeof(lusername), "locuser");
+    if (username == NULL)
+      username = lusername;
+    getstr(term, sizeof(term), "Terminal type");
+}
+
+
+
+char *speeds[] = {
+    "0", "50", "75", "110", "134", "150", "200", "300", "600",
+    "1200", "1800", "2400", "4800", "9600", "19200", "38400",
+};
+#define        NSPEEDS (sizeof(speeds) / sizeof(speeds[0]))
+
+doremoteterm(tp)
+     struct sgttyb *tp;
+{
+    register char *cp = index(term, '/'), **cpp;
+    char *speed;
+    
+    if (cp) {
+       *cp++ = '\0';
+       speed = cp;
+       cp = index(speed, '/');
+       if (cp)
+         *cp++ = '\0';
+       for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++)
+         if (strcmp(*cpp, speed) == 0) {
+             tp->sg_ispeed = tp->sg_ospeed = cpp-speeds;
+             break;
+         }
+    }
+    tp->sg_flags = ECHO|CRMOD|ANYP|XTABS;
+}
+
+
+
+sleepexit(eval)
+     int eval;
+{
+    sleep((u_int)5);
+    exit(eval);
+}
+
+
+
+void setenv(var, value)
+     char *var, *value;
+{
+    char *env_str;
+    int retval, str_size = strlen(var) + strlen(value) + strlen("=") + 1;
+    
+    env_str = (char *) malloc(str_size);
+    
+    strcpy(env_str, var);
+    strcat(env_str, "=");
+    strcat(env_str, value);
+    env_str[str_size-1] = '\0';
+    
+    if (retval = putenv(env_str)) {
+       syslog(LOG_ERR, "Not enough memory\n");
+       exit(1);
+    }
+}
diff --git a/src/appl/bsd/logutil.c b/src/appl/bsd/logutil.c
new file mode 100644 (file)
index 0000000..645df54
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)login.c    5.1 (Berkeley) 9/27/88";
+#endif /* LIBC_SCCS and not lint */
+     
+#include <sys/types.h>
+#include <sys/file.h>
+#if defined (CRAY) || defined (sgi)
+#include <sys/fcntl.h>
+#define L_SET 0
+#define L_INCR 1
+#endif
+#include <utmp.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+     
+#ifndef UTMP_FILE
+#define        UTMP_FILE       "/etc/utmp"
+#endif
+#ifndef WTMP_FILE
+#ifdef SYSV
+#define WTMPFILE    "/etc/wtmp"
+#else
+#define        WTMP_FILE       "/usr/adm/wtmp"
+#endif
+#endif
+     
+void login(ut)
+     struct utmp *ut;
+{
+    register int fd;
+    int tty;
+    off_t lseek();
+    
+    tty = ttyslot();
+    if (tty > 0 && (fd = open(UTMP_FILE, O_WRONLY, 0)) >= 0) {
+       (void)lseek(fd, (long)(tty * sizeof(struct utmp)), L_SET);
+       (void)write(fd, (char *)ut, sizeof(struct utmp));
+       (void)close(fd);
+    }
+    if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) >= 0) {
+       (void)write(fd, (char *)ut, sizeof(struct utmp));
+       (void)close(fd);
+    }
+}
+
+
+
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)logout.c   5.1 (Berkeley) 8/31/88";
+#endif /* LIBC_SCCS and not lint */
+     
+logout(line)
+     register char *line;
+{
+    register FILE *fp;
+    struct utmp ut;
+    int rval;
+    time_t time();
+    
+    if (!(fp = fopen(UTMP_FILE, "r+")))
+      return(0);
+    rval = 1;
+    while (fread((char *)&ut, sizeof(struct utmp), 1, fp) == 1) {
+       if (!ut.ut_name[0] ||
+           strncmp(ut.ut_line, line, sizeof(ut.ut_line)))
+         continue;
+       memset(ut.ut_name,0, sizeof(ut.ut_name));
+#ifndef  NO_UT_HOST
+       memset(ut.ut_host,0, sizeof(ut.ut_host));
+#endif
+       (void)time(&ut.ut_time);
+       (void)fseek(fp, (long)-sizeof(struct utmp), L_INCR);
+       (void)fwrite((char *)&ut, sizeof(struct utmp), 1, fp);
+       (void)fseek(fp, (long)0, L_INCR);
+       rval = 0;
+    }
+    (void)fclose(fp);
+    return(rval);
+}
+
+
+
+/*
+ * Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)logwtmp.c  5.2 (Berkeley) 9/20/88";
+#endif /* LIBC_SCCS and not lint */
+     
+static int fd = -1;
+
+#ifndef SYSV
+logwtmp(line, name, host, keep_open)
+#else
+logwtmp(line, name, host, keep_open, logingin)
+#endif
+     char *line, *name, *host;
+     int keep_open;
+#ifdef  SYSV
+     int logingin;
+#endif
+{
+    struct utmp ut;
+    struct stat buf;
+    time_t time();
+    char *strncpy();
+    
+    if (fd < 0 && (fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) < 0)
+      return;
+    if (!fstat(fd, &buf)) {
+       (void)strncpy(ut.ut_line, line, sizeof(ut.ut_line));
+       (void)strncpy(ut.ut_name, name, sizeof(ut.ut_name));
+#ifndef  NO_UT_HOST
+       (void)strncpy(ut.ut_host, host, sizeof(ut.ut_host));
+#endif 
+#ifdef  SYSV
+       (void)strncpy(ut.ut_id, (char *)ut.ut_line + 4,
+                     sizeof(ut.ut_id));
+       ut.ut_type = logingin ? USER_PROCESS : DEAD_PROCESS;
+       ut.ut_pid = getpid();
+#endif
+       (void)time(&ut.ut_time);
+       if (write(fd, (char *)&ut, sizeof(struct utmp)) !=
+           sizeof(struct utmp))
+         (void)ftruncate(fd, buf.st_size);
+    }
+    if ( !keep_open)
+      (void)close(fd);
+}
diff --git a/src/appl/bsd/rcp.M b/src/appl/bsd/rcp.M
new file mode 100644 (file)
index 0000000..ed3f872
--- /dev/null
@@ -0,0 +1,130 @@
+.\" $Source$
+.\" $Author$
+.\" $Header$
+.\"
+.\" Copyright (c) 1983 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms are permitted
+.\" provided that the above copyright notice and this paragraph are
+.\" duplicated in all such forms and that any documentation,
+.\" advertising materials, and other materials related to such
+.\" distribution and use acknowledge that the software was developed
+.\" by the University of California, Berkeley.  The name of the
+.\" University may not be used to endorse or promote products derived
+.\" from this software without specific prior written permission.
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+.\" WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\"    @(#)rcp.1       6.6 (Berkeley) 9/20/88
+.\"
+.TH RCP 1 "Kerberos Version 4.0" "MIT Project Athena"
+.UC 5
+.SH NAME
+rcp \- remote file copy
+.SH SYNOPSIS
+.B rcp
+[
+.B \-p
+] [
+.B \-x
+] [
+.B \-k
+realm ] file1 file2
+.br
+.B rcp
+[
+.B \-p
+] [
+.B \-x
+] [
+.B \-k
+realm ] [
+.B \-r
+] file ... directory
+.SH DESCRIPTION
+.I Rcp
+copies files between machines.  Each
+.I file
+or
+.I directory
+argument is either a remote file name of the
+form ``rhost:path'', or a local file name (containing no `:' characters,
+or a `/' before any `:'s).
+.PP
+If the
+.B \-r
+option
+is specified and any of the source files are directories,
+.I rcp
+copies each subtree rooted at that name; in this case
+the destination must be a directory.
+.PP
+By default, the mode and owner of
+.I file2
+are preserved if it already existed; otherwise the mode of the source file
+modified by the
+.IR umask (2)
+on the destination host is used.
+The
+.B \-p
+option causes
+.I rcp
+to attempt to preserve (duplicate) in its copies the modification
+times and modes of the source files, ignoring the
+.IR umask .
+.PP
+If
+.I path
+is not a full path name, it is interpreted relative to
+your login directory on 
+.IR rhost .
+A 
+.I path
+on a remote host may be quoted (using \e, ", or \(aa)
+so that the metacharacters are interpreted remotely.
+.PP
+.I Rcp
+does not prompt for passwords; it uses Kerberos authentication when
+connecting to
+.IR rhost .
+Authorization is as described in 
+.IR rlogin (1).
+.PP
+The
+.B \-x
+option selects encryption of all information transferring between hosts.
+The
+.B \-k
+.I realm
+option causes 
+.I rcp
+to obtain tickets for the remote host in
+.I realm
+instead of the remote host's realm as determined by
+.IR krb_realmofhost (3).
+.PP
+.I Rcp
+handles third party copies, where neither source nor target files
+are on the current machine.
+Hostnames may also take the form ``rname@rhost'' to use
+.I rname
+rather than the current user name on the remote host.
+.SH SEE ALSO
+cp(1), ftp(1), rsh(1), rlogin(1), kerberos(3), krb_getrealm(3),
+rcp(1) [UCB version]
+.SH BUGS
+Doesn't detect all cases where the target of a copy might
+be a file in cases where only a directory should be legal.
+.PP
+Is confused by any output generated by commands in a
+\&.login, \&.profile, or \&.cshrc file on the remote host.
+.PP
+The destination user and hostname may have to be specified as
+``rhost.rname'' when the destination machine is running the 4.2BSD
+version of \fIrcp\fP.
+.PP
+Kerberos is only used for the first connection of a third-party copy;
+the second connection uses the standard Berkeley rcp protocol.
+
diff --git a/src/appl/bsd/rlogin.M b/src/appl/bsd/rlogin.M
new file mode 100644 (file)
index 0000000..c24ef85
--- /dev/null
@@ -0,0 +1,200 @@
+.\" $Source$
+.\" $Author$
+.\" $Header$
+.\"
+.\" Copyright (c) 1983 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms are permitted
+.\" provided that the above copyright notice and this paragraph are
+.\" duplicated in all such forms and that any documentation,
+.\" advertising materials, and other materials related to such
+.\" distribution and use acknowledge that the software was developed
+.\" by the University of California, Berkeley.  The name of the
+.\" University may not be used to endorse or promote products derived
+.\" from this software without specific prior written permission.
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+.\" WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\"    @(#)rlogin.1    6.9 (Berkeley) 9/19/88
+.\"
+.TH RLOGIN 1 "Kerberos Version 4.0" "MIT Project Athena"
+.UC 5
+.SH NAME
+rlogin \- remote login
+.SH SYNOPSIS
+.B rlogin
+rhost [
+\fB\-e\fR\fI\|c\fR
+] [
+.B \-8
+] [
+.B \-c
+] [
+.B \-a
+] [
+.B \-t
+termtype ] [
+.B \-n
+] [
+.B \-7
+] [
+.B \-d
+] [
+.B \-k
+realm ] [
+.B \-x
+] [
+.B \-noflow
+] [
+.B \-L
+] [
+.B \-l
+username ]
+.br
+rhost [
+\fB\-e\fR\fIc\fR
+] [
+.B \-8
+] [
+.B \-c
+] [
+.B \-a
+] [
+.B \-t
+termtype ] [
+.B \-n
+] [
+.B \-7
+] [
+.B \-d
+] [
+.B \-k
+realm ] [
+.B \-x
+] [
+.B \-noflow
+] [
+.B \-L
+] [
+.B \-l
+username ]
+.SH DESCRIPTION
+.I Rlogin
+connects your terminal on the current local host system
+.I lhost
+to the remote host system
+.I rhost.
+.PP
+The version built to use Kerberos authentication is very similar to the
+standard Berkeley rlogin(1), except that instead of the \fIrhosts\fP
+mechanism, it uses Kerberos authentication to determine the
+authorization to use a remote account.
+.PP
+Each user may have a private authorization list in a file \&.klogin
+in his login directory.  Each line in this file should contain a
+Kerberos principal name of the form 
+.IR principal.instance@realm .
+If the originating user is authenticated to one of the principals named
+in \&.klogin, access is granted to the account.  The principal
+\fIaccountname\fP.@\fIlocalrealm\fP is granted access if there is no
+\&.klogin file. 
+Otherwise
+a login and password will be prompted for on the remote machine as in
+.IR login (1).
+To avoid some security problems, the \&.klogin file must be owned by
+the remote user.
+.PP
+If there is some problem in marshaling the Kerberos authentication
+information, an error message is printed and the standard UCB rlogin is
+executed in place of the Kerberos rlogin.
+.PP
+A line of the form ``~.'' disconnects from the remote host, where
+``~'' is the escape character.
+Similarly, the line ``~^Z'' (where ^Z, control-Z, is the suspend character)
+will suspend the rlogin session.
+Substitution of the delayed-suspend character (normally ^Y)
+for the suspend character suspends the send portion of the rlogin,
+but allows output from the remote system.
+.PP
+The remote terminal type is the same as your local
+terminal type (as given in your environment TERM variable), unless the
+.B \-t
+option is specified (see below).
+The terminal or window size is also copied to the remote system
+if the server supports the option,
+and changes in size are reflected as well.
+.PP
+All echoing takes place at the remote site, so that (except for
+delays) the rlogin is transparent.  Flow control via ^S and ^Q and
+flushing of input and output on interrupts are handled properly.
+.PP
+The
+.B \-8
+option allows an eight-bit input data path at all times;
+otherwise parity bits are stripped except when the remote side's
+stop and start characters are other than ^S/^Q. Eight-bit mode is the default.
+.PP
+The
+.B \-L
+option allows the rlogin session to be run in litout mode.
+.PP
+The
+.B \-e
+option allows specification of a different escape character.
+There is no space separating this option flag and the new escape
+character.
+.PP
+The
+.B \-c
+option requires confirmation before disconnecting via ``~.''
+.PP
+The
+.B \-a
+option forces the remote machine to ask for a password by sending a null local
+username.  This option has no effect unless the standard UCB rlogin is
+executed in place of the Kerberos rlogin (see above).
+.PP
+The
+.B \-t
+option replaces the terminal type passed to the remote host with
+\fItermtype\fP.
+.PP
+The
+.B \-n
+option prevents suspension of rlogin via ``~^Z'' or ``~^Y''.
+.PP
+The
+.B \-7
+option forces seven-bit transmissions.
+.PP
+The
+.B \-d
+option turns on socket debugging (via \fIsetsockopt(2)\fR) on the TCP
+sockets used for communication with the remote host.
+.PP
+The
+.B \-noflow
+option forces transmission of flow control characters (^S/^Q) to the
+remote system.
+.PP
+The
+.B \-k
+option requests rlogin to obtain tickets for the remote host in realm
+.I realm
+instead of the remote host's realm as determined by 
+.IR krb_realmofhost (3).
+.PP
+The
+.B \-x
+option turns on DES encryption for all data passed via the
+rlogin session.  This significantly reduces response time and
+significantly increases CPU utilization.
+.SH SEE ALSO
+rsh(1), kerberos(3), krb_sendauth(3), krb_realmofhost(3),
+rlogin(1) [UCB version]
+.SH FILES
+/usr/hosts/*           for \fIrhost\fP version of the command
+.SH BUGS
+More of the environment should be propagated.
diff --git a/src/appl/bsd/rsh.M b/src/appl/bsd/rsh.M
new file mode 100644 (file)
index 0000000..eda3328
--- /dev/null
@@ -0,0 +1,153 @@
+.\" $Source$
+.\" $Author$
+.\" $Header$
+.\"
+.\" Copyright (c) 1983 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms are permitted
+.\" provided that the above copyright notice and this paragraph are
+.\" duplicated in all such forms and that any documentation,
+.\" advertising materials, and other materials related to such
+.\" distribution and use acknowledge that the software was developed
+.\" by the University of California, Berkeley.  The name of the
+.\" University may not be used to endorse or promote products derived
+.\" from this software without specific prior written permission.
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+.\" WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\"    @(#)rsh.1       6.2 (Berkeley) 9/20/88
+.\"
+.TH RSH 1 "Kerberos Version 4.0" "MIT Project Athena"
+.UC 5
+.SH NAME
+rsh \- remote shell
+.SH SYNOPSIS
+.B rsh
+host
+[
+.B \-l
+username
+] [
+.B \-n
+] [
+.B \-d
+] [
+.B \-k
+realm ] command
+.br
+host
+[
+.B \-l
+username
+] [
+.B \-n
+] [
+.B \-d
+] [
+.B \-k
+realm ] command
+.SH DESCRIPTION
+.I Rsh
+connects to the specified
+.I host,
+and executes the specified \fIcommand\fR.
+.I Rsh
+copies its standard input to the remote command, the standard
+output of the remote command to its standard output, and the
+standard error of the remote command to its standard error.
+Interrupt, quit and terminate signals are propagated to the remote
+command; \fIrsh\fP normally terminates when the remote command does.
+.PP
+The remote username used is the same as your local username,
+unless you specify a different remote name with the
+.B \-l
+option.
+Kerberos authentication is used, and authorization is determined as in
+rlogin(1).
+.PP
+The
+.B \-k
+\fIrealm\fP option causes 
+.I rsh
+to obtain tickets for the remote host in
+.I realm
+instead of the remote host's realm as determined by
+.IR krb_realmofhost (3).
+.PP
+The
+.B \-d
+option turns on socket debugging (via \fIsetsockopt(2)\fR) on the TCP
+sockets used for communication with the remote host.
+.PP
+The
+.B \-n
+option redirects input from the special device
+.I /dev/null
+(see the BUGS section below).
+.PP
+If you omit
+.I command,
+then instead of executing a single command, you will be logged in
+on the remote host using
+.IR rlogin (1).
+.PP
+Shell metacharacters which are not quoted are interpreted
+on local machine, while quoted metacharacters are interpreted on
+the remote machine.
+Thus the command
+.PP
+\ \ \ rsh otherhost cat remotefile >> localfile
+.PP
+appends the remote file
+.I remotefile
+to the local file
+.I localfile,
+while
+.PP
+\ \ \ rsh otherhost cat remotefile ">>" otherremotefile
+.PP
+appends
+.I remotefile
+to
+.I otherremotefile.
+.PP
+The host names for local machines are also commands in the directory
+/usr/hosts; if you put this directory in your search path
+then the
+.B rsh
+on the command line can be omitted.
+.SH FILES
+.ta 2i
+/etc/hosts
+.br
+/usr/hosts/*
+.DT
+.SH SEE ALSO
+rlogin(1), kerberos(3), krb_sendauth(3), krb_realmofhost(3)
+.SH BUGS
+If you are using
+.IR csh (1)
+and put a
+.IR rsh (1)
+in the background without redirecting its input
+away from the terminal, it will block even if no reads
+are posted by the remote command.  If no input is desired
+you should redirect the input of
+.I rsh
+to /dev/null using the
+.B \-n
+option.
+.PP
+You cannot run an interactive command
+(like
+.IR rogue (6)
+or
+.IR vi (1));
+use
+.IR rlogin (1).
+.PP
+Stop signals stop the local \fIrsh\fP process only; this is arguably
+wrong, but currently hard to fix for reasons too complicated to
+explain here.
diff --git a/src/kadmin/client/Imakefile b/src/kadmin/client/Imakefile
new file mode 100644 (file)
index 0000000..1da031b
--- /dev/null
@@ -0,0 +1,45 @@
+# $Source$
+# $Author$
+# $Header$
+#
+# Copyright 1989 by the Massachusetts Institute of Technology.
+#
+# For copying and distribution information,
+# please see the file <mit-copyright.h>.
+#
+# Imakefile for Kerberos admin client library.
+
+SRCS = \
+       kadmin.c \
+       kadmin_add.c \
+       kadmin_adr.c \
+       kadmin_cpr.c \
+       kadmin_inq.c \
+       kadmin_msnd.c \
+       kadmin_mod.c \
+       kadmin_cpw.c \
+       kadmin_del.c \
+       kadmin_done.c
+
+OBJS = \
+       kadmin.o \
+       kadmin_add.o \
+       kadmin_adr.o \
+       kadmin_cpr.o \
+       kadmin_inq.o \
+       kadmin_msnd.o \
+       kadmin_mod.o \
+       kadmin_cpw.o \
+       kadmin_del.o \
+       kadmin_done.o
+
+ErrorTableObjectRule()
+
+all::  kadmin
+
+NormalProgramTarget(kadmin,$(OBJS),$(KDBDEPLIB) $(DEPKLIB), $(KLIB) ,)
+Krb5InstallClientProgram(kadmin)
+
+clean::
+
+DependTarget()
diff --git a/src/kadmin/client/kadmin.M b/src/kadmin/client/kadmin.M
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/kadmin/client/kadmin.c b/src/kadmin/client/kadmin.c
new file mode 100644 (file)
index 0000000..91887d8
--- /dev/null
@@ -0,0 +1,773 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ */
+
+/* 
+ * Sandia National Laboratories also makes no representations about the 
+ * suitability of the modifications, or additions to this software for 
+ * any purpose.  It is provided "as is" without express or implied warranty.
+ */
+
+#if !defined(lint) && !defined(SABER)
+static char rcsid_kadmin[] =
+    "$Header$";
+#endif /* lint */
+
+/*
+ * kadmin
+ * Perform Remote Kerberos Administrative Functions
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <signal.h>
+#ifndef __convex__
+#include <strings.h>
+#endif
+#include <pwd.h>
+#include <com_err.h>
+
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 1024
+#endif
+
+#include <krb5/adm_defs.h>
+
+#include <krb5/krb5.h>
+#include <krb5/ext-proto.h>
+#include <krb5/los-proto.h>
+#include <krb5/kdb.h>
+#include <krb5/kdb_dbm.h>
+
+krb5_error_code get_first_ticket 
+       PROTOTYPE((krb5_ccache, 
+               krb5_principal));
+
+struct sockaddr_in local_sin, remote_sin;
+
+krb5_creds my_creds;
+
+void get_def_princ();
+
+main(argc,argv)
+  int argc;
+  char *argv[];
+{
+    extern char *optarg;
+
+    krb5_ccache cache = NULL;
+    char cache_name[255];
+
+    krb5_address local_addr, foreign_addr;
+
+    krb5_principal client;
+
+    char *client_name; /* Single string representation of client id */
+
+    krb5_data *requested_realm;
+
+    krb5_error_code retval;    /* return code */
+
+    int local_socket;
+
+    krb5_error *err_ret;
+    krb5_ap_rep_enc_part *rep_ret;
+
+    kadmin_requests rd_priv_resp;
+
+    krb5_checksum send_cksum;
+    krb5_data msg_data, inbuf;
+    krb5_int32 seqno;
+    char buffer[255];
+    char command_type[120];
+    char princ_name[120];
+    int i, valid;
+    int option;
+    int oper_type;
+
+    krb5_init_ets();
+    client_name = (char *) malloc(755);
+    memset((char *) client_name, 0, sizeof(client_name));
+
+    if (argc > 3)
+      usage();
+
+    if (argc == 1) {  /* No User Specified */
+       get_def_princ(&client);
+       strcpy(client_name, client->data[0].data);
+       strncat(client_name, "/admin@", 7);
+       strncat(client_name, client->realm.data, client->realm.length);
+       if (retval = krb5_parse_name(client_name, &client)) {
+           fprintf(stderr, "Unable to Parse Client Name!\n");
+           usage();
+       }
+    }
+    else {
+       while ((option = getopt(argc, argv, "n")) != EOF) {
+           switch (option) {
+             case 'n':
+               if (argc == 3) {
+                   strcpy(client_name, argv[2]);
+                   if (retval = krb5_parse_name(client_name, &client)) {
+                       fprintf(stderr, "Unable to Parse Client Name!\n");
+                       usage();
+                   }
+               }
+               else {
+                   get_def_princ(&client);
+                   if (retval = krb5_unparse_name(client, &client_name)) {
+                       fprintf(stderr, "Unable to unparse Client Name!\n");
+                       usage();
+                   }
+               }
+               break;
+             case '?':
+             default:
+               usage();
+               break;
+           }
+       }
+       
+       if (client_name[0] == '\0') { /* No -n option specified */
+           if (argc > 2)
+             usage();
+           strcpy(client_name, argv[1]);
+           if (!strncmp("help", client_name, strlen(client_name))) 
+             usage();
+           if (!strncmp("root", client_name, strlen(client_name))) {
+               fprintf(stderr, "root is not a valid Administrator!\n\n");
+               usage();
+           }
+           if (retval = krb5_parse_name(client_name, &client)) {
+               fprintf(stderr, "Error Parsing User Specified Name Option!\n");
+               exit(1);
+           }
+       } 
+    }  /* switch */
+
+       /* Create credential cache for kadmin */
+    (void) sprintf(cache_name, "FILE:/tmp/tkt_adm_%d", getpid());
+
+    if ((retval = krb5_cc_resolve(cache_name, &cache))) {
+       fprintf(stderr, "Unable to Resolve Cache: !\n", cache_name);
+    }
+    
+    if ((retval = krb5_cc_initialize(cache, client))) {
+        fprintf(stderr, "Error initializing cache: %s!\n", cache_name);
+        exit(1);
+    }
+/*
+ *     Verify User by Obtaining Initial Credentials prior to Initial Link
+ */
+
+    if ((retval = get_first_ticket(cache, client))) {
+        (void) krb5_cc_destroy(cache);
+       exit(1);
+    }
+    /* my_creds has the necessary credentials for further processing:
+       Destroy credential cache for security reasons */
+    (void) krb5_cc_destroy(cache);
+    
+    requested_realm = (krb5_data *) &client->realm;
+
+
+       /* Initiate Link to Server */
+    if ((retval = adm5_init_link(requested_realm, &local_socket))) {
+       (void) krb5_cc_destroy(cache);
+       exit(1);
+    } 
+
+#ifdef unicos61
+#define SIZEOF_INADDR  SIZEOF_in_addr
+#else
+#define SIZEOF_INADDR sizeof(struct in_addr)
+#endif
+
+/* V4 kpasswd Protocol Hack
+ *     Necessary for ALL kadmind clients
+ */
+    {
+       int msg_length = 0;
+
+       retval = krb5_net_write(local_socket, (char *) &msg_length + 2, 2);
+       if (retval < 0) {
+           fprintf(stderr, "krb5_net_write failure!\n");
+            (void) krb5_cc_destroy(cache);
+           exit(1);
+       }
+    }
+
+    local_addr.addrtype = ADDRTYPE_INET;
+    local_addr.length = SIZEOF_INADDR ;
+    local_addr.contents = (krb5_octet *) &local_sin.sin_addr;
+
+    foreign_addr.addrtype = ADDRTYPE_INET;
+    foreign_addr.length = SIZEOF_INADDR ;
+    foreign_addr.contents = (krb5_octet *) &remote_sin.sin_addr;
+
+               /* compute checksum, using CRC-32 */
+    if (!(send_cksum.contents = (krb5_octet *)
+       malloc(krb5_checksum_size(CKSUMTYPE_CRC32)))) {
+        fprintf(stderr, "Insufficient Memory while Allocating Checksum!\n");
+        (void) krb5_cc_destroy(cache);
+        exit(1);
+    }
+
+               /* choose some random stuff to compute checksum from */
+       if (retval = krb5_calculate_checksum(CKSUMTYPE_CRC32,
+                                       ADM5_ADM_VERSION,
+                                       strlen(ADM5_ADM_VERSION),
+                                       0,
+                                       0, /* if length is 0, crc-32 doesn't
+                                               use the seed */
+                                       &send_cksum)) {
+        fprintf(stderr, "Error while Computing Checksum: %s!\n",
+               error_message(retval));
+       free(send_cksum.contents);
+        (void) krb5_cc_destroy(cache);
+        exit(1);
+    }
+
+    /* call Kerberos library routine to obtain an authenticator,
+       pass it over the socket to the server, and obtain mutual
+       authentication. */
+
+    if ((retval = krb5_sendauth((krb5_pointer) &local_socket,
+                       ADM_CPW_VERSION, 
+                       my_creds.client, 
+                       my_creds.server,
+                       AP_OPTS_MUTUAL_REQUIRED,
+                       &send_cksum,
+                       &my_creds,           
+                       0,
+                       &seqno, 
+                       0,           /* don't need a subsession key */
+                       &err_ret,
+                       &rep_ret))) {
+       fprintf(stderr, "Error while performing sendauth: %s!\n",
+                       error_message(retval));
+       free(send_cksum.contents);
+       exit(1);
+    }
+
+       /* Read back what the server has to say ... */
+    if (retval = krb5_read_message(&local_socket, &inbuf)){
+       fprintf(stderr, " Read Message Error: %s!\n",
+                       error_message(retval));
+       free(send_cksum.contents);
+        exit(1);
+    }
+
+    if ((inbuf.length != 2) || (inbuf.data[0] != KADMIND) ||
+                       (inbuf.data[1] != KADMSAG)){
+       fprintf(stderr, " Invalid ack from admin server.!\n");
+       free(send_cksum.contents);
+        exit(1);
+    }
+    free(inbuf.data);
+
+    if ((inbuf.data = (char *) calloc(1, 2)) == (char *) 0) {
+       fprintf(stderr, "No memory for command!\n");
+       free(send_cksum.contents);
+        exit(1);
+    }
+
+    inbuf.data[0] = KADMIN;
+    inbuf.data[1] = 0xff;
+    inbuf.length = 2;
+
+    if ((retval = krb5_mk_priv(&inbuf,
+                       ETYPE_DES_CBC_CRC,
+                       &my_creds.keyblock, 
+                       &local_addr, 
+                       &foreign_addr,
+                       seqno,
+                       KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                       0,
+                       0,
+                       &msg_data))) {
+       fprintf(stderr, "Error during First Message Encoding: %s!\n",
+                       error_message(retval));
+       free(inbuf.data);
+       free(send_cksum.contents);
+        exit(1);
+    }
+    free(inbuf.data);
+
+               /* write private message to server */
+    if (krb5_write_message(&local_socket, &msg_data)){
+       fprintf(stderr, "Write Error During First Message Transmission!\n");
+       free(send_cksum.contents);
+        exit(1);
+    } 
+    free(msg_data.data);
+
+    for ( ; ; ) {
+               /* Ok Now let's get the private message */
+       if (retval = krb5_read_message(&local_socket, &inbuf)){
+           fprintf(stderr, "Read Error During First Reply: %s!\n",
+                       error_message(retval));
+           free(send_cksum.contents);
+            exit(1);
+       }
+
+       if ((retval = krb5_rd_priv(&inbuf,
+                       &my_creds.keyblock,
+                       &foreign_addr, 
+                       &local_addr,
+                       rep_ret->seq_number, 
+                       KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                       0,
+                       0,
+                       &msg_data))) {
+           fprintf(stderr, "Error during First Read Decoding: %s!\n", 
+                       error_message(retval));
+           free(send_cksum.contents);
+            exit(1);
+       }
+       free(inbuf.data);
+
+       valid = 0;
+       princ_name[0] = '\0';
+repeat:
+       printf("\n\nCommand (add, cpw, del, inq, mod, addrnd, cpwrnd, addv4, cpwv4, q): ");
+       fgets(buffer, sizeof(buffer), stdin);
+       buffer[strlen(buffer) -1] = '\0';
+       sscanf(buffer,"%s %s", command_type, princ_name);
+       for (i = 0; command_type[i] != '\0'; i++)
+           if (isupper(command_type[i]))
+               command_type[i] = tolower(command_type[i]);
+       
+       if (!strcmp(command_type, "add")) {
+           valid++;
+           oper_type = ADDOPER;
+           if (retval = kadm_add_user(&my_creds, 
+                                      rep_ret,
+                                      &local_addr, 
+                                      &foreign_addr, 
+                                      &local_socket, 
+                                      &seqno,
+                                      oper_type,
+                                      princ_name)) break;
+       }
+       if (!strcmp(command_type, "cpw")) {
+           valid++;
+           oper_type = CHGOPER;
+           if (retval = kadm_cpw_user(&my_creds, 
+                                      rep_ret,
+                                      &local_addr, 
+                                      &foreign_addr, 
+                                      &local_socket, 
+                                      &seqno,
+                                      oper_type,
+                                      princ_name)) break;
+       }
+       if (!strcmp(command_type, "addrnd")) {
+           valid++;
+           if (retval = kadm_add_user_rnd(&my_creds, 
+                                          rep_ret,
+                                          &local_addr, 
+                                          &foreign_addr, 
+                                          &local_socket, 
+                                          &seqno,
+                                          princ_name)) break;
+       }
+       if (!strcmp(command_type, "cpwrnd")) {
+           valid++;
+           if (retval = kadm_cpw_user_rnd(&my_creds, 
+                                          rep_ret,
+                                          &local_addr, 
+                                          &foreign_addr, 
+                                          &local_socket, 
+                                          &seqno,
+                                          princ_name)) break;
+       }
+       if (!strcmp(command_type, "del")) {
+           valid++;
+           if (retval = kadm_del_user(&my_creds, 
+                                      rep_ret,
+                                      &local_addr, 
+                                      &foreign_addr, 
+                                      &local_socket, 
+                                      &seqno,
+                                      princ_name)) break;
+       }
+       if (!strcmp(command_type, "inq")) {
+           valid++;
+           if (retval = kadm_inq_user(&my_creds, 
+                                      rep_ret,
+                                      &local_addr, 
+                                      &foreign_addr, 
+                                      &local_socket, 
+                                      &seqno,
+                                      princ_name)) break;
+       }
+       if (!strcmp(command_type, "mod")) {
+           valid++;
+           if (retval = kadm_mod_user(&my_creds, 
+                                      rep_ret,
+                                      &local_addr, 
+                                      &foreign_addr, 
+                                      &local_socket, 
+                                      &seqno,
+                                      princ_name)) break;
+       }
+       if (!strcmp(command_type, "addv4")) {
+           valid++;
+           oper_type = AD4OPER;
+           if (retval = kadm_add_user(&my_creds, 
+                                      rep_ret,
+                                      &local_addr, 
+                                      &foreign_addr, 
+                                      &local_socket, 
+                                      &seqno,
+                                      oper_type,
+                                      princ_name)) break;
+       }
+       if (!strcmp(command_type, "cpwv4")) {
+           valid++;
+           oper_type = CH4OPER;
+           if (retval = kadm_cpw_user(&my_creds, 
+                                      rep_ret,
+                                      &local_addr, 
+                                      &foreign_addr, 
+                                      &local_socket, 
+                                      &seqno,
+                                      oper_type,
+                                      princ_name)) break;
+       }
+       if (!strcmp(command_type, "q")) { 
+           valid++;
+           retval = kadm_done(&my_creds, 
+                              rep_ret,
+                              &local_addr, 
+                              &foreign_addr, 
+                              &local_socket, 
+                              &seqno);
+           break;
+       }
+       
+       if (!valid) {
+           fprintf(stderr, "Invalid Input - Retry\n");
+           goto repeat;
+       }
+    }
+
+    if (retval) {
+       free(send_cksum.contents);
+        exit(1);
+    }
+
+               /* Ok Now let's get the final private message */
+    if (retval = krb5_read_message(&local_socket, &inbuf)){
+       fprintf(stderr, "Read Error During Final Reply: %s!\n",
+                        error_message(retval));
+       free(send_cksum.contents);
+        exit(1);
+    }
+     
+    if ((retval = krb5_rd_priv(&inbuf,
+                        &my_creds.keyblock,
+                        &foreign_addr,
+                        &local_addr,
+                        rep_ret->seq_number,
+                        KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                        0,
+                        0,
+                        &msg_data))) {
+       fprintf(stderr, "Error during Final Read Decoding :%s!\n",
+                        error_message(retval));
+       free(send_cksum.contents);
+       free(inbuf.data);
+       exit(1);
+    }
+    free(inbuf.data);
+    memcpy(&rd_priv_resp.appl_code, msg_data.data, 1);
+    memcpy(&rd_priv_resp.oper_code, msg_data.data + 1, 1);
+    memcpy(&rd_priv_resp.retn_code, msg_data.data + 2, 1);
+    free(msg_data.data);
+    if (!((rd_priv_resp.appl_code == KADMIN) &&
+                (rd_priv_resp.retn_code == KADMGOOD))) {
+       fprintf(stderr, "Generic Error During kadmin Termination!\n");
+       retval = 1;
+    } else {
+       fprintf(stderr, "\nHave a Good Day.\n\n");
+    }
+
+    free(send_cksum.contents);
+
+
+    if (retval) {
+       fprintf(stderr, "\n\nkadmin terminating - %s.\n\n", 
+               kadmind_kadmin_response[rd_priv_resp.retn_code]);
+       exit(1);
+    }
+    exit(0);
+}
+
+krb5_error_code
+get_first_ticket(DECLARG(krb5_ccache, cache),
+               DECLARG(krb5_principal, client))
+OLDDECLARG(krb5_ccache, cache)
+OLDDECLARG(krb5_principal, client)
+{
+    char prompt[255];                  /* for the password prompt */
+    
+    krb5_address **my_addresses;
+
+    char *client_name;
+    krb5_error_code retval;
+    char *password;
+    int  pwsize;
+    
+    if ((retval = krb5_unparse_name(client, &client_name))) {
+       fprintf(stderr, "Unable to Unparse Client Name!\n");
+       return(1);
+    }
+
+    if ((retval = krb5_os_localaddr(&my_addresses))) {
+       fprintf(stderr, "Unable to Get Principals Address!\n");
+       return(1);
+    }
+
+    memset((char *) &my_creds, 0, sizeof(my_creds));
+
+    my_creds.client = client;
+
+    if ((retval = krb5_build_principal_ext(&my_creds.server,
+                                        client->realm.length, 
+                                       client->realm.data,
+                                        strlen(CPWNAME),
+                                       CPWNAME,    /* kadmin */
+                                        client->realm.length,
+                                       client->realm.data, 
+                                          /* instance is <realm> */
+                                        0))) {
+        fprintf(stderr, "Error %s while building client name!\n");
+       krb5_free_addresses(my_addresses);
+        return(1);
+    }
+    
+    (void) sprintf(prompt,"Password for %s: ", (char *) client_name);
+
+    if ((password = (char *) calloc (1, 255)) == NULL) {
+        fprintf(stderr, "No Memory for Retrieving Admin Password!\n");
+        return(1);
+    }
+
+    pwsize = 255;
+    if ((retval = krb5_read_password(
+                                prompt,
+                                0,
+                                password,
+                                &pwsize) || pwsize == 0)) {
+       fprintf(stderr, "Error while reading password for '%s'!\n",
+                                client_name);
+       free(password);
+       krb5_free_addresses(my_addresses);
+       return(1);
+    }
+
+       /*      Build Request for Initial Credentials */
+    if ((retval = krb5_get_in_tkt_with_password(
+                       0,                      /* options */
+                       my_addresses,
+                       KRB5_PADATA_ENC_RANDOM, /* do random preauth */
+                       ETYPE_DES_CBC_CRC,      /* etype */
+                       KEYTYPE_DES,
+                       password,
+                       cache,
+                       &my_creds,
+                       0  ))) {
+            fprintf(stderr, "\nUnable to Get Initial Credentials : %s!\n",
+                        error_message(retval));
+           (void) memset(password, 0, pwsize);
+           free(password);
+           krb5_free_addresses(my_addresses);
+            return(1);
+    }
+        /* Do NOT Forget to zap password  */
+    memset((char *) password, 0, pwsize);
+    free(password);
+    krb5_free_addresses(my_addresses);
+    return(0);
+}
+
+krb5_error_code
+adm5_init_link( realm_of_server, local_socket)
+krb5_data *realm_of_server;
+int * local_socket;
+
+{
+    struct servent *service_process;          /* service we will talk to */
+    struct hostent *remote_host;              /* host we will talk to */
+    char **hostlist;
+    int namelen;
+    int i;
+
+    krb5_error_code retval;
+
+    /* clear out the structure first */
+    (void) memset((char *)&remote_sin, 0, sizeof(remote_sin));
+
+    if ((service_process = getservbyname(CPW_SNAME, "tcp")) == NULL) {
+       fprintf(stderr, "Unable to find Service (%s) Check services file!\n",
+               CPW_SNAME);
+       return(1);
+    }
+
+               /* Copy the Port Number */
+    remote_sin.sin_port = service_process->s_port;
+
+    hostlist = 0;
+
+               /* Identify all Hosts Associated with this Realm */
+    if ((retval = krb5_get_krbhst (realm_of_server, &hostlist))) {
+        fprintf(stderr, "krb5_get_krbhst: Unable to Determine Server Name!\n");
+        return(retval);
+    }
+
+    if (hostlist[0] == 0) {
+        fprintf(stderr, "No hosts found!\n");
+        return KRB5_REALM_UNKNOWN;
+    }
+
+    for (i=0; hostlist[i]; i++) {
+        remote_host = gethostbyname(hostlist[i]);
+        if (remote_host != 0) {
+
+               /* set up the address of the foreign socket for connect() */
+           remote_sin.sin_family = remote_host->h_addrtype;
+           (void) memcpy((char *) &remote_sin.sin_addr, 
+                       (char *) remote_host->h_addr,
+                       sizeof(remote_host->h_addr));
+           break;      /* Only Need one */
+       }
+    }
+
+    krb5_free_krbhst(hostlist);
+
+    /* open a TCP socket */
+    *local_socket = socket(PF_INET, SOCK_STREAM, 0);
+    if (*local_socket < 0) {
+       retval = errno;
+       fprintf(stderr, "Cannot Open Socket!\n");
+       return retval;
+    }
+    /* connect to the server */
+    if (connect(*local_socket, &remote_sin, sizeof(remote_sin)) < 0) {
+       retval = errno;
+       fprintf(stderr, "Cannot Connect to Socket!\n");
+       close(*local_socket);
+       return retval;
+    }
+
+    /* find out who I am, now that we are connected and therefore bound */
+    namelen = sizeof(local_sin);
+    if (getsockname(*local_socket, 
+               (struct sockaddr *) &local_sin, &namelen) < 0) {
+       retval = errno;
+       fprintf(stderr, "Cannot Perform getsockname!\n");
+       close(*local_socket);
+       return retval;
+    }
+       return 0;
+}
+
+void
+get_def_princ(client)
+     krb5_principal *client;
+{
+    krb5_ccache cache = NULL;
+    struct passwd *pw;
+    int retval;
+    char client_name[755];
+    krb5_flags cc_flags;
+
+    /* Identify Default Credentials Cache */
+    if (retval = krb5_cc_default(&cache)) {
+       fprintf(stderr, "Error while getting default ccache!\n");
+       exit(1);
+    }
+    
+    /*
+     *         Attempt to Modify Credentials Cache 
+     *         retval == 0 ==> ccache Exists - Use It 
+     *                 retval == ENOENT ==> No Entries, but ccache Exists 
+     *         retval != 0 ==> Assume ccache does NOT Exist 
+     */
+    cc_flags = 0;
+    if (retval = krb5_cc_set_flags(cache, cc_flags)) {
+       /* Search passwd file for client */
+       pw = getpwuid((int) getuid());
+       if (pw) {
+           (void) strcpy(client_name, pw->pw_name);
+           if (!strncmp("root", client_name, strlen(client_name))) {
+               fprintf(stderr,
+                       "root is not a valid Adimnistrator\n!\n");
+               usage();
+           }
+       } else {
+           fprintf(stderr, 
+                   "Unable to Identify Principal from Password File!\n");
+           retval = 1;
+           usage();
+       }
+       
+       /* Use this to get default_realm and format client_name */
+       if ((retval = krb5_parse_name(client_name, client))) {
+           fprintf(stderr, "Unable to Parse Client Name!\n");
+           usage();
+       }
+    } else {
+       /* Read Client from Cache */
+       if (retval = krb5_cc_get_principal(cache, client)) {
+           fprintf(stderr, 
+                   "Unable to Read Principal Credentials File!\n");
+           exit(1);
+       }
+       
+       if (!strncmp("root", (*client)->data[0].data, 
+                    (*client)->data[0].length)) {
+           fprintf(stderr, "root is not a valid Administrator\n!\n");
+           usage();
+       }
+       
+       (void) krb5_cc_close(cache);
+    }
+}
+
+usage()
+{
+    fprintf(stderr, "Usage:    ");
+    fprintf(stderr, "kadmin [-n] [Administrator name]\n\n");
+    fprintf(stderr, "  If an Administrator name is not supplied, kadmin ");
+    fprintf(stderr, "will first\n      attempt to locate the name from ");
+    fprintf(stderr, "the default ticket file, then\n   by using the ");
+    fprintf(stderr, "username from the 'passwd' file.\n\n");
+    fprintf(stderr, "  For Cross Realm Obtain a ticket for 'Administrator ");
+    fprintf(stderr, "name' in the\n    Destination realm or ");
+    fprintf(stderr, "specify the Destination Realm\n   as part of the ");
+    fprintf(stderr, "Administrator name option.\n\n");
+    fprintf(stderr, "  Note: If the Administrator Name is not ");
+    fprintf(stderr, "supplied, then the \n");
+    fprintf(stderr, "  '/admin' instance will be appended to the ");
+    fprintf(stderr, "default name unless\n");
+    fprintf(stderr, "  the -n option is used.\n\n");
+    exit(0);
+}
diff --git a/src/kadmin/client/kadmin_add.c b/src/kadmin/client/kadmin_add.c
new file mode 100644 (file)
index 0000000..425e26f
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ */
+
+/* 
+ * Sandia National Laboratories also makes no representations about the 
+ * suitability of the modifications, or additions to this software for 
+ * any purpose.  It is provided "as is" without express or implied warranty.
+ */
+
+#if !defined(lint) && !defined(SABER)
+static char rcsid_kadmin_add[] =
+  "$Header$";
+#endif /* lint */
+
+/*
+ * kadmin_add
+ * Perform Remote Kerberos Administrative Functions
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#ifndef __convex__
+#include <strings.h>
+#endif
+#include <com_err.h>
+
+#include <sys/param.h>
+
+#include <krb5/adm_defs.h>
+
+#include <krb5/krb5.h>
+#include <krb5/ext-proto.h>
+#include <krb5/los-proto.h>
+#include <krb5/kdb.h>
+#include <krb5/kdb_dbm.h>
+
+krb5_error_code
+  kadm_add_user(my_creds, rep_ret, local_addr, foreign_addr, 
+               local_socket, seqno, oper_type, principal)
+krb5_creds *my_creds;
+krb5_ap_rep_enc_part *rep_ret;
+krb5_address *local_addr, *foreign_addr;
+int *local_socket;
+krb5_int32 *seqno;
+int oper_type;
+char *principal;
+{
+    krb5_data msg_data, inbuf;
+    kadmin_requests rd_priv_resp;
+    char username[255];
+    char *password;
+    int pwsize;
+    int count;
+    krb5_error_code retval;     /* return code */
+    
+    if ((inbuf.data = (char *) calloc(1, 3 + sizeof(username))) == (char *) 0) {
+        fprintf(stderr, "No memory for command!\n");
+        return(1);
+    }
+    
+    inbuf.data[0] = KADMIN;
+    inbuf.data[1] = oper_type;
+    inbuf.data[2] = SENDDATA2;
+    
+    if (principal && principal[0] != '\0')
+       strcpy(username, principal);
+    else {
+       count = 0;
+       do {
+           fprintf(stdout, "\nName of Principal to be Added: ");
+           fgets(username, sizeof(username), stdin);
+           if (username[0] == '\n')
+               fprintf(stderr, "Invalid Principal name!\n");
+           count++;
+       } while (username[0] == '\n' && count < 3);
+    }
+
+    if (username[0] == '\n') {
+       fprintf(stderr, "Aborting!!\n\n");
+       return(1);
+    }
+
+    username[strlen(username) -1] = '\0';
+    
+    (void) memcpy( inbuf.data + 3, username, strlen(username));
+    inbuf.length = strlen(username) + 3;
+    
+    if ((retval = krb5_mk_priv(&inbuf,
+                              ETYPE_DES_CBC_CRC,
+                              &my_creds->keyblock, 
+                              local_addr, 
+                              foreign_addr,
+                              *seqno,
+                              KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                              0,
+                              0,
+                              &msg_data))) {
+        fprintf(stderr, "Error during Second Message Encoding: %s!\n",
+               error_message(retval));
+       free(inbuf.data);
+        return(1);
+    }
+    free(inbuf.data);
+    
+    /* write private message to server */
+    if (krb5_write_message(local_socket, &msg_data)){
+        fprintf(stderr, "Write Error During Second Message Transmission!\n");
+        return(1);
+    } 
+    
+    free(msg_data.data);
+    
+     if (retval = krb5_read_message(local_socket, &inbuf)){
+        fprintf(stderr, "Read Error During Second Reply: %s!\n",
+               error_message(retval));
+        return(1);
+    }
+    
+    if (retval = krb5_rd_priv(&inbuf,
+                              &my_creds->keyblock,
+                              foreign_addr, 
+                              local_addr,
+                              rep_ret->seq_number, 
+                              KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                              0,
+                              0,
+                              &msg_data)) {
+        fprintf(stderr, "Error during Second Read Decoding :%s!\n", 
+               error_message(retval));
+       free(inbuf.data);
+        return(1);
+    }
+    free(inbuf.data);
+    
+    if (msg_data.data[2] == KADMBAD) {
+       fprintf(stderr, "Principal Already Exists!\n\n");
+       return(0);
+    }
+    
+#ifdef MACH_PASS
+    pwsize = msg_data.length;
+    if ((password = (char *) calloc (1, pwsize)) == (char *) 0) {
+       fprintf(stderr, "No Memory for allocation of password!\n");
+       retval = 1;
+       free(msg_data.data);
+       return(1);
+    }
+    
+    memcpy(password, msg_data.data, pwsize);
+    memset(msg_data.data, 0, pwsize);
+    password[pwsize] = '\0';
+    fprintf(stdout, "\nPassword for \"%s\" is \"%s\"\n", username, password);
+    memset(password, 0, pwsize);
+    free(password);
+    fprintf(stdout, "\nThis password can only be used to execute kpasswd\n\n");
+    
+    free(msg_data.data);
+    
+    if ((inbuf.data = (char *) calloc(1, 2)) == (char *) 0) {
+        fprintf(stderr, "No memory for command!\n");
+        return(1);
+    }
+
+    inbuf.data[0] = KADMIN;
+    inbuf.data[1] = KADMGOOD;
+    inbuf.length = 2;
+   
+#else
+
+    if ((password = (char *) calloc (1, ADM_MAX_PW_LENGTH+1)) == (char *) 0) {
+       fprintf(stderr, "No Memory for allocation of password!\n");
+       return(1);
+    }
+
+    pwsize = ADM_MAX_PW_LENGTH+1;
+    
+    putchar('\n');
+    if (retval = krb5_read_password(
+                                    DEFAULT_PWD_STRING1,
+                                    DEFAULT_PWD_STRING2,
+                                    password,
+                                    &pwsize)) {
+       fprintf(stderr, "Error while reading new password for %s: %s!\n",
+               username, error_message(retval));
+       (void) memset((char *) password, 0, ADM_MAX_PW_LENGTH+1);
+       free(password);
+       return(1);
+    }
+    
+    if ((inbuf.data = (char *) calloc(1, strlen(password) + 1)) == (char *) 0) {
+       fprintf(stderr, "No Memory for allocation of buffer!\n");
+       (void) memset((char *) password, 0, ADM_MAX_PW_LENGTH+1);
+       free(password);
+        return(1);
+    }
+     
+    inbuf.length = strlen(password);
+    (void) memcpy(inbuf.data, password, strlen(password));
+    free(password);
+
+#endif /* MACH_PASS */
+
+    if ((retval = krb5_mk_priv(&inbuf,
+                              ETYPE_DES_CBC_CRC,
+                              &my_creds->keyblock, 
+                              local_addr, 
+                              foreign_addr,
+                              *seqno,
+                              KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                              0,
+                              0,
+                              &msg_data))) {
+        fprintf(stderr, "Error during Second Message Encoding: %s!\n",
+               error_message(retval));
+       free(inbuf.data);
+        return(1);
+    }
+    free(inbuf.data);
+    
+    /* write private message to server */
+    if (krb5_write_message(local_socket, &msg_data)){
+        fprintf(stderr, "Write Error During Second Message Transmission!\n");
+        return(1);
+    } 
+    free(msg_data.data);
+    
+    /* Ok Now let's get the final private message */
+    if (retval = krb5_read_message(local_socket, &inbuf)){
+        fprintf(stderr, "Read Error During Final Reply: %s!\n",
+               error_message(retval));
+        retval = 1;
+    }
+    
+    if ((retval = krb5_rd_priv(&inbuf,
+                              &my_creds->keyblock,
+                              foreign_addr,
+                              local_addr,
+                              rep_ret->seq_number,
+                              KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                              0,
+                              0,
+                              &msg_data))) {
+        fprintf(stderr, "Error during Final Read Decoding :%s!\n",
+               error_message(retval));
+       free(inbuf.data);
+        return(1);
+    }
+    free(inbuf.data);
+    
+    memcpy(&rd_priv_resp.appl_code, msg_data.data, 1);
+    memcpy(&rd_priv_resp.oper_code, msg_data.data + 1, 1);
+    memcpy(&rd_priv_resp.retn_code, msg_data.data + 2, 1);
+    
+    free(msg_data.data);                                   
+    
+    if (!((rd_priv_resp.appl_code == KADMIN) &&
+         (rd_priv_resp.retn_code == KADMGOOD))) {
+        fprintf(stderr, "Generic Error During kadmin Addition!\n");
+        retval = 1;
+    } else {
+        fprintf(stderr, "\nDatabase Addition Successful.\n");
+    }
+    return(retval);
+}
diff --git a/src/kadmin/client/kadmin_adr.c b/src/kadmin/client/kadmin_adr.c
new file mode 100644 (file)
index 0000000..e52e80a
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ */
+
+/* 
+ * Sandia National Laboratories also makes no representations about the 
+ * suitability of the modifications, or additions to this software for 
+ * any purpose.  It is provided "as is" without express or implied warranty.
+ */
+
+#if !defined(lint) && !defined(SABER)
+static char rcsid_kadmin_adr[] =
+  "$Header$";
+#endif /* lint */
+
+/*
+ * kadmin_adr
+ * Perform Remote Kerberos Administrative Functions
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#ifndef __convex__
+#include <strings.h>
+#endif
+#include <com_err.h>
+
+#include <sys/param.h>
+
+#include <krb5/adm_defs.h>
+
+#include <krb5/krb5.h>
+#include <krb5/ext-proto.h>
+#include <krb5/los-proto.h>
+#include <krb5/kdb.h>
+#include <krb5/kdb_dbm.h>
+
+krb5_error_code
+  kadm_add_user_rnd(my_creds, rep_ret, local_addr, foreign_addr, 
+                   local_socket, seqno, principal)
+krb5_creds *my_creds;
+krb5_ap_rep_enc_part *rep_ret;
+krb5_address *local_addr, *foreign_addr;
+int *local_socket;
+krb5_int32 *seqno;
+char *principal;
+{
+    krb5_data msg_data, inbuf;
+    kadmin_requests rd_priv_resp;
+    char username[755];
+    int count;
+    krb5_error_code retval;     /* return code */
+    
+    if ((inbuf.data = (char *) calloc(1, 3 + sizeof(username))) == (char *) 0) {
+        fprintf(stderr, "No memory for command!\n");
+        return(1);
+    }
+    
+    inbuf.data[0] = KADMIN;
+    inbuf.data[1] = ADROPER;
+    inbuf.data[2] = SENDDATA2;
+
+    if (principal && principal[0] != '\0')
+       strcpy(username, principal);
+    else {
+       count = 0;
+       do {
+           fprintf(stdout, "\nName of Principal to be Added: ");
+           fgets(username, sizeof(username), stdin);
+           if (username[0] == '\n')
+               fprintf(stderr, "Invalid Principal name!\n");
+           count++;
+       }
+       while (username[0] == '\n' && count < 3);
+
+       if (username[0] == '\n') {
+           fprintf(stderr, "Aborting!!\n\n");
+           return(1);
+       }
+       username[strlen(username) -1] = '\0';
+    }
+    
+    
+    (void) memcpy( inbuf.data + 3, username, strlen(username));
+    inbuf.length = strlen(username) + 3;
+    
+    if ((retval = krb5_mk_priv(&inbuf,
+                              ETYPE_DES_CBC_CRC,
+                              &my_creds->keyblock, 
+                              local_addr, 
+                              foreign_addr,
+                              *seqno,
+                              KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                              0,
+                              0,
+                              &msg_data))) {
+        fprintf(stderr, "Error during Second Message Encoding: %s!\n",
+               error_message(retval));
+       free(inbuf.data);
+        return(1);
+    }
+    free(inbuf.data);
+    
+    /* write private message to server */
+    if (krb5_write_message(local_socket, &msg_data)){
+        fprintf(stderr, "Write Error During Second Message Transmission!\n");
+        return(1);
+    } 
+    
+    free(msg_data.data);
+    
+    /* Ok Now let's get the final private message */
+    if (retval = krb5_read_message(local_socket, &inbuf)){
+        fprintf(stderr, "Read Error During Final Reply: %s!\n",
+               error_message(retval));
+        retval = 1;
+    }
+    
+    if ((retval = krb5_rd_priv(&inbuf,
+                              &my_creds->keyblock,
+                              foreign_addr,
+                              local_addr,
+                              rep_ret->seq_number,
+                              KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                              0,
+                              0,
+                              &msg_data))) {
+        fprintf(stderr, "Error during Final Read Decoding :%s!\n",
+               error_message(retval));
+       free(inbuf.data);
+        return(1);
+    }
+    free(inbuf.data);
+    
+    memcpy(&rd_priv_resp.appl_code, msg_data.data, 1);
+    memcpy(&rd_priv_resp.oper_code, msg_data.data + 1, 1);
+    memcpy(&rd_priv_resp.retn_code, msg_data.data + 2, 1);
+    
+    free(msg_data.data);                                   
+    
+    if (!((rd_priv_resp.appl_code == KADMIN) &&
+         (rd_priv_resp.retn_code == KADMGOOD)))
+      fprintf(stderr, "Principal already exists!\n");
+    else
+      fprintf(stderr, "\nDatabase Addition Successful.\n");
+
+    return(retval);
+}
diff --git a/src/kadmin/client/kadmin_cpr.c b/src/kadmin/client/kadmin_cpr.c
new file mode 100644 (file)
index 0000000..41f53eb
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ */
+
+/* 
+ * Sandia National Laboratories also makes no representations about the 
+ * suitability of the modifications, or additions to this software for 
+ * any purpose.  It is provided "as is" without express or implied warranty.
+ */
+
+#if !defined(lint) && !defined(SABER)
+static char rcsid_kadmin_cpr[] =
+    "$Header$";
+#endif /* lint */
+
+/*
+ * kadmin_cpr
+ * Perform Remote Kerberos Administrative Functions
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <signal.h>
+#ifndef __convex__
+#include <strings.h>
+#endif
+#include <com_err.h>
+
+#include <sys/param.h>
+
+#include <krb5/adm_defs.h>
+
+#include <krb5/krb5.h>
+#include <krb5/ext-proto.h>
+#include <krb5/los-proto.h>
+#include <krb5/kdb.h>
+#include <krb5/kdb_dbm.h>
+
+krb5_error_code
+kadm_cpw_user_rnd(my_creds, rep_ret, local_addr, foreign_addr, 
+                 local_socket, seqno, principal)
+krb5_creds *my_creds;
+krb5_ap_rep_enc_part *rep_ret;
+krb5_address *local_addr, *foreign_addr;
+int *local_socket;
+krb5_int32 *seqno;
+char *principal;
+{
+    krb5_data msg_data, inbuf;
+    kadmin_requests rd_priv_resp;
+    char username[755];
+    int count;
+    krb5_error_code retval;     /* return code */
+
+    if ((inbuf.data = (char *) calloc(1, 3 + sizeof(username))) == (char *) 0) {        fprintf(stderr, "No memory for command!\n");
+        exit(1);
+    }
+
+    inbuf.data[0] = KADMIN;
+    inbuf.data[1] = CHROPER;
+    inbuf.data[2] = SENDDATA2;
+
+    if (principal && principal[0] != '\0')
+      strcpy(username, principal);
+    else {
+       count = 0;
+       do {
+           fprintf(stdout, 
+                   "\nName of Principal Whose Password is to Change: ");
+           fgets(username, sizeof(username), stdin);
+           if (username[0] == '\n')
+               fprintf(stderr, "Invalid Principal name!\n");
+           count++;
+       }
+       while (username[0] == '\n' && count < 3);
+
+       if (username[0] == '\n') {
+           fprintf(stderr, "Aborting!!\n\n");
+           return(1);
+       }
+       username[strlen(username) -1] = '\0';
+    }
+
+    (void) memcpy( inbuf.data + 3, username, strlen(username));
+    inbuf.length = strlen(username) + 3;
+
+       /* Transmit Principal Name */
+    if ((retval = krb5_mk_priv(&inbuf,
+                       ETYPE_DES_CBC_CRC,
+                       &my_creds->keyblock, 
+                       local_addr, 
+                       foreign_addr,
+                       *seqno,
+                       KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                       0,
+                       0,
+                       &msg_data))) {
+        fprintf(stderr, "Error during Second Message Encoding: %s!\n",
+                       error_message(retval));
+       free(inbuf.data);
+        return(1);
+    }
+    free(inbuf.data);
+
+    /* write private message to server */
+    if (krb5_write_message(local_socket, &msg_data)){
+        fprintf(stderr, "Write Error During Second Message Transmission!\n");
+        return(1);
+    } 
+    free(msg_data.data);
+
+    /* Ok Now let's get the final private message */
+    if (retval = krb5_read_message(local_socket, &inbuf)){
+        fprintf(stderr, "Read Error During Final Reply: %s!\n",
+                        error_message(retval));
+        retval = 1;
+    }
+    if ((retval = krb5_rd_priv(&inbuf,
+                        &my_creds->keyblock,
+                        foreign_addr,
+                        local_addr,
+                        rep_ret->seq_number,
+                        KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                        0,
+                        0,
+                        &msg_data))) {
+        fprintf(stderr, "Error during Final Read Decoding :%s!\n",
+                        error_message(retval));
+        free(inbuf.data);
+        return(1);
+    }
+    free(inbuf.data);
+
+    memcpy(&rd_priv_resp.appl_code, msg_data.data, 1);
+    memcpy(&rd_priv_resp.oper_code, msg_data.data + 1, 1);
+    memcpy(&rd_priv_resp.retn_code, msg_data.data + 2, 1);
+    free(msg_data.data);
+    if (!((rd_priv_resp.appl_code == KADMIN) &&
+               (rd_priv_resp.retn_code == KADMGOOD)))
+      fprintf(stderr, "Principal does NOT exist!\n");
+    else
+      fprintf(stderr, "\nPassword Modification Successful.\n");
+
+    return(0);
+}
+
+
diff --git a/src/kadmin/client/kadmin_cpw.c b/src/kadmin/client/kadmin_cpw.c
new file mode 100644 (file)
index 0000000..697e1bd
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ */
+
+/* 
+ * Sandia National Laboratories also makes no representations about the 
+ * suitability of the modifications, or additions to this software for 
+ * any purpose.  It is provided "as is" without express or implied warranty.
+ */
+
+#if !defined(lint) && !defined(SABER)
+static char rcsid_kadmin_cpw[] =
+    "$Header$";
+#endif /* lint */
+
+/*
+ * kadmin_cpw
+ * Perform Remote Kerberos Administrative Functions
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <signal.h>
+#ifndef __convex__
+#include <strings.h>
+#endif
+#include <com_err.h>
+
+#include <sys/param.h>
+
+#include <krb5/adm_defs.h>
+
+#include <krb5/krb5.h>
+#include <krb5/ext-proto.h>
+#include <krb5/los-proto.h>
+#include <krb5/kdb.h>
+#include <krb5/kdb_dbm.h>
+
+krb5_error_code
+kadm_cpw_user(my_creds, rep_ret, local_addr, foreign_addr, 
+             local_socket, seqno, oper_type, principal)
+krb5_creds *my_creds;
+krb5_ap_rep_enc_part *rep_ret;
+krb5_address *local_addr, *foreign_addr;
+int *local_socket;
+krb5_int32 *seqno;
+int oper_type;
+char *principal;
+{
+    krb5_data msg_data, inbuf;
+    kadmin_requests rd_priv_resp;
+    char username[255];
+    char *password;
+    int pwsize;
+    int count;
+    krb5_error_code retval;     /* return code */
+
+    if ((inbuf.data = (char *) calloc(1, 3 + sizeof(username))) == (char *) 0) {        fprintf(stderr, "No memory for command!\n");
+        exit(1);
+    }
+
+    inbuf.data[0] = KADMIN;
+    inbuf.data[1] = oper_type;
+    inbuf.data[2] = SENDDATA2;
+
+    if (principal && principal[0] != '\0')
+      strcpy(username, principal);
+    else {
+       count = 0;
+       do {
+           fprintf(stdout, 
+                   "\nName of Principal Whose Password is to Change: ");
+           fgets(username, sizeof(username), stdin);
+           if (username[0] == '\n')
+               fprintf(stderr, "Invalid Principal name!\n");
+           count++;
+       }
+       while (username[0] == '\n' && count < 3);
+
+       if (username[0] == '\n') {
+           fprintf(stderr, "Aborting!!\n\n");
+           return(1);
+       }
+
+       username[strlen(username) -1] = '\0';
+    }
+    
+    (void) memcpy( inbuf.data + 3, username, strlen(username));
+    inbuf.length = strlen(username) + 3;
+
+       /* Transmit Principal Name */
+    if ((retval = krb5_mk_priv(&inbuf,
+                       ETYPE_DES_CBC_CRC,
+                       &my_creds->keyblock, 
+                       local_addr, 
+                       foreign_addr,
+                       *seqno,
+                       KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                       0,
+                       0,
+                       &msg_data))) {
+        fprintf(stderr, "Error during Second Message Encoding: %s!\n",
+                       error_message(retval));
+       free(inbuf.data);
+        return(1);
+    }
+    free(inbuf.data);
+
+    /* write private message to server */
+    if (krb5_write_message(local_socket, &msg_data)){
+        fprintf(stderr, "Write Error During Second Message Transmission!\n");
+        return(1);
+    } 
+    free(msg_data.data);
+
+    if (retval = krb5_read_message(local_socket, &inbuf)){
+        fprintf(stderr, "Read Error During Second Reply: %s!\n",
+                       error_message(retval));
+        return(1);
+    }
+
+    if ((retval = krb5_rd_priv(&inbuf,
+                       &my_creds->keyblock,
+                       foreign_addr, 
+                       local_addr,
+                       rep_ret->seq_number, 
+                       KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                       0,
+                       0,
+                       &msg_data))) {
+        fprintf(stderr, "Error during Second Read Decoding :%s!\n", 
+                       error_message(retval));
+       free(inbuf.data);
+        return(1);
+    }
+    free(inbuf.data);
+
+    if (msg_data.data[2] == KADMBAD) {
+        fprintf(stderr, "Principal Does NOT Exist!\n\n");
+        return(0);
+    }
+
+    if ((oper_type == CHGOPER && msg_data.data[3] == KRB5_KDB_SALTTYPE_V4) ||
+       (oper_type == CH4OPER && msg_data.data[3] == KRB5_KDB_SALTTYPE_NORMAL))
+      fprintf(stderr, "WARNING: Changing Principal Salt type to %s!\n",
+             (msg_data.data[3] == KRB5_KDB_SALTTYPE_V4) ? 
+             "Version 5 Normal" : "Version 4");
+
+#ifdef MACH_PASS /* Machine-generated passwords */
+    pwsize = msg_data.length;
+    if ((password = (char *) calloc (1, pwsize)) == (char *) 0) {
+        fprintf(stderr, "No Memory for allocation of password!\n");
+        return(1);
+    }
+
+    memcpy(password, msg_data.data, pwsize);
+    memset(msg_data.data, 0, pwsize);
+    free(msg_data.data);
+    password[pwsize] = '\0';
+    fprintf(stdout, "\nPassword for \"%s\" is \"%s\"\n", username, password);
+    memset(password, 0, pwsize);
+    free(password);
+    fprintf(stdout, "\nThis password can only be used to execute kpasswd\n\n");
+    if ((inbuf.data = (char *) calloc(1, 2)) == (char *) 0) {
+        fprintf(stderr, "No memory for command!\n");
+        return(1);
+    }
+
+    inbuf.data[0] = KADMIN;
+    inbuf.data[1] = KADMGOOD;
+    inbuf.length = 2;
+
+#else
+
+    if ((password = (char *) calloc (1, ADM_MAX_PW_LENGTH+1)) == (char *) 0) {
+       fprintf(stderr, "No Memory for allocation of password!\n");
+       return(1);
+    }
+    
+    pwsize = ADM_MAX_PW_LENGTH+1;
+    
+    putchar('\n');
+    if ((retval = krb5_read_password(
+                                    DEFAULT_PWD_STRING1,
+                                    DEFAULT_PWD_STRING2,
+                                    password,
+                                    &pwsize))) {
+       fprintf(stderr, "Error while reading new password for %s: %s!\n",
+               username, error_message(retval));
+       (void) memset((char *) password, 0, ADM_MAX_PW_LENGTH+1);
+       free(password);
+       return(1);
+    }
+    
+    if ((inbuf.data = (char *) calloc (1, strlen(password) + 1)) == 
+       (char *) 0) {
+       fprintf(stderr, "No Memory for allocation of buffer!\n");
+       (void) memset((char *) password, 0, ADM_MAX_PW_LENGTH+1);
+       free(password);
+       return(1);              /* No Memory */
+    }
+    
+    inbuf.length = strlen(password);
+    (void) memcpy(inbuf.data, password, strlen(password));
+    free(password);
+
+#endif /* MACH_PASS */
+
+    if ((retval = krb5_mk_priv(&inbuf,
+                        ETYPE_DES_CBC_CRC,
+                        &my_creds->keyblock,
+                        local_addr,
+                        foreign_addr,
+                        *seqno,
+                        KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                        0,
+                        0,
+                        &msg_data))) {
+        fprintf(stderr, "Error during Second Message Encoding: %s!\n",
+                        error_message(retval));
+       free(inbuf.data);
+        return(1);
+    }
+    free(inbuf.data);
+         /* write private message to server */
+    if (krb5_write_message(local_socket, &msg_data)){
+        fprintf(stderr, "Write Error During Second Message Transmission!\n");
+        return(1);
+    }
+    free(msg_data.data);
+
+    /* Ok Now let's get the final private message */
+    if (retval = krb5_read_message(local_socket, &inbuf)){
+        fprintf(stderr, "Read Error During Final Reply: %s!\n",
+                        error_message(retval));
+        retval = 1;
+    }
+    if ((retval = krb5_rd_priv(&inbuf,
+                        &my_creds->keyblock,
+                        foreign_addr,
+                        local_addr,
+                        rep_ret->seq_number,
+                        KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                        0,
+                        0,
+                        &msg_data))) {
+        fprintf(stderr, "Error during Final Read Decoding :%s!\n",
+                        error_message(retval));
+        free(inbuf.data);
+        return(1);
+    }
+    free(inbuf.data);
+
+    memcpy(&rd_priv_resp.appl_code, msg_data.data, 1);
+    memcpy(&rd_priv_resp.oper_code, msg_data.data + 1, 1);
+    memcpy(&rd_priv_resp.retn_code, msg_data.data + 2, 1);
+    free(msg_data.data);
+    if (!((rd_priv_resp.appl_code == KADMIN) &&
+               (rd_priv_resp.retn_code == KADMGOOD))) {
+       fprintf(stderr, "Generic Error During kadmin Password Modification!\n");
+       return(1);
+    } else {
+        fprintf(stderr, "\nPassword Modification Successful.\n");
+    }
+    return(0);
+}
diff --git a/src/kadmin/client/kadmin_del.c b/src/kadmin/client/kadmin_del.c
new file mode 100644 (file)
index 0000000..c76aa1e
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ */
+
+/* 
+ * Sandia National Laboratories also makes no representations about the 
+ * suitability of the modifications, or additions to this software for 
+ * any purpose.  It is provided "as is" without express or implied warranty.
+ */
+
+#if !defined(lint) && !defined(SABER)
+static char rcsid_kadmin_del[] =
+    "$Header$";
+#endif /* lint */
+
+/*
+ * kadmin_del
+ * Perform Remote Kerberos Administrative Functions
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#ifndef __convex__
+#include <strings.h>
+#endif
+#include <com_err.h>
+
+#include <krb5/adm_defs.h>
+
+#include <krb5/krb5.h>
+#include <krb5/ext-proto.h>
+#include <krb5/los-proto.h>
+#include <krb5/kdb.h>
+#include <krb5/kdb_dbm.h>
+
+krb5_error_code
+kadm_del_user(my_creds, rep_ret, local_addr, foreign_addr, 
+             local_socket, seqno, principal)
+krb5_creds *my_creds;
+krb5_ap_rep_enc_part *rep_ret;
+krb5_address *local_addr, *foreign_addr;
+int *local_socket;
+krb5_int32 *seqno;
+char *principal;
+{
+    krb5_data msg_data, inbuf;
+    kadmin_requests rd_priv_resp;
+    char username[755];
+    int count;
+    krb5_error_code retval;     /* return code */
+
+    if ((inbuf.data = (char *) calloc(1, 3 + sizeof(username))) == (char *) 0) {
+        fprintf(stderr, "No memory for command!\n");
+        return(1);
+    }
+
+    inbuf.data[0] = KADMIN;
+    inbuf.data[1] = DELOPER;
+    inbuf.data[2] = SENDDATA2;
+
+    if (principal && principal[0] != '\0')
+       strcpy(username, principal);
+    else {
+       count = 0;
+       do {
+           fprintf(stdout, "\nName of Principal to be Deleted: ");
+           fgets(username, sizeof(username), stdin);
+           if (username[0] == '\n')
+               fprintf(stderr, "Invalid Principal name!\n");
+           count++;
+       }
+       while (username[0] == '\n' && count < 3);
+       
+       if (username[0] == '\n') {
+           fprintf(stderr, "Aborting!!\n\n");
+           return(1);
+       }
+
+       username[strlen(username) -1] = '\0';
+    }
+    
+   (void) memcpy( inbuf.data + 3, username, strlen(username));
+    inbuf.length = strlen(username) + 3;
+
+    if ((retval = krb5_mk_priv(&inbuf,
+                       ETYPE_DES_CBC_CRC,
+                       &my_creds->keyblock, 
+                       local_addr, 
+                       foreign_addr,
+                       *seqno,
+                       KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                       0,
+                       0,
+                       &msg_data))) {
+        fprintf(stderr, "Error during Second Message Encoding: %s!\n",
+                       error_message(retval));
+        free(inbuf.data);
+        return(1);
+    }
+    free(inbuf.data);
+
+    /* write private message to server */
+    if (krb5_write_message(local_socket, &msg_data)){
+        fprintf(stderr, "Write Error During Second Message Transmission!\n");
+        return(1);
+    } 
+    free(msg_data.data);
+
+         /* Ok Now let's get the final private message */ 
+    if (retval = krb5_read_message(local_socket, &inbuf)){
+        fprintf(stderr, "Read Error During Final Reply: %s!\n",
+                       error_message(retval));
+        return(1);
+    }
+
+    if ((retval = krb5_rd_priv(&inbuf,
+                       &my_creds->keyblock,
+                       foreign_addr, 
+                       local_addr,
+                       rep_ret->seq_number, 
+                       KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                       0,
+                       0,
+                       &msg_data))) {
+        fprintf(stderr, "Error during Second Decoding :%s!\n", 
+                       error_message(retval));
+        return(1);
+    }
+
+    memcpy(&rd_priv_resp.appl_code, msg_data.data, 1);
+    memcpy(&rd_priv_resp.oper_code, msg_data.data + 1, 1);
+    memcpy(&rd_priv_resp.retn_code, msg_data.data + 2, 1);
+
+    free(inbuf.data);
+    free(msg_data.data);
+    if (!((rd_priv_resp.appl_code == KADMIN) &&
+               (rd_priv_resp.retn_code == KADMGOOD)))
+      fprintf(stderr, "Principal Does NOT Exist!\n");
+    else
+      fprintf(stderr, "\nDatabase Deletion Successful.\n");
+
+    return(0);
+}
diff --git a/src/kadmin/client/kadmin_done.c b/src/kadmin/client/kadmin_done.c
new file mode 100644 (file)
index 0000000..7ae8d57
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ */
+
+/* 
+ * Sandia National Laboratories also makes no representations about the 
+ * suitability of the modifications, or additions to this software for 
+ * any purpose.  It is provided "as is" without express or implied warranty.
+ */
+
+#if !defined(lint) && !defined(SABER)
+static char rcsid_kadmin_done[] =
+    "$Header$";
+#endif /* lint */
+
+/*
+ * kadmin_done
+ * Perform Remote Kerberos Administrative Functions
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#ifndef __convex__
+#include <strings.h>
+#endif
+#include <com_err.h>
+
+#include <krb5/adm_defs.h>
+
+#include <krb5/krb5.h>
+#include <krb5/ext-proto.h>
+#include <krb5/los-proto.h>
+#include <krb5/kdb.h>
+#include <krb5/kdb_dbm.h>
+
+krb5_error_code
+kadm_done(my_creds, rep_ret, local_addr, foreign_addr, local_socket, seqno)
+krb5_creds *my_creds;
+krb5_ap_rep_enc_part *rep_ret;
+krb5_address *local_addr, *foreign_addr;
+int *local_socket;
+krb5_int32 *seqno;
+{
+    krb5_data msg_data, inbuf;
+    krb5_error_code retval;     /* return code */
+
+    /* XXX 755 was sizeof( char username[755]) */
+    if ((inbuf.data = (char *) calloc(1, 8 + 755)) == (char *) 0) {
+       fprintf(stderr, "No memory for command!\n");
+       exit(1);
+    }
+
+    inbuf.data[0] = KADMIN;
+    inbuf.data[1] = COMPLETE;
+    inbuf.data[2] = SENDDATA2;
+    inbuf.data[3] = 0xff;
+    (void) memset( inbuf.data + 4, 0, 4);
+    inbuf.length = 16;
+
+    if ((retval = krb5_mk_priv(&inbuf,
+                       ETYPE_DES_CBC_CRC,
+                       &my_creds->keyblock, 
+                       local_addr, 
+                       foreign_addr,
+                       *seqno,
+                       KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                       0,
+                       0,
+                       &msg_data))) {
+        fprintf(stderr, "Error during Second Message Encoding: %s!\n",
+                       error_message(retval));
+        return(1);
+    }
+    free(inbuf.data);
+
+    /* write private message to server */
+    if (krb5_write_message(local_socket, &msg_data)){
+        fprintf(stderr, "Write Error During Second Message Transmission!\n");
+        return(1);
+    } 
+    free(msg_data.data);
+    return(0);
+}
diff --git a/src/kadmin/client/kadmin_inq.c b/src/kadmin/client/kadmin_inq.c
new file mode 100644 (file)
index 0000000..0b7b042
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ */
+
+/* 
+ * Sandia National Laboratories also makes no representations about the 
+ * suitability of the modifications, or additions to this software for 
+ * any purpose.  It is provided "as is" without express or implied warranty.
+ */
+
+#if !defined(lint) && !defined(SABER)
+static char rcsid_kadmin_inq[] =
+    "$Header$";
+#endif /* lint */
+
+/*
+ * kadmin_inq
+ * Perform Remote Kerberos Administrative Functions
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <signal.h>
+#ifndef __convex__
+#include <strings.h>
+#endif
+#include <com_err.h>
+
+#include <krb5/adm_defs.h>
+
+#include <krb5/krb5.h>
+#include <krb5/ext-proto.h>
+#include <krb5/los-proto.h>
+#include <krb5/kdb.h>
+#include <krb5/kdb_dbm.h>
+
+krb5_error_code
+kadm_inq_user(my_creds, rep_ret, local_addr, foreign_addr, 
+             local_socket, seqno, principal)
+krb5_creds *my_creds;
+krb5_ap_rep_enc_part *rep_ret;
+krb5_address *local_addr, *foreign_addr;
+int *local_socket;
+krb5_int32 *seqno;
+char *principal;
+{
+    krb5_data msg_data, inbuf;
+    kadmin_requests rd_priv_resp;
+    char username[755];
+    int count;
+    krb5_error_code retval;     /* return code */
+
+    char *my_data;
+
+    if ((inbuf.data = (char *) calloc(1, 3 + sizeof(username))) == (char *) 0) {
+        fprintf(stderr, "No memory for command!\n");
+        return(1);
+    }
+
+    inbuf.data[0] = KADMIN;
+    inbuf.data[1] = INQOPER;
+    inbuf.data[2] = SENDDATA2;
+    
+    if (principal && principal[0] != '\0')
+       strcpy(username, principal);
+    else {
+       count = 0;
+       do {
+           fprintf(stdout, "\nName of Principal to be Displayed: ");
+           fgets(username, sizeof(username), stdin);
+           if (username[0] == '\n')
+               fprintf(stderr, "Invalid Principal name!\n");
+           count++;
+       }
+       while (username[0] == '\n' && count < 3);
+
+       if (username[0] == '\n') {
+           fprintf(stderr, "Aborting!!\n\n");
+           return(1);
+       }
+       
+       username[strlen(username) -1] = '\0';
+    }
+    
+    (void) memcpy( inbuf.data + 3, username, strlen(username));
+    inbuf.length = strlen(username) + 3;
+    if (retval = krb5_mk_priv(&inbuf,
+                       ETYPE_DES_CBC_CRC,
+                       &my_creds->keyblock, 
+                       local_addr, 
+                       foreign_addr,
+                       *seqno,
+                       KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                       0,
+                       0,
+                       &msg_data)) {
+        fprintf(stderr, "Error during Second Message Encoding: %s!\n",
+                       error_message(retval));
+       free(inbuf.data);
+       return(1);
+    }
+    free(inbuf.data);
+
+    /* write private message to server */
+    if (krb5_write_message(local_socket, &msg_data)){
+        fprintf(stderr, "Write Error During Second Message Transmission!\n");
+        return(1);
+    } 
+    free(msg_data.data);
+
+    /* Ok Now let's get the private message */
+    if ((retval = krb5_read_message(local_socket, &inbuf))){
+        fprintf(stderr, "Read Error During Second Reply: %s!\n",
+                       error_message(retval));
+        return(1);
+    }
+
+    if (retval = krb5_rd_priv(&inbuf,
+                       &my_creds->keyblock,
+                       foreign_addr, 
+                       local_addr,
+                       rep_ret->seq_number, 
+                       KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                       0,
+                       0,
+                       &msg_data)) {
+        fprintf(stderr, "Error during Second Read Decoding :%s!\n", 
+                       error_message(retval));
+       free(inbuf.data);
+        return(1);
+    }
+    free(inbuf.data);
+
+    if (!msg_data.data) {
+        fprintf(stderr, "kadm_inq_user: Error - empty message received!\n\n");
+        return(0);
+    }
+       
+    if (msg_data.data[2] == KADMBAD) {
+        fprintf(stderr, "Principal Does Not Exist!\n\n");
+        return(0);
+    }
+
+    if ((my_data = (char *) calloc(1, msg_data.length + 1)) == (char *) 0) {
+       fprintf(stderr, "No Memory Allocating Inquiry Buffer!\n");
+       return(1);
+    }
+
+    (void) memcpy(my_data, msg_data.data, msg_data.length);
+
+               /* Print Inquiry Information */
+    fprintf(stdout, "%s\n", my_data);
+    free(my_data);
+    free(msg_data.data);
+
+    if ((inbuf.data = (char *) calloc(1, 3)) == (char *) 0) {
+       fprintf(stderr, "inbuf.data allocation error!\n");
+       return(1);
+    }
+
+    inbuf.data[0] = KADMIN;
+    inbuf.data[1] = KADMGOOD;
+    inbuf.length = 2;
+    if (retval = krb5_mk_priv(&inbuf,
+                        ETYPE_DES_CBC_CRC,
+                        &my_creds->keyblock,
+                        local_addr,
+                        foreign_addr,
+                        *seqno,
+                        KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                        0,
+                        0,
+                        &msg_data)) {
+        fprintf(stderr, "Error during Second Message Encoding: %s!\n",
+                        error_message(retval));
+       free(inbuf.data);
+        return(1);
+    }
+    free(inbuf.data);
+     
+         /* write private message to server */
+    if (krb5_write_message(local_socket, &msg_data)){
+        fprintf(stderr, "Write Error During Second Message Transmission!\n");
+        free(msg_data.data);
+        return(1);
+    }
+    free(msg_data.data);
+
+                /* Ok Now let's get the final private message */
+    if (retval = krb5_read_message(local_socket, &inbuf)){
+        fprintf(stderr, "Read Error During Final Reply: %s!\n",
+                        error_message(retval));
+        retval = 1;
+    }
+    if (retval = krb5_rd_priv(&inbuf,
+                        &my_creds->keyblock,
+                        foreign_addr,
+                        local_addr,
+                        rep_ret->seq_number,
+                        KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                        0,
+                        0,
+                        &msg_data)) {
+        fprintf(stderr, "Error during Final Read Decoding :%s!\n",
+                        error_message(retval));
+        free(inbuf.data);
+        return(1);
+    }
+    free(inbuf.data);
+     
+    memcpy(&rd_priv_resp.appl_code, msg_data.data, 1);
+    memcpy(&rd_priv_resp.oper_code, msg_data.data + 1, 1);
+    memcpy(&rd_priv_resp.retn_code, msg_data.data + 2, 1);
+    free(msg_data.data);
+    if (!((rd_priv_resp.appl_code == KADMIN) &&
+                (rd_priv_resp.retn_code == KADMGOOD))) {
+        fprintf(stderr, "Generic Error During kadmin Inquiry!\n");
+        retval = 1;
+    } else {
+        fprintf(stderr, "\nDatabase Inquiry Successful.\n");
+    }
+    return(0);
+}
diff --git a/src/kadmin/client/kadmin_mod.c b/src/kadmin/client/kadmin_mod.c
new file mode 100644 (file)
index 0000000..25a6587
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ */
+
+/* 
+ * Sandia National Laboratories also makes no representations about the 
+ * suitability of the modifications, or additions to this software for 
+ * any purpose.  It is provided "as is" without express or implied warranty.
+ */
+
+#if !defined(lint) && !defined(SABER)
+static char rcsid_kadmin_mod[] =
+    "$Header$";
+#endif /* lint */
+
+/*
+ * kadmin_mod
+ * Perform Remote Kerberos Administrative Functions
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <signal.h>
+#ifndef __convex__
+#include <strings.h>
+#endif
+#include <com_err.h>
+
+#include <krb5/adm_defs.h>
+
+#include <krb5/krb5.h>
+#include <krb5/ext-proto.h>
+#include <krb5/los-proto.h>
+#include <krb5/kdb.h>
+#include <krb5/kdb_dbm.h>
+
+krb5_error_code
+kadm_mod_user(my_creds, rep_ret, local_addr, foreign_addr, 
+             local_socket, seqno, principal)
+krb5_creds *my_creds;
+krb5_ap_rep_enc_part *rep_ret;
+krb5_address *local_addr, *foreign_addr;
+int *local_socket;
+krb5_int32 *seqno;
+char *principal;
+{
+    krb5_data msg_data, inbuf;
+    kadmin_requests rd_priv_resp;
+    char username[755];
+    int count;
+    krb5_error_code retval;     /* return code */
+
+    if ((inbuf.data = (char *) calloc(1, 3 + sizeof(username))) == (char *) 0) {        fprintf(stderr, "No memory for command!\n");
+        exit(1);
+    }
+
+    inbuf.data[0] = KADMIN;
+    inbuf.data[1] = MODOPER;
+    inbuf.data[2] = SENDDATA2;
+
+    if (principal && principal[0] != '\0')
+       strcpy(username, principal);
+    else {
+       count = 0;
+       do {
+           fprintf(stdout, "\nName of Principal to be Modified: ");
+           fgets(username, sizeof(username), stdin);
+           if (username[0] == '\n')
+               fprintf(stderr, "Invalid Principal name!\n");
+           count++;
+       }
+       while (username[0] == '\n' && count < 3);
+
+       if (username[0] == '\n') {
+           fprintf(stderr, "Aborting!!\n\n");
+           return(1);
+       }
+
+       username[strlen(username) -1] = '\0';
+    }
+    
+    (void) memcpy( inbuf.data + 3, username, strlen(username));
+    inbuf.length = strlen(username) + 3;
+    if ((retval = krb5_mk_priv(&inbuf,
+                       ETYPE_DES_CBC_CRC,
+                       &my_creds->keyblock, 
+                       local_addr, 
+                       foreign_addr,
+                       *seqno,
+                       KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                       0,
+                       0,
+                       &msg_data))) {
+        fprintf(stderr, "Error during Second Message Encoding: %s!\n",
+                       error_message(retval));
+       free(inbuf.data);
+        return(1);
+    }
+    free(inbuf.data);
+
+    /* write private message to server */
+    if (krb5_write_message(local_socket, &msg_data)){
+        fprintf(stderr, "Write Error During Second Message Transmission!\n");
+        return(1);
+    } 
+    free(msg_data.data);
+
+    /* Ok Now let's get the private message */
+    if (retval = krb5_read_message(local_socket, &inbuf)){
+        fprintf(stderr, "Read Error During Second Reply: %s!\n",
+                       error_message(retval));
+        return(1);
+    }
+
+    if ((retval = krb5_rd_priv(&inbuf,
+                       &my_creds->keyblock,
+                       foreign_addr, 
+                       local_addr,
+                       rep_ret->seq_number, 
+                       KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                       0,
+                       0,
+                       &msg_data))) {
+        fprintf(stderr, "Error during Second Read Decoding :%s!\n", 
+                       error_message(retval));
+        free(inbuf.data);
+        return(1);
+    }
+    free(inbuf.data);
+    free(msg_data.data);
+
+    if (msg_data.data[2] == KADMBAD) {
+        fprintf(stderr, "Principal Does NOT Exist!\n\n");
+        return(0);
+    }
+
+    kadm_snd_mod(my_creds, rep_ret, local_addr, 
+                       foreign_addr, local_socket, seqno);
+
+    if ((inbuf.data = (char *) calloc(1, 2)) == (char *) 0) {
+        fprintf(stderr, "No memory for command!\n");
+        return(1);
+    }
+
+
+    inbuf.data[0] = KADMIN;
+    inbuf.data[1] = KADMGOOD;
+    inbuf.data[2] = SENDDATA3;
+    inbuf.length = 3;
+    if ((retval = krb5_mk_priv(&inbuf,
+                        ETYPE_DES_CBC_CRC,
+                        &my_creds->keyblock,
+                        local_addr,
+                        foreign_addr,
+                        *seqno,
+                        KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                        0,
+                        0,
+                        &msg_data))) {
+        fprintf(stderr, "Error during Second Message Encoding: %s!\n",
+                        error_message(retval));
+       free(inbuf.data);
+        return(1);
+    }
+    free(inbuf.data);
+     
+         /* write private message to server */
+    if (krb5_write_message(local_socket, &msg_data)){
+        fprintf(stderr, "Write Error During Second Message Transmission!\n");
+        return(1);
+    }
+    free(msg_data.data);
+     
+                /* Ok Now let's get the final private message */
+    if (retval = krb5_read_message(local_socket, &inbuf)){
+        fprintf(stderr, "Read Error During Final Reply: %s!\n",
+                        error_message(retval));
+        retval = 1;
+    }
+
+    if ((retval = krb5_rd_priv(&inbuf,
+                        &my_creds->keyblock,
+                        foreign_addr,
+                        local_addr,
+                        rep_ret->seq_number,
+                        KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                        0,
+                        0,
+                        &msg_data))) {
+        fprintf(stderr, "Error during Final Read Decoding :%s!\n",
+                        error_message(retval));
+       free(inbuf.data);
+        return(1);
+    }
+    free(inbuf.data);
+
+    memcpy(&rd_priv_resp.appl_code, msg_data.data, 1);
+    memcpy(&rd_priv_resp.oper_code, msg_data.data + 1, 1);
+    memcpy(&rd_priv_resp.retn_code, msg_data.data + 2, 1);
+
+    free(msg_data.data);
+
+    if (!((rd_priv_resp.appl_code == KADMIN) &&
+               (rd_priv_resp.retn_code == KADMGOOD))) {
+       fprintf(stderr, "Error Performing kadmin service!\n");
+       retval = 1;
+    } else {
+        fprintf(stderr, "\nDatabase Modification Successful.\n");
+    }
+    return(0);
+}
diff --git a/src/kadmin/client/kadmin_msnd.c b/src/kadmin/client/kadmin_msnd.c
new file mode 100644 (file)
index 0000000..41a36c1
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ */
+
+/* 
+ * Sandia National Laboratories also makes no representations about the 
+ * suitability of the modifications, or additions to this software for 
+ * any purpose.  It is provided "as is" without express or implied warranty.
+ */
+
+#if !defined(lint) && !defined(SABER)
+static char rcsid_kadmin[] =
+    "$Header$";
+#endif /* lint */
+
+/*
+ * kadmin_snd_mod
+ * Perform Remote Kerberos Administrative Functions
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <signal.h>
+#ifndef __convex__
+#include <strings.h>
+#endif
+#include <com_err.h>
+
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 1024
+#endif
+
+#include <sys/param.h>
+#include <pwd.h>
+
+#include <krb5/adm_defs.h>
+
+#include <sys/stat.h>
+
+#include <krb5/krb5.h>
+#include <krb5/kdb.h>
+#include <krb5/kdb_dbm.h>
+#include <krb5/ext-proto.h>
+#include <krb5/los-proto.h>
+#include <krb5/asn1.h>
+#include <krb5/config.h>
+#include <krb5/base-defs.h>
+#include <krb5/asn.1/encode.h>
+
+#include <krb5/widen.h>
+
+#include <krb5/adm_err.h>
+#include <krb5/errors.h>
+#include <krb5/kdb5_err.h>
+#include <krb5/krb5_err.h>
+
+krb5_error_code
+kadm_snd_mod(my_creds, rep_ret, local_addr, foreign_addr, local_socket, seqno)
+krb5_creds *my_creds;
+krb5_ap_rep_enc_part *rep_ret;
+krb5_address *local_addr, *foreign_addr;
+int *local_socket;
+krb5_int32 *seqno;
+{
+    krb5_error_code retval;     /* return code */
+    krb5_data msg_data, inbuf;
+    char mod_type[10];
+    char attrib[20];
+    char version[10];
+    int value;
+    int valid_command;
+    extern int errno;
+    int i;
+
+    for ( ; ; ) {
+       valid_command = 0;
+repeat1:
+#ifdef SANDIA
+       fprintf(stdout, "\nParameter Type to be Modified (fcnt, vno, attr, or q): ");
+#else
+       fprintf(stdout, "\nParameter Type to be Modified (vno, attr, or q): ");
+#endif
+                         
+       (void) fgets(mod_type, 10, stdin);
+       mod_type[strlen(mod_type) - 1] = '\0';
+
+       if ((inbuf.data = (char *) calloc(1, 80)) == (char *) 0) {
+            fprintf(stderr, "No memory for command!\n");
+            exit(1);
+       }
+
+       if (!strcmp(mod_type, "q")) {
+           free(inbuf.data);
+           goto alldone;
+       }
+#ifdef SANDIA
+       if (!strcmp(mod_type, "fcnt")) {
+           valid_command = 1;
+repeat_cnt:
+           fprintf(stdout, "\nFailure Count: ");
+           (void) fgets(version, sizeof(version), stdin);
+           /* Make sure version is null terminated */
+           version[sizeof(version) -1] = '\0';
+           /* Strip linefeed */
+           if (version[strlen(version) - 1] == '\n')
+               version[strlen(version) - 1] = '\0';
+           if (!strcmp(version, "q")) {
+               free(inbuf.data);
+               goto alldone;
+            }
+           value = -1;
+           sscanf(version,"%d",&value);
+           if (value < 0 || value > 10 ) {
+               fprintf(stderr, "Value must be between 0 and 10!\n");
+               goto repeat_cnt;
+           }
+            inbuf.data[3] = KMODFCNT;
+           (void) memcpy(inbuf.data + 4, version, strlen(version));
+           inbuf.length = strlen(version) + 4;
+        }
+#endif
+       if (!strcmp(mod_type, "vno")) {
+           valid_command = 1;
+repeat2:
+           fprintf(stdout, "\nVersion Number: ");
+            (void) fgets(version, sizeof(version), stdin);
+            /* Make sure version is null terminated */
+            version[sizeof(version) -1] = '\0';
+            /* Strip linefeed */
+            if (version[strlen(version) - 1] == '\n')
+                version[strlen(version) - 1] = '\0';
+            if (!strcmp(version, "q")) {
+                free(inbuf.data);
+                goto alldone;
+            }
+            value = -1;
+            sscanf(version,"%d",&value);
+           if (value < 0 || value > 255 ) {
+               fprintf(stderr, "Value must be between 0 and 255!\n");
+               goto repeat2;
+           }
+            inbuf.data[3] = KMODVNO;
+           (void) memcpy(inbuf.data + 4, version, strlen(version));
+           inbuf.length = strlen(version) + 4;
+        }
+
+       if (!strcmp(mod_type, "attr")) {
+            valid_command = 1;
+repeat3:
+           fprintf(stdout, "\nAttribute: ");
+           fgets(attrib, 20, stdin);
+           attrib[strlen(attrib) - 1] = '\0';
+           for (i = 0; attrib[i] != '\0'; i++)
+               if (isupper(attrib[i]))
+                   attrib[i] = tolower(attrib[i]);
+
+            inbuf.data[3] = KMODATTR;
+           inbuf.data[4] = BADATTR;
+            inbuf.length = 5;
+           if (!strcmp(attrib, "post")) inbuf.data[4] = ATTRPOST;
+           if (!strcmp(attrib, "nopost")) inbuf.data[4] = ATTRNOPOST;
+           if (!strcmp(attrib, "forward")) inbuf.data[4] = ATTRFOR;
+           if (!strcmp(attrib, "noforward")) inbuf.data[4] = ATTRNOFOR;
+           if (!strcmp(attrib, "tgt")) inbuf.data[4] = ATTRTGT;
+           if (!strcmp(attrib, "notgt")) inbuf.data[4] = ATTRNOTGT;
+           if (!strcmp(attrib, "ren")) inbuf.data[4] = ATTRREN;
+           if (!strcmp(attrib, "noren")) inbuf.data[4] = ATTRNOREN;
+           if (!strcmp(attrib, "proxy")) inbuf.data[4] = ATTRPROXY;
+           if (!strcmp(attrib, "noproxy")) inbuf.data[4] = ATTRNOPROXY;
+           if (!strcmp(attrib, "dskey")) inbuf.data[4] = ATTRDSKEY;
+           if (!strcmp(attrib, "nodskey")) inbuf.data[4] = ATTRNODSKEY;
+           if (!strcmp(attrib, "lock")) inbuf.data[4] = ATTRLOCK;
+           if (!strcmp(attrib, "unlock")) inbuf.data[4] = ATTRUNLOCK;
+           if (!strcmp(attrib, "svr")) inbuf.data[4] = ATTRSVR;
+           if (!strcmp(attrib, "nosvr")) inbuf.data[4] = ATTRNOSVR;
+
+#ifdef SANDIA
+           if (!strcmp(attrib, "preauth")) inbuf.data[4] = ATTRPRE;
+           if (!strcmp(attrib, "nopreauth")) inbuf.data[4] = ATTRNOPRE;
+           if (!strcmp(attrib, "pwok")) inbuf.data[4] = ATTRPWOK;
+           if (!strcmp(attrib, "pwchange")) inbuf.data[4] = ATTRPWCHG;
+           if (!strcmp(attrib, "sid")) inbuf.data[4] = ATTRSID;
+           if (!strcmp(attrib, "nosid")) inbuf.data[4] = ATTRNOSID;
+#endif
+           if (!strcmp(attrib, "q")){
+               free(inbuf.data);
+               goto alldone;
+            }
+           if (inbuf.data[4] == BADATTR) {
+               fprintf(stderr, "Valid Responses are:\n");
+               fprintf(stderr, "post/nopost - Allow/Disallow postdating\n");
+               fprintf(stderr, "forward/noforward - Allow/Disallow forwarding\n");
+               fprintf(stderr, "tgt/notgt - Allow/Disallow initial tickets\n");
+               fprintf(stderr, "ren/noren - Allow/Disallow renewable tickets\n");
+               fprintf(stderr, 
+                   "proxy/noproxy - Allow/Disallow proxiable tickets\n");
+                   fprintf(stderr, 
+                   "dskey/nodskey - Allow/Disallow Duplicate Session Keys\n");
+               fprintf(stderr, "lock/unlock - Lock/Unlock client\n");
+               fprintf(stderr, 
+                   "svr/nosvr - Allow/Disallow Use of Principal as Server\n");
+#ifdef SANDIA
+               fprintf(stderr, 
+                   "preauth/nopreauth - Require/Do Not Require preauthentication\n");
+               fprintf(stderr, 
+                  "pwok/pwchange - Password is OK/Needs to be changed\n");
+               fprintf(stderr, 
+                   "sid/nosid - Require/Do Not Require Hardware Authentication\n");
+#endif
+               fprintf(stderr, "q - Quit from setting attributes.\n");
+               goto repeat3;
+           }
+       }
+
+       if (!valid_command) {
+           free(inbuf.data);
+           fprintf(stderr, "Invalid command - Try Again\n");
+           goto repeat1;
+       }
+
+       inbuf.data[0] = KADMIN;
+       inbuf.data[1] = MODOPER;
+       inbuf.data[2] = SENDDATA3;
+
+       if ((retval = krb5_mk_priv(&inbuf,
+                       ETYPE_DES_CBC_CRC,
+                       &my_creds->keyblock, 
+                       local_addr, 
+                       foreign_addr,
+                       *seqno,
+                       KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                       0,
+                       0,
+                       &msg_data))) {
+            fprintf(stderr, "Error during Second Message Encoding: %s!\n",
+                       error_message(retval));
+           free(inbuf.data);
+            return(1);
+       }
+       free(inbuf.data);
+
+    /* write private message to server */
+       if (krb5_write_message(local_socket, &msg_data)) {
+            fprintf(stderr, "Write Error During Second Message Transmission!\n");
+            return(1);
+       } 
+       free(msg_data.data);
+
+    /* Ok Now let's get the private message */
+       if (retval = krb5_read_message(local_socket, &inbuf)){
+            fprintf(stderr, "Read Error During Second Reply: %s!\n",
+                        error_message(retval));
+            return(1);
+       }
+
+       if ((retval = krb5_rd_priv(&inbuf,
+                       &my_creds->keyblock,
+                        foreign_addr,
+                        local_addr,
+                        rep_ret->seq_number,
+                        KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                        0,
+                        0,
+                        &msg_data))) {
+            fprintf(stderr, "Error during Second Read Decoding :%s!\n",
+                        error_message(retval));
+            free(inbuf.data);
+            return(1);     
+       }
+       free(inbuf.data);
+    }  /* for */
+
+alldone:
+    if ((inbuf.data = (char *) calloc(1, 80)) == (char *) 0) {
+       fprintf(stderr, "No memory for command!\n");
+       exit(1);
+    }
+
+    inbuf.data[0] = KADMIN;
+    inbuf.data[1] = KADMGOOD;
+    inbuf.data[2] = SENDDATA3;
+    inbuf.length = 3;
+
+    if ((retval = krb5_mk_priv(&inbuf,
+                       ETYPE_DES_CBC_CRC,
+                       &my_creds->keyblock, 
+                       local_addr, 
+                       foreign_addr,
+                       *seqno,
+                       KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                       0,
+                       0,
+                       &msg_data))) {
+       fprintf(stderr, "Error during Second Message Encoding: %s!\n",
+                       error_message(retval));
+       free(inbuf.data);
+       return(1);
+    }
+    free(inbuf.data);
+
+    /* write private message to server */
+    if (krb5_write_message(local_socket, &msg_data)) {
+       fprintf(stderr, "Write Error During Second Message Transmission!\n");
+       return(1);
+    } 
+    free(msg_data.data);
+
+    return(0);
+}
diff --git a/src/kadmin/kpasswd/Imakefile b/src/kadmin/kpasswd/Imakefile
new file mode 100644 (file)
index 0000000..11329ca
--- /dev/null
@@ -0,0 +1,40 @@
+# $Source$
+# $Author$
+# $Header$
+#
+# Copyright 1989 by the Massachusetts Institute of Technology.
+#
+# For copying and distribution information,
+# please see the file <mit-copyright.h>.
+#
+# Imakefile for Kerberos admin server library.
+
+#ifdef Krb4KDCCompat
+K4LIB=-l$(DES425LIB)
+#else
+K4LIB=
+#endif
+
+SRCS = \
+       networked.c \
+       kpasswd.c
+
+OBJS = \
+       networked.o \
+       kpasswd.o
+
+ErrorTableObjectRule()
+
+all::  kpasswd
+
+NormalProgramTarget(kpasswd,$(OBJS),$(KDBDEPLIB) $(DEPKLIB), \
+       $(KDBLIB) $(K4LIB) $(KLIB) ,)
+Krb5InstallClientProgram(kpasswd)
+
+clean::
+
+depend:: 
+
+clean::
+
+DependTarget()
diff --git a/src/kadmin/kpasswd/kpasswd.M b/src/kadmin/kpasswd/kpasswd.M
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/kadmin/kpasswd/kpasswd.c b/src/kadmin/kpasswd/kpasswd.c
new file mode 100644 (file)
index 0000000..c4a070e
--- /dev/null
@@ -0,0 +1,998 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ * change your password with kerberos
+ */
+
+/* 
+ * Sandia National Laboratories also makes no representations about the 
+ * suitability of the modifications, or additions to this software for 
+ * any purpose.  It is provided "as is" without express or implied warranty.
+ */
+
+#ifndef        lint
+static char rcsid_kpasswd_c[] =
+    "$Header$";
+#endif /* lint */
+
+/*
+ * kpasswd
+ * change your password with Version 5 Kerberos
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <signal.h>
+#ifndef __convex__
+#include <strings.h>
+#endif
+
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 1024
+#endif
+
+#include <sys/param.h>
+#include <pwd.h>
+
+#include <krb5/adm_defs.h>
+
+#include <sys/stat.h>
+
+#include <krb5/krb5.h>
+#include <krb5/kdb.h>
+#include <krb5/kdb_dbm.h>
+#include <krb5/ext-proto.h>
+#include <krb5/los-proto.h>
+#include <krb5/asn1.h>
+#include <krb5/config.h>
+#include <krb5/base-defs.h>
+#include <krb5/asn.1/encode.h>
+
+#include <krb5/widen.h>
+
+#include <krb5/adm_err.h>
+#include <krb5/errors.h>
+#include <krb5/kdb5_err.h>
+#include <krb5/krb5_err.h>
+
+krb5_error_code get_first_ticket 
+       PROTOTYPE((krb5_ccache, 
+               krb5_principal));
+
+krb5_error_code print_and_choose_password 
+       PROTOTYPE((char *, krb5_data *));
+
+struct sockaddr_in local_sin, remote_sin;
+
+krb5_creds my_creds;
+
+struct v4_pwd_keyproc_arg {
+    krb5_principal who;
+    krb5_data password;
+};
+
+extern char *krb5_default_pwd_prompt1;
+
+static krb5_error_code
+v4_pwd_keyproc(DECLARG(const krb5_keytype, type),
+           DECLARG(krb5_keyblock **, key),
+            DECLARG(krb5_const_pointer, keyseed),
+            DECLARG(krb5_pa_data **,padata))
+OLDDECLARG(const krb5_keytype, type)
+OLDDECLARG(krb5_keyblock **, key)
+OLDDECLARG(krb5_const_pointer, keyseed)
+OLDDECLARG(krb5_pa_data **, padata)
+{
+    krb5_data salt;
+    krb5_error_code retval;
+#ifdef unicos61
+    struct v4_pwd_keyproc_arg *arg;
+#else
+    const struct v4_pwd_keyproc_arg *arg;
+#endif /* unicos61 */
+    struct v4_pwd_keyproc_arg arg2;
+    char pwdbuf[BUFSIZ];
+    int pwsize = sizeof(pwdbuf);
+    char f_salt = 0, use_salt = 0;
+    krb5_keyblock *my_keyblock;
+    char v4_keyptr[8];
+
+    if (!valid_keytype(type))
+       return KRB5_PROG_KEYTYPE_NOSUPP;
+
+    if (padata) {
+        krb5_pa_data **ptr;
+
+        for (ptr = padata; *ptr; ptr++)
+        {
+            if ((*ptr)->pa_type == KRB5_PADATA_PW_SALT)
+            {
+                /* use KDC-supplied salt, instead of default */
+                salt.length = (*ptr)->length;
+                salt.data = (char *)(*ptr)->contents;
+               use_salt = 1;
+                break;
+            }
+        }
+    }
+#ifdef unicos61
+    arg = (struct v4_pwd_keyproc_arg *) keyseed;
+#else
+    arg = (const struct v4_pwd_keyproc_arg *) keyseed;
+#endif /* unicos61 */
+    if (!use_salt) {
+       /* need to use flattened principal */
+       if (retval = krb5_principal2salt(arg->who, &salt))
+           return(retval);
+       f_salt = 1;
+    }
+
+    if (!arg->password.length) {
+       if (retval = krb5_read_password(krb5_default_pwd_prompt1,
+                                       0,
+                                       pwdbuf, &pwsize)) {
+           if (f_salt) xfree(salt.data);
+           return retval;
+       }
+
+       arg2 = *arg;
+        arg2.password.length = pwsize;
+        arg2.password.data = pwdbuf;
+       arg = &arg2;
+    }
+    my_keyblock = (krb5_keyblock *)malloc(sizeof(**key));
+    if (!*key) {
+       if (f_salt) xfree(salt.data);
+       if (arg != (struct v4_pwd_keyproc_arg *) keyseed) 
+               memset((char *) arg->password.data, 0, arg->password.length);
+       return(ENOMEM);
+    }    
+
+    *key = my_keyblock;
+    (*my_keyblock).keytype = type;
+    (*my_keyblock).length = 8;
+
+    if (retval = des_string_to_key(arg->password.data,
+                                  v4_keyptr)) {
+       xfree(*key);
+       if (f_salt) xfree(salt.data);
+       if (arg != (struct v4_pwd_keyproc_arg *) keyseed) 
+               memset((char *)arg->password.data,0,arg->password.length);
+       return(retval);
+    }
+
+    (*my_keyblock).contents = (krb5_octet *)calloc(1,(*my_keyblock).length);
+    if (!(*my_keyblock).contents) return(ENOMEM);
+    memcpy((*my_keyblock).contents,(krb5_octet *) v4_keyptr,
+               (*my_keyblock).length);
+
+    if (f_salt) xfree(salt.data);
+    if (arg != (struct v4_pwd_keyproc_arg *) keyseed) 
+       memset((char *)arg->password.data,0,arg->password.length);
+    return(0);
+}
+
+main(argc,argv)
+  int argc;
+  char *argv[];
+{
+    krb5_ccache cache = NULL;
+    char cache_name[255];
+    krb5_flags cc_flags;
+
+    krb5_address local_addr, foreign_addr;
+
+    struct passwd *pw;
+
+    krb5_principal client;
+    krb5_principal server;
+
+    char default_name[256];
+    char *client_name;         /* Single string representation of client id */
+
+    krb5_data requested_realm;
+    char * local_realm;
+
+    char input_string[768];
+
+    krb5_error_code retval;    /* return code */
+
+    int local_socket;
+    int c, count;
+
+    krb5_error *err_ret;
+    krb5_ap_rep_enc_part *rep_ret;
+
+    kadmin_requests rd_priv_resp;
+
+    krb5_checksum send_cksum;
+    int cksum_alloc = 0;
+    krb5_data msg_data, inbuf;
+    krb5_int32 seqno;
+
+    char *new_password;
+    int new_pwsize;
+    krb5_data *decodable_pwd_string;
+    int i, j;
+
+#ifdef SANDIA
+    extern int networked();
+    int krb_secure;
+    struct stat statbuf;
+#endif /* SANDIA */
+
+#ifdef SANDIA  /* Allow or Disallow Remote Clients to Modify Passwords */
+/*
+ *     If a Client Modifies a Password using kpasswd on this host
+ *     from a remote host or network terminal, the Password selected 
+ *     is transmitted across the network in Cleartext.
+ *
+ *     The systems administrator can disallow "remote" kpasswd usage by
+ *     creating the file "/etc/krb.secure"
+ */
+
+    krb_secure = 0;
+/* 
+ *     First check to see if the file /etc/krb.secure exists.
+ *     If it does then krb_secure to 1.
+ */
+
+    if (stat("/etc/krb.secure", &statbuf) == 0) krb_secure = 1;
+
+/*
+ *     Check to see if this process is tied to a physical terminal.
+ *     Network() verifies the terminal device is not a pseudo tty
+ */
+    if (networked() && krb_secure) {
+        fprintf(stderr,"Sorry but you cannot %s from a\n", argv[0]);
+        fprintf(stderr,"     pseudo tty terminal!\n");
+       retval = 1;
+       goto finish;
+    }
+#endif    
+
+       /* (3 * 255) + 1 (/) + 1 (@) + 1 (NULL) */
+    if ((client_name = (char *) calloc (1, (3 * 256))) == NULL) {
+       fprintf(stderr, "No Memory for Client_name!\n");
+       retval = 1;
+       goto finish;
+    }
+
+    if ((requested_realm.data = (char *) calloc (1, 256)) == NULL) {
+       fprintf(stderr, "No Memory for realm_name!\n");
+       retval = 1;
+       free(client_name);
+       goto finish;
+    }
+
+    krb5_init_ets();
+    memset((char *) default_name, 0, sizeof(default_name));
+    
+    switch (argc) {
+       case 1:         /* No User Specified */
+
+               /* Identify Default Credentials Cache */
+           if ((retval = krb5_cc_default(&cache))) {
+               fprintf(stderr, "Error while getting default ccache!\n");
+               goto finish;
+           }
+
+/*
+ *     Attempt to Modify Credentials Cache 
+ *             retval == 0 ==> ccache Exists - Use It 
+ *             retval == ENOENT ==> No Entries, but ccache Exists 
+ *             retval != 0 ==> Assume ccache does NOT Exist 
+ */
+           cc_flags = 0;
+           if ((retval = krb5_cc_set_flags(cache, cc_flags))) {
+               /* Search passwd file for client */
+               pw = getpwuid((int) getuid());
+               if (pw) {
+                   (void) strcpy(default_name, pw->pw_name);
+               } else {
+                   fprintf(stderr, 
+                       "Unable to Identify Customer from Password File!\n");
+                   retval = 1;
+                   goto finish;
+               }
+
+               /* Use this to get default_realm and format client_name */
+               if ((retval = krb5_parse_name(default_name, &client))) {
+                   fprintf(stderr, "Unable to Parse Client Name!\n");
+                   goto finish;
+               }
+
+               if ((retval = krb5_unparse_name(client, &client_name))) {
+                   fprintf(stderr, "Unable to Parse Client Name!\n");
+                   goto finish;
+               }
+
+               requested_realm.length = client->realm.length;
+               memcpy((char *) requested_realm.data, 
+                       (char *) client->realm.data,
+                       requested_realm.length);
+           } else {
+                       /* Read Client from Cache */
+               if ((retval = krb5_cc_get_principal(cache, 
+                       (krb5_principal *) &client))) {
+                   fprintf(stderr, 
+                           "Unable to Read Customer Credentials File!\n");
+                   goto finish;
+               }
+
+               if ((retval = krb5_unparse_name(client, &client_name))) {
+                   fprintf(stderr, "Unable to Parse Client Name!\n");
+                   goto finish;
+               }
+
+               requested_realm.length = client->realm.length;
+               memcpy((char *) requested_realm.data, 
+                       (char *) client->realm.data,
+                       requested_realm.length);
+
+               (void) krb5_cc_close(cache);
+           }
+           break;
+
+       case 2:         /* Client Gave us a Token - Use it */
+                       /* Hand Parse Entry */
+           strcpy(input_string, argv[1]);
+
+           if (retval = krb5_parse_name(input_string, &client)) {
+               fprintf(stderr, "Error Parsing -u option contents!\n");
+               exit(0);
+           }
+           requested_realm.length = client->realm.length;
+           memcpy((char *) requested_realm.data, 
+                  (char *) client->realm.data,
+                  requested_realm.length);
+
+           break;
+
+       default:
+           usage();
+           break;
+    }
+
+       /* Create credential cache for changepw */
+    (void) sprintf(cache_name, "FILE:/tmp/tkt_cpw_%d", getpid());
+
+    if ((retval = krb5_cc_resolve(cache_name, &cache))) {
+       fprintf(stderr, "Unable to Resolve Cache: %s\n", cache_name);
+    }
+    
+    if ((retval = krb5_cc_initialize(cache, client))) {
+        fprintf(stderr, "Error initializing cache: %s\n", cache_name);
+        goto finish;
+    }
+/*
+ *     Verify User by Obtaining Initial Credentials prior to Initial Link
+ */
+
+    if ((retval = get_first_ticket(cache, client))) {
+       goto finish;
+    }
+    
+       /* Initiate Link to Server */
+    if ((retval = adm5_init_link(&requested_realm, &local_socket))) {
+       goto finish;
+    } 
+
+#ifdef unicos61
+#define SIZEOF_INADDR  SIZEOF_in_addr
+#else
+#define SIZEOF_INADDR sizeof(struct in_addr)
+#endif
+
+       /* V4 kpasswd Protocol Hack */
+ {
+    int msg_length = 0;
+
+    retval = krb5_net_write(local_socket, (char *) &msg_length + 2, 2);
+    if (retval < 0) {
+        fprintf(stderr, "krb5_net_write failure!\n");
+        goto finish;
+    }
+
+ }
+
+    local_addr.addrtype = ADDRTYPE_INET;
+    local_addr.length = SIZEOF_INADDR ;
+    local_addr.contents = (krb5_octet *)&local_sin.sin_addr;
+
+    foreign_addr.addrtype = ADDRTYPE_INET;
+    foreign_addr.length = SIZEOF_INADDR ;
+    foreign_addr.contents = (krb5_octet *)&remote_sin.sin_addr;
+
+   /* compute checksum, using CRC-32 */
+    if (!(send_cksum.contents = (krb5_octet *)
+          malloc(krb5_checksum_size(CKSUMTYPE_CRC32)))) {
+        fprintf(stderr, "Insufficient Memory while Allocating Checksum!\n");
+        goto finish;
+    }
+    cksum_alloc++;
+    /* choose some random stuff to compute checksum from */
+    if (retval = krb5_calculate_checksum(CKSUMTYPE_CRC32,
+                                       ADM_CPW_VERSION,
+                                       strlen(ADM_CPW_VERSION),
+                                       0,
+                                       0, /* if length is 0, crc-32 doesn't
+                                               use the seed */
+                                       &send_cksum)) {
+        fprintf(stderr, "Error while Computing Checksum: %s!\n",
+               error_message(retval));
+        goto finish;
+    }
+
+    /* call Kerberos library routine to obtain an authenticator,
+       pass it over the socket to the server, and obtain mutual
+       authentication. */
+
+   if ((retval = krb5_sendauth((krb5_pointer) &local_socket,
+                       ADM_CPW_VERSION, 
+                       my_creds.client, 
+                       my_creds.server,
+                       AP_OPTS_MUTUAL_REQUIRED,
+                       &send_cksum,
+                       0,           
+                       cache,
+                       &seqno, 
+                       0,           /* don't need a subsession key */
+                       &err_ret,
+                       &rep_ret))) {
+       fprintf(stderr, "Error while performing sendauth: %s!\n",
+                       error_message(retval));
+        goto finish;
+    }
+
+    /* Get credentials : to use for safe and private messages */
+    if (retval = krb5_get_credentials(0, cache, &my_creds)){
+       fprintf(stderr, "Error Obtaining Credentials: %s!\n", 
+               error_message(retval));
+       goto finish;
+    }
+
+    /* Read back what the server has to say... */
+     
+    if (retval = krb5_read_message(&local_socket, &inbuf)){
+       fprintf(stderr, " Read Message Error: %s!\n",
+          error_message(retval));
+        goto finish;
+    }
+    if ((inbuf.length != 2) || (inbuf.data[0] != KADMIND) ||
+       (inbuf.data[1] != KADMSAG)){
+       fprintf(stderr, " Invalid ack from admin server.\n");
+       goto finish;
+    }
+
+    inbuf.data[0] = KPASSWD;
+    inbuf.data[1] = CHGOPER;
+    inbuf.length = 2;
+
+    if ((retval = krb5_mk_priv(&inbuf,
+                       ETYPE_DES_CBC_CRC,
+                       &my_creds.keyblock, 
+                       &local_addr, 
+                       &foreign_addr,
+                       seqno,
+                       KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                       0,
+                       0,
+                       &msg_data))) {
+        fprintf(stderr, "Error during First Message Encoding: %s!\n",
+                       error_message(retval));
+        goto finish;
+    }
+    free(inbuf.data);
+
+    /* write private message to server */
+    if (krb5_write_message(&local_socket, &msg_data)){
+        fprintf(stderr, "Write Error During First Message Transmission!\n");
+       retval = 1;
+        goto finish;
+    } 
+    free(msg_data.data);
+
+#ifdef MACH_PASS /* Machine-generated Passwords */
+    /* Ok Now let's get the private message */
+    if (retval = krb5_read_message(&local_socket, &inbuf)){
+        fprintf(stderr, "Read Error During First Reply: %s!\n",
+                       error_message(retval));
+       retval = 1;
+        goto finish;
+    }
+
+    if ((retval = krb5_rd_priv(&inbuf,
+                       &my_creds.keyblock,
+                       &foreign_addr, 
+                       &local_addr,
+                       rep_ret->seq_number, 
+                       KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                       0,
+                       0,
+                       &msg_data))) {
+        fprintf(stderr, "Error during First Read Decoding: %s!\n", 
+                       error_message(retval));
+        goto finish;
+    }
+    free(inbuf.data);
+#endif
+
+    if ((new_password = (char *) calloc (1, ADM_MAX_PW_LENGTH+1)) == NULL) {
+       fprintf(stderr, "Unable to Allocate Space for New Password!\n");
+       goto finish;
+    }
+
+#ifdef MACH_PASS /* Machine-generated passwords */
+       /* Offer Client Password Choices */
+    if ((retval = print_and_choose_password(new_password,
+                        &msg_data))) {
+       (void) memset((char *) new_password, 0, ADM_MAX_PW_LENGTH+1);
+       free(new_password);
+        goto finish;
+    }
+#else
+    new_pwsize = ADM_MAX_PW_LENGTH+1;
+    putchar('\n');
+    if ((retval = krb5_read_password(
+                                    "Enter new password: ",
+                                    "Re-enter new password for verification: ",
+                                    new_password,
+                                    &new_pwsize))) {
+       fprintf(stderr, "Error while reading new password for '%s'",
+                                client_name);
+       (void) memset((char *) new_password, 0, ADM_MAX_PW_LENGTH+1);
+       free(new_password);
+        goto finish;
+    }
+#endif
+
+    inbuf.data = new_password;
+    inbuf.length = strlen(new_password);
+
+    if ((retval = krb5_mk_priv(&inbuf,
+                       ETYPE_DES_CBC_CRC,
+                       &my_creds.keyblock, 
+                       &local_addr, 
+                       &foreign_addr,
+                       seqno,
+                       KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                       0,
+                       0,
+                       &msg_data))) {
+        fprintf(stderr, "Error during Second Message Encoding: %s!\n",
+                       error_message(retval));
+        goto finish;
+    }
+    memset(inbuf.data,0,inbuf.length);
+    free(inbuf.data);
+
+    /* write private message to server */
+    if (krb5_write_message(&local_socket, &msg_data)){
+        fprintf(stderr, "Write Error During Second Message Transmission!\n");
+       retval = 1;
+        goto finish;
+    } 
+    free(msg_data.data);
+
+    /* Ok Now let's get the private message */
+    if (retval = krb5_read_message(&local_socket, &inbuf)){
+        fprintf(stderr, "Read Error During Second Reply: %s!\n",
+                       error_message(retval));
+       retval = 1;
+        goto finish;
+    }
+
+    if ((retval = krb5_rd_priv(&inbuf,
+                       &my_creds.keyblock,
+                       &foreign_addr, 
+                       &local_addr,
+                       rep_ret->seq_number, 
+                       KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                       0,
+                       0,
+                       &msg_data))) {
+        fprintf(stderr, "Error during Second Read Decoding :%s!\n", 
+                       error_message(retval));
+        goto finish;
+    }
+
+    memcpy(&rd_priv_resp.appl_code, msg_data.data, 1);
+    memcpy(&rd_priv_resp.oper_code, msg_data.data + 1, 1);
+    memcpy(&rd_priv_resp.retn_code, msg_data.data + 2, 1);
+
+    free(inbuf.data);
+    free(msg_data.data);
+    if (!((rd_priv_resp.appl_code == KPASSWD) &&
+               (rd_priv_resp.oper_code == CHGOPER) &&
+               (rd_priv_resp.retn_code == KADMGOOD))) {
+       fprintf(stderr, "Generic Error During kpasswd!\n");
+       retval = 1;
+    }
+
+    finish:
+
+    (void) krb5_cc_destroy(cache);
+
+    free(client_name);
+    free(requested_realm.data);
+
+    if (cksum_alloc) free(send_cksum.contents);
+    if (retval) {
+       fprintf(stderr, "\n\nProtocol Failure - %s\n\n", 
+               kadmind_kpasswd_response[1]);
+       exit(1);
+    }
+
+    printf("\n\n%s.\n\n", kadmind_kpasswd_response[0]);
+
+    exit(0);
+}
+
+
+
+krb5_data cpwname = {
+       sizeof(CPWNAME)-1,
+       CPWNAME
+};
+
+krb5_error_code
+get_first_ticket(DECLARG(krb5_ccache, cache),
+               DECLARG(krb5_principal, client))
+OLDDECLARG(krb5_ccache, cache)
+OLDDECLARG(krb5_principal, client)
+{
+    char prompt[255];                  /* for the password prompt */
+    char verify_prompt[255];           /* Verification Prompt if Desired */
+    char pword[ADM_MAX_PW_LENGTH+1];   /* storage for the password */
+    int  pword_length = sizeof(pword);
+    char *old_password;
+    int  old_pwsize;
+    
+    krb5_address **my_addresses;
+
+    struct v4_pwd_keyproc_arg keyseed;
+
+    char *client_name;
+    char local_realm[255];
+    krb5_error_code retval;
+    
+    if ((retval = krb5_unparse_name(client, &client_name))) {
+       fprintf(stderr, "Unable to Unparse Client Name\n");
+       return(1);
+    }
+
+    (void) sprintf(prompt,"Old password for %s: ", (char *) client_name);
+
+    if ((retval = krb5_os_localaddr(&my_addresses))) {
+       fprintf(stderr, "Unable to Get Customers Address\n");
+       return(1);
+    }
+
+    memset((char *) &my_creds, 0, sizeof(my_creds));
+
+    my_creds.client = client;                           
+    if ((retval = krb5_build_principal_ext(&my_creds.server,
+                                        client->realm.length, 
+                                       client->realm.data,
+                                        cpwname.length,                /* 6 */ 
+                                       cpwname.data,           /* "kadmin" */
+                                        client->realm.length,  
+                                          /* instance is local realm */
+                                       client->realm.data,
+                                        0))) {
+        fprintf(stderr, "Error %s while building server name\n");
+        return(1);
+    }
+
+
+    if ((old_password = (char *) calloc (1, 255)) == NULL) {
+       fprintf(stderr, "No Memory for Retrieving old password\n");
+       return(1);
+    }
+
+    old_pwsize = 255;
+    if ((retval = krb5_read_password(
+                                prompt,
+                                0,
+                                old_password,
+                                &old_pwsize))) {
+       fprintf(stderr, "Error while reading password for '%s'",
+                                client_name);
+       return(1);
+    }
+
+/*     Build Request for Initial Credentials */
+    if ((retval = krb5_get_in_tkt_with_password(
+                                       0,      /* options */
+                                       my_addresses,
+                                       /* do random preauth */
+                                        KRB5_PADATA_ENC_RANDOM,
+                                       ETYPE_DES_CBC_CRC,   /* etype */
+                                       KEYTYPE_DES,
+                                       old_password,
+                                       cache,
+                                       &my_creds,
+                                       0  ))) {
+       keyseed.password.data = (char *) old_password;
+       if (old_password)
+           keyseed.password.length = strlen(old_password);
+       else
+           keyseed.password.length = 0;
+       keyseed.who = my_creds.client;
+/*
+       if ( retval != KDC_ERR_KEY_EXPIRED ) {
+                fprintf(stderr,"\nUnable to Get Initial Credentials : %s %d\n",
+                        error_message(retval),retval);
+                return(retval);
+       }
+*/
+        if ((retval = krb5_get_in_tkt(
+                       0,      /* options */
+                       my_addresses,
+                        KRB5_PADATA_ENC_RANDOM,        /* do random preauth */
+                       ETYPE_DES_CBC_CRC,
+                       KEYTYPE_DES,
+                       v4_pwd_keyproc,
+                       (krb5_pointer) &keyseed,
+                       krb5_kdc_rep_decrypt_proc,
+                       0,
+                       &my_creds,
+                       cache,
+                       0 ))) { 
+           fprintf(stderr, "\nUnable to Get Initial Credentials : %s %d\n",
+                       error_message(retval),retval);
+           return(retval);
+       }
+    }
+
+       /* Do NOT Forget to zap password  */
+    memset((char *) old_password, 0, old_pwsize);
+    free(old_password);
+    memset((char *) pword, 0, sizeof(pword));
+    return(0);
+}
+
+#ifdef MACH_PASS /* Machine-generated Passwords */
+krb5_error_code
+print_and_choose_password(DECLARG(char *, new_password),
+                       DECLARG(krb5_data *, decodable_pwd_string))
+OLDDECLARG(char *, new_password)
+OLDDECLARG(krb5_data *, decodable_pwd_string)
+
+{
+krb5_error_code retval;
+   krb5_pwd_data *pwd_data;
+   passwd_phrase_element **next_passwd_phrase_element;
+   char prompt[255];
+   char *verify_prompt = 0;
+   int i, j, k;
+   int legit_pswd = 0; /* Assume No Legitimate Password */
+   char *password_list[ADM_MAX_PW_CHOICES];
+   char verification_passwd[ADM_MAX_PW_LENGTH+1];
+   /* char new_passwd[ADM_MAX_PW_LENGTH]; */
+   char phrase_in[ADM_MAX_PHRASE_LENGTH];
+   int new_passwd_length;
+   char *ptr;
+   int verify = 0;     /* Do Not Request Password Selection Verification */ 
+   int ok = 0;
+
+#define free_local_password_list() \
+{  for ( k = 0; k < i && k < ADM_MAX_PW_CHOICES; k++) { \
+      (void) memset(password_list[k], 0, ADM_MAX_PW_LENGTH); \
+      free(password_list[k]); } \
+}
+
+     /* Decode Password and Phrase Information Obtained from krb5_rd_priv */
+   if ((retval = decode_krb5_pwd_data(decodable_pwd_string , &pwd_data))) { 
+       fprintf(stderr, "Unable to Decode Passwords and Phrases\n");
+        fprintf(stderr, "      Notify your System Administrator or the ");
+       fprintf(stderr, "Kerberos Administrator\n");
+       return(1);
+   }
+
+   next_passwd_phrase_element = pwd_data->element;
+       /* Display List in 5 Password/Phrase Increments up to MAX Iterations */
+   memset((char *) phrase_in, 0, ADM_MAX_PHRASE_LENGTH);
+   for ( j = 0; j <= ADM_MAX_PW_ITERATIONS; j++) {
+       if (j == ADM_MAX_PW_ITERATIONS) {
+           fprintf(stderr, "\n\nSorry - You Have Exceeded the List of ");
+           fprintf(stderr, "Choices (%d) Allowed for Password\n",
+                       ADM_MAX_PW_ITERATIONS * ADM_MAX_PW_CHOICES);
+           fprintf(stderr, "   Modification.  You Must Repeat this ");
+           fprintf(stderr, "Operation in order to Successfully\n");
+           fprintf(stderr, "   Change your Password.\n");
+           break;
+       }
+
+       display_print:
+       printf("\n\nChoose a password from the following list:\n");
+
+       printf("\n\nPassword                        Remembrance Aid\n\n\n");
+
+               /* Print Passwords and Assistance Phrases List */
+       for ( i = 0; i < ADM_MAX_PW_CHOICES; i++){
+           if ((password_list[i] = (char *) calloc (1, 
+                       ADM_MAX_PW_LENGTH + 1)) == NULL) {
+               fprintf(stderr, "Unable to Allocate Password List.\n");
+               return(1);
+           }
+
+           memcpy(password_list[i],
+               (*next_passwd_phrase_element)->passwd->data,
+               (*next_passwd_phrase_element)->passwd->length);
+           printf("%s  ", password_list[i]);
+
+           memcpy((char *) phrase_in,
+               (*next_passwd_phrase_element)->phrase->data,
+               (*next_passwd_phrase_element)->phrase->length);
+           for ( k = 0; 
+                 k < 50 && k < (*next_passwd_phrase_element)->phrase->length; 
+                 k++) {
+               printf("%c", phrase_in[k]);
+           }
+           for ( k = k;
+                 k < 70 && k < (*next_passwd_phrase_element)->phrase->length;
+                 k++) {
+               if (phrase_in[k] == ' ') {
+                   printf("\n          ");
+                   k++;
+                   break;
+               } else {
+                   printf("%c", phrase_in[k]);
+               }
+           }
+           for ( k = k;
+                 k < (*next_passwd_phrase_element)->phrase->length;
+                 k++) {
+               printf("%c", phrase_in[k]);
+           }
+           printf("\n\n");
+           memset((char *) phrase_in, 0, ADM_MAX_PHRASE_LENGTH);
+           next_passwd_phrase_element++;
+       }
+
+           sprintf(prompt, 
+               "\n\nEnter Password Selection or a <CR> to get new list: ");
+
+           new_passwd_length = ADM_MAX_PW_LENGTH+1;
+       /* Read New Password from Terminal (Do Not Print on Screen) */
+           if ((retval = krb5_read_password(&prompt[0], 0, 
+                       new_password, &new_passwd_length))) {
+               fprintf(stderr, 
+                   "\nError Reading Password Input or Input Aborted\n");
+               free_local_password_list();
+               break;;
+           }
+
+       /* Check for <CR> ==> Provide a New List */
+           if (new_passwd_length == 0) continue;
+
+       /* Check that Selection is from List - Server also does this */
+           legit_pswd = 0;
+           for (i = 0; i < ADM_MAX_PW_CHOICES && !legit_pswd; i++)
+               if ((retval = memcmp(new_password, 
+                               password_list[i], 8)) == 0) {
+                   legit_pswd++;
+               }
+           free_local_password_list();
+
+           if (!(legit_pswd)) {
+               printf("\n\07\07Password must be from the specified list ");
+               printf("- Try Again!\n");
+           }
+
+           if (legit_pswd) break;      /* Exit Loop */
+       }               /* ADM_MAX_PW_CHOICES Loop */
+
+   if (!(legit_pswd)) return (1);
+
+   return(0);          /* SUCCESS */
+}
+#endif
+
+krb5_error_code
+adm5_init_link( realm_of_server, local_socket)
+krb5_data *realm_of_server;
+int * local_socket;
+
+{
+    struct servent *service_process;          /* service we will talk to */
+    struct hostent *local_host;                       /* us */
+    struct hostent *remote_host;              /* host we will talk to */
+    struct sockaddr *sockaddr_list;
+
+    char **hostlist;
+
+    int host_count;
+    int namelen;
+    int i, count;
+
+    krb5_error_code retval;
+
+    /* clear out the structure first */
+    (void) memset((char *)&remote_sin, 0, sizeof(remote_sin));
+
+    if ((service_process = getservbyname(CPW_SNAME, "tcp")) == NULL) {
+       fprintf(stderr, "Unable to find Service (%s) Check services file\n",
+               CPW_SNAME);
+       return(1);
+    }
+
+               /* Copy the Port Number */
+    remote_sin.sin_port = service_process->s_port;
+
+    hostlist = 0;
+
+               /* Identify all Hosts Associated with this Realm */
+    if ((retval = krb5_get_krbhst (realm_of_server, &hostlist))) {
+        fprintf(stderr, "krb5_get_krbhst: Unable to Determine Server Name\n");
+        return(1);
+    }
+
+    for (i=0; hostlist[i]; i++);
+    count = i;
+
+    if (count == 0) {
+        host_count = 0;
+        fprintf(stderr, "No hosts found\n");
+        return(1);
+    }
+
+    for (i=0; hostlist[i]; i++) {
+        remote_host = gethostbyname(hostlist[i]);
+        if (remote_host != 0) {
+
+               /* set up the address of the foreign socket for connect() */
+           remote_sin.sin_family = remote_host->h_addrtype;
+           (void) memcpy((char *) &remote_sin.sin_addr, 
+                       (char *) remote_host->h_addr,
+                       sizeof(remote_host->h_addr));
+           break;      /* Only Need one */
+       }
+    }
+
+    free ((char *)hostlist);
+
+    /* open a TCP socket */
+    *local_socket = socket(PF_INET, SOCK_STREAM, 0);
+    if (*local_socket < 0) {
+       fprintf(stderr, "Cannot Open Socket\n");
+       return(1);
+    }
+    /* connect to the server */
+    if (connect(*local_socket, &remote_sin, sizeof(remote_sin)) < 0) {
+       fprintf(stderr, "Cannot Connect to Socket\n");
+       close(*local_socket);
+       return(1);
+    }
+
+    /* find out who I am, now that we are connected and therefore bound */
+    namelen = sizeof(local_sin);
+    if (getsockname(*local_socket, 
+               (struct sockaddr *) &local_sin, &namelen) < 0) {
+       fprintf(stderr, "Cannot Perform getsockname\n");
+       close(*local_socket);
+       return(1);
+    }
+       return(0);
+}
+
+usage()
+{
+    fprintf(stderr, "Usage: ");
+    fprintf(stderr, "kpasswd [name]\n");
+    exit(0);
+}
diff --git a/src/kadmin/kpasswd/networked.c b/src/kadmin/kpasswd/networked.c
new file mode 100644 (file)
index 0000000..3ddd0ff
--- /dev/null
@@ -0,0 +1,226 @@
+/*                     Networked                               */
+/*                                                             */
+/* Written by: Glenn Machin 2931                               */
+/* Originated:  Nov 12, 1990                                   */
+/* Description:                                                        */
+/*                                                             */
+/*     This program/routine exits/returns with a status 1 if   */
+/*     the terminal associated with the current process is     */
+/*     connected from a remote host, otherwise exits/returns   */
+/*     with a value of 0.                                      */
+/*                                                             */
+/*     This program/routine makes some basic assumptions about */
+/*      utmp:                                                  */
+/*             *The login process, rcmd, or window application */
+/*              makes an entry into utmp for all currents      */
+/*              users.                                         */
+/*             *For entries in which the users have logged in  */
+/*              locally. The line name is not a pseudo tty     */
+/*              device.                                        */
+/*             *For X window application in which             */
+/*              the device is a pseudo tty device but the      */
+/*               display is the local system, then the ut_host  */
+/*              has the format system_name:0.0 or :0.0.        */
+/*              All other entries will be assumed to be        */
+/*              networked.                                     */
+/*                                                             */
+/*     Changes:   11/15/90  Check for file /etc/krb.secure.    */
+/*                          If it exists then perform network  */
+/*                          check, otherwise return 0.         */
+/****************************************************************/
+/* 
+ * Sandia National Laboratories also makes no representations about the 
+ * suitability of the modifications, or additions to this software for 
+ * any purpose.  It is provided "as is" without express or implied warranty.
+ */
+#ifndef _TYPES_
+#include <sys/types.h>
+#ifndef _TYPES_
+#define _TYPES_
+#endif
+#endif
+#include <utmp.h>
+#include <pwd.h>
+
+#ifndef MAXHOSTNAME
+#define MAXHOSTNAME 64
+#endif
+
+int utfile;                    /* Global utfile file descriptor for BSD version
+                                  of setutent, getutline, and endutent */
+
+#if !defined(SYSV) && !defined(UMIPS)  /* Setutent, Endutent, and getutline
+                                          routines for non System V Unix
+                                                systems */
+#include <fcntl.h>
+
+void setutent()
+{
+  utfile = open("/etc/utmp",O_RDONLY);
+}
+
+struct utmp * getutline(utmpent)
+struct utmp *utmpent;
+{
+ static struct utmp tmputmpent;
+ int found = 0;
+ while ( read(utfile,&tmputmpent,sizeof(struct utmp)) > 0 ){
+       if ( strcmp(tmputmpent.ut_line,utmpent->ut_line) == 0){
+#ifdef NO_UT_HOST
+               if ( ( 1) &&
+#else
+               if ( (strcmp(tmputmpent.ut_host,"") == 0) && 
+#endif
+                  (strcmp(tmputmpent.ut_name,"") == 0)) continue;
+               found = 1;
+               break;
+       }
+ }
+ if (found) 
+       return(&tmputmpent);
+ return((struct utmp *) 0);
+}
+
+void endutent()
+{
+  close(utfile);
+}
+#endif /* not SYSV */
+
+
+int network_connected()
+{
+struct utmp utmpent;
+struct utmp retutent, *tmpptr;
+char *display_indx;
+char currenthost[MAXHOSTNAME];
+char *username,*tmpname;
+
+
+/* Macro for pseudo_tty */
+#define pseudo_tty(ut) \
+        ((strncmp((ut).ut_line, "tty", 3) == 0 && ((ut).ut_line[3] == 'p' \
+                                                || (ut).ut_line[3] == 'q' \
+                                                || (ut).ut_line[3] == 'r' \
+                                                || (ut).ut_line[3] == 's'))\
+                               || (strncmp((ut).ut_line, "pty", 3) == 0))
+
+    /* Check to see if getlogin returns proper name */
+    if ( (tmpname = (char *) getlogin()) == (char *) 0) return(1);
+    username = (char *) malloc(strlen(tmpname) + 1);
+    if ( username == (char *) 0) return(1);
+    strcpy(username,tmpname);
+    
+    /* Obtain tty device for controlling tty of current process.*/
+    strncpy(utmpent.ut_line,ttyname(0) + strlen("/dev/"),
+           sizeof(utmpent.ut_line));
+
+    /* See if this device is currently listed in /etc/utmp under
+       calling user */
+#ifdef SYSV
+    utmpent.ut_type = USER_PROCESS;
+#define ut_name ut_user
+#endif
+    setutent();
+    while ( (tmpptr = (struct utmp *) getutline(&utmpent)) 
+            != ( struct utmp *) 0) {
+
+       /* If logged out name and host will be empty */
+       if ((strcmp(tmpptr->ut_name,"") == 0) &&
+#ifdef NO_UT_HOST
+           ( 1)) continue;
+#else
+           (strcmp(tmpptr->ut_host,"") == 0)) continue;
+#endif
+       else break;
+    }
+    if (  tmpptr   == (struct utmp *) 0) {
+       endutent();
+       return(1);
+    }
+    byte_copy((char *)tmpptr,(char *)&retutent,sizeof(struct utmp));
+    endutent();
+#ifdef DEBUG
+#ifdef NO_UT_HOST
+    printf("User %s on line %s :\n",
+               retutent.ut_name,retutent.ut_line);
+#else
+    printf("User %s on line %s connected from host :%s:\n",
+               retutent.ut_name,retutent.ut_line,retutent.ut_host);
+#endif
+#endif
+    if  (strcmp(retutent.ut_name,username) != 0) {
+        return(1);
+    }
+
+
+    /* If this is not a pseudo tty then everything is OK */
+    if (! pseudo_tty(retutent)) return(0);
+
+    /* OK now the work begins there is an entry in utmp and
+       the device is a pseudo tty. */
+
+    /* Check if : is in hostname if so this is xwindow display */
+
+    if (gethostname(currenthost,sizeof(currenthost))) return(1);
+#ifdef NO_UT_HOST
+    display_indx = (char *) 0;
+#else
+    display_indx = (char *) strchr(retutent.ut_host,':');
+#endif
+    if ( display_indx != (char *) 0) {
+        /* 
+           We have X window application here. The host field should have
+          the form => local_system_name:0.0 or :0.0  
+           if the window is being displayed on the local system.
+         */
+#ifdef NO_UT_HOST
+       return(1);
+#else
+        if (strncmp(currenthost,retutent.ut_host,
+                (display_indx - retutent.ut_host)) != 0) return(1);
+        else return(0);
+#endif
+    }
+    
+    /* Host field is empty or is not X window entry. At this point
+       we can't trust that the pseudo tty is not connected to a 
+       networked process so let's return 1.
+     */
+    return(1);
+}
+
+byte_copy(str1,str2,len)
+char *str1, *str2;
+int len;
+{
+ int i;
+ for (i=0;i < len; i++) *(str2 + i) = *(str1 + i);
+ return;
+}
+
+
+#ifdef NOTKERBEROS
+main(argc,argv)
+int argc;
+char **argv;
+{
+  if (network_connected()){
+#ifdef DEBUG
+        printf("Networked\n");
+#endif
+       exit(1);
+  }
+  else {
+#ifdef DEBUG
+       printf("Not networked\n");
+#endif
+       exit(0);
+  }
+}
+#else
+int networked()
+{
+  return(network_connected());
+}
+#endif
diff --git a/src/kadmin/server/Imakefile b/src/kadmin/server/Imakefile
new file mode 100644 (file)
index 0000000..24d6465
--- /dev/null
@@ -0,0 +1,58 @@
+# $Source$
+# $Author$
+# $Header$
+#
+# Copyright 1989 by the Massachusetts Institute of Technology.
+#
+# For copying and distribution information,
+# please see the file <mit-copyright.h>.
+#
+# Imakefile for Kerberos admin server library.
+
+#ifdef Krb4KDCCompat
+K4LIB=-l$(KRB425LIB) -l$(DES425LIB)
+#else
+K4LIB=
+#endif
+
+SRCS = \
+       adm_server.c \
+       adm_parse.c \
+       adm_network.c \
+       adm_listen.c \
+       adm_process.c \
+       adm_nego.c \
+       adm_kpasswd.c \
+       adm_kadmin.c \
+       adm_fmt_inq.c \
+       adm_adm_func.c \
+       adm_funcs.c \
+       adm_check.c \
+       adm_extern.c 
+
+OBJS = \
+       adm_server.o \
+       adm_parse.o \
+       adm_network.o \
+       adm_listen.o \
+       adm_process.o \
+       adm_nego.o \
+       adm_kpasswd.o \
+       adm_kadmin.o \
+       adm_fmt_inq.o \
+       adm_adm_func.o \
+       adm_funcs.o \
+       adm_check.o \
+       adm_extern.o
+
+ErrorTableObjectRule()
+
+all::  kadmind
+
+NormalProgramTarget(kadmind,$(OBJS),$(KDBDEPLIB) $(DEPKLIB), \
+       $(KDBLIB) $(K4LIB) $(KLIB) ,)
+Krb5InstallServerProgram(kadmind)
+
+clean::
+
+DependTarget()
diff --git a/src/kadmin/server/adm_adm_func.c b/src/kadmin/server/adm_adm_func.c
new file mode 100644 (file)
index 0000000..f694741
--- /dev/null
@@ -0,0 +1,873 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America is assumed
+ *   to require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * Sandia National Laboratories also makes no representations about the 
+ * suitability of the modifications, or additions to this software for 
+ * any purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * Modify the Kerberos Database
+ */
+
+#if !defined(lint) && !defined(SABER)
+static char rcsid_adm_adm_func[] =
+  "$Id$";
+#endif /* !lint & !SABER */
+
+#include <sys/types.h>
+#include <syslog.h>
+#include <com_err.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#ifndef hpux
+#include <arpa/inet.h>
+#endif
+
+#include <krb5/krb5.h>
+#include <krb5/ext-proto.h>
+#include <krb5/los-proto.h>
+#include <krb5/kdb.h>
+#include <krb5/kdb_dbm.h>
+
+#include <krb5/adm_defs.h>
+#include "adm_extern.h"
+
+#ifdef SANDIA
+extern int classification;
+#endif
+
+krb5_error_code
+  adm_build_key (newprinc, client_creds, new_passwd, oper_type, entry)
+krb5_principal newprinc;
+krb5_ticket *client_creds;
+char *new_passwd;
+int oper_type;
+krb5_db_entry entry;
+{
+    krb5_data outbuf;
+    int retval;
+#if defined(MACH_PASS) || defined(SANDIA)
+    char *tmp_phrase;
+    char *tmp_passwd;
+    int pwd_length, phrase_length;
+#endif
+
+#if defined(MACH_PASS) || defined(SANDIA)
+    
+    if ((tmp_passwd = (char *) calloc (1, 120)) == (char *) 0) {
+       com_err("adm_build_key", ENOMEM, "for tmp_passwd");
+       return(3);              /* No Memory */
+    }
+    
+    if ((tmp_phrase = (char *) calloc (1, 120)) == (char *) 0) {
+       free(tmp_passwd);
+       com_err("adm_build_key", ENOMEM, "for tmp_phrase");
+       return(3);              /* No Memory */
+    }
+    
+    if (retval = get_pwd_and_phrase("adm_build_key", &tmp_passwd, 
+                                   &tmp_phrase)) {
+       free(tmp_passwd);
+       free(tmp_phrase);
+       return(4);              /* Unable to get Password */
+    }
+    
+    if ((outbuf.data = (char *) calloc (1, strlen(tmp_passwd) + 1)) == 
+       (char *) 0) {
+       com_err("adm_build_key", ENOMEM, "for outbuf.data");
+       free(tmp_passwd);
+       free(tmp_phrase);
+       return(3);              /* No Memory */
+    }
+    
+    outbuf.length = strlen(tmp_passwd);
+    (void) memcpy(outbuf.data, tmp_passwd, strlen(tmp_passwd));
+    
+#else 
+    
+    if ((outbuf.data = (char *) calloc (1, 3)) == 
+       (char *) 0) {
+       com_err("adm_build_key", ENOMEM, "for outbuf.data");
+       return(3);              /* No Memory */
+    }
+
+    outbuf.data[0] = KADMIN;
+    outbuf.data[1] = oper_type;
+    outbuf.data[2] = KADMGOOD;
+    outbuf.length = 3;
+    
+    if (oper_type == CHGOPER || oper_type == CH4OPER) {
+       outbuf.data[3] = entry.salt_type;
+       outbuf.length = 4;
+    }
+    
+#endif
+
+    /* Encrypt Password and Phrase */
+    if (retval = krb5_mk_priv(&outbuf,
+                             ETYPE_DES_CBC_CRC,
+                             client_creds->enc_part2->session,
+                             &client_server_info.server_addr,
+                             &client_server_info.client_addr,
+                             send_seqno,
+                             KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                             0,
+                             0,
+                             &msg_data)) {
+       com_err("adm_build_key", retval, "during mk_priv");
+#if defined(MACH_PASS) || defined(SANDIA)
+       free(tmp_passwd);
+       free(tmp_phrase);
+#endif
+       free(outbuf.data);
+       return(5);              /* Protocol Failure */
+    }
+    
+#if defined(MACH_PASS) || defined(SANDIA)
+    (void) memcpy(new_passwd, tmp_passwd, strlen(tmp_passwd));
+    new_passwd[strlen(tmp_passwd)] = '\0';
+    
+    free(tmp_phrase);
+    free(tmp_passwd);
+#endif
+    free(outbuf.data);
+    
+    /* Send private message to Client */
+    if (krb5_write_message(&client_server_info.client_socket, &msg_data)){
+       com_err("adm_build_key", 0, "Error Performing Password Write");
+       return(5);              /* Protocol Failure */
+    }
+    
+    free(msg_data.data);
+    
+    /* Read Client Response */
+    if (krb5_read_message(&client_server_info.client_socket, &inbuf)){
+       syslog(LOG_ERR | LOG_INFO, "Error Performing Password Read");
+       return(5);              /* Protocol Failure */
+    }
+    
+    /* Decrypt Client Response */
+    if (retval = krb5_rd_priv(&inbuf,
+                             client_creds->enc_part2->session,
+                             &client_server_info.client_addr,
+                             &client_server_info.server_addr,
+                             recv_seqno,
+                             KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                             0,
+                             0,
+                             &msg_data)) {
+       syslog(LOG_ERR | LOG_INFO, "adm_build_key krb5_rd_priv error");
+       free(inbuf.data);
+       return(5);              /* Protocol Failure */
+    }
+    free(inbuf.data);
+    
+#if !defined(MACH_PASS) && !defined(SANDIA)
+    memcpy(new_passwd, msg_data.data, msg_data.length);
+#endif
+    
+    free(msg_data.data);
+    return(0);
+}
+
+/*     kadmin change password request  */
+krb5_error_code
+  adm_change_pwd(prog, customer_name, client_creds, salttype)
+char *prog;
+char *customer_name;
+krb5_ticket *client_creds;
+int salttype;
+{
+    krb5_db_entry entry;
+    int nprincs = 1;
+    
+    krb5_error_code retval;
+    krb5_principal newprinc;
+    char *composite_name;
+    char *new_passwd;
+    int oper_type;
+    
+    syslog(LOG_AUTH | LOG_INFO, 
+          "Remote Administrative Password Change Request for %s by %s", 
+          customer_name, client_server_info.name_of_client);
+    
+    if (retval = krb5_parse_name(customer_name, &newprinc)) {
+       syslog(LOG_ERR | LOG_INFO, "parse failure while parsing '%s'", 
+              customer_name);
+       return(5);              /* Protocol Failure */
+    }
+    
+    if (!(adm_princ_exists("adm_change_pwd", newprinc,
+                          &entry, &nprincs))) {
+       com_err("adm_change_pwd", 0, "Principal does not exist!");
+       krb5_free_principal(newprinc);
+       krb5_db_free_principal(&entry, nprincs);
+       return(1);              /* Principal Unknown */
+    }
+    
+    if ((new_passwd = (char *) calloc (1, ADM_MAX_PW_LENGTH+1)) == (char *) 0) {
+       com_err("adm_change_pwd", ENOMEM, "while allocating new_passwd!");
+       krb5_free_principal(newprinc);
+       krb5_db_free_principal(&entry, nprincs);
+       return(3);              /* No Memory */
+    }
+    
+    oper_type = (salttype == KRB5_KDB_SALTTYPE_NORMAL) ? CHGOPER : CH4OPER;
+
+    if (retval = adm_build_key(newprinc, 
+                              client_creds, 
+                              new_passwd, 
+                              oper_type,
+                              entry)) {
+       krb5_free_principal(newprinc);
+       krb5_db_free_principal(&entry, nprincs);
+       free(new_passwd);
+       return(retval);
+    }
+    
+    retval = krb5_unparse_name(newprinc, &composite_name);
+
+    entry.salt_type = (krb5_int32) salttype;
+
+    if (retval = adm_enter_pwd_key("adm_change_pwd",              
+                                  composite_name,
+                                  newprinc,
+                                  newprinc,
+                                  1,           /* chg_entry */
+                                  salttype,
+                                  new_passwd,
+                                  &entry)) retval = 8;
+    krb5_free_principal(newprinc);
+    krb5_db_free_principal(&entry, nprincs);
+    free(composite_name);
+    
+    (void) memset(new_passwd, 0, strlen(new_passwd));
+    free(new_passwd);
+    return(0);
+}
+
+/* kadmin add new random key function */
+krb5_error_code
+  adm_change_pwd_rnd(cmdname, customer_name, client_creds)
+char *cmdname;
+char *customer_name;
+krb5_ticket *client_creds;
+{
+    krb5_db_entry entry;
+    int nprincs = 1;
+    krb5_error_code retval;
+    krb5_principal newprinc;
+
+    
+    syslog(LOG_AUTH | LOG_INFO, 
+          "Remote Administrative Addition Request for %s by %s", 
+          customer_name, client_server_info.name_of_client);
+    
+    if (retval = krb5_parse_name(customer_name, &newprinc)) {
+       com_err("adm_change_pwd_rnd", retval, "while parsing '%s'", customer_name);
+       return(5);              /* Protocol Failure */
+    }
+#ifdef SANDIA       
+    if (!(newprinc[2])) {
+       if (retval = check_security(newprinc, classification)) {
+           krb5_free_principal(newprinc);
+           syslog(LOG_ERR, "Principal (%s) - Incorrect Classification level",
+                  customer_name);
+           return(6);
+       }
+    }
+#endif
+    if (!(adm_princ_exists("adm_change_pwd_rnd", newprinc,
+                          &entry, &nprincs))) {
+       com_err("adm_change_pwd_rnd", 0, "Principal does not exist!");
+       krb5_free_principal(newprinc);
+       krb5_db_free_principal(&entry, nprincs);
+       return(1);              /* Principal Unknown */
+    }
+    
+    if (retval = adm_enter_rnd_pwd_key("adm_change_pwd_rnd",
+                                      newprinc,
+                                      1, /* change existing entry */
+                                      &entry))
+      retval = 8;
+       
+    krb5_free_principal(newprinc);
+    krb5_db_free_principal(&entry, nprincs);
+    return(retval);
+}
+
+/* kadmin add new key function */
+krb5_error_code
+  adm_add_new_key(cmdname, customer_name, client_creds, salttype)
+char *cmdname;
+char *customer_name;
+krb5_ticket *client_creds;
+int salttype;
+{
+    krb5_db_entry entry;
+    int nprincs = 1;
+    
+    krb5_error_code retval;
+    krb5_principal newprinc;
+    char *new_passwd;
+    
+    syslog(LOG_AUTH | LOG_INFO, 
+          "Remote Administrative Addition Request for %s by %s", 
+          customer_name, client_server_info.name_of_client);
+    
+    if (retval = krb5_parse_name(customer_name, &newprinc)) {
+       com_err("adm_add_new_key", retval, "while parsing '%s'", customer_name);
+       return(5);              /* Protocol Failure */
+    }
+#ifdef SANDIA       
+    if (!(newprinc[2])) {
+       if (retval = check_security(newprinc, classification)) {
+           krb5_free_principal(newprinc);
+           syslog(LOG_ERR, "Principal (%s) - Incorrect Classification level",
+                  customer_name);
+           return(6);
+       }
+    }
+#endif
+    if (adm_princ_exists("adm_add_new_key", newprinc, &entry, &nprincs)) {
+       com_err("adm_add_new_key", 0, 
+               "principal '%s' already exists", customer_name);
+       krb5_free_principal(newprinc);
+       krb5_db_free_principal(&entry, nprincs);
+       return(2);              /* Principal Already Exists */
+    }
+    
+    if ((new_passwd = (char *) calloc (1, 255)) == (char *) 0) {
+       com_err("adm_add_new_key", ENOMEM, "for new_passwd");
+       krb5_free_principal(newprinc);
+       krb5_db_free_principal(&entry, nprincs);
+       return(3);              /* No Memory */
+    }
+    
+    if (retval = adm_build_key(newprinc, 
+                              client_creds, 
+                              new_passwd, 
+                              ADDOPER,
+                              entry)) {
+       krb5_free_principal(newprinc);
+       krb5_db_free_principal(&entry, nprincs);
+       free(new_passwd);
+       return(retval);
+    }
+    
+    if (retval = adm_enter_pwd_key( "adm_add_new_key", 
+                                  customer_name,
+                                  newprinc, 
+                                  newprinc,
+                                  0,           /* new_entry */
+                                  salttype,
+                                  new_passwd,
+                                  &entry)) 
+      retval = 8;
+    (void) memset(new_passwd, 0, strlen(new_passwd));
+    free(new_passwd);
+    krb5_free_principal(newprinc);
+    krb5_db_free_principal(&entry, nprincs);
+    return(retval);
+}
+
+/* kadmin add new random key function */
+krb5_error_code
+  adm_add_new_key_rnd(cmdname, customer_name, client_creds)
+char *cmdname;
+char *customer_name;
+krb5_ticket *client_creds;
+{
+    krb5_db_entry entry;
+    int nprincs = 1;
+    krb5_error_code retval;
+    krb5_principal newprinc;
+
+    
+    syslog(LOG_AUTH | LOG_INFO, 
+          "Remote Administrative Addition Request for %s by %s", 
+          customer_name, client_server_info.name_of_client);
+    
+    if (retval = krb5_parse_name(customer_name, &newprinc)) {
+       com_err("adm_add_new_key_rnd", retval, "while parsing '%s'", customer_name);
+       return(5);              /* Protocol Failure */
+    }
+#ifdef SANDIA       
+    if (!(newprinc[2])) {
+       if (retval = check_security(newprinc, classification)) {
+           krb5_free_principal(newprinc);
+           syslog(LOG_ERR, "Principal (%s) - Incorrect Classification level",
+                  customer_name);
+           return(6);
+       }
+    }
+#endif
+    if (adm_princ_exists("adm_add_new_key_rnd", newprinc, &entry, &nprincs)) {
+       com_err("adm_add_new_key_rnd", 0, 
+               "principal '%s' already exists", customer_name);
+       krb5_free_principal(newprinc);
+       krb5_db_free_principal(&entry, nprincs);
+       return(2);              /* Principal Already Exists */
+    }
+    
+    if (retval = adm_enter_rnd_pwd_key("adm_add_new_key_rnd",
+                                      newprinc,
+                                      0, /* new entry */
+                                      &entry))
+      retval = 8;
+       
+    krb5_free_principal(newprinc);
+    krb5_db_free_principal(&entry, nprincs);
+    return(retval);
+}
+
+/* kadmin delete old key function */
+krb5_error_code
+  adm_del_old_key(cmdname, customer_name)
+char *cmdname;
+char *customer_name;
+{
+    krb5_db_entry entry;
+    int nprincs = 1;
+    
+    krb5_error_code retval;
+    krb5_principal newprinc;
+    int one = 1;
+    
+    syslog(LOG_AUTH | LOG_INFO, 
+          "Remote Administrative Deletion Request for %s by %s", 
+          customer_name, client_server_info.name_of_client);
+    
+    if (retval = krb5_parse_name(customer_name, &newprinc)) {
+       com_err("adm_del_old_key", retval, "while parsing '%s'", customer_name);
+       return(5);              /* Protocol Failure */
+    }
+    
+    if (!adm_princ_exists("adm_del_old_key", newprinc,
+                         &entry, &nprincs)) {
+       com_err("adm_del_old_key", 0, "principal '%s' is not in the database", 
+               customer_name);
+       krb5_free_principal(newprinc);
+       krb5_db_free_principal(&entry, nprincs);
+       return(1);
+    }
+    
+    if (retval = krb5_db_delete_principal(newprinc, &one)) {
+       com_err("adm_del_old_key", retval, 
+               "while deleting '%s'", customer_name);
+       krb5_free_principal(newprinc);
+       krb5_db_free_principal(&entry, nprincs);
+       return(8);
+    } else if (one != 1) {
+       com_err("adm_del_old_key", 0, 
+               "no principal deleted - unknown error");
+       krb5_free_principal(newprinc);
+       krb5_db_free_principal(&entry, nprincs);
+       return(8);
+    }
+    
+    krb5_free_principal(newprinc);
+    krb5_db_free_principal(&entry, nprincs);
+    return(0);
+}
+
+/* kadmin modify existing Principal function */
+krb5_error_code
+  adm_mod_old_key(cmdname, customer_name, client_creds)
+char *cmdname;
+char *customer_name;
+krb5_ticket *client_creds;
+{
+    krb5_db_entry entry;
+    int nprincs = 1;
+    extern int errno;
+    
+    krb5_error_code retval;
+    krb5_principal newprinc;
+    
+    krb5_data outbuf;
+    char tempstr[20];
+    
+    int one = 1;
+    
+    syslog(LOG_AUTH | LOG_INFO, 
+          "Remote Administrative Modification Request for %s by %s", 
+          customer_name, client_server_info.name_of_client);
+    
+    if (retval = krb5_parse_name(customer_name, &newprinc)) {
+       com_err("adm_mod_old_key", retval, "while parsing '%s'", customer_name);
+       return(5);              /* Protocol Failure */
+    }
+    
+    for ( ; ; ) {
+       
+       if (!adm_princ_exists("adm_mod_old_key", newprinc,
+                             &entry, &nprincs)) {
+           com_err("adm_mod_old_key", 0, 
+                   "principal '%s' is not in the database", 
+                   customer_name);
+           krb5_free_principal(newprinc);
+           return(1);
+       }
+       
+       /* Send Acknowledgement */
+       if ((outbuf.data = (char *) calloc (1, 255)) == (char *) 0) {
+           krb5_free_principal(newprinc);
+           krb5_db_free_principal(&entry, nprincs);
+           com_err("adm_mod_old_key", ENOMEM, "for outbuf.data");
+           return(3);          /* No Memory */
+       }
+       
+       outbuf.length = 3;
+       outbuf.data[0] = KADMIND;
+       outbuf.data[1] = MODOPER;
+       outbuf.data[2] = SENDDATA3;
+       
+       if (retval = krb5_mk_priv(&outbuf,
+                                 ETYPE_DES_CBC_CRC,
+                                 client_creds->enc_part2->session,
+                                 &client_server_info.server_addr,
+                                 &client_server_info.client_addr,
+                                 send_seqno,
+                                 KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                                 0,
+                                 0,
+                                 &msg_data)) {
+           krb5_free_principal(newprinc);
+           krb5_db_free_principal(&entry, nprincs);
+           com_err("adm_mod_old_key", retval, "during mk_priv");
+           free(outbuf.data);
+           return(5);          /* Protocol Failure */
+       }
+       free(outbuf.data);
+       
+       if (krb5_write_message(&client_server_info.client_socket, &msg_data)){
+           krb5_free_principal(newprinc);
+           krb5_db_free_principal(&entry, nprincs);
+           com_err("adm_mod_old_key", 0, 
+                   "Error Performing Modification Write");
+           return(5);          /* Protocol Failure */
+       }
+       free(msg_data.data);
+       
+       /* Read Client Response */
+       if (krb5_read_message(&client_server_info.client_socket, &inbuf)){
+           krb5_free_principal(newprinc);
+           krb5_db_free_principal(&entry, nprincs);
+           com_err("adm_mod_old_key", errno, 
+                   "Error Performing Modification Read");
+            return(5);         /* Protocol Failure */
+       }
+       
+       /* Decrypt Client Response */
+       if (retval = krb5_rd_priv(&inbuf,
+                                 client_creds->enc_part2->session,
+                                 &client_server_info.client_addr,
+                                 &client_server_info.server_addr,
+                                 recv_seqno,
+                                 KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                                 0,
+                                 0,
+                                 &msg_data)) {
+           com_err("adm_mod_old_key", retval, "krb5_rd_priv error %s",
+                   error_message(retval));
+           free(inbuf.data);
+           krb5_free_principal(newprinc);
+           krb5_db_free_principal(&entry, nprincs);
+           return(5);          /* Protocol Failure */
+       }
+       
+       free(inbuf.data);
+       
+       if (msg_data.data[1] == KADMGOOD) break;
+       
+       /* Decode Message - Modify Database */
+       if (msg_data.data[2] != SENDDATA3) {
+           free(msg_data.data);
+           krb5_free_principal(newprinc);
+           krb5_db_free_principal(&entry, nprincs);
+           return(5);          /* Protocol Failure */
+       }
+#ifdef SANDIA
+       if (msg_data.data[3] == KMODFCNT) {
+           (void) memcpy(tempstr, (char *) msg_data.data + 4,
+                         msg_data.length - 4);
+           entry.fail_auth_count = atoi(tempstr);
+       }
+#endif
+       if (msg_data.data[3] == KMODVNO) {
+           (void) memcpy(tempstr, (char *) msg_data.data + 4,
+                         msg_data.length - 4);
+           entry.kvno = atoi(tempstr);
+       }
+       
+       if (msg_data.data[3] == KMODATTR) {
+           if (msg_data.data[4] == ATTRPOST)
+             entry.attributes &= ~KRB5_KDB_DISALLOW_POSTDATED;
+           if (msg_data.data[4] == ATTRNOPOST)
+             entry.attributes |= KRB5_KDB_DISALLOW_POSTDATED;
+           if (msg_data.data[4] == ATTRFOR) 
+             entry.attributes &= ~KRB5_KDB_DISALLOW_FORWARDABLE;
+           if (msg_data.data[4] == ATTRNOFOR) 
+             entry.attributes |= KRB5_KDB_DISALLOW_FORWARDABLE;
+           if (msg_data.data[4] == ATTRTGT) 
+             entry.attributes &= ~KRB5_KDB_DISALLOW_TGT_BASED;
+           if (msg_data.data[4] == ATTRNOTGT) 
+             entry.attributes |= KRB5_KDB_DISALLOW_TGT_BASED;
+           if (msg_data.data[4] == ATTRREN) 
+             entry.attributes &= ~KRB5_KDB_DISALLOW_RENEWABLE;
+           if (msg_data.data[4] == ATTRNOREN) 
+             entry.attributes |= KRB5_KDB_DISALLOW_RENEWABLE;
+           if (msg_data.data[4] == ATTRPROXY) 
+             entry.attributes &= ~KRB5_KDB_DISALLOW_PROXIABLE;
+           if (msg_data.data[4] == ATTRNOPROXY) 
+             entry.attributes |= KRB5_KDB_DISALLOW_PROXIABLE;
+           if (msg_data.data[4] == ATTRDSKEY) 
+             entry.attributes &= ~KRB5_KDB_DISALLOW_DUP_SKEY;
+           if (msg_data.data[4] == ATTRNODSKEY) 
+             entry.attributes |= KRB5_KDB_DISALLOW_DUP_SKEY;
+           if (msg_data.data[4] == ATTRLOCK) 
+             entry.attributes |= KRB5_KDB_DISALLOW_ALL_TIX;
+           if (msg_data.data[4] == ATTRUNLOCK) 
+             entry.attributes &= ~KRB5_KDB_DISALLOW_ALL_TIX;
+           if (msg_data.data[4] == ATTRNOSVR) 
+             entry.attributes |= KRB5_KDB_DISALLOW_SVR;
+           if (msg_data.data[4] == ATTRSVR) 
+             entry.attributes &= ~KRB5_KDB_DISALLOW_SVR;
+#ifdef SANDIA
+           if (msg_data.data[4] == ATTRPRE) 
+             entry.attributes &= ~KRB5_KDB_REQUIRES_PRE_AUTH;
+           if (msg_data.data[4] == ATTRNOPRE) 
+             entry.attributes |= KRB5_KDB_REQUIRES_PRE_AUTH;
+           if (msg_data.data[4] == ATTRPWOK) 
+             entry.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
+           if (msg_data.data[4] == ATTRPWCHG) 
+             entry.attributes |= KRB5_KDB_REQUIRES_PWCHANGE;
+           if (msg_data.data[4] == ATTRSID) 
+             entry.attributes &= ~KRB5_KDB_REQUIRES_SECUREID;
+           if (msg_data.data[4] == ATTRNOSID) 
+             entry.attributes |= KRB5_KDB_REQUIRES_SECUREID;
+#endif
+        }
+       
+       free(msg_data.data);
+       entry.mod_name = client_server_info.client;
+       if (retval = krb5_timeofday(&entry.mod_date)) {
+           com_err("adm_mod_old_key", retval, "while fetching date");
+           krb5_free_principal(newprinc);
+           krb5_db_free_principal(&entry, nprincs);
+           return(5);          /* Protocol Failure */
+       }
+       
+       retval = krb5_db_put_principal(&entry, &one);
+       one = 1;
+    }  /* for */
+    
+    krb5_db_free_principal(&entry, nprincs);
+    krb5_free_principal(newprinc);
+    
+    /* Read Client Response */
+    if (krb5_read_message(&client_server_info.client_socket, &inbuf)){
+       com_err("adm_mod_old_key", errno, "Error Performing Read");
+       return(5);              /* Protocol Failure */
+    }
+    
+    /* Decrypt Client Response */
+    if (retval = krb5_rd_priv(&inbuf,
+                             client_creds->enc_part2->session,
+                             &client_server_info.client_addr,
+                             &client_server_info.server_addr,
+                             recv_seqno,
+                             KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                             0,
+                             0,
+                             &msg_data)) {
+       com_err("adm_mod_old_key", retval, "krb5_rd_priv error %s",
+               error_message(retval));
+       free(inbuf.data);
+       return(5);              /* Protocol Failure */
+    }
+    
+    free(msg_data.data);
+    free(inbuf.data);
+    
+    return(0);
+}
+
+/* kadmin inquire existing Principal function */
+krb5_error_code
+  adm_inq_old_key(cmdname, customer_name, client_creds)
+char *cmdname;
+char *customer_name;
+krb5_ticket *client_creds;
+{
+    krb5_db_entry entry;
+    int nprincs = 1;
+    
+    krb5_data outbuf;
+    krb5_error_code retval;
+    krb5_principal newprinc;
+    char *fullname;
+    
+    syslog(LOG_AUTH | LOG_INFO, 
+          "Remote Administrative Inquiry Request for %s by %s", 
+          customer_name, client_server_info.name_of_client);
+    
+    if (retval = krb5_parse_name(customer_name, &newprinc)) {
+        com_err("adm_inq_old_key", retval, "while parsing '%s'", customer_name);
+       return(5);              /* Protocol Failure */
+    }
+    
+    if (retval = krb5_unparse_name(newprinc, &fullname)) {
+       krb5_free_principal(newprinc);
+       com_err("adm_inq_old_key", retval, "while unparsing");
+        return(5);             /* Protocol Failure */
+    }
+    
+    if (!adm_princ_exists("adm_inq_old_key", newprinc,
+                         &entry, &nprincs)) {
+       krb5_free_principal(newprinc);
+       free(fullname);
+       com_err("adm_inq_old_key", 0, "principal '%s' is not in the database", 
+               customer_name);
+       return(1);
+    }
+    
+    if ((outbuf.data = (char *) calloc (1, 2048)) == (char *) 0) {
+       krb5_db_free_principal(&entry, nprincs);
+       krb5_free_principal(newprinc);
+       free(fullname);
+       com_err("adm_inq_old_key", ENOMEM, "for outbuf.data");
+       return(3);              /* No Memory */
+    }
+    
+    /* Format Inquiry Data */
+    if ((retval = adm_fmt_prt(&entry, fullname, outbuf.data))) {
+       krb5_db_free_principal(&entry, nprincs);
+       krb5_free_principal(newprinc);
+       free(fullname);
+       com_err("adm_inq_old_key", 0, "Unable to Format Inquiry Data");
+    }
+    outbuf.length = strlen(outbuf.data);
+    krb5_db_free_principal(&entry, nprincs);
+    krb5_free_principal(newprinc);
+    free(fullname);
+    
+    /* Encrypt Inquiry Data */
+    if (retval = krb5_mk_priv(&outbuf,
+                             ETYPE_DES_CBC_CRC,
+                             client_creds->enc_part2->session,
+                             &client_server_info.server_addr,
+                             &client_server_info.client_addr,
+                             send_seqno,
+                             KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                             0,
+                             0,
+                             &msg_data)) {
+       com_err("adm_inq_old_key", retval, "during mk_priv");
+       free(outbuf.data);
+       return(5);              /* Protocol Failure */
+    }
+    
+    /* Send Inquiry Information */
+    if (krb5_write_message(&client_server_info.client_socket, &msg_data)){
+       com_err("adm_inq_old_key", 0, "Error Performing Write");
+       return(5);              /* Protocol Failure */
+    }
+    
+    free(msg_data.data);
+    
+    /* Read Client Response */
+    if (krb5_read_message(&client_server_info.client_socket, &inbuf)){
+       com_err("adm_inq_old_key", errno, "Error Performing Read");
+       syslog(LOG_ERR, "adm_inq sock %d", client_server_info.client_socket);
+       return(5);              /* Protocol Failure */
+    }
+    
+    /* Decrypt Client Response */
+    if (retval = krb5_rd_priv(&inbuf,
+                             client_creds->enc_part2->session,
+                             &client_server_info.client_addr,
+                             &client_server_info.server_addr,
+                             recv_seqno,
+                             KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                             0,
+                             0,
+                             &msg_data)) {
+       com_err("adm_inq_old_key", retval, "krb5_rd_priv error %s",
+               error_message(retval));
+       free(inbuf.data);
+       return(5);              /* Protocol Failure */
+    }
+    
+    free(msg_data.data);
+    free(inbuf.data);
+    return(retval);
+}
+
+#ifdef SANDIA
+krb5_error_code
+  check_security(princ, class)
+krb5_principal princ;
+int class;
+{
+    char *input_name;
+    
+    if ((input_name = (char *) calloc (1, 255)) == 0) {
+       com_err("check_security", 
+               ENOMEM, "while allocating memory for class check");
+       return(3);
+    }
+    
+    memcpy((char *) input_name, princ->data[0].data, princ->data[0].length);
+    
+    if (class) {
+       /* Must be Classified Principal */
+       if (strlen(input_name) == 8) {
+           if (!(strcmp(&input_name[7], "s") == 0) &&
+               !(strcmp(&input_name[7], "c") == 0)) {
+               free(input_name);
+               return(6);
+           }
+       }  else {
+           if (!((strncmp(&input_name[strlen(input_name) - 2], 
+                          "_s", 2) == 0) ||
+                 (strncmp(&input_name[strlen(input_name) - 2], "_c", 2) == 0))) {
+               free(input_name);
+               return(6);
+           }
+       }
+    } else {
+       /* Must be Unclassified Principal */
+       if ((strlen(input_name) >= 8) ||
+           ((strncmp(&input_name[strlen(input_name) - 2], "_s", 2) == 0) ||
+            (strncmp(&input_name[strlen(input_name) - 2], "_c", 2) == 0))) {
+           free(input_name);
+           return(6);
+       }
+    }
+    
+    free(input_name);
+    return(0);
+}
+#endif
diff --git a/src/kadmin/server/adm_check.c b/src/kadmin/server/adm_check.c
new file mode 100644 (file)
index 0000000..2cef975
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America is assumed
+ *   to require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * Sandia National Laboratories also makes no representations about the 
+ * suitability of the modifications, or additions to this software for 
+ * any purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ */
+
+#if !defined(lint) && !defined(SABER)
+static char rcsid_adm_check[] =
+"$Id$";
+#endif /* !lint & !SABER */
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <com_err.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#ifndef hpux
+#include <arpa/inet.h>
+#endif
+
+#include <krb5/krb5.h>
+#include <krb5/ext-proto.h>
+#include <krb5/los-proto.h>
+#include <krb5/adm_defs.h>
+#include <krb5/adm_err.h>
+#include "adm_extern.h"
+
+krb5_error_code
+adm_check_acl(name_of_client, acl_type)
+char *name_of_client;
+char *acl_type;
+{
+    FILE *acl_file;
+    char input_string[255];
+    char admin_name[255];
+#define num_of_privs   5
+    char priv[num_of_privs];
+    extern char *acl_file_name;
+    char *lcl_acl_file;
+    int i, j;
+
+    if ((lcl_acl_file = (char *) calloc(1, 80)) == (char *) 0) {
+       com_err("adm_check_acl", ENOMEM, "allocating acl file name");
+       return(KADM_ENOMEM);            /* No Memory */
+    }
+
+    (void) sprintf(lcl_acl_file, "%s", acl_file_name);
+
+    if ((acl_file = fopen(lcl_acl_file, "r")) == NULL) {
+       syslog(LOG_ERR, "Cannot open acl file (%s)", acl_file_name);
+       free(lcl_acl_file);
+       return(KADM_EPERM);
+    }
+
+    for ( ;; ) {
+
+       if ((fgets(input_string, sizeof(input_string), acl_file)) == NULL) {
+           syslog(LOG_ERR, "Administrator (%s) not in ACL file (%s)",
+               name_of_client, lcl_acl_file);
+           break;              /* Not Found */
+       }
+
+       if (input_string[0] == '#') continue;
+
+       i = 0;
+       while (!isspace(input_string[i]) && i < strlen(input_string)) {
+           admin_name[i] = input_string[i];
+           i++;
+       }
+
+       while (isspace(input_string[i]) && i < strlen(input_string)) {
+           i++;
+       }
+
+       priv[0] = priv[1] = priv[2] = priv[3] = priv[4] = '\0';
+
+       j = 0;
+       while ((i < strlen(input_string)) && (j < num_of_privs) &&
+               (!isspace(input_string[i]))) {
+           priv[j] = input_string[i];
+           i++; j++;
+       }
+
+       if (priv[0] == '*') {
+           priv[0] = 'a';              /* Add Priv */
+           priv[1] = 'c';              /* Changepw Priv */
+           priv[2] = 'd';              /* Delete Priv */
+           priv[3] = 'i';              /* Inquire Priv */
+           priv[4] = 'm';              /* Modify Priv */
+       }
+
+       if (!strncmp(admin_name, name_of_client, 
+               strlen(name_of_client))) {
+           switch(acl_type[0]) {
+               case 'a':
+               case 'c':
+               case 'd':
+               case 'i':
+               case 'm':
+                   for (i = 0; i < num_of_privs; i++) {
+                       if (priv[i] == acl_type[0]) {
+                           fclose(acl_file);
+                           free(lcl_acl_file);
+                           return(0);          /* Found */                     
+                       }
+                   }
+                   break;
+
+               default:
+                   break;
+           }
+       }
+    }
+
+    fclose(acl_file);
+    free(lcl_acl_file);
+    return(KADM_EPERM);
+}
diff --git a/src/kadmin/server/adm_extern.c b/src/kadmin/server/adm_extern.c
new file mode 100644 (file)
index 0000000..d544ce7
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ *
+ * Export of this software from the United States of America is assumed
+ *   to require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ *
+ * Sandia National Laboratories also makes no representations about the 
+ * suitability of the modifications, or additions to this software for 
+ * any purpose.  It is provided "as is" without express or implied warranty.
+ *
+ * allocations of adm_extern stuff
+ */
+
+#if !defined(lint) && !defined(SABER)
+static char rcsid_adm_extern_c[] =
+"$Id$";
+#endif /* !lint & !SABER */
+
+#include <krb5/copyright.h>
+
+#include <krb5/krb5.h>
+#include <krb5/kdb.h>
+#include <krb5/kdb_dbm.h>
+
+/* real declarations of KDC's externs */
+krb5_encrypt_block master_encblock;
+krb5_keyblock master_keyblock;
+krb5_principal master_princ;
+
+volatile int signal_requests_exit = 0; /* gets set when signal hits */
+
+char *dbm_db_name = DEFAULT_DBM_FILE;
+
+krb5_keyblock tgs_key;
+krb5_kvno tgs_kvno;
+
+krb5_data inbuf;
+krb5_data msg_data;
+
+int send_seqno;
+int recv_seqno;
+
+/*
+static krb5_data tgs_name = {sizeof(TGTNAME)-1, TGTNAME};
+krb5_data *tgs_server[4] = {0, &tgs_name, 0, 0};
+*/
+
+krb5_principal tgs_server;
diff --git a/src/kadmin/server/adm_extern.h b/src/kadmin/server/adm_extern.h
new file mode 100644 (file)
index 0000000..9095bdf
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * $Source$
+ * $Author$
+ * $Id$
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ *
+ * Export of this software from the United States of America is assumed
+ *   to require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * Sandia National Laboratories also makes no representations about the 
+ * suitability of the modifications, or additions to this software for 
+ * any purpose.  It is provided "as is" without express or implied warranty.
+ *
+ * <<< Description >>>
+ */
+
+#include <krb5/copyright.h>
+
+#ifndef __ADM_EXTERN__
+#define __ADM_EXTERN__
+
+typedef struct {
+       /* Client Info */
+  struct sockaddr_in client_name;
+  krb5_address client_addr;
+  krb5_principal client;
+  char *name_of_client;
+       /* Server Info */
+  struct sockaddr_in server_name;
+  krb5_address server_addr;
+  krb5_principal server;
+  char *name_of_service;
+       /* Miscellaneous */
+  int server_socket;
+  int client_socket;
+} global_client_server_info;
+/* various externs for KDC */
+extern krb5_encrypt_block master_encblock;
+extern krb5_keyblock master_keyblock;
+extern krb5_principal master_princ;
+
+extern volatile int signal_requests_exit;
+extern char *dbm_db_name;
+
+extern krb5_keyblock tgs_key;
+extern krb5_kvno tgs_kvno;
+extern krb5_principal tgs_server;
+
+extern global_client_server_info client_server_info;
+extern char *adm5_tcp_portname;
+extern int adm5_tcp_port_fd;
+
+extern unsigned pidarraysize;
+extern int *pidarray;
+
+extern char *adm5_ver_str;
+extern int adm5_ver_len;
+
+extern int send_seqno;
+extern int recv_seqno;
+
+extern int exit_now;
+
+extern krb5_data inbuf;
+extern krb5_data msg_data;
+
+#endif /* __ADM_EXTERN__ */
diff --git a/src/kadmin/server/adm_fmt_inq.c b/src/kadmin/server/adm_fmt_inq.c
new file mode 100644 (file)
index 0000000..b563ec4
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America is assumed
+ *   to require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * Sandia National Laboratories also makes no representations about the 
+ * suitability of the modifications, or additions to this software for 
+ * any purpose.  It is provided "as is" without express or implied warranty.
+ *
+ *     Administrative Display Routine
+ */
+
+#if !defined(lint) && !defined(SABER)
+static char rcsid_adm_fmt_inq[] =
+"$Id$";
+#endif /* !lint & !SABER */
+
+#include <krb5/krb5.h>
+#include <krb5/ext-proto.h>
+#include <krb5/los-proto.h>
+#include <krb5/kdb.h>
+#include <krb5/kdb_dbm.h>
+
+#include <com_err.h>
+#include <stdio.h>
+
+#if defined (unicos61) || (defined(mips) && defined(SYSTYPE_BSD43)) || defined(sysvimp)
+#include <time.h>
+#else
+#include <sys/time.h>
+#endif  /* unicos61 */
+#if defined(aux20)
+#include <time.h>
+#endif  /* aux20 */
+
+#define REALM_SEP      '@'
+#define REALM_SEP_STR  "@"
+
+krb5_error_code
+adm_print_attributes(ret_data, attribs)
+char *ret_data;
+krb5_flags attribs;
+{
+    char *my_data;
+
+    if ((my_data = (char *) calloc (1,255)) == (char *) 0) {
+       com_err("adm_print_attributes", ENOMEM, "");
+    }
+
+    sprintf(my_data, "Principal Attributes (PA): ");
+    if (attribs & KRB5_KDB_DISALLOW_POSTDATED)
+        strcat(my_data, "NOPOST ");
+    else
+        strcat(my_data, "POST ");
+    if (attribs & KRB5_KDB_DISALLOW_FORWARDABLE)
+        strcat(my_data, "NOFOR ");
+    else
+        strcat(my_data, "FOR ");
+    if (attribs & KRB5_KDB_DISALLOW_TGT_BASED)
+        strcat(my_data, "NOTGT ");
+    else
+        strcat(my_data, "TGT ");
+    if (attribs & KRB5_KDB_DISALLOW_RENEWABLE)
+        strcat(my_data, "NOREN ");
+    else
+        strcat(my_data, "REN ");
+    if (attribs & KRB5_KDB_DISALLOW_PROXIABLE)
+        strcat(my_data, "NOPROXY\n");
+    else
+        strcat(my_data, "PROXY\n");
+    strcat(my_data, "                           ");
+    if (attribs & KRB5_KDB_DISALLOW_DUP_SKEY)
+        strcat(my_data, "NODUPSKEY ");
+    else
+        strcat(my_data, "DUPSKEY ");
+    if (attribs & KRB5_KDB_DISALLOW_ALL_TIX)
+        strcat(my_data, "LOCKED ");
+    else
+        strcat(my_data, "UNLOCKED ");
+    if (attribs & KRB5_KDB_DISALLOW_SVR)
+        strcat(my_data, "NOSVR\n");
+    else
+        strcat(my_data, "SVR\n");
+    
+#ifdef SANDIA
+    strcat(my_data, "                           ");
+    if (attribs & KRB5_KDB_REQUIRES_PRE_AUTH)
+        strcat(my_data, "PREAUTH ");
+    else
+        strcat(my_data, "NOPREAUTH ");
+    if (attribs & KRB5_KDB_REQUIRES_PWCHANGE)
+        strcat(my_data, "PWCHG ");
+    else
+        strcat(my_data, "PWOK ");
+    if (attribs & KRB5_KDB_REQUIRES_HW_AUTH)
+        strcat(my_data, "SID\n");
+    else
+        strcat(my_data, "NOSID\n");
+#endif
+    (void) strcat(ret_data, my_data);
+    free(my_data);
+    return(0);
+}
+
+krb5_error_code
+adm_print_exp_time(ret_data, time_input)
+char *ret_data;
+krb5_timestamp *time_input;
+{
+    char *my_data;
+    struct tm *exp_time;
+
+    if ((my_data = (char *) calloc (1,255)) == (char *) 0) {
+       com_err("adm_print_attributes", ENOMEM, "");
+    }
+
+    exp_time = localtime((time_t *) time_input);
+    sprintf(my_data, 
+       "Principal Expiration Date (PED): %02d%02d/%02d/%02d:%02d:%02d:%02d\n",
+       (exp_time->tm_year >= 100) ? 20 : 19,
+       (exp_time->tm_year >= 100) ? exp_time->tm_year - 100 : exp_time->tm_year,
+       exp_time->tm_mon + 1,
+       exp_time->tm_mday,
+       exp_time->tm_hour,
+       exp_time->tm_min,
+       exp_time->tm_sec);
+    (void) strcat(ret_data, my_data);
+    free(my_data);
+    return(0);
+}
+
+krb5_error_code
+adm_fmt_prt(entry, Principal_name, ret_data)
+krb5_db_entry *entry;
+char *Principal_name;
+char *ret_data;
+{
+    struct tm *mod_time;
+#ifdef SANDIA
+    krb5_error_code retval;
+    struct tm *exp_time;
+    int pwd_expire;
+    krb5_timestamp now;
+#endif
+
+    char *my_data;
+    char thisline[80];
+
+    if ((my_data = (char *) calloc (1, 2048)) == (char *) 0) {
+       com_err("adm_print_attributes", ENOMEM, "");
+    }
+
+    (void) sprintf(my_data, "\n\nPrincipal: %s\n\n", Principal_name);
+    sprintf(thisline,
+       "Maximum Ticket Lifetime (MTL) = %d (seconds)\n", entry->max_life);
+    strcat(my_data, thisline);
+    sprintf(thisline, "Maximum Renewal Lifetime (MRL) = %d (seconds)\n", 
+                       entry->max_renewable_life);
+    strcat(my_data, thisline);
+    sprintf(thisline, "Principal Key Version (PKV) = %d\n", entry->kvno);
+    strcat(my_data, thisline);
+    (void) adm_print_exp_time(my_data, &entry->expiration);
+    mod_time = localtime((time_t *) &entry->mod_date);
+    sprintf(thisline, 
+       "Last Modification Date (LMD): %02d%02d/%02d/%02d:%02d:%02d:%02d\n",
+           (mod_time->tm_year >= 100) ? 20 : 19,
+           (mod_time->tm_year >= 100) ? mod_time->tm_year - 100 : mod_time->tm_year,
+           mod_time->tm_mon + 1,
+           mod_time->tm_mday,
+           mod_time->tm_hour,
+           mod_time->tm_min,
+           mod_time->tm_sec);
+    strcat(my_data, thisline);
+    (void) adm_print_attributes(my_data, entry->attributes);
+    switch (entry->salt_type & 0xff) {
+           case 0 : strcat(my_data,
+                       "Principal Salt Type (PST) = Version 5 Normal\n");
+                   break;
+           case 1 : strcat(my_data, "Principal Salt Type (PST) = Version 4\n");
+                   break;
+           case 2 : strcat(my_data, "Principal Salt Type (PST) = NOREALM\n");
+                   break;
+           case 3 : strcat(my_data, "Principal Salt Type (PST) = ONLYREALM\n");
+                   break;
+           case 4 : strcat(my_data, "Principal Salt Type (PST) = Special\n");
+                   break;
+           } 
+#ifdef SANDIA
+    sprintf(thisline,
+       "Invalid Authentication Count (FCNT) = %d\n", entry->fail_auth_count);
+    strcat(my_data, thisline);
+    retval = krb5_timeofday(&now);
+    pwd_expire = (now - entry->last_pwd_change) / 86400;
+    sprintf(thisline, "Password Age is %d Days\n", pwd_expire);
+    strcat(my_data, thisline);
+#endif
+    (void) strcat(ret_data, my_data);
+    free(my_data);
+    return(0);
+}
diff --git a/src/kadmin/server/adm_funcs.c b/src/kadmin/server/adm_funcs.c
new file mode 100644 (file)
index 0000000..b40a469
--- /dev/null
@@ -0,0 +1,599 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America is assumed
+ *   to require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * Sandia National Laboratories also makes no representations about the 
+ * suitability of the modifications, or additions to this software for 
+ * any purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * Modify the Kerberos Database
+ */
+
+#if !defined(lint) && !defined(SABER)
+static char rcsid_adm_funcs[] =
+"$Id$";
+#endif /* !lint & !SABER */
+
+#include <com_err.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#ifndef hpux
+#include <arpa/inet.h>
+#endif
+
+#include <krb5/krb5.h>
+#include <krb5/ext-proto.h>
+#include <krb5/los-proto.h>
+#include <krb5/kdb.h>
+#include <krb5/kdb_dbm.h>
+#include <krb5/asn1.h>
+
+#include <krb5/adm_defs.h>
+#include "adm_extern.h"
+
+#include <krb5/adm_err.h>
+#include <krb5/errors.h>
+#include <krb5/kdb5_err.h>
+#include <krb5/krb5_err.h>
+
+struct saltblock {
+    int salttype;
+    krb5_data saltdata;
+};
+
+extern krb5_encrypt_block master_encblock;
+extern krb5_keyblock master_keyblock;
+
+#define norealm_salt(princ, retdata) krb5_principal2salt(&(princ)[1], retdata)
+
+struct mblock {
+    krb5_deltat max_life;
+    krb5_deltat max_rlife;
+    krb5_timestamp expiration;
+    krb5_flags flags;
+    krb5_kvno mkvno;
+} mblock = {                           /* XXX */
+    KRB5_KDB_MAX_LIFE,
+    KRB5_KDB_MAX_RLIFE,
+    KRB5_KDB_EXPIRATION,
+    KRB5_KDB_DEF_FLAGS,
+    0
+};
+
+typedef unsigned char des_cblock[8];
+
+               /* krb5_kvno may be narrow */
+#include <krb5/widen.h>
+
+krb5_error_code adm_get_rnd_key PROTOTYPE((char *,
+                       krb5_ticket *,
+                       krb5_authenticator *,
+                       krb5_principal,
+                       int,
+                       krb5_db_entry *));
+
+krb5_error_code adm_modify_kdb PROTOTYPE((char const *, 
+                       char const *, 
+                       krb5_const_principal,
+                       const krb5_keyblock *,  
+                       const krb5_keyblock *,
+                       int, 
+                       struct saltblock *,
+                       struct saltblock *,
+                       krb5_db_entry *));
+
+krb5_error_code adm_enter_pwd_key PROTOTYPE((char *, 
+                       char *, 
+                       krb5_const_principal,
+                       krb5_const_principal, 
+                       int, 
+                       int, 
+                       char *,
+                       krb5_db_entry *));
+
+krb5_error_code adm_negotiate_key PROTOTYPE((char const *, 
+                       krb5_ticket *,
+                       char *));
+
+#include <krb5/narrow.h>
+
+
+krb5_kvno
+adm_princ_exists(cmdname, principal, entry, nprincs)
+char *cmdname;
+krb5_principal principal;
+krb5_db_entry *entry;
+int *nprincs;
+{
+    krb5_boolean more;
+    krb5_error_code retval;
+
+    if (retval = krb5_db_get_principal(principal, entry, nprincs, &more)) {
+       com_err("adm_princ_exists", retval, 
+               "while attempting to verify principal's existence");
+       return(0);
+    }
+
+    if (! *nprincs) return(0);
+
+    return(*nprincs);
+}
+
+krb5_error_code
+adm_modify_kdb(DECLARG(char const *, cmdname),
+        DECLARG(char const *, newprinc),
+        DECLARG(krb5_const_principal, principal),
+        DECLARG(const krb5_keyblock *, key),
+        DECLARG(const krb5_keyblock *, alt_key),
+        DECLARG(int, req_type),
+        DECLARG(struct saltblock *, salt),
+        DECLARG(struct saltblock *, altsalt),
+        DECLARG(krb5_db_entry *, entry))
+OLDDECLARG(char const *, cmdname)
+OLDDECLARG(char const *, newprinc)
+OLDDECLARG(krb5_const_principal, principal)
+OLDDECLARG(const krb5_keyblock *, key)
+OLDDECLARG(const krb5_keyblock *, alt_key)
+OLDDECLARG(int, req_type)
+OLDDECLARG(struct saltblock *, salt)
+OLDDECLARG(struct saltblock *, altsalt)
+OLDDECLARG(krb5_db_entry *, entry)
+
+{
+    krb5_error_code retval;
+    int one = 1;
+
+    krb5_kvno KDB5_VERSION_NUM = 1;
+    krb5_deltat KDB5_MAX_TKT_LIFE = KRB5_KDB_MAX_LIFE;
+    krb5_deltat KDB5_MAX_REN_LIFE = KRB5_KDB_MAX_RLIFE;
+    krb5_timestamp KDB5_EXP_DATE  = KRB5_KDB_EXPIRATION;
+    extern krb5_flags NEW_ATTRIBUTES;
+
+    if (key && key->length) {
+       retval = krb5_kdb_encrypt_key(&master_encblock,
+                                     key,
+                                     &entry->key);
+       if (retval) {
+           com_err("adm_modify_kdb", retval, 
+                   "while encrypting key for '%s'", newprinc);
+           return(KADM_NO_ENCRYPT);
+       }
+    }
+
+    if (alt_key && alt_key->length) {
+       retval = krb5_kdb_encrypt_key(&master_encblock,
+                                     alt_key,
+                                     &entry->alt_key);
+       if (retval) {
+           com_err("adm_modify_kdb", retval, 
+                   "while encrypting alt_key for '%s'", newprinc);
+           return(KADM_NO_ENCRYPT);
+       }
+    }
+
+    if (!req_type) { /* New entry - initialize */
+       memset((char *) &entry, 0, sizeof(entry));
+        entry->principal = (krb5_principal) principal;
+        entry->kvno = KDB5_VERSION_NUM;
+        entry->max_life = KDB5_MAX_TKT_LIFE;
+        entry->max_renewable_life = KDB5_MAX_REN_LIFE;
+        entry->mkvno = mblock.mkvno;
+        entry->expiration = KDB5_EXP_DATE;
+        entry->mod_name = master_princ;
+    } else { /* Modify existing entry */
+       entry->kvno++;
+#ifdef SANDIA
+       entry->attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
+#endif
+       entry->mod_name = (krb5_principal) principal;
+    }
+
+    if (retval = krb5_timeofday(&entry->mod_date)) {
+       com_err("adm_modify_kdb", retval, "while fetching date");
+       memset((char *) entry->key.contents, 0, entry->key.length);
+       memset((char *) entry->alt_key.contents, 0, entry->alt_key.length);
+       if (entry->key.contents)
+           xfree(entry->key.contents);
+       if (entry->alt_key.contents)
+           xfree(entry->alt_key.contents);
+       return(KRB_ERR_GENERIC);
+    }
+
+    if (!req_type) {
+        if (salt->salttype == KRB5_KDB_SALTTYPE_V4) {
+            entry->attributes = (KRB5_KDB_DISALLOW_DUP_SKEY | NEW_ATTRIBUTES)
+#ifdef SANDIA
+             & ~KRB5_KDB_REQUIRES_PRE_AUTH & ~KRB5_KDB_REQUIRES_HW_AUTH
+#endif
+               ;
+        } else {
+            entry->attributes = NEW_ATTRIBUTES;
+        }
+#ifdef SANDIA
+        entry->last_pwd_change = entry->mod_date;
+        entry->last_success = entry->mod_date;
+        entry->fail_auth_count = 0;
+#endif
+       
+       if (salt) {
+           entry->salt_type = salt->salttype;
+           entry->salt_length = salt->saltdata.length;
+           entry->salt = (krb5_octet *) salt->saltdata.data;
+       } else {
+           entry->salt_type = KRB5_KDB_SALTTYPE_NORMAL;
+           entry->salt_length = 0;
+           entry->salt = 0;
+       }
+       
+       /* Set up version 4 alt key and alt salt info.....*/
+       if (altsalt) {
+           entry->alt_salt_type = altsalt->salttype;
+           entry->alt_salt_length = altsalt->saltdata.length;
+           entry->alt_salt = (krb5_octet *) altsalt->saltdata.data;
+       } else {
+           entry->alt_salt_type = KRB5_KDB_SALTTYPE_NORMAL;
+           entry->alt_salt_length = 0;
+           entry->alt_salt = 0;
+       }
+    } else {
+       if (retval = krb5_timeofday(&entry->last_pwd_change)) {
+           com_err("adm_modify_kdb", retval, "while fetching date");
+           memset((char *) entry->key.contents, 0, entry->key.length);
+           memset((char *) entry->alt_key.contents, 0, entry->alt_key.length);
+           if (entry->key.contents)
+               xfree(entry->key.contents);
+           if (entry->alt_key.contents)
+               xfree(entry->alt_key.contents);
+           return(5);
+       }
+    }
+
+    retval = krb5_db_put_principal(entry, &one);
+
+    memset((char *) entry->key.contents, 0, entry->key.length);
+    if (entry->key.contents)
+       xfree(entry->key.contents);
+
+    memset((char *) entry->alt_key.contents, 0, entry->alt_key.length);
+    if (entry->alt_key.contents)
+       xfree(entry->alt_key.contents);
+
+    if (retval) {
+       com_err("adm_modify_kdb", retval, 
+               "while storing entry for '%s'\n", newprinc);
+       return(kdb5_err_base + retval);
+    }
+
+    if (one != 1)
+       com_err("adm_modify_kdb", 0, "entry not stored in database (unknown failure)");
+    return(0);
+}
+
+krb5_error_code
+adm_enter_pwd_key(DECLARG(char *, cmdname),
+             DECLARG(char *, newprinc),
+             DECLARG(krb5_const_principal, princ),
+             DECLARG(krb5_const_principal, string_princ),
+             DECLARG(int, req_type),
+             DECLARG(int, salttype),
+             DECLARG(char *, new_password),
+             DECLARG(krb5_db_entry *, entry))
+OLDDECLARG(char *, cmdname)
+OLDDECLARG(char *, newprinc)
+OLDDECLARG(krb5_const_principal, princ)
+OLDDECLARG(krb5_const_principal, string_princ)
+OLDDECLARG(int, req_type)
+OLDDECLARG(int, salttype)
+OLDDECLARG(char *, new_password)
+OLDDECLARG(krb5_db_entry *, entry)
+{
+    krb5_error_code retval;
+    krb5_keyblock tempkey;
+    krb5_data pwd;
+    struct saltblock salt;
+    struct saltblock altsalt;
+    krb5_keyblock alttempkey;
+    krb5_octet v4_keyptr[8];
+
+    pwd.data = new_password;
+    pwd.length = strlen((char *) new_password);
+
+    salt.salttype = salttype;
+
+    switch (salttype) {
+    case KRB5_KDB_SALTTYPE_NORMAL:
+       if (retval = krb5_principal2salt(string_princ, &salt.saltdata)) {
+           com_err("adm_enter_pwd_key", retval,
+                   "while converting principal to salt for '%s'", newprinc);
+           return(KRB_ERR_GENERIC);
+       }
+
+       altsalt.salttype = KRB5_KDB_SALTTYPE_V4;
+       altsalt.saltdata.data = 0;
+       altsalt.saltdata.length = 0;
+       break;
+
+    case KRB5_KDB_SALTTYPE_V4:
+       salt.saltdata.data = 0;
+       salt.saltdata.length = 0;
+        if (retval = krb5_principal2salt(string_princ, &altsalt.saltdata)) {
+            com_err("adm_enter_pwd_key", retval,
+                    "while converting principal to altsalt for '%s'", newprinc);
+            return(KRB_ERR_GENERIC);
+        }
+
+       altsalt.salttype = KRB5_KDB_SALTTYPE_NORMAL;
+       break;
+
+    case KRB5_KDB_SALTTYPE_NOREALM:
+       if (retval = norealm_salt(string_princ, &salt.saltdata)) {
+           com_err("adm_enter_pwd_key", retval,
+                   "while converting principal to salt for '%s'", newprinc);
+           return(KRB_ERR_GENERIC);
+       }
+
+       altsalt.salttype = KRB5_KDB_SALTTYPE_V4;
+       altsalt.saltdata.data = 0;
+       altsalt.saltdata.length = 0;
+       break;
+
+    case KRB5_KDB_SALTTYPE_ONLYREALM:
+    {
+       krb5_data *foo;
+       if (retval = krb5_copy_data(krb5_princ_realm(string_princ),
+                                   &foo)) {
+           com_err("adm_enter_pwd_key", retval,
+                   "while converting principal to salt for '%s'", newprinc);
+           return(KRB_ERR_GENERIC);
+       }
+
+       salt.saltdata = *foo;
+       xfree(foo);
+       altsalt.salttype = KRB5_KDB_SALTTYPE_V4;
+       altsalt.saltdata.data = 0;
+       altsalt.saltdata.length = 0;
+       break;
+    }
+
+    default:
+       com_err("adm_enter_pwd_key", 0, 
+               "Don't know how to enter salt type %d", salttype);
+       return(KRB_ERR_GENERIC);
+    }
+
+    if (retval = krb5_string_to_key(&master_encblock, 
+                               master_keyblock.keytype,
+                                &tempkey,
+                                &pwd,
+                                &salt.saltdata)) {
+       com_err("adm_enter_pwd_key", retval, 
+               "while converting password to alt_key for '%s'", newprinc);
+       memset((char *) new_password, 0, sizeof(new_password)); /* erase it */
+       xfree(salt.saltdata.data);
+       return(retval);
+    }
+
+    if (retval = krb5_string_to_key(&master_encblock, 
+                               master_keyblock.keytype,
+                                &alttempkey,
+                                &pwd,
+                                &altsalt.saltdata)) {
+       com_err("adm_enter_pwd_key", retval, 
+               "while converting password to alt_key for '%s'", newprinc);
+       xfree(salt.saltdata.data);
+       free(entry->alt_key.contents);
+       memset((char *) new_password, 0, sizeof(new_password)); /* erase it */
+       return(retval);
+    }
+
+    memset((char *) new_password, 0, sizeof(new_password)); /* erase it */
+
+    retval = adm_modify_kdb("adm_enter_pwd_key", 
+                       newprinc, 
+                       princ, 
+                       &tempkey,
+                       &alttempkey, 
+                       req_type, 
+                       &salt, 
+                       &altsalt,
+                       entry);
+
+    memset((char *) tempkey.contents, 0, tempkey.length);
+    memset((char *) alttempkey.contents, 0, alttempkey.length);
+    if (entry->alt_key.contents)
+       free(entry->alt_key.contents);
+    return(retval);
+}
+
+krb5_error_code
+adm5_change(prog, newprinc, client_creds)
+char *prog;
+krb5_principal newprinc;
+krb5_ticket *client_creds;
+{
+    krb5_db_entry entry;
+    int nprincs = 1;
+
+    krb5_error_code retval;
+    char *composite_name;
+    char new_passwd[ADM_MAX_PW_LENGTH + 1];
+
+    if (!(adm_princ_exists("adm5_change", newprinc,
+               &entry, &nprincs))) {
+       com_err("adm5_change", 0, "No principal exists!");
+       krb5_free_principal(newprinc);
+       return(1);
+    }
+
+    memset((char *) new_passwd, 0, ADM_MAX_PW_LENGTH + 1);
+
+               /* Negotiate for New Key */
+    if (retval = adm_negotiate_key("adm5_change", client_creds,
+                                  new_passwd)) {
+       krb5_db_free_principal(&entry, nprincs);
+       krb5_free_principal(newprinc);
+       return(1);
+    }
+
+    retval = krb5_unparse_name(newprinc, &composite_name);
+
+    if (entry.salt_type == KRB5_KDB_SALTTYPE_V4) {
+       entry.salt_type = KRB5_KDB_SALTTYPE_NORMAL;
+       entry.alt_salt_type = KRB5_KDB_SALTTYPE_V4;
+       com_err("adm5_change", 0, "Converting v4user to v5user");
+    }
+    retval = adm_enter_pwd_key("adm5_change",              
+                                composite_name,
+                                newprinc,
+                                newprinc,
+                                1,     /* change */
+                                KRB5_KDB_SALTTYPE_NORMAL,
+                                new_passwd,
+                               &entry);
+    (void) memset(new_passwd, 0, strlen(new_passwd));
+    krb5_free_principal(newprinc);
+    krb5_db_free_principal(&entry, nprincs);
+    free(composite_name);
+    return(retval);
+}
+
+#ifdef SANDIA
+krb5_error_code
+adm5_create_rnd(prog, change_princ, client_auth_data, client_creds)
+char *prog;
+krb5_principal change_princ;
+krb5_authenticator *client_auth_data;
+krb5_ticket *client_creds;
+{
+    krb5_db_entry entry;
+    int nprincs = 1;
+
+    krb5_error_code retval;
+
+    if (!(adm_princ_exists("adm5_create_rnd", 
+                       change_princ,
+                       &entry, 
+                       &nprincs))) {
+        com_err("adm5_create_rnd", 0, "No principal exists!");
+        krb5_free_principal(change_princ);
+        return(1);
+    }   
+
+    if (retval = adm_get_rnd_key("adm5_create_rnd", 
+                       client_creds, 
+                       client_auth_data, 
+                       change_princ, 
+                       1,      /* change */
+                       &entry)) {
+       krb5_db_free_principal(&entry, nprincs);
+        krb5_free_principal(change_princ);
+        return(retval);
+    }
+
+    krb5_free_principal(change_princ);
+    krb5_db_free_principal(&entry, nprincs);
+    return(0);
+}
+#endif
+#define MAXMSGSZ       255
+
+krb5_error_code
+adm_enter_rnd_pwd_key(DECLARG(char *, cmdname),
+               DECLARG(krb5_principal, change_princ),
+               DECLARG(int, req_type),
+               DECLARG(krb5_db_entry *, entry))
+OLDDECLARG(char *, cmdname)
+OLDDECLARG(krb5_principal, change_princ)
+OLDDECLARG(int, req_type)
+OLDDECLARG(krb5_db_entry *, entry)
+{
+    krb5_error_code retval;
+    krb5_keyblock *tempkey;
+    krb5_pointer master_random;
+    int salttype = KRB5_KDB_SALTTYPE_NORMAL;
+    struct saltblock salt;
+    char       *principal_name; 
+     
+    salt.salttype = salttype;
+    entry->salt_type = salttype;
+
+    if (retval = krb5_init_random_key(&master_encblock,
+                                      &master_keyblock,
+                                      &master_random)) {
+        com_err("adm_enter_rnd_pwd_key", 0, "Unable to Initialize Random Key");
+        (void) krb5_finish_key(&master_encblock);
+        memset((char *)master_keyblock.contents, 0, master_keyblock.length);
+        xfree(master_keyblock.contents);
+        goto finish;
+    }
+
+       /* Get Random Key */
+    if (retval = krb5_random_key(&master_encblock, 
+                                master_random, 
+                                &tempkey)) {
+        com_err("adm_enter_rnd_pwd_key", 0, "Unable to Obtain Random Key");
+        goto finish;
+    }
+
+       /* Tie the Random Key to the Principal */
+    if (retval = krb5_principal2salt(change_princ, &salt.saltdata)) {
+        com_err("adm_enter_rnd_pwd_key", 0, "Principal2salt Failure");
+        goto finish;
+    }
+
+    retval = krb5_unparse_name(change_princ, &principal_name);
+    if (retval)
+       return retval;
+    
+               /* Modify Database */
+    retval = adm_modify_kdb("adm_enter_rnd_pwd_key", 
+                           principal_name, 
+                           change_princ, 
+                           tempkey,
+                           tempkey,
+                           req_type, 
+                           &salt, 
+                           &salt,
+                           entry);
+    free(principal_name);
+    
+    if (retval) {
+        com_err("adm_enter_rnd_pwd_key", 0, "Database Modification Failure");
+       retval = 2;
+        goto finish;
+    }
+
+    finish:
+
+    if(retval) {
+       memset((char *) tempkey->contents, 0, tempkey->length);
+       return(retval);
+    }
+
+    memset((char *) tempkey->contents, 0, tempkey->length);
+
+    return(0);
+}
diff --git a/src/kadmin/server/adm_kadmin.c b/src/kadmin/server/adm_kadmin.c
new file mode 100644 (file)
index 0000000..abf38ca
--- /dev/null
@@ -0,0 +1,371 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ */
+
+/*
+ * Sandia National Laboratories also makes no representations about the
+ * suitability of the modifications, or additions to this software for
+ * any purpose.  It is provided "as is" without express or implied warranty.
+ */
+
+#if !defined(lint) && !defined(SABER)
+static char rcsid_adm_kadmin[] =
+"$Header$";
+#endif  /* lint */
+
+/*
+  adm_kadmin.c
+*/
+
+#include <sys/types.h>
+#include <syslog.h>
+#include <com_err.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#ifndef hpux
+#include <arpa/inet.h>
+#endif
+#include <krb5/krb5.h>
+#include <krb5/ext-proto.h>
+#include <krb5/los-proto.h>
+#include <krb5/kdb.h>
+#include <krb5/adm_defs.h>
+#include "adm_extern.h"
+krb5_error_code
+adm5_kadmin(prog, client_auth_data, client_creds, retbuf, otype)
+char *prog;
+krb5_authenticator *client_auth_data;
+krb5_ticket *client_creds;
+char *retbuf;          /* Allocated in Calling Routine */
+int *otype;
+{
+    krb5_error_code retval;
+    kadmin_requests request_type;
+    krb5_data msg_data, outbuf, inbuf;
+
+    char *customer_name;
+    char *completion_msg;
+    int length_of_name;
+
+    int salttype;
+
+    outbuf.data = retbuf;      /* Do NOT free outbuf.data */
+
+    for ( ; ; ) {              /* Use "return", "break", or "goto" 
+                                  to exit for loop */
+
+               /* Encode Acknowledgement Message */
+       retbuf[0] = KADMIND;
+       retbuf[1] = KADMSAG;
+       retbuf[2] = SENDDATA2;
+       outbuf.length = 3;
+
+       retval = krb5_mk_priv(&outbuf,
+                       ETYPE_DES_CBC_CRC,
+                       client_creds->enc_part2->session,
+                       &client_server_info.server_addr,
+                       &client_server_info.client_addr,
+                       send_seqno,
+                       KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                       0,
+                       0,
+                       &msg_data);
+       if (retval ) {
+           syslog(LOG_ERR, 
+               "adm5_kadmin - Error Performing Acknowledgement mk_priv");
+           return(5);          /* Protocol Failure */
+       }
+
+               /* Send Acknowledgement Reply to Client */
+       if (retval = krb5_write_message(&client_server_info.client_socket,
+                               &msg_data)){
+           syslog(LOG_ERR,
+               "adm5_kadmin - Error Performing Acknowledgement Write: %s",
+               error_message(retval));
+           return(5);          /* Protocol Failure */
+       }
+       free(msg_data.data);
+
+                       /* Read Username */
+       if (krb5_read_message(&client_server_info.client_socket, &inbuf)){
+           syslog(LOG_ERR | LOG_INFO, "Error Performing Username Read");
+           return(5);          /* Protocol Failure */
+       }
+
+                /* Decrypt Client Response */
+       if ((retval = krb5_rd_priv(&inbuf,
+                       client_creds->enc_part2->session,
+                       &client_server_info.client_addr,
+                       &client_server_info.server_addr,
+                       recv_seqno,
+                       KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                       0,
+                       0,
+                       &msg_data))) {
+           free(inbuf.data);
+           syslog(LOG_ERR | LOG_INFO, "Error decoding Username - rd_priv");
+           return(5);          /* Protocol Failure */
+       }
+       free(inbuf.data);
+
+       request_type.appl_code = msg_data.data[0];
+       request_type.oper_code = msg_data.data[1];
+       if (msg_data.data[2] != SENDDATA2) {
+           syslog(LOG_ERR | LOG_INFO, 
+               "Invalid Protocol String - Response not SENDDATA2");
+           free(msg_data.data);
+           return(5);          /* Protocol Failure */
+       }
+
+       length_of_name = msg_data.length - 3;
+
+       if (request_type.oper_code == COMPLETE) {
+           *otype = 0;
+           free(msg_data.data);
+           retval = 0;
+           goto finish_req;
+       }
+
+       if (!length_of_name) {
+           syslog(LOG_ERR,
+               "adm5_kadmin error: Invalid KADMIN request - No Customer");
+           free(msg_data.data);
+           return(5);          /* Protocol Error */
+       }
+
+       if ((customer_name = (char *) calloc(1, length_of_name + 1)) == 
+                               (char *) 0) {
+           syslog(LOG_ERR, "adm5_kadmin error: No Memory for Customer Name");
+           free(msg_data.data);
+           return(3);          /* No Memory */
+       }
+
+       (void) memcpy(customer_name, (char *) msg_data.data + 3, 
+                       length_of_name);
+       customer_name[length_of_name] = '\0';
+
+       free(msg_data.data);
+
+       if ((completion_msg = (char *) calloc (1,512)) == (char *) 0) {
+           syslog(LOG_ERR, "adm5_kadmin - No Memory for completion_msg");
+           free(customer_name);
+           return(3);          /* No Memory */
+       }
+
+       switch(request_type.oper_code) {
+           case ADDOPER:
+                       /* Check for Add Privilege */
+               if (retval = adm_check_acl(client_server_info.name_of_client,
+                                          "a")) {
+                   retval = 7;
+                   goto process_retval;
+               }
+               *otype = 1;
+               salttype = KRB5_KDB_SALTTYPE_NORMAL;
+               retval = adm_add_new_key("adm5_kadmin", customer_name,
+                                        client_creds, salttype);
+               goto process_retval;
+
+           case CHGOPER:
+                       /* Check for Password Privilege */
+               if (retval = adm_check_acl(client_server_info.name_of_client,
+                                          "c")) {
+                   retval = 7;
+                   goto process_retval;
+               }
+               *otype = 2;
+               salttype = KRB5_KDB_SALTTYPE_NORMAL;
+               retval = adm_change_pwd("adm5_kadmin", customer_name,
+                                       client_creds, salttype);
+               goto process_retval;
+
+           case ADROPER:
+                       /* Check for Add Privilege */
+               if (retval = adm_check_acl(client_server_info.name_of_client,
+                                          "a")) {
+                   retval = 7;
+                   goto process_retval;
+               }
+               *otype = 3;
+               retval = adm_add_new_key_rnd("adm5_kadmin", customer_name,
+                                            client_creds);
+               goto process_retval;
+
+           case CHROPER:
+                       /* Check for Password Privilege */
+               if (retval = adm_check_acl(client_server_info.name_of_client,
+                                          "c")) {
+                   retval = 7;
+                   goto process_retval;
+               }
+               *otype = 4;
+               retval = adm_change_pwd_rnd("adm5_kadmin", customer_name,
+                                           client_creds);
+               goto process_retval;
+
+           case DELOPER:
+                       /* Check for Delete Privilege */
+               if (retval = adm_check_acl(client_server_info.name_of_client,
+                                          "d")) {
+                   retval = 7;
+                   goto process_retval;
+               }
+               *otype = 5;
+               retval = adm_del_old_key("adm5_kadmin", customer_name);
+               goto process_retval;
+
+           case MODOPER:
+               /* Check for Modify Privilege */
+               if (retval = adm_check_acl(client_server_info.name_of_client,
+                                          "m")) {
+                   retval = 7;
+                   goto process_retval;
+               }
+               *otype = 6;
+               retval = adm_mod_old_key("adm5_kadmin", customer_name,
+                                        client_creds);
+               goto process_retval;
+
+           case INQOPER:
+                       /* Check for Inquiry Privilege */
+               if (retval = adm_check_acl(client_server_info.name_of_client,
+                                          "i")) {
+                   retval = 7;
+                   goto process_retval;
+               }
+               *otype = 7;
+               retval = adm_inq_old_key("adm5_kadmin", customer_name,
+                                        client_creds);
+               goto process_retval;
+
+           case AD4OPER:
+                       /* Check for Add Privilege */
+               if (retval = adm_check_acl(client_server_info.name_of_client,
+                                          "a")) {
+                   retval = 7;
+                   goto process_retval;
+               }
+               *otype = 8;
+               salttype = KRB5_KDB_SALTTYPE_V4;
+               retval = adm_add_new_key("adm5_kadmin", customer_name,
+                                        client_creds, salttype);
+               goto process_retval;
+
+           case CH4OPER:
+                       /* Check for Password Privilege */
+               if (retval = adm_check_acl(client_server_info.name_of_client,
+                                          "c")) {
+                   retval = 7;
+                   goto process_retval;
+               }
+               *otype = 9;
+               salttype = KRB5_KDB_SALTTYPE_V4;
+               retval = adm_change_pwd("adm5_kadmin", customer_name,
+                                       client_creds, salttype);
+               goto process_retval;
+
+           default:
+               retbuf[0] = KADMIN;
+               retbuf[1] = KUNKNOWNOPER;
+               retbuf[2] = '\0';
+               sprintf(completion_msg, "%s %s from %s FAILED",
+                       "kadmin", 
+                       "Unknown or Non-Implemented Operation Type!",
+                       inet_ntoa(client_server_info.client_name.sin_addr));
+               syslog(LOG_AUTH | LOG_INFO, completion_msg);
+               free(completion_msg);
+               retval = 255;
+               goto send_last;
+       }                       /* switch (request_type.oper_code) */
+
+process_retval:
+       switch (retval) {
+           case 0:
+               retbuf[0] = KADMIN;
+               retbuf[1] = request_type.oper_code;
+               retbuf[2] = KADMGOOD;
+               retbuf[3] = '\0';
+               goto send_last;
+
+           case 1:     /* Principal Unknown */
+           case 2:     /* Principal Already Exists */
+           case 3:     /* ENOMEM */
+           case 4:     /* Password Failure */
+           case 5:     /* Protocol Failure */
+           case 6:     /* Security Failure */
+           case 7:     /* Admin Client Not in ACL List */
+           case 8:     /* Database Update Failure */
+               retbuf[0] = KADMIN;
+               retbuf[1] = request_type.oper_code;
+               retbuf[2] = KADMBAD;
+               retbuf[3] = '\0';
+               sprintf((char *)retbuf +3, "%s",
+                       kadmind_kadmin_response[retval]);
+               sprintf(completion_msg, 
+                       "%s %s from %s FAILED - %s", 
+                       "kadmin",
+                       oper_type[request_type.oper_code],
+                       inet_ntoa(client_server_info.client_name.sin_addr),
+                       kadmind_kadmin_response[retval]);
+               syslog(LOG_AUTH | LOG_INFO, completion_msg);
+               free(completion_msg);
+               goto send_last;
+
+           default:
+               retbuf[0] = KADMIN;
+               retbuf[1] = request_type.oper_code;
+               retbuf[2] = KUNKNOWNERR;
+               retbuf[3] = '\0';
+               sprintf(completion_msg, "%s %s from %s FAILED", 
+                   "ksrvutil",
+                   oper_type[1],
+                   inet_ntoa( client_server_info.client_name.sin_addr));
+               syslog(LOG_AUTH | LOG_INFO, completion_msg);
+               retval = 255;
+               goto send_last;
+       }               /* switch(retval) */
+
+send_last:
+       free(customer_name);
+       free(completion_msg);
+       outbuf.data = retbuf;
+       outbuf.length = strlen(retbuf) + 1;
+
+               /* Send Completion Message */
+       if (retval = krb5_mk_priv(&outbuf,
+                       ETYPE_DES_CBC_CRC,
+                       client_creds->enc_part2->session,
+                       &client_server_info.server_addr,
+                       &client_server_info.client_addr,
+                       send_seqno,
+                       KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                       0,
+                       0,
+                       &msg_data)) {
+           syslog(LOG_ERR, "adm5_kadmin - Error Performing Final mk_priv");
+           return(1);
+       }
+
+                       /* Send Final Reply to Client */
+       if (retval = krb5_write_message(&client_server_info.client_socket,
+                                       &msg_data)){
+           syslog(LOG_ERR, "adm5_kadmin - Error Performing Final Write: %s",
+                       error_message(retval));
+           return(1);
+       }
+       free(msg_data.data);
+    }          /* for */
+
+finish_req:
+    return(retval);
+}
diff --git a/src/kadmin/server/adm_kpasswd.c b/src/kadmin/server/adm_kpasswd.c
new file mode 100644 (file)
index 0000000..f01475f
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ */
+
+/*
+ * Sandia National Laboratories also makes no representations about the
+ * suitability of the modifications, or additions to this software for
+ * any purpose.  It is provided "as is" without express or implied warranty.
+ */
+
+#if !defined(lint) && !defined(SABER)
+static char rcsid_adm_kpasswd[] =
+"$Header$";
+#endif  /* lint */
+
+/*
+  adm_kpasswd.c
+*/
+
+#include <sys/types.h>
+#include <syslog.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <com_err.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#ifndef hpux
+#include <arpa/inet.h>
+#endif
+#include <krb5/krb5.h>
+#include <krb5/kdb.h>
+#include <krb5/ext-proto.h>
+#include <krb5/los-proto.h>
+#include <krb5/adm_defs.h>
+#include "adm_extern.h"
+extern krb5_encrypt_block master_encblock;
+extern krb5_keyblock master_keyblock;
+struct cpw_keyproc_arg {
+    krb5_keyblock *key;
+};
+krb5_error_code
+adm5_kpasswd(prog, request_type, client_creds, retbuf, otype)
+char *prog;
+kadmin_requests *request_type;
+krb5_ticket *client_creds;
+char *retbuf;
+int *otype;
+{
+    char completion_msg[520];
+    krb5_error_code retval;
+
+    switch (request_type->oper_code) {
+    case CHGOPER:
+       *otype = 3;
+       syslog(LOG_AUTH | LOG_INFO,
+              "adm_kpasswd: kpasswd change received");
+       retval = adm5_change("adm5_kpasswd", 
+                            client_server_info.client,
+                            client_creds);
+
+       switch(retval) {
+       case 0:
+           retbuf[0] = KPASSWD;
+           retbuf[1] = CHGOPER;
+           retbuf[2] = KPASSGOOD;
+           retbuf[3] = '\0';
+           break;
+
+       case 1:
+           retbuf[0] = KPASSWD;
+           retbuf[1] = CHGOPER;
+           retbuf[2] = KPASSBAD;
+           retbuf[3] = '\0';
+           sprintf((char *)retbuf +3, "%s", 
+                   kadmind_kpasswd_response[retval]);
+           sprintf(completion_msg,
+                   "kpasswd change from %s FAILED: %s", 
+                   inet_ntoa(client_server_info.client_name.sin_addr),
+                   kadmind_kpasswd_response[retval]);
+           syslog(LOG_AUTH | LOG_INFO, completion_msg);
+           goto finish;
+
+       default:
+           retbuf[0] = KPASSWD;
+           retbuf[1] = CHGOPER;
+           retbuf[2] = KUNKNOWNERR;
+           retbuf[3] = '\0';
+           sprintf(completion_msg, "kpasswd change from %s FAILED", 
+                   inet_ntoa(client_server_info.client_name.sin_addr));
+           syslog(LOG_AUTH | LOG_INFO, completion_msg);
+           retval = 255;
+           goto finish;
+       }               /* switch (retval) */
+       break;
+
+    default:
+       retbuf[0] = KPASSWD;
+       retbuf[1] = KUNKNOWNOPER;
+       retbuf[2] = '\0';
+       sprintf(completion_msg, "kpasswd %s from %s FAILED", 
+               "Unknown or Non-Implemented Operation Type!",
+               inet_ntoa(client_server_info.client_name.sin_addr ));
+       syslog(LOG_AUTH | LOG_INFO, completion_msg);
+       retval = 255;
+       goto finish;
+    }                  /* switch (request_type->oper_code) */
+    
+finish:
+       return(retval);
+}
diff --git a/src/kadmin/server/adm_listen.c b/src/kadmin/server/adm_listen.c
new file mode 100644 (file)
index 0000000..abedc1d
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ * Network Listen Loop for the Kerberos Version 5 Administration server
+ */
+
+/* 
+ * Sandia National Laboratories also makes no representations about the 
+ * suitability of the modifications, or additions to this software for 
+ * any purpose.  It is provided "as is" without express or implied warranty.
+ */
+
+#if !defined(lint) && !defined(SABER)
+static char rcsid_adm_listen[] =
+"$Header$";
+#endif /* lint */
+
+/*
+  adm_listen.c
+*/
+
+#include <sys/types.h>
+#include <syslog.h>
+#include <signal.h>
+#include <com_err.h>
+
+#ifndef sigmask
+#define sigmask(m)    (1 <<((m)-1))
+#endif
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#ifndef hpux
+#include <arpa/inet.h>
+#endif
+
+#include <krb5/krb5.h>
+#include <krb5/ext-proto.h>
+#include <krb5/los-proto.h>
+#include <krb5/adm_defs.h>
+#include "adm_extern.h"
+
+void
+kill_children()
+{
+    register int i;
+    int osigmask;
+
+    osigmask = sigblock(sigmask(SIGCHLD));
+
+    for (i = 0; i < pidarraysize; i++) {
+       kill(pidarray[i], SIGINT);
+       syslog(LOG_AUTH | LOG_INFO, "Killing Admin Child %d", pidarray[i]);
+    }
+
+    sigsetmask(osigmask);
+    return;
+}
+
+/*
+adm5_listen_and_process - listen on the admin servers port for a request
+*/
+adm5_listen_and_process(prog)
+const char *prog;
+{
+    extern int errno;
+    int found;
+    fd_set mask, readfds;
+    int addrlen;
+    krb5_error_code process_client();
+    krb5_error_code retval;
+    void kill_children();
+    int pid;
+
+    (void) listen(client_server_info.server_socket, 1);
+
+    FD_ZERO(&mask);
+    FD_SET(client_server_info.server_socket, &mask);
+
+    for (;;) {                         /* loop nearly forever */
+       if (exit_now) {
+               kill_children();
+               return(0);
+       }
+
+       readfds = mask;
+       if ((found = select(client_server_info.server_socket + 1,
+                               &readfds,
+                               (fd_set *)0,
+                               (fd_set *)0, 
+                               (struct timeval *)0)) == 0)
+               continue;                       /* no things read */
+
+       if (found < 0) {
+               if (errno != EINTR)
+                       syslog(LOG_AUTH | LOG_INFO, 
+                               "%s: select: %s", "adm5_listen_and_process", 
+                               error_message(errno));
+               continue;
+       }      
+
+       if (FD_ISSET(client_server_info.server_socket, &readfds)) {
+               /* accept the conn */
+               addrlen = sizeof(client_server_info.client_name);
+               if ((client_server_info.client_socket = 
+                       accept(client_server_info.server_socket, 
+                       (struct sockaddr *) &client_server_info.client_name,
+                       &addrlen)) < 0) {
+                   syslog(LOG_AUTH | LOG_INFO, "%s: accept: %s", 
+                               "adm5_listen_and_process", 
+                               error_message(errno));
+                   continue;
+               }
+#ifndef DEBUG
+               /* if you want a sep daemon for each server */
+               if (!(pid = fork())) {
+                       /* child */
+                       (void) close(client_server_info.server_socket);
+
+                       retval = process_client("adm5_listen_and_process");
+                       exit(retval);
+               } else {
+                       /* parent */
+                       if (pid < 0) {
+                               syslog(LOG_AUTH | LOG_INFO, "%s: fork: %s",
+                                       "adm5_listen_and_process", 
+                                       error_message(errno));
+                               (void) close(client_server_info.client_socket);
+                               continue;
+                       }
+
+                       /* fork succeded: keep tabs on child */
+
+                       (void) close(client_server_info.client_socket);
+                       if (pidarray) {
+                               pidarray = (int *) realloc((char *)pidarray, 
+                                       (++pidarraysize) * sizeof(int));
+                               pidarray[pidarraysize - 1] = pid;
+                       } else {
+                               pidarraysize = 1;
+                               pidarray = 
+                                 (int *) malloc(pidarraysize *sizeof(int));
+                               pidarray[0] = pid;
+                       }
+               }
+#else
+               /* do stuff */
+
+               retval = process_client("adm5_listen_and_process");
+               exit(retval);
+#endif /* DEBUG */
+       } else {
+               syslog(LOG_AUTH | LOG_INFO, "%s: something else woke me up!",
+                       "adm5_listen_and_process");
+               return(0);
+       }
+    }
+}
diff --git a/src/kadmin/server/adm_nego.c b/src/kadmin/server/adm_nego.c
new file mode 100644 (file)
index 0000000..1243720
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America is assumed
+ *   to require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * Sandia National Laboratories also makes no representations about the 
+ * suitability of the modifications, or additions to this software for 
+ * any purpose.  It is provided "as is" without express or implied warranty.
+ * 
+ * Modify the Kerberos Database
+ */
+
+#if !defined(lint) && !defined(SABER)
+static char rcsid_adm_nego[] =
+"$Id$";
+#endif /* !lint & !SABER */
+
+#include <com_err.h>
+#include <sys/types.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#ifndef hpux
+#include <arpa/inet.h>
+#endif
+
+#include <stdio.h>
+
+#include <krb5/krb5.h>
+#include <krb5/ext-proto.h>
+#include <krb5/los-proto.h>
+#include <krb5/asn1.h>
+
+#include <krb5/adm_defs.h>
+#include "adm_extern.h"
+
+krb5_error_code
+adm_negotiate_key(DECLARG(char const *, prog),
+        DECLARG(krb5_ticket *, client_creds),
+        DECLARG(char *, new_passwd))
+OLDDECLARG(char const *, prog)
+OLDDECLARG(krb5_ticket *, client_creds)
+OLDDECLARG(char *, new_passwd)
+
+{
+   krb5_data msg_data, inbuf;
+   krb5_error_code retval;
+#if defined(MACH_PASS) || defined(SANDIA) /* Machine-generated passwords. */
+   krb5_pwd_data *pwd_data;
+   krb5_pwd_data encodable_data;
+   krb5_data *encoded_pw_string;
+   passwd_phrase_element **next_passwd_phrase_element;
+   char *tmp_passwd, *tmp_phrase;
+   krb5_authenticator *client_auth_data;
+   int count, i, j, k;
+   int legit_passwd = 0;
+#endif
+   extern int errno;
+
+#if defined(MACH_PASS) || defined(SANDIA) /* Machine-generated passwords. */
+
+#define clear_encodable_data() \
+{ encodable_data.sequence_count = 0; \
+  encodable_data.element = 0; \
+}
+
+#define free_seq_list() \
+{ free(encodable_data.element); \
+}
+
+#define free_pwd_and_phrase_structures() \
+{ next_passwd_phrase_element = encodable_data.element; \
+  for (k = 0; \
+       *next_passwd_phrase_element != 0 &&  k < encodable_data.sequence_count; \
+       k++) { \
+     free(*next_passwd_phrase_element); \
+     *next_passwd_phrase_element = 0; \
+     next_passwd_phrase_element++; } \
+}
+
+#define free_passwds() \
+{ next_passwd_phrase_element = encodable_data.element; \
+  for (k = 0; \
+       *next_passwd_phrase_element != 0 && k < encodable_data.sequence_count; \
+       k++) { \
+     memset((char *) (*next_passwd_phrase_element)->passwd->data, \
+       0, (*next_passwd_phrase_element)->passwd->length); \
+     free((*next_passwd_phrase_element)->passwd->data); \
+     next_passwd_phrase_element++; } \
+}
+
+#define free_phrases() \
+{ next_passwd_phrase_element = encodable_data.element; \
+  for (k = 0; \
+       *next_passwd_phrase_element != 0 && k < encodable_data.sequence_count; \
+       k++) { \
+     memset((char *) (*next_passwd_phrase_element)->phrase->data, \
+       0, (*next_passwd_phrase_element)->phrase->length); \
+     free((*next_passwd_phrase_element)->phrase->data); \
+     next_passwd_phrase_element++; } \
+}
+
+   encodable_data.sequence_count = 
+               ADM_MAX_PW_CHOICES * ADM_MAX_PW_ITERATIONS;
+
+           /* Allocate List of Password and Phrase Addresses Pointers */
+   if ((encodable_data.element = (passwd_phrase_element **) calloc(
+                   encodable_data.sequence_count + 1, 
+                   sizeof(passwd_phrase_element *))) == 
+                       (passwd_phrase_element **) 0) {
+               clear_encodable_data();
+               com_err("adm_negotiate_key", 0, 
+                       "No Memory for Password and Phrase List");
+               return(1);
+       }
+
+   next_passwd_phrase_element = encodable_data.element;
+
+       /* Allow for ADM_MAX_PW_ITERATIONS Sets of Five Passwords/Phrases */
+   for ( i = 0; i < ADM_MAX_PW_ITERATIONS; i++) {
+       if ( i == ADM_MAX_PW_ITERATIONS ) {
+               com_err("adm_negotiate_key", 0, 
+                       "Excessive Password List Requests");
+               return(1);
+       }
+
+               /* Allocate passwd_phrase_element structures */
+        for (j = 0; j < ADM_MAX_PW_CHOICES; j++) {
+           if ((*next_passwd_phrase_element = 
+                   (passwd_phrase_element *) calloc(1, 
+                   sizeof(passwd_phrase_element))) == 
+                               (passwd_phrase_element *) 0) {
+               free_pwd_and_phrase_structures();
+               free_seq_list();
+               clear_encodable_data();
+               com_err("adm_negotiate_key", 0, 
+                   "No Memory for Additional Password and Phrase Structures");
+               return(1);
+           }
+
+           if ((retval = get_pwd_and_phrase("adm_negotiate_key",
+                       &tmp_passwd, &tmp_phrase))) {
+               free_pwd_and_phrase_structures();
+               free_seq_list();
+               clear_encodable_data();
+               com_err("adm_negotiate_key", 0, "Unable to get_pwd_and_phrase");
+               return(1);
+           }
+
+           if (((*next_passwd_phrase_element)->passwd = 
+                   (krb5_data *) calloc(1, 
+                   sizeof(krb5_data))) == (krb5_data *) 0) {
+               free_pwd_and_phrase_structures();
+               free_seq_list();
+               clear_encodable_data();
+               com_err("adm_negotiate_key", 0, 
+                   "No Memory for Additional Password and Phrase Structures");
+               return(1);
+           }
+
+           if (((*next_passwd_phrase_element)->passwd->data = 
+                       (char *) calloc (1, 
+                       strlen(tmp_passwd))) == (char *) 0) {
+               free_pwd_and_phrase_structures();
+               free_seq_list();
+               clear_encodable_data();
+               com_err("adm_negotiate_key", ENOMEM, 
+                       "for Additional Passwords");
+           }
+
+           strcpy((*next_passwd_phrase_element)->passwd->data, tmp_passwd);
+           (*next_passwd_phrase_element)->passwd->length = strlen(tmp_passwd);
+
+           if (((*next_passwd_phrase_element)->phrase = 
+                   (krb5_data *) calloc(1, 
+                   sizeof(krb5_data))) == (krb5_data *) 0) {
+               free_pwd_and_phrase_structures();
+               free_seq_list();
+               clear_encodable_data();
+               com_err("adm_negotiate_key", 0, 
+                   "No Memory for Additional Password and Phrase Structures");
+               return(1);
+           }
+
+           if (((*next_passwd_phrase_element)->phrase->data = 
+                       (char *) calloc (1, 
+                       strlen(tmp_phrase))) == (char *) 0) {
+               free_pwd_and_phrase_structures();
+               free_seq_list();
+               clear_encodable_data();
+               com_err("adm_negotiate_key", ENOMEM, 
+                       "for Additional Passwords");
+           }
+
+           strcpy((*next_passwd_phrase_element)->phrase->data, tmp_phrase);
+           (*next_passwd_phrase_element)->phrase->length = strlen(tmp_phrase);
+
+           free(tmp_passwd);
+           free(tmp_phrase);
+
+           next_passwd_phrase_element++;
+       }
+    }  /* for i <= KADM_MAX_PW_CHOICES */
+
+               /* Asn.1 Encode the Passwords and Phrases */
+    if ((retval = encode_krb5_pwd_data(&encodable_data, 
+                       &encoded_pw_string))) {
+       com_err("adm_negotiate_key", 0, 
+                       "Unable to encode Password and Phrase Data");
+       return(1);
+    }
+
+               /* Free Phrases But Hold onto Passwds for Awhile*/
+    free_phrases();
+
+               /* Encrypt Password/Phrases Encoding */
+    retval = krb5_mk_priv(encoded_pw_string,
+                       ETYPE_DES_CBC_CRC,
+                       client_creds->enc_part2->session, 
+                       &client_server_info.server_addr, 
+                       &client_server_info.client_addr,
+                       send_seqno,
+                       KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                       0,
+                       0,
+                       &msg_data);
+    if (retval ) {
+       free_passwds();
+       free_pwd_and_phrase_structures();
+       free_seq_list();
+       clear_encodable_data();
+       com_err("adm_negotiate_key", retval, "during mk_priv");
+       return(1);  
+    }
+
+       /* Send Encrypted/Encoded Passwords and Phrases to Client */
+    if (krb5_write_message(&client_server_info.client_socket, &msg_data)){
+       free(msg_data.data);
+       free_passwds();
+       free_pwd_and_phrase_structures();
+       free_seq_list();
+       clear_encodable_data();
+       com_err("adm_negotiate_key", 0, "Error Performing Password Write");
+       return(1);  
+    } 
+    free(msg_data.data);
+
+#endif /* MACH_PASS - Machine-gen. passwords */
+               /* Read Client Response */
+    if (krb5_read_message(&client_server_info.client_socket, &inbuf)){
+#if defined(MACH_PASS) || defined(SANDIA)
+       free_passwds();
+       free_pwd_and_phrase_structures();
+       free_seq_list();
+       clear_encodable_data();
+#endif
+       com_err("adm_negotiate_key", errno, "Error Performing Password Read");
+       return(1);
+    }
+
+               /* Decrypt Client Response */
+    if ((retval = krb5_rd_priv(&inbuf,
+                       client_creds->enc_part2->session,
+                       &client_server_info.client_addr,
+                       &client_server_info.server_addr, 
+                       recv_seqno,
+                       KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                       0,
+                       0,
+                       &msg_data))) {
+       free(inbuf.data);
+#if defined(MACH_PASS) || defined(SANDIA)
+       free_passwds();
+       free_pwd_and_phrase_structures();
+       free_seq_list();
+       clear_encodable_data();
+#endif
+       com_err("adm_negotiate_key", retval, "krb5_rd_priv error %s",
+                               error_message(retval));
+       return(1);
+    }
+    free(inbuf.data);
+
+#if defined(MACH_PASS) || defined(SANDIA) /* Machine-generated passwords */
+    legit_passwd = 0;
+    next_passwd_phrase_element = encodable_data.element;
+               /* Compare Response with Acceptable Passwords */
+    for (j = 0; 
+       j < ADM_MAX_PW_CHOICES * ADM_MAX_PW_ITERATIONS; 
+       j++) {
+       if ((retval = memcmp(msg_data.data, 
+                  (*next_passwd_phrase_element)->passwd->data, 
+                  strlen((*next_passwd_phrase_element)->passwd->data))) == 0) {
+           legit_passwd++;
+           break; /* Exit Loop - Match Found */
+       }
+       next_passwd_phrase_element++;
+    }
+               /* Now Free Passwds */
+    free_passwds();
+
+       /* free password_and_phrase structures */
+    free_pwd_and_phrase_structures();
+
+       /* free passwd_phrase_element list */
+    free_seq_list();
+
+       /* clear krb5_pwd_data */
+    clear_encodable_data();
+
+    if (!(legit_passwd)) {
+       com_err("adm_negotiate_key", 0, "Invalid Password Entered");
+       return(1);
+    }
+#endif
+    strncpy(new_passwd, msg_data.data, msg_data.length);
+    free(msg_data.data);
+
+    return(0);
+}
+
diff --git a/src/kadmin/server/adm_network.c b/src/kadmin/server/adm_network.c
new file mode 100644 (file)
index 0000000..a7de9f2
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ * Network Initialization/Shutdown Component of the 
+ * Version 5 Administration network
+ */
+
+/* 
+ * Sandia National Laboratories also makes no representations about the 
+ * suitability of the modifications, or additions to this software for 
+ * any purpose.  It is provided "as is" without express or implied warranty.
+ */
+
+#if !defined(lint) && !defined(SABER)
+static char rcsid_adm_network[] =
+"$Header$";
+#endif /* lint */
+
+/*
+ *   adm_network.c
+ */
+
+#include <stdio.h>
+#include <com_err.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/param.h>
+#include <signal.h>
+
+#ifndef sigmask
+#define sigmask(m)    (1 <<((m)-1))
+#endif
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#ifndef hpux
+#include <arpa/inet.h>
+#endif
+#include <netdb.h>
+
+#include <krb5/krb5.h>
+#include <krb5/ext-proto.h>
+#include <krb5/los-proto.h>
+#include <krb5/adm_defs.h>
+#include "adm_extern.h"
+
+extern int errno;
+
+krb5_error_code
+closedown_network(prog)
+const char *prog;
+{
+    if (client_server_info.server_socket == -1) return(1);
+
+    (void) close(client_server_info.server_socket);
+    client_server_info.server_socket = -1;
+    return(0);
+}
+
+krb5_sigtype
+doexit()
+{
+    exit_now = 1;
+#if defined (POSIX) || defined(SYSV) || defined(sun) && !defined(sysvimp) || defined(ultrix) || (defined(mips) && defined(SYSTYPE_BSD43)) || defined(convex)
+    return;
+#else /* !POSIX */
+    return(0);
+#endif /* POSIX */
+}
+
+/*
+ *  SIGCHLD brings us here
+ */
+krb5_sigtype
+do_child()
+{
+    /*
+     *  <sys/param.h> has been included, so BSD will be defined on
+     * BSD systems
+     */
+#if BSD > 0 && BSD <= 43
+#ifndef WEXITSTATUS
+#define        WEXITSTATUS(w)  (w).w_retcode
+#define WTERMSIG(w)    (w).w_termsig
+#endif
+    union wait status;
+#else
+    int        status;
+#endif
+    int pid, i, j;
+
+    pid = wait(&status);
+    if (pid < 0) {
+#ifdef SYSV
+       signal(SIGCHLD, do_child);
+#endif
+#if defined (POSIX) || defined(SYSV) || defined(sun) && !defined(sysvimp) || defined(ultrix) || (defined(mips) && defined(SYSTYPE_BSD43)) || defined(convex)
+       return;
+#else /* !POSIX */
+       return(0);
+#endif /* POSIX */
+    }
+    for (i = 0; i < pidarraysize; i++)
+       if (pidarray[i] == pid) {
+                       /* found it */
+               for (j = i; j < pidarraysize-1; j++)
+                       /* copy others down */
+                       pidarray[j] = pidarray[j+1];
+               pidarraysize--;
+               if ( !WIFEXITED(status) ) {
+                       com_err("adm_network", 0, "child %d: termsig %d", 
+                               pid, WTERMSIG(status) );
+                       com_err("adm_network", 0, "retcode %d", 
+                               WEXITSTATUS(status));
+               }
+
+#ifdef SYSV
+                signal(SIGCHLD, do_child);
+#endif
+
+#if defined (POSIX) || defined(SYSV) || defined(sun) && !defined(sysvimp) || defined(ultrix) || (defined(mips) && defined(SYSTYPE_BSD43)) || defined(convex)
+               return;
+#else /* !POSIX */
+               return(0);
+#endif /* POSIX */
+       }
+#ifdef SYSV
+        signal(SIGCHLD, do_child);
+#endif
+
+    com_err("adm_network", 0, 
+       "child %d not in list: termsig %d, retcode %d", pid,
+       WTERMSIG(status), WEXITSTATUS(status));
+
+#if defined (POSIX) || defined(SYSV) || defined(sun) && !defined(sysvimp) || defined(ultrix) || (defined(mips) && defined(SYSTYPE_BSD43)) || defined(convex)
+    return;
+#else /* !POSIX */
+    return(0);
+#endif /* POSIX */
+}
+
+krb5_error_code
+setup_network(prog)
+const char *prog;
+{
+    krb5_error_code retval;
+    char server_host_name[MAXHOSTNAMELEN];
+    char *lrealm;
+    krb5_sigtype     doexit(), do_child();
+    struct servent *service_servent;
+    struct hostent *service_hostent;
+
+    signal(SIGINT, doexit);
+    signal(SIGTERM, doexit);
+    signal(SIGHUP, doexit);
+    signal(SIGQUIT, doexit);
+    signal(SIGPIPE, SIG_IGN); /* get errors on write() */
+    signal(SIGALRM, doexit);
+    signal(SIGCHLD, do_child);
+    client_server_info.name_of_service = malloc(768);
+    if (!client_server_info.name_of_service) {
+        com_err("setup_network", 0, 
+               "adm_network: No Memory for name_of_service");
+        return ENOMEM;
+    }
+
+   
+    if (retval = krb5_get_default_realm(&lrealm)) {
+        free(client_server_info.name_of_service);
+       com_err( "setup_network", 0, 
+               "adm_network: Unable to get Default Realm");
+       return retval;
+    }
+
+    (void) sprintf(client_server_info.name_of_service, "%s%s%s%s%s",
+                        CPWNAME, "/", lrealm, "", "");
+    free(lrealm);
+
+#ifdef DEBUG
+    fprintf(stderr, "client_server_info.name_of_service = %s\n",
+               client_server_info.name_of_service);
+#endif /* DEBUG */
+
+    if ((retval = krb5_parse_name(client_server_info.name_of_service,
+                        &client_server_info.server))) {
+        free(client_server_info.name_of_service);
+       com_err( "setup_network", retval, 
+               "adm_network: Unable to Parse Server Name");
+       return retval;
+    }
+
+    if (gethostname(server_host_name, sizeof(server_host_name))) {
+       retval = errno;
+        krb5_free_principal(client_server_info.server);
+        free(client_server_info.name_of_service);
+       com_err( "setup_network", retval,
+               "adm_network: Unable to Identify Who I am");
+       return retval;
+    }
+
+    service_hostent = gethostbyname(server_host_name);
+    if (!service_hostent) {
+       retval = errno;
+        free(client_server_info.name_of_service);
+       com_err("setup_network", retval, "adm_network: Failed gethostname");
+       return retval;
+    }
+
+#ifdef DEBUG
+    fprintf(stderr, "Official host name = %s\n", service_hostent->h_name);
+#endif /* DEBUG */
+
+    client_server_info.server_name.sin_family = AF_INET;
+
+#ifdef unicos61
+    memcpy((char *) &client_server_info.server_name.sin_addr,
+               (char *) service_hostent->h_addr, service_hostent->h_length);
+#else
+    memcpy((char *) &client_server_info.server_name.sin_addr.s_addr,
+               (char *) service_hostent->h_addr, service_hostent->h_length);
+#endif /* unicos61 */
+
+    client_server_info.server_socket = -1;
+
+#ifdef DEBUG
+    fprintf(stderr, "adm5_tcp_portname = %s\n", adm5_tcp_portname);
+#endif /* DEBUG */
+
+    service_servent = getservbyname(adm5_tcp_portname, "tcp");
+
+    if (!service_servent) {
+        krb5_free_principal(client_server_info.server);
+        free(client_server_info.name_of_service);
+       com_err("setup_network", 0, "adm_network: %s/tcp service unknown", 
+                       adm5_tcp_portname);
+       return(1);
+    }
+
+#ifdef DEBUG
+    fprintf(stderr, "Official service name = %s\n", service_servent->s_name);
+#endif /* DEBUG */
+
+    client_server_info.server_name.sin_port =  service_servent->s_port;
+
+    if ((client_server_info.server_socket = 
+               socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+       retval = errno;
+        krb5_free_principal(client_server_info.server);
+        free(client_server_info.name_of_service);
+       com_err("setup_network", retval, 
+               "adm_network: Cannot create server socket.");
+       return(1);
+    }
+
+#ifdef DEBUG
+    fprintf(stderr, "Socket File Descriptor = %d\n", 
+               client_server_info.server_socket);
+    fprintf(stderr, "sin_family = %d\n", 
+               client_server_info.server_name.sin_family);
+    fprintf(stderr, "sin_port = %d\n", 
+               client_server_info.server_name.sin_port);
+    fprintf(stderr, "in_addr.s_addr = %s\n", 
+               inet_ntoa( client_server_info.server_name.sin_addr ));
+#endif /* DEBUG */
+
+    if (bind(client_server_info.server_socket,
+               &client_server_info.server_name, 
+               sizeof(client_server_info.server_name)) < 0) {
+       retval = errno;
+        krb5_free_principal(client_server_info.server);
+        free(client_server_info.name_of_service);
+       com_err("setup_network", retval, 
+               "adm_network: Cannot bind server socket.");
+       return(1);
+    }
+
+    return(0);
+}
diff --git a/src/kadmin/server/adm_parse.c b/src/kadmin/server/adm_parse.c
new file mode 100644 (file)
index 0000000..eb284c7
--- /dev/null
@@ -0,0 +1,270 @@
+#ifdef SANDIA
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1990,1991 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America is assumed
+ *   to require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ * Sandia National Laboratories also makes no representations about the
+ * suitability of the modifications, or additions to this software for
+ * any purpose.  It is provided "as is" without express or implied warranty.
+ *
+ * Edit a KDC database.
+ */
+
+#if !defined(lint) && !defined(SABER)
+static char rcsid_adm_parse[] =
+"$Id$";
+#endif  /* !lint & !SABER */
+#include <syslog.h>
+#include <stdio.h>
+
+#if defined (unicos61) || (defined(mips) && defined(SYSTYPE_BSD43)) || defined(sysvimp)
+#include <time.h>
+#else
+#include <sys/time.h>
+#endif  /* unicos61 */
+#if defined(aux20)
+#include <time.h>
+#endif  /* aux20 */
+
+#include <krb5/krb5.h>
+#include <krb5/kdb.h>
+#include <krb5/kdb_dbm.h>
+
+void
+kadmin_parse_and_set(input_string)
+char *input_string;
+{
+    extern int classification;
+    extern krb5_kvno KDB5_VERSION_NUM;
+    extern krb5_deltat KDB5_MAX_TKT_LIFE;
+    extern krb5_deltat KDB5_MAX_REN_LIFE;
+    extern krb5_timestamp KDB5_EXP_DATE;
+    extern krb5_flags NEW_ATTRIBUTES;
+
+    int num_args;
+    char parameter[40];
+    char first_token[40];
+    char second_token[40];
+    int bypass = 0;
+
+    struct tm exp_date;
+    long todays_date;
+    int year;
+    int month;
+    int mday;
+
+    first_token[0] = second_token[0] = '\0';
+    num_args = sscanf(input_string, "%s %s %s", parameter,
+                        first_token, second_token);
+
+    if (strcmp(parameter, "BYPASS") == 0) {
+        bypass++;
+        syslog(LOG_ERR,
+         "CAUTION: Classified and  Unclassified Principals will be allowed");
+       return;
+    }
+    if (strcmp(parameter, "CLASSIFICATION") == 0) {
+        if (strcmp(first_token, "CLASS") == 0) {
+            classification = 1;
+            if (bypass) classification = 0;
+       }
+       return;
+    }
+
+    if (strcmp(parameter, "VERSION_NUM") == 0) {
+        if (num_args < 2) {
+                KDB5_VERSION_NUM  = 1;
+        } else {
+                KDB5_VERSION_NUM = atoi(first_token);
+        }
+        return;
+    }    
+
+    if (strcmp(parameter, "MAX_TKT_LIFE") == 0) {
+        if (num_args < 2) {
+                KDB5_MAX_TKT_LIFE = KRB5_KDB_MAX_LIFE;
+        } else {
+            switch (second_token[0]) {
+                case 's':
+                        KDB5_MAX_TKT_LIFE = atoi(first_token);
+                        break;
+                case 'm':
+                        KDB5_MAX_TKT_LIFE = atoi(first_token) * 60;
+                        break;
+                case 'h':
+                        KDB5_MAX_TKT_LIFE = atoi(first_token) * 3600;
+                        break;
+                case 'd':
+                        KDB5_MAX_TKT_LIFE = atoi(first_token) * 86400;
+                        break;
+                case 'w':
+                        KDB5_MAX_TKT_LIFE = atoi(first_token) * 604800;
+                        break;
+                case 'M':               /* 30 days */
+                        KDB5_MAX_TKT_LIFE = atoi(first_token) * 18144000;
+                        break;
+                case 'y':               /* 365 days */
+                        KDB5_MAX_TKT_LIFE = atoi(first_token) * 220752000;
+                        break;
+                case 'e':               /* eternity */
+                        KDB5_MAX_TKT_LIFE = 2145830400;
+                        break;
+                default:
+                        break;
+            }            
+        }
+        return;
+    }    
+
+    if (strcmp(parameter, "MAX_REN_LIFE") == 0) {
+        if (num_args < 2) {
+                KDB5_MAX_REN_LIFE = KRB5_KDB_MAX_RLIFE;
+        } else {
+            switch (second_token[0]) {
+                case 's':
+                        KDB5_MAX_REN_LIFE = atoi(first_token);
+                        break;
+                case 'm':
+                        KDB5_MAX_REN_LIFE = atoi(first_token) * 60;
+                        break;
+                case 'h':
+                        KDB5_MAX_REN_LIFE = atoi(first_token) * 3600;
+                        break;
+                case 'd':
+                        KDB5_MAX_REN_LIFE = atoi(first_token) * 86400;
+                        break;
+                case 'w':
+                        KDB5_MAX_REN_LIFE = atoi(first_token) * 604800;
+                        break;
+                case 'M':               /* 30 days */
+                        KDB5_MAX_REN_LIFE = atoi(first_token) * 18144000;
+                        break;
+                case 'y':               /* 365 days */
+                        KDB5_MAX_REN_LIFE = atoi(first_token) * 220752000;
+                        break;
+                case 'e':               /* eternity */
+                        KDB5_MAX_REN_LIFE = 2145830400;
+                        break;
+                default:
+                        break;
+            }
+        }
+        return;
+    }    
+    if (strcmp(parameter, "SET_EXP_DATE") == 0) {
+        (void) time(&todays_date);
+        switch (first_token[0]) {
+              case 'e':               /* eternity */
+                      KDB5_EXP_DATE = 2145830400;
+                      year = 2037;
+                      month = 12;
+                      mday = 30;
+                      sprintf(first_token, "%s", "eternity");
+                      break;
+              case 'y':               /* yesterday */
+                      KDB5_EXP_DATE = todays_date - 86400;
+                      year = 1970;
+                      month = 01;
+                      mday = 01;
+                      sprintf(first_token, "%s", "yesterday");
+                      break;
+              case '0':
+              case '1':
+              case '2':
+              case '3':
+              case '9':
+                sscanf(first_token, "%d/%d/%d", &year, &month, &mday);
+                      year = (year > 1900) ? year - 1900 : year;
+                      year = (year > 137) ? year - 100 : year;
+                      year = (year > 137) ? 137 : year;
+                      exp_date.tm_year =
+                         ((year >= 00 && year < 38) ||
+                          (year >= 70 && year <= 138)) ? year : 137;
+                      exp_date.tm_mon =
+                          (month >= 1 &&
+                           month <= 12) ? month - 1 : 0;
+                      exp_date.tm_mday =
+                          (mday >= 1 &&
+                           mday <= 31) ? mday : 1;
+                      exp_date.tm_hour = 0;
+                      exp_date.tm_min = 1;
+                      exp_date.tm_sec = 0;
+                      KDB5_EXP_DATE = convert_tm_to_sec(&exp_date);
+                      break;
+              default:
+                      KDB5_EXP_DATE = KRB5_KDB_EXPIRATION;
+                      sprintf(first_token, "%s", "Default KDB Expiration");
+                      break;
+        }
+        if (year < 1900) year += 1900;
+        if (year < 1938) year += 100;
+        return;
+    }
+    if (strcmp(parameter, "SET_PWCHG") == 0) {
+        if (num_args < 2) {
+           NEW_ATTRIBUTES = NEW_ATTRIBUTES | KRB5_KDB_REQUIRES_PWCHANGE;
+        } else {
+            if (first_token[0] == 'y' || first_token[0] == 'Y') {
+                NEW_ATTRIBUTES = NEW_ATTRIBUTES | KRB5_KDB_REQUIRES_PWCHANGE;
+            } else {
+                NEW_ATTRIBUTES = NEW_ATTRIBUTES & ~KRB5_KDB_REQUIRES_PWCHANGE;
+                KDB5_VERSION_NUM  = 1;
+            }
+        }
+        return;
+    }    
+
+    if (strcmp(parameter, "SET_PREAUTH") == 0) {
+        if (num_args < 2) {
+           NEW_ATTRIBUTES = NEW_ATTRIBUTES | KRB5_KDB_REQUIRES_PRE_AUTH;
+        } else {
+            if (first_token[0] == 'y' || first_token[0] == 'Y') {
+                NEW_ATTRIBUTES = NEW_ATTRIBUTES | KRB5_KDB_REQUIRES_PRE_AUTH;
+            } else {
+                NEW_ATTRIBUTES = NEW_ATTRIBUTES & ~KRB5_KDB_REQUIRES_PRE_AUTH;
+            }
+        }
+        return;
+    }    
+
+    if (strcmp(parameter, "SET_SECUREID") == 0) {
+        if (num_args < 2) {
+           NEW_ATTRIBUTES = NEW_ATTRIBUTES | KRB5_KDB_REQUIRES_HW_AUTH |
+                KRB5_KDB_REQUIRES_PRE_AUTH;
+        } else {
+            if (first_token[0] == 'y' || first_token[0] == 'Y') {
+                NEW_ATTRIBUTES = NEW_ATTRIBUTES | KRB5_KDB_REQUIRES_HW_AUTH |
+                        KRB5_KDB_REQUIRES_PRE_AUTH;
+            } else {
+                NEW_ATTRIBUTES = NEW_ATTRIBUTES & ~KRB5_KDB_REQUIRES_HW_AUTH;
+            }
+        }
+        return;
+    }
+}
+#endif
diff --git a/src/kadmin/server/adm_process.c b/src/kadmin/server/adm_process.c
new file mode 100644 (file)
index 0000000..0e3d0d4
--- /dev/null
@@ -0,0 +1,454 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ */
+
+/* 
+ * Sandia National Laboratories also makes no representations about the 
+ * suitability of the modifications, or additions to this software for 
+ * any purpose.  It is provided "as is" without express or implied warranty.
+ */
+
+#if !defined(lint) && !defined(SABER)
+static char rcsid_adm_process[] =
+"$Header$";
+#endif /* lint */
+
+/*
+  adm_process.c
+*/
+
+#include <sys/types.h>
+#include <syslog.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <com_err.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#ifndef hpux
+#include <arpa/inet.h>
+#endif
+
+#include <krb5/krb5.h>
+#include <krb5/ext-proto.h>
+#include <krb5/los-proto.h>
+#include <krb5/kdb.h>
+#include <krb5/adm_defs.h>
+#include "adm_extern.h"
+
+extern krb5_encrypt_block master_encblock;
+extern krb5_keyblock master_keyblock;
+
+struct cpw_keyproc_arg {
+    krb5_keyblock *key;
+};
+
+static krb5_error_code
+cpw_keyproc(DECLARG(krb5_pointer, keyprocarg),
+               DECLARG(krb5_principal, server),
+               DECLARG(krb5_kvno, key_vno),
+               DECLARG(krb5_keyblock **, key))
+OLDDECLARG(krb5_pointer, keyprocarg)
+OLDDECLARG(krb5_principal, server)
+OLDDECLARG(krb5_kvno, key_vno)
+OLDDECLARG(krb5_keyblock **, key)
+{
+    krb5_error_code retval;
+    krb5_db_entry cpw_entry;
+    krb5_principal cpw_krb;
+    krb5_keyblock *realkey;
+
+    struct cpw_keyproc_arg *arg;
+
+    krb5_boolean more;
+
+    int nprincs = 1;
+
+    arg = ( struct cpw_keyproc_arg *) keyprocarg;
+
+    if (arg->key) {
+       *key = arg->key;
+    } else {
+       if (retval = krb5_parse_name(client_server_info.name_of_service, 
+                                    &cpw_krb)) {
+            syslog(LOG_ERR, 
+                  "cpw_keyproc %d while attempting to parse \"%s\"",
+                  client_server_info.name_of_service, retval);
+            return(0);
+       }
+
+       if (retval = krb5_db_get_principal(cpw_krb, &cpw_entry, 
+                       &nprincs, &more)) {
+            syslog(LOG_ERR, 
+                  "cpw_keyproc %d while extracting %s entry",
+                  client_server_info.name_of_service, retval);
+            return(0);
+       }
+
+       if (!nprincs) return(0);
+
+       if ((realkey = (krb5_keyblock *) calloc (1, 
+               sizeof(krb5_keyblock))) == (krb5_keyblock * ) 0) {
+           krb5_db_free_principal(&cpw_entry, nprincs);
+           syslog(LOG_ERR, "cpw_keyproc: No Memory for server key");
+           close(client_server_info.client_socket);
+           return(0);
+       }
+
+       /* Extract the real kadmin/<realm> keyblock */
+       if (retval = krb5_kdb_decrypt_key(
+                               &master_encblock,
+                               &cpw_entry.key,
+                               realkey)) {
+           krb5_db_free_principal(&cpw_entry, nprincs);
+           free(realkey);
+           syslog(LOG_ERR, 
+                  "cpw_keyproc: Cannot extract %s from master key",
+                  client_server_info.name_of_service);
+           exit(0);
+       }
+
+       *key = realkey;
+    }
+
+    return(0);
+}
+
+krb5_error_code
+process_client(prog)
+char *prog;
+{
+    krb5_error_code retval;
+
+    struct cpw_keyproc_arg cpw_key;
+
+    int on = 1;
+    krb5_db_entry server_entry;
+
+    krb5_ticket *client_creds;
+    krb5_authenticator *client_auth_data;
+    char retbuf[512];
+
+    krb5_data final_msg;
+    char completion_msg[520];
+    kadmin_requests request_type;
+
+    int number_of_entries;
+    krb5_boolean more;
+    int namelen;
+
+    char *req_type = "";
+    int otype;
+
+    u_short data_len;
+    krb5_data outbuf;
+    krb5_data inbuf, msg_data;
+    extern int errno;
+    
+    krb5_timestamp adm_time;
+
+    outbuf.data = retbuf;
+    if (setsockopt(client_server_info.client_socket, 
+                       SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) < 0) {
+       syslog(LOG_ERR, "adm_process: setsockopt keepalive: %d", errno);
+    }
+
+               /* V4 kpasswd Protocol Hack */
+               /* Read Length of Data */
+    retval = krb5_net_read(client_server_info.client_socket,
+               (char *) &data_len, 2);
+    if (retval < 0) {
+       syslog(LOG_ERR, "kadmind error: net_read Length Failure");
+       (void) sprintf(retbuf, "kadmind error during net_read for Length\n");
+       exit(0);
+    }
+
+    if (retval = krb5_db_init()) {             /* Open as client */
+       syslog(LOG_ERR, "adm_process: Can't Open Database");
+       close(client_server_info.client_socket);
+       exit(0);
+    }
+
+/*     Get Server Credentials for Mutual Authentication and Private
+ *     Messages  Note: Here client is the kadmin/<realm> server
+ */
+    number_of_entries = 1;
+    if ((retval = krb5_db_get_principal(client_server_info.server,
+                       &server_entry,
+                       &number_of_entries,
+                       &more))) {
+       syslog(LOG_ERR, 
+               "kadmind error: krb5_db_get_principal error: %d", retval);
+       close(client_server_info.client_socket);
+       exit(0);
+    }
+
+    if (more) {
+       krb5_db_free_principal(&server_entry, number_of_entries);
+       syslog(LOG_ERR, "kadmind error: kadmin/<realm> service not unique");
+       exit(1);
+    }
+
+    if (number_of_entries != 1) {
+       krb5_db_free_principal(&server_entry, number_of_entries);
+       syslog(LOG_ERR, "kadmind error: kadmin/<realm> service UNKNOWN");
+       close(client_server_info.client_socket);
+       exit(0);
+    }
+
+    if ((cpw_key.key = (krb5_keyblock *) calloc (1, 
+               sizeof(krb5_keyblock))) == (krb5_keyblock *) 0) {
+       krb5_db_free_principal(&server_entry, number_of_entries);
+       syslog(LOG_ERR, 
+              "kadmind error: No Memory for server key");
+       close(client_server_info.client_socket);
+       exit(0);
+    }
+
+    /* Extract the real kadmin/<realm> keyblock */
+    if (retval = krb5_kdb_decrypt_key(
+                                     &master_encblock,
+                                     &server_entry.key,
+                                     (krb5_keyblock *) cpw_key.key)) {
+       krb5_db_free_principal(&server_entry, number_of_entries);
+       free(cpw_key.key);
+       syslog(LOG_ERR,  
+              "kadmind error: Cannot extract kadmin/<realm> from master key");
+       close(client_server_info.client_socket);
+       exit(0);
+    }
+
+/*
+ *     To verify authenticity, we need to know the address of the
+ *     client.
+ */
+
+    namelen = sizeof(client_server_info.client_addr);
+    if (getpeername(client_server_info.client_socket, 
+                       (struct sockaddr *) &client_server_info.client_addr, 
+                       &namelen) < 0) {
+       syslog(LOG_ERR,  "kadmind error: Unable to Obtain Client Name.");
+       close(client_server_info.client_socket);
+       exit(0);
+    }
+
+                       /* we use mutual authentication */
+    client_server_info.client_addr.addrtype = 
+               client_server_info.client_name.sin_family;
+    client_server_info.client_addr.length = SIZEOF_INADDR;
+    client_server_info.client_addr.contents = 
+               (krb5_octet *) &client_server_info.client_name.sin_addr;
+
+    client_server_info.server_addr.addrtype = 
+               client_server_info.server_name.sin_family;
+    client_server_info.server_addr.length = SIZEOF_INADDR;
+    client_server_info.server_addr.contents = 
+               (krb5_octet *) &client_server_info.server_name.sin_addr;
+
+    krb5_init_ets();
+
+    syslog(LOG_AUTH | LOG_INFO,
+       "Request for Administrative Service Received from %s - Authenticating.",
+       inet_ntoa( client_server_info.client_name.sin_addr ));
+       
+    if ((retval = krb5_recvauth(
+               (krb5_pointer) &client_server_info.client_socket,
+               ADM5_CPW_VERSION,
+               client_server_info.server,
+               &client_server_info.client_addr,
+               0,
+               cpw_keyproc,
+               (krb5_pointer) &cpw_key,
+               0,
+               &send_seqno,
+               &client_server_info.client,
+               &client_creds,
+               &client_auth_data
+               ))) {
+       syslog(LOG_ERR, "kadmind error: %s during recvauth\n", 
+                       error_message(retval));
+       (void) sprintf(retbuf, "kadmind error during recvauth: %s\n", 
+                       error_message(retval));
+    } else {
+       /* Check if ticket was issued using password (and not tgt)
+          within the last 5 minutes */
+       
+       if (!(client_creds->enc_part2->flags & TKT_FLG_INITIAL)) {
+           syslog(LOG_ERR,
+                "Client ticket not initial");
+           close(client_server_info.client_socket);
+           exit(0);
+       }
+
+       if (retval = krb5_timeofday(&adm_time)) {
+           syslog(LOG_ERR,
+                "Can't get time of day");
+           close(client_server_info.client_socket);
+           exit(0);
+       }
+       
+       if ((client_creds->enc_part2->times.authtime - adm_time) > 60*5) {
+           syslog(LOG_ERR,
+                "Client ticket not recent");
+           close(client_server_info.client_socket);
+           exit(0);
+       }
+
+       recv_seqno = client_auth_data->seq_number;
+
+       if ((client_server_info.name_of_client =
+                       (char *) calloc (1, 3 * 255)) == (char *) 0) {
+           syslog(LOG_ERR, "kadmind error: No Memory for name_of_client");
+           close(client_server_info.client_socket);
+           exit(0);
+       }
+
+       if ((retval = krb5_unparse_name(client_server_info.client, 
+                       &client_server_info.name_of_client))) {
+            syslog(LOG_ERR, "kadmind error: unparse failed.", 
+                               error_message(retval));
+           goto finish;
+       }
+
+       syslog(LOG_AUTH | LOG_INFO,
+               "Request for Administrative Service Received from %s at %s.",
+               client_server_info.name_of_client,
+               inet_ntoa( client_server_info.client_name.sin_addr ));
+       
+                       /* compose the reply */
+       outbuf.data[0] = KADMIND;
+        outbuf.data[1] = KADMSAG;
+        outbuf.length = 2;
+    }
+
+               /* write back the response */
+    if ((retval = krb5_write_message(&client_server_info.client_socket,
+                                       &outbuf))){
+       syslog(LOG_ERR, "kadmind error: Write Message Failure: %s",
+                       error_message(retval));
+       retval = 1;
+       goto finish;
+    }
+
+       /* Ok Now let's get the first private message and respond */
+    if (retval = krb5_read_message(&client_server_info.client_socket,
+                                        &inbuf)){
+       syslog(LOG_ERR, "kadmind error: read First Message Failure: %s",
+               error_message(retval));
+       retval = 1;
+       goto finish;
+    }
+
+    if ((retval = krb5_rd_priv(&inbuf, 
+                       client_creds->enc_part2->session,
+                       &client_server_info.client_addr, 
+                       &client_server_info.server_addr,
+                       client_auth_data->seq_number,
+                       KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                       0,
+                       0,
+                       &msg_data))) {
+       syslog(LOG_ERR, "kadmind error: rd_priv:%s\n", error_message(retval));
+       goto finish;
+    }
+    free(inbuf.data);
+
+    request_type.appl_code = msg_data.data[0];
+    request_type.oper_code = msg_data.data[1];
+
+    free(msg_data.data);
+
+    switch (request_type.appl_code) {
+       case KPASSWD:
+           req_type = "kpasswd";
+           if (retval = adm5_kpasswd("process_client", &request_type, 
+                       client_creds, retbuf, &otype)) {
+               goto finish;
+           }
+           break;
+
+       case KADMIN:
+           req_type = "kadmin";
+           if (retval = adm5_kadmin("process_client", client_auth_data,
+                       client_creds, retbuf, &otype)) {
+               goto finish;
+           }
+           retbuf[0] = KADMIN;
+           retbuf[2] = KADMGOOD;
+           retbuf[3] = '\0';
+           otype = 0;
+           break;
+
+       default:
+           retbuf[0] = KUNKNOWNAPPL;
+           retbuf[1] = '\0';
+           sprintf(completion_msg, "%s from %s (%02x) FAILED", 
+                       "Unknown Application Type!", 
+                       inet_ntoa(client_server_info.client_name.sin_addr),
+                   request_type.appl_code);
+               /* Service Not Supported */
+           retval = 255;
+           syslog(LOG_AUTH | LOG_INFO, completion_msg);
+           goto finish;
+    }                          /* switch(request_type.appl_code) */
+
+    if ((final_msg.data = (char *) calloc(1,10)) == (char *) 0) {
+       syslog(LOG_ERR | LOG_INFO, "no Memory while allocating final_msg.data");
+       return ENOMEM;
+    }
+    final_msg.data = retbuf;
+    final_msg.length = strlen(retbuf) + 1;
+
+                /* Send Completion Message */
+    if (retval = krb5_mk_priv(&final_msg,
+                        ETYPE_DES_CBC_CRC,
+                        client_creds->enc_part2->session,
+                        &client_server_info.server_addr,
+                        &client_server_info.client_addr,
+                        send_seqno,
+                        KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME,
+                        0,
+                        0,
+                        &msg_data)) {
+       syslog(LOG_ERR, "kadmind error Error Performing Final mk_priv");
+       free(final_msg.data);
+       goto finish;
+    }
+    free(final_msg.data);
+    
+        /* Send Final Reply to Client */
+    if (retval = krb5_write_message(&client_server_info.client_socket,
+                                       &msg_data)){
+       syslog(LOG_ERR, "Error Performing Final Write: %s",
+                       error_message(retval));
+       retval = 1;
+       goto finish;
+    }
+    free(msg_data.data);
+
+finish:
+
+    if (retval) {
+       free (client_server_info.name_of_client);
+       close(client_server_info.client_socket);
+       exit(1);
+    }
+    sprintf(completion_msg,
+        "%s %s for %s at %s - Completed Successfully",
+       req_type,
+       oper_type[otype],
+        client_server_info.name_of_client, 
+        inet_ntoa( client_server_info.client_name.sin_addr )); 
+    syslog(LOG_AUTH | LOG_INFO, completion_msg);
+    free (client_server_info.name_of_client);
+    close(client_server_info.client_socket);
+    return 0;
+}
diff --git a/src/kadmin/server/adm_server.c b/src/kadmin/server/adm_server.c
new file mode 100644 (file)
index 0000000..c61a8da
--- /dev/null
@@ -0,0 +1,480 @@
+/*
+ * $Source$
+ * $Author$
+ *
+ * Copyright 1988 by the Massachusetts Institute of Technology.
+ *
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
+ *
+ * Top-level loop of the Kerberos Version 5 Administration server
+ */
+
+/* 
+ * Sandia National Laboratories also makes no representations about the 
+ * suitability of the modifications, or additions to this software for 
+ * any purpose.  It is provided "as is" without express or implied warranty.
+ */
+
+#if !defined(lint) && !defined(SABER)
+static char rcsid_adm_server_c[] =
+"$Header$";
+#endif /* lint */
+
+/*
+  adm_server.c
+  this holds the main loop and initialization and cleanup code for the server
+*/
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <syslog.h>
+#include <string.h>
+#include <com_err.h>
+
+#include <signal.h>
+#ifndef sigmask
+#define sigmask(m)    (1 <<((m)-1))
+#endif
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#ifndef hpux
+#include <arpa/inet.h>
+#endif
+
+#ifndef __STDC__
+#include <varargs.h>
+#endif
+
+#include <krb5/krb5.h>
+#include <krb5/kdb.h>
+#include <krb5/dbm.h>
+#include <krb5/ext-proto.h>
+#include <krb5/los-proto.h>
+#include <krb5/mit-des.h>
+#include <krb5/kdb_dbm.h>
+
+#include <krb5/adm_defs.h>
+#include "adm_server.h"
+#include "adm_extern.h"
+
+global_client_server_info client_server_info;
+
+#ifdef SANDIA
+int classification;             /* default = Unclassified */
+#endif
+
+krb5_flags NEW_ATTRIBUTES;
+
+cleanexit(val)
+    int        val;
+{
+    (void) krb5_db_fini();
+    exit(val);
+}
+
+krb5_error_code
+closedown_db()
+{
+    krb5_error_code retval;
+
+    /* clean up master key stuff */
+    retval = krb5_finish_key(&master_encblock);
+
+    memset((char *)&master_encblock, 0, sizeof(master_encblock));
+    memset((char *)tgs_key.contents, 0, tgs_key.length);
+
+    /* close database */
+    if (retval) {
+       (void) krb5_db_fini();
+       return(retval);
+    } else
+       return(krb5_db_fini());
+}
+void
+usage(name)
+char *name;
+{
+    fprintf(stderr, "Usage: %s\t[-a aclfile] [-d dbname] [-k masterkeytype]", 
+                       name);
+    fprintf(stderr, "\n\t[-h] [-m] [-M masterkeyname] [-r realm]\n");
+    return;
+}
+krb5_error_code
+process_args(argc, argv)
+int argc;
+char **argv;
+{
+    krb5_error_code retval;
+    int c;
+    krb5_boolean manual = FALSE;
+    int keytypedone = 0;
+    char *db_realm = 0;
+    char *mkey_name = 0;
+    char *local_realm;
+    krb5_enctype etype;
+
+#ifdef SANDIA
+    char input_string[80];
+    FILE *startup_file;
+#endif
+
+    extern char *optarg;
+
+#ifdef SANDIA
+    classification = 0;
+
+    if ((startup_file =
+        fopen(DEFAULT_KDCPARM_NAME, "r")) == (FILE *) 0) {
+        syslog(LOG_ERR, 
+               "Cannot open parameter file (%s) - Using default parameters",
+               DEFAULT_KDCPARM_NAME);
+        syslog(LOG_ERR, "Only Unclassified Principals will be allowed");
+    } else {
+        for ( ;; ) {
+            if ((fgets(input_string, sizeof(input_string), startup_file)) == NULL)
+                break;
+            kadmin_parse_and_set(input_string);
+        }
+        fclose(startup_file);
+    }
+#endif
+    while ((c = getopt(argc, argv, "hmMa:d:k:r:")) != EOF) {
+       switch(c) {
+           case 'a':                   /* new acl directory */
+               acl_file_name = optarg;
+               break;
+
+           case 'd':
+               /* put code to deal with alt database place */
+               dbm_db_name = optarg;
+               if (retval = krb5_dbm_db_set_name(dbm_db_name)) {
+                       fprintf(stderr, "opening database %s: %s",
+                               dbm_db_name, error_message(retval));
+                       exit(1);
+               }
+               break;
+
+           case 'k':                   /* keytype for master key */
+               master_keyblock.keytype = atoi(optarg);
+               keytypedone++;
+               break;
+
+           case 'm':                   /* manual type-in of master key */
+               manual = TRUE;
+               break;
+
+           case 'M':                   /* master key name in DB */
+               mkey_name = optarg;
+               break;
+
+           case 'r':
+               db_realm = optarg;
+               break;
+
+           case 'h':                   /* get help on using adm_server */
+           default:
+               usage(argv[0]);
+               exit(1);                /* Failure - Exit */
+       }
+
+    }
+
+    if (!db_realm) {
+               /* no realm specified, use default realm */
+       if (retval = krb5_get_default_realm(&local_realm)) {
+               com_err(argv[0], retval,
+                       "while attempting to retrieve default realm");
+               exit(1);
+       }
+       db_realm = local_realm;
+    }        
+    if (!mkey_name) {
+       mkey_name = KRB5_KDB_M_NAME;
+    }
+    if (!keytypedone) {
+       master_keyblock.keytype = KEYTYPE_DES;
+    }
+    /* assemble & parse the master key name */
+    if (retval = krb5_db_setup_mkey_name(mkey_name, 
+                                       db_realm, 
+                                       (char **) 0,
+                                       &master_princ)) {
+       com_err(argv[0], retval, "while setting up master key name");
+       exit(1);
+    }
+
+    master_encblock.crypto_entry = &mit_des_cryptosystem_entry;
+    if (retval = krb5_db_fetch_mkey(
+               master_princ, 
+               &master_encblock, 
+               manual,
+               FALSE,                  /* only read it once, if at all */
+               0,                      /* No salt supplied */
+               &master_keyblock)) {
+       com_err(argv[0], retval, "while fetching master key");
+       exit(1);
+    }
+
+    /* initialize random key generators */
+    for (etype = 0; etype <= krb5_max_cryptosystem; etype++) {
+       if (krb5_csarray[etype]) {
+               if (retval = (*krb5_csarray[etype]->system->
+                               init_random_key)(&master_keyblock,
+                               &krb5_csarray[etype]->random_sequence)) {
+                       com_err(argv[0], retval, 
+       "while setting up random key generator for etype %d--etype disabled", 
+                               etype);
+                       krb5_csarray[etype] = 0;
+               }
+       }
+    }
+    return(0);
+}
+
+krb5_error_code
+init_db(dbname, masterkeyname, masterkeyblock)
+char *dbname;
+krb5_principal masterkeyname;
+krb5_keyblock *masterkeyblock;
+
+{
+    krb5_error_code retval;
+
+    krb5_db_entry server_entry;
+    krb5_boolean more;
+    int number_of_entries;
+    char tgs_name[255];
+
+    /* set db name if appropriate */
+    if (dbname && (retval = krb5_db_set_name(dbname)))
+        return(retval);
+
+    /* initialize database */
+    if (retval = krb5_db_init())
+        return(retval);
+
+    if (retval = krb5_db_verify_master_key(masterkeyname, 
+                                       masterkeyblock,
+                                        &master_encblock)) {
+        master_encblock.crypto_entry = 0;
+        return(retval);
+    }
+    /* do any necessary key pre-processing */
+    if (retval = krb5_process_key(&master_encblock, masterkeyblock)) {
+        master_encblock.crypto_entry = 0;
+        (void) krb5_db_fini();
+        return(retval);
+    }
+/*
+       fetch the TGS key, and hold onto it; this is an efficiency hack 
+       the master key name here is from the master_princ global,
+       so we can safely share its substructure
+ */
+    strcpy(tgs_name, TGTNAME);
+    strcat(tgs_name, "/");
+    strcat(tgs_name, masterkeyname->realm.data);
+    krb5_parse_name(tgs_name, &tgs_server);
+
+    tgs_server->type  = KRB5_NT_SRV_INST;
+
+    number_of_entries = 1;
+    if (retval = krb5_db_get_principal(
+                               tgs_server,
+                               &server_entry, 
+                               &number_of_entries,
+                               &more)) {
+       return(retval);
+    }
+
+    if (more) {
+       krb5_db_free_principal(&server_entry, number_of_entries);
+       (void) krb5_finish_key(&master_encblock);
+       memset((char *)&master_encblock, 0, sizeof(master_encblock));
+       (void) krb5_db_fini();
+       return(KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE);
+    } else if (number_of_entries != 1) {
+       krb5_db_free_principal(&server_entry, number_of_entries);
+       (void) krb5_finish_key(&master_encblock);
+       memset((char *)&master_encblock, 0, sizeof(master_encblock));
+       (void) krb5_db_fini();
+       return(KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN);
+    }
+
+/* 
+       convert server.key into a real key 
+       (it may be encrypted in the database) 
+ */
+    if (retval = KDB_CONVERT_KEY_OUTOF_DB(&server_entry.key, &tgs_key)) {
+       krb5_db_free_principal(&server_entry, number_of_entries);
+       (void) krb5_finish_key(&master_encblock);
+       memset((char *)&master_encblock, 0, sizeof(master_encblock));
+       (void) krb5_db_fini();
+       return(retval);
+    }
+
+    tgs_kvno = server_entry.kvno;
+    krb5_db_free_principal(&server_entry, number_of_entries);
+    return(0);
+}
+krb5_sigtype
+request_exit()
+{
+    signal_requests_exit = 1;
+    return;
+}
+
+void
+setup_signal_handlers()
+{
+  krb5_sigtype     request_exit();
+
+    (void)signal(SIGINT, request_exit);
+    (void)signal(SIGHUP, request_exit);
+    (void)signal(SIGTERM, request_exit);
+    return;
+}
+static void
+kdc_com_err_proc(whoami, code, format, pvar)
+    const char *whoami;
+    long code;
+    const char *format;
+    va_list pvar;
+{
+#ifndef __STDC__
+    extern int vfprintf();
+#endif
+
+    if (whoami) {
+       fputs(whoami, stderr);
+       fputs(": ", stderr);
+    }
+
+    if (code) {
+       fputs(error_message(code), stderr);
+       fputs(" ", stderr);
+    }
+
+    if (format) {
+       vfprintf (stderr, format, pvar);
+    }
+
+    putc('\n', stderr);
+       /* should do this only on a tty in raw mode */
+    putc('\r', stderr);
+    fflush(stderr);
+
+    if (format) {
+               /* now need to frob the format a bit... */
+       if (code) {
+               char *nfmt;
+               nfmt = (char *) malloc(
+                               strlen(format)+strlen(error_message(code))+2);
+               strcpy(nfmt, error_message(code));
+               strcat(nfmt, " ");
+               strcat(nfmt, format);
+               vsyslog(LOG_ERR, nfmt, pvar);
+       } else {
+               vsyslog(LOG_ERR, format, pvar);
+       }
+    } else {
+       if (code) {
+               syslog(LOG_ERR, "%s", error_message(code));
+       }
+    }
+    return;
+}
+void
+setup_com_err()
+{
+    initialize_krb5_error_table();
+    initialize_kdb5_error_table();
+    initialize_isod_error_table();
+
+    (void) set_com_err_hook(kdc_com_err_proc);
+    return;
+}
+
+/*
+** Main does the logical thing, it sets up the database and RPC interface,
+**  as well as handling the creation and maintenance of the syslog file...
+*/
+main(argc, argv)               /* adm_server main routine */
+int argc;
+char **argv;
+{
+    krb5_error_code retval;
+    int errout = 0;
+
+    adm5_ver_len = ADM5_VERSIZE;
+
+       /* Get the Name of this program (adm_server) for Error Messages */
+    if (strrchr(argv[0], '/'))
+       argv[0] = (char *)strrchr(argv[0], '/') + 1;
+
+    setup_com_err();
+
+       /* Use Syslog for Messages */
+#ifndef LOG_AUTH        /* 4.2 syslog */
+#define LOG_AUTH 0
+    openlog(argv[0], LOG_CONS|LOG_NDELAY|LOG_PID, LOG_LOCAL6);
+#else
+    openlog(argv[0], LOG_AUTH|LOG_CONS|LOG_NDELAY|LOG_PID, LOG_LOCAL6);
+#endif  /* LOG_AUTH */
+
+    process_args(argc, argv);           /* includes reading master key */
+
+    setup_signal_handlers();
+
+    if (retval = init_db(dbm_db_name, 
+                       master_princ, 
+                       &master_keyblock)) {
+       com_err(argv[0], retval, "while initializing database");
+       exit(1);
+    }
+
+    if (retval = setup_network(argv[0])) {
+       exit(1);
+    }
+
+    syslog(LOG_AUTH | LOG_INFO, "Admin Server Commencing Operation");
+
+    if (retval = adm5_listen_and_process(argv[0])){
+        krb5_free_principal(client_server_info.server);
+       com_err(argv[0], retval, "while processing network requests");
+       errout++;
+    }
+
+    free(client_server_info.name_of_service);
+    krb5_free_principal(client_server_info.server);
+
+shutdown:
+    if (errout = closedown_network(argv[0])) {
+       com_err(argv[0], retval, "while shutting down network");
+       retval = retval + errout;
+    }
+
+    if (errout = closedown_db()) {
+       com_err(argv[0], retval, "while closing database");
+       retval = retval + errout;
+    }
+
+    syslog(LOG_AUTH | LOG_INFO, "Admin Server Shutting Down");
+
+    printf("Admin Server (kadmind) has completed operation.\n");
+
+    exit(retval);
+}
diff --git a/src/kadmin/server/adm_server.h b/src/kadmin/server/adm_server.h
new file mode 100644 (file)
index 0000000..d5b600a
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * $Source$
+ * $Author$
+ * $Id$
+ *
+ * Copyright 1990 by the Massachusetts Institute of Technology.
+ *
+ * Export of this software from the United States of America is assumed
+ *   to require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ * 
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ * 
+ * Sandia National Laboratories also makes no representations about the 
+ * suitability of the modifications, or additions to this software for 
+ * any purpose.  It is provided "as is" without express or implied warranty.
+ *
+ * <<< Description >>>
+ */
+
+char prog[32];
+char *progname = prog;
+char *acl_file_name = DEFAULT_ACL_NAME;
+char *adm5_ver_str = ADM5_VERSTR;
+int  adm5_ver_len;
+
+char *adm5_tcp_portname = ADM5_PORTNAME;
+int adm5_tcp_port_fd = -1;
+unsigned pidarraysize = 0;
+int *pidarray = (int *) 0;
+
+int exit_now = 0;
diff --git a/src/kadmin/server/adm_v4_pwd.c b/src/kadmin/server/adm_v4_pwd.c
new file mode 100644 (file)
index 0000000..65ccefe
--- /dev/null
@@ -0,0 +1,437 @@
+
+/* 
+ * Sandia National Laboratories also makes no representations about the 
+ * suitability of the modifications, or additions to this software for 
+ * any purpose.  It is provided "as is" without express or implied warranty.
+ */
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <syslog.h>
+#include <stdio.h>
+
+#define         MAX_KTXT_LEN    1250
+#define        ANAME_SZ        40
+#define                INST_SZ         40
+#define                REALM_SZ        40
+#define                DATE_SZ         26
+
+typedef unsigned char des_cblock[8];   /* crypto-block size */
+#define C_Block des_cblock
+typedef struct des_ks_struct { des_cblock _; } des_key_schedule[16];
+#define Key_schedule des_key_schedule
+
+int des_debug = 0;
+
+struct ktext {
+    int     length;             /* Length of the text */
+    unsigned char dat[MAX_KTXT_LEN];    /* The data itself */
+    unsigned long mbz;          /* zero to catch runaway strings */
+};
+
+typedef struct ktext *KTEXT;
+typedef struct ktext KTEXT_ST;
+
+struct auth_dat {
+    unsigned char k_flags;      /* Flags from ticket */
+    char    pname[ANAME_SZ];    /* Principal's name */
+    char    pinst[INST_SZ];     /* His Instance */
+    char    prealm[REALM_SZ];   /* His Realm */
+    unsigned long checksum;     /* Data checksum (opt) */
+    C_Block session;            /* Session Key */
+    int     life;               /* Life of ticket */
+    unsigned long time_sec;     /* Time ticket issued */
+    unsigned long address;      /* Address in ticket */
+    KTEXT_ST reply;             /* Auth reply (opt) */
+};
+
+typedef struct auth_dat AUTH_DAT;
+
+#define KADM_VERSTR    "SKADM.m1"
+#define KADM_VERSIZE strlen(KADM_VERSTR)
+
+struct msg_dat {
+    unsigned char *app_data;    /* pointer to appl data */
+    unsigned long app_length;   /* length of appl data */
+    unsigned long hash;         /* hash to lookup replay */
+    int     swap;               /* swap bytes? */
+    long    time_sec;           /* msg timestamp seconds */
+    unsigned char time_5ms;     /* msg timestamp 5ms units */
+};
+
+typedef struct msg_dat MSG_DAT;
+
+typedef struct {
+    char    name[ANAME_SZ];
+    char    instance[INST_SZ];
+    unsigned long key_low;
+    unsigned long key_high;
+    unsigned long exp_date;
+    char    exp_date_txt[DATE_SZ];
+    unsigned long mod_date;
+    char    mod_date_txt[DATE_SZ];
+    unsigned short attributes;
+    unsigned char max_life;
+    unsigned char kdc_key_ver;
+    unsigned char key_version;
+    char mod_name[ANAME_SZ];
+    char mod_instance[INST_SZ];
+    char *old;
+} V4_Principal;
+
+        /* V5 Definitions */
+#include <krb5/adm_defs.h>
+#include <krb5/krb5.h>
+#include <krb5/osconf.h>
+#include <krb5/kdb.h>
+#include <krb5/kdb_dbm.h>
+#include <krb5/encryption.h>
+#include <krb5/mit-des.h>
+
+#include "adm_extern.h"
+
+struct saltblock {
+    int salttype;
+    krb5_data saltdata;
+};
+
+struct cpw_keyproc_arg {
+    krb5_keyblock *key;
+};
+
+/*
+process_v4_kpasswd
+unwrap the data stored in dat, process, and return it.
+ */
+process_v4_kpasswd(dat, dat_len, cpw_key)
+u_char **dat;
+int *dat_len;
+struct cpw_keyproc_arg *cpw_key;
+
+{
+    u_char *in_st;                      /* pointer into the sent packet */
+    int in_len,retc;                    /* where in packet we are, for
+                                           returns */
+    u_long r_len;                       /* length of the actual packet */
+    KTEXT_ST authent;                   /* the authenticator */
+    AUTH_DAT ad;                        /* who is this, klink */
+    u_long ncksum;                      /* checksum of encrypted data */
+    des_key_schedule sess_sched;        /* our schedule */
+    MSG_DAT msg_st;
+    u_char *retdat, *tmpdat;
+    int retval, retlen;
+    u_short dlen;
+    extern int errno;
+
+    if (strncmp(KADM_VERSTR, (char *) *dat, KADM_VERSIZE)) {
+       syslog(LOG_ERR, "process_v4_kpasswd: Bad Version String");
+        return(1);
+    }
+
+    in_len = KADM_VERSIZE;
+                       /* get the length */
+    if ((retc = stv_long(*dat, &r_len, in_len, *dat_len)) < 0) {
+       syslog(LOG_AUTH | LOG_INFO, "process_v4_kpasswd: Bad Length");
+        return(1);
+    }
+
+    in_len += retc;
+    authent.length = *dat_len - r_len - KADM_VERSIZE - sizeof(u_long);
+    memcpy((char *) authent.dat, (char *) (*dat) + in_len, authent.length);
+    authent.mbz = 0;
+
+    if (retval = krb_set_key(cpw_key->key->contents, 0) != 0) {
+       syslog(LOG_ERR, "process_v4_kpasswd: Bad set_key Request");
+        return(1);
+    }
+
+    /* service key should be set before here */
+    if (retc = krb4_rd_req(&authent, 
+                          CPWNAME, 
+                          client_server_info.server->realm.data,
+                          client_server_info.client_name.sin_addr.s_addr,
+                          &ad, 
+                          (char *) 0)) {
+       syslog(LOG_AUTH | LOG_INFO, "process_v4_kpasswd: Bad Read Request");
+        return(1);
+    }
+
+#define clr_cli_secrets() \
+{ \
+       memset((char *) sess_sched, 0, sizeof(sess_sched)); \
+       memset((char *) ad.session, 0, sizeof(ad.session)); \
+}
+    in_st = *dat + *dat_len - r_len;
+    ncksum = des_quad_cksum(in_st, (u_long *) 0, (long) r_len, 0, ad.session);
+    if (ncksum!=ad.checksum) {          /* yow, are we correct yet */
+        clr_cli_secrets();
+       syslog(LOG_ERR, "process_v4_kpasswd: Invalid Checksum");
+        return(1);
+    }
+
+    des_key_sched(ad.session, sess_sched);
+
+    if (retc = (int) krb4_rd_priv(in_st, 
+                           r_len, 
+                           sess_sched, 
+                           ad.session,
+                           &client_server_info.client_name,
+                           &client_server_info.server_name,
+                           &msg_st)) {
+       syslog(LOG_ERR, "process_v4_kpasswd: Bad Read Private Code = %d",
+               retc);
+        clr_cli_secrets();
+        return(1);
+    }
+
+    if (msg_st.app_data[0] != 2) { /* Only Valid Request is CHANGE_PW = 2 */
+       syslog(LOG_ERR, "process_v4_kpasswd: Invalid V4 Request");
+        clr_cli_secrets();
+        return(1);
+    }
+
+    retval = adm_v4_cpw(msg_st.app_data+1,
+                   (int) msg_st.app_length,
+                   &ad,
+                   &retdat, 
+                   &retlen);
+
+    if (retval) {
+       syslog(LOG_ERR, 
+               "process_v4_kpasswd: Password Modification for %s%s%s Failed",
+               ad.pname, (ad.pinst[0] != '\0') ? "/" : "",
+               (ad.pinst[0] != '\0') ? ad.pinst : "");
+    } else {
+       syslog(LOG_ERR, 
+               "process_v4_kpasswd: Password Modification for %s%s%s Complete",
+               ad.pname, (ad.pinst[0] != '\0') ? "/" : "",
+               (ad.pinst[0] != '\0') ? ad.pinst : "");
+    }
+
+    /* Now seal the response back into a priv msg */
+    free((char *)*dat);
+    tmpdat = (u_char *) malloc((unsigned)(retlen + KADM_VERSIZE +
+                                          sizeof(u_long)));
+
+    (void) strncpy((char *) tmpdat, KADM_VERSTR, KADM_VERSIZE);
+
+    retval = htonl((u_long) retval);
+
+    memcpy((char *) tmpdat + KADM_VERSIZE, (char *) &retval, sizeof(u_long));
+
+    if (retlen) {
+        memcpy((char *) tmpdat + KADM_VERSIZE + sizeof(u_long),
+              (char *) retdat, retlen);
+        free((char *) retdat);
+    }
+
+    /* slop for mk_priv stuff */
+    *dat = (u_char *) malloc((unsigned) (retlen + KADM_VERSIZE +
+                                         sizeof(u_long) + 200));
+
+    if ((*dat_len = krb4_mk_priv(tmpdat, *dat,
+                                (u_long) (retlen + KADM_VERSIZE +
+                                          sizeof(u_long)),
+                                sess_sched,
+                                ad.session, 
+                               &client_server_info.server_name,
+                                &client_server_info.client_name)) < 0) {
+        clr_cli_secrets();
+       syslog(LOG_ERR, "process_v4_kpasswd: Bad mk_priv");
+        return(1);
+    }
+
+    dlen = (u_short) *dat_len;
+
+    dlen = htons(dlen);
+
+    if (krb5_net_write(client_server_info.client_socket, 
+                       (char *) &dlen, 2) < 0) {
+       syslog(LOG_ERR, "process_v4_kpasswd: Error writing dlen to client");
+       (void) close(client_server_info.client_socket);
+    }
+    
+    if (krb5_net_write(client_server_info.client_socket, 
+                       (char *) *dat, *dat_len) < 0) {
+       syslog(LOG_ERR, "writing to client: %s",error_message(errno));
+       (void) close(client_server_info.client_socket);
+    }
+
+    free((char *) *dat);
+    clr_cli_secrets();
+    return(0);
+}
+
+krb5_kvno
+princ_exists(principal, entry)
+krb5_principal principal;
+krb5_db_entry *entry;
+{
+    int nprincs = 1;
+    krb5_boolean more;
+    krb5_error_code retval;
+    krb5_kvno vno;
+
+    nprincs = 1;
+    if (retval = krb5_db_get_principal(principal, entry, &nprincs, &more)) {
+        return 0;
+    }
+
+    if (!nprincs)
+            return 0;
+
+    return(nprincs);
+}
+
+/*
+adm_v4_cpw - the server side of the change_password routine
+  recieves    : KTEXT, {key}
+  returns     : CKSUM, RETCODE
+  acl         : caller can change only own password
+
+Replaces the password (i.e. des key) of the caller with that specified in key.
+Returns no actual data from the master server, since this is called by a user
+*/
+int
+adm_v4_cpw(dat, len, ad, datout, outlen)
+u_char *dat;
+int len;
+AUTH_DAT *ad;
+u_char **datout;
+int *outlen;
+{
+    krb5_db_entry entry;
+    krb5_keyblock *v5_keyblock;
+
+    int number_of_principals;
+    krb5_error_code retval;
+    int one = 1;
+    char v5_principal[255];
+
+    C_Block  v4_clear_key;
+    unsigned long keylow, keyhigh;
+    int stvlen;
+       /* Identify the Customer */
+    (void) sprintf(v5_principal, "%s%s%s\0", ad->pname, 
+               (ad->pinst[0] != '\0') ? "/" : "", 
+               (ad->pinst[0] != '\0') ? ad->pinst : "");
+
+    /* take key off the stream, and change the database */
+    if ((stvlen = stv_long(dat, &keyhigh, 0, len)) < 0) {
+       syslog(LOG_ERR, "adm_v4_cpw - (keyhigh) Length Error for stv_long");
+        return(1);
+    }
+    if (stv_long(dat, &keylow, stvlen, len) < 0) {
+       syslog(LOG_ERR, "adm_v4_cpw - (keylow) Length Error for stv_long");
+        return(1);
+    }
+    keylow = ntohl(keylow);
+    keyhigh = ntohl(keyhigh);
+
+                        /* Convert V4 Key to V5 Key */
+    (void) memcpy(v4_clear_key, (char *) &keylow, 4);
+    (void) memcpy(((long *) v4_clear_key) + 1, (char *) &keyhigh, 4);
+
+                        /* Zero Next Output Entry */
+    memset((char *) &entry, 0, sizeof(entry));
+
+    if (retval = krb5_parse_name(v5_principal, &entry.principal)) {
+        syslog(LOG_ERR, "adm_v4_cpw - Error parsing %s",
+                v5_principal);
+        return(1);
+    }
+
+   if (!(number_of_principals = princ_exists(entry.principal, &entry))) {
+        syslog(LOG_ERR, "adm_v4_cpw - principal %s is NOT in the database",
+                v5_principal);
+        return(1);
+    }
+
+                /* Allocate v5_keyblock and fill some fields */
+    if (!(v5_keyblock = (krb5_keyblock *) calloc (1,
+                sizeof(krb5_keyblock)))) {
+        syslog(LOG_ERR, "adm_v4_cpw - Error Allocating krb5_keyblock");
+        return(1);
+    }  
+    v5_keyblock->keytype = KEYTYPE_DES;
+    v5_keyblock->length = 8;
+    if (!(v5_keyblock->contents = (krb5_octet *) calloc (1,
+                8))) {
+        syslog(LOG_ERR, 
+               "adm_v4_cpw - Error Allocating krb5_keyblock->contents\n");
+        free(v5_keyblock);
+        return(1);
+    }
+    memcpy(v5_keyblock->contents, v4_clear_key, 8);
+
+    if (retval = krb5_kdb_encrypt_key(&master_encblock,
+                                  v5_keyblock,
+                                  &entry.key)) {
+       syslog(LOG_ERR, 
+               "adm_v4_cpw - Error %d while encrypting key for '%s'\n", retval,
+                        v5_principal);
+       return(1);
+    }
+    entry.alt_key.length = 0;
+
+               /* Increment Version Number */
+    entry.kvno = entry.kvno + 1;
+#ifdef SANDIA
+    entry.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
+#endif
+    if (retval = krb5_timeofday(&entry.mod_date)) {
+        syslog(LOG_ERR, "adm_v4_cpw - Error while fetching date");
+        return(1);
+    }
+#ifdef SANDIA
+    entry.last_pwd_change = entry.mod_date;
+#endif
+    entry.mod_name = entry.principal; /* Should be Person who did Action */
+
+        /* Write the Modified Principal to the V5 Database */
+    if (retval = krb5_db_put_principal(&entry, &one)) {
+        syslog(LOG_ERR, 
+               "adm_v4_cpw - Error %d while Entering Principal for '%s'", 
+               retval, v5_principal);
+        return(1);
+    }
+
+    *datout = 0;
+    *outlen = 0;
+    return(0);
+}
+
+stv_long(st, dat, loc, maxlen)
+u_char *st;                     /* a base pointer to the stream */
+u_long *dat;                    /* the attributes field */
+int loc;                        /* offset into the stream for current data */
+int maxlen;                     /* maximum length of st */
+{
+    u_long temp = 0;            /* to hold the net order short */
+
+#ifdef BITS64
+    if (loc + 4 > maxlen)
+       return(-1);
+    (void) memcpy((char *) &temp + 4, (char *) ((u_long)st + (u_long)loc), 4);
+    *dat = ntohl(temp);         /* convert to network order */
+    return(4);
+#else
+    if (loc + sizeof(u_long) > maxlen)
+       return(-1);
+    (void) memcpy((char *) &temp, (char *) ((u_long)st + (u_long)loc), 
+               sizeof(u_long));
+    *dat = ntohl(temp);         /* convert to network order */
+    return(sizeof(u_long));
+#endif
+}
diff --git a/src/kadmin/server/kadmind.M b/src/kadmin/server/kadmind.M
new file mode 100644 (file)
index 0000000..e69de29