Index: Makefile =================================================================== RCS file: /networking/master_src/tac_plus/Makefile,v retrieving revision 1.1.1.2 retrieving revision 1.4 diff -c -r1.1.1.2 -r1.4 *** Makefile 1998/07/02 19:34:17 1.1.1.2 --- Makefile 1998/07/14 20:16:15 1.4 *************** *** 17,23 **** # LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE. ! # CC = gcc # For AIX # See /usr/lpp/bos/bsdport on your system for details of how to define bsdcc --- 17,23 ---- # LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE. ! CC = gcc # For AIX # See /usr/lpp/bos/bsdport on your system for details of how to define bsdcc *************** *** 31,38 **** # OS=-DMIPS # For Solaris (SUNOS 5.3, 5.4) uncomment the following two lines ! # OS=-DSOLARIS ! # OSLIBS=-lsocket -lnsl # For FreeBSD # OS=-DFREEBSD --- 31,38 ---- # OS=-DMIPS # For Solaris (SUNOS 5.3, 5.4) uncomment the following two lines ! OS=-DSOLARIS ! OSLIBS=-lsocket -lnsl # For FreeBSD # OS=-DFREEBSD *************** *** 61,72 **** # INCLUDES = -I../crimelab/skey/src # Debugging flags ! DEBUG = -g # Enforce a limit on maximum sessions per user. See the user's guide # for more information. MAXSESS = -DMAXSESS # Microsoft CHAP extension support. See the user's guide for more # information. # MSCHAP = -DMSCHAP --- 61,75 ---- # INCLUDES = -I../crimelab/skey/src # Debugging flags ! DEBUG = -g -O # Enforce a limit on maximum sessions per user. See the user's guide # for more information. MAXSESS = -DMAXSESS + OPTIONS = -DUSE_KRB4 -DUSE_KRB5 -I/usr/pubsw/include + OPT_LIBS = -L/usr/pubsw/lib -lkrb -ldes -lcom_err -lkrb5 -lcrypto + # Microsoft CHAP extension support. See the user's guide for more # information. # MSCHAP = -DMSCHAP *************** *** 83,89 **** # End of customisable section of Makefile # ! CFLAGS = $(DEBUG) $(DEFINES) $(INCLUDES) $(FLAGS) $(OS) $(PIDFILE) $(MAXSESS) HFILES = expire.h parse.h regmagic.h md5.h regexp.h tac_plus.h --- 86,92 ---- # End of customisable section of Makefile # ! CFLAGS = $(DEBUG) $(DEFINES) $(INCLUDES) $(OPTIONS) $(FLAGS) $(OS) $(PIDFILE) $(MAXSESS) HFILES = expire.h parse.h regmagic.h md5.h regexp.h tac_plus.h *************** *** 91,97 **** do_author.c dump.c encrypt.c expire.c $(MSCHAP_MD4_SRC) md5.c \ packet.c report.c sendauth.c tac_plus.c utils.c pw.c hash.c \ parse.c regexp.c programs.c enable.c pwlib.c default_fn.c \ ! skey_fn.c default_v0_fn.c sendpass.c maxsess.c OBJS = $(SRCS:.c=.o) --- 94,100 ---- do_author.c dump.c encrypt.c expire.c $(MSCHAP_MD4_SRC) md5.c \ packet.c report.c sendauth.c tac_plus.c utils.c pw.c hash.c \ parse.c regexp.c programs.c enable.c pwlib.c default_fn.c \ ! skey_fn.c default_v0_fn.c sendpass.c maxsess.c krb_fn.c auth_krb.c OBJS = $(SRCS:.c=.o) *************** *** 99,105 **** @echo "Please edit the Makefile and then make tac_plus" tac_plus: $(OBJS) $(LIBS) generate_passwd ! $(CC) -o tac_plus $(CFLAGS) $(OBJS) $(LIBS) $(OSLIBS) purecov: $(OBJS) $(LIBS) purecov -follow-child-processes -handle-signals=SIGTERM \ --- 102,108 ---- @echo "Please edit the Makefile and then make tac_plus" tac_plus: $(OBJS) $(LIBS) generate_passwd ! $(CC) -o tac_plus $(CFLAGS) $(OBJS) $(LIBS) $(OSLIBS) $(OPT_LIBS) purecov: $(OBJS) $(LIBS) purecov -follow-child-processes -handle-signals=SIGTERM \ Index: acct.c =================================================================== RCS file: /networking/master_src/tac_plus/acct.c,v retrieving revision 1.1.1.2 retrieving revision 1.2 diff -c -r1.1.1.2 -r1.2 *** acct.c 1998/07/02 19:34:01 1.1.1.2 --- acct.c 1998/07/27 21:48:56 1.2 *************** *** 108,118 **** identity.NAS_port = tac_make_string(p, (int)acct_pak->port_len); p += acct_pak->port_len; if (acct_pak->port_len <= 0) { ! strcpy(session.port, "unknown-port"); } else { ! strcpy(session.port, identity.NAS_port); } ! identity.NAC_address = tac_make_string(p, (int)acct_pak->rem_addr_len); p += acct_pak->rem_addr_len; --- 108,118 ---- identity.NAS_port = tac_make_string(p, (int)acct_pak->port_len); p += acct_pak->port_len; if (acct_pak->port_len <= 0) { ! tac_strcpy(session.port, "unknown-port",NAS_PORT_MAX_LEN); } else { ! tac_strcpy(session.port, identity.NAS_port,NAS_PORT_MAX_LEN); } ! identity.NAC_address = tac_make_string(p, (int)acct_pak->rem_addr_len); p += acct_pak->rem_addr_len; Index: auth_krb.c =================================================================== RCS file: auth_krb.c diff -N auth_krb.c *** /tmp/da003x6 Thu Aug 13 16:16:57 1998 --- /var/tmp/aaaa003wx Thu Aug 13 16:40:22 1998 *************** *** 0 **** --- 1,842 ---- + /* Stealing the useful bits from MIT K5 src/appl/bsd/login.c */ + + + + + /* + * appl/bsd/login.c + */ + + /* + * 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 */ + + /* based on @(#)login.c 5.25 (Berkeley) 1/6/89 */ + + /* While the code may be compiled with some of these options turned off, + the default will be to turn them *all* on if v4 compatibility is + available, and allow them to be configured via krb5.conf. */ + /* The configuration is of the form + [login] + # login stanza + krb5_get_tickets = 1 + # use password to get v5 tickets + krb4_get_tickets = 1 + # use password to get v4 tickets + + */ + #define KRB5_GET_TICKETS 1 + int login_krb5_get_tickets = 1; + #define KRB4_GET_TICKETS 1 + int login_krb4_get_tickets = 1; + + /* + */ + + #define HAVE_UNISTD_H + #define HAVE_STDLIB_H + + #ifdef HAVE_UNISTD_H + #include + #endif + #ifdef HAVE_STDLIB_H + #include + #endif + #include + #include + #ifdef OQUOTA + #include + #endif + #include + #include + #include + #include + #include + #include + + #include + #include + + #include + + + #ifdef linux + /* linux has V* but not C* in headers. Perhaps we shouldn't be + * initializing these values anyway -- tcgetattr *should* give + * them reasonable defaults... */ + #define NO_INIT_CC + #endif + + #include + + #include + #include + #include + #include + #include + + + #ifdef KRB5_GET_TICKETS + #include + /* need k5-int.h to get ->profile from krb5_context */ + /* include "k5-int.h" */ + #include + /* include "osconf.h" */ + #endif /* KRB5_GET_TICKETS */ + + #ifdef KRB4_KLOGIN + /* support for running under v4 klogind, -k -K flags */ + #define KRB4 + #endif + + #if (defined(KRB4_GET_TICKETS) || defined(KRB4_CONVERT)) + /* support for prompting for v4 initial tickets */ + #define KRB4 + #endif + + #ifdef KRB4 + #include + #include + #include + #ifdef HAVE_KRB4_PROTO_H + #include + #endif + #include + #ifdef BIND_HACK + #include + #include + #endif /* BIND_HACK */ + + /* Hacks to maintain compatability with Athena libkrb*/ + #ifndef HAVE_KRB_SAVE_CREDENTIALS + #define krb_save_credentials save_credentials + #endif /*HAVE_KRB_SAVE_CREDENTIALS*/ + + #ifndef HAVE_KRB_GET_ERR_TEXT + + #ifndef KRB5_ENV_CCNAME + #define KRB5_ENV_CCNAME "KRB5CCNAME" + #endif + + + static const char * krb_get_err_text(kerror) + int kerror; + { + return krb_err_txt[kerror]; + } + + #endif /*HAVE_KRB_GET_ERR_TEXT*/ + #endif /* KRB4 */ + + #ifndef __STDC__ + #ifndef volatile + #define volatile + #endif + #endif + + #ifdef _IBMR2 + #include + #include + #endif + + #if defined(_AIX) + #define PRIO_OFFSET 20 + #else + #define PRIO_OFFSET 0 + #endif + + #if !defined(TAB3) + #define TAB3 0 + #endif + + #include "tac_plus.h" + + #define MAXENVIRON 32 + + /* + * 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; + + char term[64], *hostname, *username; + + extern int errno; + + #ifdef KRB4 + #define KRB_ENVIRON "KRBTKFILE" /* Ticket file environment variable */ + #define KRB_TK_DIR "/tmp/tkt_tacacs" /* Where to put the ticket */ + #endif /* KRB4_GET_TICKETS */ + + #if defined(KRB4_GET_TICKETS) || defined(KRB5_GET_TICKETS) + #define MAXPWSIZE 128 /* Biggest string accepted for KRB4 + passsword */ + #endif + + + + + + #ifdef KRB5_GET_TICKETS + static struct login_confs { + char *flagname; + int *flag; + } login_conf_set[] = { + "krb5_get_tickets", &login_krb5_get_tickets, + #ifdef KRB5_KRB4_COMPAT + "krb4_get_tickets", &login_krb4_get_tickets, + "krb4_convert", &login_krb4_convert, + "krb4_run_aklog", &login_krb_run_aklog, + #endif /* KRB5_KRB4_COMPAT */ + }; + static char *conf_yes[] = { + "y", "yes", "true", "t", "1", "on", + 0 + }; + static char *conf_no[] = { + "n", "no", "false", "nil", "0", "off", + 0 + }; + /* 1 = true, 0 = false, -1 = ambiguous */ + static int conf_affirmative(s) + char *s; + { + char **p; + for(p=conf_yes; *p; p++) { + if (!strcasecmp(*p,s)) + return 1; + } + for(p=conf_no; *p; p++) { + if (!strcasecmp(*p,s)) + return 0; + } + /* ambiguous */ + return -1; + } + #endif /* KRB5_GET_TICKETS */ + + #ifdef KRB5_GET_TICKETS + krb5_data tgtname = { + 0, + KRB5_TGS_NAME_SIZE, + KRB5_TGS_NAME + }; + #endif + + + + + /* Kerberos support */ + #ifdef KRB5_GET_TICKETS + krb5_context kcontext; + krb5_ccache ccache; + static int got_v5_tickets, got_v4_tickets; + char ccfile[MAXPATHLEN+6]; /* FILE:path+\0 */ + int krbflag; /* set if tickets have been obtained */ + + #ifdef KRB4_GET_TICKETS + AUTH_DAT *kdata = (AUTH_DAT *) NULL; + KTEXT ticket = (KTEXT) NULL; + char tkfile[MAXPATHLEN]; + char realm[REALM_SZ]; + #endif + + int k_init (uniq_str,do_kerberos) + char *uniq_str; + { + krb5_error_code retval; + + if ( do_kerberos > 4 ) { /* What the &(*&^( was I thinking... */ + retval = krb5_init_context(&kcontext); + if (retval) { + report( LOG_DEBUG, "error %d while initializing krb5",retval); + return -1; + } + retval = krb5_secure_config_files (kcontext); + + if (retval) { + report( LOG_DEBUG, "error %d while initializing krb5",retval); + return -1; + } + + + /* Set up the credential cache environment variable */ + if (!getenv(KRB5_ENV_CCNAME)) { + sprintf(ccfile, "FILE:/tmp/krb5cc_%s", uniq_str); + krb5_setenv(KRB5_ENV_CCNAME, ccfile, 1); + unlink(ccfile+strlen("FILE:")); + } else { + /* note it correctly */ + strncpy(ccfile, getenv(KRB5_ENV_CCNAME),sizeof(ccfile)); + } + } + #ifdef KRB4_GET_TICKETS + if ( do_kerberos < 5 ) { + if (krb_get_lrealm(realm, 1) != KSUCCESS) { + strncpy(realm, KRB_REALM, sizeof(realm)); + } + + if (login_krb4_get_tickets) { + /* Set up the ticket file environment variable */ + strncpy(tkfile, KRB_TK_DIR, sizeof(tkfile)); + strncat(tkfile, uniq_str, + sizeof(tkfile) - strlen(tkfile)); + (void) unlink (tkfile); + krb5_setenv(KRB_ENVIRON, tkfile, 1); + } + } + #endif + + #ifdef BIND_HACK + /* Set name server timeout to be reasonable, + so that people don't take 5 minutes to + log in. Can you say abstraction violation? */ + _res.retrans = 1; + #endif /* BIND_HACK */ + return 0 ; + } + + + #define KRB5_DEFAULT_LIFE 60*5 /* 5 minutes */ + int krb5_options = 0; + krb5_deltat krb5_ticket_lifetime = KRB5_DEFAULT_LIFE; + + int try_krb5 (name, pass) + char *name; + char *pass; + { + krb5_error_code code; + krb5_principal server, me; + krb5_creds my_creds; + krb5_timestamp now; + krb5_deltat lifetime = krb5_ticket_lifetime; + + /* set up credential cache -- obeying KRB5_ENV_CCNAME + set earlier */ + /* (KRB5_ENV_CCNAME == "KRB5CCNAME" via osconf.h) */ + if ((code = krb5_cc_default(kcontext, &ccache))) { + report( LOG_DEBUG, "error %d while getting default ccache",code); + return 0; + } + /* setup code from v5 kinit */ + memset((char *)&my_creds, 0, sizeof(my_creds)); + + code = krb5_parse_name (kcontext, name, &me); + if (code) { + report( LOG_DEBUG,"error %d when parsing name %s",code,name); + return 0; + } + + my_creds.client = me; + + code = krb5_cc_initialize (kcontext, ccache, me); + if (code) { + report( LOG_DEBUG,"error %d when initializing cache",code); + return 0; + } + + code = krb5_build_principal_ext(kcontext, &server, + krb5_princ_realm(kcontext, me)->length, + krb5_princ_realm(kcontext, me)->data, + tgtname.length, tgtname.data, + krb5_princ_realm(kcontext, me)->length, + krb5_princ_realm(kcontext, me)->data, + 0); + if (code) { + report( LOG_DEBUG, "error %d while building server name",code); + goto nuke_ccache; + } + + my_creds.server = server; + code = krb5_timeofday(kcontext, &now); + if (code) { + report( LOG_DEBUG, "error %d while getting time of day",code); + goto nuke_ccache; + } + my_creds.times.starttime = 0; /* start timer when + request gets to KDC */ + my_creds.times.endtime = now + lifetime; + my_creds.times.renew_till = 0; + + code = krb5_get_in_tkt_with_password(kcontext, krb5_options, + 0, NULL, 0 /*preauth*/, + pass, + ccache, + &my_creds, 0); + + if (code) { + if (code == KRB5KRB_AP_ERR_BAD_INTEGRITY) + report(LOG_INFO, + "%s: Kerberos password incorrect\n", + username); + else + report( LOG_INFO,"error %d while getting initial credentials",code); + nuke_ccache: + krb5_cc_destroy (kcontext, ccache); + return 0; + } else { + /* get_name pulls out just the name not the + type */ + strncpy(ccfile, krb5_cc_get_name(kcontext, ccache),sizeof(ccfile)); + krbflag = got_v5_tickets = 1; + return 1; + } + } + + int have_v5_tickets (me) + krb5_principal *me; + { + if (krb5_cc_default (kcontext, &ccache)) + return 0; + if (krb5_cc_get_principal (kcontext, ccache, me)) { + krb5_cc_close (kcontext, ccache); + return 0; + } + krbflag = 1; + return 1; + } + + + #ifdef KRB4_GET_TICKETS + try_krb4 (username, user_pwstring) + char *username ; + char *user_pwstring; + { + int krbval, kpass_ok = 0; + + krbval = krb_get_pw_in_tkt(username, "", realm, + "krbtgt", realm, + DEFAULT_TKT_LIFE, + user_pwstring); + + switch (krbval) { + case INTK_OK: + kpass_ok = 1; + krbflag = 1; + strncpy(tkfile, tkt_string(),sizeof(tkfile)); + break; + + case KDC_NULL_KEY: + case KDC_PR_UNKNOWN: + case INTK_BADPW: + case KDC_PR_N_UNIQUE: + case -1: + report(LOG_INFO, "Kerberos error: %s for %s\n", + krb_get_err_text(krbval),username); + break; + #if 0 /* I want to see where INTK_W_NOTALL comes from before letting + kpass_ok be set in that case. KR */ + /* These should be printed but are not fatal */ + case INTK_W_NOTALL: + krbflag = 1; + kpass_ok = 1; + report(LOG_DEBUG, "Kerberos error: %s\n", + krb_get_err_text(krbval)); + break; + #endif + default: + report(LOG_DEBUG, "Kerberos error: %s\n", + krb_get_err_text(krbval)); + break; + } + report(LOG_DEBUG, "Kerberos status: %s\n", krb_get_err_text(krbval)); + + got_v4_tickets = kpass_ok; + return kpass_ok; + } + #endif /* KRB4_GET_TICKETS */ + + /* Kerberos ticket-handling routines */ + + #ifdef KRB4_GET_TICKETS + /* call already conditionalized on login_krb4_get_tickets */ + /* + * Verify the Kerberos ticket-granting ticket just retrieved for the + * user. If the Kerberos server doesn't respond, assume the user is + * trying to fake us out (since we DID just get a TGT from what is + * supposedly our KDC). If the rcmd. service is unknown (i.e., + * the local srvtab doesn't have it), let her in. + * + * Returns 1 for confirmation, -1 for failure, 0 for uncertainty. + */ + int verify_krb_v4_tgt (realm) + char *realm; + { + char hostname[MAXHOSTNAMELEN], phost[BUFSIZ]; + struct hostent *hp; + KTEXT_ST ticket; + AUTH_DAT authdata; + unsigned long addr; + static /*const*/ char rcmd[] = "rcmd"; + char key[8]; + int krbval, retval, have_keys; + + if (gethostname(hostname, sizeof(hostname)) == -1) { + report (LOG_DEBUG,"cannot retrieve local hostname"); + return -1; + } + strncpy (phost,(char *) krb_get_phost (hostname), sizeof (phost)); + phost[sizeof(phost)-1] = 0; + hp = gethostbyname (hostname); + if (!hp) { + report(LOG_DEBUG,"cannot retrieve local host address"); + return -1; + } + memcpy ((char *) &addr, (char *)hp->h_addr, sizeof (addr)); + /* Do we have rcmd. keys? */ + #if 0 /* Be paranoid. If srvtab exists, assume it must contain the + right key. */ + have_keys = read_service_key (rcmd, phost, realm, 0, KEYFILE, key) + ? 0 : 1; + memset (key, 0, sizeof (key)); + #else + have_keys = 0 == access (KEYFILE, F_OK); + #endif + krbval = krb_mk_req (&ticket, rcmd, phost, realm, 0); + if (krbval == KDC_PR_UNKNOWN) { + /* + * Our rcmd. principal isn't known -- just assume valid + * for now? This is one case that the user _could_ fake out. + */ + if (have_keys) + return -1; + else + return 0; + } + else if (krbval != KSUCCESS) { + report(LOG_INFO,"Unable to verify Kerberos TGT: %s\n", + krb_get_err_text(krbval)); + #ifndef SYSLOG42 + syslog (LOG_NOTICE|LOG_AUTH, "Kerberos TGT bad: %s", + krb_get_err_text(krbval)); + #endif + return -1; + } + /* got ticket, try to use it */ + krbval = krb_rd_req (&ticket, rcmd, phost, addr, &authdata, ""); + if (krbval != KSUCCESS) { + if (krbval == RD_AP_UNDEC && !have_keys) + retval = 0; + else { + retval = -1; + report (LOG_DEBUG,"Unable to verify `rcmd' ticket: %s\n", + krb_get_err_text(krbval)); + } + #ifndef SYSLOG42 + syslog (LOG_NOTICE|LOG_AUTH, "can't verify rcmd ticket: %s;%s\n", + krb_get_err_text(krbval), + retval + ? "srvtab found, assuming failure" + : "no srvtab found, assuming success"); + #endif + goto EGRESS; + } + /* + * The rcmd. ticket has been received _and_ verified. + */ + retval = 1; + /* do cleanup and return */ + EGRESS: + memset (&ticket, 0, sizeof (ticket)); + memset (&authdata, 0, sizeof (authdata)); + return retval; + } + #endif /* KRB4_GET_TICKETS */ + + /* call already conditionalized on login_krb5_get_tickets */ + /* + * Verify the Kerberos ticket-granting ticket just retrieved for the + * user. If the Kerberos server doesn't respond, assume the user is + * trying to fake us out (since we DID just get a TGT from what is + * supposedly our KDC). If the host/ service is unknown (i.e., + * the local keytab doesn't have it), let her in. + * + * Returns 1 for confirmation, -1 for failure, 0 for uncertainty. + */ + int verify_krb_v5_tgt (c) + krb5_context c; + { + char phost[BUFSIZ]; + krb5_ccache ccdef; + int retval, have_keys; + krb5_principal princ; + krb5_keyblock *kb = 0; + krb5_error_code krbval; + krb5_data packet; + krb5_auth_context auth_context = NULL; + krb5_ticket *ticket = NULL; + + /* XXX This is to work around a library bug. I'm not sure if it's + been fixed for beta-7, so leave this in for now. Remove it (and + fix the bug if necessary) after beta-7 ships. + + Whoever wrote that comment didn't mention what the bug is! Ted + says it is something about the starttime of the ticket and + "now" being equal. He thinks it is fixed, but isn't sure. + */ + sleep(2); + + /* get the server principal for the local host */ + /* (use defaults of "host" and canonicalized local name) */ + krbval = krb5_sname_to_principal(c, 0, 0, KRB5_NT_SRV_HST, &princ); + if (krbval) { + report( LOG_DEBUG,"error %d constructing local service name",krbval); + return -1; + } + + /* since krb5_sname_to_principal has done the work for us, just + extract the name directly */ + strncpy(phost, krb5_princ_component(c, princ, 1)->data, BUFSIZ); + + /* Do we have host/ keys? */ + /* (use default keytab, kvno IGNORE_VNO to get the first match, + and enctype is currently ignored anyhow.) */ + krbval = krb5_kt_read_service_key (c, NULL, princ, 0, ENCTYPE_DES_CBC_CRC, &kb); + if (kb) + krb5_free_keyblock (c, kb); + /* any failure means we don't have keys at all. */ + have_keys = krbval ? 0 : 1; + + /* set up credential cache -- obeying KRB5_ENV_CCNAME set earlier */ + /* (KRB5_ENV_CCNAME == "KRB5CCNAME" via osconf.h) */ + if (krbval = krb5_cc_default(c, &ccdef)) { + report( LOG_DEBUG, "error %d while getting default ccache",krbval); + return -1; + } + /* talk to the kdc and construct the ticket */ + krbval = krb5_mk_req(c, &auth_context, 0, "host", phost, + 0, ccdef, &packet); + /* wipe the auth context for mk_req */ + if (auth_context) { + krb5_auth_con_free(c, auth_context); + auth_context = NULL; + } + if (krbval == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN) { + /* we have a service key, so something should be + in the database, therefore this error packet could + have come from an attacker. */ + if (have_keys) { retval = -1; goto EGRESS; } + /* but if it is unknown and we've got no key, we don't + have any security anyhow, so it is ok. */ + else { retval = 0; goto EGRESS; } + } + else if (krbval) { + report( LOG_INFO, + "error %d Unable to verify Kerberos V5 TGT: %s",krbval, phost); + #ifndef SYSLOG42 + syslog (LOG_NOTICE|LOG_AUTH, "Kerberos V5 TGT bad: %s", + error_message(krbval)); + #endif + retval = -1; + goto EGRESS; + } + /* got ticket, try to use it */ + krbval = krb5_rd_req(c, &auth_context, &packet, + princ, NULL, NULL, &ticket); + if (krbval) { + if (!have_keys) + /* The krb5 errors aren't specified well, but I think + these values cover the cases we expect. */ + switch (krbval) { + /* no keytab */ + case ENOENT: + /* keytab found, missing entry */ + #if 0 /* Don't depend on the nameserver for security. Assume that if + we have a keytab, it must contain the right host/FQDN key. */ + case KRB5_KT_NOTFOUND: + #endif + retval = 0; + break; + default: + /* unexpected error: fail */ + retval = -1; + break; + } + else + /* Any error here is bad. */ + retval = -1; + report( LOG_INFO, "error %d Unable to verify host ticket",krbval); + #ifndef SYSLOG42 + syslog (LOG_NOTICE|LOG_AUTH, "can't verify v5 ticket: %s; %s\n", + error_message(krbval), + retval + ? "keytab found, assuming failure" + : "no keytab found, assuming success"); + #endif + goto EGRESS; + } + /* + * The host/ ticket has been received _and_ verified. + */ + retval = 1; + /* do cleanup and return */ + EGRESS: + if (auth_context) krb5_auth_con_free(c, auth_context); + krb5_free_principal(c, princ); + /* possibly ticket and packet need freeing here as well */ + /* memset (&ticket, 0, sizeof (ticket)); */ + return retval; + } + + destroy_tickets() + { + krb5_context c; + krb5_ccache cache; + krb5_error_code retval; + + #ifdef KRB5_GET_TICKETS + if (login_krb5_get_tickets) { + if(!krb5_cc_default(kcontext, &cache)) + krb5_cc_destroy (kcontext, cache); + } + #endif + #ifdef KRB4_GET_TICKETS + if (login_krb4_get_tickets ) + dest_tkt(); + #endif /* KRB4_GET_TICKETS */ + } + + #endif /* KRB5_GET_TICKETS */ + + + + + + #ifndef HAVE_STRSAVE + /* 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; + int len ; + len = strlen(sp) ; + + if((ret = (char *) malloc((unsigned) len+1)) == NULL) { + report(LOG_DEBUG, "no memory for saving args\n"); + return NULL; + } + (void) strncpy(ret,sp,len); + ret[len] = '\0' ; + return(ret); + } + + #endif + + /* + * Verify the username and password via kerberos. Note that + * this routine cannot do case insensitive matches and any special tweakings. + * Only used if the do_krb_pw has been set. + */ + + int + kerberos4_verify(char *passwd, struct authen_data *data) + + { + int status = 0 ; + char *name ; + data->status = TAC_PLUS_AUTHEN_STATUS_FAIL; + + name = data->NAS_id->username ; + /* Need to check status here */ + if ( k_init(name,4) < 0 ) { + report(LOG_INFO,"Failure to initialize Kerberos" ); + status = 1 ; + data->status = TAC_PLUS_AUTHEN_STATUS_ERROR; + goto HASTA_LA_VISTA ; + } + + + if (try_krb4(name, passwd) > 0) { + /* krb4 authentication succeeded */ + #ifdef DEBUG + report (LOG_DEBUG, "authent_krb: passing user=\"%s\"", name ); + #endif /* DEBUG */ + /* Verify the ticket */ + /* Returns 1 for confirmation, -1 for failure, 0 for uncertainty. + */ + if ( verify_krb_v4_tgt (realm) < 0 ) { + #ifdef DEBUG + report (LOG_DEBUG, "authent_krb: ticket verify failure user=\"%s\"", nam + e ); + #endif /* DEBUG */ + data->status = TAC_PLUS_AUTHEN_STATUS_ERROR; + status = 1 ; + } else { + data->status = TAC_PLUS_AUTHEN_STATUS_PASS; + } + } + + HASTA_LA_VISTA: + destroy_tickets() ; + return (status); + + } + + int + kerberos5_verify(char *passwd, struct authen_data *data) + { + + int status = 0 ; + char *name ; + data->status = TAC_PLUS_AUTHEN_STATUS_FAIL; + + name = data->NAS_id->username ; + /* Need to check status here */ + if ( k_init(name,5) < 0 ) { + report(LOG_INFO,"Failure to initialize Kerberos" ); + status = 1 ; + goto HASTA_LA_VISTA ; + } + + + if (try_krb5(name, passwd) > 0) { + /* krb5 authentication succeeded */ + + #ifdef DEBUG + report (LOG_DEBUG, "authent_krb: passing user=\"%s\"", name ); + #endif /* DEBUG */ + /* Verify the ticket */ + /* Returns 1 for confirmation, -1 for failure, 0 for uncertainty. + */ + if ( verify_krb_v5_tgt (kcontext) < 0 ) { + #ifdef DEBUG + report (LOG_DEBUG, "authent_krb: ticket verify failure user=\"%s\"", nam + e ); + #endif /* DEBUG */ + status = 1 ; + } else { + data->status = TAC_PLUS_AUTHEN_STATUS_PASS; + + } + + } + HASTA_LA_VISTA: + destroy_tickets() ; + return (status); + + + } + Index: authen.c =================================================================== RCS file: /networking/master_src/tac_plus/authen.c,v retrieving revision 1.1.1.2 retrieving revision 1.2 diff -c -r1.1.1.2 -r1.2 *** authen.c 1998/07/02 19:34:01 1.1.1.2 --- authen.c 1998/07/27 21:48:57 1.2 *************** *** 99,108 **** p += start->port_len; if (start->port_len <= 0) { ! strcpy(session.port, "unknown-port"); } else { ! strcpy(session.port, identity.NAS_port); } identity.NAC_address = tac_make_string(p, (int)start->rem_addr_len); p += start->rem_addr_len; --- 99,109 ---- p += start->port_len; if (start->port_len <= 0) { ! strncpy(session.port, "unknown-port",NAS_PORT_MAX_LEN); } else { ! strncpy(session.port, identity.NAS_port,NAS_PORT_MAX_LEN); } + session.port[NAS_PORT_MAX_LEN] ='\0' ; identity.NAC_address = tac_make_string(p, (int)start->rem_addr_len); p += start->rem_addr_len; Index: author.c =================================================================== RCS file: /networking/master_src/tac_plus/author.c,v retrieving revision 1.1.1.2 retrieving revision 1.2 diff -c -r1.1.1.2 -r1.2 *** author.c 1998/07/02 19:34:02 1.1.1.2 --- author.c 1998/07/27 21:48:58 1.2 *************** *** 85,95 **** identity.NAS_port = tac_make_string(p, (int)apak->port_len); p += apak->port_len; if (apak->port_len <= 0) { ! strcpy(session.port, "unknown-port"); } else { ! strcpy(session.port, identity.NAS_port); } ! identity.NAC_address = tac_make_string(p, (int)apak->rem_addr_len); p += apak->rem_addr_len; --- 85,95 ---- identity.NAS_port = tac_make_string(p, (int)apak->port_len); p += apak->port_len; if (apak->port_len <= 0) { ! tac_strcpy(session.port, "unknown-port",NAS_PORT_MAX_LEN); } else { ! tac_strcpy(session.port, identity.NAS_port,NAS_PORT_MAX_LEN); } ! identity.NAC_address = tac_make_string(p, (int)apak->rem_addr_len); p += apak->rem_addr_len; Index: choose_authen.c =================================================================== RCS file: /networking/master_src/tac_plus/choose_authen.c,v retrieving revision 1.1.1.2 retrieving revision 1.7 diff -c -r1.1.1.2 -r1.7 *** choose_authen.c 1998/07/02 19:34:02 1.1.1.2 --- choose_authen.c 1998/07/27 21:48:58 1.7 *************** *** 59,65 **** break; } type->authen_func = enable_fn; ! strcpy(type->authen_name, "enable_fn"); return (CHOOSE_OK); } return(choose_login(data, type)); --- 59,67 ---- break; } type->authen_func = enable_fn; ! strncpy(type->authen_name, "enable_fn",AUTHEN_NAME_SIZE); ! type->authen_name[AUTHEN_NAME_SIZE] = '\0' ; ! return (CHOOSE_OK); } return(choose_login(data, type)); *************** *** 92,97 **** --- 94,100 ---- { char *name = data->NAS_id->username; char *cfg_passwd; + switch(type->authen_type) { case TAC_PLUS_AUTHEN_TYPE_ASCII: *************** *** 106,118 **** /* Does this user require s/key? */ cfg_passwd = cfg_get_login_secret(name, TAC_PLUS_RECURSE); if (cfg_passwd && STREQ(cfg_passwd, "skey")) { if (debug & DEBUG_PASSWD_FLAG) report(LOG_DEBUG, "%s %s: user %s requires skey", session.peer, session.port, name); #ifdef SKEY type->authen_func = skey_fn; ! strcpy(type->authen_name, "skey_fn"); return (CHOOSE_OK); #else /* SKEY */ report(LOG_ERR, --- 109,122 ---- /* Does this user require s/key? */ cfg_passwd = cfg_get_login_secret(name, TAC_PLUS_RECURSE); + if (cfg_passwd && STREQ(cfg_passwd, "skey")) { if (debug & DEBUG_PASSWD_FLAG) report(LOG_DEBUG, "%s %s: user %s requires skey", session.peer, session.port, name); #ifdef SKEY type->authen_func = skey_fn; ! tac_strcpy(type->authen_name, "skey_fn",AUTHEN_NAME_SIZE); return (CHOOSE_OK); #else /* SKEY */ report(LOG_ERR, *************** *** 121,131 **** session.peer, session.port); return(CHOOSE_FAILED); #endif /* SKEY */ ! } /* Not an skey user. Must be none, des, cleartext or file password */ type->authen_func = default_fn; ! strcpy(type->authen_name, "default_fn"); return (CHOOSE_OK); case TAC_PLUS_AUTHEN_TYPE_ARAP: --- 125,158 ---- session.peer, session.port); return(CHOOSE_FAILED); #endif /* SKEY */ ! } ! #ifdef USE_KRB4 ! if (cfg_passwd && STREQ(cfg_passwd, "kerberos4")) { ! if (debug & DEBUG_PASSWD_FLAG) ! report(LOG_DEBUG, "%s %s: user %s requires kerberos4", ! session.peer, session.port, name); ! type->authen_func = kerberos4_fn; ! tac_strcpy(type->authen_name, "kerberos4_fn",AUTHEN_NAME_SIZE); ! return (CHOOSE_OK); ! } ! #endif ! ! #ifdef USE_KRB5 ! if (cfg_passwd && STREQ(cfg_passwd, "kerberos5")) { ! if (debug & DEBUG_PASSWD_FLAG) ! report(LOG_DEBUG, "%s %s: user %s requires kerberos5", ! session.peer, session.port, name); ! type->authen_func = kerberos5_fn; ! tac_strcpy(type->authen_name, "kerberos5_fn",AUTHEN_NAME_SIZE); ! return (CHOOSE_OK); ! } ! ! #endif ! /* Not an skey user. Must be none, des, cleartext or file password */ type->authen_func = default_fn; ! tac_strcpy(type->authen_name, "default_fn",AUTHEN_NAME_SIZE); return (CHOOSE_OK); case TAC_PLUS_AUTHEN_TYPE_ARAP: *************** *** 159,168 **** #endif /* MSCHAP */ case TAC_PLUS_AUTHEN_TYPE_PAP: case TAC_PLUS_AUTHEN_TYPE_CHAP: if (session.version == TAC_PLUS_VER_0) { type->authen_func = default_v0_fn; ! strcpy(type->authen_name, "default_v0_fn"); return (CHOOSE_OK); } --- 186,197 ---- #endif /* MSCHAP */ case TAC_PLUS_AUTHEN_TYPE_PAP: + + case TAC_PLUS_AUTHEN_TYPE_CHAP: if (session.version == TAC_PLUS_VER_0) { type->authen_func = default_v0_fn; ! tac_strcpy(type->authen_name, "default_v0_fn",AUTHEN_NAME_SIZE); return (CHOOSE_OK); } *************** *** 174,181 **** session.peer, session.port); return (CHOOSE_FAILED); } type->authen_func = default_fn; ! strcpy(type->authen_name, "default_fn"); return (CHOOSE_OK); default: --- 203,237 ---- session.peer, session.port); return (CHOOSE_FAILED); } + + cfg_passwd = cfg_get_login_secret(name, TAC_PLUS_RECURSE); + /* We can do PAP with krb, we can't do chap */ + if ( type->authen_type == TAC_PLUS_AUTHEN_TYPE_PAP ) { + #ifdef USE_KRB4 + if (cfg_passwd && STREQ(cfg_passwd, "kerberos4")) { + if (debug & DEBUG_PASSWD_FLAG) + report(LOG_DEBUG, "%s %s: user %s requires kerberos4", + session.peer, session.port, name); + type->authen_func = kerberos4_fn; + tac_strcpy(type->authen_name, "kerberos4_fn",AUTHEN_NAME_SIZE); + return (CHOOSE_OK); + } + #endif + + #ifdef USE_KRB5 + if (cfg_passwd && STREQ(cfg_passwd, "kerberos5")) { + if (debug & DEBUG_PASSWD_FLAG) + report(LOG_DEBUG, "%s %s: user %s requires kerberos5", + session.peer, session.port, name); + type->authen_func = kerberos5_fn; + tac_strcpy(type->authen_name, "kerberos5_fn",AUTHEN_NAME_SIZE); + return (CHOOSE_OK); + } + + #endif + } type->authen_func = default_fn; ! tac_strcpy(type->authen_name, "default_fn",AUTHEN_NAME_SIZE); return (CHOOSE_OK); default: *************** *** 229,235 **** return (CHOOSE_FAILED); } type->authen_func = sendauth_fn; ! strcpy(type->authen_name, "sendauth_fn"); return (CHOOSE_OK); default: --- 285,291 ---- return (CHOOSE_FAILED); } type->authen_func = sendauth_fn; ! tac_strcpy(type->authen_name, "sendauth_fn",AUTHEN_NAME_SIZE); return (CHOOSE_OK); default: *************** *** 273,279 **** } type->authen_func = sendpass_fn; ! strcpy(type->authen_name, "sendpass_fn"); return (CHOOSE_OK); default: --- 329,335 ---- } type->authen_func = sendpass_fn; ! tac_strcpy(type->authen_name, "sendpass_fn",AUTHEN_NAME_SIZE); return (CHOOSE_OK); default: Index: config.c =================================================================== RCS file: /networking/master_src/tac_plus/config.c,v retrieving revision 1.1.1.2 retrieving revision 1.7 diff -c -r1.1.1.2 -r1.7 *** config.c 1998/07/02 19:34:03 1.1.1.2 --- config.c 1998/08/14 00:34:11 1.7 *************** *** 32,38 **** default authorization = permit | key = ! := default authentication = file := permit | deny --- 32,44 ---- default authorization = permit | key = ! := default authentication = file | ! #ifdef USE_KRB4 ! kerberos4 | ! #endif ! #ifdef USE_KRB5 ! kerberos5 ! #endif := permit | deny *************** *** 47,53 **** } := file | ! skey | cleartext | des | nopassword --- 53,65 ---- } := file | ! skey | ! #ifdef USE_KRB4 ! kerberos4 | ! #endif ! #ifdef USE_KRB5 ! kerberos5 | ! #endif cleartext | des | nopassword *************** *** 497,502 **** --- 509,515 ---- static int parse_decls() { + char buf[256] ; no_user_dflt = 0; /* default if user doesn't exist */ sym_code = 0; *************** *** 543,550 **** } parse(S_authentication); parse(S_separator); ! parse(S_file); ! authen_default = tac_strdup(sym_buf); sym_get(); continue; --- 556,601 ---- } parse(S_authentication); parse(S_separator); ! /* I'd like to use kerberosX here. Need to think about this */ ! switch(sym_code) { ! ! case S_skey: ! authen_default = tac_strdup(sym_buf); ! break; ! #ifdef USE_KRB4 ! case S_kerberos4: ! authen_default = tac_strdup(sym_buf); ! break; ! #endif ! #ifdef USE_KRB5 ! case S_kerberos5: ! authen_default = tac_strdup(sym_buf); ! break; ! #endif ! case S_nopasswd: ! /* set to dummy string, so that we detect a duplicate ! * password definition attempt ! */ ! authen_default = tac_strdup(nopasswd_str); ! ! break; ! ! case S_file: ! case S_cleartext: ! case S_des: ! sprintf(buf, "%s ", sym_buf); ! sym_get(); ! tac_strcat(buf, sym_buf,MAX_INPUT_LINE_LEN); ! authen_default = tac_strdup(buf); ! break; ! ! default: ! parse_error( ! "expecting 'file', 'cleartext', 'nopassword', 'skey', or 'des' keyword after 'login =' on line %d", ! sym_line); ! } ! ! sym_get(); continue; *************** *** 693,699 **** case S_skey: user->login = tac_strdup(sym_buf); break; ! case S_nopasswd: /* set to dummy string, so that we detect a duplicate * password definition attempt --- 744,759 ---- case S_skey: user->login = tac_strdup(sym_buf); break; ! #ifdef USE_KRB4 ! case S_kerberos4: ! user->login = tac_strdup(sym_buf); ! break; ! #endif ! #ifdef USE_KRB5 ! case S_kerberos5: ! user->login = tac_strdup(sym_buf); ! break; ! #endif case S_nopasswd: /* set to dummy string, so that we detect a duplicate * password definition attempt *************** *** 707,719 **** case S_des: sprintf(buf, "%s ", sym_buf); sym_get(); ! strcat(buf, sym_buf); user->login = tac_strdup(buf); break; default: parse_error( ! "expecting 'file', 'cleartext', 'nopassword', 'skey', or 'des' keyword after 'login =' on line %d", sym_line); } sym_get(); --- 767,787 ---- case S_des: sprintf(buf, "%s ", sym_buf); sym_get(); ! tac_strcat(buf, sym_buf,MAX_INPUT_LINE_LEN); user->login = tac_strdup(buf); break; default: parse_error( ! #ifdef USE_KRB4 ! #ifdef USE_KRB5 ! "expecting 'file', 'cleartext', 'nopassword', 'skey', 'kerberos4', 'kerberos5' or 'des' keyword after 'login =' on line %d", ! #else ! "expecting 'file', 'cleartext', 'nopassword', 'skey', 'kerberos4', or 'des' keyword after 'login =' on line %d", ! #endif ! #else ! "expecting 'file', 'cleartext', 'nopassword', 'skey' or 'des' keyword after 'login =' on line %d", ! #endif sym_line); } sym_get(); *************** *** 752,758 **** parse(S_separator); sprintf(buf, "%s ", sym_buf); parse(S_cleartext); ! strcat(buf, sym_buf); if (save_sym == S_arap) fieldp = &user->arap; --- 820,826 ---- parse(S_separator); sprintf(buf, "%s ", sym_buf); parse(S_cleartext); ! tac_strcat(buf, sym_buf,MAX_INPUT_LINE_LEN); if (save_sym == S_arap) fieldp = &user->arap; *************** *** 938,948 **** } result->type = optional ? N_optarg : N_arg; ! strcpy(buf, sym_buf); parse(S_string); ! strcat(buf, sym_buf); parse(S_separator); ! strcat(buf, sym_buf); parse(S_string); result->value = tac_strdup(buf); --- 1006,1016 ---- } result->type = optional ? N_optarg : N_arg; ! tac_strcpy(buf, sym_buf,MAX_INPUT_LINE_LEN); parse(S_string); ! tac_strcat(buf, sym_buf,MAX_INPUT_LINE_LEN); parse(S_separator); ! tac_strcat(buf, sym_buf,MAX_INPUT_LINE_LEN); parse(S_string); result->value = tac_strdup(buf); *************** *** 1005,1023 **** goto next; case '=': ! strcpy(sym_buf, "="); sym_code = S_separator; rch(); return; case '{': ! strcpy(sym_buf, "{"); sym_code = S_openbra; rch(); return; case '}': ! strcpy(sym_buf, "}"); sym_code = S_closebra; rch(); return; --- 1073,1091 ---- goto next; case '=': ! tac_strcpy(sym_buf, "=",MAX_INPUT_LINE_LEN); sym_code = S_separator; rch(); return; case '{': ! tac_strcpy(sym_buf, "{",MAX_INPUT_LINE_LEN); sym_code = S_openbra; rch(); return; case '}': ! tac_strcpy(sym_buf, "}",MAX_INPUT_LINE_LEN); sym_code = S_closebra; rch(); return; *************** *** 1435,1441 **** char *user; { ! return (cfg_get_pvalue(user, TAC_IS_USER, S_login, recurse)); } /* return value of the nopasswd field. If none, try groups she is a member --- 1503,1523 ---- char *user; { ! char *value ; ! value = cfg_get_pvalue(user, TAC_IS_USER, S_login, recurse); ! #if defined (USE_KRB4) || defined ( USE_KRB5 ) ! if ( value == NULL ) { ! value = cfg_get_authen_default() ; ! if ( STREQ(value,"kerberos4") || ! STREQ(value,"kerberos5") ) { /* this is want I want you could add ! other stuff like skey here */ ! return (value ) ; ! } else { ! value = NULL ; ! } ! } ! #endif ! return( value) ; } /* return value of the nopasswd field. If none, try groups she is a member Index: default_fn.c =================================================================== RCS file: /networking/master_src/tac_plus/default_fn.c,v retrieving revision 1.1.1.2 retrieving revision 1.2 diff -c -r1.1.1.2 -r1.2 *** default_fn.c 1998/07/02 19:34:11 1.1.1.2 --- default_fn.c 1998/07/27 21:48:59 1.2 *************** *** 427,433 **** arap_verify(data) struct authen_data *data; { ! char nas_chal[8], r_chal[8], r_resp[8], secret[8]; char *name, *cfg_secret, *exp_date, *p; if (!(char) data->NAS_id->username[0]) { --- 427,433 ---- arap_verify(data) struct authen_data *data; { ! char nas_chal[8], r_chal[8], r_resp[8], secret[9]; char *name, *cfg_secret, *exp_date, *p; if (!(char) data->NAS_id->username[0]) { *************** *** 471,477 **** } /* need to allocate 8 bytes for secret, even if it's actually shorter */ bzero(secret, sizeof(secret)); ! strcpy(secret, p); pw_bitshift(secret); --- 471,477 ---- } /* need to allocate 8 bytes for secret, even if it's actually shorter */ bzero(secret, sizeof(secret)); ! tac_strcpy(secret, p,sizeof(secret)); pw_bitshift(secret); Index: do_author.c =================================================================== RCS file: /networking/master_src/tac_plus/do_author.c,v retrieving revision 1.1.1.2 retrieving revision 1.2 diff -c -r1.1.1.2 -r1.2 *** do_author.c 1998/07/02 19:34:03 1.1.1.2 --- do_author.c 1998/07/27 21:49:00 1.2 *************** *** 383,391 **** free(buf); return (NULL); } ! strcat(buf, v); if (i < (data->num_in_args - 1)) ! strcat(buf, " "); } return (buf); } --- 383,391 ---- free(buf); return (NULL); } ! tac_strcat(buf, v,len); if (i < (data->num_in_args - 1)) ! tac_strcat(buf, " ",len); } return (buf); } Index: dump.c =================================================================== RCS file: /networking/master_src/tac_plus/dump.c,v retrieving revision 1.1.1.2 retrieving revision 1.3 diff -c -r1.1.1.2 -r1.3 *** dump.c 1998/07/02 19:34:04 1.1.1.2 --- dump.c 1998/07/23 21:21:48 1.3 *************** *** 19,24 **** --- 19,27 ---- #include "tac_plus.h" + /* from packet.c */ + extern u_char *walk_packet() ; + /* Routines for dumping packets to stderr */ char * summarise_outgoing_packet_type(pak) *************** *** 127,133 **** struct acct *acct; int i; HDR *hdr; ! u_char *p, *argsizep; int seq; dump_header(pak); --- 130,136 ---- struct acct *acct; int i; HDR *hdr; ! u_char *p,*pnext,*data_start, *argsizep; int seq; dump_header(pak); *************** *** 228,246 **** /* start of variable length data is here */ p = pak + TAC_PLUS_HDR_SIZE + TAC_AUTHEN_START_FIXED_FIELDS_SIZE; report(LOG_DEBUG, "User: "); report_string(LOG_DEBUG, p, start->user_len); ! p += start->user_len; report(LOG_DEBUG, "port: "); report_string(LOG_DEBUG, p, start->port_len); ! p += start->port_len; report(LOG_DEBUG, "rem_addr: "); report_string(LOG_DEBUG, p, start->rem_addr_len); ! p += start->rem_addr_len; report(LOG_DEBUG, "data: "); report_string(LOG_DEBUG, p, start->data_len); report(LOG_DEBUG, "End packet"); --- 231,275 ---- /* start of variable length data is here */ p = pak + TAC_PLUS_HDR_SIZE + TAC_AUTHEN_START_FIXED_FIELDS_SIZE; + data_start = p ; + report(LOG_DEBUG, "User: "); + + + pnext = walk_packet(hdr,data_start,p,start->user_len); + if ( pnext == NULL ) { + report(LOG_DEBUG, "garbage in user_len"); + return ; + } report_string(LOG_DEBUG, p, start->user_len); ! p = pnext ; report(LOG_DEBUG, "port: "); + + pnext = walk_packet(hdr,data_start,p,start->port_len); + if ( pnext == NULL ) { + report(LOG_DEBUG, "garbage in port_len"); + return ; + } report_string(LOG_DEBUG, p, start->port_len); ! p = pnext ; report(LOG_DEBUG, "rem_addr: "); + + pnext = walk_packet(hdr,data_start,p,start->rem_addr_len); + if ( pnext == NULL ) { + report(LOG_DEBUG, "garbage in rem_addr_len"); + return ; + } report_string(LOG_DEBUG, p, start->rem_addr_len); ! p = pnext ; report(LOG_DEBUG, "data: "); + pnext = walk_packet(hdr,data_start,p,start->data_len); + if ( pnext == NULL ) { + report(LOG_DEBUG, "garbage in data_len"); + return ; + } report_string(LOG_DEBUG, p, start->data_len); report(LOG_DEBUG, "End packet"); *************** *** 258,268 **** p = pak + TAC_PLUS_HDR_SIZE + TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE; report(LOG_DEBUG, "User msg: "); report_string(LOG_DEBUG, p, cont->user_msg_len); ! p += cont->user_msg_len; ! report(LOG_DEBUG, "User data: "); report_string(LOG_DEBUG, p, cont->user_data_len); report(LOG_DEBUG, "End packet"); --- 287,310 ---- p = pak + TAC_PLUS_HDR_SIZE + TAC_AUTHEN_CONT_FIXED_FIELDS_SIZE; + data_start = p ; + report(LOG_DEBUG, "User msg: "); + + pnext = walk_packet(hdr,data_start,p,cont->user_msg_len); + if ( pnext == NULL ) { + report(LOG_DEBUG, "garbage in user_msg_len"); + return ; + } report_string(LOG_DEBUG, p, cont->user_msg_len); ! p = pnext ; ! report(LOG_DEBUG, "User data: "); + pnext = walk_packet(hdr,data_start,p,cont->user_data_len); + if ( pnext == NULL ) { + report(LOG_DEBUG, "garbage in user_data_len"); + return ; + } report_string(LOG_DEBUG, p, cont->user_data_len); report(LOG_DEBUG, "End packet"); Index: packet.c =================================================================== RCS file: /networking/master_src/tac_plus/packet.c,v retrieving revision 1.1.1.2 retrieving revision 1.2 diff -c -r1.1.1.2 -r1.2 *** packet.c 1998/07/02 19:34:06 1.1.1.2 --- packet.c 1998/07/23 20:32:32 1.2 *************** *** 513,518 **** --- 513,538 ---- return (0); } + /* Walk through the variable data parts of a packet */ + u_char * + walk_packet(hdr,vstart,vcurrent,len) + HDR *hdr; + u_char *vstart; + u_char *vcurrent; + int len; + { + u_char *p = NULL ; + /* Be paranoid about garbage in len */ + if ( len > -1 ) { + if (((int) vcurrent - (int)vstart + len) < hdr->datalength) { + p = vcurrent ; + p += len ; + } + } + + return p ; + } + send_error_reply(type, msg) int type; char *msg; Index: krb_fn.c =================================================================== RCS file: krb_fn.c diff -N krb_fn.c *** /tmp/da003xZ Thu Aug 13 16:16:57 1998 --- /var/tmp/baaa003wx Thu Aug 13 16:40:23 1998 *************** *** 0 **** --- 1,381 ---- + /* + Copyright (c) 1995-1998 by Cisco systems, Inc. + + Permission to use, copy, modify, and distribute this software for + any purpose and without fee is hereby granted, provided that this + copyright and permission notice appear on all copies of the + software and supporting documentation, the name of Cisco Systems, + Inc. not be used in advertising or publicity pertaining to + distribution of the program without specific prior permission, and + notice be given in supporting documentation that modification, + copying and distribution is by permission of Cisco Systems, Inc. + + Cisco Systems, Inc. makes no representations about the suitability + of this software for any purpose. THIS SOFTWARE IS PROVIDED ``AS + IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, + WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE. + */ + + + #include "tac_plus.h" + #include "expire.h" + + + + + /* internal state variables */ + #define STATE_AUTHEN_START 0 /* no requests issued */ + #define STATE_AUTHEN_GETUSER 1 /* username has been requested */ + #define STATE_AUTHEN_GETPASS 2 /* password has been requested */ + + + + struct private_data { + char password[MAX_PASSWD_LEN + 1]; + int state; + }; + + #ifdef USE_KRB4 + + /* + * Kerberos tacacs login authentication function. Wants a username + * and a password, and tries to verify them via kerberos. + * + * Choose_authen will ensure that we already have a username before this + * gets called. + * + * We will query for a password and keep it in the method_data. + * + * Any strings returned via pointers in authen_data must come from the + * heap. They will get freed by the caller. + * + * These could be collapsed into one function, but it makes the ifdef + * stuff harder. + * + * Return 0 if data->status is valid, otherwise 1 + */ + + int + kerberos4_fn(data) + struct authen_data *data; + { + char *name, *passwd; + struct private_data *p; + + int pwlen; + char *prompt; + + + p = (struct private_data *) data->method_data; + + /* An abort has been received. Clean up and return */ + if (data->flags & TAC_PLUS_CONTINUE_FLAG_ABORT) { + if (data->method_data) + free(data->method_data); + data->method_data = NULL; + return (1); + } + /* Initialise method_data if first time through */ + if (!p) { + p = (struct private_data *) tac_malloc(sizeof(struct private_data)); + bzero(p, sizeof(struct private_data)); + data->method_data = p; + p->state = STATE_AUTHEN_START; + } + + /* Unless we're enabling, we need a username */ + if (data->service != TAC_PLUS_AUTHEN_SVC_ENABLE && + !(char) data->NAS_id->username[0]) { + switch (p->state) { + + case STATE_AUTHEN_GETUSER: + /* we have previously asked for a username but none came back. + * This is a gross error */ + data->status = TAC_PLUS_AUTHEN_STATUS_ERROR; + report(LOG_ERR, "%s: No username supplied after GETUSER", + session.peer); + return (0); + + case STATE_AUTHEN_START: + /* No username. Try requesting one */ + data->status = TAC_PLUS_AUTHEN_STATUS_GETUSER; + if (data->service == TAC_PLUS_AUTHEN_SVC_LOGIN) { + prompt = "\nUser Access Verification\n\nUsername: "; + } else { + prompt = "Username: "; + } + data->server_msg = tac_strdup(prompt); + p->state = STATE_AUTHEN_GETUSER; + return (0); + + default: + /* something awful has happened. Give up and die */ + report(LOG_ERR, "%s: kerberos4_fn bad state %d", + session.peer, p->state); + return (1); + } + } + + /* we now have a username if we needed one */ + name = data->NAS_id->username; + + /* Do we have a password? */ + passwd = p->password; + + /* get the password if we are doing PAP */ + + if ( data->type == TAC_PLUS_AUTHEN_TYPE_PAP ) { + passwd = tac_malloc(data->client_dlen + 1); + bcopy(data->client_data, passwd, data->client_dlen); + passwd[data->client_dlen] = '\0'; + } + + if (!passwd[0]) { + + + /* no password yet. Either we need to ask for one and expect to get + * called again, or we asked but nothing came back, which is fatal */ + + switch (p->state) { + case STATE_AUTHEN_GETPASS: + /* We already asked for a password. This should be the reply */ + if (data->client_msg) { + pwlen = MIN(strlen(data->client_msg), MAX_PASSWD_LEN); + } else { + pwlen = 0; + } + strncpy(passwd, data->client_msg, pwlen); + passwd[pwlen] = '\0'; + break; + + default: + /* Request a password */ + passwd = cfg_get_login_secret(name, TAC_PLUS_RECURSE); + if (!passwd && !STREQ(passwd, "kerberos4")) { + report(LOG_ERR, "Cannot find kerberos4 password declaration for %s", + name); + data->status = TAC_PLUS_AUTHEN_STATUS_ERROR; + return(1); + } + prompt ="Password: " ; + data->server_msg = tac_strdup(prompt); + data->status = TAC_PLUS_AUTHEN_STATUS_GETPASS; + p->state = STATE_AUTHEN_GETPASS; + return (0); + + } + } + + /* We have a username and password. Try validating */ + + /* Assume the worst */ + data->status = TAC_PLUS_AUTHEN_STATUS_FAIL; + + switch (data->service) { + case TAC_PLUS_AUTHEN_SVC_PPP: + case TAC_PLUS_AUTHEN_SVC_LOGIN: + kerberos4_verify(passwd, data); + if (debug) + report(LOG_INFO, "login query for '%s' %s from %s %s", + name && name[0] ? name : "unknown", + data->NAS_id->NAS_port && data->NAS_id->NAS_port[0] ? + data->NAS_id->NAS_port : "unknown", + session.peer, + (data->status == TAC_PLUS_AUTHEN_STATUS_PASS) ? + "accepted" : "rejected"); + break; + + default: + data->status = TAC_PLUS_AUTHEN_STATUS_ERROR; + report(LOG_ERR, "%s: Bogus service value %d from packet", + session.peer, data->service); + break; + } + + if (data->method_data) + free(data->method_data); + data->method_data = NULL; + + switch (data->status) { + case TAC_PLUS_AUTHEN_STATUS_ERROR: + case TAC_PLUS_AUTHEN_STATUS_FAIL: + case TAC_PLUS_AUTHEN_STATUS_PASS: + return (0); + default: + report(LOG_ERR, "%s: kerberos4_fn couldn't set recognizable status %d", + session.peer, data->status); + data->status = TAC_PLUS_AUTHEN_STATUS_ERROR; + return (1); + } + } + + #endif /* USE_KRB4 */ + + #ifdef USE_KRB5 + + int + kerberos5_fn(data) + struct authen_data *data; + { + char *name, *passwd; + struct private_data *p; + char *prompt; + int pwlen; + + + p = (struct private_data *) data->method_data; + + /* An abort has been received. Clean up and return */ + if (data->flags & TAC_PLUS_CONTINUE_FLAG_ABORT) { + if (data->method_data) + free(data->method_data); + data->method_data = NULL; + return (1); + } + /* Initialise method_data if first time through */ + if (!p) { + p = (struct private_data *) tac_malloc(sizeof(struct private_data)); + bzero(p, sizeof(struct private_data)); + data->method_data = p; + p->state = STATE_AUTHEN_START; + } + + /* Unless we're enabling, we need a username */ + if (data->service != TAC_PLUS_AUTHEN_SVC_ENABLE && + !(char) data->NAS_id->username[0]) { + switch (p->state) { + + case STATE_AUTHEN_GETUSER: + /* we have previously asked for a username but none came back. + * This is a gross error */ + data->status = TAC_PLUS_AUTHEN_STATUS_ERROR; + report(LOG_ERR, "%s: No username supplied after GETUSER", + session.peer); + return (0); + + case STATE_AUTHEN_START: + /* No username. Try requesting one */ + data->status = TAC_PLUS_AUTHEN_STATUS_GETUSER; + if (data->service == TAC_PLUS_AUTHEN_SVC_LOGIN) { + prompt = "\nUser Access Verification\n\nUsername: "; + } else { + prompt = "Username: "; + } + data->server_msg = tac_strdup(prompt); + p->state = STATE_AUTHEN_GETUSER; + return (0); + + default: + /* something awful has happened. Give up and die */ + report(LOG_ERR, "%s: kerberos5_fn bad state %d", + session.peer, p->state); + return (1); + } + } + + /* we now have a username if we needed one */ + name = data->NAS_id->username; + + /* Do we have a password? */ + passwd = p->password; + + /* get the password if we are doing PAP */ + + if ( data->type == TAC_PLUS_AUTHEN_TYPE_PAP ) { + passwd = tac_malloc(data->client_dlen + 1); + bcopy(data->client_data, passwd, data->client_dlen); + passwd[data->client_dlen] = '\0'; + } + + if (!passwd[0]) { + + + /* no password yet. Either we need to ask for one and expect to get + * called again, or we asked but nothing came back, which is fatal */ + + switch (p->state) { + case STATE_AUTHEN_GETPASS: + /* We already asked for a password. This should be the reply */ + if (data->client_msg) { + pwlen = MIN(strlen(data->client_msg), MAX_PASSWD_LEN); + } else { + pwlen = 0; + } + strncpy(passwd, data->client_msg, pwlen); + passwd[pwlen] = '\0'; + break; + + default: + /* Request a password */ + passwd = cfg_get_login_secret(name, TAC_PLUS_RECURSE); + if (!passwd && !STREQ(passwd, "kerberos5")) { + report(LOG_ERR, "Cannot find kerberos5 password declaration for %s", + name); + data->status = TAC_PLUS_AUTHEN_STATUS_ERROR; + return(1); + } + + prompt = "Password: " ; + data->server_msg = tac_strdup(prompt); + data->status = TAC_PLUS_AUTHEN_STATUS_GETPASS; + p->state = STATE_AUTHEN_GETPASS; + return (0); + + } + } + + /* We have a username and password. Try validating */ + + /* Assume the worst */ + data->status = TAC_PLUS_AUTHEN_STATUS_FAIL; + + switch (data->service) { + case TAC_PLUS_AUTHEN_SVC_PPP: + case TAC_PLUS_AUTHEN_SVC_LOGIN: + kerberos5_verify(passwd, data); + if (debug) + report(LOG_INFO, "login query for '%s' %s from %s %s", + name && name[0] ? name : "unknown", + data->NAS_id->NAS_port && data->NAS_id->NAS_port[0] ? + data->NAS_id->NAS_port : "unknown", + session.peer, + (data->status == TAC_PLUS_AUTHEN_STATUS_PASS) ? + "accepted" : "rejected"); + break; + + default: + data->status = TAC_PLUS_AUTHEN_STATUS_ERROR; + report(LOG_ERR, "%s: Bogus service value %d from packet", + session.peer, data->service); + break; + } + + if (data->method_data) + free(data->method_data); + data->method_data = NULL; + + switch (data->status) { + case TAC_PLUS_AUTHEN_STATUS_ERROR: + case TAC_PLUS_AUTHEN_STATUS_FAIL: + case TAC_PLUS_AUTHEN_STATUS_PASS: + return (0); + default: + report(LOG_ERR, "%s: kerberos5_fn couldn't set recognizable status %d", + session.peer, data->status); + data->status = TAC_PLUS_AUTHEN_STATUS_ERROR; + return (1); + } + } + + #endif /* USE_KRB5 */ + + #ifndef USE_KRB4 + #ifndef USE_KRB5 + /* The following code is not needed or used. It exists solely to + prevent compilers from "helpfully" complaining that this source + file is empty, which upsets novices building the software */ + + static int dummy = 0; + #endif + #endif Index: packet.c =================================================================== RCS file: /networking/master_src/tac_plus/packet.c,v retrieving revision 1.1.1.2 retrieving revision 1.2 diff -c -r1.1.1.2 -r1.2 *** packet.c 1998/07/02 19:34:06 1.1.1.2 --- packet.c 1998/07/23 20:32:32 1.2 *************** *** 513,518 **** --- 513,538 ---- return (0); } + /* Walk through the variable data parts of a packet */ + u_char * + walk_packet(hdr,vstart,vcurrent,len) + HDR *hdr; + u_char *vstart; + u_char *vcurrent; + int len; + { + u_char *p = NULL ; + /* Be paranoid about garbage in len */ + if ( len > -1 ) { + if (((int) vcurrent - (int)vstart + len) < hdr->datalength) { + p = vcurrent ; + p += len ; + } + } + + return p ; + } + send_error_reply(type, msg) int type; char *msg; Index: parse.c =================================================================== RCS file: /networking/master_src/tac_plus/parse.c,v retrieving revision 1.1.1.2 retrieving revision 1.3 diff -c -r1.1.1.2 -r1.3 *** parse.c 1998/07/02 19:34:09 1.1.1.2 --- parse.c 1998/07/14 20:58:30 1.3 *************** *** 100,105 **** --- 100,111 ---- declare("ppp", S_ppp); declare("protocol", S_protocol); declare("skey", S_skey); + #ifdef USE_KRB4 + declare("kerberos4", S_kerberos4); + #endif + #ifdef USE_KRB5 + declare("kerberos5", S_kerberos5); + #endif declare("slip", S_slip); declare("service", S_svc); declare("user", S_user); *************** *** 148,153 **** --- 154,167 ---- return ("file"); case S_skey: return ("skey"); + #ifdef USE_KRB4 + case S_kerberos4: + return ("kerberos4"); + #endif + #ifdef USE_KRB5 + case S_kerberos5: + return ("kerberos5"); + #endif case S_name: return ("name"); case S_login: Index: parse.h =================================================================== RCS file: /networking/master_src/tac_plus/parse.h,v retrieving revision 1.1.1.2 retrieving revision 1.3 diff -c -r1.1.1.2 -r1.3 *** parse.h 1998/07/02 19:34:14 1.1.1.2 --- parse.h 1998/07/14 20:58:30 1.3 *************** *** 75,77 **** --- 75,83 ---- #ifdef MSCHAP #define S_mschap 42 #endif /* MSCHAP */ + #ifdef USE_KRB4 + #define S_kerberos4 43 + #endif + #ifdef USE_KRB5 + #define S_kerberos5 44 + #endif Index: programs.c =================================================================== RCS file: /networking/master_src/tac_plus/programs.c,v retrieving revision 1.1.1.2 retrieving revision 1.2 diff -c -r1.1.1.2 -r1.2 *** programs.c 1998/07/02 19:34:09 1.1.1.2 --- programs.c 1998/07/27 21:49:01 1.2 *************** *** 292,298 **** *bufp = '\0'; out = read_args(n + 1, fd); out[n] = (char *) tac_malloc(strlen(buf) + 1); ! strcpy(out[n], buf); return (out); } /* eof */ --- 292,298 ---- *bufp = '\0'; out = read_args(n + 1, fd); out[n] = (char *) tac_malloc(strlen(buf) + 1); ! tac_strcpy(out[n], buf,sizeof(out[n])); return (out); } /* eof */ Index: regexp.c =================================================================== RCS file: /networking/master_src/tac_plus/regexp.c,v retrieving revision 1.1.1.2 retrieving revision 1.2 diff -c -r1.1.1.2 -r1.2 *** regexp.c 1998/07/02 19:34:09 1.1.1.2 --- regexp.c 1998/07/27 21:49:01 1.2 *************** *** 1128,1134 **** register char *p; static char buf[50]; ! (void) strcpy(buf, ":"); switch (OP(op)) { case BOL: --- 1128,1134 ---- register char *p; static char buf[50]; ! (void) tac_strcpy(buf, ":",sizeof(buf)); switch (OP(op)) { case BOL: *************** *** 1196,1202 **** break; } if (p != NULL) ! (void) strcat(buf, p); return(buf); } #endif --- 1196,1202 ---- break; } if (p != NULL) ! (void) tac_strcat(buf, p,sizeof(buf)); return(buf); } #endif Index: report.c =================================================================== RCS file: /networking/master_src/tac_plus/report.c,v retrieving revision 1.1.1.2 retrieving revision 1.3 diff -c -r1.1.1.2 -r1.3 *** report.c 1998/07/02 19:34:06 1.1.1.2 --- report.c 1998/07/27 21:49:02 1.3 *************** *** 209,215 **** for (i = 0; i < len && i < 255; i++, p++) { sprintf(digit, "0x%x ", *p); ! strcat(buf, digit); buflen += strlen(digit); if (buflen > 75) { --- 209,215 ---- for (i = 0; i < len && i < 255; i++, p++) { sprintf(digit, "0x%x ", *p); ! tac_strcat(buf, digit,sizeof(buf)); buflen += strlen(digit); if (buflen > 75) { *************** *** 233,249 **** { char buf[256]; char *bufp = buf; ! int i; if (len <= 0) return; ! for (i = 0; i < len && i < 255; i++) { if (32 <= *p && *p <= 126) { *bufp++ = *p++; } else { sprintf(bufp, " 0x%x ", *p); ! bufp += strlen(bufp); p++; } } --- 233,252 ---- { char buf[256]; char *bufp = buf; ! int i,j,k; if (len <= 0) return; ! for (i = 0, j = 0 ; (i < len && i < 255) && j < 255; i++) { if (32 <= *p && *p <= 126) { *bufp++ = *p++; + j++ ; } else { sprintf(bufp, " 0x%x ", *p); ! k += strlen(bufp); ! bufp += k ; ! j += k ; p++; } } Index: tac_plus.c =================================================================== RCS file: /networking/master_src/tac_plus/tac_plus.c,v retrieving revision 1.1.1.2 retrieving revision 1.5 diff -c -r1.1.1.2 -r1.5 *** tac_plus.c 1998/07/02 19:34:07 1.1.1.2 --- tac_plus.c 1998/08/12 20:13:17 1.5 *************** *** 25,32 **** --- 25,34 ---- #include "tac_plus.h" #include "sys/wait.h" #include "signal.h" + #include static int standalone = 1; /* running standalone (1) or under inetd (0) */ + static int frominit = 0; /* running out of init */ static int initialised = 0; /* data structures have been allocated */ int sendauth_only = 0; /* don't respond to sendpass requests */ int debug = 0; /* debugging flags */ *************** *** 37,43 **** struct session session; /* session data */ ! static char pidfilebuf[75]; /* holds current name of the pidfile */ void start_session(); --- 39,45 ---- struct session session; /* session data */ ! static char pidfilebuf[PATH_MAX]; /* holds current name of the pidfile */ void start_session(); *************** *** 84,90 **** report(LOG_INFO, "Reading config"); ! session.acctfile = tac_strdup("/var/tmp/acctfile"); if (!session.cfgfile) { report(LOG_ERR, "no config file specified"); --- 86,92 ---- report(LOG_INFO, "Reading config"); ! session.acctfile = tac_strdup(ACCTFILE_DEFAULT); if (!session.cfgfile) { report(LOG_ERR, "no config file specified"); *************** *** 212,218 **** if (argc <= 1) { fprintf(stderr, "Usage: tac_plus -C \n"); fprintf(stderr, "\t[ -t ] [ -P ] [ -g ] [ -p ]\n"); ! fprintf(stderr, "\t[ -d ] [ -i ] [ -v ] [ -s ]\n"); fprintf(stderr, "\t[ -l logfile ]"); #ifdef MAXSESS fprintf(stderr, " [ -w whologfile ]"); --- 214,220 ---- if (argc <= 1) { fprintf(stderr, "Usage: tac_plus -C \n"); fprintf(stderr, "\t[ -t ] [ -P ] [ -g ] [ -p ]\n"); ! fprintf(stderr, "\t[ -d ] [-I] [ -i ] [ -v ] [ -s ]\n"); fprintf(stderr, "\t[ -l logfile ]"); #ifdef MAXSESS fprintf(stderr, " [ -w whologfile ]"); *************** *** 221,227 **** tac_exit(1); } ! while ((c = getopt(argc, argv, "td:C:ip:PgvsLl:w:")) != EOF) switch (c) { case 'L': /* lookup peer names via DNS */ lookup_peer++; --- 223,229 ---- tac_exit(1); } ! while ((c = getopt(argc, argv, "td:C:iIp:PgvsLl:w:")) != EOF) switch (c) { case 'L': /* lookup peer names via DNS */ lookup_peer++; *************** *** 253,258 **** --- 255,263 ---- case 'i': /* stand-alone */ standalone = 0; break; + case 'I': /* from init */ + frominit = 1 ; + break ; case 'l': /* logfile */ logfile = tac_strdup(optarg); break; *************** *** 332,388 **** signal(SIGHUP, SIG_IGN); ! if ((childpid = fork()) < 0) report(LOG_ERR, "Can't fork first child"); ! else if (childpid > 0) exit(0); /* parent */ ! if (debug) report(LOG_DEBUG, "Backgrounded"); ! #ifndef REAPCHILD #ifdef LINUX ! if (setpgrp() == -1) #else /* LINUX */ ! if (setpgrp(0, getpid()) == -1) #endif /* LINUX */ ! report(LOG_ERR, "Can't change process group"); ! c = open("/dev/tty", O_RDWR); ! if (c >= 0) { ioctl(c, TIOCNOTTY, (char *) 0); (void) close(c); ! } ! signal(SIGCHLD, reapchild); #else /* REAPCHILD */ ! if (setpgrp() == 1) report(LOG_ERR, "Can't change process group"); ! signal(SIGHUP, SIG_IGN); ! if ((childpid = fork()) < 0) report(LOG_ERR, "Can't fork second child"); ! else if (childpid > 0) exit(0); ! if (debug & DEBUG_FORK_FLAG) report(LOG_DEBUG, "Forked grandchild"); ! signal(SIGCHLD, SIG_IGN); #endif /* REAPCHILD */ ! closelog(); /* some systems require this */ ! for (c = 0; c < getdtablesize(); c++) (void) close(c); ! /* make sure we can still log to syslog now we've closed everything */ ! open_logfile(); } /* ! single threaded */ ostream = NULL; --- 337,395 ---- signal(SIGHUP, SIG_IGN); ! if ( !frominit ) { ! if ((childpid = fork()) < 0) report(LOG_ERR, "Can't fork first child"); ! else if (childpid > 0) exit(0); /* parent */ ! if (debug) report(LOG_DEBUG, "Backgrounded"); ! #ifndef REAPCHILD #ifdef LINUX ! if (setpgrp() == -1) #else /* LINUX */ ! if (setpgrp(0, getpid()) == -1) #endif /* LINUX */ ! report(LOG_ERR, "Can't change process group"); ! c = open("/dev/tty", O_RDWR); ! if (c >= 0) { ioctl(c, TIOCNOTTY, (char *) 0); (void) close(c); ! } ! signal(SIGCHLD, reapchild); #else /* REAPCHILD */ ! if (setpgrp() == 1) report(LOG_ERR, "Can't change process group"); ! signal(SIGHUP, SIG_IGN); ! if ((childpid = fork()) < 0) report(LOG_ERR, "Can't fork second child"); ! else if (childpid > 0) exit(0); ! if (debug & DEBUG_FORK_FLAG) report(LOG_DEBUG, "Forked grandchild"); ! signal(SIGCHLD, SIG_IGN); #endif /* REAPCHILD */ ! closelog(); /* some systems require this */ ! for (c = 0; c < getdtablesize(); c++) (void) close(c); ! /* make sure we can still log to syslog now we've closed everything */ ! open_logfile(); + } /* ! frominit */ } /* ! single threaded */ ostream = NULL; *************** *** 403,409 **** } if (port == TAC_PLUS_PORT) { ! strcpy(pidfilebuf, TAC_PLUS_PIDFILE); } else { sprintf(pidfilebuf, "%s.%d", TAC_PLUS_PIDFILE, port); } --- 410,416 ---- } if (port == TAC_PLUS_PORT) { ! tac_strcpy(pidfilebuf, TAC_PLUS_PIDFILE,PATH_MAX); } else { sprintf(pidfilebuf, "%s.%d", TAC_PLUS_PIDFILE, port); } Index: tac_plus.h =================================================================== RCS file: /networking/master_src/tac_plus/tac_plus.h,v retrieving revision 1.1.1.2 retrieving revision 1.4 diff -c -r1.1.1.2 -r1.4 *** tac_plus.h 1998/07/02 19:34:15 1.1.1.2 --- tac_plus.h 1998/08/12 20:13:18 1.4 *************** *** 697,702 **** --- 697,708 ---- extern int default_fn(); extern int default_v0_fn(); extern int skey_fn(); + #ifdef USE_KRB4 + extern int kerberos4_fn(); + #endif + #ifdef USE_KRB5 + extern int kerberos5_fn(); + #endif #ifdef MSCHAP extern void mschap_lmchallengeresponse(); extern void mschap_ntchallengeresponse(); *************** *** 724,728 **** #endif /* MAXSESS */ ! #define LOGFILE_DEFAULT "/var/tmp/tac_plus.log" extern char *logfile; --- 730,735 ---- #endif /* MAXSESS */ ! #define LOGFILE_DEFAULT "/var/log/tac_plus.log" ! #define ACCTFILE_DEFAULT "/var/log/acctfile" extern char *logfile; Index: users_guide =================================================================== RCS file: /networking/master_src/tac_plus/users_guide,v retrieving revision 1.1.1.2 retrieving revision 1.2 diff -c -r1.1.1.2 -r1.2 *** users_guide 1998/07/02 19:34:17 1.1.1.2 --- users_guide 1998/07/08 19:30:50 1.2 *************** *** 434,439 **** --- 434,451 ---- login = skey } + 4). Authentication using kerberos + + Specify a user to be authenticated using kerberos 4/5 + + user = fred { + login = kerberos4 + } + + user = fred { + login = kerberos5 + } + RECURSIVE PASSWORD LOOKUPS --------------------------- Index: utils.c =================================================================== RCS file: /networking/master_src/tac_plus/utils.c,v retrieving revision 1.1.1.2 retrieving revision 1.3 diff -c -r1.1.1.2 -r1.3 *** utils.c 1998/07/02 19:34:07 1.1.1.2 --- utils.c 1998/08/12 20:13:18 1.3 *************** *** 82,94 **** tac_strdup(p) char *p; { ! char *n = strdup(p); ! ! if (n == NULL) { ! report(LOG_ERR, "strdup allocation failure"); ! tac_exit(1); ! } ! return (n); } char * --- 82,99 ---- tac_strdup(p) char *p; { ! char *n ; ! if ( p == NULL ) { ! report(LOG_ERR,"Attempted to dup NULL string"); ! tac_exit(1) ; ! } ! n = strdup(p); ! ! if (n == NULL) { ! report(LOG_ERR, "strdup allocation failure"); ! tac_exit(1); ! } ! return (n); } char * *************** *** 264,266 **** --- 269,302 ---- } return(1); } + + /* Having strcpy in a server gives me the hebbie-jebbies */ + char * + tac_strcpy(dst,src,size) + char *dst; + char *src; + int size ; { + char *result ; + + result = strncpy(dst,src,size) ; + dst[--size] = '\0' ; + + return result ; + + } + + char * + tac_strcat(dst,src,size) char *dst; + char *src; + int size ; { + char *result ; + int len ; + len = size - strlen(dst) ; + + result = strncat(dst,src,len) ; + dst[--size] = '\0' ; + + return result ; + + } +