--- /dev/null
+# $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()
--- /dev/null
+/*
+ * $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
--- /dev/null
+/*
+ * $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 */
--- /dev/null
+/*
+ * $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 *)¬c);
+#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 *)¬c);
+#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 = ¬c;
+ 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);
+}
--- /dev/null
+.\" 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.
--- /dev/null
+/*
+ * $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
--- /dev/null
+/*
+ * $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 */
--- /dev/null
+.\" 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.
--- /dev/null
+/*
+ * $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;
+}
--- /dev/null
+/*
+ * $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 *)<c);
+ (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);
+ }
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+.\" $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.
+
--- /dev/null
+.\" $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.
--- /dev/null
+.\" $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.
--- /dev/null
+# $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()
--- /dev/null
+/*
+ * $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);
+}
--- /dev/null
+/*
+ * $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);
+}
--- /dev/null
+/*
+ * $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);
+}
--- /dev/null
+/*
+ * $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);
+}
+
+
--- /dev/null
+/*
+ * $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);
+}
--- /dev/null
+/*
+ * $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);
+}
--- /dev/null
+/*
+ * $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);
+}
--- /dev/null
+/*
+ * $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);
+}
--- /dev/null
+/*
+ * $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);
+}
--- /dev/null
+/*
+ * $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);
+}
--- /dev/null
+# $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()
--- /dev/null
+/*
+ * $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);
+}
--- /dev/null
+/* 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
--- /dev/null
+# $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()
--- /dev/null
+/*
+ * $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
--- /dev/null
+/*
+ * $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);
+}
--- /dev/null
+/*
+ * $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;
--- /dev/null
+/*
+ * $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__ */
--- /dev/null
+/*
+ * $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);
+}
--- /dev/null
+/*
+ * $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);
+}
--- /dev/null
+/*
+ * $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);
+}
--- /dev/null
+/*
+ * $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);
+}
--- /dev/null
+/*
+ * $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);
+ }
+ }
+}
--- /dev/null
+/*
+ * $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);
+}
+
--- /dev/null
+/*
+ * $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);
+}
--- /dev/null
+#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
--- /dev/null
+/*
+ * $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;
+}
--- /dev/null
+/*
+ * $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);
+}
--- /dev/null
+/*
+ * $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;
--- /dev/null
+
+/*
+ * 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
+}