From: Theodore Tso Date: Tue, 29 Sep 1992 14:51:34 +0000 (+0000) Subject: *** empty log message *** X-Git-Tag: krb5-1.0-beta2~18 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=d4e95b17ce5d033759cb529f0cada608982ef5c8;p=krb5.git *** empty log message *** git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@2444 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/appl/bsd/Imakefile b/src/appl/bsd/Imakefile new file mode 100644 index 000000000..fa3392e7e --- /dev/null +++ b/src/appl/bsd/Imakefile @@ -0,0 +1,70 @@ +# $Source$ +# $Author$ +# $Id$ +# +# Copyright 1990,1991 by the Massachusetts Institute of Technology. +# All Rights Reserved. +# +# Export of this software from the United States of America is assumed +# to require a specific license from the United States Government. +# It is the responsibility of any person or organization contemplating +# export to obtain such a license before exporting. +# +# WITHIN THAT CONSTRAINT, permission to use, copy, modify, and +# distribute this software and its documentation for any purpose and +# without fee is hereby granted, provided that the above copyright +# notice appear in all copies and that both that copyright notice and +# this permission notice appear in supporting documentation, and that +# the name of M.I.T. not be used in advertising or publicity pertaining +# to distribution of the software without specific, written prior +# permission. M.I.T. makes no representations about the suitability of +# this software for any purpose. It is provided "as is" without express +# or implied warranty. +# +# + + DEPLIBS = $(DEPKLIB) +#ifdef CrayArchitecture +LOCAL_LIBRARIES = $(KLIB) -lshare -lm -lrsc +#else +LOCAL_LIBRARIES = $(KLIB) +#endif + DEFINES = $(APPL_BSD_DEF) + +CLIENTSRCS= krcp.c krlogin.c krsh.c kcmd.c logutil.c +CLIENTOBJS= krcp.o krlogin.o krsh.o kcmd.o logutil.o + +#ifdef CrayArchitecture +SERVERSRCS= krshd.c +SERVEROBJS= krshd.o +#else +SERVERSRCS= krlogind.c krshd.c +SERVEROBJS= krlogind.o krshd.o +#endif + +SRCS= $(CLIENTSRCS) $(SERVERSRCS) + +#ifdef CrayArchitecture +all:: rsh rcp rlogin krshd +#else +all:: rsh rcp rlogin krshd krlogind +#endif + +NormalProgramTarget(rsh,krsh.o kcmd.o,$(DEPLIBS),$(LOCAL_LIBRARIES),) +Krb5InstallClientProgram(rsh) + +NormalProgramTarget(rcp,krcp.o kcmd.o,$(DEPLIBS),$(LOCAL_LIBRARIES),) +Krb5InstallClientProgram(rcp) + +NormalProgramTarget(rlogin,krlogin.o kcmd.o,$(DEPLIBS),$(LOCAL_LIBRARIES),) +Krb5InstallClientProgram(rlogin) + +NormalProgramTarget(krshd,krshd.o kcmd.o logutil.o,$(DEPLIBS),$(LOCAL_LIBRARIES),) +Krb5InstallServerProgram(krshd) + +#ifndef CrayArchitecture +NormalProgramTarget(krlogind,krlogind.o logutil.o kcmd.o,$(DEPLIBS),$(LOCAL_LIBRARIES),) +#endif +Krb5InstallServerProgram(krlogind) + +DependTarget() diff --git a/src/appl/bsd/kcmd.c b/src/appl/bsd/kcmd.c new file mode 100644 index 000000000..a7b9f962e --- /dev/null +++ b/src/appl/bsd/kcmd.c @@ -0,0 +1,611 @@ +/* + * $Source$ + * $Id$ + */ + +#ifndef lint +static char *rcsid_kcmd_c = + "$Id$"; +#endif /* lint */ +#define LIBC_SCCS + +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "derived from @(#)rcmd.c 5.17 (Berkeley) 6/27/88"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#include +#include +#ifndef _TYPES_ +#include +#define _TYPES_ +#endif + + +#ifndef MAXPATHLEN +#define MAXPATHLEN 1024 +#endif +#include +#include +#ifndef sigmask +#define sigmask(m) (1 << ((m)-1)) +#endif +#include +#include + +#include +#include + +#include +#include +#include + +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 64 +#endif + +extern errno; + +#define START_PORT 5120 /* arbitrary */ +char *default_service = "host"; + + + +kcmd(sock, ahost, rport, locuser, remuser, cmd, fd2p, service, realm, + cred, seqno, server_seqno, laddr, faddr, authopts) + int *sock; + char **ahost; + u_short rport; + char *locuser, *remuser, *cmd; + int *fd2p; + char *service; + char *realm; + krb5_creds **cred; + krb5_int32 *seqno; + krb5_int32 *server_seqno; + struct sockaddr_in *laddr, *faddr; + krb5_flags authopts; +{ + int s, timo = 1, pid; + long oldmask; + struct sockaddr_in sin, from, local_laddr; + krb5_creds *ret_cred = 0; + char c; + int lport = START_PORT; + struct hostent *hp; + int rc; + char *host_save; + krb5_error_code status; + krb5_error *err_ret; + krb5_ap_rep_enc_part *rep_ret; + krb5_checksum send_cksum; + krb5_principal server, client; + char *tmpstr = 0; + int sin_len; + krb5_ccache cc; + krb5_data outbuf; + + pid = getpid(); + hp = gethostbyname(*ahost); + if (hp == 0) { + fprintf(stderr, "%s: unknown host\n", *ahost); + return (-1); + } + + host_save = malloc(strlen(hp->h_name) + 1); + if ( host_save == (char *) 0){ + fprintf(stderr,"kcmd: no memory\n"); + return(-1); + } + + strcpy(host_save, hp->h_name); + + *ahost = host_save; + + /* If no service is given set to the default service */ + if (!service) service = default_service; + + sin_len = strlen(host_save) + strlen(service) + + (realm ? strlen(realm): 0) + 3; + if ( sin_len < 20 ) sin_len = 20; + tmpstr = malloc(sin_len); + if ( tmpstr == (char *) 0){ + fprintf(stderr,"kcmd: no memory\n"); + return(-1); + } + + if (!(ret_cred = (krb5_creds *)calloc(1,sizeof(*ret_cred)))){ + fprintf(stderr,"kcmd: no memory\n"); + return(-1); + } + if ((realm == NULL) || (realm[0] == '\0')) { + krb5_sname_to_principal(host_save,service,1,&ret_cred->server); + } + else { + sprintf(tmpstr,"%s/%s@%s",service,host_save,realm); + krb5_parse_name(tmpstr,&ret_cred->server); + } +#ifdef sgi + oldmask = sigignore(sigmask(SIGURG)); +#else + oldmask = sigblock(sigmask(SIGURG)); +#endif + + for (;;) { + s = getport(&lport); + if (s < 0) { + if (errno == EAGAIN) + fprintf(stderr, "socket: All ports in use\n"); + else + perror("kcmd: socket"); +#ifndef sgi + sigsetmask(oldmask); +#endif + if (tmpstr) xfree(tmpstr); + if (host_save) xfree(host_save); + krb5_free_creds(ret_cred); + return (-1); + } +#if defined (hpux) || defined (CRAY) /*hpux does not handle async + io thus setown is disabled */ +#else + fcntl(s, F_SETOWN, pid); +#endif /* hpux */ + sin.sin_family = hp->h_addrtype; + memcpy((caddr_t)&sin.sin_addr,hp->h_addr, hp->h_length); + sin.sin_port = rport; + if (connect(s, (struct sockaddr *)&sin, sizeof (sin)) >= 0) + break; + (void) close(s); + if (errno == EADDRINUSE) { + lport--; + continue; + } + /* + * don't wait very long for Kerberos kcmd. + */ + if (errno == ECONNREFUSED && timo <= 4) { + sleep(timo); + timo *= 2; + continue; + } +#if !(defined(tek) || defined(ultrix) || defined(sun) || defined(SYSV)) + if (hp->h_addr_list[1] != NULL) { + int oerrno = errno; + + fprintf(stderr, + "connect to address %s: ", inet_ntoa(sin.sin_addr)); + errno = oerrno; + perror(0); + hp->h_addr_list++; + memcpy((caddr_t)&sin.sin_addr,hp->h_addr_list[0], + hp->h_length); + fprintf(stderr, "Trying %s...\n", + inet_ntoa(sin.sin_addr)); + continue; + } +#endif /* !(defined(ultrix) || defined(sun)) */ + perror(hp->h_name); +#ifndef sgi + sigsetmask(oldmask); +#endif + if (tmpstr) xfree(tmpstr); + if (host_save) xfree(host_save); + krb5_free_creds(ret_cred); + return (-1); + } + lport--; + if (fd2p == 0) { + write(s, "", 1); + lport = 0; + } else { + char num[8]; + int s2 = getport(&lport), s3; + int len = sizeof (from); + + if (s2 < 0) { + status = -1; + goto bad; + } + listen(s2, 1); + (void) sprintf(num, "%d", lport); + if (write(s, num, strlen(num)+1) != strlen(num)+1) { + perror("write: setting up stderr"); + (void) close(s2); + status = -1; + goto bad; + } + s3 = accept(s2, (struct sockaddr *)&from, &len); + (void) close(s2); + if (s3 < 0) { + perror("accept"); + lport = 0; + status = -1; + goto bad; + } + *fd2p = s3; + from.sin_port = ntohs((u_short)from.sin_port); + if (from.sin_family != AF_INET || + from.sin_port >= IPPORT_RESERVED) { + fprintf(stderr, + "socket: protocol failure in circuit setup.\n"); + goto bad2; + } + } + + if (!laddr) laddr = &local_laddr; + if (!faddr) faddr = &sin; + else + memcpy(faddr,&sin,sizeof(sin)); + + sin_len = sizeof (struct sockaddr_in); + if (getsockname(s, (struct sockaddr *)laddr, &sin_len) < 0) { + perror("getsockname"); + status = -1; + goto bad2; + } + + /* compute checksum, using CRC-32 */ + if (!(send_cksum.contents = (krb5_octet *) + malloc(krb5_checksum_size(CKSUMTYPE_CRC32)))) { + status = -1; + goto bad2; + } + /* choose some random stuff to compute checksum from */ + sprintf(tmpstr,"%x %x",pid,pid); + if (status = krb5_calculate_checksum(CKSUMTYPE_CRC32, + tmpstr, + strlen(tmpstr), + 0, + 0, /* if length is 0, crc-32 doesn't + use the seed */ + &send_cksum)) + goto bad3; + + status = krb5_cc_default(&cc); + if (status) goto bad3; + + status = krb5_cc_get_principal(cc, &ret_cred->client); + if (status) goto bad3; + + /* Get ticket from credentials cache or kdc */ + status = krb5_get_credentials(0, cc, ret_cred); + if (status) goto bad3; + + krb5_cc_close(cc); + + /* call Kerberos library routine to obtain an authenticator, + pass it over the socket to the server, and obtain mutual + authentication. */ + status = krb5_sendauth((krb5_pointer) &s, + "KCMDV0.1", ret_cred->client, ret_cred->server, + AP_OPTS_MUTUAL_REQUIRED, + &send_cksum, + ret_cred, + 0, /* We have the credentials */ + seqno, + 0, /* don't need a subsession key */ + 0, /* No error return */ + &rep_ret); + + if (status) goto bad3; + if (rep_ret && server_seqno) { + *server_seqno = rep_ret->seq_number; + krb5_free_ap_rep_enc_part(rep_ret); + } + + outbuf.length = 0; + + /* Send two empty messages. These will be used in a later release + to send a forwarded TGT and related info. */ + if (status = krb5_write_message((krb5_pointer)&s, &outbuf)) + goto bad3; + if (status = krb5_write_message((krb5_pointer)&s, &outbuf)) + goto bad3; + + (void) write(s, remuser, strlen(remuser)+1); + (void) write(s, cmd, strlen(cmd)+1); + (void) write(s, locuser, strlen(locuser)+1); + + if ((rc=read(s, &c, 1)) != 1) { + if (rc==-1) { + perror(*ahost); + } else { + fprintf(stderr,"kcmd: bad connection with remote host\n"); + } + status = -1; + goto bad3; + } + if (c != 0) { + while (read(s, &c, 1) == 1) { + (void) write(2, &c, 1); + if (c == '\n') + break; + } + status = -1; + goto bad3; + } +#ifndef sgi + sigsetmask(oldmask); +#endif + *sock = s; + if (tmpstr) xfree(tmpstr); + if (host_save) xfree(host_save); + + /* Pass back credentials if wanted */ + if (cred) krb5_copy_creds(ret_cred,cred); + krb5_free_creds(ret_cred); + + return (0); + bad3: + free(send_cksum.contents); + bad2: + if (lport) + (void) close(*fd2p); + bad: + (void) close(s); +#ifndef sgi + sigsetmask(oldmask); +#endif + if (tmpstr) xfree(tmpstr); + if (host_save) xfree(host_save); + if (ret_cred) + krb5_free_creds(ret_cred); + return (status); +} + + + +getport(alport) + int *alport; +{ + struct sockaddr_in sin; + int s; + + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = INADDR_ANY; + s = socket(AF_INET, SOCK_STREAM, 0); + if (s < 0) + return (-1); + for (;;) { + sin.sin_port = htons((u_short)*alport); + if (bind(s, (struct sockaddr *)&sin, sizeof (sin)) >= 0) + return (s); + if (errno != EADDRINUSE) { + (void) close(s); + return (-1); + } + (*alport)--; + if (*alport == IPPORT_RESERVED) { + (void) close(s); + errno = EAGAIN; /* close */ + return (-1); + } + } +} + + + +#if defined(sun) +/* The IMP and ultrix do not like multiple defined routines + and since it does not have users with NFS filesystems + mounted, the ruserok on it's OS will work just fine. + However that is not the case with SUNS who's ruserok which + is provided with the OS has problems with it's seteuid + ( which will eventually be traced no doubt to using + setreuid(-1,pgid)). + Therefore we provide a version of ruserok with fixes + the seteuid problem....Drawback - it can only be used + by a root process.*/ + +#ifndef convex +ruserok(rhost, superuser, ruser, luser) + char *rhost; + int superuser; + char *ruser, *luser; +{ + FILE *hostf; + char fhost[MAXHOSTNAMELEN]; + int first = 1; + register char *sp, *p; + int baselen = -1; + int euid = -1; + + sp = rhost; + p = fhost; + while (*sp) { + if (*sp == '.') { + if (baselen == -1) + baselen = sp - rhost; + *p++ = *sp++; + } else { + *p++ = islower(*sp) ? toupper(*sp++) : *sp++; + } + } + *p = '\0'; + hostf = superuser ? (FILE *)0 : fopen("/etc/hosts.equiv", "r"); + again: + if (hostf) { + if (!_validuser(hostf, fhost, luser, ruser, baselen)) { + (void) fclose(hostf); + if (euid != -1) + (void) setreuid ( 0,euid); + return(0); + } + (void) fclose(hostf); + } + if (first == 1) { + struct stat sbuf; + struct passwd *pwd; + char pbuf[MAXPATHLEN]; + + first = 0; + if ((pwd = getpwnam(luser)) == NULL) + return(-1); + /* + * Read .rhosts as the local user to avoid NFS mapping the + * root uid to something that can't read .rhosts. + */ + euid = geteuid(); + if (euid != -1) + (void) setreuid ( 0,pwd->pw_uid); + (void)strcpy(pbuf, pwd->pw_dir); + (void)strcat(pbuf, "/.rhosts"); + if ((hostf = fopen(pbuf, "r")) == NULL){ + if (euid != -1) + (void) setreuid ( 0,euid); + return(-1); + } + (void)fstat(fileno(hostf), &sbuf); + if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid) { + fclose(hostf); + if (euid != -1) + (void) setreuid ( 0,euid); + return(-1); + } + goto again; + } + if (euid != -1) + (void) setreuid ( 0,euid); + return (-1); +} + + + +_validuser(hostf, rhost, luser, ruser, baselen) + char *rhost, *luser, *ruser; + FILE *hostf; + int baselen; +{ + char *user; + char ahost[MAXHOSTNAMELEN]; + register char *p; + + while (fgets(ahost, sizeof (ahost), hostf)) { + p = ahost; + while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') { + *p = islower(*p) ? toupper(*p) : *p; + p++; + } + if (*p == ' ' || *p == '\t') { + *p++ = '\0'; + while (*p == ' ' || *p == '\t') + p++; + user = p; + while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') + p++; + } else + user = p; + *p = '\0'; + if (_checkhost(rhost, ahost, baselen) && + !strcmp(ruser, *user ? user : luser)) { + return (0); + } + } + return (-1); +} +#endif /* convex */ + + + +_checkhost(rhost, lhost, len) + char *rhost, *lhost; + int len; +{ + static char ldomain[MAXHOSTNAMELEN + 1]; + static char *domainp = NULL; + static int nodomain = 0; + register char *cp; + + if (len == -1) + return(!strcmp(rhost, lhost)); + if (strncmp(rhost, lhost, len)) + return(0); + if (!strcmp(rhost, lhost)) + return(1); + if (*(lhost + len) != '\0') + return(0); + if (nodomain) + return(0); + if (!domainp) { + if (gethostname(ldomain, sizeof(ldomain)) == -1) { + nodomain = 1; + return(0); + } + ldomain[MAXHOSTNAMELEN] = NULL; + if ((domainp = index(ldomain, '.')) == (char *)NULL) { + nodomain = 1; + return(0); + } + for (cp = ++domainp; *cp; ++cp) + if (islower(*cp)) + *cp = toupper(*cp); + } + return(!strcmp(domainp, rhost + len +1)); + +} +#endif /* ! sysvimp */ + + + +#if defined (hpux) +int setreuid(real,eff) + int real,eff; +{ + int tmpint = -1; + return(setresuid(real,eff,tmpint)); +} +#endif + + + +/* Strsave was a routine in the version 4 krb library: we put it here + for compatablilty with version 5 krb library, since kcmd.o is linked + into all programs. */ + +char * + strsave(sp) +char *sp; +{ + register char *ret; + + if((ret = malloc((unsigned) strlen(sp)+1)) == NULL) { + fprintf(stderr, "no memory for saving args\n"); + exit(1); + } + (void) strcpy(ret,sp); + return(ret); +} + + + +#ifdef SYSV + +int killpg(pid,sig) + int pid,sig; +{ + + if ( pid >= 0) + pid *= -1; + return(kill(pid,sig)); +} + +#endif diff --git a/src/appl/bsd/krcp.c b/src/appl/bsd/krcp.c new file mode 100644 index 000000000..a6ecf15d5 --- /dev/null +++ b/src/appl/bsd/krcp.c @@ -0,0 +1,1420 @@ +/* + * $Source$ + * $Header$ + */ + +#ifndef lint +static char *rcsid_rcp_c = "$Header$"; +#endif /* lint */ + +/* + * Copyright (c) 1983 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +char copyright[] = + "@(#) Copyright (c) 1983 The Regents of the University of California.\n\ + All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)rcp.c 5.10 (Berkeley) 9/20/88"; +#endif /* not lint */ + +#define KERBEROS + + /* + * rcp + */ +#include +#ifndef _TYPES_ +#include +#define _TYPES_ +#endif +#include +#ifdef CRAY +#include +#endif +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#ifdef KERBEROS +#include +#include +#include +#include +#include + +#include + +#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 +#else +#ifdef sysvimp +#include +#else +#include +#endif +#endif + +rsource(name, statp) + char *name; + struct stat *statp; +{ + DIR *d = opendir(name); + char *last; +#if defined(SYSV) && !defined(sysvimp) + struct dirent *dp; +#else + struct direct *dp; +#endif + char buf[BUFSIZ]; + char *bufv[1]; + + if (d == 0) { + error("rcp: %s: %s\n", name, sys_errlist[errno]); + return; + } + last = rindex(name, '/'); + if (last == 0) + last = name; + else + last++; + if (pflag) { + (void) sprintf(buf, "T%ld 0 %ld 0\n", + statp->st_mtime, statp->st_atime); + (void) des_write(rem, buf, strlen(buf)); + if (response() < 0) { + closedir(d); + return; + } + } + (void) sprintf(buf, "D%04o %d %s\n", statp->st_mode&07777, 0, last); + (void) des_write(rem, buf, strlen(buf)); + if (response() < 0) { + closedir(d); + return; + } + while (dp = readdir(d)) { + if (dp->d_ino == 0) + continue; + if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) + continue; + if (strlen(name) + 1 + strlen(dp->d_name) >= BUFSIZ - 1) { + error("%s/%s: Name too long.\n", name, dp->d_name); + continue; + } + (void) sprintf(buf, "%s/%s", name, dp->d_name); + bufv[0] = buf; + source(1, bufv); + } + closedir(d); + (void) des_write(rem, "E\n", 2); + (void) response(); +} + + + +response() +{ + char resp, c, rbuf[BUFSIZ], *cp = rbuf; + if (des_read(rem, &resp, 1) != 1) + lostconn(); + switch (resp) { + + case 0: /* ok */ + return (0); + + default: + *cp++ = resp; + /* fall into... */ + case 1: /* error, followed by err msg */ + case 2: /* fatal error, "" */ + do { + if (des_read(rem, &c, 1) != 1) + lostconn(); + *cp++ = c; + } while (cp < &rbuf[BUFSIZ] && c != '\n'); + if (iamremote == 0) + (void) write(2, rbuf, cp - rbuf); + errs++; + if (resp == 1) + return (-1); + exit(1); + } + /*NOTREACHED*/ +} + + + +krb5_sigtype + lostconn() +{ + if (iamremote == 0) + fprintf(stderr, "rcp: lost connection\n"); + exit(1); +} + + + +sink(argc, argv) + int argc; + char **argv; +{ + off_t i, j; + char *targ, *whopp, *cp; + int of, mode, wrerr, exists, first, count, amt, size; + struct buffer *bp; + static struct buffer buffer; + struct stat stb; + int targisdir = 0; + int mask = umask(0); + char *myargv[1]; + char cmdbuf[BUFSIZ], nambuf[BUFSIZ]; + int setimes = 0; + struct timeval tv[2]; +#define atime tv[0] +#define mtime tv[1] +#define SCREWUP(str) { whopp = str; goto screwup; } + + if (!pflag) + (void) umask(mask); + if (argc != 1) { + error("rcp: ambiguous target\n"); + exit(1); + } + targ = *argv; + if (targetshouldbedirectory) + verifydir(targ); + ga(); + if (stat(targ, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR) + targisdir = 1; + for (first = 1; ; first = 0) { + cp = cmdbuf; + if (des_read(rem, cp, 1) <= 0) + return; + if (*cp++ == '\n') + SCREWUP("unexpected '\\n'"); + do { + if (des_read(rem, cp, 1) != 1) + SCREWUP("lost connection"); + } while (*cp++ != '\n'); + *cp = 0; + if (cmdbuf[0] == '\01' || cmdbuf[0] == '\02') { + if (iamremote == 0) + (void) write(2, cmdbuf+1, strlen(cmdbuf+1)); + if (cmdbuf[0] == '\02') + exit(1); + errs++; + continue; + } + *--cp = 0; + cp = cmdbuf; + if (*cp == 'E') { + ga(); + return; + } + +#define getnum(t) (t) = 0; while (isdigit(*cp)) (t) = (t) * 10 + (*cp++ - '0'); + if (*cp == 'T') { + setimes++; + cp++; + getnum(mtime.tv_sec); + if (*cp++ != ' ') + SCREWUP("mtime.sec not delimited"); + getnum(mtime.tv_usec); + if (*cp++ != ' ') + SCREWUP("mtime.usec not delimited"); + getnum(atime.tv_sec); + if (*cp++ != ' ') + SCREWUP("atime.sec not delimited"); + getnum(atime.tv_usec); + if (*cp++ != '\0') + SCREWUP("atime.usec not delimited"); + ga(); + continue; + } + if (*cp != 'C' && *cp != 'D') { + /* + * Check for the case "rcp remote:foo\* local:bar". + * In this case, the line "No match." can be returned + * by the shell before the rcp command on the remote is + * executed so the ^Aerror_message convention isn't + * followed. + */ + if (first) { + error("%s\n", cp); + exit(1); + } + SCREWUP("expected control record"); + } + cp++; + mode = 0; + for (; cp < cmdbuf+5; cp++) { + if (*cp < '0' || *cp > '7') + SCREWUP("bad mode"); + mode = (mode << 3) | (*cp - '0'); + } + if (*cp++ != ' ') + SCREWUP("mode not delimited"); + size = 0; + while (isdigit(*cp)) + size = size * 10 + (*cp++ - '0'); + if (*cp++ != ' ') + SCREWUP("size not delimited"); + if (targisdir) + (void) sprintf(nambuf, "%s%s%s", targ, + *targ ? "/" : "", cp); + else + (void) strcpy(nambuf, targ); + exists = stat(nambuf, &stb) == 0; + if (cmdbuf[0] == 'D') { + if (exists) { + if ((stb.st_mode&S_IFMT) != S_IFDIR) { + errno = ENOTDIR; + goto bad; + } + if (pflag) + (void) chmod(nambuf, mode); + } else if (mkdir(nambuf, mode) < 0) + goto bad; + myargv[0] = nambuf; + sink(1, myargv); + if (setimes) { + setimes = 0; + if (utimes(nambuf, tv) < 0) + error("rcp: can't set times on %s: %s\n", + nambuf, sys_errlist[errno]); + } + continue; + } + if ((of = open(nambuf, O_WRONLY|O_CREAT, mode)) < 0) { + bad: + error("rcp: %s: %s\n", nambuf, sys_errlist[errno]); + continue; + } + if (exists && pflag) +#ifdef NOFCHMOD + (void) chmod(nambuf, mode); +#else + (void) fchmod(of, mode); +#endif + ga(); + if ((bp = allocbuf(&buffer, of, BUFSIZ)) == NULLBUF) { + (void) close(of); + continue; + } + cp = bp->buf; + count = 0; + wrerr = 0; + for (i = 0; i < size; i += BUFSIZ) { + amt = BUFSIZ; + if (i + amt > size) + amt = size - i; + count += amt; + do { + j = des_read(rem, cp, amt); + if (j <= 0) { + if (j == 0) + error("rcp: dropped connection"); + else + error("rcp: %s\n", + sys_errlist[errno]); + exit(1); + } + amt -= j; + cp += j; + } while (amt > 0); + if (count == bp->cnt) { + if (wrerr == 0 && + write(of, bp->buf, count) != count) + wrerr++; + count = 0; + cp = bp->buf; + } + } + if (count != 0 && wrerr == 0 && + write(of, bp->buf, count) != count) + wrerr++; + if (ftruncate(of, size)) + error("rcp: can't truncate %s: %s\n", + nambuf, sys_errlist[errno]); + (void) close(of); + (void) response(); + if (setimes) { + setimes = 0; + if (utimes(nambuf, tv) < 0) + error("rcp: can't set times on %s: %s\n", + nambuf, sys_errlist[errno]); + } + if (wrerr) + error("rcp: %s: %s\n", nambuf, sys_errlist[errno]); + else + ga(); + } + screwup: + error("rcp: protocol screwup: %s\n", whopp); + exit(1); +} + + + +struct buffer *allocbuf(bp, fd, blksize) + struct buffer *bp; + int fd, blksize; +{ + struct stat stb; + int size; + + if (fstat(fd, &stb) < 0) { + error("rcp: fstat: %s\n", sys_errlist[errno]); + return (NULLBUF); + } +#ifdef NOROUNDUP + size = 0; +#else + size = roundup(stb.st_blksize, blksize); +#endif + if (size == 0) + size = blksize; + if (bp->cnt < size) { + if (bp->buf != 0) + free(bp->buf); + bp->buf = (char *)malloc((unsigned) size); + if (bp->buf == 0) { + error("rcp: malloc: out of memory\n"); + return (NULLBUF); + } + } + bp->cnt = size; + return (bp); +} + + + +/*VARARGS1*/ +error(fmt, a1, a2, a3, a4, a5) + char *fmt; + int a1, a2, a3, a4, a5; +{ + char buf[BUFSIZ], *cp = buf; + + errs++; + *cp++ = 1; + (void) sprintf(cp, fmt, a1, a2, a3, a4, a5); + (void) des_write(rem, buf, strlen(buf)); + if (iamremote == 0) + (void) write(2, buf+1, strlen(buf+1)); +} + + + +usage() +{ +#ifdef KERBEROS + fprintf(stderr, + "Usage: \trcp [-p] [-x] [-k realm] f1 f2; or:\n\trcp [-r] [-p] [-x] [-k realm] f1 ... fn d2\n"); +#else /* !KERBEROS */ + fputs("usage: rcp [-p] f1 f2; or: rcp [-rp] f1 ... fn d2\n", stderr); +#endif + exit(1); +} + + + +hosteq(h1, h2) + char *h1, *h2; +{ + struct hostent *h_ptr; + char hname1[256]; + + /* get the official names for the two hosts */ + + if ((h_ptr = gethostbyname(h1)) == NULL) + return(0); + strcpy(hname1, h_ptr->h_name); + if ((h_ptr = gethostbyname(h2)) == NULL) + return(0); + + /*return if they are equal (strcmp returns 0 for equal - I return 1) */ + + return(!strcmp(hname1, h_ptr->h_name)); +} + + + +#ifdef KERBEROS +void try_normal(argv) + char **argv; +{ + register int i; + + if (!encryptflag) { + fprintf(stderr,"trying normal rcp (%s)\n", UCB_RCP); + fflush(stderr); + /* close all but stdin, stdout, stderr */ + for (i = getdtablesize(); i > 2; i--) + (void) close(i); + execv(UCB_RCP, argv); + perror("exec"); + } + exit(1); +} + + + +char **save_argv(argc, argv) + int argc; + char **argv; +{ + register int i; + + char **local_argv = (char **)calloc((unsigned) argc+1, + (unsigned) sizeof(char *)); + /* allocate an extra pointer, so that it is initialized to NULL + and execv() will work */ + for (i = 0; i < argc; i++) + local_argv[i] = strsave(argv[i]); + return(local_argv); +} + + + +#ifdef unicos61 +#define SIZEOF_INADDR SIZEOF_in_addr +#else +#define SIZEOF_INADDR sizeof(struct in_addr) +#endif + +krb5_error_code tgt_keyproc(DECLARG(krb5_pointer, keyprocarg), + DECLARG(krb5_principal, principal), + DECLARG(krb5_kvno, vno), + DECLARG(krb5_keyblock **, key)) + OLDDECLARG(krb5_pointer, keyprocarg) + OLDDECLARG(krb5_principal, principal) + OLDDECLARG(krb5_kvno, vno) + OLDDECLARG(krb5_keyblock **, key) +{ + krb5_creds *creds = (krb5_creds *)keyprocarg; + + return krb5_copy_keyblock(&creds->keyblock, key); +} + + + +void send_auth() +{ + int sin_len; + char *princ; /* principal in credentials cache */ + krb5_ccache cc; + krb5_creds creds; + krb5_principal sprinc; /* principal of server */ + krb5_data reply, msg, princ_data; + krb5_tkt_authent *authdat; + krb5_error_code status; + krb5_address faddr; + + + + if (status = krb5_cc_default(&cc)){ + fprintf(stderr,"rcp: send_auth failed krb5_cc_default : %s\n", + error_message(status)); + exit(1); + } + + memset ((char*)&creds, 0, sizeof(creds)); + + if (status = krb5_cc_get_principal(cc, &creds.client)){ + fprintf(stderr, + "rcp: send_auth failed krb5_cc_get_principal : %s\n", + error_message(status)); + krb5_cc_close(cc); + exit(1); + } + + if (status = krb5_unparse_name(creds.client, &princ)){ + fprintf(stderr,"rcp: send_auth failed krb5_parse_name : %s\n", + error_message(status)); + krb5_cc_close(cc); + exit(1); + } + if (status = krb5_build_principal_ext(&sprinc, + krb5_princ_realm(creds.client)->length, + krb5_princ_realm(creds.client)->data, + 6, "krbtgt", + krb5_princ_realm(creds.client)->length, + krb5_princ_realm(creds.client)->data, + 0)){ + fprintf(stderr, + "rcp: send_auth failed krb5_build_principal_ext : %s\n", + error_message(status)); + krb5_cc_close(cc); + exit(1); + } + + creds.server = sprinc; + + /* Get TGT from credentials cache */ + if (status = krb5_get_credentials(KRB5_GC_CACHED, cc, &creds)){ + fprintf(stderr, + "rcp: send_auth failed krb5_get_credentials: %s\n", + error_message(status)); + krb5_cc_close(cc); + exit(1); + } + krb5_cc_close(cc); + + krb5_free_principal(sprinc); /* creds.server is replaced + upon retrieval */ + + + princ_data.data = princ; + princ_data.length = strlen(princ_data.data) + 1; /* include null + terminator for + server's convenience */ + status = krb5_write_message((krb5_pointer) &rem, &princ_data); + if (status){ + fprintf(stderr, + "rcp: send_auth failed krb5_write_message: %s\n", + error_message(status)); + exit(1); + } + xfree(princ); + status = krb5_write_message((krb5_pointer) &rem, &creds.ticket); + if (status){ + fprintf(stderr, + "rcp: send_auth failed krb5_write_message: %s\n", + error_message(status)); + exit(1); + } + + status = krb5_read_message((krb5_pointer) &rem, &reply); + if (status){ + fprintf(stderr, + "rcp: send_auth failed krb5_read_message: %s\n", + error_message(status)); + exit(1); + } + + sin_len = SIZEOF_INADDR; + faddr.addrtype = foreign.sin_family; + faddr.length = SIZEOF_INADDR; + faddr.contents = (krb5_octet *) &foreign.sin_addr; + + /* read the ap_req to get the session key */ + status = krb5_rd_req(&reply, + 0, /* don't know server's name... */ + &faddr, + 0, /* no fetchfrom */ + tgt_keyproc, + (krb5_pointer)&creds, /* credentials as arg to + keyproc */ + 0, /* no rcache for the moment XXX */ + &authdat); + xfree(reply.data); + if (status) { + fprintf(stderr, "rcp: send_auth failed krb5_rd_req: %s\n", + error_message(status)); + exit(1); + } + + krb5_copy_keyblock(authdat->ticket->enc_part2->session,&session_key); + krb5_free_tkt_authent(authdat); + krb5_free_cred_contents(&creds); + + krb5_use_keytype(&eblock, session_key->keytype); + if ( status = krb5_process_key(&eblock, + session_key)){ + fprintf(stderr, "rcp: send_auth failed krb5_process_key: %s\n", + error_message(status)); + exit(1); + } + +} + + + +void + answer_auth() +{ + krb5_data pname_data, msg; + krb5_creds creds; + krb5_ccache cc; + krb5_error_code status; + extern krb5_flags krb5_kdc_default_options; + + + memset ((char*)&creds, 0, sizeof(creds)); + + if (status = krb5_read_message((krb5_pointer) &rem, &pname_data)) { + exit(1); + } + + if (status = krb5_read_message((krb5_pointer) &rem, + &creds.second_ticket)) { + exit(1); + } + + if (status = krb5_cc_default(&cc)){ + exit(1); + } + + if (status = krb5_cc_get_principal(cc, &creds.client)){ + krb5_cc_destroy(cc); + krb5_cc_close(cc); + exit(1); + } + + if (status = krb5_parse_name(pname_data.data, &creds.server)){ + krb5_cc_destroy(cc); + krb5_cc_close(cc); + exit(1); + } + xfree(pname_data.data); + + if (status = krb5_get_credentials(KRB5_GC_USER_USER, cc, &creds)){ + krb5_cc_destroy(cc); + krb5_cc_close(cc); + exit(1); + } + + if (status = krb5_mk_req_extended(AP_OPTS_USE_SESSION_KEY, + 0, /* no application checksum here */ + krb5_kdc_default_options, + 0, + 0, /* no need for subkey */ + cc, + &creds, + 0, /* don't need authenticator copy */ + &msg)) { + krb5_cc_destroy(cc); + krb5_cc_close(cc); + exit(1); + } + krb5_cc_destroy(cc); + krb5_cc_close(cc); + status = krb5_write_message((krb5_pointer) &rem, &msg); + xfree(msg.data); + if (status){ + exit(1); + } + + /* setup eblock for des_read and write */ + krb5_copy_keyblock(&creds.keyblock,&session_key); + + /* cleanup */ + krb5_free_cred_contents(&creds); + + /* OK process key */ + krb5_use_keytype(&eblock, session_key->keytype); + if ( status = krb5_process_key(&eblock,session_key)) { + exit(1); + } + + return; +} + + + +char storage[2*BUFSIZ]; /* storage for the decryption */ +int nstored = 0; +char *store_ptr = storage; + +int des_read(fd, buf, len) + int fd; + register char *buf; + int len; +{ + int nreturned = 0; + long net_len,rd_len; + int cc; + krb5_error_code status; + + if (!encryptflag) + return(read(fd, buf, len)); + + if (nstored >= len) { + memcpy(buf, store_ptr, len); + store_ptr += len; + nstored -= len; + return(len); + } else if (nstored) { + memcpy(buf, store_ptr, nstored); + nreturned += nstored; + buf += nstored; + len -= nstored; + nstored = 0; + } + +#ifdef BITS64 + /* + * XXX Ick; this assumes a big-endian word order.... + */ + rd_len = 0; + if ((cc = krb5_net_read(fd, (char *)&rd_len + 4, 4)) != 4) { +#else + if ((cc = krb5_net_read(fd, (char *)&rd_len, sizeof(rd_len))) != + sizeof(rd_len)) { +#endif + /* XXX can't read enough, pipe + must have closed */ + return(0); + } + rd_len = ntohl(rd_len); + net_len = krb5_encrypt_size(rd_len,eblock.crypto_entry); + if (net_len <= 0 || net_len > sizeof(des_inbuf)) { + /* preposterous length; assume out-of-sync; only + recourse is to close connection, so return 0 */ + error( "rcp: Des_read size problem net_len %d rd_len %d %d.\n", + net_len,rd_len, len); + errno = E2BIG; + return(-1); + } + if ((cc = krb5_net_read(fd, desinbuf.data, net_len)) != net_len) { + /* pipe must have closed, return 0 */ + error( "rcp: Des_read error: length received %d != expected %d.\n", + cc,net_len); + return(0); + } + /* decrypt info */ + if ((status = krb5_decrypt(desinbuf.data, + (krb5_pointer) storage, + net_len, + &eblock, 0))) { + error("rcp: Des_read cannot decrypt data from network %s.\n", + error_message(status)); + return(0); + } + store_ptr = storage; + nstored = rd_len; + if (nstored > len) { + memcpy(buf, store_ptr, len); + nreturned += len; + store_ptr += len; + nstored -= len; + } else { + memcpy(buf, store_ptr, nstored); + nreturned += nstored; + nstored = 0; + } + + return(nreturned); +} + + + +int des_write(fd, buf, len) + int fd; + char *buf; + int len; +{ + long net_len; + + if (!encryptflag) + return(write(fd, buf, len)); + + desoutbuf.length = krb5_encrypt_size(len,eblock.crypto_entry); + if (desoutbuf.length > sizeof(des_outbuf)){ + return(-1); + } + if (( krb5_encrypt((krb5_pointer)buf, + desoutbuf.data, + len, + &eblock, + 0))){ + return(-1); + } + + net_len = htonl(len); +#ifdef BITS64 + (void) write(fd,(char *)&net_len + 4, 4); +#else + (void) write(fd, &net_len, sizeof(net_len)); +#endif + if (write(fd, desoutbuf.data,desoutbuf.length) != desoutbuf.length){ + return(-1); + } + else return(len); +} + +#endif /* KERBEROS */ diff --git a/src/appl/bsd/krlogin.c b/src/appl/bsd/krlogin.c new file mode 100644 index 000000000..8191f5798 --- /dev/null +++ b/src/appl/bsd/krlogin.c @@ -0,0 +1,1468 @@ +/* + * $Source$! * $Author$ + * $Header$ + */ +#ifndef lint +static char rcsid_rlogin_c[] = "$Header$"; +#endif /* lint */ + +/* + * Copyright (c) 1983 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +char copyright[] = + "@(#) Copyright (c) 1983 The Regents of the University of California.\n\ + All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)rlogin.c 5.12 (Berkeley) 9/19/88"; +#endif /* not lint */ + +#define KERBEROS + + /* + * rlogin - remote login + */ + +#include +#include +#ifndef _TYPES +#include +#define _TYPES_ +#endif +#include +#include +#include +#include +#include + +#include + +#include + +#ifdef SYSV +#ifndef USE_TERMIO +#define USE_TERMIO +#endif +#endif + +#ifdef USE_TERMIO +#ifdef CRAY +#include +#endif +#include +#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 +#endif /* USE_TERMIO */ + +#include +#include +#include +#include +#include + +#ifdef KERBEROS +#include +#include +#include +#include +#include + +#include + +#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 +#include +#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); +} diff --git a/src/appl/bsd/krlogind.M b/src/appl/bsd/krlogind.M new file mode 100644 index 000000000..4ceebd773 --- /dev/null +++ b/src/appl/bsd/krlogind.M @@ -0,0 +1,102 @@ +.\" Copyright (c) 1983 Regents of the University of California. +.\" All rights reserved. The Berkeley software License Agreement +.\" specifies the terms and conditions for redistribution. +.\" +.\" @(#)rlogind.8c 6.3 (Berkeley) 5/24/86 +.\" +.TH RLOGIND 8C "May 24, 1986" +.UC 5 +.SH NAME +rlogind \- remote login server +.SH SYNOPSIS +.B /etc/rlogind +[ +.B \-d +] +.SH DESCRIPTION +.I Rlogind +is the server for the +.IR rlogin (1C) +program. The server provides a remote login facility +with authentication based on privileged port numbers from trusted hosts. +.PP +.I Rlogind +listens for service requests at the port indicated in +the ``login'' service specification; see +.IR services (5). +When a service request is received the following protocol +is initiated: +.IP 1) +The server checks the client's source port. +If the port is not in the range 0-1023, the server +aborts the connection. +.IP 2) +The server checks the client's source address +and requests the corresponding host name (see +.IR gethostbyaddr (3N), +.IR hosts (5) +and +.IR named (8)). +If the hostname cannot be determined, +the dot-notation representation of the host address is used. +.PP +Once the source port and address have been checked, +.I rlogind +allocates a pseudo terminal (see +.IR pty (4)), +and manipulates file descriptors so that the slave +half of the pseudo terminal becomes the +.B stdin , +.B stdout , +and +.B stderr +for a login process. +The login process is an instance of the +.IR login (1) +program, invoked with the +.B \-r +option. The login process then proceeds with the authentication +process as described in +.IR rshd (8C), +but if automatic authentication fails, it reprompts the user +to login as one finds on a standard terminal line. +.PP +The parent of the login process manipulates the master side of +the pseduo terminal, operating as an intermediary +between the login process and the client instance of the +.I rlogin +program. In normal operation, the packet protocol described +in +.IR pty (4) +is invoked to provide ^S/^Q type facilities and propagate +interrupt signals to the remote programs. The login process +propagates the client terminal's baud rate and terminal type, +as found in the environment variable, ``TERM''; see +.IR environ (7). +The screen or window size of the terminal is requested from the client, +and window size changes from the client are propagated to the pseudo terminal. +.SH DIAGNOSTICS +All diagnostic messages are returned on the connection +associated with the +.BR stderr , +after which any network connections are closed. +An error is indicated by a leading byte with a value of 1. +.PP +.B ``Try again.'' +.br +A +.I fork +by the server failed. +.PP +.B ``/bin/sh: ...'' +.br +The user's login shell could not be started. +.SH BUGS +The authentication procedure used here assumes the integrity +of each client machine and the connecting medium. This is +insecure, but is useful in an ``open'' environment. +.PP +A facility to allow all data exchanges to be encrypted should be +present. +.PP +A more extensible protocol should be used. diff --git a/src/appl/bsd/krlogind.c b/src/appl/bsd/krlogind.c new file mode 100644 index 000000000..9360b6fef --- /dev/null +++ b/src/appl/bsd/krlogind.c @@ -0,0 +1,1365 @@ +/* + * $Source$ + * $Header$ + */ + + +#ifndef lint +static char *rcsid_rlogind_c = "$Header$"; +#endif /* lint */ + +/* + * Copyright (c) 1983 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +char copyright[] = + "@(#) Copyright (c) 1983 The Regents of the University of California.\n\ + All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)rlogind.c 5.17 (Berkeley) 8/31/88"; +#endif /* not lint */ + + /* + * remote login server: + * remuser\0 + * locuser\0 + * terminal info\0 + * data + */ + + /* + * This is the rlogin daemon. The very basic protocol for checking + * authentication and authorization is: + * 1) Check authentication. + * 2) Check authorization via the access-control files: + * ~/.k5login (using krb5_kuserok) and/or + * ~/.rhosts (using ruserok). + * 3) Prompt for password if any checks fail, or if so configured. + * Allow login if all goes well either by calling the accompanying login.krb + * or /bin/login, according to the definition of DO_NOT_USE_K_LOGIN. + * + * The configuration is done either by command-line arguments passed by inetd, + * or by the name of the daemon. If command-line arguments are present, they + * take priority. The options are: + * -k and -K means check .k5login (using krb5_kuserok). + * -r and -R means check .rhosts (using ruserok). + * -p and -P means prompt for password. + * The difference between upper and lower case is as follows: + * If lower case -r or -k, then as long as one of krb5_kuserok or ruserok + * passes, allow login without password. If the -p option is passed with -r + * or -k, then if both checks fail, allow login but only after password + * verification. + * If uppercase -R or -K, then those checks must be passed, regardless of + * other checks, else no login with or without password. + * If the -P option is passed, then the password is verified in + * addition to all other checks. If -p is not passed with -k or -r, and both + * checks fail, then login permission is denied. + * -x and -e means use encryption. + * If no command-line arguments are present, then the presence of the + * letters kKrRexpP in the program-name before "logind" determine the + * behaviour of the program exactly as with the command-line arguments. + * + * If the ruserok check is to be used, then the client should connect from a + * privileged port, else deny permission. + */ + + /* DEFINES: + * KERBEROS - Define this if application is to be kerberised. + * CRYPT - Define this if encryption is to be an option. + * DO_NOT_USE_K_LOGIN - Define this if you want to use /bin/login instead + * of the accompanying login.krb. In that case, the remote user's + * name must be present in the local .rhosts file, regardless of + * any options specified. + * LOG_ALL_LOGINS - Define this if you want to log all logins. + * LOG_OTHER_USERS - Define this if you want to log all principals that do + * not map onto the local user. + * LOG_REMOTE_REALM - Define this if you want to log all principals from + * remote realms. + * Note: Root logins are always logged. + */ + +#define LOG_REMOTE_REALM +#define KERBEROS + +#include +#include +#include +#include +#include +#include +/* #include ??? What system has a sys/unistd.h? */ + +#include +#include +#include + +#ifdef sun +#include +#include +#include +#endif + +#include +#ifdef hpux +#include +#endif + +#ifdef sysvimp +#include +#define STREAMS +#include +#endif + +#ifdef SYSV +#define USE_TERMIO +#endif + +#ifdef USE_TERMIO +#include +#else +#include +#endif /* USE_TERMIO */ + +#include +#include +#include +#include +#include + +#ifdef NO_WINSIZE +struct winsize { + unsigned short ws_row, ws_col; + unsigned short ws_xpixel, ws_ypixel; +}; +#endif /* NO_WINSIZE */ + +#ifdef KERBEROS + +#include +#include +#include +#include +#include + +#include + +#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<= 0) + if (pcc) + obits |= (1< 0) + memcpy(cp, + cp+n, + left); + fcc -= n; + goto top; /* n^2 */ + } + } + } + } + + if ((obits & (1< 0) { + cc = write(p, fbp, fcc); + if (cc > 0) { + fcc -= cc; + fbp += cc; + } + } + + if (ibits & (1< 0) { + cc = des_write(f, pbp, pcc); + if (cc < 0 && errno == EWOULDBLOCK) { + /* also shouldn't happen */ + sleep(5); + continue; + } + if (cc > 0) { + pcc -= cc; + pbp += cc; + } + } + } +} + + + +int cleanup() +{ + char *p; + + /* + I dont know why P starts with the character '/', but apparently it + has to do with the way login set line when the initial entry for this + line is made. + */ + p = line + sizeof("/dev/") -1 ; + if (!logout(p)) { +#ifdef SYSV + logwtmp(p, "", "", 0, 0); +#else + logwtmp(p, "", "", 0); +#endif + } + else + syslog(LOG_ERR , + "Cannot delete entry from utmp for %s\n",p); + + (void)chmod(line, 0666); + (void)chown(line, 0, 0); +#ifndef STREAMS + *p = 'p'; + (void)chmod(line, 0666); + (void)chown(line, 0, 0); +#endif + shutdown(netf, 2); + exit(1); +} + + +void fatal(f, msg) + int f; + char *msg; +{ + char buf[512]; + int out = 1 ; /* Output queue of f */ + + buf[0] = '\01'; /* error indicator */ + (void) sprintf(buf + 1, "%s: %s.\r\n",progname, msg); + if ((f == netf) && (pid > 0)) + (void) des_write(f, buf, strlen(buf)); + else + (void) write(f, buf, strlen(buf)); + syslog(LOG_ERR,"%s\n",msg); + if (pid > 0) { + signal(SIGCHLD,SIG_IGN); + kill(pid,SIGKILL); +#ifdef TIOCFLUSH + (void) ioctl(f, TIOCFLUSH, (char *)&out); +#else + (void) ioctl(f, TCFLSH, out); +#endif + cleanup(); + } + exit(1); +} + + + +void fatalperror(f, msg) + int f; + char *msg; +{ + char buf[512]; + extern int sys_nerr; + extern char *sys_errlist[]; + + if ((unsigned)errno < sys_nerr) + (void) sprintf(buf, "%s: %s", msg, sys_errlist[errno]); + else + (void) sprintf(buf, "%s: Error %d", msg, errno); + fatal(f, buf); +} + +#ifdef KERBEROS + + +do_krb_login(host) + char *host; +{ + int rc; + krb5_error_code status; + struct sockaddr_in peersin; + krb5_address peeraddr; + struct passwd *pwd; + krb5_principal server; + char srv_name[100]; + char def_host[100]; + krb5_data inbuf; + + if (getuid()) { + exit(1); + } + + /* we want mutual authentication */ +#ifdef unicos61 +#define SIZEOF_INADDR SIZEOF_in_addr +#else +#define SIZEOF_INADDR sizeof(struct in_addr) +#endif + + rc = sizeof(peersin); + if (getpeername(netf, (struct sockaddr *)&peersin, &rc)) { + syslog(LOG_ERR, "get peer name failed %d", netf); + exit(1); + } + + peeraddr.addrtype = peersin.sin_family; + peeraddr.length = SIZEOF_INADDR; + peeraddr.contents = (krb5_octet *)&peersin.sin_addr; + + strcpy(srv_name, "host/"); + gethostname(def_host, 100); + strcat(srv_name, def_host); + if (status = krb5_parse_name(srv_name, &server)) { + syslog(LOG_ERR, "parse server name %s: %s", "host", + error_message(status)); + exit(1); + } + krb5_princ_type(server) = KRB5_NT_SRV_HST; + + if (status = krb5_recvauth(&netf, + "KCMDV0.1", + server, /* no match on server + incase we have are + serving multiple realms*/ + &peeraddr, /* We do want to match this + against caddrs in the + ticket. */ + 0, /* use srv5tab */ + 0, /* no keyproc */ + 0, /* no keyproc arg */ + 0, /* no rc_type */ + 0, /* no seq number */ + &client, /* return client */ + &ticket, /* return ticket */ + &kdata /* return authenticator */ + )) { + syslog(LOG_ERR, + "Kerberos authentication failed from %s: %s\n", + host,error_message(status)); + + /* Dont exit out for klogin, but + grab locuser, terminal, and remuser. + */ + + /* These two reads will be used in the next release to obtain + a forwarded TGT and related info. */ + if (status = krb5_read_message((krb5_pointer)&netf, &inbuf)) + fatal(netf, "Error reading message"); + if (inbuf.length) + fatal(netf, "Forwarding is not yet supported"); + if (status = krb5_read_message((krb5_pointer)&netf, &inbuf)) + fatal(netf, "Error reading message"); + if (inbuf.length) + fatal(netf, "Forwarding is not yet supported"); + + getstr(lusername, sizeof(lusername), "locuser"); + getstr(term, sizeof(term), "Terminal type"); + rusername = malloc(sizeof (lusername) + 1); + getstr(rusername, sizeof(lusername), "remuser"); + + failed_auth = 1; + if (ticket) + krb5_free_ticket(ticket); + return; + } + + /* Setup up eblock if encrypted login session */ + /* otherwise zero out session key */ + if (do_encrypt) { + krb5_use_keytype(&eblock, + ticket->enc_part2->session->keytype); + if (status = krb5_process_key(&eblock, + ticket->enc_part2->session)) + fatal(netf, "Permission denied"); + } + + /* These two reads will be used in the next release to obtain + a forwarded TGT and related info. */ + if (status = krb5_read_message((krb5_pointer)&netf, &inbuf)) + fatal(netf, "Error reading message"); + if (inbuf.length) + fatal(netf, "Forwarding is not yet supported"); + if (status = krb5_read_message((krb5_pointer)&netf, &inbuf)) + fatal(netf, "Error reading message"); + if (inbuf.length) + fatal(netf, "Forwarding is not yet supported"); + + getstr(lusername, sizeof(lusername), "locuser"); + getstr(term, sizeof(term), "Terminal type"); + rusername = malloc(sizeof (lusername) + 1); + getstr(rusername, sizeof(lusername), "remuser"); + + /* OK we have authenticated this user - now check authorization. */ + /* We must do this here since we want the same functionality as */ + /* the MIT version without having to provide the login.krb program.*/ + + /* The Kerberos authenticated programs must use krb5_kuserok */ + + krb5_unparse_name(kdata->client,&krusername); + + if (must_pass_k5 || must_pass_one) { + /* krb5_kuserok returns 1 if OK */ + rc = !(krb5_kuserok(kdata->client,lusername)); + + if (rc){ + syslog(LOG_ERR, + "Principal %s (%s@%s) logging in as %s failed krb5_kuserok.\n", + krusername, rusername, host, lusername); + if (must_pass_k5) + fatal(netf, "Permission denied"); + failed_k5 = 1; + if (ticket) + krb5_free_ticket(ticket); + } + } + + /* The kerberos authenticated request must pass ruserok also + if asked for. */ + + if (must_pass_rhosts || (failed_k5 && must_pass_one)) { + pwd = (struct passwd *) getpwnam(lusername); + if ((pwd == (struct passwd *) 0) || + (ruserok(rhost_name, pwd->pw_uid == 0, rusername, lusername))) { + failed_rhosts = 1; + if (ticket) + krb5_free_ticket(ticket); + + if (pwd == (struct passwd *) 0) + syslog(LOG_ERR, + "Principal %s (%s@%s) logging in as %s has no account.\n", + krusername, rusername, rhost_name, lusername); + else + syslog(LOG_ERR, + "Principal %s (%s@%s) logging in as %s failed ruserok.\n", + krusername, rusername, rhost_name, lusername); + + if (must_pass_rhosts) + fatal(netf, "Permission denied"); + } + } + + return; +} + + + +getstr(buf, cnt, err) + char *buf; + int cnt; + char *err; +{ + + char c; + + do { + if (read(0, &c, 1) != 1) { + exit(1); + } + if (--cnt < 0) { + printf("%s too long\r\n", err); + exit(1); + } + *buf++ = c; + } while (c != 0); +} + + + +char storage[2*BUFSIZ]; /* storage for the decryption */ +int nstored = 0; +char *store_ptr = storage; + + +des_read(fd, buf, len) + int fd; + register char *buf; + int len; +{ + int nreturned = 0; + long net_len,rd_len; + int cc,retry; + + if (!do_encrypt) + return(read(fd, buf, len)); + + if (nstored >= len) { + memcpy(buf, store_ptr, len); + store_ptr += len; + nstored -= len; + return(len); + } else if (nstored) { + memcpy(buf, store_ptr, nstored); + nreturned += nstored; + buf += nstored; + len -= nstored; + nstored = 0; + } + +#ifdef BITS64 + rd_len = 0; + if ((cc = krb5_net_read(fd, (char *)&rd_len + 4, 4)) != 4) { +#else + if ((cc = krb5_net_read(fd, (char *)&rd_len, sizeof(rd_len))) != + sizeof(rd_len)) { +#endif + if ((cc < 0) && (errno == EWOULDBLOCK)) return(cc); + /* XXX can't read enough, pipe + must have closed */ + return(0); + } + rd_len = ntohl(rd_len); + net_len = krb5_encrypt_size(rd_len,eblock.crypto_entry); + if (net_len < 0 || net_len > sizeof(des_inbuf)) { + /* XXX preposterous length, probably out of sync. + act as if pipe closed */ + syslog(LOG_ERR,"Read size problem."); + return(0); + } + retry = 0; + datard: + if ((cc = krb5_net_read(fd, desinbuf.data, net_len)) != net_len) { + /* XXX can't read enough, pipe + must have closed */ + if ((cc < 0) && (errno == EWOULDBLOCK)) { + retry++; + sleep(1); + if (retry > MAXRETRIES){ + syslog(LOG_ERR, + "des_read retry count exceeded %d\n", + retry); + return(0); + } + goto datard; + } + syslog(LOG_ERR, + "Read data received %d != expected %d.", + cc, net_len); + return(0); + } + /* decrypt info */ + if ((krb5_decrypt(desinbuf.data, + (krb5_pointer) storage, + net_len, + &eblock, 0))) { + syslog(LOG_ERR,"Read decrypt problem."); + return(0); + } + store_ptr = storage; + nstored = rd_len; + if (nstored > len) { + memcpy(buf, store_ptr, len); + nreturned += len; + store_ptr += len; + nstored -= len; + } else { + memcpy(buf, store_ptr, nstored); + nreturned += nstored; + nstored = 0; + } + return(nreturned); +} + + + +des_write(fd, buf, len) + int fd; + char *buf; + int len; +{ + long net_len; + + if (!do_encrypt) + return(write(fd, buf, len)); + + + desoutbuf.length = krb5_encrypt_size(len,eblock.crypto_entry); + if (desoutbuf.length > sizeof(des_outbuf)){ + syslog(LOG_ERR,"Write size problem."); + return(-1); + } + if ((krb5_encrypt((krb5_pointer)buf, + desoutbuf.data, + len, + &eblock, + 0))){ + syslog(LOG_ERR,"Write encrypt problem."); + return(-1); + } + + net_len = htonl(len); +#ifdef BITS64 + (void) write(fd,(char *)&net_len + 4, 4); +#else + (void) write(fd, &net_len, sizeof(net_len)); +#endif + if (write(fd, desoutbuf.data,desoutbuf.length) != desoutbuf.length){ + syslog(LOG_ERR,"Could not write out all data."); + return(-1); + } + else return(len); +} + +#endif /* KERBEROS */ + + + +getpty(fd,slave) + int *fd; + char *slave; +{ + char c; + int i,ptynum; + struct stat stb; +#ifdef STREAMS +#ifdef sysvimp + *fd = open("/dev/pty", O_RDWR|O_NDELAY); +#else + *fd = open("/dev/ptc", O_RDWR|O_NDELAY); +#endif + if (*fd >= 0) { + if (fstat(*fd, &stb) < 0) { + close(*fd); + return 1; + } + ptynum = (int)(stb.st_rdev&0xFF); +#ifdef sysvimp + sprintf(slave, "/dev/ttyp%x", ptynum); +#else + sprintf(slave, "/dev/ttyq%x", ptynum); +#endif + } + return (0); + +#else /* NOT STREAMS */ + for (c = 'p'; c <= 's'; c++) { + sprintf(slave,"/dev/ptyXX"); + slave[strlen("/dev/pty")] = c; + slave[strlen("/dev/ptyp")] = '0'; + if (stat(slave, &stb) < 0) + break; + for (i = 0; i < 16; i++) { + slave[sizeof("/dev/ptyp") - 1] = "0123456789abcdef"[i]; + *fd = open(slave, O_RDWR); + if (*fd > 0) + goto gotpty; + } + } + return(1); + gotpty: + slave[strlen("/dev/")] = 't'; + return(0); +#endif /* STREAMS */ +} + + + +void usage() +{ +#ifdef KERBEROS + syslog(LOG_ERR, + "usage: klogind [-rRkKxpP] or [r/R][k/K][x/e][p/P]logind"); +#else + syslog(LOG_ERR, "usage: rlogind [-rRpP] or [r/R][p/P]logind"); +#endif +} + + + +#ifdef KERBEROS +int princ_maps_to_lname(principal, luser) + krb5_principal principal; + char *luser; +{ + char kuser[10]; + if (!(krb5_aname_to_localname(principal, + sizeof(kuser), kuser)) + && (strcmp(kuser, luser) == 0)) { + return 1; + } + return 0; +} + +int default_realm(principal) + krb5_principal principal; +{ + char *def_realm; + int realm_length; + int retval; + + realm_length = krb5_princ_realm(principal)->length; + + if (retval = krb5_get_default_realm(&def_realm)) { + return 0; + } + + if ((realm_length != strlen(def_realm)) || + (memcmp(def_realm, krb5_princ_realm(principal)->data, realm_length))) { + free(def_realm); + return 0; + } + free(def_realm); + return 1; +} +#endif diff --git a/src/appl/bsd/krsh.c b/src/appl/bsd/krsh.c new file mode 100644 index 000000000..57df62ad5 --- /dev/null +++ b/src/appl/bsd/krsh.c @@ -0,0 +1,416 @@ +/* + * $Source$ + * $Header$ + */ + +#ifndef lint +static char *rcsid_rsh_c = + "$Header$"; +#endif /* lint */ + +/* + * Copyright (c) 1983 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +char copyright[] = + "@(#) Copyright (c) 1983 The Regents of the University of California.\n\ + All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)rsh.c 5.7 (Berkeley) 9/20/88"; +#endif /* not lint */ + +#define KERBEROS + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#ifdef KERBEROS +#include +#include +#include +#include +#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<: ...'' +.br +The user's login shell could not be started. This message is returned +on the connection associated with the +.BR stderr , +and is not preceded by a flag byte. +.SH SEE ALSO +rsh(1C), +rcmd(3X) +.SH BUGS +The authentication procedure used here assumes the integrity +of each client machine and the connecting medium. This is +insecure, but is useful in an ``open'' environment. +.PP +A facility to allow all data exchanges to be encrypted should be +present. +.PP +A more extensible protocol should be used. diff --git a/src/appl/bsd/krshd.c b/src/appl/bsd/krshd.c new file mode 100644 index 000000000..0654d54fb --- /dev/null +++ b/src/appl/bsd/krshd.c @@ -0,0 +1,1340 @@ +/* + * $Author$ + * $Header$ + */ + +#ifndef lint +static char rcsid_rshd_c[] = + "$Header$"; +#endif /* lint */ + +/* + * Copyright (c) 1983 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +char copyright[] = + "@(#) Copyright (c) 1983 The Regents of the University of California.\n\ + All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)rshd.c 5.12 (Berkeley) 9/12/88"; +#endif /* not lint */ + +#define KERBEROS + + /* + * remote shell server: + * remuser\0 + * locuser\0 + * command\0 + * data + */ + + /* + * This is the rshell daemon. The very basic protocol for checking + * authentication and authorization is: + * 1) Check authentication. + * 2) Check authorization via the access-control files: + * ~/.k5login (using krb5_kuserok) and/or + * ~/.rhosts (using ruserok). + * Execute command if configured authoriztion checks pass, else deny + * permission. + * + * The configuration is done either by command-line arguments passed by inetd, + * or by the name of the daemon. If command-line arguments are present, they + * take priority. The options are: + * -k and -K means check .k5login (using krb5_kuserok). + * -r and -R means check .rhosts (using ruserok). + * The difference between upper and lower case is as follows: + * If lower case -r or -k, then as long as one of krb5_kuserok or ruserok + * passes, allow access. If both fail, no access. The program does not fall + * back on password verification. + * If uppercase -R or -K, then those checks must be passed, regardless of + * other checks, else no access. + * + * If no command-line arguments are present, then the presence of the + * letters kKrR in the program-name before "shd" determine the + * behaviour of the program exactly as with the command-line arguments. + */ + + /* DEFINES: + * KERBEROS - Define this if application is to be kerberised. + * LOG_ALL_LOGINS - Define this if you want to log all logins. + * LOG_OTHER_USERS - Define this if you want to log all principals that do + * not map onto the local user. + * LOG_REMOTE_REALM - Define this if you want to log all principals from + * remote realms. + * LOG_CMD - Define this if you want to log not only the user but also the + * command executed. This only decides the type of information + * logged. Whether or not to log is still decided by the above + * three DEFINES. + * Note: Root account access is always logged. + */ + +#define LOG_REMOTE_REALM +#define LOG_CMD + +#include +#include + +#if defined(CRAY) || defined(sysvimp) || defined(aux20) +#include +#ifndef _TYPES_ +#define _TYPES_ +#endif +#ifndef F_OK +#define F_OK 0 +#endif +#endif + +#include +#include +#include +#include + +#include + +#ifndef SYSV +#include +#endif + +#include +#include +#include + +#ifdef sun +#include +#include +#include +#endif + +#include +#include + +#ifdef CRAY +#ifndef NO_UDB +#include +#endif /* !NO_UDB */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif /* CRAY */ + +#include + +#ifdef KERBEROS +#include +#include +#include +#include + +#include + +#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 +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<pw_shell == '\0') + pwd->pw_shell = "/bin/sh"; + (void) close(f); + (void) setgid((gid_t)pwd->pw_gid); +#ifndef sgi + initgroups(pwd->pw_name, pwd->pw_gid); +#endif + (void) setuid((uid_t)pwd->pw_uid); + environ = envinit; + strncat(homedir, pwd->pw_dir, sizeof(homedir)-6); + strncat(shell, pwd->pw_shell, sizeof(shell)-7); + strncat(username, pwd->pw_name, sizeof(username)-6); + cp = rindex(pwd->pw_shell, '/'); + if (cp) + cp++; + else + cp = pwd->pw_shell; + + execl(pwd->pw_shell, cp, "-c", cmdbuf, 0); + perror(pwd->pw_shell); + perror(cp); + exit(1); + + signout_please: +#ifdef SYSV + logwtmp(ttyn,"","",0,0); /* Close wtmp */ +#else + logwtmp(ttyn,"","",0); /* Close wtmp */ +#endif + exit(1); +} + + + +/*VARARGS1*/ +error(fmt, a1, a2, a3) + char *fmt; + int a1, a2, a3; +{ + char buf[BUFSIZ]; + + buf[0] = 1; + (void) sprintf(buf+1, fmt, a1, a2, a3); + (void) write(2, buf, strlen(buf)); + syslog(LOG_ERR ,"%s",buf+1); +} + + + +getstr(buf, cnt, err) + char *buf; + int cnt; + char *err; +{ + char c; + + do { + if (read(0, &c, 1) != 1) + exit(1); + *buf++ = c; + if (--cnt == 0) { + error("%s too long\n", err); + exit(1); + } + } while (c != 0); +} + + + +krb5_sigtype + cleanup() +{ + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + signal(SIGTERM, SIG_IGN); + signal(SIGPIPE, SIG_IGN); + signal(SIGHUP, SIG_IGN); + + killpg(pid, SIGTERM); + wait(0); + +#ifdef SYSV + logwtmp(ttyn,"","",0,0); /* Close wtmp */ +#else + logwtmp(ttyn,"","",0); /* Close wtmp */ +#endif + syslog(LOG_INFO ,"Shell process completed."); + exit(0); +} + + + +#ifdef CRAY +char *makejtmp(uid, gid, jid) + register int uid, gid, jid; +{ + extern int errno; + + register char *endc, *tdp = &tmpdir[strlen(tmpdir)]; + register int i; + + sprintf(tdp, "%s/jtmp.%06d", JTMPDIR, jid); + endc = &tmpdir[strlen(tmpdir)]; + + endc[1] = '\0'; + for (i = 0; i < 26; i++) { + endc[0] = 'a' + i; + if (mkdir(tdp, JTMPMODE) != -1) { + chown(tdp, uid, gid); + return (tdp); + } else if (errno != EEXIST) + break; + } + return(NULL); +} + + + +cleanjtmp(user, tpath) + register char *user, *tpath; +{ + switch(fork()) { + case -1: + break; + case 0: + if (secflag) { + execl("/bin/rm", "rm", "-rf", tpath, 0); + error("exec of %s failed; errno = %d\n", + "/bin/rm", errno); + } else { + execl(CLEANTMPCMD, CLEANTMPCMD, user, tpath, 0); + error("exec of %s failed; errno = %d\n", + CLEANTMPCMD, errno); + } + exit(1); + break; + default: + /* + * Just forget about the child, let init will pick it + * up after we exit. + */ + break; + } +} + + + +/***get_packet_classification + * + * + * int get_packet_classification(): + * Obtain packet level and compartments from passed fd... + * + * Returns: + * -1: If could not get user defaults. + * 0: success + */ +#ifdef IP_SECURITY +static int get_packet_classification(fd,useruid,level,comp) + int fd; + uid_t useruid; + int *level; + long *comp; +{ + struct socket_security pkt_sec; + struct udb *udb; + int retval; + int sockoptlen; + + retval = 0; + getsysudb (); + udb = getudbuid ((int) useruid); + endudb (); + if (udb == (struct udb *) 0) return(-1); + /* Get packet IP packet label */ + sockoptlen = SIZEOF_sec; + if ( getsockopt(fd,SOL_SOCKET,SO_SECURITY, + (char *) &pkt_sec,&sockoptlen)){ /* Failed */ + return(-2); + } + *level = pkt_sec.sec_level; + *comp = udb->ue_defcomps; + return(0); +} + +#else /* If no IP_SECURITY set level to users default */ + +static int get_packet_classification(fd,useruid,level,comp) + int fd; + uid_t useruid; + int *level; + long *comp; +{ + struct udb *udb; + getsysudb (); + udb = getudbuid ((int) useruid); + endudb (); + if (udb == (struct udb *) 0) return(-1); + *level = udb->ue_deflvl; + *comp = udb->ue_defcomps; + return(0); +} + +#endif /* IP_SECURITY */ + + + +/* + * Make a security log entry for the login attempt. + * host = pointer to host id + * flag = status of login + * failures = current losing streak in login attempts + */ +/* Make a security log entry for the login attempt. + * host = pointer to host id + * flag = status of login + * failures = current losing streak in login attempts + */ + +loglogin(host, flag, failures, ue) + char *host; + int flag; + int failures; + struct udb * ue; +{ + char urec[sizeof(struct slghdr) + sizeof(struct slglogin)]; + struct slghdr *uhdr = (struct slghdr *)urec; + struct slglogin *ulogin=(struct slglogin *)&urec[sizeof(struct slghdr)]; + + strncpy(ulogin->sl_line, ttyn, sizeof(ulogin->sl_line)); + strncpy(ulogin->sl_host, host, sizeof(ulogin->sl_host)); + ulogin->sl_failures = failures; + if ( maxlogs && (failures >= maxlogs)) + flag |= SLG_DSABL; + ulogin->sl_result = flag; + uhdr->sl_uid = ue->ue_uid; + uhdr->sl_ruid = ue->ue_uid; + uhdr->sl_juid = ue->ue_uid; + uhdr->sl_gid = ue->ue_gids[0]; + uhdr->sl_rgid = ue->ue_gids[0]; + uhdr->sl_slvl = ue->ue_deflvl; + /* uhdr->sl_scls = ue->ue_defcls; enable for integrity policy */ + uhdr->sl_olvl = 0; + uhdr->sl_len = sizeof(urec); + +#ifdef CRAY2 + slgentry(SLG_LOGN, (word *)urec); +#else /* ! CRAY2 */ + slgentry(SLG_LOGN, (waddr_t)urec); +#endif + return; +} + +#endif CRAY + + + +usage() +{ +#ifdef KERBEROS + syslog(LOG_ERR, "usage: kshd [-rRkK] or [r/R][k/K]shd"); +#else + syslog(LOG_ERR, "usage: rshd"); +#endif +} + + + +int princ_maps_to_lname(principal, luser) + krb5_principal principal; + char *luser; +{ + char kuser[10]; + if (!(krb5_aname_to_localname(principal, + sizeof(kuser), kuser)) + && (strcmp(kuser, luser) == 0)) { + return 1; + } + return 0; +} + + + +int default_realm(principal) + krb5_principal principal; +{ + char *def_realm; + int realm_length; + int retval; + + realm_length = krb5_princ_realm(principal)->length; + + if (retval = krb5_get_default_realm(&def_realm)) { + return 0; + } + + if ((realm_length != strlen(def_realm)) || + (memcmp(def_realm, krb5_princ_realm(principal)->data, realm_length))) { + free(def_realm); + return 0; + } + free(def_realm); + return 1; +} diff --git a/src/appl/bsd/login.c b/src/appl/bsd/login.c new file mode 100644 index 000000000..36fc46fb9 --- /dev/null +++ b/src/appl/bsd/login.c @@ -0,0 +1,684 @@ +/* + * $Source$ + * $Author$ + * $Id$ + */ + +#ifndef lint +static char rcsid_login_c[] = "$Id$"; +#endif lint + +/* + * Copyright (c) 1980, 1987, 1988 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef lint +char copyright[] = + "@(#) Copyright (c) 1980, 1987, 1988 The Regents of the University of California.\n\ + All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)login.c 5.25 (Berkeley) 1/6/89"; +#endif /* not lint */ + +#define KERBEROS + + /* + * login -f name (for pre-authenticated login) + * login name (for non-authenticated/non-authorized login) + */ + +#define VFS +#define BYPASS_ROOT_CHK + +#include +#ifndef VFS +#include +#endif VFS +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#ifndef NOTTYENT +#include +#endif /* NOTTYENT */ +#include +#include +#include +#include +#include +#include + +#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 +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); + } +} diff --git a/src/appl/bsd/logutil.c b/src/appl/bsd/logutil.c new file mode 100644 index 000000000..645df5459 --- /dev/null +++ b/src/appl/bsd/logutil.c @@ -0,0 +1,178 @@ +/* + * Copyright (c) 1988 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)login.c 5.1 (Berkeley) 9/27/88"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include +#if defined (CRAY) || defined (sgi) +#include +#define L_SET 0 +#define L_INCR 1 +#endif +#include +#include +#include +#include + +#ifndef UTMP_FILE +#define UTMP_FILE "/etc/utmp" +#endif +#ifndef WTMP_FILE +#ifdef SYSV +#define WTMPFILE "/etc/wtmp" +#else +#define WTMP_FILE "/usr/adm/wtmp" +#endif +#endif + +void login(ut) + struct utmp *ut; +{ + register int fd; + int tty; + off_t lseek(); + + tty = ttyslot(); + if (tty > 0 && (fd = open(UTMP_FILE, O_WRONLY, 0)) >= 0) { + (void)lseek(fd, (long)(tty * sizeof(struct utmp)), L_SET); + (void)write(fd, (char *)ut, sizeof(struct utmp)); + (void)close(fd); + } + if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) >= 0) { + (void)write(fd, (char *)ut, sizeof(struct utmp)); + (void)close(fd); + } +} + + + +/* + * Copyright (c) 1988 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)logout.c 5.1 (Berkeley) 8/31/88"; +#endif /* LIBC_SCCS and not lint */ + +logout(line) + register char *line; +{ + register FILE *fp; + struct utmp ut; + int rval; + time_t time(); + + if (!(fp = fopen(UTMP_FILE, "r+"))) + return(0); + rval = 1; + while (fread((char *)&ut, sizeof(struct utmp), 1, fp) == 1) { + if (!ut.ut_name[0] || + strncmp(ut.ut_line, line, sizeof(ut.ut_line))) + continue; + memset(ut.ut_name,0, sizeof(ut.ut_name)); +#ifndef NO_UT_HOST + memset(ut.ut_host,0, sizeof(ut.ut_host)); +#endif + (void)time(&ut.ut_time); + (void)fseek(fp, (long)-sizeof(struct utmp), L_INCR); + (void)fwrite((char *)&ut, sizeof(struct utmp), 1, fp); + (void)fseek(fp, (long)0, L_INCR); + rval = 0; + } + (void)fclose(fp); + return(rval); +} + + + +/* + * Copyright (c) 1988 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)logwtmp.c 5.2 (Berkeley) 9/20/88"; +#endif /* LIBC_SCCS and not lint */ + +static int fd = -1; + +#ifndef SYSV +logwtmp(line, name, host, keep_open) +#else +logwtmp(line, name, host, keep_open, logingin) +#endif + char *line, *name, *host; + int keep_open; +#ifdef SYSV + int logingin; +#endif +{ + struct utmp ut; + struct stat buf; + time_t time(); + char *strncpy(); + + if (fd < 0 && (fd = open(WTMP_FILE, O_WRONLY|O_APPEND, 0)) < 0) + return; + if (!fstat(fd, &buf)) { + (void)strncpy(ut.ut_line, line, sizeof(ut.ut_line)); + (void)strncpy(ut.ut_name, name, sizeof(ut.ut_name)); +#ifndef NO_UT_HOST + (void)strncpy(ut.ut_host, host, sizeof(ut.ut_host)); +#endif +#ifdef SYSV + (void)strncpy(ut.ut_id, (char *)ut.ut_line + 4, + sizeof(ut.ut_id)); + ut.ut_type = logingin ? USER_PROCESS : DEAD_PROCESS; + ut.ut_pid = getpid(); +#endif + (void)time(&ut.ut_time); + if (write(fd, (char *)&ut, sizeof(struct utmp)) != + sizeof(struct utmp)) + (void)ftruncate(fd, buf.st_size); + } + if ( !keep_open) + (void)close(fd); +} diff --git a/src/appl/bsd/rcp.M b/src/appl/bsd/rcp.M new file mode 100644 index 000000000..ed3f872ca --- /dev/null +++ b/src/appl/bsd/rcp.M @@ -0,0 +1,130 @@ +.\" $Source$ +.\" $Author$ +.\" $Header$ +.\" +.\" Copyright (c) 1983 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms are permitted +.\" provided that the above copyright notice and this paragraph are +.\" duplicated in all such forms and that any documentation, +.\" advertising materials, and other materials related to such +.\" distribution and use acknowledge that the software was developed +.\" by the University of California, Berkeley. The name of the +.\" University may not be used to endorse or promote products derived +.\" from this software without specific prior written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +.\" WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.\" @(#)rcp.1 6.6 (Berkeley) 9/20/88 +.\" +.TH RCP 1 "Kerberos Version 4.0" "MIT Project Athena" +.UC 5 +.SH NAME +rcp \- remote file copy +.SH SYNOPSIS +.B rcp +[ +.B \-p +] [ +.B \-x +] [ +.B \-k +realm ] file1 file2 +.br +.B rcp +[ +.B \-p +] [ +.B \-x +] [ +.B \-k +realm ] [ +.B \-r +] file ... directory +.SH DESCRIPTION +.I Rcp +copies files between machines. Each +.I file +or +.I directory +argument is either a remote file name of the +form ``rhost:path'', or a local file name (containing no `:' characters, +or a `/' before any `:'s). +.PP +If the +.B \-r +option +is specified and any of the source files are directories, +.I rcp +copies each subtree rooted at that name; in this case +the destination must be a directory. +.PP +By default, the mode and owner of +.I file2 +are preserved if it already existed; otherwise the mode of the source file +modified by the +.IR umask (2) +on the destination host is used. +The +.B \-p +option causes +.I rcp +to attempt to preserve (duplicate) in its copies the modification +times and modes of the source files, ignoring the +.IR umask . +.PP +If +.I path +is not a full path name, it is interpreted relative to +your login directory on +.IR rhost . +A +.I path +on a remote host may be quoted (using \e, ", or \(aa) +so that the metacharacters are interpreted remotely. +.PP +.I Rcp +does not prompt for passwords; it uses Kerberos authentication when +connecting to +.IR rhost . +Authorization is as described in +.IR rlogin (1). +.PP +The +.B \-x +option selects encryption of all information transferring between hosts. +The +.B \-k +.I realm +option causes +.I rcp +to obtain tickets for the remote host in +.I realm +instead of the remote host's realm as determined by +.IR krb_realmofhost (3). +.PP +.I Rcp +handles third party copies, where neither source nor target files +are on the current machine. +Hostnames may also take the form ``rname@rhost'' to use +.I rname +rather than the current user name on the remote host. +.SH SEE ALSO +cp(1), ftp(1), rsh(1), rlogin(1), kerberos(3), krb_getrealm(3), +rcp(1) [UCB version] +.SH BUGS +Doesn't detect all cases where the target of a copy might +be a file in cases where only a directory should be legal. +.PP +Is confused by any output generated by commands in a +\&.login, \&.profile, or \&.cshrc file on the remote host. +.PP +The destination user and hostname may have to be specified as +``rhost.rname'' when the destination machine is running the 4.2BSD +version of \fIrcp\fP. +.PP +Kerberos is only used for the first connection of a third-party copy; +the second connection uses the standard Berkeley rcp protocol. + diff --git a/src/appl/bsd/rlogin.M b/src/appl/bsd/rlogin.M new file mode 100644 index 000000000..c24ef85e0 --- /dev/null +++ b/src/appl/bsd/rlogin.M @@ -0,0 +1,200 @@ +.\" $Source$ +.\" $Author$ +.\" $Header$ +.\" +.\" Copyright (c) 1983 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms are permitted +.\" provided that the above copyright notice and this paragraph are +.\" duplicated in all such forms and that any documentation, +.\" advertising materials, and other materials related to such +.\" distribution and use acknowledge that the software was developed +.\" by the University of California, Berkeley. The name of the +.\" University may not be used to endorse or promote products derived +.\" from this software without specific prior written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +.\" WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.\" @(#)rlogin.1 6.9 (Berkeley) 9/19/88 +.\" +.TH RLOGIN 1 "Kerberos Version 4.0" "MIT Project Athena" +.UC 5 +.SH NAME +rlogin \- remote login +.SH SYNOPSIS +.B rlogin +rhost [ +\fB\-e\fR\fI\|c\fR +] [ +.B \-8 +] [ +.B \-c +] [ +.B \-a +] [ +.B \-t +termtype ] [ +.B \-n +] [ +.B \-7 +] [ +.B \-d +] [ +.B \-k +realm ] [ +.B \-x +] [ +.B \-noflow +] [ +.B \-L +] [ +.B \-l +username ] +.br +rhost [ +\fB\-e\fR\fIc\fR +] [ +.B \-8 +] [ +.B \-c +] [ +.B \-a +] [ +.B \-t +termtype ] [ +.B \-n +] [ +.B \-7 +] [ +.B \-d +] [ +.B \-k +realm ] [ +.B \-x +] [ +.B \-noflow +] [ +.B \-L +] [ +.B \-l +username ] +.SH DESCRIPTION +.I Rlogin +connects your terminal on the current local host system +.I lhost +to the remote host system +.I rhost. +.PP +The version built to use Kerberos authentication is very similar to the +standard Berkeley rlogin(1), except that instead of the \fIrhosts\fP +mechanism, it uses Kerberos authentication to determine the +authorization to use a remote account. +.PP +Each user may have a private authorization list in a file \&.klogin +in his login directory. Each line in this file should contain a +Kerberos principal name of the form +.IR principal.instance@realm . +If the originating user is authenticated to one of the principals named +in \&.klogin, access is granted to the account. The principal +\fIaccountname\fP.@\fIlocalrealm\fP is granted access if there is no +\&.klogin file. +Otherwise +a login and password will be prompted for on the remote machine as in +.IR login (1). +To avoid some security problems, the \&.klogin file must be owned by +the remote user. +.PP +If there is some problem in marshaling the Kerberos authentication +information, an error message is printed and the standard UCB rlogin is +executed in place of the Kerberos rlogin. +.PP +A line of the form ``~.'' disconnects from the remote host, where +``~'' is the escape character. +Similarly, the line ``~^Z'' (where ^Z, control-Z, is the suspend character) +will suspend the rlogin session. +Substitution of the delayed-suspend character (normally ^Y) +for the suspend character suspends the send portion of the rlogin, +but allows output from the remote system. +.PP +The remote terminal type is the same as your local +terminal type (as given in your environment TERM variable), unless the +.B \-t +option is specified (see below). +The terminal or window size is also copied to the remote system +if the server supports the option, +and changes in size are reflected as well. +.PP +All echoing takes place at the remote site, so that (except for +delays) the rlogin is transparent. Flow control via ^S and ^Q and +flushing of input and output on interrupts are handled properly. +.PP +The +.B \-8 +option allows an eight-bit input data path at all times; +otherwise parity bits are stripped except when the remote side's +stop and start characters are other than ^S/^Q. Eight-bit mode is the default. +.PP +The +.B \-L +option allows the rlogin session to be run in litout mode. +.PP +The +.B \-e +option allows specification of a different escape character. +There is no space separating this option flag and the new escape +character. +.PP +The +.B \-c +option requires confirmation before disconnecting via ``~.'' +.PP +The +.B \-a +option forces the remote machine to ask for a password by sending a null local +username. This option has no effect unless the standard UCB rlogin is +executed in place of the Kerberos rlogin (see above). +.PP +The +.B \-t +option replaces the terminal type passed to the remote host with +\fItermtype\fP. +.PP +The +.B \-n +option prevents suspension of rlogin via ``~^Z'' or ``~^Y''. +.PP +The +.B \-7 +option forces seven-bit transmissions. +.PP +The +.B \-d +option turns on socket debugging (via \fIsetsockopt(2)\fR) on the TCP +sockets used for communication with the remote host. +.PP +The +.B \-noflow +option forces transmission of flow control characters (^S/^Q) to the +remote system. +.PP +The +.B \-k +option requests rlogin to obtain tickets for the remote host in realm +.I realm +instead of the remote host's realm as determined by +.IR krb_realmofhost (3). +.PP +The +.B \-x +option turns on DES encryption for all data passed via the +rlogin session. This significantly reduces response time and +significantly increases CPU utilization. +.SH SEE ALSO +rsh(1), kerberos(3), krb_sendauth(3), krb_realmofhost(3), +rlogin(1) [UCB version] +.SH FILES +/usr/hosts/* for \fIrhost\fP version of the command +.SH BUGS +More of the environment should be propagated. diff --git a/src/appl/bsd/rsh.M b/src/appl/bsd/rsh.M new file mode 100644 index 000000000..eda3328d4 --- /dev/null +++ b/src/appl/bsd/rsh.M @@ -0,0 +1,153 @@ +.\" $Source$ +.\" $Author$ +.\" $Header$ +.\" +.\" Copyright (c) 1983 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms are permitted +.\" provided that the above copyright notice and this paragraph are +.\" duplicated in all such forms and that any documentation, +.\" advertising materials, and other materials related to such +.\" distribution and use acknowledge that the software was developed +.\" by the University of California, Berkeley. The name of the +.\" University may not be used to endorse or promote products derived +.\" from this software without specific prior written permission. +.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +.\" WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. +.\" +.\" @(#)rsh.1 6.2 (Berkeley) 9/20/88 +.\" +.TH RSH 1 "Kerberos Version 4.0" "MIT Project Athena" +.UC 5 +.SH NAME +rsh \- remote shell +.SH SYNOPSIS +.B rsh +host +[ +.B \-l +username +] [ +.B \-n +] [ +.B \-d +] [ +.B \-k +realm ] command +.br +host +[ +.B \-l +username +] [ +.B \-n +] [ +.B \-d +] [ +.B \-k +realm ] command +.SH DESCRIPTION +.I Rsh +connects to the specified +.I host, +and executes the specified \fIcommand\fR. +.I Rsh +copies its standard input to the remote command, the standard +output of the remote command to its standard output, and the +standard error of the remote command to its standard error. +Interrupt, quit and terminate signals are propagated to the remote +command; \fIrsh\fP normally terminates when the remote command does. +.PP +The remote username used is the same as your local username, +unless you specify a different remote name with the +.B \-l +option. +Kerberos authentication is used, and authorization is determined as in +rlogin(1). +.PP +The +.B \-k +\fIrealm\fP option causes +.I rsh +to obtain tickets for the remote host in +.I realm +instead of the remote host's realm as determined by +.IR krb_realmofhost (3). +.PP +The +.B \-d +option turns on socket debugging (via \fIsetsockopt(2)\fR) on the TCP +sockets used for communication with the remote host. +.PP +The +.B \-n +option redirects input from the special device +.I /dev/null +(see the BUGS section below). +.PP +If you omit +.I command, +then instead of executing a single command, you will be logged in +on the remote host using +.IR rlogin (1). +.PP +Shell metacharacters which are not quoted are interpreted +on local machine, while quoted metacharacters are interpreted on +the remote machine. +Thus the command +.PP +\ \ \ rsh otherhost cat remotefile >> localfile +.PP +appends the remote file +.I remotefile +to the local file +.I localfile, +while +.PP +\ \ \ rsh otherhost cat remotefile ">>" otherremotefile +.PP +appends +.I remotefile +to +.I otherremotefile. +.PP +The host names for local machines are also commands in the directory +/usr/hosts; if you put this directory in your search path +then the +.B rsh +on the command line can be omitted. +.SH FILES +.ta 2i +/etc/hosts +.br +/usr/hosts/* +.DT +.SH SEE ALSO +rlogin(1), kerberos(3), krb_sendauth(3), krb_realmofhost(3) +.SH BUGS +If you are using +.IR csh (1) +and put a +.IR rsh (1) +in the background without redirecting its input +away from the terminal, it will block even if no reads +are posted by the remote command. If no input is desired +you should redirect the input of +.I rsh +to /dev/null using the +.B \-n +option. +.PP +You cannot run an interactive command +(like +.IR rogue (6) +or +.IR vi (1)); +use +.IR rlogin (1). +.PP +Stop signals stop the local \fIrsh\fP process only; this is arguably +wrong, but currently hard to fix for reasons too complicated to +explain here. diff --git a/src/kadmin/client/Imakefile b/src/kadmin/client/Imakefile new file mode 100644 index 000000000..1da031b85 --- /dev/null +++ b/src/kadmin/client/Imakefile @@ -0,0 +1,45 @@ +# $Source$ +# $Author$ +# $Header$ +# +# Copyright 1989 by the Massachusetts Institute of Technology. +# +# For copying and distribution information, +# please see the file . +# +# Imakefile for Kerberos admin client library. + +SRCS = \ + kadmin.c \ + kadmin_add.c \ + kadmin_adr.c \ + kadmin_cpr.c \ + kadmin_inq.c \ + kadmin_msnd.c \ + kadmin_mod.c \ + kadmin_cpw.c \ + kadmin_del.c \ + kadmin_done.c + +OBJS = \ + kadmin.o \ + kadmin_add.o \ + kadmin_adr.o \ + kadmin_cpr.o \ + kadmin_inq.o \ + kadmin_msnd.o \ + kadmin_mod.o \ + kadmin_cpw.o \ + kadmin_del.o \ + kadmin_done.o + +ErrorTableObjectRule() + +all:: kadmin + +NormalProgramTarget(kadmin,$(OBJS),$(KDBDEPLIB) $(DEPKLIB), $(KLIB) ,) +Krb5InstallClientProgram(kadmin) + +clean:: + +DependTarget() diff --git a/src/kadmin/client/kadmin.M b/src/kadmin/client/kadmin.M new file mode 100644 index 000000000..e69de29bb diff --git a/src/kadmin/client/kadmin.c b/src/kadmin/client/kadmin.c new file mode 100644 index 000000000..91887d8a8 --- /dev/null +++ b/src/kadmin/client/kadmin.c @@ -0,0 +1,773 @@ +/* + * $Source$ + * $Author$ + * + * Copyright 1988 by the Massachusetts Institute of Technology. + * + * For copying and distribution information, please see the file + * . + * + */ + +/* + * 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 +#include +#include +#include +#include +#include +#include +#ifndef __convex__ +#include +#endif +#include +#include + +#ifndef MAXPATHLEN +#define MAXPATHLEN 1024 +#endif + +#include + +#include +#include +#include +#include +#include + +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 */ + 0))) { + fprintf(stderr, "Error %s while building client name!\n"); + krb5_free_addresses(my_addresses); + return(1); + } + + (void) sprintf(prompt,"Password for %s: ", (char *) client_name); + + if ((password = (char *) calloc (1, 255)) == NULL) { + fprintf(stderr, "No Memory for Retrieving Admin Password!\n"); + return(1); + } + + pwsize = 255; + if ((retval = krb5_read_password( + prompt, + 0, + password, + &pwsize) || pwsize == 0)) { + fprintf(stderr, "Error while reading password for '%s'!\n", + client_name); + free(password); + krb5_free_addresses(my_addresses); + return(1); + } + + /* Build Request for Initial Credentials */ + if ((retval = krb5_get_in_tkt_with_password( + 0, /* options */ + my_addresses, + KRB5_PADATA_ENC_RANDOM, /* do random preauth */ + ETYPE_DES_CBC_CRC, /* etype */ + KEYTYPE_DES, + password, + cache, + &my_creds, + 0 ))) { + fprintf(stderr, "\nUnable to Get Initial Credentials : %s!\n", + error_message(retval)); + (void) memset(password, 0, pwsize); + free(password); + krb5_free_addresses(my_addresses); + return(1); + } + + /* Do NOT Forget to zap password */ + memset((char *) password, 0, pwsize); + free(password); + krb5_free_addresses(my_addresses); + return(0); +} + +krb5_error_code +adm5_init_link( realm_of_server, local_socket) +krb5_data *realm_of_server; +int * local_socket; + +{ + struct servent *service_process; /* service we will talk to */ + struct hostent *remote_host; /* host we will talk to */ + char **hostlist; + int namelen; + int i; + + krb5_error_code retval; + + /* clear out the structure first */ + (void) memset((char *)&remote_sin, 0, sizeof(remote_sin)); + + if ((service_process = getservbyname(CPW_SNAME, "tcp")) == NULL) { + fprintf(stderr, "Unable to find Service (%s) Check services file!\n", + CPW_SNAME); + return(1); + } + + /* Copy the Port Number */ + remote_sin.sin_port = service_process->s_port; + + hostlist = 0; + + /* Identify all Hosts Associated with this Realm */ + if ((retval = krb5_get_krbhst (realm_of_server, &hostlist))) { + fprintf(stderr, "krb5_get_krbhst: Unable to Determine Server Name!\n"); + return(retval); + } + + if (hostlist[0] == 0) { + fprintf(stderr, "No hosts found!\n"); + return KRB5_REALM_UNKNOWN; + } + + for (i=0; hostlist[i]; i++) { + remote_host = gethostbyname(hostlist[i]); + if (remote_host != 0) { + + /* set up the address of the foreign socket for connect() */ + remote_sin.sin_family = remote_host->h_addrtype; + (void) memcpy((char *) &remote_sin.sin_addr, + (char *) remote_host->h_addr, + sizeof(remote_host->h_addr)); + break; /* Only Need one */ + } + } + + krb5_free_krbhst(hostlist); + + /* open a TCP socket */ + *local_socket = socket(PF_INET, SOCK_STREAM, 0); + if (*local_socket < 0) { + retval = errno; + fprintf(stderr, "Cannot Open Socket!\n"); + return retval; + } + /* connect to the server */ + if (connect(*local_socket, &remote_sin, sizeof(remote_sin)) < 0) { + retval = errno; + fprintf(stderr, "Cannot Connect to Socket!\n"); + close(*local_socket); + return retval; + } + + /* find out who I am, now that we are connected and therefore bound */ + namelen = sizeof(local_sin); + if (getsockname(*local_socket, + (struct sockaddr *) &local_sin, &namelen) < 0) { + retval = errno; + fprintf(stderr, "Cannot Perform getsockname!\n"); + close(*local_socket); + return retval; + } + return 0; +} + +void +get_def_princ(client) + krb5_principal *client; +{ + krb5_ccache cache = NULL; + struct passwd *pw; + int retval; + char client_name[755]; + krb5_flags cc_flags; + + /* Identify Default Credentials Cache */ + if (retval = krb5_cc_default(&cache)) { + fprintf(stderr, "Error while getting default ccache!\n"); + exit(1); + } + + /* + * Attempt to Modify Credentials Cache + * retval == 0 ==> ccache Exists - Use It + * retval == ENOENT ==> No Entries, but ccache Exists + * retval != 0 ==> Assume ccache does NOT Exist + */ + cc_flags = 0; + if (retval = krb5_cc_set_flags(cache, cc_flags)) { + /* Search passwd file for client */ + pw = getpwuid((int) getuid()); + if (pw) { + (void) strcpy(client_name, pw->pw_name); + if (!strncmp("root", client_name, strlen(client_name))) { + fprintf(stderr, + "root is not a valid Adimnistrator\n!\n"); + usage(); + } + } else { + fprintf(stderr, + "Unable to Identify Principal from Password File!\n"); + retval = 1; + usage(); + } + + /* Use this to get default_realm and format client_name */ + if ((retval = krb5_parse_name(client_name, client))) { + fprintf(stderr, "Unable to Parse Client Name!\n"); + usage(); + } + } else { + /* Read Client from Cache */ + if (retval = krb5_cc_get_principal(cache, client)) { + fprintf(stderr, + "Unable to Read Principal Credentials File!\n"); + exit(1); + } + + if (!strncmp("root", (*client)->data[0].data, + (*client)->data[0].length)) { + fprintf(stderr, "root is not a valid Administrator\n!\n"); + usage(); + } + + (void) krb5_cc_close(cache); + } +} + +usage() +{ + fprintf(stderr, "Usage: "); + fprintf(stderr, "kadmin [-n] [Administrator name]\n\n"); + fprintf(stderr, " If an Administrator name is not supplied, kadmin "); + fprintf(stderr, "will first\n attempt to locate the name from "); + fprintf(stderr, "the default ticket file, then\n by using the "); + fprintf(stderr, "username from the 'passwd' file.\n\n"); + fprintf(stderr, " For Cross Realm Obtain a ticket for 'Administrator "); + fprintf(stderr, "name' in the\n Destination realm or "); + fprintf(stderr, "specify the Destination Realm\n as part of the "); + fprintf(stderr, "Administrator name option.\n\n"); + fprintf(stderr, " Note: If the Administrator Name is not "); + fprintf(stderr, "supplied, then the \n"); + fprintf(stderr, " '/admin' instance will be appended to the "); + fprintf(stderr, "default name unless\n"); + fprintf(stderr, " the -n option is used.\n\n"); + exit(0); +} diff --git a/src/kadmin/client/kadmin_add.c b/src/kadmin/client/kadmin_add.c new file mode 100644 index 000000000..425e26ff4 --- /dev/null +++ b/src/kadmin/client/kadmin_add.c @@ -0,0 +1,275 @@ +/* + * $Source$ + * $Author$ + * + * Copyright 1988 by the Massachusetts Institute of Technology. + * + * For copying and distribution information, please see the file + * . + * + */ + +/* + * 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 +#include +#include +#include +#include +#ifndef __convex__ +#include +#endif +#include + +#include + +#include + +#include +#include +#include +#include +#include + +krb5_error_code + kadm_add_user(my_creds, rep_ret, local_addr, foreign_addr, + local_socket, seqno, oper_type, principal) +krb5_creds *my_creds; +krb5_ap_rep_enc_part *rep_ret; +krb5_address *local_addr, *foreign_addr; +int *local_socket; +krb5_int32 *seqno; +int oper_type; +char *principal; +{ + krb5_data msg_data, inbuf; + kadmin_requests rd_priv_resp; + char username[255]; + char *password; + int pwsize; + int count; + krb5_error_code retval; /* return code */ + + if ((inbuf.data = (char *) calloc(1, 3 + sizeof(username))) == (char *) 0) { + fprintf(stderr, "No memory for command!\n"); + return(1); + } + + inbuf.data[0] = KADMIN; + inbuf.data[1] = oper_type; + inbuf.data[2] = SENDDATA2; + + if (principal && principal[0] != '\0') + strcpy(username, principal); + else { + count = 0; + do { + fprintf(stdout, "\nName of Principal to be Added: "); + fgets(username, sizeof(username), stdin); + if (username[0] == '\n') + fprintf(stderr, "Invalid Principal name!\n"); + count++; + } while (username[0] == '\n' && count < 3); + } + + if (username[0] == '\n') { + fprintf(stderr, "Aborting!!\n\n"); + return(1); + } + + username[strlen(username) -1] = '\0'; + + (void) memcpy( inbuf.data + 3, username, strlen(username)); + inbuf.length = strlen(username) + 3; + + if ((retval = krb5_mk_priv(&inbuf, + ETYPE_DES_CBC_CRC, + &my_creds->keyblock, + local_addr, + foreign_addr, + *seqno, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data))) { + fprintf(stderr, "Error during Second Message Encoding: %s!\n", + error_message(retval)); + free(inbuf.data); + return(1); + } + free(inbuf.data); + + /* write private message to server */ + if (krb5_write_message(local_socket, &msg_data)){ + fprintf(stderr, "Write Error During Second Message Transmission!\n"); + return(1); + } + + free(msg_data.data); + + if (retval = krb5_read_message(local_socket, &inbuf)){ + fprintf(stderr, "Read Error During Second Reply: %s!\n", + error_message(retval)); + return(1); + } + + if (retval = krb5_rd_priv(&inbuf, + &my_creds->keyblock, + foreign_addr, + local_addr, + rep_ret->seq_number, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data)) { + fprintf(stderr, "Error during Second Read Decoding :%s!\n", + error_message(retval)); + free(inbuf.data); + return(1); + } + free(inbuf.data); + + if (msg_data.data[2] == KADMBAD) { + fprintf(stderr, "Principal Already Exists!\n\n"); + return(0); + } + +#ifdef MACH_PASS + pwsize = msg_data.length; + if ((password = (char *) calloc (1, pwsize)) == (char *) 0) { + fprintf(stderr, "No Memory for allocation of password!\n"); + retval = 1; + free(msg_data.data); + return(1); + } + + memcpy(password, msg_data.data, pwsize); + memset(msg_data.data, 0, pwsize); + password[pwsize] = '\0'; + fprintf(stdout, "\nPassword for \"%s\" is \"%s\"\n", username, password); + memset(password, 0, pwsize); + free(password); + fprintf(stdout, "\nThis password can only be used to execute kpasswd\n\n"); + + free(msg_data.data); + + if ((inbuf.data = (char *) calloc(1, 2)) == (char *) 0) { + fprintf(stderr, "No memory for command!\n"); + return(1); + } + + inbuf.data[0] = KADMIN; + inbuf.data[1] = KADMGOOD; + inbuf.length = 2; + +#else + + if ((password = (char *) calloc (1, ADM_MAX_PW_LENGTH+1)) == (char *) 0) { + fprintf(stderr, "No Memory for allocation of password!\n"); + return(1); + } + + pwsize = ADM_MAX_PW_LENGTH+1; + + putchar('\n'); + if (retval = krb5_read_password( + DEFAULT_PWD_STRING1, + DEFAULT_PWD_STRING2, + password, + &pwsize)) { + fprintf(stderr, "Error while reading new password for %s: %s!\n", + username, error_message(retval)); + (void) memset((char *) password, 0, ADM_MAX_PW_LENGTH+1); + free(password); + return(1); + } + + if ((inbuf.data = (char *) calloc(1, strlen(password) + 1)) == (char *) 0) { + fprintf(stderr, "No Memory for allocation of buffer!\n"); + (void) memset((char *) password, 0, ADM_MAX_PW_LENGTH+1); + free(password); + return(1); + } + + inbuf.length = strlen(password); + (void) memcpy(inbuf.data, password, strlen(password)); + free(password); + +#endif /* MACH_PASS */ + + if ((retval = krb5_mk_priv(&inbuf, + ETYPE_DES_CBC_CRC, + &my_creds->keyblock, + local_addr, + foreign_addr, + *seqno, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data))) { + fprintf(stderr, "Error during Second Message Encoding: %s!\n", + error_message(retval)); + free(inbuf.data); + return(1); + } + free(inbuf.data); + + /* write private message to server */ + if (krb5_write_message(local_socket, &msg_data)){ + fprintf(stderr, "Write Error During Second Message Transmission!\n"); + return(1); + } + free(msg_data.data); + + /* Ok Now let's get the final private message */ + if (retval = krb5_read_message(local_socket, &inbuf)){ + fprintf(stderr, "Read Error During Final Reply: %s!\n", + error_message(retval)); + retval = 1; + } + + if ((retval = krb5_rd_priv(&inbuf, + &my_creds->keyblock, + foreign_addr, + local_addr, + rep_ret->seq_number, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data))) { + fprintf(stderr, "Error during Final Read Decoding :%s!\n", + error_message(retval)); + free(inbuf.data); + return(1); + } + free(inbuf.data); + + memcpy(&rd_priv_resp.appl_code, msg_data.data, 1); + memcpy(&rd_priv_resp.oper_code, msg_data.data + 1, 1); + memcpy(&rd_priv_resp.retn_code, msg_data.data + 2, 1); + + free(msg_data.data); + + if (!((rd_priv_resp.appl_code == KADMIN) && + (rd_priv_resp.retn_code == KADMGOOD))) { + fprintf(stderr, "Generic Error During kadmin Addition!\n"); + retval = 1; + } else { + fprintf(stderr, "\nDatabase Addition Successful.\n"); + } + return(retval); +} diff --git a/src/kadmin/client/kadmin_adr.c b/src/kadmin/client/kadmin_adr.c new file mode 100644 index 000000000..e52e80acd --- /dev/null +++ b/src/kadmin/client/kadmin_adr.c @@ -0,0 +1,158 @@ +/* + * $Source$ + * $Author$ + * + * Copyright 1988 by the Massachusetts Institute of Technology. + * + * For copying and distribution information, please see the file + * . + * + */ + +/* + * 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 +#include +#include +#include +#include +#ifndef __convex__ +#include +#endif +#include + +#include + +#include + +#include +#include +#include +#include +#include + +krb5_error_code + kadm_add_user_rnd(my_creds, rep_ret, local_addr, foreign_addr, + local_socket, seqno, principal) +krb5_creds *my_creds; +krb5_ap_rep_enc_part *rep_ret; +krb5_address *local_addr, *foreign_addr; +int *local_socket; +krb5_int32 *seqno; +char *principal; +{ + krb5_data msg_data, inbuf; + kadmin_requests rd_priv_resp; + char username[755]; + int count; + krb5_error_code retval; /* return code */ + + if ((inbuf.data = (char *) calloc(1, 3 + sizeof(username))) == (char *) 0) { + fprintf(stderr, "No memory for command!\n"); + return(1); + } + + inbuf.data[0] = KADMIN; + inbuf.data[1] = ADROPER; + inbuf.data[2] = SENDDATA2; + + if (principal && principal[0] != '\0') + strcpy(username, principal); + else { + count = 0; + do { + fprintf(stdout, "\nName of Principal to be Added: "); + fgets(username, sizeof(username), stdin); + if (username[0] == '\n') + fprintf(stderr, "Invalid Principal name!\n"); + count++; + } + while (username[0] == '\n' && count < 3); + + if (username[0] == '\n') { + fprintf(stderr, "Aborting!!\n\n"); + return(1); + } + username[strlen(username) -1] = '\0'; + } + + + (void) memcpy( inbuf.data + 3, username, strlen(username)); + inbuf.length = strlen(username) + 3; + + if ((retval = krb5_mk_priv(&inbuf, + ETYPE_DES_CBC_CRC, + &my_creds->keyblock, + local_addr, + foreign_addr, + *seqno, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data))) { + fprintf(stderr, "Error during Second Message Encoding: %s!\n", + error_message(retval)); + free(inbuf.data); + return(1); + } + free(inbuf.data); + + /* write private message to server */ + if (krb5_write_message(local_socket, &msg_data)){ + fprintf(stderr, "Write Error During Second Message Transmission!\n"); + return(1); + } + + free(msg_data.data); + + /* Ok Now let's get the final private message */ + if (retval = krb5_read_message(local_socket, &inbuf)){ + fprintf(stderr, "Read Error During Final Reply: %s!\n", + error_message(retval)); + retval = 1; + } + + if ((retval = krb5_rd_priv(&inbuf, + &my_creds->keyblock, + foreign_addr, + local_addr, + rep_ret->seq_number, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data))) { + fprintf(stderr, "Error during Final Read Decoding :%s!\n", + error_message(retval)); + free(inbuf.data); + return(1); + } + free(inbuf.data); + + memcpy(&rd_priv_resp.appl_code, msg_data.data, 1); + memcpy(&rd_priv_resp.oper_code, msg_data.data + 1, 1); + memcpy(&rd_priv_resp.retn_code, msg_data.data + 2, 1); + + free(msg_data.data); + + if (!((rd_priv_resp.appl_code == KADMIN) && + (rd_priv_resp.retn_code == KADMGOOD))) + fprintf(stderr, "Principal already exists!\n"); + else + fprintf(stderr, "\nDatabase Addition Successful.\n"); + + return(retval); +} diff --git a/src/kadmin/client/kadmin_cpr.c b/src/kadmin/client/kadmin_cpr.c new file mode 100644 index 000000000..41f53eb87 --- /dev/null +++ b/src/kadmin/client/kadmin_cpr.c @@ -0,0 +1,160 @@ +/* + * $Source$ + * $Author$ + * + * Copyright 1988 by the Massachusetts Institute of Technology. + * + * For copying and distribution information, please see the file + * . + * + */ + +/* + * 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 +#include +#include +#include +#include +#include +#ifndef __convex__ +#include +#endif +#include + +#include + +#include + +#include +#include +#include +#include +#include + +krb5_error_code +kadm_cpw_user_rnd(my_creds, rep_ret, local_addr, foreign_addr, + local_socket, seqno, principal) +krb5_creds *my_creds; +krb5_ap_rep_enc_part *rep_ret; +krb5_address *local_addr, *foreign_addr; +int *local_socket; +krb5_int32 *seqno; +char *principal; +{ + krb5_data msg_data, inbuf; + kadmin_requests rd_priv_resp; + char username[755]; + int count; + krb5_error_code retval; /* return code */ + + if ((inbuf.data = (char *) calloc(1, 3 + sizeof(username))) == (char *) 0) { fprintf(stderr, "No memory for command!\n"); + exit(1); + } + + inbuf.data[0] = KADMIN; + inbuf.data[1] = CHROPER; + inbuf.data[2] = SENDDATA2; + + if (principal && principal[0] != '\0') + strcpy(username, principal); + else { + count = 0; + do { + fprintf(stdout, + "\nName of Principal Whose Password is to Change: "); + fgets(username, sizeof(username), stdin); + if (username[0] == '\n') + fprintf(stderr, "Invalid Principal name!\n"); + count++; + } + while (username[0] == '\n' && count < 3); + + if (username[0] == '\n') { + fprintf(stderr, "Aborting!!\n\n"); + return(1); + } + username[strlen(username) -1] = '\0'; + } + + (void) memcpy( inbuf.data + 3, username, strlen(username)); + inbuf.length = strlen(username) + 3; + + /* Transmit Principal Name */ + if ((retval = krb5_mk_priv(&inbuf, + ETYPE_DES_CBC_CRC, + &my_creds->keyblock, + local_addr, + foreign_addr, + *seqno, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data))) { + fprintf(stderr, "Error during Second Message Encoding: %s!\n", + error_message(retval)); + free(inbuf.data); + return(1); + } + free(inbuf.data); + + /* write private message to server */ + if (krb5_write_message(local_socket, &msg_data)){ + fprintf(stderr, "Write Error During Second Message Transmission!\n"); + return(1); + } + free(msg_data.data); + + /* Ok Now let's get the final private message */ + if (retval = krb5_read_message(local_socket, &inbuf)){ + fprintf(stderr, "Read Error During Final Reply: %s!\n", + error_message(retval)); + retval = 1; + } + + if ((retval = krb5_rd_priv(&inbuf, + &my_creds->keyblock, + foreign_addr, + local_addr, + rep_ret->seq_number, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data))) { + fprintf(stderr, "Error during Final Read Decoding :%s!\n", + error_message(retval)); + free(inbuf.data); + return(1); + } + free(inbuf.data); + + memcpy(&rd_priv_resp.appl_code, msg_data.data, 1); + memcpy(&rd_priv_resp.oper_code, msg_data.data + 1, 1); + memcpy(&rd_priv_resp.retn_code, msg_data.data + 2, 1); + + free(msg_data.data); + + if (!((rd_priv_resp.appl_code == KADMIN) && + (rd_priv_resp.retn_code == KADMGOOD))) + fprintf(stderr, "Principal does NOT exist!\n"); + else + fprintf(stderr, "\nPassword Modification Successful.\n"); + + return(0); +} + + diff --git a/src/kadmin/client/kadmin_cpw.c b/src/kadmin/client/kadmin_cpw.c new file mode 100644 index 000000000..697e1bde0 --- /dev/null +++ b/src/kadmin/client/kadmin_cpw.c @@ -0,0 +1,281 @@ +/* + * $Source$ + * $Author$ + * + * Copyright 1988 by the Massachusetts Institute of Technology. + * + * For copying and distribution information, please see the file + * . + * + */ + +/* + * 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 +#include +#include +#include +#include +#include +#ifndef __convex__ +#include +#endif +#include + +#include + +#include + +#include +#include +#include +#include +#include + +krb5_error_code +kadm_cpw_user(my_creds, rep_ret, local_addr, foreign_addr, + local_socket, seqno, oper_type, principal) +krb5_creds *my_creds; +krb5_ap_rep_enc_part *rep_ret; +krb5_address *local_addr, *foreign_addr; +int *local_socket; +krb5_int32 *seqno; +int oper_type; +char *principal; +{ + krb5_data msg_data, inbuf; + kadmin_requests rd_priv_resp; + char username[255]; + char *password; + int pwsize; + int count; + krb5_error_code retval; /* return code */ + + if ((inbuf.data = (char *) calloc(1, 3 + sizeof(username))) == (char *) 0) { fprintf(stderr, "No memory for command!\n"); + exit(1); + } + + inbuf.data[0] = KADMIN; + inbuf.data[1] = oper_type; + inbuf.data[2] = SENDDATA2; + + if (principal && principal[0] != '\0') + strcpy(username, principal); + else { + count = 0; + do { + fprintf(stdout, + "\nName of Principal Whose Password is to Change: "); + fgets(username, sizeof(username), stdin); + if (username[0] == '\n') + fprintf(stderr, "Invalid Principal name!\n"); + count++; + } + while (username[0] == '\n' && count < 3); + + if (username[0] == '\n') { + fprintf(stderr, "Aborting!!\n\n"); + return(1); + } + + username[strlen(username) -1] = '\0'; + } + + (void) memcpy( inbuf.data + 3, username, strlen(username)); + inbuf.length = strlen(username) + 3; + + /* Transmit Principal Name */ + if ((retval = krb5_mk_priv(&inbuf, + ETYPE_DES_CBC_CRC, + &my_creds->keyblock, + local_addr, + foreign_addr, + *seqno, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data))) { + fprintf(stderr, "Error during Second Message Encoding: %s!\n", + error_message(retval)); + free(inbuf.data); + return(1); + } + free(inbuf.data); + + /* write private message to server */ + if (krb5_write_message(local_socket, &msg_data)){ + fprintf(stderr, "Write Error During Second Message Transmission!\n"); + return(1); + } + free(msg_data.data); + + if (retval = krb5_read_message(local_socket, &inbuf)){ + fprintf(stderr, "Read Error During Second Reply: %s!\n", + error_message(retval)); + return(1); + } + + if ((retval = krb5_rd_priv(&inbuf, + &my_creds->keyblock, + foreign_addr, + local_addr, + rep_ret->seq_number, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data))) { + fprintf(stderr, "Error during Second Read Decoding :%s!\n", + error_message(retval)); + free(inbuf.data); + return(1); + } + free(inbuf.data); + + if (msg_data.data[2] == KADMBAD) { + fprintf(stderr, "Principal Does NOT Exist!\n\n"); + return(0); + } + + if ((oper_type == CHGOPER && msg_data.data[3] == KRB5_KDB_SALTTYPE_V4) || + (oper_type == CH4OPER && msg_data.data[3] == KRB5_KDB_SALTTYPE_NORMAL)) + fprintf(stderr, "WARNING: Changing Principal Salt type to %s!\n", + (msg_data.data[3] == KRB5_KDB_SALTTYPE_V4) ? + "Version 5 Normal" : "Version 4"); + +#ifdef MACH_PASS /* Machine-generated passwords */ + pwsize = msg_data.length; + if ((password = (char *) calloc (1, pwsize)) == (char *) 0) { + fprintf(stderr, "No Memory for allocation of password!\n"); + return(1); + } + + memcpy(password, msg_data.data, pwsize); + memset(msg_data.data, 0, pwsize); + free(msg_data.data); + password[pwsize] = '\0'; + fprintf(stdout, "\nPassword for \"%s\" is \"%s\"\n", username, password); + memset(password, 0, pwsize); + free(password); + fprintf(stdout, "\nThis password can only be used to execute kpasswd\n\n"); + + if ((inbuf.data = (char *) calloc(1, 2)) == (char *) 0) { + fprintf(stderr, "No memory for command!\n"); + return(1); + } + + inbuf.data[0] = KADMIN; + inbuf.data[1] = KADMGOOD; + inbuf.length = 2; + +#else + + if ((password = (char *) calloc (1, ADM_MAX_PW_LENGTH+1)) == (char *) 0) { + fprintf(stderr, "No Memory for allocation of password!\n"); + return(1); + } + + pwsize = ADM_MAX_PW_LENGTH+1; + + putchar('\n'); + if ((retval = krb5_read_password( + DEFAULT_PWD_STRING1, + DEFAULT_PWD_STRING2, + password, + &pwsize))) { + fprintf(stderr, "Error while reading new password for %s: %s!\n", + username, error_message(retval)); + (void) memset((char *) password, 0, ADM_MAX_PW_LENGTH+1); + free(password); + return(1); + } + + if ((inbuf.data = (char *) calloc (1, strlen(password) + 1)) == + (char *) 0) { + fprintf(stderr, "No Memory for allocation of buffer!\n"); + (void) memset((char *) password, 0, ADM_MAX_PW_LENGTH+1); + free(password); + return(1); /* No Memory */ + } + + inbuf.length = strlen(password); + (void) memcpy(inbuf.data, password, strlen(password)); + free(password); + +#endif /* MACH_PASS */ + + if ((retval = krb5_mk_priv(&inbuf, + ETYPE_DES_CBC_CRC, + &my_creds->keyblock, + local_addr, + foreign_addr, + *seqno, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data))) { + fprintf(stderr, "Error during Second Message Encoding: %s!\n", + error_message(retval)); + free(inbuf.data); + return(1); + } + free(inbuf.data); + + /* write private message to server */ + if (krb5_write_message(local_socket, &msg_data)){ + fprintf(stderr, "Write Error During Second Message Transmission!\n"); + return(1); + } + free(msg_data.data); + + /* Ok Now let's get the final private message */ + if (retval = krb5_read_message(local_socket, &inbuf)){ + fprintf(stderr, "Read Error During Final Reply: %s!\n", + error_message(retval)); + retval = 1; + } + + if ((retval = krb5_rd_priv(&inbuf, + &my_creds->keyblock, + foreign_addr, + local_addr, + rep_ret->seq_number, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data))) { + fprintf(stderr, "Error during Final Read Decoding :%s!\n", + error_message(retval)); + free(inbuf.data); + return(1); + } + free(inbuf.data); + + memcpy(&rd_priv_resp.appl_code, msg_data.data, 1); + memcpy(&rd_priv_resp.oper_code, msg_data.data + 1, 1); + memcpy(&rd_priv_resp.retn_code, msg_data.data + 2, 1); + + free(msg_data.data); + + if (!((rd_priv_resp.appl_code == KADMIN) && + (rd_priv_resp.retn_code == KADMGOOD))) { + fprintf(stderr, "Generic Error During kadmin Password Modification!\n"); + return(1); + } else { + fprintf(stderr, "\nPassword Modification Successful.\n"); + } + return(0); +} diff --git a/src/kadmin/client/kadmin_del.c b/src/kadmin/client/kadmin_del.c new file mode 100644 index 000000000..c76aa1e0b --- /dev/null +++ b/src/kadmin/client/kadmin_del.c @@ -0,0 +1,153 @@ +/* + * $Source$ + * $Author$ + * + * Copyright 1988 by the Massachusetts Institute of Technology. + * + * For copying and distribution information, please see the file + * . + * + */ + +/* + * 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 +#include +#include +#include +#include +#ifndef __convex__ +#include +#endif +#include + +#include + +#include +#include +#include +#include +#include + +krb5_error_code +kadm_del_user(my_creds, rep_ret, local_addr, foreign_addr, + local_socket, seqno, principal) +krb5_creds *my_creds; +krb5_ap_rep_enc_part *rep_ret; +krb5_address *local_addr, *foreign_addr; +int *local_socket; +krb5_int32 *seqno; +char *principal; +{ + krb5_data msg_data, inbuf; + kadmin_requests rd_priv_resp; + char username[755]; + int count; + krb5_error_code retval; /* return code */ + + if ((inbuf.data = (char *) calloc(1, 3 + sizeof(username))) == (char *) 0) { + fprintf(stderr, "No memory for command!\n"); + return(1); + } + + inbuf.data[0] = KADMIN; + inbuf.data[1] = DELOPER; + inbuf.data[2] = SENDDATA2; + + if (principal && principal[0] != '\0') + strcpy(username, principal); + else { + count = 0; + do { + fprintf(stdout, "\nName of Principal to be Deleted: "); + fgets(username, sizeof(username), stdin); + if (username[0] == '\n') + fprintf(stderr, "Invalid Principal name!\n"); + count++; + } + while (username[0] == '\n' && count < 3); + + if (username[0] == '\n') { + fprintf(stderr, "Aborting!!\n\n"); + return(1); + } + + username[strlen(username) -1] = '\0'; + } + + (void) memcpy( inbuf.data + 3, username, strlen(username)); + inbuf.length = strlen(username) + 3; + + if ((retval = krb5_mk_priv(&inbuf, + ETYPE_DES_CBC_CRC, + &my_creds->keyblock, + local_addr, + foreign_addr, + *seqno, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data))) { + fprintf(stderr, "Error during Second Message Encoding: %s!\n", + error_message(retval)); + free(inbuf.data); + return(1); + } + free(inbuf.data); + + /* write private message to server */ + if (krb5_write_message(local_socket, &msg_data)){ + fprintf(stderr, "Write Error During Second Message Transmission!\n"); + return(1); + } + free(msg_data.data); + + /* Ok Now let's get the final private message */ + if (retval = krb5_read_message(local_socket, &inbuf)){ + fprintf(stderr, "Read Error During Final Reply: %s!\n", + error_message(retval)); + return(1); + } + + if ((retval = krb5_rd_priv(&inbuf, + &my_creds->keyblock, + foreign_addr, + local_addr, + rep_ret->seq_number, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data))) { + fprintf(stderr, "Error during Second Decoding :%s!\n", + error_message(retval)); + return(1); + } + + memcpy(&rd_priv_resp.appl_code, msg_data.data, 1); + memcpy(&rd_priv_resp.oper_code, msg_data.data + 1, 1); + memcpy(&rd_priv_resp.retn_code, msg_data.data + 2, 1); + + free(inbuf.data); + free(msg_data.data); + if (!((rd_priv_resp.appl_code == KADMIN) && + (rd_priv_resp.retn_code == KADMGOOD))) + fprintf(stderr, "Principal Does NOT Exist!\n"); + else + fprintf(stderr, "\nDatabase Deletion Successful.\n"); + + return(0); +} diff --git a/src/kadmin/client/kadmin_done.c b/src/kadmin/client/kadmin_done.c new file mode 100644 index 000000000..7ae8d579f --- /dev/null +++ b/src/kadmin/client/kadmin_done.c @@ -0,0 +1,93 @@ +/* + * $Source$ + * $Author$ + * + * Copyright 1988 by the Massachusetts Institute of Technology. + * + * For copying and distribution information, please see the file + * . + * + */ + +/* + * 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 +#include +#include +#include +#include +#ifndef __convex__ +#include +#endif +#include + +#include + +#include +#include +#include +#include +#include + +krb5_error_code +kadm_done(my_creds, rep_ret, local_addr, foreign_addr, local_socket, seqno) +krb5_creds *my_creds; +krb5_ap_rep_enc_part *rep_ret; +krb5_address *local_addr, *foreign_addr; +int *local_socket; +krb5_int32 *seqno; +{ + krb5_data msg_data, inbuf; + krb5_error_code retval; /* return code */ + + /* XXX 755 was sizeof( char username[755]) */ + if ((inbuf.data = (char *) calloc(1, 8 + 755)) == (char *) 0) { + fprintf(stderr, "No memory for command!\n"); + exit(1); + } + + inbuf.data[0] = KADMIN; + inbuf.data[1] = COMPLETE; + inbuf.data[2] = SENDDATA2; + inbuf.data[3] = 0xff; + (void) memset( inbuf.data + 4, 0, 4); + inbuf.length = 16; + + if ((retval = krb5_mk_priv(&inbuf, + ETYPE_DES_CBC_CRC, + &my_creds->keyblock, + local_addr, + foreign_addr, + *seqno, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data))) { + fprintf(stderr, "Error during Second Message Encoding: %s!\n", + error_message(retval)); + return(1); + } + free(inbuf.data); + + /* write private message to server */ + if (krb5_write_message(local_socket, &msg_data)){ + fprintf(stderr, "Write Error During Second Message Transmission!\n"); + return(1); + } + free(msg_data.data); + return(0); +} diff --git a/src/kadmin/client/kadmin_inq.c b/src/kadmin/client/kadmin_inq.c new file mode 100644 index 000000000..0b7b04289 --- /dev/null +++ b/src/kadmin/client/kadmin_inq.c @@ -0,0 +1,238 @@ +/* + * $Source$ + * $Author$ + * + * Copyright 1988 by the Massachusetts Institute of Technology. + * + * For copying and distribution information, please see the file + * . + * + */ + +/* + * 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 +#include +#include +#include +#include +#include +#ifndef __convex__ +#include +#endif +#include + +#include + +#include +#include +#include +#include +#include + +krb5_error_code +kadm_inq_user(my_creds, rep_ret, local_addr, foreign_addr, + local_socket, seqno, principal) +krb5_creds *my_creds; +krb5_ap_rep_enc_part *rep_ret; +krb5_address *local_addr, *foreign_addr; +int *local_socket; +krb5_int32 *seqno; +char *principal; +{ + krb5_data msg_data, inbuf; + kadmin_requests rd_priv_resp; + char username[755]; + int count; + krb5_error_code retval; /* return code */ + + char *my_data; + + if ((inbuf.data = (char *) calloc(1, 3 + sizeof(username))) == (char *) 0) { + fprintf(stderr, "No memory for command!\n"); + return(1); + } + + inbuf.data[0] = KADMIN; + inbuf.data[1] = INQOPER; + inbuf.data[2] = SENDDATA2; + + if (principal && principal[0] != '\0') + strcpy(username, principal); + else { + count = 0; + do { + fprintf(stdout, "\nName of Principal to be Displayed: "); + fgets(username, sizeof(username), stdin); + if (username[0] == '\n') + fprintf(stderr, "Invalid Principal name!\n"); + count++; + } + while (username[0] == '\n' && count < 3); + + if (username[0] == '\n') { + fprintf(stderr, "Aborting!!\n\n"); + return(1); + } + + username[strlen(username) -1] = '\0'; + } + + (void) memcpy( inbuf.data + 3, username, strlen(username)); + inbuf.length = strlen(username) + 3; + + if (retval = krb5_mk_priv(&inbuf, + ETYPE_DES_CBC_CRC, + &my_creds->keyblock, + local_addr, + foreign_addr, + *seqno, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data)) { + fprintf(stderr, "Error during Second Message Encoding: %s!\n", + error_message(retval)); + free(inbuf.data); + return(1); + } + free(inbuf.data); + + /* write private message to server */ + if (krb5_write_message(local_socket, &msg_data)){ + fprintf(stderr, "Write Error During Second Message Transmission!\n"); + return(1); + } + free(msg_data.data); + + /* Ok Now let's get the private message */ + if ((retval = krb5_read_message(local_socket, &inbuf))){ + fprintf(stderr, "Read Error During Second Reply: %s!\n", + error_message(retval)); + return(1); + } + + if (retval = krb5_rd_priv(&inbuf, + &my_creds->keyblock, + foreign_addr, + local_addr, + rep_ret->seq_number, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data)) { + fprintf(stderr, "Error during Second Read Decoding :%s!\n", + error_message(retval)); + free(inbuf.data); + return(1); + } + free(inbuf.data); + + if (!msg_data.data) { + fprintf(stderr, "kadm_inq_user: Error - empty message received!\n\n"); + return(0); + } + + if (msg_data.data[2] == KADMBAD) { + fprintf(stderr, "Principal Does Not Exist!\n\n"); + return(0); + } + + if ((my_data = (char *) calloc(1, msg_data.length + 1)) == (char *) 0) { + fprintf(stderr, "No Memory Allocating Inquiry Buffer!\n"); + return(1); + } + + (void) memcpy(my_data, msg_data.data, msg_data.length); + + /* Print Inquiry Information */ + fprintf(stdout, "%s\n", my_data); + free(my_data); + free(msg_data.data); + + if ((inbuf.data = (char *) calloc(1, 3)) == (char *) 0) { + fprintf(stderr, "inbuf.data allocation error!\n"); + return(1); + } + + inbuf.data[0] = KADMIN; + inbuf.data[1] = KADMGOOD; + inbuf.length = 2; + + if (retval = krb5_mk_priv(&inbuf, + ETYPE_DES_CBC_CRC, + &my_creds->keyblock, + local_addr, + foreign_addr, + *seqno, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data)) { + fprintf(stderr, "Error during Second Message Encoding: %s!\n", + error_message(retval)); + free(inbuf.data); + return(1); + } + free(inbuf.data); + + /* write private message to server */ + if (krb5_write_message(local_socket, &msg_data)){ + fprintf(stderr, "Write Error During Second Message Transmission!\n"); + free(msg_data.data); + return(1); + } + free(msg_data.data); + + /* Ok Now let's get the final private message */ + if (retval = krb5_read_message(local_socket, &inbuf)){ + fprintf(stderr, "Read Error During Final Reply: %s!\n", + error_message(retval)); + retval = 1; + } + + if (retval = krb5_rd_priv(&inbuf, + &my_creds->keyblock, + foreign_addr, + local_addr, + rep_ret->seq_number, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data)) { + fprintf(stderr, "Error during Final Read Decoding :%s!\n", + error_message(retval)); + free(inbuf.data); + return(1); + } + free(inbuf.data); + + memcpy(&rd_priv_resp.appl_code, msg_data.data, 1); + memcpy(&rd_priv_resp.oper_code, msg_data.data + 1, 1); + memcpy(&rd_priv_resp.retn_code, msg_data.data + 2, 1); + + free(msg_data.data); + + if (!((rd_priv_resp.appl_code == KADMIN) && + (rd_priv_resp.retn_code == KADMGOOD))) { + fprintf(stderr, "Generic Error During kadmin Inquiry!\n"); + retval = 1; + } else { + fprintf(stderr, "\nDatabase Inquiry Successful.\n"); + } + return(0); +} diff --git a/src/kadmin/client/kadmin_mod.c b/src/kadmin/client/kadmin_mod.c new file mode 100644 index 000000000..25a6587c1 --- /dev/null +++ b/src/kadmin/client/kadmin_mod.c @@ -0,0 +1,223 @@ +/* + * $Source$ + * $Author$ + * + * Copyright 1988 by the Massachusetts Institute of Technology. + * + * For copying and distribution information, please see the file + * . + * + */ + +/* + * 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 +#include +#include +#include +#include +#include +#ifndef __convex__ +#include +#endif +#include + +#include + +#include +#include +#include +#include +#include + +krb5_error_code +kadm_mod_user(my_creds, rep_ret, local_addr, foreign_addr, + local_socket, seqno, principal) +krb5_creds *my_creds; +krb5_ap_rep_enc_part *rep_ret; +krb5_address *local_addr, *foreign_addr; +int *local_socket; +krb5_int32 *seqno; +char *principal; +{ + krb5_data msg_data, inbuf; + kadmin_requests rd_priv_resp; + char username[755]; + int count; + krb5_error_code retval; /* return code */ + + if ((inbuf.data = (char *) calloc(1, 3 + sizeof(username))) == (char *) 0) { fprintf(stderr, "No memory for command!\n"); + exit(1); + } + + inbuf.data[0] = KADMIN; + inbuf.data[1] = MODOPER; + inbuf.data[2] = SENDDATA2; + + if (principal && principal[0] != '\0') + strcpy(username, principal); + else { + count = 0; + do { + fprintf(stdout, "\nName of Principal to be Modified: "); + fgets(username, sizeof(username), stdin); + if (username[0] == '\n') + fprintf(stderr, "Invalid Principal name!\n"); + count++; + } + while (username[0] == '\n' && count < 3); + + if (username[0] == '\n') { + fprintf(stderr, "Aborting!!\n\n"); + return(1); + } + + username[strlen(username) -1] = '\0'; + } + + (void) memcpy( inbuf.data + 3, username, strlen(username)); + inbuf.length = strlen(username) + 3; + + if ((retval = krb5_mk_priv(&inbuf, + ETYPE_DES_CBC_CRC, + &my_creds->keyblock, + local_addr, + foreign_addr, + *seqno, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data))) { + fprintf(stderr, "Error during Second Message Encoding: %s!\n", + error_message(retval)); + free(inbuf.data); + return(1); + } + free(inbuf.data); + + /* write private message to server */ + if (krb5_write_message(local_socket, &msg_data)){ + fprintf(stderr, "Write Error During Second Message Transmission!\n"); + return(1); + } + free(msg_data.data); + + /* Ok Now let's get the private message */ + if (retval = krb5_read_message(local_socket, &inbuf)){ + fprintf(stderr, "Read Error During Second Reply: %s!\n", + error_message(retval)); + return(1); + } + + if ((retval = krb5_rd_priv(&inbuf, + &my_creds->keyblock, + foreign_addr, + local_addr, + rep_ret->seq_number, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data))) { + fprintf(stderr, "Error during Second Read Decoding :%s!\n", + error_message(retval)); + free(inbuf.data); + return(1); + } + free(inbuf.data); + free(msg_data.data); + + if (msg_data.data[2] == KADMBAD) { + fprintf(stderr, "Principal Does NOT Exist!\n\n"); + return(0); + } + + kadm_snd_mod(my_creds, rep_ret, local_addr, + foreign_addr, local_socket, seqno); + + if ((inbuf.data = (char *) calloc(1, 2)) == (char *) 0) { + fprintf(stderr, "No memory for command!\n"); + return(1); + } + + + inbuf.data[0] = KADMIN; + inbuf.data[1] = KADMGOOD; + inbuf.data[2] = SENDDATA3; + inbuf.length = 3; + + if ((retval = krb5_mk_priv(&inbuf, + ETYPE_DES_CBC_CRC, + &my_creds->keyblock, + local_addr, + foreign_addr, + *seqno, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data))) { + fprintf(stderr, "Error during Second Message Encoding: %s!\n", + error_message(retval)); + free(inbuf.data); + return(1); + } + free(inbuf.data); + + /* write private message to server */ + if (krb5_write_message(local_socket, &msg_data)){ + fprintf(stderr, "Write Error During Second Message Transmission!\n"); + return(1); + } + free(msg_data.data); + + /* Ok Now let's get the final private message */ + if (retval = krb5_read_message(local_socket, &inbuf)){ + fprintf(stderr, "Read Error During Final Reply: %s!\n", + error_message(retval)); + retval = 1; + } + + if ((retval = krb5_rd_priv(&inbuf, + &my_creds->keyblock, + foreign_addr, + local_addr, + rep_ret->seq_number, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data))) { + fprintf(stderr, "Error during Final Read Decoding :%s!\n", + error_message(retval)); + free(inbuf.data); + return(1); + } + free(inbuf.data); + + memcpy(&rd_priv_resp.appl_code, msg_data.data, 1); + memcpy(&rd_priv_resp.oper_code, msg_data.data + 1, 1); + memcpy(&rd_priv_resp.retn_code, msg_data.data + 2, 1); + + free(msg_data.data); + + if (!((rd_priv_resp.appl_code == KADMIN) && + (rd_priv_resp.retn_code == KADMGOOD))) { + fprintf(stderr, "Error Performing kadmin service!\n"); + retval = 1; + } else { + fprintf(stderr, "\nDatabase Modification Successful.\n"); + } + return(0); +} diff --git a/src/kadmin/client/kadmin_msnd.c b/src/kadmin/client/kadmin_msnd.c new file mode 100644 index 000000000..41a36c117 --- /dev/null +++ b/src/kadmin/client/kadmin_msnd.c @@ -0,0 +1,320 @@ +/* + * $Source$ + * $Author$ + * + * Copyright 1988 by the Massachusetts Institute of Technology. + * + * For copying and distribution information, please see the file + * . + * + */ + +/* + * 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 +#include +#include +#include +#include +#include +#include +#ifndef __convex__ +#include +#endif +#include + +#ifndef MAXPATHLEN +#define MAXPATHLEN 1024 +#endif + +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +krb5_error_code +kadm_snd_mod(my_creds, rep_ret, local_addr, foreign_addr, local_socket, seqno) +krb5_creds *my_creds; +krb5_ap_rep_enc_part *rep_ret; +krb5_address *local_addr, *foreign_addr; +int *local_socket; +krb5_int32 *seqno; +{ + krb5_error_code retval; /* return code */ + krb5_data msg_data, inbuf; + char mod_type[10]; + char attrib[20]; + char version[10]; + int value; + int valid_command; + extern int errno; + int i; + + for ( ; ; ) { + valid_command = 0; +repeat1: +#ifdef SANDIA + fprintf(stdout, "\nParameter Type to be Modified (fcnt, vno, attr, or q): "); +#else + fprintf(stdout, "\nParameter Type to be Modified (vno, attr, or q): "); +#endif + + (void) fgets(mod_type, 10, stdin); + mod_type[strlen(mod_type) - 1] = '\0'; + + if ((inbuf.data = (char *) calloc(1, 80)) == (char *) 0) { + fprintf(stderr, "No memory for command!\n"); + exit(1); + } + + if (!strcmp(mod_type, "q")) { + free(inbuf.data); + goto alldone; + } +#ifdef SANDIA + if (!strcmp(mod_type, "fcnt")) { + valid_command = 1; +repeat_cnt: + fprintf(stdout, "\nFailure Count: "); + (void) fgets(version, sizeof(version), stdin); + /* Make sure version is null terminated */ + version[sizeof(version) -1] = '\0'; + /* Strip linefeed */ + if (version[strlen(version) - 1] == '\n') + version[strlen(version) - 1] = '\0'; + if (!strcmp(version, "q")) { + free(inbuf.data); + goto alldone; + } + value = -1; + sscanf(version,"%d",&value); + if (value < 0 || value > 10 ) { + fprintf(stderr, "Value must be between 0 and 10!\n"); + goto repeat_cnt; + } + inbuf.data[3] = KMODFCNT; + (void) memcpy(inbuf.data + 4, version, strlen(version)); + inbuf.length = strlen(version) + 4; + } +#endif + if (!strcmp(mod_type, "vno")) { + valid_command = 1; +repeat2: + fprintf(stdout, "\nVersion Number: "); + (void) fgets(version, sizeof(version), stdin); + /* Make sure version is null terminated */ + version[sizeof(version) -1] = '\0'; + /* Strip linefeed */ + if (version[strlen(version) - 1] == '\n') + version[strlen(version) - 1] = '\0'; + if (!strcmp(version, "q")) { + free(inbuf.data); + goto alldone; + } + value = -1; + sscanf(version,"%d",&value); + if (value < 0 || value > 255 ) { + fprintf(stderr, "Value must be between 0 and 255!\n"); + goto repeat2; + } + inbuf.data[3] = KMODVNO; + (void) memcpy(inbuf.data + 4, version, strlen(version)); + inbuf.length = strlen(version) + 4; + } + + if (!strcmp(mod_type, "attr")) { + valid_command = 1; +repeat3: + fprintf(stdout, "\nAttribute: "); + fgets(attrib, 20, stdin); + attrib[strlen(attrib) - 1] = '\0'; + for (i = 0; attrib[i] != '\0'; i++) + if (isupper(attrib[i])) + attrib[i] = tolower(attrib[i]); + + inbuf.data[3] = KMODATTR; + inbuf.data[4] = BADATTR; + inbuf.length = 5; + if (!strcmp(attrib, "post")) inbuf.data[4] = ATTRPOST; + if (!strcmp(attrib, "nopost")) inbuf.data[4] = ATTRNOPOST; + if (!strcmp(attrib, "forward")) inbuf.data[4] = ATTRFOR; + if (!strcmp(attrib, "noforward")) inbuf.data[4] = ATTRNOFOR; + if (!strcmp(attrib, "tgt")) inbuf.data[4] = ATTRTGT; + if (!strcmp(attrib, "notgt")) inbuf.data[4] = ATTRNOTGT; + if (!strcmp(attrib, "ren")) inbuf.data[4] = ATTRREN; + if (!strcmp(attrib, "noren")) inbuf.data[4] = ATTRNOREN; + if (!strcmp(attrib, "proxy")) inbuf.data[4] = ATTRPROXY; + if (!strcmp(attrib, "noproxy")) inbuf.data[4] = ATTRNOPROXY; + if (!strcmp(attrib, "dskey")) inbuf.data[4] = ATTRDSKEY; + if (!strcmp(attrib, "nodskey")) inbuf.data[4] = ATTRNODSKEY; + if (!strcmp(attrib, "lock")) inbuf.data[4] = ATTRLOCK; + if (!strcmp(attrib, "unlock")) inbuf.data[4] = ATTRUNLOCK; + if (!strcmp(attrib, "svr")) inbuf.data[4] = ATTRSVR; + if (!strcmp(attrib, "nosvr")) inbuf.data[4] = ATTRNOSVR; + +#ifdef SANDIA + if (!strcmp(attrib, "preauth")) inbuf.data[4] = ATTRPRE; + if (!strcmp(attrib, "nopreauth")) inbuf.data[4] = ATTRNOPRE; + if (!strcmp(attrib, "pwok")) inbuf.data[4] = ATTRPWOK; + if (!strcmp(attrib, "pwchange")) inbuf.data[4] = ATTRPWCHG; + if (!strcmp(attrib, "sid")) inbuf.data[4] = ATTRSID; + if (!strcmp(attrib, "nosid")) inbuf.data[4] = ATTRNOSID; +#endif + if (!strcmp(attrib, "q")){ + free(inbuf.data); + goto alldone; + } + if (inbuf.data[4] == BADATTR) { + fprintf(stderr, "Valid Responses are:\n"); + fprintf(stderr, "post/nopost - Allow/Disallow postdating\n"); + fprintf(stderr, "forward/noforward - Allow/Disallow forwarding\n"); + fprintf(stderr, "tgt/notgt - Allow/Disallow initial tickets\n"); + fprintf(stderr, "ren/noren - Allow/Disallow renewable tickets\n"); + fprintf(stderr, + "proxy/noproxy - Allow/Disallow proxiable tickets\n"); + fprintf(stderr, + "dskey/nodskey - Allow/Disallow Duplicate Session Keys\n"); + fprintf(stderr, "lock/unlock - Lock/Unlock client\n"); + fprintf(stderr, + "svr/nosvr - Allow/Disallow Use of Principal as Server\n"); +#ifdef SANDIA + fprintf(stderr, + "preauth/nopreauth - Require/Do Not Require preauthentication\n"); + fprintf(stderr, + "pwok/pwchange - Password is OK/Needs to be changed\n"); + fprintf(stderr, + "sid/nosid - Require/Do Not Require Hardware Authentication\n"); +#endif + fprintf(stderr, "q - Quit from setting attributes.\n"); + goto repeat3; + } + } + + if (!valid_command) { + free(inbuf.data); + fprintf(stderr, "Invalid command - Try Again\n"); + goto repeat1; + } + + inbuf.data[0] = KADMIN; + inbuf.data[1] = MODOPER; + inbuf.data[2] = SENDDATA3; + + if ((retval = krb5_mk_priv(&inbuf, + ETYPE_DES_CBC_CRC, + &my_creds->keyblock, + local_addr, + foreign_addr, + *seqno, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data))) { + fprintf(stderr, "Error during Second Message Encoding: %s!\n", + error_message(retval)); + free(inbuf.data); + return(1); + } + free(inbuf.data); + + /* write private message to server */ + if (krb5_write_message(local_socket, &msg_data)) { + fprintf(stderr, "Write Error During Second Message Transmission!\n"); + return(1); + } + free(msg_data.data); + + /* Ok Now let's get the private message */ + if (retval = krb5_read_message(local_socket, &inbuf)){ + fprintf(stderr, "Read Error During Second Reply: %s!\n", + error_message(retval)); + return(1); + } + + if ((retval = krb5_rd_priv(&inbuf, + &my_creds->keyblock, + foreign_addr, + local_addr, + rep_ret->seq_number, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data))) { + fprintf(stderr, "Error during Second Read Decoding :%s!\n", + error_message(retval)); + free(inbuf.data); + return(1); + } + free(inbuf.data); + } /* for */ + +alldone: + if ((inbuf.data = (char *) calloc(1, 80)) == (char *) 0) { + fprintf(stderr, "No memory for command!\n"); + exit(1); + } + + inbuf.data[0] = KADMIN; + inbuf.data[1] = KADMGOOD; + inbuf.data[2] = SENDDATA3; + inbuf.length = 3; + + if ((retval = krb5_mk_priv(&inbuf, + ETYPE_DES_CBC_CRC, + &my_creds->keyblock, + local_addr, + foreign_addr, + *seqno, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data))) { + fprintf(stderr, "Error during Second Message Encoding: %s!\n", + error_message(retval)); + free(inbuf.data); + return(1); + } + free(inbuf.data); + + /* write private message to server */ + if (krb5_write_message(local_socket, &msg_data)) { + fprintf(stderr, "Write Error During Second Message Transmission!\n"); + return(1); + } + free(msg_data.data); + + return(0); +} diff --git a/src/kadmin/kpasswd/Imakefile b/src/kadmin/kpasswd/Imakefile new file mode 100644 index 000000000..11329ca1c --- /dev/null +++ b/src/kadmin/kpasswd/Imakefile @@ -0,0 +1,40 @@ +# $Source$ +# $Author$ +# $Header$ +# +# Copyright 1989 by the Massachusetts Institute of Technology. +# +# For copying and distribution information, +# please see the file . +# +# Imakefile for Kerberos admin server library. + +#ifdef Krb4KDCCompat +K4LIB=-l$(DES425LIB) +#else +K4LIB= +#endif + +SRCS = \ + networked.c \ + kpasswd.c + +OBJS = \ + networked.o \ + kpasswd.o + +ErrorTableObjectRule() + +all:: kpasswd + +NormalProgramTarget(kpasswd,$(OBJS),$(KDBDEPLIB) $(DEPKLIB), \ + $(KDBLIB) $(K4LIB) $(KLIB) ,) +Krb5InstallClientProgram(kpasswd) + +clean:: + +depend:: + +clean:: + +DependTarget() diff --git a/src/kadmin/kpasswd/kpasswd.M b/src/kadmin/kpasswd/kpasswd.M new file mode 100644 index 000000000..e69de29bb diff --git a/src/kadmin/kpasswd/kpasswd.c b/src/kadmin/kpasswd/kpasswd.c new file mode 100644 index 000000000..c4a070ede --- /dev/null +++ b/src/kadmin/kpasswd/kpasswd.c @@ -0,0 +1,998 @@ +/* + * $Source$ + * $Author$ + * + * Copyright 1988 by the Massachusetts Institute of Technology. + * + * For copying and distribution information, please see the file + * . + * + * 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 +#include +#include +#include +#include +#include +#ifndef __convex__ +#include +#endif + +#ifndef MAXPATHLEN +#define MAXPATHLEN 1024 +#endif + +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +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 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 ==> Provide a New List */ + if (new_passwd_length == 0) continue; + + /* Check that Selection is from List - Server also does this */ + legit_pswd = 0; + for (i = 0; i < ADM_MAX_PW_CHOICES && !legit_pswd; i++) + if ((retval = memcmp(new_password, + password_list[i], 8)) == 0) { + legit_pswd++; + } + free_local_password_list(); + + if (!(legit_pswd)) { + printf("\n\07\07Password must be from the specified list "); + printf("- Try Again!\n"); + } + + if (legit_pswd) break; /* Exit Loop */ + } /* ADM_MAX_PW_CHOICES Loop */ + + if (!(legit_pswd)) return (1); + + return(0); /* SUCCESS */ +} +#endif + +krb5_error_code +adm5_init_link( realm_of_server, local_socket) +krb5_data *realm_of_server; +int * local_socket; + +{ + struct servent *service_process; /* service we will talk to */ + struct hostent *local_host; /* us */ + struct hostent *remote_host; /* host we will talk to */ + struct sockaddr *sockaddr_list; + + char **hostlist; + + int host_count; + int namelen; + int i, count; + + krb5_error_code retval; + + /* clear out the structure first */ + (void) memset((char *)&remote_sin, 0, sizeof(remote_sin)); + + if ((service_process = getservbyname(CPW_SNAME, "tcp")) == NULL) { + fprintf(stderr, "Unable to find Service (%s) Check services file\n", + CPW_SNAME); + return(1); + } + + /* Copy the Port Number */ + remote_sin.sin_port = service_process->s_port; + + hostlist = 0; + + /* Identify all Hosts Associated with this Realm */ + if ((retval = krb5_get_krbhst (realm_of_server, &hostlist))) { + fprintf(stderr, "krb5_get_krbhst: Unable to Determine Server Name\n"); + return(1); + } + + for (i=0; hostlist[i]; i++); + + count = i; + + if (count == 0) { + host_count = 0; + fprintf(stderr, "No hosts found\n"); + return(1); + } + + for (i=0; hostlist[i]; i++) { + remote_host = gethostbyname(hostlist[i]); + if (remote_host != 0) { + + /* set up the address of the foreign socket for connect() */ + remote_sin.sin_family = remote_host->h_addrtype; + (void) memcpy((char *) &remote_sin.sin_addr, + (char *) remote_host->h_addr, + sizeof(remote_host->h_addr)); + break; /* Only Need one */ + } + } + + free ((char *)hostlist); + + /* open a TCP socket */ + *local_socket = socket(PF_INET, SOCK_STREAM, 0); + if (*local_socket < 0) { + fprintf(stderr, "Cannot Open Socket\n"); + return(1); + } + /* connect to the server */ + if (connect(*local_socket, &remote_sin, sizeof(remote_sin)) < 0) { + fprintf(stderr, "Cannot Connect to Socket\n"); + close(*local_socket); + return(1); + } + + /* find out who I am, now that we are connected and therefore bound */ + namelen = sizeof(local_sin); + if (getsockname(*local_socket, + (struct sockaddr *) &local_sin, &namelen) < 0) { + fprintf(stderr, "Cannot Perform getsockname\n"); + close(*local_socket); + return(1); + } + return(0); +} + +usage() +{ + fprintf(stderr, "Usage: "); + fprintf(stderr, "kpasswd [name]\n"); + exit(0); +} diff --git a/src/kadmin/kpasswd/networked.c b/src/kadmin/kpasswd/networked.c new file mode 100644 index 000000000..3ddd0ffa5 --- /dev/null +++ b/src/kadmin/kpasswd/networked.c @@ -0,0 +1,226 @@ +/* Networked */ +/* */ +/* Written by: Glenn Machin 2931 */ +/* Originated: Nov 12, 1990 */ +/* Description: */ +/* */ +/* This program/routine exits/returns with a status 1 if */ +/* the terminal associated with the current process is */ +/* connected from a remote host, otherwise exits/returns */ +/* with a value of 0. */ +/* */ +/* This program/routine makes some basic assumptions about */ +/* utmp: */ +/* *The login process, rcmd, or window application */ +/* makes an entry into utmp for all currents */ +/* users. */ +/* *For entries in which the users have logged in */ +/* locally. The line name is not a pseudo tty */ +/* device. */ +/* *For X window application in which */ +/* the device is a pseudo tty device but the */ +/* display is the local system, then the ut_host */ +/* has the format system_name:0.0 or :0.0. */ +/* All other entries will be assumed to be */ +/* networked. */ +/* */ +/* Changes: 11/15/90 Check for file /etc/krb.secure. */ +/* If it exists then perform network */ +/* check, otherwise return 0. */ +/****************************************************************/ +/* + * Sandia National Laboratories also makes no representations about the + * suitability of the modifications, or additions to this software for + * any purpose. It is provided "as is" without express or implied warranty. + */ +#ifndef _TYPES_ +#include +#ifndef _TYPES_ +#define _TYPES_ +#endif +#endif +#include +#include + +#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 + +void setutent() +{ + utfile = open("/etc/utmp",O_RDONLY); +} + +struct utmp * getutline(utmpent) +struct utmp *utmpent; +{ + static struct utmp tmputmpent; + int found = 0; + while ( read(utfile,&tmputmpent,sizeof(struct utmp)) > 0 ){ + if ( strcmp(tmputmpent.ut_line,utmpent->ut_line) == 0){ +#ifdef NO_UT_HOST + if ( ( 1) && +#else + if ( (strcmp(tmputmpent.ut_host,"") == 0) && +#endif + (strcmp(tmputmpent.ut_name,"") == 0)) continue; + found = 1; + break; + } + } + if (found) + return(&tmputmpent); + return((struct utmp *) 0); +} + +void endutent() +{ + close(utfile); +} +#endif /* not SYSV */ + + +int network_connected() +{ +struct utmp utmpent; +struct utmp retutent, *tmpptr; +char *display_indx; +char currenthost[MAXHOSTNAME]; +char *username,*tmpname; + + +/* Macro for pseudo_tty */ +#define pseudo_tty(ut) \ + ((strncmp((ut).ut_line, "tty", 3) == 0 && ((ut).ut_line[3] == 'p' \ + || (ut).ut_line[3] == 'q' \ + || (ut).ut_line[3] == 'r' \ + || (ut).ut_line[3] == 's'))\ + || (strncmp((ut).ut_line, "pty", 3) == 0)) + + /* Check to see if getlogin returns proper name */ + if ( (tmpname = (char *) getlogin()) == (char *) 0) return(1); + username = (char *) malloc(strlen(tmpname) + 1); + if ( username == (char *) 0) return(1); + strcpy(username,tmpname); + + /* Obtain tty device for controlling tty of current process.*/ + strncpy(utmpent.ut_line,ttyname(0) + strlen("/dev/"), + sizeof(utmpent.ut_line)); + + /* See if this device is currently listed in /etc/utmp under + calling user */ +#ifdef SYSV + utmpent.ut_type = USER_PROCESS; +#define ut_name ut_user +#endif + setutent(); + while ( (tmpptr = (struct utmp *) getutline(&utmpent)) + != ( struct utmp *) 0) { + + /* If logged out name and host will be empty */ + if ((strcmp(tmpptr->ut_name,"") == 0) && +#ifdef NO_UT_HOST + ( 1)) continue; +#else + (strcmp(tmpptr->ut_host,"") == 0)) continue; +#endif + else break; + } + if ( tmpptr == (struct utmp *) 0) { + endutent(); + return(1); + } + byte_copy((char *)tmpptr,(char *)&retutent,sizeof(struct utmp)); + endutent(); +#ifdef DEBUG +#ifdef NO_UT_HOST + printf("User %s on line %s :\n", + retutent.ut_name,retutent.ut_line); +#else + printf("User %s on line %s connected from host :%s:\n", + retutent.ut_name,retutent.ut_line,retutent.ut_host); +#endif +#endif + if (strcmp(retutent.ut_name,username) != 0) { + return(1); + } + + + /* If this is not a pseudo tty then everything is OK */ + if (! pseudo_tty(retutent)) return(0); + + /* OK now the work begins there is an entry in utmp and + the device is a pseudo tty. */ + + /* Check if : is in hostname if so this is xwindow display */ + + if (gethostname(currenthost,sizeof(currenthost))) return(1); +#ifdef NO_UT_HOST + display_indx = (char *) 0; +#else + display_indx = (char *) strchr(retutent.ut_host,':'); +#endif + if ( display_indx != (char *) 0) { + /* + We have X window application here. The host field should have + the form => local_system_name:0.0 or :0.0 + if the window is being displayed on the local system. + */ +#ifdef NO_UT_HOST + return(1); +#else + if (strncmp(currenthost,retutent.ut_host, + (display_indx - retutent.ut_host)) != 0) return(1); + else return(0); +#endif + } + + /* Host field is empty or is not X window entry. At this point + we can't trust that the pseudo tty is not connected to a + networked process so let's return 1. + */ + return(1); +} + +byte_copy(str1,str2,len) +char *str1, *str2; +int len; +{ + int i; + for (i=0;i < len; i++) *(str2 + i) = *(str1 + i); + return; +} + + +#ifdef NOTKERBEROS +main(argc,argv) +int argc; +char **argv; +{ + if (network_connected()){ +#ifdef DEBUG + printf("Networked\n"); +#endif + exit(1); + } + else { +#ifdef DEBUG + printf("Not networked\n"); +#endif + exit(0); + } +} +#else +int networked() +{ + return(network_connected()); +} +#endif diff --git a/src/kadmin/server/Imakefile b/src/kadmin/server/Imakefile new file mode 100644 index 000000000..24d646528 --- /dev/null +++ b/src/kadmin/server/Imakefile @@ -0,0 +1,58 @@ +# $Source$ +# $Author$ +# $Header$ +# +# Copyright 1989 by the Massachusetts Institute of Technology. +# +# For copying and distribution information, +# please see the file . +# +# Imakefile for Kerberos admin server library. + +#ifdef Krb4KDCCompat +K4LIB=-l$(KRB425LIB) -l$(DES425LIB) +#else +K4LIB= +#endif + +SRCS = \ + adm_server.c \ + adm_parse.c \ + adm_network.c \ + adm_listen.c \ + adm_process.c \ + adm_nego.c \ + adm_kpasswd.c \ + adm_kadmin.c \ + adm_fmt_inq.c \ + adm_adm_func.c \ + adm_funcs.c \ + adm_check.c \ + adm_extern.c + +OBJS = \ + adm_server.o \ + adm_parse.o \ + adm_network.o \ + adm_listen.o \ + adm_process.o \ + adm_nego.o \ + adm_kpasswd.o \ + adm_kadmin.o \ + adm_fmt_inq.o \ + adm_adm_func.o \ + adm_funcs.o \ + adm_check.o \ + adm_extern.o + +ErrorTableObjectRule() + +all:: kadmind + +NormalProgramTarget(kadmind,$(OBJS),$(KDBDEPLIB) $(DEPKLIB), \ + $(KDBLIB) $(K4LIB) $(KLIB) ,) +Krb5InstallServerProgram(kadmind) + +clean:: + +DependTarget() diff --git a/src/kadmin/server/adm_adm_func.c b/src/kadmin/server/adm_adm_func.c new file mode 100644 index 000000000..f694741e4 --- /dev/null +++ b/src/kadmin/server/adm_adm_func.c @@ -0,0 +1,873 @@ +/* + * $Source$ + * $Author$ + * + * Copyright 1990,1991 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America is assumed + * to require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * Sandia National Laboratories also makes no representations about the + * suitability of the modifications, or additions to this software for + * any purpose. It is provided "as is" without express or implied warranty. + * + * Modify the Kerberos Database + */ + +#if !defined(lint) && !defined(SABER) +static char rcsid_adm_adm_func[] = + "$Id$"; +#endif /* !lint & !SABER */ + +#include +#include +#include + +#include +#include +#ifndef hpux +#include +#endif + +#include +#include +#include +#include +#include + +#include +#include "adm_extern.h" + +#ifdef SANDIA +extern int classification; +#endif + +krb5_error_code + adm_build_key (newprinc, client_creds, new_passwd, oper_type, entry) +krb5_principal newprinc; +krb5_ticket *client_creds; +char *new_passwd; +int oper_type; +krb5_db_entry entry; +{ + krb5_data outbuf; + int retval; +#if defined(MACH_PASS) || defined(SANDIA) + char *tmp_phrase; + char *tmp_passwd; + int pwd_length, phrase_length; +#endif + +#if defined(MACH_PASS) || defined(SANDIA) + + if ((tmp_passwd = (char *) calloc (1, 120)) == (char *) 0) { + com_err("adm_build_key", ENOMEM, "for tmp_passwd"); + return(3); /* No Memory */ + } + + if ((tmp_phrase = (char *) calloc (1, 120)) == (char *) 0) { + free(tmp_passwd); + com_err("adm_build_key", ENOMEM, "for tmp_phrase"); + return(3); /* No Memory */ + } + + if (retval = get_pwd_and_phrase("adm_build_key", &tmp_passwd, + &tmp_phrase)) { + free(tmp_passwd); + free(tmp_phrase); + return(4); /* Unable to get Password */ + } + + if ((outbuf.data = (char *) calloc (1, strlen(tmp_passwd) + 1)) == + (char *) 0) { + com_err("adm_build_key", ENOMEM, "for outbuf.data"); + free(tmp_passwd); + free(tmp_phrase); + return(3); /* No Memory */ + } + + outbuf.length = strlen(tmp_passwd); + (void) memcpy(outbuf.data, tmp_passwd, strlen(tmp_passwd)); + +#else + + if ((outbuf.data = (char *) calloc (1, 3)) == + (char *) 0) { + com_err("adm_build_key", ENOMEM, "for outbuf.data"); + return(3); /* No Memory */ + } + + outbuf.data[0] = KADMIN; + outbuf.data[1] = oper_type; + outbuf.data[2] = KADMGOOD; + outbuf.length = 3; + + if (oper_type == CHGOPER || oper_type == CH4OPER) { + outbuf.data[3] = entry.salt_type; + outbuf.length = 4; + } + +#endif + + /* Encrypt Password and Phrase */ + if (retval = krb5_mk_priv(&outbuf, + ETYPE_DES_CBC_CRC, + client_creds->enc_part2->session, + &client_server_info.server_addr, + &client_server_info.client_addr, + send_seqno, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data)) { + com_err("adm_build_key", retval, "during mk_priv"); +#if defined(MACH_PASS) || defined(SANDIA) + free(tmp_passwd); + free(tmp_phrase); +#endif + free(outbuf.data); + return(5); /* Protocol Failure */ + } + +#if defined(MACH_PASS) || defined(SANDIA) + (void) memcpy(new_passwd, tmp_passwd, strlen(tmp_passwd)); + new_passwd[strlen(tmp_passwd)] = '\0'; + + free(tmp_phrase); + free(tmp_passwd); +#endif + free(outbuf.data); + + /* Send private message to Client */ + if (krb5_write_message(&client_server_info.client_socket, &msg_data)){ + com_err("adm_build_key", 0, "Error Performing Password Write"); + return(5); /* Protocol Failure */ + } + + free(msg_data.data); + + /* Read Client Response */ + if (krb5_read_message(&client_server_info.client_socket, &inbuf)){ + syslog(LOG_ERR | LOG_INFO, "Error Performing Password Read"); + return(5); /* Protocol Failure */ + } + + /* Decrypt Client Response */ + if (retval = krb5_rd_priv(&inbuf, + client_creds->enc_part2->session, + &client_server_info.client_addr, + &client_server_info.server_addr, + recv_seqno, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data)) { + syslog(LOG_ERR | LOG_INFO, "adm_build_key krb5_rd_priv error"); + free(inbuf.data); + return(5); /* Protocol Failure */ + } + free(inbuf.data); + +#if !defined(MACH_PASS) && !defined(SANDIA) + memcpy(new_passwd, msg_data.data, msg_data.length); +#endif + + free(msg_data.data); + return(0); +} + +/* kadmin change password request */ +krb5_error_code + adm_change_pwd(prog, customer_name, client_creds, salttype) +char *prog; +char *customer_name; +krb5_ticket *client_creds; +int salttype; +{ + krb5_db_entry entry; + int nprincs = 1; + + krb5_error_code retval; + krb5_principal newprinc; + char *composite_name; + char *new_passwd; + int oper_type; + + syslog(LOG_AUTH | LOG_INFO, + "Remote Administrative Password Change Request for %s by %s", + customer_name, client_server_info.name_of_client); + + if (retval = krb5_parse_name(customer_name, &newprinc)) { + syslog(LOG_ERR | LOG_INFO, "parse failure while parsing '%s'", + customer_name); + return(5); /* Protocol Failure */ + } + + if (!(adm_princ_exists("adm_change_pwd", newprinc, + &entry, &nprincs))) { + com_err("adm_change_pwd", 0, "Principal does not exist!"); + krb5_free_principal(newprinc); + krb5_db_free_principal(&entry, nprincs); + return(1); /* Principal Unknown */ + } + + if ((new_passwd = (char *) calloc (1, ADM_MAX_PW_LENGTH+1)) == (char *) 0) { + com_err("adm_change_pwd", ENOMEM, "while allocating new_passwd!"); + krb5_free_principal(newprinc); + krb5_db_free_principal(&entry, nprincs); + return(3); /* No Memory */ + } + + oper_type = (salttype == KRB5_KDB_SALTTYPE_NORMAL) ? CHGOPER : CH4OPER; + + if (retval = adm_build_key(newprinc, + client_creds, + new_passwd, + oper_type, + entry)) { + krb5_free_principal(newprinc); + krb5_db_free_principal(&entry, nprincs); + free(new_passwd); + return(retval); + } + + retval = krb5_unparse_name(newprinc, &composite_name); + + entry.salt_type = (krb5_int32) salttype; + + if (retval = adm_enter_pwd_key("adm_change_pwd", + composite_name, + newprinc, + newprinc, + 1, /* chg_entry */ + salttype, + new_passwd, + &entry)) retval = 8; + krb5_free_principal(newprinc); + krb5_db_free_principal(&entry, nprincs); + free(composite_name); + + (void) memset(new_passwd, 0, strlen(new_passwd)); + free(new_passwd); + return(0); +} + +/* kadmin add new random key function */ +krb5_error_code + adm_change_pwd_rnd(cmdname, customer_name, client_creds) +char *cmdname; +char *customer_name; +krb5_ticket *client_creds; +{ + krb5_db_entry entry; + int nprincs = 1; + krb5_error_code retval; + krb5_principal newprinc; + + + syslog(LOG_AUTH | LOG_INFO, + "Remote Administrative Addition Request for %s by %s", + customer_name, client_server_info.name_of_client); + + if (retval = krb5_parse_name(customer_name, &newprinc)) { + com_err("adm_change_pwd_rnd", retval, "while parsing '%s'", customer_name); + return(5); /* Protocol Failure */ + } +#ifdef SANDIA + if (!(newprinc[2])) { + if (retval = check_security(newprinc, classification)) { + krb5_free_principal(newprinc); + syslog(LOG_ERR, "Principal (%s) - Incorrect Classification level", + customer_name); + return(6); + } + } +#endif + if (!(adm_princ_exists("adm_change_pwd_rnd", newprinc, + &entry, &nprincs))) { + com_err("adm_change_pwd_rnd", 0, "Principal does not exist!"); + krb5_free_principal(newprinc); + krb5_db_free_principal(&entry, nprincs); + return(1); /* Principal Unknown */ + } + + if (retval = adm_enter_rnd_pwd_key("adm_change_pwd_rnd", + newprinc, + 1, /* change existing entry */ + &entry)) + retval = 8; + + krb5_free_principal(newprinc); + krb5_db_free_principal(&entry, nprincs); + return(retval); +} + +/* kadmin add new key function */ +krb5_error_code + adm_add_new_key(cmdname, customer_name, client_creds, salttype) +char *cmdname; +char *customer_name; +krb5_ticket *client_creds; +int salttype; +{ + krb5_db_entry entry; + int nprincs = 1; + + krb5_error_code retval; + krb5_principal newprinc; + char *new_passwd; + + syslog(LOG_AUTH | LOG_INFO, + "Remote Administrative Addition Request for %s by %s", + customer_name, client_server_info.name_of_client); + + if (retval = krb5_parse_name(customer_name, &newprinc)) { + com_err("adm_add_new_key", retval, "while parsing '%s'", customer_name); + return(5); /* Protocol Failure */ + } +#ifdef SANDIA + if (!(newprinc[2])) { + if (retval = check_security(newprinc, classification)) { + krb5_free_principal(newprinc); + syslog(LOG_ERR, "Principal (%s) - Incorrect Classification level", + customer_name); + return(6); + } + } +#endif + if (adm_princ_exists("adm_add_new_key", newprinc, &entry, &nprincs)) { + com_err("adm_add_new_key", 0, + "principal '%s' already exists", customer_name); + krb5_free_principal(newprinc); + krb5_db_free_principal(&entry, nprincs); + return(2); /* Principal Already Exists */ + } + + if ((new_passwd = (char *) calloc (1, 255)) == (char *) 0) { + com_err("adm_add_new_key", ENOMEM, "for new_passwd"); + krb5_free_principal(newprinc); + krb5_db_free_principal(&entry, nprincs); + return(3); /* No Memory */ + } + + if (retval = adm_build_key(newprinc, + client_creds, + new_passwd, + ADDOPER, + entry)) { + krb5_free_principal(newprinc); + krb5_db_free_principal(&entry, nprincs); + free(new_passwd); + return(retval); + } + + if (retval = adm_enter_pwd_key( "adm_add_new_key", + customer_name, + newprinc, + newprinc, + 0, /* new_entry */ + salttype, + new_passwd, + &entry)) + retval = 8; + (void) memset(new_passwd, 0, strlen(new_passwd)); + free(new_passwd); + krb5_free_principal(newprinc); + krb5_db_free_principal(&entry, nprincs); + return(retval); +} + +/* kadmin add new random key function */ +krb5_error_code + adm_add_new_key_rnd(cmdname, customer_name, client_creds) +char *cmdname; +char *customer_name; +krb5_ticket *client_creds; +{ + krb5_db_entry entry; + int nprincs = 1; + krb5_error_code retval; + krb5_principal newprinc; + + + syslog(LOG_AUTH | LOG_INFO, + "Remote Administrative Addition Request for %s by %s", + customer_name, client_server_info.name_of_client); + + if (retval = krb5_parse_name(customer_name, &newprinc)) { + com_err("adm_add_new_key_rnd", retval, "while parsing '%s'", customer_name); + return(5); /* Protocol Failure */ + } +#ifdef SANDIA + if (!(newprinc[2])) { + if (retval = check_security(newprinc, classification)) { + krb5_free_principal(newprinc); + syslog(LOG_ERR, "Principal (%s) - Incorrect Classification level", + customer_name); + return(6); + } + } +#endif + if (adm_princ_exists("adm_add_new_key_rnd", newprinc, &entry, &nprincs)) { + com_err("adm_add_new_key_rnd", 0, + "principal '%s' already exists", customer_name); + krb5_free_principal(newprinc); + krb5_db_free_principal(&entry, nprincs); + return(2); /* Principal Already Exists */ + } + + if (retval = adm_enter_rnd_pwd_key("adm_add_new_key_rnd", + newprinc, + 0, /* new entry */ + &entry)) + retval = 8; + + krb5_free_principal(newprinc); + krb5_db_free_principal(&entry, nprincs); + return(retval); +} + +/* kadmin delete old key function */ +krb5_error_code + adm_del_old_key(cmdname, customer_name) +char *cmdname; +char *customer_name; +{ + krb5_db_entry entry; + int nprincs = 1; + + krb5_error_code retval; + krb5_principal newprinc; + int one = 1; + + syslog(LOG_AUTH | LOG_INFO, + "Remote Administrative Deletion Request for %s by %s", + customer_name, client_server_info.name_of_client); + + if (retval = krb5_parse_name(customer_name, &newprinc)) { + com_err("adm_del_old_key", retval, "while parsing '%s'", customer_name); + return(5); /* Protocol Failure */ + } + + if (!adm_princ_exists("adm_del_old_key", newprinc, + &entry, &nprincs)) { + com_err("adm_del_old_key", 0, "principal '%s' is not in the database", + customer_name); + krb5_free_principal(newprinc); + krb5_db_free_principal(&entry, nprincs); + return(1); + } + + if (retval = krb5_db_delete_principal(newprinc, &one)) { + com_err("adm_del_old_key", retval, + "while deleting '%s'", customer_name); + krb5_free_principal(newprinc); + krb5_db_free_principal(&entry, nprincs); + return(8); + } else if (one != 1) { + com_err("adm_del_old_key", 0, + "no principal deleted - unknown error"); + krb5_free_principal(newprinc); + krb5_db_free_principal(&entry, nprincs); + return(8); + } + + krb5_free_principal(newprinc); + krb5_db_free_principal(&entry, nprincs); + return(0); +} + +/* kadmin modify existing Principal function */ +krb5_error_code + adm_mod_old_key(cmdname, customer_name, client_creds) +char *cmdname; +char *customer_name; +krb5_ticket *client_creds; +{ + krb5_db_entry entry; + int nprincs = 1; + extern int errno; + + krb5_error_code retval; + krb5_principal newprinc; + + krb5_data outbuf; + char tempstr[20]; + + int one = 1; + + syslog(LOG_AUTH | LOG_INFO, + "Remote Administrative Modification Request for %s by %s", + customer_name, client_server_info.name_of_client); + + if (retval = krb5_parse_name(customer_name, &newprinc)) { + com_err("adm_mod_old_key", retval, "while parsing '%s'", customer_name); + return(5); /* Protocol Failure */ + } + + for ( ; ; ) { + + if (!adm_princ_exists("adm_mod_old_key", newprinc, + &entry, &nprincs)) { + com_err("adm_mod_old_key", 0, + "principal '%s' is not in the database", + customer_name); + krb5_free_principal(newprinc); + return(1); + } + + /* Send Acknowledgement */ + if ((outbuf.data = (char *) calloc (1, 255)) == (char *) 0) { + krb5_free_principal(newprinc); + krb5_db_free_principal(&entry, nprincs); + com_err("adm_mod_old_key", ENOMEM, "for outbuf.data"); + return(3); /* No Memory */ + } + + outbuf.length = 3; + outbuf.data[0] = KADMIND; + outbuf.data[1] = MODOPER; + outbuf.data[2] = SENDDATA3; + + if (retval = krb5_mk_priv(&outbuf, + ETYPE_DES_CBC_CRC, + client_creds->enc_part2->session, + &client_server_info.server_addr, + &client_server_info.client_addr, + send_seqno, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data)) { + krb5_free_principal(newprinc); + krb5_db_free_principal(&entry, nprincs); + com_err("adm_mod_old_key", retval, "during mk_priv"); + free(outbuf.data); + return(5); /* Protocol Failure */ + } + free(outbuf.data); + + if (krb5_write_message(&client_server_info.client_socket, &msg_data)){ + krb5_free_principal(newprinc); + krb5_db_free_principal(&entry, nprincs); + com_err("adm_mod_old_key", 0, + "Error Performing Modification Write"); + return(5); /* Protocol Failure */ + } + free(msg_data.data); + + /* Read Client Response */ + if (krb5_read_message(&client_server_info.client_socket, &inbuf)){ + krb5_free_principal(newprinc); + krb5_db_free_principal(&entry, nprincs); + com_err("adm_mod_old_key", errno, + "Error Performing Modification Read"); + return(5); /* Protocol Failure */ + } + + /* Decrypt Client Response */ + if (retval = krb5_rd_priv(&inbuf, + client_creds->enc_part2->session, + &client_server_info.client_addr, + &client_server_info.server_addr, + recv_seqno, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data)) { + com_err("adm_mod_old_key", retval, "krb5_rd_priv error %s", + error_message(retval)); + free(inbuf.data); + krb5_free_principal(newprinc); + krb5_db_free_principal(&entry, nprincs); + return(5); /* Protocol Failure */ + } + + free(inbuf.data); + + if (msg_data.data[1] == KADMGOOD) break; + + /* Decode Message - Modify Database */ + if (msg_data.data[2] != SENDDATA3) { + free(msg_data.data); + krb5_free_principal(newprinc); + krb5_db_free_principal(&entry, nprincs); + return(5); /* Protocol Failure */ + } +#ifdef SANDIA + if (msg_data.data[3] == KMODFCNT) { + (void) memcpy(tempstr, (char *) msg_data.data + 4, + msg_data.length - 4); + entry.fail_auth_count = atoi(tempstr); + } +#endif + if (msg_data.data[3] == KMODVNO) { + (void) memcpy(tempstr, (char *) msg_data.data + 4, + msg_data.length - 4); + entry.kvno = atoi(tempstr); + } + + if (msg_data.data[3] == KMODATTR) { + if (msg_data.data[4] == ATTRPOST) + entry.attributes &= ~KRB5_KDB_DISALLOW_POSTDATED; + if (msg_data.data[4] == ATTRNOPOST) + entry.attributes |= KRB5_KDB_DISALLOW_POSTDATED; + if (msg_data.data[4] == ATTRFOR) + entry.attributes &= ~KRB5_KDB_DISALLOW_FORWARDABLE; + if (msg_data.data[4] == ATTRNOFOR) + entry.attributes |= KRB5_KDB_DISALLOW_FORWARDABLE; + if (msg_data.data[4] == ATTRTGT) + entry.attributes &= ~KRB5_KDB_DISALLOW_TGT_BASED; + if (msg_data.data[4] == ATTRNOTGT) + entry.attributes |= KRB5_KDB_DISALLOW_TGT_BASED; + if (msg_data.data[4] == ATTRREN) + entry.attributes &= ~KRB5_KDB_DISALLOW_RENEWABLE; + if (msg_data.data[4] == ATTRNOREN) + entry.attributes |= KRB5_KDB_DISALLOW_RENEWABLE; + if (msg_data.data[4] == ATTRPROXY) + entry.attributes &= ~KRB5_KDB_DISALLOW_PROXIABLE; + if (msg_data.data[4] == ATTRNOPROXY) + entry.attributes |= KRB5_KDB_DISALLOW_PROXIABLE; + if (msg_data.data[4] == ATTRDSKEY) + entry.attributes &= ~KRB5_KDB_DISALLOW_DUP_SKEY; + if (msg_data.data[4] == ATTRNODSKEY) + entry.attributes |= KRB5_KDB_DISALLOW_DUP_SKEY; + if (msg_data.data[4] == ATTRLOCK) + entry.attributes |= KRB5_KDB_DISALLOW_ALL_TIX; + if (msg_data.data[4] == ATTRUNLOCK) + entry.attributes &= ~KRB5_KDB_DISALLOW_ALL_TIX; + if (msg_data.data[4] == ATTRNOSVR) + entry.attributes |= KRB5_KDB_DISALLOW_SVR; + if (msg_data.data[4] == ATTRSVR) + entry.attributes &= ~KRB5_KDB_DISALLOW_SVR; +#ifdef SANDIA + if (msg_data.data[4] == ATTRPRE) + entry.attributes &= ~KRB5_KDB_REQUIRES_PRE_AUTH; + if (msg_data.data[4] == ATTRNOPRE) + entry.attributes |= KRB5_KDB_REQUIRES_PRE_AUTH; + if (msg_data.data[4] == ATTRPWOK) + entry.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE; + if (msg_data.data[4] == ATTRPWCHG) + entry.attributes |= KRB5_KDB_REQUIRES_PWCHANGE; + if (msg_data.data[4] == ATTRSID) + entry.attributes &= ~KRB5_KDB_REQUIRES_SECUREID; + if (msg_data.data[4] == ATTRNOSID) + entry.attributes |= KRB5_KDB_REQUIRES_SECUREID; +#endif + } + + free(msg_data.data); + entry.mod_name = client_server_info.client; + if (retval = krb5_timeofday(&entry.mod_date)) { + com_err("adm_mod_old_key", retval, "while fetching date"); + krb5_free_principal(newprinc); + krb5_db_free_principal(&entry, nprincs); + return(5); /* Protocol Failure */ + } + + retval = krb5_db_put_principal(&entry, &one); + one = 1; + } /* for */ + + krb5_db_free_principal(&entry, nprincs); + krb5_free_principal(newprinc); + + /* Read Client Response */ + if (krb5_read_message(&client_server_info.client_socket, &inbuf)){ + com_err("adm_mod_old_key", errno, "Error Performing Read"); + return(5); /* Protocol Failure */ + } + + /* Decrypt Client Response */ + if (retval = krb5_rd_priv(&inbuf, + client_creds->enc_part2->session, + &client_server_info.client_addr, + &client_server_info.server_addr, + recv_seqno, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data)) { + com_err("adm_mod_old_key", retval, "krb5_rd_priv error %s", + error_message(retval)); + free(inbuf.data); + return(5); /* Protocol Failure */ + } + + free(msg_data.data); + free(inbuf.data); + + return(0); +} + +/* kadmin inquire existing Principal function */ +krb5_error_code + adm_inq_old_key(cmdname, customer_name, client_creds) +char *cmdname; +char *customer_name; +krb5_ticket *client_creds; +{ + krb5_db_entry entry; + int nprincs = 1; + + krb5_data outbuf; + krb5_error_code retval; + krb5_principal newprinc; + char *fullname; + + syslog(LOG_AUTH | LOG_INFO, + "Remote Administrative Inquiry Request for %s by %s", + customer_name, client_server_info.name_of_client); + + if (retval = krb5_parse_name(customer_name, &newprinc)) { + com_err("adm_inq_old_key", retval, "while parsing '%s'", customer_name); + return(5); /* Protocol Failure */ + } + + if (retval = krb5_unparse_name(newprinc, &fullname)) { + krb5_free_principal(newprinc); + com_err("adm_inq_old_key", retval, "while unparsing"); + return(5); /* Protocol Failure */ + } + + if (!adm_princ_exists("adm_inq_old_key", newprinc, + &entry, &nprincs)) { + krb5_free_principal(newprinc); + free(fullname); + com_err("adm_inq_old_key", 0, "principal '%s' is not in the database", + customer_name); + return(1); + } + + if ((outbuf.data = (char *) calloc (1, 2048)) == (char *) 0) { + krb5_db_free_principal(&entry, nprincs); + krb5_free_principal(newprinc); + free(fullname); + com_err("adm_inq_old_key", ENOMEM, "for outbuf.data"); + return(3); /* No Memory */ + } + + /* Format Inquiry Data */ + if ((retval = adm_fmt_prt(&entry, fullname, outbuf.data))) { + krb5_db_free_principal(&entry, nprincs); + krb5_free_principal(newprinc); + free(fullname); + com_err("adm_inq_old_key", 0, "Unable to Format Inquiry Data"); + } + outbuf.length = strlen(outbuf.data); + krb5_db_free_principal(&entry, nprincs); + krb5_free_principal(newprinc); + free(fullname); + + /* Encrypt Inquiry Data */ + if (retval = krb5_mk_priv(&outbuf, + ETYPE_DES_CBC_CRC, + client_creds->enc_part2->session, + &client_server_info.server_addr, + &client_server_info.client_addr, + send_seqno, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data)) { + com_err("adm_inq_old_key", retval, "during mk_priv"); + free(outbuf.data); + return(5); /* Protocol Failure */ + } + + /* Send Inquiry Information */ + if (krb5_write_message(&client_server_info.client_socket, &msg_data)){ + com_err("adm_inq_old_key", 0, "Error Performing Write"); + return(5); /* Protocol Failure */ + } + + free(msg_data.data); + + /* Read Client Response */ + if (krb5_read_message(&client_server_info.client_socket, &inbuf)){ + com_err("adm_inq_old_key", errno, "Error Performing Read"); + syslog(LOG_ERR, "adm_inq sock %d", client_server_info.client_socket); + return(5); /* Protocol Failure */ + } + + /* Decrypt Client Response */ + if (retval = krb5_rd_priv(&inbuf, + client_creds->enc_part2->session, + &client_server_info.client_addr, + &client_server_info.server_addr, + recv_seqno, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data)) { + com_err("adm_inq_old_key", retval, "krb5_rd_priv error %s", + error_message(retval)); + free(inbuf.data); + return(5); /* Protocol Failure */ + } + + free(msg_data.data); + free(inbuf.data); + return(retval); +} + +#ifdef SANDIA +krb5_error_code + check_security(princ, class) +krb5_principal princ; +int class; +{ + char *input_name; + + if ((input_name = (char *) calloc (1, 255)) == 0) { + com_err("check_security", + ENOMEM, "while allocating memory for class check"); + return(3); + } + + memcpy((char *) input_name, princ->data[0].data, princ->data[0].length); + + if (class) { + /* Must be Classified Principal */ + if (strlen(input_name) == 8) { + if (!(strcmp(&input_name[7], "s") == 0) && + !(strcmp(&input_name[7], "c") == 0)) { + free(input_name); + return(6); + } + } else { + if (!((strncmp(&input_name[strlen(input_name) - 2], + "_s", 2) == 0) || + (strncmp(&input_name[strlen(input_name) - 2], "_c", 2) == 0))) { + free(input_name); + return(6); + } + } + } else { + /* Must be Unclassified Principal */ + if ((strlen(input_name) >= 8) || + ((strncmp(&input_name[strlen(input_name) - 2], "_s", 2) == 0) || + (strncmp(&input_name[strlen(input_name) - 2], "_c", 2) == 0))) { + free(input_name); + return(6); + } + } + + free(input_name); + return(0); +} +#endif diff --git a/src/kadmin/server/adm_check.c b/src/kadmin/server/adm_check.c new file mode 100644 index 000000000..2cef9757b --- /dev/null +++ b/src/kadmin/server/adm_check.c @@ -0,0 +1,144 @@ +/* + * $Source$ + * $Author$ + * + * Copyright 1990,1991 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America is assumed + * to require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * Sandia National Laboratories also makes no representations about the + * suitability of the modifications, or additions to this software for + * any purpose. It is provided "as is" without express or implied warranty. + * + */ + +#if !defined(lint) && !defined(SABER) +static char rcsid_adm_check[] = +"$Id$"; +#endif /* !lint & !SABER */ + +#include +#include +#include +#include +#include + +#include +#include +#ifndef hpux +#include +#endif + +#include +#include +#include +#include +#include +#include "adm_extern.h" + +krb5_error_code +adm_check_acl(name_of_client, acl_type) +char *name_of_client; +char *acl_type; +{ + FILE *acl_file; + char input_string[255]; + char admin_name[255]; +#define num_of_privs 5 + char priv[num_of_privs]; + extern char *acl_file_name; + char *lcl_acl_file; + int i, j; + + if ((lcl_acl_file = (char *) calloc(1, 80)) == (char *) 0) { + com_err("adm_check_acl", ENOMEM, "allocating acl file name"); + return(KADM_ENOMEM); /* No Memory */ + } + + (void) sprintf(lcl_acl_file, "%s", acl_file_name); + + if ((acl_file = fopen(lcl_acl_file, "r")) == NULL) { + syslog(LOG_ERR, "Cannot open acl file (%s)", acl_file_name); + free(lcl_acl_file); + return(KADM_EPERM); + } + + for ( ;; ) { + + if ((fgets(input_string, sizeof(input_string), acl_file)) == NULL) { + syslog(LOG_ERR, "Administrator (%s) not in ACL file (%s)", + name_of_client, lcl_acl_file); + break; /* Not Found */ + } + + if (input_string[0] == '#') continue; + + i = 0; + while (!isspace(input_string[i]) && i < strlen(input_string)) { + admin_name[i] = input_string[i]; + i++; + } + + while (isspace(input_string[i]) && i < strlen(input_string)) { + i++; + } + + priv[0] = priv[1] = priv[2] = priv[3] = priv[4] = '\0'; + + j = 0; + while ((i < strlen(input_string)) && (j < num_of_privs) && + (!isspace(input_string[i]))) { + priv[j] = input_string[i]; + i++; j++; + } + + if (priv[0] == '*') { + priv[0] = 'a'; /* Add Priv */ + priv[1] = 'c'; /* Changepw Priv */ + priv[2] = 'd'; /* Delete Priv */ + priv[3] = 'i'; /* Inquire Priv */ + priv[4] = 'm'; /* Modify Priv */ + } + + if (!strncmp(admin_name, name_of_client, + strlen(name_of_client))) { + switch(acl_type[0]) { + case 'a': + case 'c': + case 'd': + case 'i': + case 'm': + for (i = 0; i < num_of_privs; i++) { + if (priv[i] == acl_type[0]) { + fclose(acl_file); + free(lcl_acl_file); + return(0); /* Found */ + } + } + break; + + default: + break; + } + } + } + + fclose(acl_file); + free(lcl_acl_file); + return(KADM_EPERM); +} diff --git a/src/kadmin/server/adm_extern.c b/src/kadmin/server/adm_extern.c new file mode 100644 index 000000000..d544ce719 --- /dev/null +++ b/src/kadmin/server/adm_extern.c @@ -0,0 +1,65 @@ +/* + * $Source$ + * $Author$ + * + * Copyright 1990 by the Massachusetts Institute of Technology. + * + * Export of this software from the United States of America is assumed + * to require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * + * Sandia National Laboratories also makes no representations about the + * suitability of the modifications, or additions to this software for + * any purpose. It is provided "as is" without express or implied warranty. + * + * allocations of adm_extern stuff + */ + +#if !defined(lint) && !defined(SABER) +static char rcsid_adm_extern_c[] = +"$Id$"; +#endif /* !lint & !SABER */ + +#include + +#include +#include +#include + +/* real declarations of KDC's externs */ +krb5_encrypt_block master_encblock; +krb5_keyblock master_keyblock; +krb5_principal master_princ; + +volatile int signal_requests_exit = 0; /* gets set when signal hits */ + +char *dbm_db_name = DEFAULT_DBM_FILE; + +krb5_keyblock tgs_key; +krb5_kvno tgs_kvno; + +krb5_data inbuf; +krb5_data msg_data; + +int send_seqno; +int recv_seqno; + +/* +static krb5_data tgs_name = {sizeof(TGTNAME)-1, TGTNAME}; +krb5_data *tgs_server[4] = {0, &tgs_name, 0, 0}; +*/ + +krb5_principal tgs_server; diff --git a/src/kadmin/server/adm_extern.h b/src/kadmin/server/adm_extern.h new file mode 100644 index 000000000..9095bdf5e --- /dev/null +++ b/src/kadmin/server/adm_extern.h @@ -0,0 +1,82 @@ +/* + * $Source$ + * $Author$ + * $Id$ + * + * Copyright 1990 by the Massachusetts Institute of Technology. + * + * Export of this software from the United States of America is assumed + * to require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * Sandia National Laboratories also makes no representations about the + * suitability of the modifications, or additions to this software for + * any purpose. It is provided "as is" without express or implied warranty. + * + * <<< Description >>> + */ + +#include + +#ifndef __ADM_EXTERN__ +#define __ADM_EXTERN__ + +typedef struct { + /* Client Info */ + struct sockaddr_in client_name; + krb5_address client_addr; + krb5_principal client; + char *name_of_client; + /* Server Info */ + struct sockaddr_in server_name; + krb5_address server_addr; + krb5_principal server; + char *name_of_service; + /* Miscellaneous */ + int server_socket; + int client_socket; +} global_client_server_info; + +/* various externs for KDC */ +extern krb5_encrypt_block master_encblock; +extern krb5_keyblock master_keyblock; +extern krb5_principal master_princ; + +extern volatile int signal_requests_exit; +extern char *dbm_db_name; + +extern krb5_keyblock tgs_key; +extern krb5_kvno tgs_kvno; +extern krb5_principal tgs_server; + +extern global_client_server_info client_server_info; +extern char *adm5_tcp_portname; +extern int adm5_tcp_port_fd; + +extern unsigned pidarraysize; +extern int *pidarray; + +extern char *adm5_ver_str; +extern int adm5_ver_len; + +extern int send_seqno; +extern int recv_seqno; + +extern int exit_now; + +extern krb5_data inbuf; +extern krb5_data msg_data; + +#endif /* __ADM_EXTERN__ */ diff --git a/src/kadmin/server/adm_fmt_inq.c b/src/kadmin/server/adm_fmt_inq.c new file mode 100644 index 000000000..b563ec4b1 --- /dev/null +++ b/src/kadmin/server/adm_fmt_inq.c @@ -0,0 +1,218 @@ +/* + * $Source$ + * $Author$ + * + * Copyright 1990,1991 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America is assumed + * to require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * Sandia National Laboratories also makes no representations about the + * suitability of the modifications, or additions to this software for + * any purpose. It is provided "as is" without express or implied warranty. + * + * Administrative Display Routine + */ + +#if !defined(lint) && !defined(SABER) +static char rcsid_adm_fmt_inq[] = +"$Id$"; +#endif /* !lint & !SABER */ + +#include +#include +#include +#include +#include + +#include +#include + +#if defined (unicos61) || (defined(mips) && defined(SYSTYPE_BSD43)) || defined(sysvimp) +#include +#else +#include +#endif /* unicos61 */ +#if defined(aux20) +#include +#endif /* aux20 */ + +#define REALM_SEP '@' +#define REALM_SEP_STR "@" + +krb5_error_code +adm_print_attributes(ret_data, attribs) +char *ret_data; +krb5_flags attribs; +{ + char *my_data; + + if ((my_data = (char *) calloc (1,255)) == (char *) 0) { + com_err("adm_print_attributes", ENOMEM, ""); + } + + sprintf(my_data, "Principal Attributes (PA): "); + if (attribs & KRB5_KDB_DISALLOW_POSTDATED) + strcat(my_data, "NOPOST "); + else + strcat(my_data, "POST "); + if (attribs & KRB5_KDB_DISALLOW_FORWARDABLE) + strcat(my_data, "NOFOR "); + else + strcat(my_data, "FOR "); + if (attribs & KRB5_KDB_DISALLOW_TGT_BASED) + strcat(my_data, "NOTGT "); + else + strcat(my_data, "TGT "); + if (attribs & KRB5_KDB_DISALLOW_RENEWABLE) + strcat(my_data, "NOREN "); + else + strcat(my_data, "REN "); + if (attribs & KRB5_KDB_DISALLOW_PROXIABLE) + strcat(my_data, "NOPROXY\n"); + else + strcat(my_data, "PROXY\n"); + strcat(my_data, " "); + if (attribs & KRB5_KDB_DISALLOW_DUP_SKEY) + strcat(my_data, "NODUPSKEY "); + else + strcat(my_data, "DUPSKEY "); + if (attribs & KRB5_KDB_DISALLOW_ALL_TIX) + strcat(my_data, "LOCKED "); + else + strcat(my_data, "UNLOCKED "); + if (attribs & KRB5_KDB_DISALLOW_SVR) + strcat(my_data, "NOSVR\n"); + else + strcat(my_data, "SVR\n"); + +#ifdef SANDIA + strcat(my_data, " "); + if (attribs & KRB5_KDB_REQUIRES_PRE_AUTH) + strcat(my_data, "PREAUTH "); + else + strcat(my_data, "NOPREAUTH "); + if (attribs & KRB5_KDB_REQUIRES_PWCHANGE) + strcat(my_data, "PWCHG "); + else + strcat(my_data, "PWOK "); + if (attribs & KRB5_KDB_REQUIRES_HW_AUTH) + strcat(my_data, "SID\n"); + else + strcat(my_data, "NOSID\n"); +#endif + (void) strcat(ret_data, my_data); + free(my_data); + return(0); +} + +krb5_error_code +adm_print_exp_time(ret_data, time_input) +char *ret_data; +krb5_timestamp *time_input; +{ + char *my_data; + struct tm *exp_time; + + if ((my_data = (char *) calloc (1,255)) == (char *) 0) { + com_err("adm_print_attributes", ENOMEM, ""); + } + + exp_time = localtime((time_t *) time_input); + sprintf(my_data, + "Principal Expiration Date (PED): %02d%02d/%02d/%02d:%02d:%02d:%02d\n", + (exp_time->tm_year >= 100) ? 20 : 19, + (exp_time->tm_year >= 100) ? exp_time->tm_year - 100 : exp_time->tm_year, + exp_time->tm_mon + 1, + exp_time->tm_mday, + exp_time->tm_hour, + exp_time->tm_min, + exp_time->tm_sec); + (void) strcat(ret_data, my_data); + free(my_data); + return(0); +} + +krb5_error_code +adm_fmt_prt(entry, Principal_name, ret_data) +krb5_db_entry *entry; +char *Principal_name; +char *ret_data; +{ + struct tm *mod_time; +#ifdef SANDIA + krb5_error_code retval; + struct tm *exp_time; + int pwd_expire; + krb5_timestamp now; +#endif + + char *my_data; + char thisline[80]; + + if ((my_data = (char *) calloc (1, 2048)) == (char *) 0) { + com_err("adm_print_attributes", ENOMEM, ""); + } + + (void) sprintf(my_data, "\n\nPrincipal: %s\n\n", Principal_name); + sprintf(thisline, + "Maximum Ticket Lifetime (MTL) = %d (seconds)\n", entry->max_life); + strcat(my_data, thisline); + sprintf(thisline, "Maximum Renewal Lifetime (MRL) = %d (seconds)\n", + entry->max_renewable_life); + strcat(my_data, thisline); + sprintf(thisline, "Principal Key Version (PKV) = %d\n", entry->kvno); + strcat(my_data, thisline); + (void) adm_print_exp_time(my_data, &entry->expiration); + mod_time = localtime((time_t *) &entry->mod_date); + sprintf(thisline, + "Last Modification Date (LMD): %02d%02d/%02d/%02d:%02d:%02d:%02d\n", + (mod_time->tm_year >= 100) ? 20 : 19, + (mod_time->tm_year >= 100) ? mod_time->tm_year - 100 : mod_time->tm_year, + mod_time->tm_mon + 1, + mod_time->tm_mday, + mod_time->tm_hour, + mod_time->tm_min, + mod_time->tm_sec); + strcat(my_data, thisline); + (void) adm_print_attributes(my_data, entry->attributes); + switch (entry->salt_type & 0xff) { + case 0 : strcat(my_data, + "Principal Salt Type (PST) = Version 5 Normal\n"); + break; + case 1 : strcat(my_data, "Principal Salt Type (PST) = Version 4\n"); + break; + case 2 : strcat(my_data, "Principal Salt Type (PST) = NOREALM\n"); + break; + case 3 : strcat(my_data, "Principal Salt Type (PST) = ONLYREALM\n"); + break; + case 4 : strcat(my_data, "Principal Salt Type (PST) = Special\n"); + break; + } +#ifdef SANDIA + sprintf(thisline, + "Invalid Authentication Count (FCNT) = %d\n", entry->fail_auth_count); + strcat(my_data, thisline); + retval = krb5_timeofday(&now); + pwd_expire = (now - entry->last_pwd_change) / 86400; + sprintf(thisline, "Password Age is %d Days\n", pwd_expire); + strcat(my_data, thisline); +#endif + (void) strcat(ret_data, my_data); + free(my_data); + return(0); +} diff --git a/src/kadmin/server/adm_funcs.c b/src/kadmin/server/adm_funcs.c new file mode 100644 index 000000000..b40a46938 --- /dev/null +++ b/src/kadmin/server/adm_funcs.c @@ -0,0 +1,599 @@ +/* + * $Source$ + * $Author$ + * + * Copyright 1990,1991 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America is assumed + * to require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * Sandia National Laboratories also makes no representations about the + * suitability of the modifications, or additions to this software for + * any purpose. It is provided "as is" without express or implied warranty. + * + * Modify the Kerberos Database + */ + +#if !defined(lint) && !defined(SABER) +static char rcsid_adm_funcs[] = +"$Id$"; +#endif /* !lint & !SABER */ + +#include +#include + +#include +#include +#ifndef hpux +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include "adm_extern.h" + +#include +#include +#include +#include + +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_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_kvno +adm_princ_exists(cmdname, principal, entry, nprincs) +char *cmdname; +krb5_principal principal; +krb5_db_entry *entry; +int *nprincs; +{ + krb5_boolean more; + krb5_error_code retval; + + if (retval = krb5_db_get_principal(principal, entry, nprincs, &more)) { + com_err("adm_princ_exists", retval, + "while attempting to verify principal's existence"); + return(0); + } + + if (! *nprincs) return(0); + + return(*nprincs); +} + +krb5_error_code +adm_modify_kdb(DECLARG(char const *, cmdname), + DECLARG(char const *, newprinc), + DECLARG(krb5_const_principal, principal), + DECLARG(const krb5_keyblock *, key), + DECLARG(const krb5_keyblock *, alt_key), + DECLARG(int, req_type), + DECLARG(struct saltblock *, salt), + DECLARG(struct saltblock *, altsalt), + DECLARG(krb5_db_entry *, entry)) +OLDDECLARG(char const *, cmdname) +OLDDECLARG(char const *, newprinc) +OLDDECLARG(krb5_const_principal, principal) +OLDDECLARG(const krb5_keyblock *, key) +OLDDECLARG(const krb5_keyblock *, alt_key) +OLDDECLARG(int, req_type) +OLDDECLARG(struct saltblock *, salt) +OLDDECLARG(struct saltblock *, altsalt) +OLDDECLARG(krb5_db_entry *, entry) + +{ + krb5_error_code retval; + int one = 1; + + krb5_kvno KDB5_VERSION_NUM = 1; + krb5_deltat KDB5_MAX_TKT_LIFE = KRB5_KDB_MAX_LIFE; + krb5_deltat KDB5_MAX_REN_LIFE = KRB5_KDB_MAX_RLIFE; + krb5_timestamp KDB5_EXP_DATE = KRB5_KDB_EXPIRATION; + extern krb5_flags NEW_ATTRIBUTES; + + if (key && key->length) { + retval = krb5_kdb_encrypt_key(&master_encblock, + key, + &entry->key); + if (retval) { + com_err("adm_modify_kdb", retval, + "while encrypting key for '%s'", newprinc); + return(KADM_NO_ENCRYPT); + } + } + + if (alt_key && alt_key->length) { + retval = krb5_kdb_encrypt_key(&master_encblock, + alt_key, + &entry->alt_key); + if (retval) { + com_err("adm_modify_kdb", retval, + "while encrypting alt_key for '%s'", newprinc); + return(KADM_NO_ENCRYPT); + } + } + + if (!req_type) { /* New entry - initialize */ + memset((char *) &entry, 0, sizeof(entry)); + entry->principal = (krb5_principal) principal; + entry->kvno = KDB5_VERSION_NUM; + entry->max_life = KDB5_MAX_TKT_LIFE; + entry->max_renewable_life = KDB5_MAX_REN_LIFE; + entry->mkvno = mblock.mkvno; + entry->expiration = KDB5_EXP_DATE; + entry->mod_name = master_princ; + } else { /* Modify existing entry */ + entry->kvno++; +#ifdef SANDIA + entry->attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE; +#endif + entry->mod_name = (krb5_principal) principal; + } + + if (retval = krb5_timeofday(&entry->mod_date)) { + com_err("adm_modify_kdb", retval, "while fetching date"); + memset((char *) entry->key.contents, 0, entry->key.length); + memset((char *) entry->alt_key.contents, 0, entry->alt_key.length); + if (entry->key.contents) + xfree(entry->key.contents); + if (entry->alt_key.contents) + xfree(entry->alt_key.contents); + return(KRB_ERR_GENERIC); + } + + if (!req_type) { + if (salt->salttype == KRB5_KDB_SALTTYPE_V4) { + entry->attributes = (KRB5_KDB_DISALLOW_DUP_SKEY | NEW_ATTRIBUTES) +#ifdef SANDIA + & ~KRB5_KDB_REQUIRES_PRE_AUTH & ~KRB5_KDB_REQUIRES_HW_AUTH +#endif + ; + } else { + entry->attributes = NEW_ATTRIBUTES; + } + +#ifdef SANDIA + entry->last_pwd_change = entry->mod_date; + entry->last_success = entry->mod_date; + entry->fail_auth_count = 0; +#endif + + if (salt) { + entry->salt_type = salt->salttype; + entry->salt_length = salt->saltdata.length; + entry->salt = (krb5_octet *) salt->saltdata.data; + } else { + entry->salt_type = KRB5_KDB_SALTTYPE_NORMAL; + entry->salt_length = 0; + entry->salt = 0; + } + + /* Set up version 4 alt key and alt salt info.....*/ + if (altsalt) { + entry->alt_salt_type = altsalt->salttype; + entry->alt_salt_length = altsalt->saltdata.length; + entry->alt_salt = (krb5_octet *) altsalt->saltdata.data; + } else { + entry->alt_salt_type = KRB5_KDB_SALTTYPE_NORMAL; + entry->alt_salt_length = 0; + entry->alt_salt = 0; + } + } else { + if (retval = krb5_timeofday(&entry->last_pwd_change)) { + com_err("adm_modify_kdb", retval, "while fetching date"); + memset((char *) entry->key.contents, 0, entry->key.length); + memset((char *) entry->alt_key.contents, 0, entry->alt_key.length); + if (entry->key.contents) + xfree(entry->key.contents); + if (entry->alt_key.contents) + xfree(entry->alt_key.contents); + return(5); + } + } + + retval = krb5_db_put_principal(entry, &one); + + memset((char *) entry->key.contents, 0, entry->key.length); + if (entry->key.contents) + xfree(entry->key.contents); + + memset((char *) entry->alt_key.contents, 0, entry->alt_key.length); + if (entry->alt_key.contents) + xfree(entry->alt_key.contents); + + if (retval) { + com_err("adm_modify_kdb", retval, + "while storing entry for '%s'\n", newprinc); + return(kdb5_err_base + retval); + } + + if (one != 1) + com_err("adm_modify_kdb", 0, "entry not stored in database (unknown failure)"); + return(0); +} + +krb5_error_code +adm_enter_pwd_key(DECLARG(char *, cmdname), + DECLARG(char *, newprinc), + DECLARG(krb5_const_principal, princ), + DECLARG(krb5_const_principal, string_princ), + DECLARG(int, req_type), + DECLARG(int, salttype), + DECLARG(char *, new_password), + DECLARG(krb5_db_entry *, entry)) +OLDDECLARG(char *, cmdname) +OLDDECLARG(char *, newprinc) +OLDDECLARG(krb5_const_principal, princ) +OLDDECLARG(krb5_const_principal, string_princ) +OLDDECLARG(int, req_type) +OLDDECLARG(int, salttype) +OLDDECLARG(char *, new_password) +OLDDECLARG(krb5_db_entry *, entry) +{ + krb5_error_code retval; + krb5_keyblock tempkey; + krb5_data pwd; + struct saltblock salt; + struct saltblock altsalt; + krb5_keyblock alttempkey; + krb5_octet v4_keyptr[8]; + + pwd.data = new_password; + pwd.length = strlen((char *) new_password); + + salt.salttype = salttype; + + switch (salttype) { + case KRB5_KDB_SALTTYPE_NORMAL: + if (retval = krb5_principal2salt(string_princ, &salt.saltdata)) { + com_err("adm_enter_pwd_key", retval, + "while converting principal to salt for '%s'", newprinc); + return(KRB_ERR_GENERIC); + } + + altsalt.salttype = KRB5_KDB_SALTTYPE_V4; + altsalt.saltdata.data = 0; + altsalt.saltdata.length = 0; + break; + + case KRB5_KDB_SALTTYPE_V4: + salt.saltdata.data = 0; + salt.saltdata.length = 0; + if (retval = krb5_principal2salt(string_princ, &altsalt.saltdata)) { + com_err("adm_enter_pwd_key", retval, + "while converting principal to altsalt for '%s'", newprinc); + return(KRB_ERR_GENERIC); + } + + altsalt.salttype = KRB5_KDB_SALTTYPE_NORMAL; + break; + + case KRB5_KDB_SALTTYPE_NOREALM: + if (retval = norealm_salt(string_princ, &salt.saltdata)) { + com_err("adm_enter_pwd_key", retval, + "while converting principal to salt for '%s'", newprinc); + return(KRB_ERR_GENERIC); + } + + altsalt.salttype = KRB5_KDB_SALTTYPE_V4; + altsalt.saltdata.data = 0; + altsalt.saltdata.length = 0; + break; + + case KRB5_KDB_SALTTYPE_ONLYREALM: + { + krb5_data *foo; + if (retval = krb5_copy_data(krb5_princ_realm(string_princ), + &foo)) { + com_err("adm_enter_pwd_key", retval, + "while converting principal to salt for '%s'", newprinc); + return(KRB_ERR_GENERIC); + } + + salt.saltdata = *foo; + xfree(foo); + altsalt.salttype = KRB5_KDB_SALTTYPE_V4; + altsalt.saltdata.data = 0; + altsalt.saltdata.length = 0; + break; + } + + default: + com_err("adm_enter_pwd_key", 0, + "Don't know how to enter salt type %d", salttype); + return(KRB_ERR_GENERIC); + } + + if (retval = krb5_string_to_key(&master_encblock, + master_keyblock.keytype, + &tempkey, + &pwd, + &salt.saltdata)) { + com_err("adm_enter_pwd_key", retval, + "while converting password to alt_key for '%s'", newprinc); + memset((char *) new_password, 0, sizeof(new_password)); /* erase it */ + xfree(salt.saltdata.data); + return(retval); + } + + if (retval = krb5_string_to_key(&master_encblock, + master_keyblock.keytype, + &alttempkey, + &pwd, + &altsalt.saltdata)) { + com_err("adm_enter_pwd_key", retval, + "while converting password to alt_key for '%s'", newprinc); + xfree(salt.saltdata.data); + free(entry->alt_key.contents); + memset((char *) new_password, 0, sizeof(new_password)); /* erase it */ + return(retval); + } + + memset((char *) new_password, 0, sizeof(new_password)); /* erase it */ + + retval = adm_modify_kdb("adm_enter_pwd_key", + newprinc, + princ, + &tempkey, + &alttempkey, + req_type, + &salt, + &altsalt, + entry); + + memset((char *) tempkey.contents, 0, tempkey.length); + memset((char *) alttempkey.contents, 0, alttempkey.length); + if (entry->alt_key.contents) + free(entry->alt_key.contents); + return(retval); +} + +krb5_error_code +adm5_change(prog, newprinc, client_creds) +char *prog; +krb5_principal newprinc; +krb5_ticket *client_creds; +{ + krb5_db_entry entry; + int nprincs = 1; + + krb5_error_code retval; + char *composite_name; + char new_passwd[ADM_MAX_PW_LENGTH + 1]; + + if (!(adm_princ_exists("adm5_change", newprinc, + &entry, &nprincs))) { + com_err("adm5_change", 0, "No principal exists!"); + krb5_free_principal(newprinc); + return(1); + } + + memset((char *) new_passwd, 0, ADM_MAX_PW_LENGTH + 1); + + /* Negotiate for New Key */ + if (retval = adm_negotiate_key("adm5_change", client_creds, + new_passwd)) { + krb5_db_free_principal(&entry, nprincs); + krb5_free_principal(newprinc); + return(1); + } + + retval = krb5_unparse_name(newprinc, &composite_name); + + if (entry.salt_type == KRB5_KDB_SALTTYPE_V4) { + entry.salt_type = KRB5_KDB_SALTTYPE_NORMAL; + entry.alt_salt_type = KRB5_KDB_SALTTYPE_V4; + com_err("adm5_change", 0, "Converting v4user to v5user"); + } + + retval = adm_enter_pwd_key("adm5_change", + composite_name, + newprinc, + newprinc, + 1, /* change */ + KRB5_KDB_SALTTYPE_NORMAL, + new_passwd, + &entry); + (void) memset(new_passwd, 0, strlen(new_passwd)); + krb5_free_principal(newprinc); + krb5_db_free_principal(&entry, nprincs); + free(composite_name); + return(retval); +} + +#ifdef SANDIA +krb5_error_code +adm5_create_rnd(prog, change_princ, client_auth_data, client_creds) +char *prog; +krb5_principal change_princ; +krb5_authenticator *client_auth_data; +krb5_ticket *client_creds; +{ + krb5_db_entry entry; + int nprincs = 1; + + krb5_error_code retval; + + if (!(adm_princ_exists("adm5_create_rnd", + change_princ, + &entry, + &nprincs))) { + com_err("adm5_create_rnd", 0, "No principal exists!"); + krb5_free_principal(change_princ); + return(1); + } + + if (retval = adm_get_rnd_key("adm5_create_rnd", + client_creds, + client_auth_data, + change_princ, + 1, /* change */ + &entry)) { + krb5_db_free_principal(&entry, nprincs); + krb5_free_principal(change_princ); + return(retval); + } + + krb5_free_principal(change_princ); + krb5_db_free_principal(&entry, nprincs); + return(0); +} +#endif +#define MAXMSGSZ 255 + +krb5_error_code +adm_enter_rnd_pwd_key(DECLARG(char *, cmdname), + DECLARG(krb5_principal, change_princ), + DECLARG(int, req_type), + DECLARG(krb5_db_entry *, entry)) +OLDDECLARG(char *, cmdname) +OLDDECLARG(krb5_principal, change_princ) +OLDDECLARG(int, req_type) +OLDDECLARG(krb5_db_entry *, entry) +{ + krb5_error_code retval; + krb5_keyblock *tempkey; + krb5_pointer master_random; + int salttype = KRB5_KDB_SALTTYPE_NORMAL; + struct saltblock salt; + char *principal_name; + + salt.salttype = salttype; + entry->salt_type = salttype; + + if (retval = krb5_init_random_key(&master_encblock, + &master_keyblock, + &master_random)) { + com_err("adm_enter_rnd_pwd_key", 0, "Unable to Initialize Random Key"); + (void) krb5_finish_key(&master_encblock); + memset((char *)master_keyblock.contents, 0, master_keyblock.length); + xfree(master_keyblock.contents); + goto finish; + } + + /* Get Random Key */ + if (retval = krb5_random_key(&master_encblock, + master_random, + &tempkey)) { + com_err("adm_enter_rnd_pwd_key", 0, "Unable to Obtain Random Key"); + goto finish; + } + + /* Tie the Random Key to the Principal */ + if (retval = krb5_principal2salt(change_princ, &salt.saltdata)) { + com_err("adm_enter_rnd_pwd_key", 0, "Principal2salt Failure"); + goto finish; + } + + retval = krb5_unparse_name(change_princ, &principal_name); + if (retval) + return retval; + + /* Modify Database */ + retval = adm_modify_kdb("adm_enter_rnd_pwd_key", + principal_name, + change_princ, + tempkey, + tempkey, + req_type, + &salt, + &salt, + entry); + free(principal_name); + + if (retval) { + com_err("adm_enter_rnd_pwd_key", 0, "Database Modification Failure"); + retval = 2; + goto finish; + } + + finish: + + if(retval) { + memset((char *) tempkey->contents, 0, tempkey->length); + return(retval); + } + + memset((char *) tempkey->contents, 0, tempkey->length); + + return(0); +} diff --git a/src/kadmin/server/adm_kadmin.c b/src/kadmin/server/adm_kadmin.c new file mode 100644 index 000000000..abf38cad6 --- /dev/null +++ b/src/kadmin/server/adm_kadmin.c @@ -0,0 +1,371 @@ +/* + * $Source$ + * $Author$ + * + * Copyright 1988 by the Massachusetts Institute of Technology. + * + * For copying and distribution information, please see the file + * . + * + */ + +/* + * 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 +#include +#include + +#include +#include +#ifndef hpux +#include +#endif + +#include +#include +#include +#include +#include +#include "adm_extern.h" + +krb5_error_code +adm5_kadmin(prog, client_auth_data, client_creds, retbuf, otype) +char *prog; +krb5_authenticator *client_auth_data; +krb5_ticket *client_creds; +char *retbuf; /* Allocated in Calling Routine */ +int *otype; +{ + krb5_error_code retval; + kadmin_requests request_type; + krb5_data msg_data, outbuf, inbuf; + + char *customer_name; + char *completion_msg; + int length_of_name; + + int salttype; + + outbuf.data = retbuf; /* Do NOT free outbuf.data */ + + for ( ; ; ) { /* Use "return", "break", or "goto" + to exit for loop */ + + /* Encode Acknowledgement Message */ + retbuf[0] = KADMIND; + retbuf[1] = KADMSAG; + retbuf[2] = SENDDATA2; + outbuf.length = 3; + + retval = krb5_mk_priv(&outbuf, + ETYPE_DES_CBC_CRC, + client_creds->enc_part2->session, + &client_server_info.server_addr, + &client_server_info.client_addr, + send_seqno, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data); + if (retval ) { + syslog(LOG_ERR, + "adm5_kadmin - Error Performing Acknowledgement mk_priv"); + return(5); /* Protocol Failure */ + } + + /* Send Acknowledgement Reply to Client */ + if (retval = krb5_write_message(&client_server_info.client_socket, + &msg_data)){ + syslog(LOG_ERR, + "adm5_kadmin - Error Performing Acknowledgement Write: %s", + error_message(retval)); + return(5); /* Protocol Failure */ + } + free(msg_data.data); + + /* Read Username */ + if (krb5_read_message(&client_server_info.client_socket, &inbuf)){ + syslog(LOG_ERR | LOG_INFO, "Error Performing Username Read"); + return(5); /* Protocol Failure */ + } + + /* Decrypt Client Response */ + if ((retval = krb5_rd_priv(&inbuf, + client_creds->enc_part2->session, + &client_server_info.client_addr, + &client_server_info.server_addr, + recv_seqno, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data))) { + free(inbuf.data); + syslog(LOG_ERR | LOG_INFO, "Error decoding Username - rd_priv"); + return(5); /* Protocol Failure */ + } + free(inbuf.data); + + request_type.appl_code = msg_data.data[0]; + request_type.oper_code = msg_data.data[1]; + if (msg_data.data[2] != SENDDATA2) { + syslog(LOG_ERR | LOG_INFO, + "Invalid Protocol String - Response not SENDDATA2"); + free(msg_data.data); + return(5); /* Protocol Failure */ + } + + length_of_name = msg_data.length - 3; + + if (request_type.oper_code == COMPLETE) { + *otype = 0; + free(msg_data.data); + retval = 0; + goto finish_req; + } + + if (!length_of_name) { + syslog(LOG_ERR, + "adm5_kadmin error: Invalid KADMIN request - No Customer"); + free(msg_data.data); + return(5); /* Protocol Error */ + } + + if ((customer_name = (char *) calloc(1, length_of_name + 1)) == + (char *) 0) { + syslog(LOG_ERR, "adm5_kadmin error: No Memory for Customer Name"); + free(msg_data.data); + return(3); /* No Memory */ + } + + (void) memcpy(customer_name, (char *) msg_data.data + 3, + length_of_name); + customer_name[length_of_name] = '\0'; + + free(msg_data.data); + + if ((completion_msg = (char *) calloc (1,512)) == (char *) 0) { + syslog(LOG_ERR, "adm5_kadmin - No Memory for completion_msg"); + free(customer_name); + return(3); /* No Memory */ + } + + switch(request_type.oper_code) { + case ADDOPER: + /* Check for Add Privilege */ + if (retval = adm_check_acl(client_server_info.name_of_client, + "a")) { + retval = 7; + goto process_retval; + } + *otype = 1; + salttype = KRB5_KDB_SALTTYPE_NORMAL; + retval = adm_add_new_key("adm5_kadmin", customer_name, + client_creds, salttype); + goto process_retval; + + case CHGOPER: + /* Check for Password Privilege */ + if (retval = adm_check_acl(client_server_info.name_of_client, + "c")) { + retval = 7; + goto process_retval; + } + *otype = 2; + salttype = KRB5_KDB_SALTTYPE_NORMAL; + retval = adm_change_pwd("adm5_kadmin", customer_name, + client_creds, salttype); + goto process_retval; + + case ADROPER: + /* Check for Add Privilege */ + if (retval = adm_check_acl(client_server_info.name_of_client, + "a")) { + retval = 7; + goto process_retval; + } + *otype = 3; + retval = adm_add_new_key_rnd("adm5_kadmin", customer_name, + client_creds); + goto process_retval; + + case CHROPER: + /* Check for Password Privilege */ + if (retval = adm_check_acl(client_server_info.name_of_client, + "c")) { + retval = 7; + goto process_retval; + } + *otype = 4; + retval = adm_change_pwd_rnd("adm5_kadmin", customer_name, + client_creds); + goto process_retval; + + case DELOPER: + /* Check for Delete Privilege */ + if (retval = adm_check_acl(client_server_info.name_of_client, + "d")) { + retval = 7; + goto process_retval; + } + *otype = 5; + retval = adm_del_old_key("adm5_kadmin", customer_name); + goto process_retval; + + case MODOPER: + /* Check for Modify Privilege */ + if (retval = adm_check_acl(client_server_info.name_of_client, + "m")) { + retval = 7; + goto process_retval; + } + *otype = 6; + retval = adm_mod_old_key("adm5_kadmin", customer_name, + client_creds); + goto process_retval; + + case INQOPER: + /* Check for Inquiry Privilege */ + if (retval = adm_check_acl(client_server_info.name_of_client, + "i")) { + retval = 7; + goto process_retval; + } + *otype = 7; + retval = adm_inq_old_key("adm5_kadmin", customer_name, + client_creds); + goto process_retval; + + case AD4OPER: + /* Check for Add Privilege */ + if (retval = adm_check_acl(client_server_info.name_of_client, + "a")) { + retval = 7; + goto process_retval; + } + *otype = 8; + salttype = KRB5_KDB_SALTTYPE_V4; + retval = adm_add_new_key("adm5_kadmin", customer_name, + client_creds, salttype); + goto process_retval; + + case CH4OPER: + /* Check for Password Privilege */ + if (retval = adm_check_acl(client_server_info.name_of_client, + "c")) { + retval = 7; + goto process_retval; + } + *otype = 9; + salttype = KRB5_KDB_SALTTYPE_V4; + retval = adm_change_pwd("adm5_kadmin", customer_name, + client_creds, salttype); + goto process_retval; + + default: + retbuf[0] = KADMIN; + retbuf[1] = KUNKNOWNOPER; + retbuf[2] = '\0'; + sprintf(completion_msg, "%s %s from %s FAILED", + "kadmin", + "Unknown or Non-Implemented Operation Type!", + inet_ntoa(client_server_info.client_name.sin_addr)); + syslog(LOG_AUTH | LOG_INFO, completion_msg); + free(completion_msg); + retval = 255; + goto send_last; + } /* switch (request_type.oper_code) */ + +process_retval: + switch (retval) { + case 0: + retbuf[0] = KADMIN; + retbuf[1] = request_type.oper_code; + retbuf[2] = KADMGOOD; + retbuf[3] = '\0'; + goto send_last; + + case 1: /* Principal Unknown */ + case 2: /* Principal Already Exists */ + case 3: /* ENOMEM */ + case 4: /* Password Failure */ + case 5: /* Protocol Failure */ + case 6: /* Security Failure */ + case 7: /* Admin Client Not in ACL List */ + case 8: /* Database Update Failure */ + retbuf[0] = KADMIN; + retbuf[1] = request_type.oper_code; + retbuf[2] = KADMBAD; + retbuf[3] = '\0'; + sprintf((char *)retbuf +3, "%s", + kadmind_kadmin_response[retval]); + sprintf(completion_msg, + "%s %s from %s FAILED - %s", + "kadmin", + oper_type[request_type.oper_code], + inet_ntoa(client_server_info.client_name.sin_addr), + kadmind_kadmin_response[retval]); + syslog(LOG_AUTH | LOG_INFO, completion_msg); + free(completion_msg); + goto send_last; + + default: + retbuf[0] = KADMIN; + retbuf[1] = request_type.oper_code; + retbuf[2] = KUNKNOWNERR; + retbuf[3] = '\0'; + sprintf(completion_msg, "%s %s from %s FAILED", + "ksrvutil", + oper_type[1], + inet_ntoa( client_server_info.client_name.sin_addr)); + syslog(LOG_AUTH | LOG_INFO, completion_msg); + retval = 255; + goto send_last; + } /* switch(retval) */ + +send_last: + free(customer_name); + free(completion_msg); + outbuf.data = retbuf; + outbuf.length = strlen(retbuf) + 1; + + /* Send Completion Message */ + if (retval = krb5_mk_priv(&outbuf, + ETYPE_DES_CBC_CRC, + client_creds->enc_part2->session, + &client_server_info.server_addr, + &client_server_info.client_addr, + send_seqno, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data)) { + syslog(LOG_ERR, "adm5_kadmin - Error Performing Final mk_priv"); + return(1); + } + + /* Send Final Reply to Client */ + if (retval = krb5_write_message(&client_server_info.client_socket, + &msg_data)){ + syslog(LOG_ERR, "adm5_kadmin - Error Performing Final Write: %s", + error_message(retval)); + return(1); + } + free(msg_data.data); + } /* for */ + +finish_req: + return(retval); +} diff --git a/src/kadmin/server/adm_kpasswd.c b/src/kadmin/server/adm_kpasswd.c new file mode 100644 index 000000000..f01475fc4 --- /dev/null +++ b/src/kadmin/server/adm_kpasswd.c @@ -0,0 +1,122 @@ +/* + * $Source$ + * $Author$ + * + * Copyright 1988 by the Massachusetts Institute of Technology. + * + * For copying and distribution information, please see the file + * . + * + */ + +/* + * 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 +#include +#include +#include +#include + +#include +#include +#ifndef hpux +#include +#endif + +#include +#include +#include +#include +#include +#include "adm_extern.h" + +extern krb5_encrypt_block master_encblock; +extern krb5_keyblock master_keyblock; + +struct cpw_keyproc_arg { + krb5_keyblock *key; +}; + +krb5_error_code +adm5_kpasswd(prog, request_type, client_creds, retbuf, otype) +char *prog; +kadmin_requests *request_type; +krb5_ticket *client_creds; +char *retbuf; +int *otype; +{ + char completion_msg[520]; + krb5_error_code retval; + + switch (request_type->oper_code) { + case CHGOPER: + *otype = 3; + syslog(LOG_AUTH | LOG_INFO, + "adm_kpasswd: kpasswd change received"); + retval = adm5_change("adm5_kpasswd", + client_server_info.client, + client_creds); + + switch(retval) { + case 0: + retbuf[0] = KPASSWD; + retbuf[1] = CHGOPER; + retbuf[2] = KPASSGOOD; + retbuf[3] = '\0'; + break; + + case 1: + retbuf[0] = KPASSWD; + retbuf[1] = CHGOPER; + retbuf[2] = KPASSBAD; + retbuf[3] = '\0'; + sprintf((char *)retbuf +3, "%s", + kadmind_kpasswd_response[retval]); + sprintf(completion_msg, + "kpasswd change from %s FAILED: %s", + inet_ntoa(client_server_info.client_name.sin_addr), + kadmind_kpasswd_response[retval]); + syslog(LOG_AUTH | LOG_INFO, completion_msg); + goto finish; + + default: + retbuf[0] = KPASSWD; + retbuf[1] = CHGOPER; + retbuf[2] = KUNKNOWNERR; + retbuf[3] = '\0'; + sprintf(completion_msg, "kpasswd change from %s FAILED", + inet_ntoa(client_server_info.client_name.sin_addr)); + syslog(LOG_AUTH | LOG_INFO, completion_msg); + retval = 255; + goto finish; + } /* switch (retval) */ + break; + + default: + retbuf[0] = KPASSWD; + retbuf[1] = KUNKNOWNOPER; + retbuf[2] = '\0'; + sprintf(completion_msg, "kpasswd %s from %s FAILED", + "Unknown or Non-Implemented Operation Type!", + inet_ntoa(client_server_info.client_name.sin_addr )); + syslog(LOG_AUTH | LOG_INFO, completion_msg); + retval = 255; + goto finish; + } /* switch (request_type->oper_code) */ + +finish: + return(retval); +} diff --git a/src/kadmin/server/adm_listen.c b/src/kadmin/server/adm_listen.c new file mode 100644 index 000000000..abedc1d79 --- /dev/null +++ b/src/kadmin/server/adm_listen.c @@ -0,0 +1,164 @@ +/* + * $Source$ + * $Author$ + * + * Copyright 1988 by the Massachusetts Institute of Technology. + * + * For copying and distribution information, please see the file + * . + * + * 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 +#include +#include +#include + +#ifndef sigmask +#define sigmask(m) (1 <<((m)-1)) +#endif + +#include +#include +#ifndef hpux +#include +#endif + +#include +#include +#include +#include +#include "adm_extern.h" + +void +kill_children() +{ + register int i; + int osigmask; + + osigmask = sigblock(sigmask(SIGCHLD)); + + for (i = 0; i < pidarraysize; i++) { + kill(pidarray[i], SIGINT); + syslog(LOG_AUTH | LOG_INFO, "Killing Admin Child %d", pidarray[i]); + } + + sigsetmask(osigmask); + return; +} + +/* +adm5_listen_and_process - listen on the admin servers port for a request +*/ +adm5_listen_and_process(prog) +const char *prog; +{ + extern int errno; + int found; + fd_set mask, readfds; + int addrlen; + krb5_error_code process_client(); + krb5_error_code retval; + void kill_children(); + int pid; + + (void) listen(client_server_info.server_socket, 1); + + FD_ZERO(&mask); + FD_SET(client_server_info.server_socket, &mask); + + for (;;) { /* loop nearly forever */ + if (exit_now) { + kill_children(); + return(0); + } + + readfds = mask; + if ((found = select(client_server_info.server_socket + 1, + &readfds, + (fd_set *)0, + (fd_set *)0, + (struct timeval *)0)) == 0) + continue; /* no things read */ + + if (found < 0) { + if (errno != EINTR) + syslog(LOG_AUTH | LOG_INFO, + "%s: select: %s", "adm5_listen_and_process", + error_message(errno)); + continue; + } + + if (FD_ISSET(client_server_info.server_socket, &readfds)) { + /* accept the conn */ + addrlen = sizeof(client_server_info.client_name); + if ((client_server_info.client_socket = + accept(client_server_info.server_socket, + (struct sockaddr *) &client_server_info.client_name, + &addrlen)) < 0) { + syslog(LOG_AUTH | LOG_INFO, "%s: accept: %s", + "adm5_listen_and_process", + error_message(errno)); + continue; + } +#ifndef DEBUG + /* if you want a sep daemon for each server */ + if (!(pid = fork())) { + /* child */ + (void) close(client_server_info.server_socket); + + retval = process_client("adm5_listen_and_process"); + exit(retval); + } else { + /* parent */ + if (pid < 0) { + syslog(LOG_AUTH | LOG_INFO, "%s: fork: %s", + "adm5_listen_and_process", + error_message(errno)); + (void) close(client_server_info.client_socket); + continue; + } + + /* fork succeded: keep tabs on child */ + + (void) close(client_server_info.client_socket); + if (pidarray) { + pidarray = (int *) realloc((char *)pidarray, + (++pidarraysize) * sizeof(int)); + pidarray[pidarraysize - 1] = pid; + } else { + pidarraysize = 1; + pidarray = + (int *) malloc(pidarraysize *sizeof(int)); + pidarray[0] = pid; + } + } +#else + /* do stuff */ + + retval = process_client("adm5_listen_and_process"); + exit(retval); +#endif /* DEBUG */ + } else { + syslog(LOG_AUTH | LOG_INFO, "%s: something else woke me up!", + "adm5_listen_and_process"); + return(0); + } + } +} diff --git a/src/kadmin/server/adm_nego.c b/src/kadmin/server/adm_nego.c new file mode 100644 index 000000000..124372032 --- /dev/null +++ b/src/kadmin/server/adm_nego.c @@ -0,0 +1,339 @@ +/* + * $Source$ + * $Author$ + * + * Copyright 1990,1991 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America is assumed + * to require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * Sandia National Laboratories also makes no representations about the + * suitability of the modifications, or additions to this software for + * any purpose. It is provided "as is" without express or implied warranty. + * + * Modify the Kerberos Database + */ + +#if !defined(lint) && !defined(SABER) +static char rcsid_adm_nego[] = +"$Id$"; +#endif /* !lint & !SABER */ + +#include +#include + +#include +#include +#ifndef hpux +#include +#endif + +#include + +#include +#include +#include +#include + +#include +#include "adm_extern.h" + +krb5_error_code +adm_negotiate_key(DECLARG(char const *, prog), + DECLARG(krb5_ticket *, client_creds), + DECLARG(char *, new_passwd)) +OLDDECLARG(char const *, prog) +OLDDECLARG(krb5_ticket *, client_creds) +OLDDECLARG(char *, new_passwd) + +{ + krb5_data msg_data, inbuf; + krb5_error_code retval; +#if defined(MACH_PASS) || defined(SANDIA) /* Machine-generated passwords. */ + krb5_pwd_data *pwd_data; + krb5_pwd_data encodable_data; + krb5_data *encoded_pw_string; + passwd_phrase_element **next_passwd_phrase_element; + char *tmp_passwd, *tmp_phrase; + krb5_authenticator *client_auth_data; + int count, i, j, k; + int legit_passwd = 0; +#endif + extern int errno; + +#if defined(MACH_PASS) || defined(SANDIA) /* Machine-generated passwords. */ + +#define clear_encodable_data() \ +{ encodable_data.sequence_count = 0; \ + encodable_data.element = 0; \ +} + +#define free_seq_list() \ +{ free(encodable_data.element); \ +} + +#define free_pwd_and_phrase_structures() \ +{ next_passwd_phrase_element = encodable_data.element; \ + for (k = 0; \ + *next_passwd_phrase_element != 0 && k < encodable_data.sequence_count; \ + k++) { \ + free(*next_passwd_phrase_element); \ + *next_passwd_phrase_element = 0; \ + next_passwd_phrase_element++; } \ +} + +#define free_passwds() \ +{ next_passwd_phrase_element = encodable_data.element; \ + for (k = 0; \ + *next_passwd_phrase_element != 0 && k < encodable_data.sequence_count; \ + k++) { \ + memset((char *) (*next_passwd_phrase_element)->passwd->data, \ + 0, (*next_passwd_phrase_element)->passwd->length); \ + free((*next_passwd_phrase_element)->passwd->data); \ + next_passwd_phrase_element++; } \ +} + +#define free_phrases() \ +{ next_passwd_phrase_element = encodable_data.element; \ + for (k = 0; \ + *next_passwd_phrase_element != 0 && k < encodable_data.sequence_count; \ + k++) { \ + memset((char *) (*next_passwd_phrase_element)->phrase->data, \ + 0, (*next_passwd_phrase_element)->phrase->length); \ + free((*next_passwd_phrase_element)->phrase->data); \ + next_passwd_phrase_element++; } \ +} + + encodable_data.sequence_count = + ADM_MAX_PW_CHOICES * ADM_MAX_PW_ITERATIONS; + + /* Allocate List of Password and Phrase Addresses Pointers */ + if ((encodable_data.element = (passwd_phrase_element **) calloc( + encodable_data.sequence_count + 1, + sizeof(passwd_phrase_element *))) == + (passwd_phrase_element **) 0) { + clear_encodable_data(); + com_err("adm_negotiate_key", 0, + "No Memory for Password and Phrase List"); + return(1); + } + + next_passwd_phrase_element = encodable_data.element; + + /* Allow for ADM_MAX_PW_ITERATIONS Sets of Five Passwords/Phrases */ + for ( i = 0; i < ADM_MAX_PW_ITERATIONS; i++) { + if ( i == ADM_MAX_PW_ITERATIONS ) { + com_err("adm_negotiate_key", 0, + "Excessive Password List Requests"); + return(1); + } + + /* Allocate passwd_phrase_element structures */ + for (j = 0; j < ADM_MAX_PW_CHOICES; j++) { + if ((*next_passwd_phrase_element = + (passwd_phrase_element *) calloc(1, + sizeof(passwd_phrase_element))) == + (passwd_phrase_element *) 0) { + free_pwd_and_phrase_structures(); + free_seq_list(); + clear_encodable_data(); + com_err("adm_negotiate_key", 0, + "No Memory for Additional Password and Phrase Structures"); + return(1); + } + + if ((retval = get_pwd_and_phrase("adm_negotiate_key", + &tmp_passwd, &tmp_phrase))) { + free_pwd_and_phrase_structures(); + free_seq_list(); + clear_encodable_data(); + com_err("adm_negotiate_key", 0, "Unable to get_pwd_and_phrase"); + return(1); + } + + if (((*next_passwd_phrase_element)->passwd = + (krb5_data *) calloc(1, + sizeof(krb5_data))) == (krb5_data *) 0) { + free_pwd_and_phrase_structures(); + free_seq_list(); + clear_encodable_data(); + com_err("adm_negotiate_key", 0, + "No Memory for Additional Password and Phrase Structures"); + return(1); + } + + if (((*next_passwd_phrase_element)->passwd->data = + (char *) calloc (1, + strlen(tmp_passwd))) == (char *) 0) { + free_pwd_and_phrase_structures(); + free_seq_list(); + clear_encodable_data(); + com_err("adm_negotiate_key", ENOMEM, + "for Additional Passwords"); + } + + strcpy((*next_passwd_phrase_element)->passwd->data, tmp_passwd); + (*next_passwd_phrase_element)->passwd->length = strlen(tmp_passwd); + + if (((*next_passwd_phrase_element)->phrase = + (krb5_data *) calloc(1, + sizeof(krb5_data))) == (krb5_data *) 0) { + free_pwd_and_phrase_structures(); + free_seq_list(); + clear_encodable_data(); + com_err("adm_negotiate_key", 0, + "No Memory for Additional Password and Phrase Structures"); + return(1); + } + + if (((*next_passwd_phrase_element)->phrase->data = + (char *) calloc (1, + strlen(tmp_phrase))) == (char *) 0) { + free_pwd_and_phrase_structures(); + free_seq_list(); + clear_encodable_data(); + com_err("adm_negotiate_key", ENOMEM, + "for Additional Passwords"); + } + + strcpy((*next_passwd_phrase_element)->phrase->data, tmp_phrase); + (*next_passwd_phrase_element)->phrase->length = strlen(tmp_phrase); + + free(tmp_passwd); + free(tmp_phrase); + + next_passwd_phrase_element++; + } + } /* for i <= KADM_MAX_PW_CHOICES */ + + /* Asn.1 Encode the Passwords and Phrases */ + if ((retval = encode_krb5_pwd_data(&encodable_data, + &encoded_pw_string))) { + com_err("adm_negotiate_key", 0, + "Unable to encode Password and Phrase Data"); + return(1); + } + + /* Free Phrases But Hold onto Passwds for Awhile*/ + free_phrases(); + + /* Encrypt Password/Phrases Encoding */ + retval = krb5_mk_priv(encoded_pw_string, + ETYPE_DES_CBC_CRC, + client_creds->enc_part2->session, + &client_server_info.server_addr, + &client_server_info.client_addr, + send_seqno, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data); + if (retval ) { + free_passwds(); + free_pwd_and_phrase_structures(); + free_seq_list(); + clear_encodable_data(); + com_err("adm_negotiate_key", retval, "during mk_priv"); + return(1); + } + + /* Send Encrypted/Encoded Passwords and Phrases to Client */ + if (krb5_write_message(&client_server_info.client_socket, &msg_data)){ + free(msg_data.data); + free_passwds(); + free_pwd_and_phrase_structures(); + free_seq_list(); + clear_encodable_data(); + com_err("adm_negotiate_key", 0, "Error Performing Password Write"); + return(1); + } + free(msg_data.data); + +#endif /* MACH_PASS - Machine-gen. passwords */ + /* Read Client Response */ + if (krb5_read_message(&client_server_info.client_socket, &inbuf)){ +#if defined(MACH_PASS) || defined(SANDIA) + free_passwds(); + free_pwd_and_phrase_structures(); + free_seq_list(); + clear_encodable_data(); +#endif + com_err("adm_negotiate_key", errno, "Error Performing Password Read"); + return(1); + } + + /* Decrypt Client Response */ + if ((retval = krb5_rd_priv(&inbuf, + client_creds->enc_part2->session, + &client_server_info.client_addr, + &client_server_info.server_addr, + recv_seqno, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data))) { + free(inbuf.data); +#if defined(MACH_PASS) || defined(SANDIA) + free_passwds(); + free_pwd_and_phrase_structures(); + free_seq_list(); + clear_encodable_data(); +#endif + com_err("adm_negotiate_key", retval, "krb5_rd_priv error %s", + error_message(retval)); + return(1); + } + free(inbuf.data); + +#if defined(MACH_PASS) || defined(SANDIA) /* Machine-generated passwords */ + legit_passwd = 0; + next_passwd_phrase_element = encodable_data.element; + /* Compare Response with Acceptable Passwords */ + for (j = 0; + j < ADM_MAX_PW_CHOICES * ADM_MAX_PW_ITERATIONS; + j++) { + if ((retval = memcmp(msg_data.data, + (*next_passwd_phrase_element)->passwd->data, + strlen((*next_passwd_phrase_element)->passwd->data))) == 0) { + legit_passwd++; + break; /* Exit Loop - Match Found */ + } + next_passwd_phrase_element++; + } + /* Now Free Passwds */ + free_passwds(); + + /* free password_and_phrase structures */ + free_pwd_and_phrase_structures(); + + /* free passwd_phrase_element list */ + free_seq_list(); + + /* clear krb5_pwd_data */ + clear_encodable_data(); + + if (!(legit_passwd)) { + com_err("adm_negotiate_key", 0, "Invalid Password Entered"); + return(1); + } +#endif + strncpy(new_passwd, msg_data.data, msg_data.length); + free(msg_data.data); + + return(0); +} + diff --git a/src/kadmin/server/adm_network.c b/src/kadmin/server/adm_network.c new file mode 100644 index 000000000..a7de9f2eb --- /dev/null +++ b/src/kadmin/server/adm_network.c @@ -0,0 +1,286 @@ +/* + * $Source$ + * $Author$ + * + * Copyright 1988 by the Massachusetts Institute of Technology. + * + * For copying and distribution information, please see the file + * . + * + * 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 +#include +#include +#include +#include +#include + +#ifndef sigmask +#define sigmask(m) (1 <<((m)-1)) +#endif + +#include +#include +#ifndef hpux +#include +#endif +#include + +#include +#include +#include +#include +#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() +{ + /* + * has been included, so BSD will be defined on + * BSD systems + */ +#if BSD > 0 && BSD <= 43 +#ifndef WEXITSTATUS +#define WEXITSTATUS(w) (w).w_retcode +#define WTERMSIG(w) (w).w_termsig +#endif + union wait status; +#else + int status; +#endif + int pid, i, j; + + pid = wait(&status); + if (pid < 0) { +#ifdef SYSV + signal(SIGCHLD, do_child); +#endif +#if defined (POSIX) || defined(SYSV) || defined(sun) && !defined(sysvimp) || defined(ultrix) || (defined(mips) && defined(SYSTYPE_BSD43)) || defined(convex) + return; +#else /* !POSIX */ + return(0); +#endif /* POSIX */ + } + + for (i = 0; i < pidarraysize; i++) + if (pidarray[i] == pid) { + /* found it */ + for (j = i; j < pidarraysize-1; j++) + /* copy others down */ + pidarray[j] = pidarray[j+1]; + pidarraysize--; + if ( !WIFEXITED(status) ) { + com_err("adm_network", 0, "child %d: termsig %d", + pid, WTERMSIG(status) ); + com_err("adm_network", 0, "retcode %d", + WEXITSTATUS(status)); + } + +#ifdef SYSV + signal(SIGCHLD, do_child); +#endif + +#if defined (POSIX) || defined(SYSV) || defined(sun) && !defined(sysvimp) || defined(ultrix) || (defined(mips) && defined(SYSTYPE_BSD43)) || defined(convex) + return; +#else /* !POSIX */ + return(0); +#endif /* POSIX */ + } +#ifdef SYSV + signal(SIGCHLD, do_child); +#endif + + com_err("adm_network", 0, + "child %d not in list: termsig %d, retcode %d", pid, + WTERMSIG(status), WEXITSTATUS(status)); + +#if defined (POSIX) || defined(SYSV) || defined(sun) && !defined(sysvimp) || defined(ultrix) || (defined(mips) && defined(SYSTYPE_BSD43)) || defined(convex) + return; +#else /* !POSIX */ + return(0); +#endif /* POSIX */ +} + +krb5_error_code +setup_network(prog) +const char *prog; +{ + krb5_error_code retval; + char server_host_name[MAXHOSTNAMELEN]; + char *lrealm; + krb5_sigtype doexit(), do_child(); + struct servent *service_servent; + struct hostent *service_hostent; + + signal(SIGINT, doexit); + signal(SIGTERM, doexit); + signal(SIGHUP, doexit); + signal(SIGQUIT, doexit); + signal(SIGPIPE, SIG_IGN); /* get errors on write() */ + signal(SIGALRM, doexit); + signal(SIGCHLD, do_child); + + client_server_info.name_of_service = malloc(768); + if (!client_server_info.name_of_service) { + com_err("setup_network", 0, + "adm_network: No Memory for name_of_service"); + return ENOMEM; + } + + + if (retval = krb5_get_default_realm(&lrealm)) { + free(client_server_info.name_of_service); + com_err( "setup_network", 0, + "adm_network: Unable to get Default Realm"); + return retval; + } + + (void) sprintf(client_server_info.name_of_service, "%s%s%s%s%s", + CPWNAME, "/", lrealm, "", ""); + free(lrealm); + +#ifdef DEBUG + fprintf(stderr, "client_server_info.name_of_service = %s\n", + client_server_info.name_of_service); +#endif /* DEBUG */ + + if ((retval = krb5_parse_name(client_server_info.name_of_service, + &client_server_info.server))) { + free(client_server_info.name_of_service); + com_err( "setup_network", retval, + "adm_network: Unable to Parse Server Name"); + return retval; + } + + if (gethostname(server_host_name, sizeof(server_host_name))) { + retval = errno; + krb5_free_principal(client_server_info.server); + free(client_server_info.name_of_service); + com_err( "setup_network", retval, + "adm_network: Unable to Identify Who I am"); + return retval; + } + + service_hostent = gethostbyname(server_host_name); + if (!service_hostent) { + retval = errno; + free(client_server_info.name_of_service); + com_err("setup_network", retval, "adm_network: Failed gethostname"); + return retval; + } + +#ifdef DEBUG + fprintf(stderr, "Official host name = %s\n", service_hostent->h_name); +#endif /* DEBUG */ + + client_server_info.server_name.sin_family = AF_INET; + +#ifdef unicos61 + memcpy((char *) &client_server_info.server_name.sin_addr, + (char *) service_hostent->h_addr, service_hostent->h_length); +#else + memcpy((char *) &client_server_info.server_name.sin_addr.s_addr, + (char *) service_hostent->h_addr, service_hostent->h_length); +#endif /* unicos61 */ + + client_server_info.server_socket = -1; + +#ifdef DEBUG + fprintf(stderr, "adm5_tcp_portname = %s\n", adm5_tcp_portname); +#endif /* DEBUG */ + + service_servent = getservbyname(adm5_tcp_portname, "tcp"); + + if (!service_servent) { + krb5_free_principal(client_server_info.server); + free(client_server_info.name_of_service); + com_err("setup_network", 0, "adm_network: %s/tcp service unknown", + adm5_tcp_portname); + return(1); + } + +#ifdef DEBUG + fprintf(stderr, "Official service name = %s\n", service_servent->s_name); +#endif /* DEBUG */ + + client_server_info.server_name.sin_port = service_servent->s_port; + + if ((client_server_info.server_socket = + socket(AF_INET, SOCK_STREAM, 0)) < 0) { + retval = errno; + krb5_free_principal(client_server_info.server); + free(client_server_info.name_of_service); + com_err("setup_network", retval, + "adm_network: Cannot create server socket."); + return(1); + } + +#ifdef DEBUG + fprintf(stderr, "Socket File Descriptor = %d\n", + client_server_info.server_socket); + fprintf(stderr, "sin_family = %d\n", + client_server_info.server_name.sin_family); + fprintf(stderr, "sin_port = %d\n", + client_server_info.server_name.sin_port); + fprintf(stderr, "in_addr.s_addr = %s\n", + inet_ntoa( client_server_info.server_name.sin_addr )); +#endif /* DEBUG */ + + if (bind(client_server_info.server_socket, + &client_server_info.server_name, + sizeof(client_server_info.server_name)) < 0) { + retval = errno; + krb5_free_principal(client_server_info.server); + free(client_server_info.name_of_service); + com_err("setup_network", retval, + "adm_network: Cannot bind server socket."); + return(1); + } + + return(0); +} diff --git a/src/kadmin/server/adm_parse.c b/src/kadmin/server/adm_parse.c new file mode 100644 index 000000000..eb284c78f --- /dev/null +++ b/src/kadmin/server/adm_parse.c @@ -0,0 +1,270 @@ +#ifdef SANDIA +/* + * $Source$ + * $Author$ + * + * Copyright 1990,1991 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America is assumed + * to require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * Sandia National Laboratories also makes no representations about the + * suitability of the modifications, or additions to this software for + * any purpose. It is provided "as is" without express or implied warranty. + * + * Edit a KDC database. + */ + +#if !defined(lint) && !defined(SABER) +static char rcsid_adm_parse[] = +"$Id$"; +#endif /* !lint & !SABER */ + +#include +#include + +#if defined (unicos61) || (defined(mips) && defined(SYSTYPE_BSD43)) || defined(sysvimp) +#include +#else +#include +#endif /* unicos61 */ +#if defined(aux20) +#include +#endif /* aux20 */ + +#include +#include +#include + +void +kadmin_parse_and_set(input_string) +char *input_string; +{ + extern int classification; + extern krb5_kvno KDB5_VERSION_NUM; + extern krb5_deltat KDB5_MAX_TKT_LIFE; + extern krb5_deltat KDB5_MAX_REN_LIFE; + extern krb5_timestamp KDB5_EXP_DATE; + extern krb5_flags NEW_ATTRIBUTES; + + int num_args; + char parameter[40]; + char first_token[40]; + char second_token[40]; + + int bypass = 0; + + struct tm exp_date; + long todays_date; + int year; + int month; + int mday; + + first_token[0] = second_token[0] = '\0'; + num_args = sscanf(input_string, "%s %s %s", parameter, + first_token, second_token); + + if (strcmp(parameter, "BYPASS") == 0) { + bypass++; + syslog(LOG_ERR, + "CAUTION: Classified and Unclassified Principals will be allowed"); + return; + } + + if (strcmp(parameter, "CLASSIFICATION") == 0) { + if (strcmp(first_token, "CLASS") == 0) { + classification = 1; + if (bypass) classification = 0; + } + return; + } + + if (strcmp(parameter, "VERSION_NUM") == 0) { + if (num_args < 2) { + KDB5_VERSION_NUM = 1; + } else { + KDB5_VERSION_NUM = atoi(first_token); + } + return; + } + + if (strcmp(parameter, "MAX_TKT_LIFE") == 0) { + if (num_args < 2) { + KDB5_MAX_TKT_LIFE = KRB5_KDB_MAX_LIFE; + } else { + switch (second_token[0]) { + case 's': + KDB5_MAX_TKT_LIFE = atoi(first_token); + break; + case 'm': + KDB5_MAX_TKT_LIFE = atoi(first_token) * 60; + break; + case 'h': + KDB5_MAX_TKT_LIFE = atoi(first_token) * 3600; + break; + case 'd': + KDB5_MAX_TKT_LIFE = atoi(first_token) * 86400; + break; + case 'w': + KDB5_MAX_TKT_LIFE = atoi(first_token) * 604800; + break; + case 'M': /* 30 days */ + KDB5_MAX_TKT_LIFE = atoi(first_token) * 18144000; + break; + case 'y': /* 365 days */ + KDB5_MAX_TKT_LIFE = atoi(first_token) * 220752000; + break; + case 'e': /* eternity */ + KDB5_MAX_TKT_LIFE = 2145830400; + break; + default: + break; + } + } + return; + } + + if (strcmp(parameter, "MAX_REN_LIFE") == 0) { + if (num_args < 2) { + KDB5_MAX_REN_LIFE = KRB5_KDB_MAX_RLIFE; + } else { + switch (second_token[0]) { + case 's': + KDB5_MAX_REN_LIFE = atoi(first_token); + break; + case 'm': + KDB5_MAX_REN_LIFE = atoi(first_token) * 60; + break; + case 'h': + KDB5_MAX_REN_LIFE = atoi(first_token) * 3600; + break; + case 'd': + KDB5_MAX_REN_LIFE = atoi(first_token) * 86400; + break; + case 'w': + KDB5_MAX_REN_LIFE = atoi(first_token) * 604800; + break; + case 'M': /* 30 days */ + KDB5_MAX_REN_LIFE = atoi(first_token) * 18144000; + break; + case 'y': /* 365 days */ + KDB5_MAX_REN_LIFE = atoi(first_token) * 220752000; + break; + case 'e': /* eternity */ + KDB5_MAX_REN_LIFE = 2145830400; + break; + default: + break; + } + } + return; + } + + + if (strcmp(parameter, "SET_EXP_DATE") == 0) { + (void) time(&todays_date); + switch (first_token[0]) { + case 'e': /* eternity */ + KDB5_EXP_DATE = 2145830400; + year = 2037; + month = 12; + mday = 30; + sprintf(first_token, "%s", "eternity"); + break; + case 'y': /* yesterday */ + KDB5_EXP_DATE = todays_date - 86400; + year = 1970; + month = 01; + mday = 01; + sprintf(first_token, "%s", "yesterday"); + break; + case '0': + case '1': + case '2': + case '3': + case '9': + sscanf(first_token, "%d/%d/%d", &year, &month, &mday); + year = (year > 1900) ? year - 1900 : year; + year = (year > 137) ? year - 100 : year; + year = (year > 137) ? 137 : year; + exp_date.tm_year = + ((year >= 00 && year < 38) || + (year >= 70 && year <= 138)) ? year : 137; + exp_date.tm_mon = + (month >= 1 && + month <= 12) ? month - 1 : 0; + exp_date.tm_mday = + (mday >= 1 && + mday <= 31) ? mday : 1; + exp_date.tm_hour = 0; + exp_date.tm_min = 1; + exp_date.tm_sec = 0; + KDB5_EXP_DATE = convert_tm_to_sec(&exp_date); + break; + default: + KDB5_EXP_DATE = KRB5_KDB_EXPIRATION; + sprintf(first_token, "%s", "Default KDB Expiration"); + break; + } + if (year < 1900) year += 1900; + if (year < 1938) year += 100; + return; + } + + if (strcmp(parameter, "SET_PWCHG") == 0) { + if (num_args < 2) { + NEW_ATTRIBUTES = NEW_ATTRIBUTES | KRB5_KDB_REQUIRES_PWCHANGE; + } else { + if (first_token[0] == 'y' || first_token[0] == 'Y') { + NEW_ATTRIBUTES = NEW_ATTRIBUTES | KRB5_KDB_REQUIRES_PWCHANGE; + } else { + NEW_ATTRIBUTES = NEW_ATTRIBUTES & ~KRB5_KDB_REQUIRES_PWCHANGE; + KDB5_VERSION_NUM = 1; + } + } + return; + } + + if (strcmp(parameter, "SET_PREAUTH") == 0) { + if (num_args < 2) { + NEW_ATTRIBUTES = NEW_ATTRIBUTES | KRB5_KDB_REQUIRES_PRE_AUTH; + } else { + if (first_token[0] == 'y' || first_token[0] == 'Y') { + NEW_ATTRIBUTES = NEW_ATTRIBUTES | KRB5_KDB_REQUIRES_PRE_AUTH; + } else { + NEW_ATTRIBUTES = NEW_ATTRIBUTES & ~KRB5_KDB_REQUIRES_PRE_AUTH; + } + } + return; + } + + if (strcmp(parameter, "SET_SECUREID") == 0) { + if (num_args < 2) { + NEW_ATTRIBUTES = NEW_ATTRIBUTES | KRB5_KDB_REQUIRES_HW_AUTH | + KRB5_KDB_REQUIRES_PRE_AUTH; + } else { + if (first_token[0] == 'y' || first_token[0] == 'Y') { + NEW_ATTRIBUTES = NEW_ATTRIBUTES | KRB5_KDB_REQUIRES_HW_AUTH | + KRB5_KDB_REQUIRES_PRE_AUTH; + } else { + NEW_ATTRIBUTES = NEW_ATTRIBUTES & ~KRB5_KDB_REQUIRES_HW_AUTH; + } + } + return; + } +} +#endif diff --git a/src/kadmin/server/adm_process.c b/src/kadmin/server/adm_process.c new file mode 100644 index 000000000..0e3d0d478 --- /dev/null +++ b/src/kadmin/server/adm_process.c @@ -0,0 +1,454 @@ +/* + * $Source$ + * $Author$ + * + * Copyright 1988 by the Massachusetts Institute of Technology. + * + * For copying and distribution information, please see the file + * . + * + */ + +/* + * 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 +#include +#include +#include +#include + +#include +#include +#ifndef hpux +#include +#endif + +#include +#include +#include +#include +#include +#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/ 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/ 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/ 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/ 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/ 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/ from master key"); + close(client_server_info.client_socket); + exit(0); + } + +/* + * To verify authenticity, we need to know the address of the + * client. + */ + + namelen = sizeof(client_server_info.client_addr); + if (getpeername(client_server_info.client_socket, + (struct sockaddr *) &client_server_info.client_addr, + &namelen) < 0) { + syslog(LOG_ERR, "kadmind error: Unable to Obtain Client Name."); + close(client_server_info.client_socket); + exit(0); + } + + /* we use mutual authentication */ + client_server_info.client_addr.addrtype = + client_server_info.client_name.sin_family; + client_server_info.client_addr.length = SIZEOF_INADDR; + client_server_info.client_addr.contents = + (krb5_octet *) &client_server_info.client_name.sin_addr; + + client_server_info.server_addr.addrtype = + client_server_info.server_name.sin_family; + client_server_info.server_addr.length = SIZEOF_INADDR; + client_server_info.server_addr.contents = + (krb5_octet *) &client_server_info.server_name.sin_addr; + + krb5_init_ets(); + + syslog(LOG_AUTH | LOG_INFO, + "Request for Administrative Service Received from %s - Authenticating.", + inet_ntoa( client_server_info.client_name.sin_addr )); + + if ((retval = krb5_recvauth( + (krb5_pointer) &client_server_info.client_socket, + ADM5_CPW_VERSION, + client_server_info.server, + &client_server_info.client_addr, + 0, + cpw_keyproc, + (krb5_pointer) &cpw_key, + 0, + &send_seqno, + &client_server_info.client, + &client_creds, + &client_auth_data + ))) { + syslog(LOG_ERR, "kadmind error: %s during recvauth\n", + error_message(retval)); + (void) sprintf(retbuf, "kadmind error during recvauth: %s\n", + error_message(retval)); + } else { + /* Check if ticket was issued using password (and not tgt) + within the last 5 minutes */ + + if (!(client_creds->enc_part2->flags & TKT_FLG_INITIAL)) { + syslog(LOG_ERR, + "Client ticket not initial"); + close(client_server_info.client_socket); + exit(0); + } + + if (retval = krb5_timeofday(&adm_time)) { + syslog(LOG_ERR, + "Can't get time of day"); + close(client_server_info.client_socket); + exit(0); + } + + if ((client_creds->enc_part2->times.authtime - adm_time) > 60*5) { + syslog(LOG_ERR, + "Client ticket not recent"); + close(client_server_info.client_socket); + exit(0); + } + + recv_seqno = client_auth_data->seq_number; + + if ((client_server_info.name_of_client = + (char *) calloc (1, 3 * 255)) == (char *) 0) { + syslog(LOG_ERR, "kadmind error: No Memory for name_of_client"); + close(client_server_info.client_socket); + exit(0); + } + + if ((retval = krb5_unparse_name(client_server_info.client, + &client_server_info.name_of_client))) { + syslog(LOG_ERR, "kadmind error: unparse failed.", + error_message(retval)); + goto finish; + } + + syslog(LOG_AUTH | LOG_INFO, + "Request for Administrative Service Received from %s at %s.", + client_server_info.name_of_client, + inet_ntoa( client_server_info.client_name.sin_addr )); + + /* compose the reply */ + outbuf.data[0] = KADMIND; + outbuf.data[1] = KADMSAG; + outbuf.length = 2; + } + + /* write back the response */ + if ((retval = krb5_write_message(&client_server_info.client_socket, + &outbuf))){ + syslog(LOG_ERR, "kadmind error: Write Message Failure: %s", + error_message(retval)); + retval = 1; + goto finish; + } + + /* Ok Now let's get the first private message and respond */ + if (retval = krb5_read_message(&client_server_info.client_socket, + &inbuf)){ + syslog(LOG_ERR, "kadmind error: read First Message Failure: %s", + error_message(retval)); + retval = 1; + goto finish; + } + + if ((retval = krb5_rd_priv(&inbuf, + client_creds->enc_part2->session, + &client_server_info.client_addr, + &client_server_info.server_addr, + client_auth_data->seq_number, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data))) { + syslog(LOG_ERR, "kadmind error: rd_priv:%s\n", error_message(retval)); + goto finish; + } + free(inbuf.data); + + request_type.appl_code = msg_data.data[0]; + request_type.oper_code = msg_data.data[1]; + + free(msg_data.data); + + switch (request_type.appl_code) { + case KPASSWD: + req_type = "kpasswd"; + if (retval = adm5_kpasswd("process_client", &request_type, + client_creds, retbuf, &otype)) { + goto finish; + } + break; + + case KADMIN: + req_type = "kadmin"; + if (retval = adm5_kadmin("process_client", client_auth_data, + client_creds, retbuf, &otype)) { + goto finish; + } + retbuf[0] = KADMIN; + retbuf[2] = KADMGOOD; + retbuf[3] = '\0'; + otype = 0; + break; + + default: + retbuf[0] = KUNKNOWNAPPL; + retbuf[1] = '\0'; + sprintf(completion_msg, "%s from %s (%02x) FAILED", + "Unknown Application Type!", + inet_ntoa(client_server_info.client_name.sin_addr), + request_type.appl_code); + /* Service Not Supported */ + retval = 255; + syslog(LOG_AUTH | LOG_INFO, completion_msg); + goto finish; + } /* switch(request_type.appl_code) */ + + if ((final_msg.data = (char *) calloc(1,10)) == (char *) 0) { + syslog(LOG_ERR | LOG_INFO, "no Memory while allocating final_msg.data"); + return ENOMEM; + } + final_msg.data = retbuf; + final_msg.length = strlen(retbuf) + 1; + + /* Send Completion Message */ + if (retval = krb5_mk_priv(&final_msg, + ETYPE_DES_CBC_CRC, + client_creds->enc_part2->session, + &client_server_info.server_addr, + &client_server_info.client_addr, + send_seqno, + KRB5_PRIV_DOSEQUENCE|KRB5_PRIV_NOTIME, + 0, + 0, + &msg_data)) { + syslog(LOG_ERR, "kadmind error Error Performing Final mk_priv"); + free(final_msg.data); + goto finish; + } + free(final_msg.data); + + /* Send Final Reply to Client */ + if (retval = krb5_write_message(&client_server_info.client_socket, + &msg_data)){ + syslog(LOG_ERR, "Error Performing Final Write: %s", + error_message(retval)); + retval = 1; + goto finish; + } + free(msg_data.data); + +finish: + + if (retval) { + free (client_server_info.name_of_client); + close(client_server_info.client_socket); + exit(1); + } + + sprintf(completion_msg, + "%s %s for %s at %s - Completed Successfully", + req_type, + oper_type[otype], + client_server_info.name_of_client, + inet_ntoa( client_server_info.client_name.sin_addr )); + syslog(LOG_AUTH | LOG_INFO, completion_msg); + free (client_server_info.name_of_client); + close(client_server_info.client_socket); + return 0; +} diff --git a/src/kadmin/server/adm_server.c b/src/kadmin/server/adm_server.c new file mode 100644 index 000000000..c61a8dad4 --- /dev/null +++ b/src/kadmin/server/adm_server.c @@ -0,0 +1,480 @@ +/* + * $Source$ + * $Author$ + * + * Copyright 1988 by the Massachusetts Institute of Technology. + * + * For copying and distribution information, please see the file + * . + * + * 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 +#include +#include +#include +#include + +#include +#ifndef sigmask +#define sigmask(m) (1 <<((m)-1)) +#endif + +#include +#include +#ifndef hpux +#include +#endif + +#ifndef __STDC__ +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include "adm_server.h" +#include "adm_extern.h" + +global_client_server_info client_server_info; + +#ifdef SANDIA +int classification; /* default = Unclassified */ +#endif + +krb5_flags NEW_ATTRIBUTES; + +cleanexit(val) + int val; +{ + (void) krb5_db_fini(); + exit(val); +} + +krb5_error_code +closedown_db() +{ + krb5_error_code retval; + + /* clean up master key stuff */ + retval = krb5_finish_key(&master_encblock); + + memset((char *)&master_encblock, 0, sizeof(master_encblock)); + memset((char *)tgs_key.contents, 0, tgs_key.length); + + /* close database */ + if (retval) { + (void) krb5_db_fini(); + return(retval); + } else + return(krb5_db_fini()); +} + +void +usage(name) +char *name; +{ + fprintf(stderr, "Usage: %s\t[-a aclfile] [-d dbname] [-k masterkeytype]", + name); + fprintf(stderr, "\n\t[-h] [-m] [-M masterkeyname] [-r realm]\n"); + return; +} + +krb5_error_code +process_args(argc, argv) +int argc; +char **argv; +{ + krb5_error_code retval; + int c; + krb5_boolean manual = FALSE; + int keytypedone = 0; + char *db_realm = 0; + char *mkey_name = 0; + char *local_realm; + krb5_enctype etype; + +#ifdef SANDIA + char input_string[80]; + FILE *startup_file; +#endif + + extern char *optarg; + +#ifdef SANDIA + classification = 0; + + if ((startup_file = + fopen(DEFAULT_KDCPARM_NAME, "r")) == (FILE *) 0) { + syslog(LOG_ERR, + "Cannot open parameter file (%s) - Using default parameters", + DEFAULT_KDCPARM_NAME); + syslog(LOG_ERR, "Only Unclassified Principals will be allowed"); + } else { + for ( ;; ) { + if ((fgets(input_string, sizeof(input_string), startup_file)) == NULL) + break; + kadmin_parse_and_set(input_string); + } + fclose(startup_file); + } +#endif + while ((c = getopt(argc, argv, "hmMa:d:k:r:")) != EOF) { + switch(c) { + case 'a': /* new acl directory */ + acl_file_name = optarg; + break; + + case 'd': + /* put code to deal with alt database place */ + dbm_db_name = optarg; + if (retval = krb5_dbm_db_set_name(dbm_db_name)) { + fprintf(stderr, "opening database %s: %s", + dbm_db_name, error_message(retval)); + exit(1); + } + break; + + case 'k': /* keytype for master key */ + master_keyblock.keytype = atoi(optarg); + keytypedone++; + break; + + case 'm': /* manual type-in of master key */ + manual = TRUE; + break; + + case 'M': /* master key name in DB */ + mkey_name = optarg; + break; + + case 'r': + db_realm = optarg; + break; + + case 'h': /* get help on using adm_server */ + default: + usage(argv[0]); + exit(1); /* Failure - Exit */ + } + + } + + if (!db_realm) { + /* no realm specified, use default realm */ + if (retval = krb5_get_default_realm(&local_realm)) { + com_err(argv[0], retval, + "while attempting to retrieve default realm"); + exit(1); + } + db_realm = local_realm; + } + + if (!mkey_name) { + mkey_name = KRB5_KDB_M_NAME; + } + + if (!keytypedone) { + master_keyblock.keytype = KEYTYPE_DES; + } + + /* assemble & parse the master key name */ + if (retval = krb5_db_setup_mkey_name(mkey_name, + db_realm, + (char **) 0, + &master_princ)) { + com_err(argv[0], retval, "while setting up master key name"); + exit(1); + } + + master_encblock.crypto_entry = &mit_des_cryptosystem_entry; + + if (retval = krb5_db_fetch_mkey( + master_princ, + &master_encblock, + manual, + FALSE, /* only read it once, if at all */ + 0, /* No salt supplied */ + &master_keyblock)) { + com_err(argv[0], retval, "while fetching master key"); + exit(1); + } + + /* initialize random key generators */ + for (etype = 0; etype <= krb5_max_cryptosystem; etype++) { + if (krb5_csarray[etype]) { + if (retval = (*krb5_csarray[etype]->system-> + init_random_key)(&master_keyblock, + &krb5_csarray[etype]->random_sequence)) { + com_err(argv[0], retval, + "while setting up random key generator for etype %d--etype disabled", + etype); + krb5_csarray[etype] = 0; + } + } + } + + return(0); +} + +krb5_error_code +init_db(dbname, masterkeyname, masterkeyblock) +char *dbname; +krb5_principal masterkeyname; +krb5_keyblock *masterkeyblock; + +{ + krb5_error_code retval; + + krb5_db_entry server_entry; + krb5_boolean more; + int number_of_entries; + char tgs_name[255]; + + /* set db name if appropriate */ + if (dbname && (retval = krb5_db_set_name(dbname))) + return(retval); + + /* initialize database */ + if (retval = krb5_db_init()) + return(retval); + + if (retval = krb5_db_verify_master_key(masterkeyname, + masterkeyblock, + &master_encblock)) { + master_encblock.crypto_entry = 0; + return(retval); + } + + /* do any necessary key pre-processing */ + if (retval = krb5_process_key(&master_encblock, masterkeyblock)) { + master_encblock.crypto_entry = 0; + (void) krb5_db_fini(); + return(retval); + } + +/* + fetch the TGS key, and hold onto it; this is an efficiency hack + the master key name here is from the master_princ global, + so we can safely share its substructure + */ + strcpy(tgs_name, TGTNAME); + strcat(tgs_name, "/"); + strcat(tgs_name, masterkeyname->realm.data); + krb5_parse_name(tgs_name, &tgs_server); + + tgs_server->type = KRB5_NT_SRV_INST; + + number_of_entries = 1; + if (retval = krb5_db_get_principal( + tgs_server, + &server_entry, + &number_of_entries, + &more)) { + return(retval); + } + + if (more) { + krb5_db_free_principal(&server_entry, number_of_entries); + (void) krb5_finish_key(&master_encblock); + memset((char *)&master_encblock, 0, sizeof(master_encblock)); + (void) krb5_db_fini(); + return(KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE); + } else if (number_of_entries != 1) { + krb5_db_free_principal(&server_entry, number_of_entries); + (void) krb5_finish_key(&master_encblock); + memset((char *)&master_encblock, 0, sizeof(master_encblock)); + (void) krb5_db_fini(); + return(KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN); + } + +/* + convert server.key into a real key + (it may be encrypted in the database) + */ + if (retval = KDB_CONVERT_KEY_OUTOF_DB(&server_entry.key, &tgs_key)) { + krb5_db_free_principal(&server_entry, number_of_entries); + (void) krb5_finish_key(&master_encblock); + memset((char *)&master_encblock, 0, sizeof(master_encblock)); + (void) krb5_db_fini(); + return(retval); + } + + tgs_kvno = server_entry.kvno; + krb5_db_free_principal(&server_entry, number_of_entries); + return(0); +} + +krb5_sigtype +request_exit() +{ + signal_requests_exit = 1; + return; +} + +void +setup_signal_handlers() +{ + krb5_sigtype request_exit(); + + (void)signal(SIGINT, request_exit); + (void)signal(SIGHUP, request_exit); + (void)signal(SIGTERM, request_exit); + return; +} + +static void +kdc_com_err_proc(whoami, code, format, pvar) + const char *whoami; + long code; + const char *format; + va_list pvar; +{ +#ifndef __STDC__ + extern int vfprintf(); +#endif + + if (whoami) { + fputs(whoami, stderr); + fputs(": ", stderr); + } + + if (code) { + fputs(error_message(code), stderr); + fputs(" ", stderr); + } + + if (format) { + vfprintf (stderr, format, pvar); + } + + putc('\n', stderr); + /* should do this only on a tty in raw mode */ + putc('\r', stderr); + fflush(stderr); + + if (format) { + /* now need to frob the format a bit... */ + if (code) { + char *nfmt; + nfmt = (char *) malloc( + strlen(format)+strlen(error_message(code))+2); + strcpy(nfmt, error_message(code)); + strcat(nfmt, " "); + strcat(nfmt, format); + vsyslog(LOG_ERR, nfmt, pvar); + } else { + vsyslog(LOG_ERR, format, pvar); + } + } else { + if (code) { + syslog(LOG_ERR, "%s", error_message(code)); + } + } + return; +} + +void +setup_com_err() +{ + initialize_krb5_error_table(); + initialize_kdb5_error_table(); + initialize_isod_error_table(); + + (void) set_com_err_hook(kdc_com_err_proc); + return; +} + +/* +** Main does the logical thing, it sets up the database and RPC interface, +** as well as handling the creation and maintenance of the syslog file... +*/ +main(argc, argv) /* adm_server main routine */ +int argc; +char **argv; +{ + krb5_error_code retval; + int errout = 0; + + adm5_ver_len = ADM5_VERSIZE; + + /* Get the Name of this program (adm_server) for Error Messages */ + if (strrchr(argv[0], '/')) + argv[0] = (char *)strrchr(argv[0], '/') + 1; + + setup_com_err(); + + /* Use Syslog for Messages */ +#ifndef LOG_AUTH /* 4.2 syslog */ +#define LOG_AUTH 0 + openlog(argv[0], LOG_CONS|LOG_NDELAY|LOG_PID, LOG_LOCAL6); +#else + openlog(argv[0], LOG_AUTH|LOG_CONS|LOG_NDELAY|LOG_PID, LOG_LOCAL6); +#endif /* LOG_AUTH */ + + process_args(argc, argv); /* includes reading master key */ + + setup_signal_handlers(); + + if (retval = init_db(dbm_db_name, + master_princ, + &master_keyblock)) { + com_err(argv[0], retval, "while initializing database"); + exit(1); + } + + if (retval = setup_network(argv[0])) { + exit(1); + } + + syslog(LOG_AUTH | LOG_INFO, "Admin Server Commencing Operation"); + + if (retval = adm5_listen_and_process(argv[0])){ + krb5_free_principal(client_server_info.server); + com_err(argv[0], retval, "while processing network requests"); + errout++; + } + + free(client_server_info.name_of_service); + krb5_free_principal(client_server_info.server); + +shutdown: + if (errout = closedown_network(argv[0])) { + com_err(argv[0], retval, "while shutting down network"); + retval = retval + errout; + } + + if (errout = closedown_db()) { + com_err(argv[0], retval, "while closing database"); + retval = retval + errout; + } + + syslog(LOG_AUTH | LOG_INFO, "Admin Server Shutting Down"); + + printf("Admin Server (kadmind) has completed operation.\n"); + + exit(retval); +} diff --git a/src/kadmin/server/adm_server.h b/src/kadmin/server/adm_server.h new file mode 100644 index 000000000..d5b600a59 --- /dev/null +++ b/src/kadmin/server/adm_server.h @@ -0,0 +1,43 @@ +/* + * $Source$ + * $Author$ + * $Id$ + * + * Copyright 1990 by the Massachusetts Institute of Technology. + * + * Export of this software from the United States of America is assumed + * to require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * Sandia National Laboratories also makes no representations about the + * suitability of the modifications, or additions to this software for + * any purpose. It is provided "as is" without express or implied warranty. + * + * <<< Description >>> + */ + +char prog[32]; +char *progname = prog; +char *acl_file_name = DEFAULT_ACL_NAME; +char *adm5_ver_str = ADM5_VERSTR; +int adm5_ver_len; + +char *adm5_tcp_portname = ADM5_PORTNAME; +int adm5_tcp_port_fd = -1; + +unsigned pidarraysize = 0; +int *pidarray = (int *) 0; + +int exit_now = 0; diff --git a/src/kadmin/server/adm_v4_pwd.c b/src/kadmin/server/adm_v4_pwd.c new file mode 100644 index 000000000..65ccefe5c --- /dev/null +++ b/src/kadmin/server/adm_v4_pwd.c @@ -0,0 +1,437 @@ + +/* + * Sandia National Laboratories also makes no representations about the + * suitability of the modifications, or additions to this software for + * any purpose. It is provided "as is" without express or implied warranty. + */ + +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include +#include + +#include "adm_extern.h" + +struct saltblock { + int salttype; + krb5_data saltdata; +}; + +struct cpw_keyproc_arg { + krb5_keyblock *key; +}; + +/* +process_v4_kpasswd +unwrap the data stored in dat, process, and return it. + */ +process_v4_kpasswd(dat, dat_len, cpw_key) +u_char **dat; +int *dat_len; +struct cpw_keyproc_arg *cpw_key; + +{ + u_char *in_st; /* pointer into the sent packet */ + int in_len,retc; /* where in packet we are, for + returns */ + u_long r_len; /* length of the actual packet */ + KTEXT_ST authent; /* the authenticator */ + AUTH_DAT ad; /* who is this, klink */ + u_long ncksum; /* checksum of encrypted data */ + des_key_schedule sess_sched; /* our schedule */ + MSG_DAT msg_st; + u_char *retdat, *tmpdat; + int retval, retlen; + u_short dlen; + extern int errno; + + if (strncmp(KADM_VERSTR, (char *) *dat, KADM_VERSIZE)) { + syslog(LOG_ERR, "process_v4_kpasswd: Bad Version String"); + return(1); + } + + in_len = KADM_VERSIZE; + /* get the length */ + if ((retc = stv_long(*dat, &r_len, in_len, *dat_len)) < 0) { + syslog(LOG_AUTH | LOG_INFO, "process_v4_kpasswd: Bad Length"); + return(1); + } + + in_len += retc; + authent.length = *dat_len - r_len - KADM_VERSIZE - sizeof(u_long); + memcpy((char *) authent.dat, (char *) (*dat) + in_len, authent.length); + authent.mbz = 0; + + if (retval = krb_set_key(cpw_key->key->contents, 0) != 0) { + syslog(LOG_ERR, "process_v4_kpasswd: Bad set_key Request"); + return(1); + } + + /* service key should be set before here */ + if (retc = krb4_rd_req(&authent, + CPWNAME, + client_server_info.server->realm.data, + client_server_info.client_name.sin_addr.s_addr, + &ad, + (char *) 0)) { + syslog(LOG_AUTH | LOG_INFO, "process_v4_kpasswd: Bad Read Request"); + return(1); + } + +#define clr_cli_secrets() \ +{ \ + memset((char *) sess_sched, 0, sizeof(sess_sched)); \ + memset((char *) ad.session, 0, sizeof(ad.session)); \ +} + + in_st = *dat + *dat_len - r_len; + ncksum = des_quad_cksum(in_st, (u_long *) 0, (long) r_len, 0, ad.session); + if (ncksum!=ad.checksum) { /* yow, are we correct yet */ + clr_cli_secrets(); + syslog(LOG_ERR, "process_v4_kpasswd: Invalid Checksum"); + return(1); + } + + des_key_sched(ad.session, sess_sched); + + if (retc = (int) krb4_rd_priv(in_st, + r_len, + sess_sched, + ad.session, + &client_server_info.client_name, + &client_server_info.server_name, + &msg_st)) { + syslog(LOG_ERR, "process_v4_kpasswd: Bad Read Private Code = %d", + retc); + clr_cli_secrets(); + return(1); + } + + if (msg_st.app_data[0] != 2) { /* Only Valid Request is CHANGE_PW = 2 */ + syslog(LOG_ERR, "process_v4_kpasswd: Invalid V4 Request"); + clr_cli_secrets(); + return(1); + } + + retval = adm_v4_cpw(msg_st.app_data+1, + (int) msg_st.app_length, + &ad, + &retdat, + &retlen); + + if (retval) { + syslog(LOG_ERR, + "process_v4_kpasswd: Password Modification for %s%s%s Failed", + ad.pname, (ad.pinst[0] != '\0') ? "/" : "", + (ad.pinst[0] != '\0') ? ad.pinst : ""); + } else { + syslog(LOG_ERR, + "process_v4_kpasswd: Password Modification for %s%s%s Complete", + ad.pname, (ad.pinst[0] != '\0') ? "/" : "", + (ad.pinst[0] != '\0') ? ad.pinst : ""); + } + + /* Now seal the response back into a priv msg */ + free((char *)*dat); + tmpdat = (u_char *) malloc((unsigned)(retlen + KADM_VERSIZE + + sizeof(u_long))); + + (void) strncpy((char *) tmpdat, KADM_VERSTR, KADM_VERSIZE); + + retval = htonl((u_long) retval); + + memcpy((char *) tmpdat + KADM_VERSIZE, (char *) &retval, sizeof(u_long)); + + if (retlen) { + memcpy((char *) tmpdat + KADM_VERSIZE + sizeof(u_long), + (char *) retdat, retlen); + free((char *) retdat); + } + + /* slop for mk_priv stuff */ + *dat = (u_char *) malloc((unsigned) (retlen + KADM_VERSIZE + + sizeof(u_long) + 200)); + + if ((*dat_len = krb4_mk_priv(tmpdat, *dat, + (u_long) (retlen + KADM_VERSIZE + + sizeof(u_long)), + sess_sched, + ad.session, + &client_server_info.server_name, + &client_server_info.client_name)) < 0) { + clr_cli_secrets(); + syslog(LOG_ERR, "process_v4_kpasswd: Bad mk_priv"); + return(1); + } + + dlen = (u_short) *dat_len; + + dlen = htons(dlen); + + if (krb5_net_write(client_server_info.client_socket, + (char *) &dlen, 2) < 0) { + syslog(LOG_ERR, "process_v4_kpasswd: Error writing dlen to client"); + (void) close(client_server_info.client_socket); + } + + if (krb5_net_write(client_server_info.client_socket, + (char *) *dat, *dat_len) < 0) { + syslog(LOG_ERR, "writing to client: %s",error_message(errno)); + (void) close(client_server_info.client_socket); + } + + free((char *) *dat); + clr_cli_secrets(); + + return(0); +} + +krb5_kvno +princ_exists(principal, entry) +krb5_principal principal; +krb5_db_entry *entry; +{ + int nprincs = 1; + krb5_boolean more; + krb5_error_code retval; + krb5_kvno vno; + + nprincs = 1; + if (retval = krb5_db_get_principal(principal, entry, &nprincs, &more)) { + return 0; + } + + if (!nprincs) + return 0; + + return(nprincs); +} + +/* +adm_v4_cpw - the server side of the change_password routine + recieves : KTEXT, {key} + returns : CKSUM, RETCODE + acl : caller can change only own password + +Replaces the password (i.e. des key) of the caller with that specified in key. +Returns no actual data from the master server, since this is called by a user +*/ +int +adm_v4_cpw(dat, len, ad, datout, outlen) +u_char *dat; +int len; +AUTH_DAT *ad; +u_char **datout; +int *outlen; +{ + krb5_db_entry entry; + krb5_keyblock *v5_keyblock; + + int number_of_principals; + krb5_error_code retval; + int one = 1; + char v5_principal[255]; + + C_Block v4_clear_key; + unsigned long keylow, keyhigh; + int stvlen; + + /* Identify the Customer */ + (void) sprintf(v5_principal, "%s%s%s\0", ad->pname, + (ad->pinst[0] != '\0') ? "/" : "", + (ad->pinst[0] != '\0') ? ad->pinst : ""); + + /* take key off the stream, and change the database */ + + if ((stvlen = stv_long(dat, &keyhigh, 0, len)) < 0) { + syslog(LOG_ERR, "adm_v4_cpw - (keyhigh) Length Error for stv_long"); + return(1); + } + if (stv_long(dat, &keylow, stvlen, len) < 0) { + syslog(LOG_ERR, "adm_v4_cpw - (keylow) Length Error for stv_long"); + return(1); + } + + keylow = ntohl(keylow); + keyhigh = ntohl(keyhigh); + + /* Convert V4 Key to V5 Key */ + (void) memcpy(v4_clear_key, (char *) &keylow, 4); + (void) memcpy(((long *) v4_clear_key) + 1, (char *) &keyhigh, 4); + + /* Zero Next Output Entry */ + memset((char *) &entry, 0, sizeof(entry)); + + if (retval = krb5_parse_name(v5_principal, &entry.principal)) { + syslog(LOG_ERR, "adm_v4_cpw - Error parsing %s", + v5_principal); + return(1); + } + + if (!(number_of_principals = princ_exists(entry.principal, &entry))) { + syslog(LOG_ERR, "adm_v4_cpw - principal %s is NOT in the database", + v5_principal); + return(1); + } + + /* Allocate v5_keyblock and fill some fields */ + if (!(v5_keyblock = (krb5_keyblock *) calloc (1, + sizeof(krb5_keyblock)))) { + syslog(LOG_ERR, "adm_v4_cpw - Error Allocating krb5_keyblock"); + return(1); + } + + v5_keyblock->keytype = KEYTYPE_DES; + v5_keyblock->length = 8; + if (!(v5_keyblock->contents = (krb5_octet *) calloc (1, + 8))) { + syslog(LOG_ERR, + "adm_v4_cpw - Error Allocating krb5_keyblock->contents\n"); + free(v5_keyblock); + return(1); + } + + memcpy(v5_keyblock->contents, v4_clear_key, 8); + + if (retval = krb5_kdb_encrypt_key(&master_encblock, + v5_keyblock, + &entry.key)) { + syslog(LOG_ERR, + "adm_v4_cpw - Error %d while encrypting key for '%s'\n", retval, + v5_principal); + return(1); + } + entry.alt_key.length = 0; + + /* Increment Version Number */ + entry.kvno = entry.kvno + 1; +#ifdef SANDIA + entry.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE; +#endif + if (retval = krb5_timeofday(&entry.mod_date)) { + syslog(LOG_ERR, "adm_v4_cpw - Error while fetching date"); + return(1); + } +#ifdef SANDIA + entry.last_pwd_change = entry.mod_date; +#endif + entry.mod_name = entry.principal; /* Should be Person who did Action */ + + /* Write the Modified Principal to the V5 Database */ + if (retval = krb5_db_put_principal(&entry, &one)) { + syslog(LOG_ERR, + "adm_v4_cpw - Error %d while Entering Principal for '%s'", + retval, v5_principal); + return(1); + } + + *datout = 0; + *outlen = 0; + + return(0); +} + +stv_long(st, dat, loc, maxlen) +u_char *st; /* a base pointer to the stream */ +u_long *dat; /* the attributes field */ +int loc; /* offset into the stream for current data */ +int maxlen; /* maximum length of st */ +{ + u_long temp = 0; /* to hold the net order short */ + +#ifdef BITS64 + if (loc + 4 > maxlen) + return(-1); + (void) memcpy((char *) &temp + 4, (char *) ((u_long)st + (u_long)loc), 4); + *dat = ntohl(temp); /* convert to network order */ + return(4); +#else + if (loc + sizeof(u_long) > maxlen) + return(-1); + (void) memcpy((char *) &temp, (char *) ((u_long)st + (u_long)loc), + sizeof(u_long)); + *dat = ntohl(temp); /* convert to network order */ + return(sizeof(u_long)); +#endif +} diff --git a/src/kadmin/server/kadmind.M b/src/kadmin/server/kadmind.M new file mode 100644 index 000000000..e69de29bb