diff --git a/eBones/include/krb.h b/eBones/include/krb.h index 0b1ae090a2ab..d7b77f7ab856 100644 --- a/eBones/include/krb.h +++ b/eBones/include/krb.h @@ -1,504 +1,515 @@ /* * Copyright 1987, 1988 by the Massachusetts Institute of Technology. * For copying and distribution information, please see the file * . * * Include file for the Kerberos library. * * from: krb.h,v 4.26 89/08/08 17:55:25 jtkohl Exp $ - * $Id: krb.h,v 1.7 1995/09/07 20:50:36 mark Exp $ + * $Id: krb.h,v 1.6 1995/09/13 17:23:47 markm Exp $ */ /* Only one time, please */ #ifndef KRB_DEFS #define KRB_DEFS /* Need some defs from des.h */ #include #include #include /* Text describing error codes */ #define MAX_KRB_ERRORS 256 extern char *krb_err_txt[MAX_KRB_ERRORS]; /* These are not defined for at least SunOS 3.3 and Ultrix 2.2 */ #if defined(ULTRIX022) || (defined(SunOS) && SunOS < 40) #define FD_ZERO(p) ((p)->fds_bits[0] = 0) #define FD_SET(n, p) ((p)->fds_bits[0] |= (1 << (n))) #define FD_ISSET(n, p) ((p)->fds_bits[0] & (1 << (n))) #endif /* ULTRIX022 || SunOS */ /* General definitions */ #define KSUCCESS 0 #define KFAILURE 255 #ifdef NO_UIDGID_T typedef unsigned short uid_t; typedef unsigned short gid_t; #endif /* NO_UIDGID_T */ /* * Kerberos specific definitions * * KRBLOG is the log file for the kerberos master server. KRB_CONF is * the configuration file where different host machines running master * and slave servers can be found. KRB_MASTER is the name of the * machine with the master database. The admin_server runs on this * machine, and all changes to the db (as opposed to read-only * requests, which can go to slaves) must go to it. KRB_HOST is the * default machine * when looking for a kerberos slave server. Other * possibilities are * in the KRB_CONF file. KRB_REALM is the name of * the realm. */ #ifdef notdef this is server - only, does not belong here; #define KRBLOG "/etc/kerberosIV/kerberos.log" are these used anyplace '?'; #define VX_KRB_HSTFILE "/etc/krbhst" #define PC_KRB_HSTFILE "\\kerberos\\krbhst" #endif #define KRB_CONF "/etc/kerberosIV/krb.conf" #define KRB_RLM_TRANS "/etc/kerberosIV/krb.realms" #define KRB_MASTER "kerberos" #define KRB_HOST KRB_MASTER #define KRB_REALM "ATHENA.MIT.EDU" /* The maximum sizes for aname, realm, sname, and instance +1 */ #define ANAME_SZ 40 #define REALM_SZ 40 #define SNAME_SZ 40 #define INST_SZ 40 /* include space for '.' and '@' */ #define MAX_K_NAME_SZ (ANAME_SZ + INST_SZ + REALM_SZ + 2) #define KKEY_SZ 100 #define VERSION_SZ 1 #define MSG_TYPE_SZ 1 #define DATE_SZ 26 /* RTI date output */ #define MAX_HSTNM 100 #ifndef DEFAULT_TKT_LIFE /* allow compile-time override */ #define DEFAULT_TKT_LIFE 96 /* default lifetime for krb_mk_req & co., 8 hrs */ #endif /* Definition of text structure used to pass text around */ #define MAX_KTXT_LEN 1250 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; /* Definitions for send_to_kdc */ #define CLIENT_KRB_TIMEOUT 4 /* time between retries */ #define CLIENT_KRB_RETRY 5 /* retry this many times */ #define CLIENT_KRB_BUFLEN 512 /* max unfragmented packet */ /* Definitions for ticket file utilities */ #define R_TKT_FIL 0 #define W_TKT_FIL 1 /* Definitions for cl_get_tgt */ #ifdef PC #define CL_GTGT_INIT_FILE "\\kerberos\\k_in_tkts" #else #define CL_GTGT_INIT_FILE "/etc/k_in_tkts" #endif PC /* Parameters for rd_ap_req */ /* Maximum alloable clock skew in seconds */ #define CLOCK_SKEW 5*60 /* Filename for readservkey */ #define KEYFILE "/etc/kerberosIV/srvtab" /* Structure definition for rd_ap_req */ 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; /* Structure definition for credentials returned by get_cred */ struct credentials { char service[ANAME_SZ]; /* Service name */ char instance[INST_SZ]; /* Instance */ char realm[REALM_SZ]; /* Auth domain */ C_Block session; /* Session key */ int lifetime; /* Lifetime */ int kvno; /* Key version number */ KTEXT_ST ticket_st; /* The ticket itself */ long issue_date; /* The issue time */ char pname[ANAME_SZ]; /* Principal's name */ char pinst[INST_SZ]; /* Principal's instance */ }; typedef struct credentials CREDENTIALS; /* Structure definition for rd_private_msg and rd_safe_msg */ 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; /* Location of ticket file for save_cred and get_cred */ #ifdef PC #define TKT_FILE "\\kerberos\\ticket.ses" #else #define TKT_FILE tkt_string() #define TKT_ROOT "/tmp/tkt" #endif PC /* Error codes returned from the KDC */ #define KDC_OK 0 /* Request OK */ #define KDC_NAME_EXP 1 /* Principal expired */ #define KDC_SERVICE_EXP 2 /* Service expired */ #define KDC_AUTH_EXP 3 /* Auth expired */ #define KDC_PKT_VER 4 /* Protocol version unknown */ #define KDC_P_MKEY_VER 5 /* Wrong master key version */ #define KDC_S_MKEY_VER 6 /* Wrong master key version */ #define KDC_BYTE_ORDER 7 /* Byte order unknown */ #define KDC_PR_UNKNOWN 8 /* Principal unknown */ #define KDC_PR_N_UNIQUE 9 /* Principal not unique */ #define KDC_NULL_KEY 10 /* Principal has null key */ #define KDC_GEN_ERR 20 /* Generic error from KDC */ /* Values returned by get_credentials */ #define GC_OK 0 /* Retrieve OK */ #define RET_OK 0 /* Retrieve OK */ #define GC_TKFIL 21 /* Can't read ticket file */ #define RET_TKFIL 21 /* Can't read ticket file */ #define GC_NOTKT 22 /* Can't find ticket or TGT */ #define RET_NOTKT 22 /* Can't find ticket or TGT */ /* Values returned by mk_ap_req */ #define MK_AP_OK 0 /* Success */ #define MK_AP_TGTEXP 26 /* TGT Expired */ /* Values returned by rd_ap_req */ #define RD_AP_OK 0 /* Request authentic */ #define RD_AP_UNDEC 31 /* Can't decode authenticator */ #define RD_AP_EXP 32 /* Ticket expired */ #define RD_AP_NYV 33 /* Ticket not yet valid */ #define RD_AP_REPEAT 34 /* Repeated request */ #define RD_AP_NOT_US 35 /* The ticket isn't for us */ #define RD_AP_INCON 36 /* Request is inconsistent */ #define RD_AP_TIME 37 /* delta_t too big */ #define RD_AP_BADD 38 /* Incorrect net address */ #define RD_AP_VERSION 39 /* protocol version mismatch */ #define RD_AP_MSG_TYPE 40 /* invalid msg type */ #define RD_AP_MODIFIED 41 /* message stream modified */ #define RD_AP_ORDER 42 /* message out of order */ #define RD_AP_UNAUTHOR 43 /* unauthorized request */ /* Values returned by get_pw_tkt */ #define GT_PW_OK 0 /* Got password changing tkt */ #define GT_PW_NULL 51 /* Current PW is null */ #define GT_PW_BADPW 52 /* Incorrect current password */ #define GT_PW_PROT 53 /* Protocol Error */ #define GT_PW_KDCERR 54 /* Error returned by KDC */ #define GT_PW_NULLTKT 55 /* Null tkt returned by KDC */ /* Values returned by send_to_kdc */ #define SKDC_OK 0 /* Response received */ #define SKDC_RETRY 56 /* Retry count exceeded */ #define SKDC_CANT 57 /* Can't send request */ /* * Values returned by get_intkt * (can also return SKDC_* and KDC errors) */ #define INTK_OK 0 /* Ticket obtained */ #define INTK_W_NOTALL 61 /* Not ALL tickets returned */ #define INTK_BADPW 62 /* Incorrect password */ #define INTK_PROT 63 /* Protocol Error */ #define INTK_ERR 70 /* Other error */ /* Values returned by get_adtkt */ #define AD_OK 0 /* Ticket Obtained */ #define AD_NOTGT 71 /* Don't have tgt */ /* Error codes returned by ticket file utilities */ #define NO_TKT_FIL 76 /* No ticket file found */ #define TKT_FIL_ACC 77 /* Couldn't access tkt file */ #define TKT_FIL_LCK 78 /* Couldn't lock ticket file */ #define TKT_FIL_FMT 79 /* Bad ticket file format */ #define TKT_FIL_INI 80 /* tf_init not called first */ /* Error code returned by kparse_name */ #define KNAME_FMT 81 /* Bad Kerberos name format */ +/* Error codes returned by get_local_addr and bind_local_addr */ +#define GT_LADDR_NOSOCK 82 /* Can't open socket */ +#define GT_LADDR_IFLIST 83 /* + * Can't retrieve local interface + * configuration list + */ +#define GT_LADDR_NVI 84 /* No valid local interface found */ +#define BND_LADDR_BIND 85 /* Can't bind local address */ + /* Error code returned by krb_mk_safe */ #define SAFE_PRIV_ERROR -1 /* syscall error */ /* * macros for byte swapping; also scratch space * u_quad 0-->7, 1-->6, 2-->5, 3-->4, 4-->3, 5-->2, 6-->1, 7-->0 * u_long 0-->3, 1-->2, 2-->1, 3-->0 * u_short 0-->1, 1-->0 */ #define swap_u_16(x) {\ unsigned long _krb_swap_tmp[4];\ swab(((char *) x) +0, ((char *) _krb_swap_tmp) +14 ,2); \ swab(((char *) x) +2, ((char *) _krb_swap_tmp) +12 ,2); \ swab(((char *) x) +4, ((char *) _krb_swap_tmp) +10 ,2); \ swab(((char *) x) +6, ((char *) _krb_swap_tmp) +8 ,2); \ swab(((char *) x) +8, ((char *) _krb_swap_tmp) +6 ,2); \ swab(((char *) x) +10,((char *) _krb_swap_tmp) +4 ,2); \ swab(((char *) x) +12,((char *) _krb_swap_tmp) +2 ,2); \ swab(((char *) x) +14,((char *) _krb_swap_tmp) +0 ,2); \ bcopy((char *)_krb_swap_tmp,(char *)x,16);\ } #define swap_u_12(x) {\ unsigned long _krb_swap_tmp[4];\ swab(( char *) x, ((char *) _krb_swap_tmp) +10 ,2); \ swab(((char *) x) +2, ((char *) _krb_swap_tmp) +8 ,2); \ swab(((char *) x) +4, ((char *) _krb_swap_tmp) +6 ,2); \ swab(((char *) x) +6, ((char *) _krb_swap_tmp) +4 ,2); \ swab(((char *) x) +8, ((char *) _krb_swap_tmp) +2 ,2); \ swab(((char *) x) +10,((char *) _krb_swap_tmp) +0 ,2); \ bcopy((char *)_krb_swap_tmp,(char *)x,12);\ } #define swap_C_Block(x) {\ unsigned long _krb_swap_tmp[4];\ swab(( char *) x, ((char *) _krb_swap_tmp) +6 ,2); \ swab(((char *) x) +2,((char *) _krb_swap_tmp) +4 ,2); \ swab(((char *) x) +4,((char *) _krb_swap_tmp) +2 ,2); \ swab(((char *) x) +6,((char *) _krb_swap_tmp) ,2); \ bcopy((char *)_krb_swap_tmp,(char *)x,8);\ } #define swap_u_quad(x) {\ unsigned long _krb_swap_tmp[4];\ swab(( char *) &x, ((char *) _krb_swap_tmp) +6 ,2); \ swab(((char *) &x) +2,((char *) _krb_swap_tmp) +4 ,2); \ swab(((char *) &x) +4,((char *) _krb_swap_tmp) +2 ,2); \ swab(((char *) &x) +6,((char *) _krb_swap_tmp) ,2); \ bcopy((char *)_krb_swap_tmp,(char *)&x,8);\ } #define swap_u_long(x) {\ unsigned long _krb_swap_tmp[4];\ swab((char *) &x, ((char *) _krb_swap_tmp) +2 ,2); \ swab(((char *) &x) +2,((char *) _krb_swap_tmp),2); \ x = _krb_swap_tmp[0]; \ } #define swap_u_short(x) {\ unsigned short _krb_swap_sh_tmp; \ swab((char *) &x, ( &_krb_swap_sh_tmp) ,2); \ x = (unsigned short) _krb_swap_sh_tmp; \ } /* Kerberos ticket flag field bit definitions */ #define K_FLAG_ORDER 0 /* bit 0 --> lsb */ #define K_FLAG_1 /* reserved */ #define K_FLAG_2 /* reserved */ #define K_FLAG_3 /* reserved */ #define K_FLAG_4 /* reserved */ #define K_FLAG_5 /* reserved */ #define K_FLAG_6 /* reserved */ #define K_FLAG_7 /* reserved, bit 7 --> msb */ #ifndef PC char *tkt_string(); #endif PC #ifdef OLDNAMES #define krb_mk_req mk_ap_req #define krb_rd_req rd_ap_req #define krb_kntoln an_to_ln #define krb_set_key set_serv_key #define krb_get_cred get_credentials #define krb_mk_priv mk_private_msg #define krb_rd_priv rd_private_msg #define krb_mk_safe mk_safe_msg #define krb_rd_safe rd_safe_msg #define krb_mk_err mk_appl_err_msg #define krb_rd_err rd_appl_err_msg #define krb_ck_repl check_replay #define krb_get_pw_in_tkt get_in_tkt #define krb_get_svc_in_tkt get_svc_in_tkt #define krb_get_pw_tkt get_pw_tkt #define krb_realmofhost krb_getrealm #define krb_get_phost get_phost #define krb_get_krbhst get_krbhst #define krb_get_lrealm get_krbrlm #endif OLDNAMES /* Defines for krb_sendauth and krb_recvauth */ #define KOPT_DONT_MK_REQ 0x00000001 /* don't call krb_mk_req */ #define KOPT_DO_MUTUAL 0x00000002 /* do mutual auth */ #define KOPT_DONT_CANON 0x00000004 /* * don't canonicalize inst as * a hostname */ #define KRB_SENDAUTH_VLEN 8 /* length for version strings */ #ifdef ATHENA_COMPAT #define KOPT_DO_OLDSTYLE 0x00000008 /* use the old-style protocol */ #endif ATHENA_COMPAT /* libacl */ void acl_canonicalize_principal __P((char *principal, char *buf)); int acl_check __P((char *acl, char *principal)); int acl_exact_match __P((char *acl, char *principal)); int acl_add __P((char *acl, char *principal)); int acl_delete __P((char *acl, char *principal)); int acl_initialize __P((char *acl_file, int mode)); /* libkrb - krb.3 */ int krb_mk_req __P((KTEXT authent, char *service, char *instance, char *realm, long checksum); int krb_rd_req __P((KTEXT authent, char *service, char *instance, long from_addr, AUTH_DAT *ad, char *fn)); int krb_kntoln __P((AUTH_DAT *ad, char *lname)); int krb_set_key __P((char *key, int cvt)); int krb_get_cred __P((char *service, char *instance, char *realm, CREDENTIALS *c)); long krb_mk_priv __P((u_char *in, u_char *out, u_long in_length, des_key_schedule schedule, des_cblock key, struct sockaddr_in *sender, struct sockaddr_in *receiver)); long krb_rd_priv __P((u_char *in, u_long in_length, Key_schedule schedule, des_cblock key, struct sockaddr_in *sender, struct sockaddr_in *receiver, MSG_DAT *msg_data)); long krb_mk_safe __P((u_char *in, u_char *out, u_long in_length, des_cblock *key, struct sockaddr_in *sender, struct sockaddr_in *receiver)); long krb_rd_safe __P((u_char *in, u_long length, des_cblock *key, struct sockaddr_in *sender, struct sockaddr_in *receiver, MSG_DAT *msg_data)); long krb_mk_err __P((u_char *out, long code, char *string)); int krb_rd_err __P((u_char *in, u_long in_length, long *code, MSG_DAT *m_data)); /* libkrb - krb_sendauth.3 */ int krb_sendauth __P((long options, int fd, KTEXT ticket, char *service, char *inst, char *realm, u_long checksum, MSG_DAT *msg_data, CREDENTIALS *cred, Key_schedule schedule, struct sockaddr_in *laddr, struct sockaddr_in *faddr, char *version)); int krb_recvauth __P((long options, int fd, KTEXT ticket, char *service, char *instance, struct sockaddr_in *faddr, struct sockaddr_in *laddr, AUTH_DAT *kdata, char *filename, Key_schedule schedule, char *version)); int krb_net_write __P((int fd, char *buf, int len)); int krb_net_read __P((int fd, char *buf, int len)); /* libkrb - krb_realmofhost.3 */ char *krb_realmofhost __P((char *host)); char *krb_get_phost __P((char *alias)); int krb_get_krbhst __P((char *h, char *r, int n)); int krb_get_admhst __P((char *h, char *r, int n)); int krb_get_lrealm __P((char *r, int n)); /* libkrb - krb_set_tkt_string.3 */ void krb_set_tkt_string(char *val); /* libkrb - kuserok.3 */ int kuserok __P((AUTH_DAT *authdata, char *localuser)); /* libkrb - tf_util.3 */ int tf_init __P((char *tf_name, int rw)); int tf_get_pname __P((char *p)); int tf_get_pinst __P((char *inst)); int tf_get_cred __P((CREDENTIALS *c)); void tf_close __P((void)); /* Internal routines */ int des_read __P((int fd, char *buf, int len)); int des_write __P((int fd, char *buf, int len)); int krb_get_tf_realm __P((char *ticket_file, char *realm)); int krb_get_in_tkt __P((char *user, char *instance, char *realm, char *service, char *sinstance, int life, int (*key_proc)(), int (*decrypt_proc)(), char *arg)); int krb_get_pw_in_tkt __P((char *user, char *instance, char *realm, char *service, char *sinstance, int life, char *password)); int krb_get_svc_in_tkt __P((char *user, char *instance, char *realm, char *service, char *sinstance, int life, char *srvtab)); int krb_get_tf_fullname __P((char *ticket_file, char *name, char *instance, char *realm)); int save_credentials __P((char *service, char *instance, char *realm, des_cblock session, int lifetime, int kvno, KTEXT ticket, long issue_date)); int read_service_key __P((char *service, char *instance, char *realm, int kvno, char *file, char *key)); int get_ad_tkt __P((char *service, char *sinstance, char *realm, int lifetime)); int send_to_kdc __P((KTEXT pkt, KTEXT rpkt, char *realm)); +int krb_bind_local_addr __P((int s)); +int krb_get_local_addr __P((struct sockaddr_in *returned_addr)); int krb_create_ticket __P((KTEXT tkt, unsigned char flags, char *pname, char *pinstance, char *prealm, long paddress, char *session, short life, long time_sec, char *sname, char *sinstance, C_Block key)); int decomp_ticket __P((KTEXT tkt, unsigned char *flags, char *pname, char *pinstance, char *prealm, unsigned long *paddress, des_cblock session, int *life, unsigned long *time_sec, char *sname, char *sinstance, des_cblock key, des_key_schedule key_s)); int create_ciph __P((KTEXT c, C_Block session, char *service, char *instance, char *realm, unsigned long life, int kvno, KTEXT tkt, unsigned long kdc_time, C_Block key)); int kname_parse __P((char *np, char *ip, char *rp, char *fullname)); int tf_save_cred __P((char *service, char *instance, char *realm, des_cblock session, int lifetime, int kvno, KTEXT ticket, long issue_date)); int getst(int fd, char *s, int n)); int pkt_clen __P((KTEXT pkt)); int in_tkt __P((char *pname, char *pinst)); int dest_tkt __P((void)); char *month_sname __P((int n)); void log __P(()); /* Actually VARARGS - markm */ void kset_logfile __P((char *filename)); void set_logfile __P((char *filename)); int k_isinst __P((char *s)); int k_isrealm __P((char *s)); int k_isname __P((char *s)); int k_gethostname __P((char *name, int namelen)); int kerb_init __P((void)); void kerb_fini __P((void)); int kerb_db_set_name __P((char *name)); int kerb_db_set_lockmode __P((int mode)); int kerb_db_create __P((char *db_name)); int kerb_db_iterate __P((int (*func)(), char *arg)); int kerb_db_rename __P((char *from, char *to)); long kerb_get_db_age __P((void)); char * stime __P((long *t)); long kdb_get_master_key __P((int prompt, C_Block master_key, Key_schedule master_key_sched)); long kdb_verify_master_key __P((C_Block master_key, Key_schedule master_key_sched, FILE *out)); void kdb_encrypt_key __P((C_Block in, C_Block out, C_Block master_key, Key_schedule master_key_sched, int e_d_flag)); extern int krb_ap_req_debug; extern int krb_debug; #endif KRB_DEFS diff --git a/eBones/lib/libkadm/kadm_cli_wrap.c b/eBones/lib/libkadm/kadm_cli_wrap.c index e25439dbba2b..c3eb730de891 100644 --- a/eBones/lib/libkadm/kadm_cli_wrap.c +++ b/eBones/lib/libkadm/kadm_cli_wrap.c @@ -1,509 +1,514 @@ /* * Copyright 1988 by the Massachusetts Institute of Technology. * * For copying and distribution information, please see the file * Copyright.MIT. * * Kerberos administration server client-side routines */ #if 0 #ifndef lint static char rcsid_kadm_cli_wrap_c[] = "from: Id: kadm_cli_wrap.c,v 4.6 89/12/30 20:09:45 qjb Exp"; static const char rcsid[] = - "$Id: kadm_cli_wrap.c,v 1.1 1995/07/18 16:40:23 mark Exp $"; + "$Id: kadm_cli_wrap.c,v 1.4 1995/09/07 21:38:47 markm Exp $"; #endif lint #endif /* * kadm_cli_wrap.c the client side wrapping of the calls to the admin server */ #include #include #include #include #include #include #include #include #include #include #ifndef NULL #define NULL 0 #endif static Kadm_Client client_parm; /* Macros for use in returning data... used in kadm_cli_send */ #define RET_N_FREE(r) {clear_secrets(); free((char *)act_st); free((char *)priv_pak); return r;} /* Keys for use in the transactions */ static des_cblock sess_key; /* to be filled in by kadm_cli_keyd */ static Key_schedule sess_sched; static void clear_secrets() { bzero((char *)sess_key, sizeof(sess_key)); bzero((char *)sess_sched, sizeof(sess_sched)); } /* * kadm_init_link * receives : name, inst, realm * * initializes client parm, the Kadm_Client structure which holds the * data about the connection between the server and client, the services * used, the locations and other fun things */ int kadm_init_link(n, i, r) char n[]; char i[]; char r[]; { struct servent *sep; /* service we will talk to */ struct hostent *hop; /* host we will talk to */ char adm_hostname[MAXHOSTNAMELEN]; (void) init_kadm_err_tbl(); (void) init_krb_err_tbl(); (void) strcpy(client_parm.sname, n); (void) strcpy(client_parm.sinst, i); (void) strcpy(client_parm.krbrlm, r); client_parm.admin_fd = -1; /* set up the admin_addr - fetch name of admin host */ if (krb_get_admhst(adm_hostname, client_parm.krbrlm, 1) != KSUCCESS) return KADM_NO_HOST; if ((hop = gethostbyname(adm_hostname)) == NULL) return KADM_UNK_HOST; /* couldnt find the admin servers * address */ if ((sep = getservbyname(KADM_SNAME, "tcp")) == NULL) return KADM_NO_SERV; /* couldnt find the admin service */ bzero((char *) &client_parm.admin_addr, sizeof(client_parm.admin_addr)); client_parm.admin_addr.sin_family = hop->h_addrtype; bcopy((char *) hop->h_addr, (char *) &client_parm.admin_addr.sin_addr, hop->h_length); client_parm.admin_addr.sin_port = sep->s_port; return KADM_SUCCESS; } /* procedure kadm_init_link */ /* * kadm_change_pw * recieves : key * * 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 kadm_change_pw(newkey) des_cblock newkey; /* The DES form of the users key */ { int stsize, retc; /* stream size and return code */ u_char *send_st; /* send stream */ u_char *ret_st; int ret_sz; u_long keytmp; if ((retc = kadm_cli_conn()) != KADM_SUCCESS) return(retc); /* possible problem with vts_long on a non-multiple of four boundary */ stsize = 0; /* start of our output packet */ send_st = (u_char *) malloc(1);/* to make it reallocable */ send_st[stsize++] = (u_char) CHANGE_PW; /* change key to stream */ bcopy((char *) (((long *) newkey) + 1), (char *) &keytmp, 4); keytmp = htonl(keytmp); stsize += vts_long(keytmp, &send_st, stsize); bcopy((char *) newkey, (char *) &keytmp, 4); keytmp = htonl(keytmp); stsize += vts_long(keytmp, &send_st, stsize); retc = kadm_cli_send(send_st, stsize, &ret_st, &ret_sz); free((char *)send_st); if (retc == KADM_SUCCESS) { free((char *)ret_st); } kadm_cli_disconn(); return(retc); } /* * kadm_add * receives : vals * returns : vals * * Adds and entry containing values to the database returns the values of the * entry, so if you leave certain fields blank you will be able to determine * the default values they are set to */ int kadm_add(vals) Kadm_vals *vals; { u_char *st, *st2; /* st will hold the stream of values */ int st_len; /* st2 the final stream with opcode */ int retc; /* return code from call */ u_char *ret_st; int ret_sz; if ((retc = kadm_cli_conn()) != KADM_SUCCESS) return(retc); st_len = vals_to_stream(vals, &st); st2 = (u_char *) malloc((unsigned)(1 + st_len)); *st2 = (u_char) ADD_ENT; /* here's the opcode */ bcopy((char *) st, (char *) st2 + 1, st_len); /* append st on */ retc = kadm_cli_send(st2, st_len + 1, &ret_st, &ret_sz); free((char *)st); free((char *)st2); if (retc == KADM_SUCCESS) { /* ret_st has vals */ if (stream_to_vals(ret_st, vals, ret_sz) < 0) retc = KADM_LENGTH_ERROR; free((char *)ret_st); } kadm_cli_disconn(); return(retc); } /* * kadm_mod * receives : KTEXT, {values, values} * returns : CKSUM, RETCODE, {values} * acl : su, sms (as register or dealloc) * * Modifies all entries corresponding to the first values so they match the * second values. returns the values for the changed entries in vals2 */ int kadm_mod(vals1, vals2) Kadm_vals *vals1; Kadm_vals *vals2; { u_char *st, *st2; /* st will hold the stream of values */ int st_len, nlen; /* st2 the final stream with opcode */ u_char *ret_st; int ret_sz; /* nlen is the length of second vals */ int retc; /* return code from call */ if ((retc = kadm_cli_conn()) != KADM_SUCCESS) return(retc); st_len = vals_to_stream(vals1, &st); st2 = (u_char *) malloc((unsigned)(1 + st_len)); *st2 = (u_char) MOD_ENT; /* here's the opcode */ bcopy((char *) st, (char *) st2 + 1, st_len++); /* append st on */ free((char *)st); nlen = vals_to_stream(vals2, &st); st2 = (u_char *) realloc((char *) st2, (unsigned)(st_len + nlen)); bcopy((char *) st, (char *) st2 + st_len, nlen); /* append st on */ retc = kadm_cli_send(st2, st_len + nlen, &ret_st, &ret_sz); free((char *)st); free((char *)st2); if (retc == KADM_SUCCESS) { /* ret_st has vals */ if (stream_to_vals(ret_st, vals2, ret_sz) < 0) retc = KADM_LENGTH_ERROR; free((char *)ret_st); } kadm_cli_disconn(); return(retc); } /* * kadm_get * receives : KTEXT, {values, flags} * returns : CKSUM, RETCODE, {count, values, values, values} * acl : su * * gets the fields requested by flags from all entries matching values returns * this data for each matching recipient, after a count of how many such * matches there were */ int kadm_get(vals, fl) Kadm_vals *vals; u_char fl[4]; { int loop; /* for copying the fields data */ u_char *st, *st2; /* st will hold the stream of values */ int st_len; /* st2 the final stream with opcode */ int retc; /* return code from call */ u_char *ret_st; int ret_sz; if ((retc = kadm_cli_conn()) != KADM_SUCCESS) return(retc); st_len = vals_to_stream(vals, &st); st2 = (u_char *) malloc((unsigned)(1 + st_len + FLDSZ)); *st2 = (u_char) GET_ENT; /* here's the opcode */ bcopy((char *) st, (char *) st2 + 1, st_len); /* append st on */ for (loop = FLDSZ - 1; loop >= 0; loop--) *(st2 + st_len + FLDSZ - loop) = fl[loop]; /* append the flags */ retc = kadm_cli_send(st2, st_len + 1 + FLDSZ, &ret_st, &ret_sz); free((char *)st); free((char *)st2); if (retc == KADM_SUCCESS) { /* ret_st has vals */ if (stream_to_vals(ret_st, vals, ret_sz) < 0) retc = KADM_LENGTH_ERROR; free((char *)ret_st); } kadm_cli_disconn(); return(retc); } /* * kadm_cli_send * recieves : opcode, packet, packet length, serv_name, serv_inst * returns : return code from the packet build, the server, or * something else * * It assembles a packet as follows: * 8 bytes : VERSION STRING * 4 bytes : LENGTH OF MESSAGE DATA and OPCODE * : KTEXT * : OPCODE \ * : DATA > Encrypted (with make priv) * : ...... / * * If it builds the packet and it is small enough, then it attempts to open the * connection to the admin server. If the connection is succesfully open * then it sends the data and waits for a reply. */ int kadm_cli_send(st_dat, st_siz, ret_dat, ret_siz) u_char *st_dat; /* the actual data */ int st_siz; /* length of said data */ u_char **ret_dat; /* to give return info */ int *ret_siz; /* length of returned info */ { int act_len, retdat; /* current offset into packet, return * data */ KTEXT_ST authent; /* the authenticator we will build */ u_char *act_st; /* the pointer to the complete packet */ u_char *priv_pak; /* private version of the packet */ int priv_len; /* length of private packet */ u_long cksum; /* checksum of the packet */ MSG_DAT mdat; u_char *return_dat; act_st = (u_char *) malloc(KADM_VERSIZE); /* verstr stored first */ (void) strncpy((char *)act_st, KADM_VERSTR, KADM_VERSIZE); act_len = KADM_VERSIZE; if ((retdat = kadm_cli_keyd(sess_key, sess_sched)) != KADM_SUCCESS) { free((char *)act_st); return retdat; /* couldnt get key working */ } priv_pak = (u_char *) malloc((unsigned)(st_siz + 200)); /* 200 bytes for extra info case */ if ((priv_len = krb_mk_priv(st_dat, priv_pak, (u_long)st_siz, sess_sched, sess_key, &client_parm.my_addr, &client_parm.admin_addr)) < 0) RET_N_FREE(KADM_NO_ENCRYPT); /* whoops... we got a lose * here */ /* here is the length of priv data. receiver calcs size of authenticator by subtracting vno size, priv size, and sizeof(u_long) (for the size indication) from total size */ act_len += vts_long((u_long) priv_len, &act_st, act_len); #ifdef NOENCRYPTION cksum = 0; #else cksum = quad_cksum((des_cblock *)priv_pak, (des_cblock *)0, (long)priv_len, 0, (des_cblock *)sess_key); #endif if ((retdat = krb_mk_req(&authent, client_parm.sname, client_parm.sinst, client_parm.krbrlm, (long)cksum))) { /* authenticator? */ RET_N_FREE(retdat + krb_err_base); } act_st = (u_char *) realloc((char *) act_st, (unsigned) (act_len + authent.length + priv_len)); if (!act_st) { clear_secrets(); free((char *)priv_pak); return(KADM_NOMEM); } bcopy((char *) authent.dat, (char *) act_st + act_len, authent.length); bcopy((char *) priv_pak, (char *) act_st + act_len + authent.length, priv_len); free((char *)priv_pak); if ((retdat = kadm_cli_out(act_st, act_len + authent.length + priv_len, ret_dat, ret_siz)) != KADM_SUCCESS) RET_N_FREE(retdat); free((char *)act_st); #define RET_N_FREE2(r) {free((char *)*ret_dat); clear_secrets(); return(r);} /* first see if it's a YOULOUSE */ if ((*ret_siz >= KADM_VERSIZE) && !strncmp(KADM_ULOSE, (char *)*ret_dat, KADM_VERSIZE)) { u_long errcode; /* it's a youlose packet */ if (*ret_siz < KADM_VERSIZE + sizeof(u_long)) RET_N_FREE2(KADM_BAD_VER); bcopy((char *)(*ret_dat) + KADM_VERSIZE, (char *)&errcode, sizeof(u_long)); retdat = (int) ntohl(errcode); RET_N_FREE2(retdat); } /* need to decode the ret_dat */ if ((retdat = krb_rd_priv(*ret_dat, (u_long)*ret_siz, sess_sched, sess_key, &client_parm.admin_addr, &client_parm.my_addr, &mdat))) RET_N_FREE2(retdat+krb_err_base); if (mdat.app_length < KADM_VERSIZE + 4) /* too short! */ RET_N_FREE2(KADM_BAD_VER); if (strncmp((char *)mdat.app_data, KADM_VERSTR, KADM_VERSIZE)) /* bad version */ RET_N_FREE2(KADM_BAD_VER); bcopy((char *)mdat.app_data+KADM_VERSIZE, (char *)&retdat, sizeof(u_long)); retdat = ntohl((u_long)retdat); if (!(return_dat = (u_char *)malloc((unsigned)(mdat.app_length - KADM_VERSIZE - sizeof(u_long))))) RET_N_FREE2(KADM_NOMEM); bcopy((char *) mdat.app_data + KADM_VERSIZE + sizeof(u_long), (char *)return_dat, (int)mdat.app_length - KADM_VERSIZE - sizeof(u_long)); free((char *)*ret_dat); clear_secrets(); *ret_dat = return_dat; *ret_siz = mdat.app_length - KADM_VERSIZE - sizeof(u_long); return retdat; } /* takes in the sess_key and key_schedule and sets them appropriately */ int kadm_cli_keyd(s_k, s_s) des_cblock s_k; /* session key */ des_key_schedule s_s; /* session key schedule */ { CREDENTIALS cred; /* to get key data */ int stat; /* want .sname and .sinst here.... */ if ((stat = krb_get_cred(client_parm.sname, client_parm.sinst, client_parm.krbrlm, &cred))) return stat + krb_err_base; bcopy((char *) cred.session, (char *) s_k, sizeof(des_cblock)); bzero((char *) cred.session, sizeof(des_cblock)); #ifdef NOENCRYPTION bzero(s_s, sizeof(des_key_schedule)); #else if ((stat = key_sched((des_cblock *)s_k,s_s))) return(stat+krb_err_base); #endif return KADM_SUCCESS; } /* This code "works" */ static sigtype (*opipe)(); int kadm_cli_conn() { /* this connects and sets my_addr */ int on = 1; + int kerror; if ((client_parm.admin_fd = socket(client_parm.admin_addr.sin_family, SOCK_STREAM,0)) < 0) return KADM_NO_SOCK; /* couldnt create the socket */ + client_parm.my_addr_len = sizeof(client_parm.my_addr); + if ((kerror = krb_get_local_addr(&client_parm.my_addr)) != KSUCCESS) { + (void) close(client_parm.admin_fd); + client_parm.admin_fd = -1; + return KADM_NO_HERE; + } + if (bind(client_parm.admin_fd, + (struct sockaddr *) & client_parm.admin_addr, + sizeof(client_parm.my_addr))) { + (void) close(client_parm.admin_fd); + client_parm.admin_fd = -1; + return KADM_NO_HERE; + } if (connect(client_parm.admin_fd, (struct sockaddr *) & client_parm.admin_addr, sizeof(client_parm.admin_addr))) { (void) close(client_parm.admin_fd); client_parm.admin_fd = -1; return KADM_NO_CONN; /* couldnt get the connect */ } opipe = signal(SIGPIPE, SIG_IGN); - client_parm.my_addr_len = sizeof(client_parm.my_addr); - if (getsockname(client_parm.admin_fd, - (struct sockaddr *) & client_parm.my_addr, - &client_parm.my_addr_len) < 0) { - (void) close(client_parm.admin_fd); - client_parm.admin_fd = -1; - (void) signal(SIGPIPE, opipe); - return KADM_NO_HERE; /* couldnt find out who we are */ - } if (setsockopt(client_parm.admin_fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) < 0) { (void) close(client_parm.admin_fd); client_parm.admin_fd = -1; (void) signal(SIGPIPE, opipe); return KADM_NO_CONN; /* XXX */ } return KADM_SUCCESS; } void kadm_cli_disconn() { (void) close(client_parm.admin_fd); (void) signal(SIGPIPE, opipe); } int kadm_cli_out(dat, dat_len, ret_dat, ret_siz) u_char *dat; int dat_len; u_char **ret_dat; int *ret_siz; { extern int errno; u_short dlen; int retval; dlen = (u_short) dat_len; if (dat_len != (int)dlen) return (KADM_NO_ROOM); dlen = htons(dlen); if (krb_net_write(client_parm.admin_fd, (char *) &dlen, sizeof(u_short)) < 0) return (errno); /* XXX */ if (krb_net_write(client_parm.admin_fd, (char *) dat, dat_len) < 0) return (errno); /* XXX */ if ((retval = krb_net_read(client_parm.admin_fd, (char *) &dlen, sizeof(u_short)) != sizeof(u_short))) { if (retval < 0) return(errno); /* XXX */ else return(EPIPE); /* short read ! */ } dlen = ntohs(dlen); *ret_dat = (u_char *)malloc((unsigned)dlen); if (!*ret_dat) return(KADM_NOMEM); if ((retval = krb_net_read(client_parm.admin_fd, (char *) *ret_dat, (int) dlen) != dlen)) { if (retval < 0) return(errno); /* XXX */ else return(EPIPE); /* short read ! */ } *ret_siz = (int) dlen; return KADM_SUCCESS; } diff --git a/eBones/lib/libkrb/Makefile b/eBones/lib/libkrb/Makefile index eefe1a55d9b3..829fbeadee9d 100644 --- a/eBones/lib/libkrb/Makefile +++ b/eBones/lib/libkrb/Makefile @@ -1,53 +1,54 @@ # From: @(#)Makefile 5.1 (Berkeley) 6/25/90 -# $Id: Makefile,v 1.8 1995/09/13 17:23:55 markm Exp $ +# $Id: Makefile,v 1.9 1995/09/14 04:05:02 gibbs Exp $ LIB= krb CFLAGS+=-DKERBEROS -DCRYPT -DDEBUG -DBSD42 SRCS= krb_err.c create_auth_reply.c create_ciph.c \ create_death_packet.c create_ticket.c debug_decl.c decomp_ticket.c \ des_rw.c dest_tkt.c extract_ticket.c fgetst.c get_ad_tkt.c \ get_admhst.c get_cred.c get_in_tkt.c get_krbhst.c get_krbrlm.c \ get_phost.c get_pw_tkt.c get_request.c get_svc_in_tkt.c \ get_tf_fullname.c get_tf_realm.c getrealm.c getst.c in_tkt.c \ k_gethostname.c klog.c kname_parse.c kntoln.c kparse.c \ krb_err_txt.c krb_get_in_tkt.c kuserok.c log.c mk_err.c \ mk_priv.c mk_req.c mk_safe.c month_sname.c \ netread.c netwrite.c one.c pkt_cipher.c pkt_clen.c rd_err.c \ rd_priv.c rd_req.c rd_safe.c read_service_key.c recvauth.c \ save_credentials.c send_to_kdc.c sendauth.c stime.c tf_util.c \ tkt_string.c util.c LDADD+= -lcom_err beforeinstall: -cd ${.OBJDIR}; cmp -s krb_err.h \ ${DESTDIR}/usr/include/kerberosIV/krb_err.h || \ install -c -o ${BINOWN} -g ${BINGRP} -m 444 krb_err.h \ ${DESTDIR}/usr/include/kerberosIV MAN3= krb.3 krb_realmofhost.3 krb_sendauth.3 krb_set_tkt_string.3 \ kuserok.3 tf_util.3 MLINKS= krb.3 krb_mk_req.3 krb.3 krb_rd_req.3 krb.3 krb_kntoln.3 \ krb.3 krb_set_key.3 krb.3 krb_get_cred.3 krb.3 krb_mk_priv.3 \ krb.3 krb_rd_priv.3 krb.3 krb_mk_safe.3 krb.3 krb_rd_safe.3 \ - krb.3 krb_mk_err.3 krb.3 krb_rd_err.3 krb.3 krb_ck_repl.3 + krb.3 krb_mk_err.3 krb.3 krb_rd_err.3 krb.3 krb_ck_repl.3 \ + krb.3 krb_get_local_addr.3 krb.3 krb_bind_local_addr.3 MLINKS+=krb_realmofhost.3 krb_get_phost.3 krb_realmofhost.3 krb_get_krbhst.3 \ krb_realmofhost.3 krb_get_admhst.3 krb_realmofhost.3 krb_get_lrealm.3 MLINKS+=krb_realmofhost.3 realm.3 MLINKS+=krb_sendauth.3 krb_recvauth.3 krb_sendauth.3 krb_net_write.3 \ krb_sendauth.3 krb_net_read.3 MLINKS+=krb_sendauth.3 ksend.3 MLINKS+=tf_util.3 tf_init.3 tf_util.3 tf_get_pname.3 \ tf_util.3 tf_get_pinst.3 tf_util.3 tf_get_cred.3 \ tf_util.3 tf_close.3 .include krb_err.c: ${KRBOBJDIR}/krb_err.h diff --git a/eBones/lib/libkrb/krb.3 b/eBones/lib/libkrb/krb.3 index 10e20e948077..f2061cd184bf 100644 --- a/eBones/lib/libkrb/krb.3 +++ b/eBones/lib/libkrb/krb.3 @@ -1,462 +1,508 @@ -.\" $Source: /usr/cvs/src/eBones/krb/krb.3,v $ -.\" $Author: mark $ -.\" $Header: /usr/cvs/src/eBones/krb/krb.3,v 1.2 1995/07/18 16:40:57 mark Exp $ +.\" $Source: /home/ncvs/src/eBones/lib/libkrb/krb.3,v $ +.\" $Author: markm $ +.\" $Header: /home/ncvs/src/eBones/lib/libkrb/krb.3,v 1.3 1995/09/13 17:23:55 markm Exp $ .\" Copyright 1989 by the Massachusetts Institute of Technology. .\" .\" For copying and distribution information, .\" please see the file . .\" .TH KERBEROS 3 "Kerberos Version 4.0" "MIT Project Athena" .SH NAME -krb_mk_req, krb_rd_req, krb_kntoln, krb_set_key, krb_get_cred, -krb_mk_priv, krb_rd_priv, krb_mk_safe, krb_rd_safe, krb_mk_err, -krb_rd_err, krb_ck_repl \- Kerberos authentication library +Kerberos authentication library +.PP +krb_mk_req, krb_rd_req, krb_kntoln, krb_set_key, +krb_get_cred, krb_mk_priv, krb_rd_priv, krb_mk_safe, +krb_rd_safe, krb_mk_err, krb_rd_err, krb_ck_repl +krb_get_local_addr, krb_bind_local_addr .SH SYNOPSIS .nf .nj .ft B #include #include .PP .ft B extern char *krb_err_txt[]; .PP .ft B int krb_mk_req(authent,service,instance,realm,checksum) KTEXT authent; char *service; char *instance; char *realm; u_long checksum; .PP .ft B int krb_rd_req(authent,service,instance,from_addr,ad,fn) KTEXT authent; char *service; char *instance; u_long from_addr; AUTH_DAT *ad; char *fn; .PP .ft B int krb_kntoln(ad,lname) AUTH_DAT *ad; char *lname; .PP .ft B int krb_set_key(key,cvt) char *key; int cvt; .PP .ft B int krb_get_cred(service,instance,realm,c) char *service; char *instance; char *realm; CREDENTIALS *c; .PP .ft B long krb_mk_priv(in,out,in_length,schedule,key,sender,receiver) u_char *in; u_char *out; u_long in_length; des_cblock key; des_key_schedule schedule; struct sockaddr_in *sender; struct sockaddr_in *receiver; .PP .ft B long krb_rd_priv(in,in_length,schedule,key,sender,receiver,msg_data) u_char *in; u_long in_length; Key_schedule schedule; des_cblock key; struct sockaddr_in *sender; struct sockaddr_in *receiver; MSG_DAT *msg_data; .PP .ft B long krb_mk_safe(in,out,in_length,key,sender,receiver) u_char *in; u_char *out; u_long in_length; des_cblock key; struct sockaddr_in *sender; struct sockaddr_in *receiver; .PP .ft B long krb_rd_safe(in,length,key,sender,receiver,msg_data) u_char *in; u_long length; des_cblock key; struct sockaddr_in *sender; struct sockaddr_in *receiver; MSG_DAT *msg_data; .PP .ft B long krb_mk_err(out,code,string) u_char *out; long code; char *string; .PP .ft B long krb_rd_err(in,length,code,msg_data) u_char *in; u_long length; long code; MSG_DAT *msg_data; +.PP +.ft B +int krb_get_local_addr(address) +struct sockaddr_in *address; +.PP +.ft B +int krb_bind_local_addr(socket) +int socket; .fi .ft R .SH DESCRIPTION This library supports network authentication and various related operations. The library contains many routines beyond those described in this man page, but they are not intended to be used directly. Instead, they are called by the routines that are described, the authentication server and the login program. .PP +The original MIT implementation of the krb library could fail when used on +multi-homed client machines. Two functions, +.I krb_get_local_addr +and +.I krb_bind_local_addr, +are provided to overcome this limitation. Any +application expected to function in a multi-homed environment (clients +with more than one network interface) that opens sockets to perform +authenticated or encrypted transactions must use one of these functions +to bind its sockets to the local address used and authenticated by Kerberos. +.PP .I krb_err_txt[] contains text string descriptions of various Kerberos error codes returned by some of the routines below. .PP .I krb_mk_req takes a pointer to a text structure in which an authenticator is to be built. It also takes the name, instance, and realm of the service to be used and an optional checksum. It is up to the application to decide how to generate the checksum. .I krb_mk_req then retrieves a ticket for the desired service and creates an authenticator. The authenticator is built in .I authent and is accessible to the calling procedure. .PP It is up to the application to get the authenticator to the service where it will be read by .I krb_rd_req. Unless an attacker posesses the session key contained in the ticket, it will be unable to modify the authenticator. Thus, the checksum can be used to verify the authenticity of the other data that will pass through a connection. .PP .I krb_rd_req takes an authenticator of type .B KTEXT, a service name, an instance, the address of the host originating the request, and a pointer to a structure of type .B AUTH_DAT which is filled in with information obtained from the authenticator. It also optionally takes the name of the file in which it will find the secret key(s) for the service. If the supplied .I instance contains "*", then the first service key with the same service name found in the service key file will be used, and the .I instance argument will be filled in with the chosen instance. This means that the caller must provide space for such an instance name. .PP It is used to find out information about the principal when a request has been made to a service. It is up to the application protocol to get the authenticator from the client to the service. The authenticator is then passed to .I krb_rd_req to extract the desired information. .PP .I krb_rd_req returns zero (RD_AP_OK) upon successful authentication. If a packet was forged, modified, or replayed, authentication will fail. If the authentication fails, a non-zero value is returned indicating the particular problem encountered. See .I krb.h for the list of error codes. .PP If the last argument is the null string (""), krb_rd_req will use the file /etc/kerberosIV/srvtab to find its keys. If the last argument is NULL, it will assume that the key has been set by .I krb_set_key and will not bother looking further. .PP .I krb_kntoln converts a Kerberos name to a local name. It takes a structure of type AUTH_DAT and uses the name and instance to look in the database /etc/kerberosIV/aname to find the corresponding local name. The local name is returned and can be used by an application to change uids, directories, or other parameters. It is not an integral part of Kerberos, but is instead provided to support the use of Kerberos in existing utilities. .PP .I krb_set_key takes as an argument a des key. It then creates a key schedule from it and saves the original key to be used as an initialization vector. It is used to set the server's key which must be used to decrypt tickets. .PP If called with a non-zero second argument, .I krb_set_key will first convert the input from a string of arbitrary length to a DES key by encrypting it with a one-way function. .PP In most cases it should not be necessary to call .I krb_set_key. The necessary keys will usually be obtained and set inside .I krb_rd_req. krb_set_key is provided for those applications that do not wish to place the application keys on disk. .PP .I krb_get_cred searches the caller's ticket file for a ticket for the given service, instance, and realm; and, if a ticket is found, fills in the given CREDENTIALS structure with the ticket information. .PP If the ticket was found, .I krb_get_cred returns GC_OK. If the ticket file can't be found, can't be read, doesn't belong to the user (other than root), isn't a regular file, or is in the wrong mode, the error GC_TKFIL is returned. .PP .I krb_mk_priv creates an encrypted, authenticated message from any arbitrary application data, pointed to by .I in and .I in_length bytes long. The private session key, pointed to by .I key and the key schedule, .I schedule, are used to encrypt the data and some header information using .I pcbc_encrypt. .I sender and .I receiver point to the Internet address of the two parties. In addition to providing privacy, this protocol message protects against modifications, insertions or replays. The encapsulated message and header are placed in the area pointed to by .I out and the routine returns the length of the output, or -1 indicating an error. .PP .I krb_rd_priv decrypts and authenticates a received .I krb_mk_priv message. .I in points to the beginning of the received message, whose length is specified in .I in_length. The private session key, pointed to by .I key, and the key schedule, .I schedule, are used to decrypt and verify the received message. .I msg_data is a pointer to a .I MSG_DAT struct, defined in .I krb.h. The routine fills in the .I app_data field with a pointer to the decrypted application data, .I app_length with the length of the .I app_data field, .I time_sec and .I time_5ms with the timestamps in the message, and .I swap with a 1 if the byte order of the receiver is different than that of the sender. (The application must still determine if it is appropriate to byte-swap application data; the Kerberos protocol fields are already taken care of). The .I hash field returns a value useful as input to the .I krb_ck_repl routine. The routine returns zero if ok, or a Kerberos error code. Modified messages and old messages cause errors, but it is up to the caller to check the time sequence of messages, and to check against recently replayed messages using .I krb_ck_repl if so desired. .PP .I krb_mk_safe creates an authenticated, but unencrypted message from any arbitrary application data, pointed to by .I in and .I in_length bytes long. The private session key, pointed to by .I key, is used to seed the .I quad_cksum() checksum algorithm used as part of the authentication. .I sender and .I receiver point to the Internet address of the two parties. This message does not provide privacy, but does protect (via detection) against modifications, insertions or replays. The encapsulated message and header are placed in the area pointed to by .I out and the routine returns the length of the output, or -1 indicating an error. The authentication provided by this routine is not as strong as that provided by .I krb_mk_priv or by computing the checksum using .I cbc_cksum instead, both of which authenticate via DES. .PP .I krb_rd_safe authenticates a received .I krb_mk_safe message. .I in points to the beginning of the received message, whose length is specified in .I in_length. The private session key, pointed to by .I key, is used to seed the quad_cksum() routine as part of the authentication. .I msg_data is a pointer to a .I MSG_DAT struct, defined in .I krb.h . The routine fills in these .I MSG_DAT fields: the .I app_data field with a pointer to the application data, .I app_length with the length of the .I app_data field, .I time_sec and .I time_5ms with the timestamps in the message, and .I swap with a 1 if the byte order of the receiver is different than that of the sender. (The application must still determine if it is appropriate to byte-swap application data; the Kerberos protocol fields are already taken care of). The .I hash field returns a value useful as input to the .I krb_ck_repl routine. The routine returns zero if ok, or a Kerberos error code. Modified messages and old messages cause errors, but it is up to the caller to check the time sequence of messages, and to check against recently replayed messages using .I krb_ck_repl if so desired. .PP .I krb_mk_err constructs an application level error message that may be used along with .I krb_mk_priv or .I krb_mk_safe. .I out is a pointer to the output buffer, .I code is an application specific error code, and .I string is an application specific error string. .PP .I krb_rd_err unpacks a received .I krb_mk_err message. .I in points to the beginning of the received message, whose length is specified in .I in_length. .I code is a pointer to a value to be filled in with the error value provided by the application. .I msg_data is a pointer to a .I MSG_DAT struct, defined in .I krb.h . The routine fills in these .I MSG_DAT fields: the .I app_data field with a pointer to the application error text, .I app_length with the length of the .I app_data field, and .I swap with a 1 if the byte order of the receiver is different than that of the sender. (The application must still determine if it is appropriate to byte-swap application data; the Kerberos protocol fields are already taken care of). The routine returns zero if the error message has been successfully received, or a Kerberos error code. .PP +.I krb_get_local_addr +retrieves the address of the local interface used for +all kerberos transactions and copies it to the sockaddr_in pointed to +by +.I address. +This information is usually used to bind additional sockets in client +programs to the kerberos authenticated local address so transactions +to kerberos services on remote machines succeed. This routine may be called +at any time and the address returned will not change during the lifetime of +the program. + +The routine returns zero on success or a Kerberos error code. +.PP +.I krb_bind_local_addr +binds +.I socket +to the address of the local interface used for all kerberos +transactions. The bind allows the system to assign a port for the socket, +so programs wishing to specify an explicit port should use +.I krb_get_local_addr +and perform the bind manually. + +The routine returns zero on success or a Kerberos error code. +.PP The .I KTEXT structure is used to pass around text of varying lengths. It consists of a buffer for the data, and a length. krb_rd_req takes an argument of this type containing the authenticator, and krb_mk_req returns the authenticator in a structure of this type. KTEXT itself is really a pointer to the structure. The actual structure is of type KTEXT_ST. .PP The .I AUTH_DAT structure is filled in by krb_rd_req. It must be allocated before calling krb_rd_req, and a pointer to it is passed. The structure is filled in with data obtained from Kerberos. .I MSG_DAT structure is filled in by either krb_rd_priv, krb_rd_safe, or krb_rd_err. It must be allocated before the call and a pointer to it is passed. The structure is filled in with data obtained from Kerberos. .PP .SH FILES /usr/include/kerberosIV/krb.h .br /usr/lib/libkrb.a .br /usr/include/des.h .br /usr/lib/libdes.a .br /etc/kerberosIV/aname .br /etc/kerberosIV/srvtab .br /tmp/tkt[uid] .SH "SEE ALSO" kerberos(1), des_crypt(3) .SH DIAGNOSTICS .SH BUGS The caller of .I krb_rd_req, krb_rd_priv, and krb_rd_safe must check time order and for replay attempts. .I krb_ck_repl is not implemented yet. .SH AUTHORS Clifford Neuman, MIT Project Athena .br Steve Miller, MIT Project Athena/Digital Equipment Corporation .SH RESTRICTIONS COPYRIGHT 1985,1986,1989 Massachusetts Institute of Technology diff --git a/eBones/lib/libkrb/krb_err.et b/eBones/lib/libkrb/krb_err.et index 7d2baef47345..6200280b1200 100644 --- a/eBones/lib/libkrb/krb_err.et +++ b/eBones/lib/libkrb/krb_err.et @@ -1,257 +1,269 @@ # Copyright 1987,1988 Massachusetts Institute of Technology # For copying and distribution information, see the file # "Copyright.MIT". # # from: krb_err.et,v 4.1 89/09/26 09:24:20 jtkohl Exp $ -# $Id: krb_err.et,v 1.3 1995/07/18 16:39:00 mark Exp $ +# $Id: krb_err.et,v 1.3 1995/09/07 21:38:09 markm Exp $ # error_table krb ec KRBET_KSUCCESS, "Kerberos successful" ec KRBET_KDC_NAME_EXP, "Kerberos principal expired" ec KRBET_KDC_SERVICE_EXP, "Kerberos service expired" ec KRBET_KDC_AUTH_EXP, "Kerberos auth expired" ec KRBET_KDC_PKT_VER, "Incorrect kerberos master key version" ec KRBET_KDC_P_MKEY_VER, "Incorrect kerberos master key version" ec KRBET_KDC_S_MKEY_VER, "Incorrect kerberos master key version" ec KRBET_KDC_BYTE_ORDER, "Kerberos error: byte order unknown" ec KRBET_KDC_PR_UNKNOWN, "Kerberos principal unknown" ec KRBET_KDC_PR_N_UNIQUE, "Kerberos principal not unique" ec KRBET_KDC_NULL_KEY, "Kerberos principal has null key" ec KRBET_KRB_RES11, "Reserved 11" ec KRBET_KRB_RES12, "Reserved 12" ec KRBET_KRB_RES13, "Reserved 13" ec KRBET_KRB_RES14, "Reserved 14" ec KRBET_KRB_RES15, "Reserved 15" ec KRBET_KRB_RES16, "Reserved 16" ec KRBET_KRB_RES17, "Reserved 17" ec KRBET_KRB_RES18, "Reserved 18" ec KRBET_KRB_RES19, "Reserved 19" ec KRBET_KDC_GEN_ERR, "Generic error from Kerberos KDC" ec KRBET_GC_TKFIL, "Can't read Kerberos ticket file" ec KRBET_GC_NOTKT, "Can't find Kerberos ticket or TGT" ec KRBET_KRB_RES23, "Reserved 23" ec KRBET_KRB_RES24, "Reserved 24" ec KRBET_KRB_RES25, "Reserved 25" ec KRBET_MK_AP_TGTEXP, "Kerberos TGT Expired" ec KRBET_KRB_RES27, "Reserved 27" ec KRBET_KRB_RES28, "Reserved 28" ec KRBET_KRB_RES29, "Reserved 29" ec KRBET_KRB_RES30, "Reserved 30" ec KRBET_RD_AP_UNDEC, "Kerberos error: Can't decode authenticator" ec KRBET_RD_AP_EXP, "Kerberos ticket expired" ec KRBET_RD_AP_NYV, "Kerberos ticket not yet valid" ec KRBET_RD_AP_REPEAT, "Kerberos error: Repeated request" ec KRBET_RD_AP_NOT_US, "The kerberos ticket isn't for us" ec KRBET_RD_AP_INCON, "Kerberos request inconsistent" ec KRBET_RD_AP_TIME, "Kerberos error: delta_t too big" ec KRBET_RD_AP_BADD, "Kerberos error: incorrect net address" ec KRBET_RD_AP_VERSION, "Kerberos protocol version mismatch" ec KRBET_RD_AP_MSG_TYPE, "Kerberos error: invalid msg type" ec KRBET_RD_AP_MODIFIED, "Kerberos error: message stream modified" ec KRBET_RD_AP_ORDER, "Kerberos error: message out of order" ec KRBET_RD_AP_UNAUTHOR, "Kerberos error: unauthorized request" ec KRBET_KRB_RES44, "Reserved 44" ec KRBET_KRB_RES45, "Reserved 45" ec KRBET_KRB_RES46, "Reserved 46" ec KRBET_KRB_RES47, "Reserved 47" ec KRBET_KRB_RES48, "Reserved 48" ec KRBET_KRB_RES49, "Reserved 49" ec KRBET_KRB_RES50, "Reserved 50" ec KRBET_GT_PW_NULL, "Kerberos error: current PW is null" ec KRBET_GT_PW_BADPW, "Kerberos error: Incorrect current password" ec KRBET_GT_PW_PROT, "Kerberos protocol error" ec KRBET_GT_PW_KDCERR, "Error returned by Kerberos KDC" ec KRBET_GT_PW_NULLTKT, "Null Kerberos ticket returned by KDC" ec KRBET_SKDC_RETRY, "Kerberos error: Retry count exceeded" ec KRBET_SKDC_CANT, "Kerberos error: Can't send request" ec KRBET_KRB_RES58, "Reserved 58" ec KRBET_KRB_RES59, "Reserved 59" ec KRBET_KRB_RES60, "Reserved 60" ec KRBET_INTK_W_NOTALL, "Kerberos error: not all tickets returned" ec KRBET_INTK_BADPW, "Kerberos error: incorrect password" ec KRBET_INTK_PROT, "Kerberos error: Protocol Error" ec KRBET_KRB_RES64, "Reserved 64" ec KRBET_KRB_RES65, "Reserved 65" ec KRBET_KRB_RES66, "Reserved 66" ec KRBET_KRB_RES67, "Reserved 67" ec KRBET_KRB_RES68, "Reserved 68" ec KRBET_KRB_RES69, "Reserved 69" ec KRBET_INTK_ERR, "Other error" ec KRBET_AD_NOTGT, "Don't have Kerberos ticket-granting ticket" ec KRBET_KRB_RES72, "Reserved 72" ec KRBET_KRB_RES73, "Reserved 73" ec KRBET_KRB_RES74, "Reserved 74" ec KRBET_KRB_RES75, "Reserved 75" ec KRBET_NO_TKT_FIL, "No ticket file found" ec KRBET_TKT_FIL_ACC, "Couldn't access ticket file" ec KRBET_TKT_FIL_LCK, "Couldn't lock ticket file" ec KRBET_TKT_FIL_FMT, "Bad ticket file format" ec KRBET_TKT_FIL_INI, "tf_init not called first" ec KRBET_KNAME_FMT, "Bad Kerberos name format" + ec KRBET_GT_LADDR_NOSOCK, + "Can't open socket" + + ec KRBET_GT_LADDR_IFLIST, + "Can't retrieve local interface list" + + ec KRBET_GT_LADDR_NVI, + "No valid local interface found" + + ec KRBET_BND_LADDR_BIND, + "Can't bind local address" + end diff --git a/eBones/lib/libkrb/krb_err_txt.c b/eBones/lib/libkrb/krb_err_txt.c index 2c8c0cacbe20..040727b99e5f 100644 --- a/eBones/lib/libkrb/krb_err_txt.c +++ b/eBones/lib/libkrb/krb_err_txt.c @@ -1,280 +1,280 @@ /* * Copyright 1988 by the Massachusetts Institute of Technology. * For copying and distribution information, please see the file * . * * from: krb_err_txt.c,v 4.7 88/12/01 14:10:14 jtkohl Exp $ - * $Id: krb_err_txt.c,v 1.3 1995/07/18 16:39:02 mark Exp $ + * $Id: krb_err_txt.c,v 1.3 1995/09/07 21:38:10 markm Exp $ */ #if 0 #ifndef lint static char rcsid[] = -"$Id: krb_err_txt.c,v 1.3 1995/07/18 16:39:02 mark Exp $"; +"$Id: krb_err_txt.c,v 1.3 1995/09/07 21:38:10 markm Exp $"; #endif lint #endif /* * This file contains an array of error text strings. * The associated error codes (which are defined in "krb.h") * follow the string in the comments at the end of each line. */ char *krb_err_txt[256] = { "OK", /* 000 */ "Principal expired (kerberos)", /* 001 */ "Service expired (kerberos)", /* 002 */ "Authentication expired (kerberos)", /* 003 */ "Unknown protocol version number (kerberos)", /* 004 */ "Principal: Incorrect master key version (kerberos)", /* 005 */ "Service: Incorrect master key version (kerberos)", /* 006 */ "Bad byte order (kerberos)", /* 007 */ "Principal unknown (kerberos)", /* 008 */ "Principal not unique (kerberos)", /* 009 */ "Principal has null key (kerberos)", /* 010 */ "Reserved error message 11 (kerberos)", /* 011 */ "Reserved error message 12 (kerberos)", /* 012 */ "Reserved error message 13 (kerberos)", /* 013 */ "Reserved error message 14 (kerberos)", /* 014 */ "Reserved error message 15 (kerberos)", /* 015 */ "Reserved error message 16 (kerberos)", /* 016 */ "Reserved error message 17 (kerberos)", /* 017 */ "Reserved error message 18 (kerberos)", /* 018 */ "Reserved error message 19 (kerberos)", /* 019 */ "Permission Denied (kerberos)", /* 020 */ "Can't read ticket file (krb_get_cred)", /* 021 */ "Can't find ticket (krb_get_cred)", /* 022 */ "Reserved error message 23 (krb_get_cred)", /* 023 */ "Reserved error message 24 (krb_get_cred)", /* 024 */ "Reserved error message 25 (krb_get_cred)", /* 025 */ "Ticket granting ticket expired (krb_mk_req)", /* 026 */ "Reserved error message 27 (krb_mk_req)", /* 027 */ "Reserved error message 28 (krb_mk_req)", /* 028 */ "Reserved error message 29 (krb_mk_req)", /* 029 */ "Reserved error message 30 (krb_mk_req)", /* 030 */ "Can't decode authenticator (krb_rd_req)", /* 031 */ "Ticket expired (krb_rd_req)", /* 032 */ "Ticket issue date too far in the future (krb_rd_req)",/* 033 */ "Repeat request (krb_rd_req)", /* 034 */ "Ticket for wrong server (krb_rd_req)", /* 035 */ "Request inconsistent (krb_rd_req)", /* 036 */ "Time is out of bounds (krb_rd_req)", /* 037 */ "Incorrect network address (krb_rd_req)", /* 038 */ "Protocol version mismatch (krb_rd_req)", /* 039 */ "Illegal message type (krb_rd_req)", /* 040 */ "Message integrity error (krb_rd_req)", /* 041 */ "Message duplicate or out of order (krb_rd_req)", /* 042 */ "Unauthorized request (krb_rd_req)", /* 043 */ "Reserved error message 44 (krb_rd_req)", /* 044 */ "Reserved error message 45 (krb_rd_req)", /* 045 */ "Reserved error message 46 (krb_rd_req)", /* 046 */ "Reserved error message 47 (krb_rd_req)", /* 047 */ "Reserved error message 48 (krb_rd_req)", /* 048 */ "Reserved error message 49 (krb_rd_req)", /* 049 */ "Reserved error message 50 (krb_rd_req)", /* 050 */ "Current password is NULL (get_pw_tkt)", /* 051 */ "Current password incorrect (get_pw_tkt)", /* 052 */ "Protocol error (gt_pw_tkt)", /* 053 */ "Error returned by KDC (gt_pw_tkt)", /* 054 */ "Null ticket returned by KDC (gt_pw_tkt)", /* 055 */ "Retry count exceeded (send_to_kdc)", /* 056 */ "Can't send request (send_to_kdc)", /* 057 */ "Reserved error message 58 (send_to_kdc)", /* 058 */ "Reserved error message 59 (send_to_kdc)", /* 059 */ "Reserved error message 60 (send_to_kdc)", /* 060 */ "Warning: Not ALL tickets returned", /* 061 */ "Password incorrect", /* 062 */ "Protocol error (get_intkt)", /* 063 */ "Reserved error message 64 (get_in_tkt)", /* 064 */ "Reserved error message 65 (get_in_tkt)", /* 065 */ "Reserved error message 66 (get_in_tkt)", /* 066 */ "Reserved error message 67 (get_in_tkt)", /* 067 */ "Reserved error message 68 (get_in_tkt)", /* 068 */ "Reserved error message 69 (get_in_tkt)", /* 069 */ "Generic error (get_intkt)", /* 070 */ "Don't have ticket granting ticket (get_ad_tkt)", /* 071 */ "Reserved error message 72 (get_ad_tkt)", /* 072 */ "Reserved error message 73 (get_ad_tkt)", /* 073 */ "Reserved error message 74 (get_ad_tkt)", /* 074 */ "Reserved error message 75 (get_ad_tkt)", /* 075 */ "No ticket file (tf_util)", /* 076 */ "Can't access ticket file (tf_util)", /* 077 */ "Can't lock ticket file; try later (tf_util)", /* 078 */ "Bad ticket file format (tf_util)", /* 079 */ "Read ticket file before tf_init (tf_util)", /* 080 */ "Bad Kerberos name format (kname_parse)", /* 081 */ - "(reserved)", - "(reserved)", - "(reserved)", - "(reserved)", + "Can't open socket", /* 082 */ + "Can't retrieve local interface list", /* 083 */ + "No valid local interface found", /* 084 */ + "Can't bind local address", /* 085 */ "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "(reserved)", "Generic kerberos error (kfailure)", /* 255 */ }; diff --git a/eBones/lib/libkrb/krb_sendauth.3 b/eBones/lib/libkrb/krb_sendauth.3 index 5608255009d9..8f250a592557 100644 --- a/eBones/lib/libkrb/krb_sendauth.3 +++ b/eBones/lib/libkrb/krb_sendauth.3 @@ -1,348 +1,356 @@ .\" from: krb_sendauth.3,v 4.1 89/01/23 11:10:58 jtkohl Exp $ -.\" $Id: krb_sendauth.3,v 1.3 1995/07/18 16:41:03 mark Exp $ +.\" $Id: krb_sendauth.3,v 1.3 1995/09/13 17:23:57 markm Exp $ .\" Copyright 1988 by the Massachusetts Institute of Technology. .\" .\" For copying and distribution information, .\" please see the file . .\" .TH KRB_SENDAUTH 3 "Kerberos Version 4.0" "MIT Project Athena" .SH NAME krb_sendauth, krb_recvauth, krb_net_write, krb_net_read \- Kerberos routines for sending authentication via network stream sockets .SH SYNOPSIS .nf .nj .ft B #include #include #include .PP .fi .HP 1i .ft B int krb_sendauth(options, fd, ktext, service, inst, realm, checksum, msg_data, cred, schedule, laddr, faddr, version) .nf .RS 0 .ft B long options; int fd; KTEXT ktext; char *service, *inst, *realm; u_long checksum; MSG_DAT *msg_data; CREDENTIALS *cred; Key_schedule schedule; struct sockaddr_in *laddr, *faddr; char *version; .PP .fi .HP 1i .ft B int krb_recvauth(options, fd, ktext, service, inst, faddr, laddr, auth_data, filename, schedule, version) .nf .RS 0 .ft B long options; int fd; KTEXT ktext; char *service, *inst; struct sockaddr_in *faddr, *laddr; AUTH_DAT *auth_data; char *filename; Key_schedule schedule; char *version; .PP .ft B int krb_net_write(fd, buf, len) int fd; char *buf; int len; .PP .ft B int krb_net_read(fd, buf, len) int fd; char *buf; int len; .fi .SH DESCRIPTION .PP These functions, which are built on top of the core Kerberos library, provide a convenient means for client and server programs to send authentication messages to one another through network connections. The .I krb_sendauth function sends an authenticated ticket from the client program to the server program by writing the ticket to a network socket. The .I krb_recvauth function receives the ticket from the client by reading from a network socket. +To ensure proper behavior on multi-homed systems (machines with more +than one network interface) all sockets used with these routines should +be bound to the same address as that used by the Kerberos library via +.I krb_get_local_addr +or +.I krb_bind_local_addr. + .SH KRB_SENDAUTH .PP This function writes the ticket to the network socket specified by the file descriptor .IR fd, returning KSUCCESS if the write proceeds successfully, and an error code if it does not. The .I ktext argument should point to an allocated KTEXT_ST structure. The .IR service, .IR inst, and .IR realm arguments specify the server program's Kerberos principal name, instance, and realm. If you are writing a client that uses the local realm exclusively, you can set the .I realm argument to NULL. The .I version argument allows the client program to pass an application-specific version string that the server program can then match against its own version string. The .I version string can be up to KSEND_VNO_LEN (see .IR ) characters in length. The .I checksum argument can be used to pass checksum information to the server program. The client program is responsible for specifying this information. This checksum information is difficult to corrupt because .I krb_sendauth passes it over the network in encrypted form. The .I checksum argument is passed as the checksum argument to .IR krb_mk_req . You can set .IR krb_sendauth's other arguments to NULL unless you want the client and server programs to mutually authenticate themselves. In the case of mutual authentication, the client authenticates itself to the server program, and demands that the server in turn authenticate itself to the client. .SH KRB_SENDAUTH AND MUTUAL AUTHENTICATION .PP If you want mutual authentication, make sure that you read all pending data from the local socket before calling .IR krb_sendauth. Set .IR krb_sendauth's .I options argument to .BR KOPT_DO_MUTUAL (this macro is defined in the .IR krb.h file); make sure that the .I laddr argument points to the address of the local socket, and that .I faddr points to the foreign socket's network address. .I Krb_sendauth fills in the other arguments-- .IR msg_data , .IR cred , and .IR schedule --before sending the ticket to the server program. You must, however, allocate space for these arguments before calling the function. .I Krb_sendauth supports two other options: .BR KOPT_DONT_MK_REQ, and .BR KOPT_DONT_CANON. If called with .I options set as KOPT_DONT_MK_REQ, .I krb_sendauth will not use the .I krb_mk_req function to retrieve the ticket from the Kerberos server. The .I ktext argument must point to an existing ticket and authenticator (such as would be created by .IR krb_mk_req ), and the .IR service, .IR inst, and .IR realm arguments can be set to NULL. If called with .I options set as KOPT_DONT_CANON, .I krb_sendauth will not convert the service's instance to canonical form using .IR krb_get_phost (3). If you want to call .I krb_sendauth with a multiple .I options specification, construct .I options as a bitwise-OR of the options you want to specify. .SH KRB_RECVAUTH .PP The .I krb_recvauth function reads a ticket/authenticator pair from the socket pointed to by the .I fd argument. Set the .I options argument as a bitwise-OR of the options desired. Currently only KOPT_DO_MUTUAL is useful to the receiver. The .I ktext argument should point to an allocated KTEXT_ST structure. .I Krb_recvauth fills .I ktext with the ticket/authenticator pair read from .IR fd , then passes it to .IR krb_rd_req . The .I service and .I inst arguments specify the expected service and instance for which the ticket was generated. They are also passed to .IR krb_rd_req. The .I inst argument may be set to "*" if the caller wishes .I krb_mk_req to fill in the instance used (note that there must be space in the .I inst argument to hold a full instance name, see .IR krb_mk_req (3)). The .I faddr argument should point to the address of the peer which is presenting the ticket. It is also passed to .IR krb_rd_req . If the client and server plan to mutually authenticate one another, the .I laddr argument should point to the local address of the file descriptor. Otherwise you can set this argument to NULL. The .I auth_data argument should point to an allocated AUTH_DAT area. It is passed to and filled in by .IR krb_rd_req . The checksum passed to the corresponding .I krb_sendauth is available as part of the filled-in AUTH_DAT area. The .I filename argument specifies the filename which the service program should use to obtain its service key. .I Krb_recvauth passes .I filename to the .I krb_rd_req function. If you set this argument to "", .I krb_rd_req looks for the service key in the file .IR /etc/kerberosIV/srvtab. If the client and server are performing mutual authenication, the .I schedule argument should point to an allocated Key_schedule. Otherwise it is ignored and may be NULL. The .I version argument should point to a character array of at least KSEND_VNO_LEN characters. It is filled in with the version string passed by the client to .IR krb_sendauth. .PP .SH KRB_NET_WRITE AND KRB_NET_READ .PP The .I krb_net_write function emulates the write(2) system call, but guarantees that all data specified is written to .I fd before returning, unless an error condition occurs. .PP The .I krb_net_read function emulates the read(2) system call, but guarantees that the requested amount of data is read from .I fd before returning, unless an error condition occurs. .PP .SH BUGS .IR krb_sendauth, .IR krb_recvauth, .IR krb_net_write, and .IR krb_net_read will not work properly on sockets set to non-blocking I/O mode. .SH SEE ALSO -krb_mk_req(3), krb_rd_req(3), krb_get_phost(3) +krb_mk_req(3), krb_rd_req(3), krb_get_phost(3), krb_get_local_addr(3), +krb_bind_local_addr(3) .SH AUTHOR John T. Kohl, MIT Project Athena .SH RESTRICTIONS Copyright 1988, Massachusetts Instititute of Technology. For copying and distribution information, please see the file . diff --git a/eBones/lib/libkrb/send_to_kdc.c b/eBones/lib/libkrb/send_to_kdc.c index 521ba9a19cfd..c9f4355547dc 100644 --- a/eBones/lib/libkrb/send_to_kdc.c +++ b/eBones/lib/libkrb/send_to_kdc.c @@ -1,391 +1,529 @@ /* * Copyright 1987, 1988 by the Massachusetts Institute of Technology. * For copying and distribution information, please see the file * . * * from: send_to_kdc.c,v 4.20 90/01/02 13:40:37 jtkohl Exp $ - * $Id: send_to_kdc.c,v 1.8 1995/09/14 20:58:35 gibbs Exp $ + * $Id: send_to_kdc.c,v 1.9 1995/09/16 23:11:25 gibbs Exp $ */ #if 0 #ifndef lint static char rcsid_send_to_kdc_c[] = "$Id: send_to_kdc.c,v 1.1 1994/03/21 17:35:39 piero Exp "; #endif /* lint */ #endif #include #include #include #include #include #include #include +#include #include #ifdef lint #include /* struct iovec to make lint happy */ #endif /* lint */ +#include #include +#include +#include #include #include #include #include #define S_AD_SZ sizeof(struct sockaddr_in) +/* Used for extracting addresses from routing messages */ +#define ROUNDUP(a) \ + ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) +#define ADVANCE(x, n) (x += ROUNDUP((n)->sin_len)) + extern int errno; extern int krb_debug; extern char *malloc(), *calloc(), *realloc(); int krb_udp_port = 0; +static struct sockaddr_in local_addr = { S_AD_SZ, + AF_INET + }; + /* CLIENT_KRB_TIMEOUT indicates the time to wait before * retrying a server. It's defined in "krb.h". */ static struct timeval timeout = { CLIENT_KRB_TIMEOUT, 0}; static char *prog = "send_to_kdc"; static send_recv(); /* * This file contains two routines, send_to_kdc() and send_recv(). * send_recv() is a static routine used by send_to_kdc(). */ /* * send_to_kdc() sends a message to the Kerberos authentication * server(s) in the given realm and returns the reply message. * The "pkt" argument points to the message to be sent to Kerberos; * the "rpkt" argument will be filled in with Kerberos' reply. * The "realm" argument indicates the realm of the Kerberos server(s) * to transact with. If the realm is null, the local realm is used. * * If more than one Kerberos server is known for a given realm, * different servers will be queried until one of them replies. * Several attempts (retries) are made for each server before * giving up entirely. * * If an answer was received from a Kerberos host, KSUCCESS is * returned. The following errors can be returned: * * SKDC_CANT - can't get local realm * - can't find "kerberos" in /etc/services database * - can't open socket * - can't bind socket * - all ports in use * - couldn't find any Kerberos host * * SKDC_RETRY - couldn't get an answer from any Kerberos server, * after several retries */ int send_to_kdc(pkt,rpkt,realm) KTEXT pkt; KTEXT rpkt; char *realm; { int i, f; int no_host; /* was a kerberos host found? */ int retry; int n_hosts; int retval; int addr_count; struct sockaddr_in to; struct hostent *host, *hostlist; char krbhst[MAX_HSTNM]; char lrealm[REALM_SZ]; /* * If "realm" is non-null, use that, otherwise get the * local realm. */ if (realm) (void) strcpy(lrealm, realm); else if (krb_get_lrealm(lrealm,1)) { if (krb_debug) fprintf(stderr, "%s: can't get local realm\n", prog); return(SKDC_CANT); } if (krb_debug) printf("lrealm is %s\n", lrealm); if (krb_udp_port == 0) { register struct servent *sp; if ((sp = getservbyname("kerberos","udp")) == 0) { if (krb_debug) fprintf(stderr, "%s: Can't get kerberos/udp service\n", prog); return(SKDC_CANT); } krb_udp_port = sp->s_port; if (krb_debug) printf("krb_udp_port is %d\n", krb_udp_port); } bzero((char *)&to, S_AD_SZ); hostlist = (struct hostent *) malloc(sizeof(struct hostent)); if (!hostlist) return (/*errno */SKDC_CANT); if ((f = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { if (krb_debug) fprintf(stderr,"%s: Can't open socket\n", prog); return(SKDC_CANT); } /* from now on, exit through rtn label for cleanup */ no_host = 1; /* get an initial allocation */ n_hosts = 0; for (i = 1; krb_get_krbhst(krbhst, lrealm, i) == KSUCCESS; ++i) { if (krb_debug) { printf("Getting host entry for %s...",krbhst); (void) fflush(stdout); } host = gethostbyname(krbhst); if (krb_debug) { printf("%s.\n", host ? "Got it" : "Didn't get it"); (void) fflush(stdout); } if (!host) continue; no_host = 0; /* found at least one */ n_hosts++; /* * Preserve host network addresses to check against later */ hostlist = (struct hostent *) realloc((char *)hostlist, (unsigned) sizeof(struct hostent)*(n_hosts+1)); if (!hostlist) { fprintf(stderr, "Could not grow hostlist\n"); return /*errno */SKDC_CANT; } bcopy((char *)host, (char *)&hostlist[n_hosts-1], sizeof(struct hostent)); host = &hostlist[n_hosts-1]; /* At least Sun OS version 3.2 (or worse) and Ultrix version 2.2 (or worse) only return one address ... */ #if (defined(ULTRIX022) || (defined(SunOS) && SunOS < 40)) { char *cp = malloc((unsigned)host->h_length); if (!cp) { retval = /*errno */SKDC_CANT; goto rtn; } bcopy((char *)host->h_addr, cp, host->h_length); host->h_addr = cp; } #else /* !(ULTRIX022 || (SunOS < 40)) */ /* * Make a copy of the entire h_addr_list. */ { char *addr; char **old_addr_list; addr_count = 0; old_addr_list = host->h_addr_list; while(old_addr_list[addr_count++]) ; host->h_addr_list = (char **)malloc(addr_count+1 * sizeof(char *)); if (host->h_addr_list == NULL) { fprintf(stderr, "Could not allocate host->h_addr_list\n"); retval = SKDC_CANT; goto rtn; } if (krb_debug) { printf("h_length = %d\n", host->h_length); printf("Number of addresses = %d\n", addr_count); } for (addr_count = 0; old_addr_list[addr_count]; addr_count++) { if (krb_debug) printf ("addr[%d] = %s\n", addr_count, inet_ntoa(*(struct in_addr *)old_addr_list[addr_count])); addr = (char *)malloc(host->h_length); if (addr == NULL) { fprintf(stderr, "Could not allocate address\n"); retval = SKDC_CANT; goto rtn; } bcopy(old_addr_list[addr_count], addr, host->h_length); host->h_addr_list[addr_count] = addr; } host->h_addr_list[addr_count] = NULL; } #endif /* !(ULTRIX022 || (SunOS < 40)) */ bzero((char *)&hostlist[n_hosts], sizeof(struct hostent)); to.sin_family = host->h_addrtype; bcopy(host->h_addr, (char *)&to.sin_addr, host->h_length); to.sin_port = krb_udp_port; + if ((retval = krb_bind_local_addr(f)) != KSUCCESS) { + fprintf(stderr, "krb_bind_local_addr: %s", krb_err_txt[retval]); + retval = SKDC_CANT; + goto rtn; + } if (send_recv(pkt, rpkt, f, &to, hostlist)) { retval = KSUCCESS; goto rtn; } if (krb_debug) { printf("Timeout, error, or wrong descriptor\n"); (void) fflush(stdout); } } if (no_host) { if (krb_debug) fprintf(stderr, "%s: can't find any Kerberos host.\n", prog); retval = SKDC_CANT; goto rtn; } /* * retry each host in sequence. Some addresses may be unreachable * from where we are, so loop through them as well. */ for (retry = 0; retry < CLIENT_KRB_RETRY; ++retry) { for (host = hostlist; host->h_name != (char *)NULL; host++) { #if (defined(ULTRIX022) || (defined(SunOS) && SunOS < 40)) to.sin_family = host->h_addrtype; bcopy(host->h_addr_list[addr_count], (char *)&to.sin_addr, host->h_length); if (send_recv(pkt, rpkt, f, &to, hostlist)) { retval = KSUCCESS; goto rtn; } #else /* !(ULTRIX022 || (SunOS < 40)) */ for (addr_count = 0; host->h_addr_list[addr_count]; addr_count++) { to.sin_family = host->h_addrtype; bcopy(host->h_addr_list[addr_count], (char *)&to.sin_addr, host->h_length); if (send_recv(pkt, rpkt, f, &to, hostlist)) { retval = KSUCCESS; goto rtn; } } #endif /* !(ULTRIX022 || (SunOS < 40)) */ } } retval = SKDC_RETRY; rtn: (void) close(f); if (hostlist) { if(!no_host) { register struct hostent *hp; for (hp = hostlist; hp->h_name; hp++) #if !(defined(ULTRIX022) || (defined(SunOS) && SunOS < 40)) if (hp->h_addr_list) { #endif /* ULTRIX022 || SunOS */ if (hp->h_addr) free(hp->h_addr); #if !(defined(ULTRIX022) || (defined(SunOS) && SunOS < 40)) free((char *)hp->h_addr_list); } #endif /* ULTRIX022 || SunOS */ } free((char *)hostlist); } return(retval); } /* * try to send out and receive message. * return 1 on success, 0 on failure */ static int send_recv(pkt,rpkt,f,_to,addrs) KTEXT pkt; KTEXT rpkt; int f; struct sockaddr_in *_to; struct hostent *addrs; { fd_set readfds; register struct hostent *hp; struct sockaddr_in from; int sin_size; int numsent; int addr_count; if (krb_debug) { if (_to->sin_family == AF_INET) printf("Sending message to %s...", inet_ntoa(_to->sin_addr)); else printf("Sending message..."); (void) fflush(stdout); } if ((numsent = sendto(f,(char *)(pkt->dat), pkt->length, 0, (struct sockaddr *)_to, S_AD_SZ)) != pkt->length) { if (krb_debug) printf("sent only %d/%d\n",numsent, pkt->length); return 0; } if (krb_debug) { printf("Sent\nWaiting for reply..."); (void) fflush(stdout); } FD_ZERO(&readfds); FD_SET(f, &readfds); errno = 0; /* select - either recv is ready, or timeout */ /* see if timeout or error or wrong descriptor */ if (select(f + 1, &readfds, (fd_set *)0, (fd_set *)0, &timeout) < 1 || !FD_ISSET(f, &readfds)) { if (krb_debug) { fprintf(stderr, "select failed: readfds=%x", readfds); perror(""); } return 0; } sin_size = sizeof(from); if (recvfrom(f, (char *)(rpkt->dat), sizeof(rpkt->dat), 0, (struct sockaddr *)&from, &sin_size) < 0) { if (krb_debug) perror("recvfrom"); return 0; } if (krb_debug) { printf("received packet from %s\n", inet_ntoa(from.sin_addr)); fflush(stdout); } /* At least Sun OS version 3.2 (or worse) and Ultrix version 2.2 (or worse) only return one address ... */ #if (defined(ULTRIX022) || (defined(SunOS) && SunOS < 40)) for (hp = addrs; hp->h_name != (char *)NULL; hp++) { if (!bcmp(hp->h_addr, (char *)&from.sin_addr.s_addr, hp->h_length)) { if (krb_debug) { printf("Received it\n"); (void) fflush(stdout); } return 1; } if (krb_debug) fprintf(stderr, "packet not from %s\n", inet_ntoa(*(struct in_addr *)hp->h_addr)); } #else /* !(ULTRIX022 || (SunOS < 40)) */ for (hp = addrs; hp->h_name != (char *)NULL; hp++) { for (addr_count = 0; hp->h_addr_list[addr_count]; addr_count++) { if (!bcmp(hp->h_addr_list[addr_count], (char *)&from.sin_addr.s_addr, hp->h_length)) { if (krb_debug) { printf("Received it\n"); (void) fflush(stdout); } return 1; } if (krb_debug) fprintf(stderr, "packet not from %s\n", inet_ntoa(*(struct in_addr *)hp->h_addr_list[addr_count])); } } #endif /* !(ULTRIX022 || (SunOS < 40)) */ if (krb_debug) fprintf(stderr, "%s: received packet from wrong host! (%s)\n", "send_to_kdc(send_rcv)", inet_ntoa(from.sin_addr)); return 0; } + + +static int +setfixedaddr(s) + int s; +{ + struct ifa_msghdr *ifa, *ifa0, *ifa_end; + struct sockaddr_in *cur_addr; + int tries; + int i; + u_long loopback; + int mib[6] = { CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, 0 }; + size_t len; + + /* Get information about our interfaces */ +#define NUMTRIES 10 + tries = 0; + +retry: + len = 0; + if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) { + perror("setfixedaddr: Can't get size of interface table: sysctl"); + return GT_LADDR_IFLIST; + } + ifa = (struct ifa_msghdr *)malloc(len); + if (!ifa) { + fprintf(stderr, "setfixedaddr: Cannot malloc\n"); + return (KFAILURE); + } + if (sysctl(mib, 6, ifa, &len, NULL, 0) < 0) { + free(ifa); + if (errno == ENOMEM && tries < NUMTRIES) { + /* Table grew between calls */ + tries++; + goto retry; + } + else { + perror("setfixedaddr: Can't get interface table: sysctl"); + return GT_LADDR_IFLIST; + } + } + loopback = inet_addr("127.0.0.1"); + + ifa0 = ifa; + for(ifa_end = (struct ifa_msghdr *)((caddr_t)ifa + len); + ifa < ifa_end; + (caddr_t)ifa += ifa->ifam_msglen) { + /* Ignore interface name messages and ensure we have an address */ + if (ifa->ifam_type == RTM_IFINFO || !(ifa->ifam_addrs & RTAX_IFA)) + continue; + cur_addr = (struct sockaddr_in *)(ifa + 1); + for (i = 0; i < RTAX_IFA; i++) { + if (ifa->ifam_addrs & (1 << i)) + ADVANCE((caddr_t)cur_addr, cur_addr); + } + if (cur_addr->sin_addr.s_addr != loopback) { + local_addr.sin_addr.s_addr = cur_addr->sin_addr.s_addr; + break; + } + } + free(ifa0); + if (ifa >= ifa_end) { + return GT_LADDR_NVI; + } + if (krb_debug) { + fprintf(stderr, "setfixedaddr: using local address %s\n", + inet_ntoa(local_addr.sin_addr)); + } + return (KSUCCESS); +} + +int +krb_bind_local_addr(s) + int s; +{ + int retval; + if (local_addr.sin_addr.s_addr == INADDR_ANY) { + /* + * We haven't determined the local interface to use + * for kerberos server interactions. Do so now. + */ + if ((retval = setfixedaddr(s)) != KSUCCESS) + return (retval); + } + if (bind(s, (struct sockaddr *)&local_addr, sizeof(local_addr)) < 0) { + perror("krb_bind_local_addr: bind"); + return BND_LADDR_BIND; + } + if (krb_debug) + printf("local_addr = %s\n", inet_ntoa(local_addr.sin_addr)); + return(KSUCCESS); +} + +int +krb_get_local_addr(returned_addr) + struct sockaddr_in *returned_addr; +{ + int retval; + if (local_addr.sin_addr.s_addr == INADDR_ANY) { + /* + * We haven't determined the local interface to use + * for kerberos server interactions. Do so now. + */ + int s; + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + return GT_LADDR_NOSOCK; + } + if ((retval = setfixedaddr(s)) != KSUCCESS) { + close(s); + return (retval); + } + close(s); + } + if (!returned_addr) + return(KFAILURE); + *returned_addr = local_addr; + if (krb_debug) + printf("local_addr = %s\n", inet_ntoa(local_addr.sin_addr)); + return (KSUCCESS); +} diff --git a/eBones/lib/librkinit/rk_rpc.c b/eBones/lib/librkinit/rk_rpc.c index dd6132779461..d9318993a822 100644 --- a/eBones/lib/librkinit/rk_rpc.c +++ b/eBones/lib/librkinit/rk_rpc.c @@ -1,387 +1,392 @@ /* - * $Id: rk_rpc.c,v 1.1 1993/12/10 19:36:09 dglo Exp gibbs $ - * $Source: /usr/src/eBones/librkinit/RCS/rk_rpc.c,v $ - * $Author: dglo $ + * $Id: rk_rpc.c,v 1.1.1.1 1995/09/15 06:09:30 gibbs Exp $ + * $Source: /home/ncvs/src/eBones/lib/librkinit/rk_rpc.c,v $ + * $Author: gibbs $ * * This file contains functions that are used for network communication. * See the comment at the top of rk_lib.c for a description of the naming * conventions used within the rkinit library. */ #if !defined(lint) && !defined(SABER) && !defined(LOCORE) && defined(RCS_HDRS) -static char *rcsid = "$Id: rk_rpc.c,v 1.1 1993/12/10 19:36:09 dglo Exp gibbs $"; +static char *rcsid = "$Id: rk_rpc.c,v 1.1.1.1 1995/09/15 06:09:30 gibbs Exp $"; #endif /* lint || SABER || LOCORE || RCS_HDRS */ #include #include #include #include #include #include #include #include #include #include #include #include #include extern int errno; static int sock; struct sockaddr_in saddr; static char errbuf[BUFSIZ]; char *calloc(); #ifdef __STDC__ int rki_send_packet(int sock, char type, u_int32_t length, const char *data) #else int rki_send_packet(sock, type, length, data) int sock; char type; u_int32_t length; const char *data; #endif /* __STDC__ */ { int len; u_char *packet; u_int32_t pkt_len; u_int32_t net_pkt_len; pkt_len = length + PKT_DATA; if ((packet = (u_char *)calloc(pkt_len, sizeof(u_char))) == NULL) { sprintf(errbuf, "rki_send_packet: failure allocating %d bytes", pkt_len * sizeof(u_char)); rkinit_errmsg(errbuf); return(RKINIT_MEMORY); } net_pkt_len = htonl(pkt_len); packet[PKT_TYPE] = type; bcopy((char *)&net_pkt_len, packet + PKT_LEN, sizeof(u_int32_t)); bcopy(data, packet + PKT_DATA, length); if ((len = write(sock, packet, pkt_len)) != pkt_len) { if (len == -1) sprintf(errbuf, "write: %s", sys_errlist[errno]); else sprintf(errbuf, "write: %d bytes written; %d bytes actually sent", pkt_len, len); rkinit_errmsg(errbuf); free(packet); return(RKINIT_WRITE); } free(packet); return(RKINIT_SUCCESS); } #ifdef __STDC__ int rki_get_packet(int sock, u_char type, u_int32_t *length, char *data) #else int rki_get_packet(sock, type, length, data) int sock; u_char type; u_int32_t *length; char *data; #endif /* __STDC__ */ { int len; int len_sofar = 0; u_int32_t expected_length = 0; int got_full_packet = FALSE; int tries = 0; u_char *packet; u_int32_t max_pkt_len; max_pkt_len = *length + PKT_DATA; if ((packet = (u_char *)calloc(max_pkt_len, sizeof(u_char))) == NULL) { sprintf(errbuf, "rki_get_packet: failure allocating %d bytes", max_pkt_len * sizeof(u_char)); rkinit_errmsg(errbuf); return(RKINIT_MEMORY); } /* Read the packet type and length */ while ((len_sofar < PKT_DATA) && (tries < RETRIES)) { if ((len = read(sock, packet + len_sofar, PKT_DATA - len_sofar)) < 0) { sprintf(errbuf, "read: %s", sys_errlist[errno]); rkinit_errmsg(errbuf); return(RKINIT_READ); } len_sofar += len; tries++; } if (len_sofar < PKT_DATA) { sprintf(errbuf, "read: expected to receive at least %d bytes; received %d", PKT_DATA, len_sofar); rkinit_errmsg(errbuf); return(RKINIT_PACKET); } bcopy(packet + PKT_LEN, (char *)&expected_length, sizeof(u_int32_t)); expected_length = ntohl(expected_length); if (expected_length > max_pkt_len) { sprintf(errbuf, "%s %d %s %d", "rki_get_packet: incoming message of size", expected_length, "is larger than message buffer of size", max_pkt_len); rkinit_errmsg(errbuf); return(RKINIT_PACKET); } tries = 0; while (!got_full_packet && (tries < RETRIES)) { if ((len = read(sock, packet + len_sofar, expected_length - len_sofar)) < 0) { sprintf(errbuf, "read: %s", sys_errlist[errno]); rkinit_errmsg(errbuf); return(RKINIT_READ); } len_sofar += len; if (expected_length == len_sofar) got_full_packet = TRUE; } if (len_sofar < expected_length) { sprintf(errbuf, "read: expected to receive at least %d bytes; received %d", expected_length, len_sofar); rkinit_errmsg(errbuf); return(RKINIT_PACKET); } if (packet[PKT_TYPE] == MT_DROP) { BCLEAR(errbuf); rkinit_errmsg(errbuf); return(RKINIT_DROPPED); } if (packet[PKT_TYPE] != type) { sprintf(errbuf, "Expected packet type of %s; got %s", rki_mt_to_string(type), rki_mt_to_string(packet[PKT_TYPE])); rkinit_errmsg(errbuf); return(RKINIT_PACKET); } *length = len_sofar - PKT_DATA; bcopy(packet + PKT_DATA, data, *length); free(packet); return(RKINIT_SUCCESS); } #ifdef __STDC__ int rki_setup_rpc(char *host) #else int rki_setup_rpc(host) char *host; #endif /* __STDC__ */ { struct hostent *hp; struct servent *sp; - int port; + int port, retval; SBCLEAR(saddr); SBCLEAR(hp); SBCLEAR(sp); if ((hp = gethostbyname(host)) == NULL) { sprintf(errbuf, "%s: unknown host.", host); rkinit_errmsg(errbuf); return(RKINIT_HOST); } if ((sp = getservbyname(SERVENT, "tcp"))) port = sp->s_port; else /* Fall back on known port number */ port = htons(PORT); saddr.sin_family = hp->h_addrtype; bcopy(hp->h_addr, (char *)&saddr.sin_addr, hp->h_length); saddr.sin_port = port; if ((sock = socket(hp->h_addrtype, SOCK_STREAM, IPPROTO_IP)) < 0) { sprintf(errbuf, "socket: %s", sys_errlist[errno]); rkinit_errmsg(errbuf); return(RKINIT_SOCKET); } - + if ((retval = krb_bind_local_addr(sock)) != KSUCCESS) { + sprintf(errbuf, "krb_bind_local_addr: %s", krb_err_txt[retval]); + rkinit_errmsg(errbuf); + close(sock); + return(RKINIT_SOCKET); + } if (connect(sock, (struct sockaddr *)&saddr, sizeof (saddr)) < 0) { sprintf(errbuf, "connect: %s", sys_errlist[errno]); rkinit_errmsg(errbuf); close(sock); return(RKINIT_CONNECT); } return(RKINIT_SUCCESS); } #ifdef __STDC__ int rki_rpc_exchange_version_info(int c_lversion, int c_hversion, int *s_lversion, int *s_hversion) #else int rki_rpc_exchange_version_info(c_lversion, c_hversion, s_lversion, s_hversion) int c_lversion; int c_hversion; int *s_lversion; int *s_hversion; #endif /* __STDC__ */ { int status = RKINIT_SUCCESS; u_char version_info[VERSION_INFO_SIZE]; u_int32_t length = sizeof(version_info); version_info[0] = (u_char) c_lversion; version_info[1] = (u_char) c_hversion; if ((status = rki_send_packet(sock, MT_CVERSION, length, (char *)version_info)) != RKINIT_SUCCESS) return(status); if ((status = rki_get_packet(sock, MT_SVERSION, &length, (char *)version_info)) != RKINIT_SUCCESS) return(status); *s_lversion = (int) version_info[0]; *s_hversion = (int) version_info[1]; return(RKINIT_SUCCESS); } #ifdef __STDC__ int rki_rpc_send_rkinit_info(rkinit_info *info) #else int rki_rpc_send_rkinit_info(info) rkinit_info *info; #endif /* __STDC__ */ { rkinit_info info_copy; bcopy(info, &info_copy, sizeof(rkinit_info)); info_copy.lifetime = htonl(info_copy.lifetime); return(rki_send_packet(sock, MT_RKINIT_INFO, sizeof(rkinit_info), (char *)&info_copy)); } #ifdef __STDC__ int rki_rpc_get_status(void) #else int rki_rpc_get_status() #endif /* __STDC__ */ { char msg[BUFSIZ]; int status = RKINIT_SUCCESS; u_int32_t length = sizeof(msg); if ((status = rki_get_packet(sock, MT_STATUS, &length, msg))) return(status); if (length == 0) return(RKINIT_SUCCESS); else { rkinit_errmsg(msg); return(RKINIT_DAEMON); } } #ifdef __STDC__ int rki_rpc_get_ktext(int sock, KTEXT auth, u_char type) #else int rki_rpc_get_ktext(sock, auth, type) int sock; KTEXT auth; u_char type; #endif /* __STDC__ */ { int status = RKINIT_SUCCESS; u_int32_t length = MAX_KTXT_LEN; if ((status = rki_get_packet(sock, type, &length, (char *)auth->dat))) return(status); auth->length = length; return(RKINIT_SUCCESS); } #ifdef __STDC__ int rki_rpc_sendauth(KTEXT auth) #else int rki_rpc_sendauth(auth) KTEXT auth; #endif /* __STDC__ */ { return(rki_send_packet(sock, MT_AUTH, auth->length, (char *)auth->dat)); } #ifdef __STDC__ int rki_rpc_get_skdc(KTEXT scip) #else int rki_rpc_get_skdc(scip) KTEXT scip; #endif /* __STDC__ */ { return(rki_rpc_get_ktext(sock, scip, MT_SKDC)); } #ifdef __STDC__ int rki_rpc_send_ckdc(MSG_DAT *scip) #else int rki_rpc_send_ckdc(scip) MSG_DAT *scip; #endif /* __STDC__ */ { return(rki_send_packet(sock, MT_CKDC, scip->app_length, (char *)scip->app_data)); } #ifdef __STDC__ int rki_get_csaddr(struct sockaddr_in *caddrp, struct sockaddr_in *saddrp) #else int rki_get_csaddr(caddrp, saddrp) struct sockaddr_in *caddrp; struct sockaddr_in *saddrp; #endif /* __STDC__ */ { int addrlen = sizeof(struct sockaddr_in); bcopy((char *)&saddr, (char *)saddrp, addrlen); if (getsockname(sock, (struct sockaddr *)caddrp, &addrlen) < 0) { sprintf(errbuf, "getsockname: %s", sys_errlist[errno]); rkinit_errmsg(errbuf); return(RKINIT_GETSOCK); } return(RKINIT_SUCCESS); } #ifdef __STDC__ void rki_drop_server(void) #else void rki_drop_server() #endif /* __STDC__ */ { (void) rki_send_packet(sock, MT_DROP, 0, ""); } #ifdef __STDC__ void rki_cleanup_rpc(void) #else void rki_cleanup_rpc() #endif /* __STDC__ */ { rki_drop_server(); (void) close(sock); } diff --git a/eBones/usr.sbin/kprop/kprop.c b/eBones/usr.sbin/kprop/kprop.c index 23bb893d2703..4307330cfbc1 100644 --- a/eBones/usr.sbin/kprop/kprop.c +++ b/eBones/usr.sbin/kprop/kprop.c @@ -1,637 +1,655 @@ /* * * Copyright 1987 by the Massachusetts Institute of Technology. * * For copying and distribution information, * please see the file . * - * $Revision: 1.1.1.1 $ - * $Date: 1995/08/03 07:36:18 $ + * $Revision: 1.3 $ + * $Date: 1995/09/07 21:37:34 $ * $State: Exp $ - * $Source: /usr/cvs/src/eBones/kprop/kprop.c,v $ - * $Author: mark $ + * $Source: /home/ncvs/src/eBones/usr.sbin/kprop/kprop.c,v $ + * $Author: markm $ * $Locker: $ * * $Log: kprop.c,v $ + * Revision 1.3 1995/09/07 21:37:34 markm + * Major cleanup of eBones code: + * + * - Get all functions prototyped or at least defined before use. + * - Make code compile (Mostly) clean with -Wall set + * - Start to reduce the degree to which DES aka libdes is built in. + * - get all functions to the same uniform standard of definition: + * int + * foo(a, b) + * int a; + * int *b; + * { + * : + * } + * - fix numerous bugs exposed by above processes. + * + * Note - this replaces the previous work which used an unpopular function + * definition style. + * * Revision 1.1.1.1 1995/08/03 07:36:18 mark * Import an updated revision of the MIT kprop program for distributing * kerberos databases to slave servers. * * NOTE: This method was abandoned by MIT long ago, this code is close to * garbage, but it is slightly more secure than using rdist. * There is no documentation available on how to use it, and * it should -not- be built by default. * * Obtained from: MIT Project Athena * * Revision 1.1.1.1 1995/08/02 22:11:44 pst * Import an updated revision of the MIT kprop program for distributing * kerberos databases to slave servers. * * NOTE: This method was abandoned by MIT long ago, this code is close to * garbage, but it is slightly more secure than using rdist. * There is no documentation available on how to use it, and * it should -not- be built by default. * * Obtained from: MIT Project Athena * * Revision 4.7 92/11/10 23:01:06 tytso * Removed incompatible #include * * Revision 4.6 91/02/28 22:49:34 probe * Fixed header file inclusion * * Revision 4.5 90/03/20 15:37:57 jon * Stop kpropd port number from being bashed (static buffers) * Programmer: jtkohl * Auditor: jon * * Revision 4.4 90/01/02 13:42:40 jtkohl * add back in accidentally deleted $ in rcsid string * * Revision 4.3 89/12/30 21:22:27 qjb * Added #define MAXHOSTNAMELEN if not already defined for the benifit * of Unixes that don't have this variable in sys/param.h. * * Revision 4.2 89/03/23 10:23:43 jtkohl * fix misuse of mkstemp to use mktemp * NOENCRYPTION changes * * Revision 4.1 89/01/24 20:35:17 root * name change * * Revision 4.0 89/01/24 18:44:38 wesommer * Original version; programmer: wesommer * auditor: jon. * * Revision 4.4 88/01/08 18:05:21 jon * formating changes and rcs header info * * */ #if 0 #ifndef lint static char rcsid_kprop_c[] = -"$Id: kprop.c,v 1.1.1.1 1995/08/03 07:36:18 mark Exp $"; +"$Id: kprop.c,v 1.3 1995/09/07 21:37:34 markm Exp $"; #endif lint #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kprop.h" /* for those broken Unixes without this defined... should be in sys/param.h */ #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 64 #endif static char kprop_version[KPROP_PROT_VERSION_LEN] = KPROP_PROT_VERSION; int debug = 0; char my_realm[REALM_SZ]; int princ_data_size = 3 * sizeof(long) + 3 * sizeof(unsigned char); short transfer_mode, net_transfer_mode; int force_flag; static char ok[] = ".dump_ok"; extern char *krb_get_phost(char *); struct slave_host { u_long net_addr; char *name; char *instance; char *realm; int not_time_yet; int succeeded; struct slave_host *next; }; void Death(char *s); int get_slaves(struct slave_host **psl, char *file, time_t ok_mtime); int prop_to_slaves(struct slave_host *sl, int fd, char *fslv); int main(argc, argv) int argc; char *argv[]; { int fd, i; char *floc, *floc_ok; char *fslv; struct stat stbuf, stbuf_ok; long l_init, l_final; char *pc; int l_diff; static struct slave_host *slave_host_list = NULL; struct slave_host *sh; transfer_mode = KPROP_TRANSFER_PRIVATE; time(&l_init); pc = ctime(&l_init); pc[strlen(pc) - 1] = '\0'; printf("\nStart slave propagation: %s\n", pc); floc = (char *) NULL; fslv = (char *) NULL; if (krb_get_lrealm(my_realm,1) != KSUCCESS) Death ("Getting my kerberos realm. Check krb.conf"); for (i = 1; i < argc; i++) switch (argv[i][0]) { case '-': if (strcmp (argv[i], "-private") == 0) transfer_mode = KPROP_TRANSFER_PRIVATE; #ifdef not_safe_yet else if (strcmp (argv[i], "-safe") == 0) transfer_mode = KPROP_TRANSFER_SAFE; else if (strcmp (argv[i], "-clear") == 0) transfer_mode = KPROP_TRANSFER_CLEAR; #endif else if (strcmp (argv[i], "-realm") == 0) { i++; if (i < argc) strcpy(my_realm, argv[i]); else goto usage; } else if (strcmp (argv[i], "-force") == 0) force_flag++; else { fprintf (stderr, "kprop: unknown control argument %s.\n", argv[i]); exit (1); } break; default: /* positional arguments are marginal at best ... */ if (floc == (char *) NULL) floc = argv[i]; else { if (fslv == (char *) NULL) fslv = argv[i]; else { usage: /* already got floc and fslv, what is this? */ fprintf(stderr, "\nUsage: kprop [-force] [-realm realm] [-private|-safe|-clear] data_file slaves_file\n\n"); exit(1); } } } if ((floc == (char *)NULL) || (fslv == (char *)NULL)) goto usage; if ((floc_ok = (char *) malloc(strlen(floc) + strlen(ok) + 1)) == NULL) { Death(floc); } strcat(strcpy(floc_ok, floc), ok); if ((fd = open(floc, O_RDONLY)) < 0) { Death(floc); } if (flock(fd, LOCK_EX | LOCK_NB)) { Death(floc); } if (stat(floc, &stbuf)) { Death(floc); } if (stat(floc_ok, &stbuf_ok)) { Death(floc_ok); } if (stbuf.st_mtime > stbuf_ok.st_mtime) { fprintf(stderr, "kprop: '%s' more recent than '%s'.\n", floc, floc_ok); exit(1); } if (!get_slaves(&slave_host_list, fslv, stbuf_ok.st_mtime)) { fprintf(stderr, "kprop: can't read slave host file '%s'.\n", fslv); exit(1); } #ifdef KPROP_DBG { struct slave_host *sh; int i; fprintf(stderr, "\n\n"); fflush(stderr); for (sh = slave_host_list; sh; sh = sh->next) { fprintf(stderr, "slave %d: %s, %s", i++, sh->name, inet_ntoa(sh->net_addr)); fflush(stderr); } } #endif /* KPROP_DBG */ if (!prop_to_slaves(slave_host_list, fd, fslv)) { fprintf(stderr, "kprop: propagation failed.\n"); exit(1); } if (flock(fd, LOCK_UN)) { Death(floc); } fprintf(stderr, "\n\n"); for (sh = slave_host_list; sh; sh = sh->next) { fprintf(stderr, "%s:\t\t%s\n", sh->name, (sh->not_time_yet? "Not time yet" : (sh->succeeded ? "Succeeded" : "FAILED"))); } time(&l_final); l_diff = l_final - l_init; printf("propagation finished, %d:%02d:%02d elapsed\n", l_diff / 3600, (l_diff % 3600) / 60, l_diff % 60); exit(0); } void Death(s) char *s; { fprintf(stderr, "kprop: "); perror(s); exit(1); } /* The master -> slave protocol looks like this: 1) 8 byte version string 2) 2 bytes of "transfer mode" (net byte order of course) 3) ticket/authentication send by sendauth 4) 4 bytes of "block" length (u_long) 5) data 4 and 5 repeat til EOF ... */ int prop_to_slaves(sl, fd, fslv) struct slave_host *sl; int fd; char *fslv; { char buf[KPROP_BUFSIZ]; char obuf[KPROP_BUFSIZ + 64 /* leave room for private msg overhead */ ]; struct servent *sp; struct sockaddr_in sin, my_sin; int i, n, s; struct slave_host *cs; /* current slave */ char path[256], my_host_name[MAXHOSTNAMELEN], *p_my_host_name; char kprop_service_instance[INST_SZ]; char *pc; u_long cksum, get_data_checksum(); u_long length, nlength; long kerror; KTEXT_ST ticket; CREDENTIALS cred; MSG_DAT msg_dat; static char tkstring[] = "/tmp/kproptktXXXXXX"; Key_schedule session_sched; (void) mktemp(tkstring); krb_set_tkt_string(tkstring); if ((sp = getservbyname("krb_prop", "tcp")) == 0) { fprintf(stderr, "tcp/krb_prop: service unknown.\n"); exit(1); } bzero(&sin, sizeof sin); sin.sin_family = AF_INET; sin.sin_port = sp->s_port; strcpy(path, fslv); if ((pc = rindex(path, '/'))) { pc += 1; } else { pc = path; } for (i = 0; i < 5; i++) { /* try each slave five times max */ for (cs = sl; cs; cs = cs->next) { if (!cs->succeeded) { if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("kprop: socket"); exit(1); } bcopy(&cs->net_addr, &sin.sin_addr, sizeof cs->net_addr); - - if (connect(s, (struct sockaddr *) &sin, sizeof sin) < 0) { - fprintf(stderr, "%s: ", cs->name); - perror("connect"); - close(s); - continue; /*** NEXT SLAVE ***/ - } - /* for krb_mk_{priv, safe} */ bzero (&my_sin, sizeof my_sin); n = sizeof my_sin; - if (getsockname (s, (struct sockaddr *) &my_sin, &n) != 0) { - fprintf (stderr, "kprop: can't get socketname."); - perror ("getsockname"); + if ((kerror = krb_get_local_addr (&my_sin)) != KSUCCESS) { + fprintf (stderr, "kprop: can't get local address: %s\n", + krb_err_txt[kerror]); close (s); continue; /*** NEXT SLAVE ***/ } - if (n != sizeof (my_sin)) { - fprintf (stderr, "kprop: can't get socketname. len"); - close (s); + if (bind(s, (struct sockaddr *) &my_sin, sizeof my_sin) < 0) { + fprintf(stderr, "Unable to bind local address: "); + perror("bind"); + close(s); + continue; + } + if (connect(s, (struct sockaddr *) &sin, sizeof sin) < 0) { + fprintf(stderr, "%s: ", cs->name); + perror("connect"); + close(s); continue; /*** NEXT SLAVE ***/ } /* Get ticket */ kerror = krb_mk_req (&ticket, KPROP_SERVICE_NAME, cs->instance, cs->realm, (u_long) 0); /* if ticket has expired try to get a new one, but * first get a TGT ... */ if (kerror != MK_AP_OK) { if (gethostname (my_host_name, sizeof(my_host_name)) != 0) { fprintf (stderr, "%s:", cs->name); perror ("getting my hostname"); close (s); break; /* next one can't work either! */ } /* get canonical kerberos service instance name */ p_my_host_name = krb_get_phost (my_host_name); /* copy it to make sure gethostbyname static doesn't * screw us. */ strcpy (kprop_service_instance, p_my_host_name); kerror = krb_get_svc_in_tkt (KPROP_SERVICE_NAME, #if 0 kprop_service_instance, #else KRB_MASTER, #endif my_realm, TGT_SERVICE_NAME, my_realm, 96, KPROP_SRVTAB); if (kerror != INTK_OK) { fprintf (stderr, "%s: %s. While getting initial ticket\n", cs->name, krb_err_txt[kerror]); close (s); goto punt; } kerror = krb_mk_req (&ticket, KPROP_SERVICE_NAME, cs->instance, cs->realm, (u_long) 0); } if (kerror != MK_AP_OK) { fprintf (stderr, "%s: %s. Calling krb_mk_req.", cs->name, krb_err_txt[kerror]); close (s); continue; /*** NEXT SLAVE ***/ } if (write(s, kprop_version, sizeof(kprop_version)) != sizeof(kprop_version)) { fprintf (stderr, "%s: ", cs->name); perror ("write (version) error"); close (s); continue; /*** NEXT SLAVE ***/ } net_transfer_mode = htons (transfer_mode); if (write(s, &net_transfer_mode, sizeof(net_transfer_mode)) != sizeof(net_transfer_mode)) { fprintf (stderr, "%s: ", cs->name); perror ("write (transfer_mode) error"); close (s); continue; /*** NEXT SLAVE ***/ } kerror = krb_get_cred (KPROP_SERVICE_NAME, cs->instance, cs->realm, &cred); if (kerror != KSUCCESS) { fprintf (stderr, "%s: %s. Getting session key.", cs->name, krb_err_txt[kerror]); close (s); continue; /*** NEXT SLAVE ***/ } #ifdef NOENCRYPTION bzero((char *)session_sched, sizeof(session_sched)); #else if (key_sched ((C_Block *)cred.session, session_sched)) { fprintf (stderr, "%s: can't make key schedule.", cs->name); close (s); continue; /*** NEXT SLAVE ***/ } #endif /* SAFE (quad_cksum) and CLEAR are just not good enough */ cksum = 0; #ifdef not_working_yet if (transfer_mode != KPROP_TRANSFER_PRIVATE) { cksum = get_data_checksum(fd, session_sched); lseek(fd, 0L, 0); } else #endif { struct stat st; fstat (fd, &st); cksum = st.st_size; } kerror = krb_sendauth(KOPT_DO_MUTUAL, s, &ticket, KPROP_SERVICE_NAME, cs->instance, cs->realm, cksum, &msg_dat, &cred, session_sched, &my_sin, &sin, KPROP_PROT_VERSION); if (kerror != KSUCCESS) { fprintf (stderr, "%s: %s. Calling krb_sendauth.", cs->name, krb_err_txt[kerror]); close (s); continue; /*** NEXT SLAVE ***/ } while ((n = read(fd, buf, sizeof buf))) { if (n < 0) { perror("input file read error"); exit(1); } switch (transfer_mode) { case KPROP_TRANSFER_PRIVATE: case KPROP_TRANSFER_SAFE: if (transfer_mode == KPROP_TRANSFER_PRIVATE) length = krb_mk_priv (buf, obuf, n, session_sched, cred.session, &my_sin, &sin); else length = krb_mk_safe (buf, obuf, n, (C_Block *)cred.session, &my_sin, &sin); if (length == -1) { fprintf (stderr, "%s: %s failed.", cs->name, (transfer_mode == KPROP_TRANSFER_PRIVATE) ? "krb_rd_priv" : "krb_rd_safe"); close (s); continue; /*** NEXT SLAVE ***/ } nlength = htonl(length); if (write(s, &nlength, sizeof nlength) != sizeof nlength) { fprintf (stderr, "%s: ", cs->name); perror ("write error"); close (s); continue; /*** NEXT SLAVE ***/ } if (write(s, obuf, length) != length) { fprintf(stderr, "%s: ", cs->name); perror("write error"); close(s); continue; /*** NEXT SLAVE ***/ } break; case KPROP_TRANSFER_CLEAR: if (write(s, buf, n) != n) { fprintf(stderr, "%s: ", cs->name); perror("write error"); close(s); continue; /*** NEXT SLAVE ***/ } break; } } close(s); cs->succeeded = 1; fprintf(stderr, "%s: success.\n", cs->name); strcat(strcpy(pc, cs->name), "-last-prop"); close(creat(path, 0600)); } } } punt: dest_tkt(); for (cs = sl; cs; cs = cs->next) { if (!cs->succeeded) return (0); /* didn't get this slave */ } return (1); } int get_slaves(psl, file, ok_mtime) struct slave_host **psl; char *file; time_t ok_mtime; { FILE *fin; char namebuf[128], *inst; char *pc; struct hostent *host; struct slave_host **th; char path[256]; char *ppath; struct stat stbuf; if ((fin = fopen(file, "r")) == NULL) { fprintf(stderr, "Can't open slave host file, '%s'.\n", file); exit(-1); } strcpy(path, file); if ((ppath = rindex(path, '/'))) { ppath += 1; } else { ppath = path; } for (th = psl; fgets(namebuf, sizeof namebuf, fin); th = &(*th)->next) { if ((pc = index(namebuf, '\n'))) { *pc = '\0'; } else { fprintf(stderr, "Host name too long (>= %d chars) in '%s'.\n", sizeof namebuf, file); exit(-1); } host = gethostbyname(namebuf); if (host == NULL) { fprintf(stderr, "Unknown host '%s' in '%s'.\n", namebuf, file); exit(-1); } (*th) = (struct slave_host *) malloc(sizeof(struct slave_host)); if (!*th) { fprintf(stderr, "No memory reading host list from '%s'.\n", file); exit(-1); } (*th)->name = malloc(strlen(namebuf) + 1); if (!(*th)->name) { fprintf(stderr, "No memory reading host list from '%s'.\n", file); exit(-1); } /* get kerberos cannonical instance name */ strcpy((*th)->name, namebuf); inst = krb_get_phost ((*th)->name); (*th)->instance = malloc(strlen(inst) + 1); if (!(*th)->instance) { fprintf(stderr, "No memory reading host list from '%s'.\n", file); exit(-1); } strcpy((*th)->instance, inst); /* what a concept, slave servers in different realms! */ (*th)->realm = my_realm; (*th)->net_addr = *(u_long *) host->h_addr; (*th)->succeeded = 0; (*th)->next = NULL; strcat(strcpy(ppath, (*th)->name), "-last-prop"); if (!force_flag && !stat(path, &stbuf) && stbuf.st_mtime > ok_mtime) { (*th)->not_time_yet = 1; (*th)->succeeded = 1; /* no change since last success */ } } fclose(fin); return (1); } #ifdef doesnt_work_yet u_long get_data_checksum(fd, key_sched) int fd; Key_schedule key_sched; { unsigned long cksum = 0; unsigned long cbc_cksum(); int n; char buf[BUFSIZ]; long obuf[2]; while (n = read(fd, buf, sizeof buf)) { if (n < 0) { fprintf(stderr, "Input data file read error: "); perror("read"); exit(1); } cksum = cbc_cksum(buf, obuf, n, key_sched, key_sched); } return cksum; } #endif diff --git a/libexec/rlogind/rlogind.c b/libexec/rlogind/rlogind.c index 4ff0af7c36aa..37a974d73012 100644 --- a/libexec/rlogind/rlogind.c +++ b/libexec/rlogind/rlogind.c @@ -1,764 +1,764 @@ /*- * Copyright (c) 1983, 1988, 1989, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static char copyright[] = "@(#) Copyright (c) 1983, 1988, 1989, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint static char sccsid[] = "@(#)rlogind.c 8.1 (Berkeley) 6/4/93"; #endif /* not lint */ /* * remote login server: * \0 * remuser\0 * locuser\0 * terminal_type/speed\0 * data */ #define FD_SETSIZE 16 /* don't need many bits for select */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pathnames.h" #ifndef TIOCPKT_WINDOW #define TIOCPKT_WINDOW 0x80 #endif #ifdef KERBEROS #include #include #define SECURE_MESSAGE "This rlogin session is using DES encryption for all transmissions.\r\n" AUTH_DAT *kdata; KTEXT ticket; u_char auth_buf[sizeof(AUTH_DAT)]; u_char tick_buf[sizeof(KTEXT_ST)]; Key_schedule schedule; int doencrypt, retval, use_kerberos, vacuous; #define ARGSTR "alnkvx" #else #define ARGSTR "aln" #endif /* KERBEROS */ char *env[2]; #define NMAX 30 char lusername[NMAX+1], rusername[NMAX+1]; static char term[64] = "TERM="; #define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */ int keepalive = 1; int check_all = 0; struct passwd *pwd; void doit __P((int, struct sockaddr_in *)); int control __P((int, char *, int)); void protocol __P((int, int)); void cleanup __P((int)); void fatal __P((int, char *, int)); int do_rlogin __P((struct sockaddr_in *)); void getstr __P((char *, int, char *)); void setup_term __P((int)); int do_krb_login __P((struct sockaddr_in *)); void usage __P((void)); int local_domain __P((char *)); char *topdomain __P((char *)); int main(argc, argv) int argc; char *argv[]; { extern int __check_rhosts_file; struct sockaddr_in from; int ch, fromlen, on; openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH); opterr = 0; while ((ch = getopt(argc, argv, ARGSTR)) != EOF) switch (ch) { case 'a': check_all = 1; break; case 'l': __check_rhosts_file = 0; break; case 'n': keepalive = 0; break; #ifdef KERBEROS case 'k': use_kerberos = 1; break; case 'v': vacuous = 1; break; #ifdef CRYPT case 'x': doencrypt = 1; break; #endif #endif case '?': default: usage(); break; } argc -= optind; argv += optind; #ifdef KERBEROS if (use_kerberos && vacuous) { usage(); fatal(STDERR_FILENO, "only one of -k and -v allowed", 0); } #endif fromlen = sizeof (from); if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) { syslog(LOG_ERR,"Can't get peer name of remote host: %m"); fatal(STDERR_FILENO, "Can't get peer name of remote host", 1); } on = 1; if (keepalive && setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); on = IPTOS_LOWDELAY; if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0) syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); doit(0, &from); } int child; int netf; char line[MAXPATHLEN]; int confirmed; struct winsize win = { 0, 0, 0, 0 }; void doit(f, fromp) int f; struct sockaddr_in *fromp; { int master, pid, on = 1; int authenticated = 0; register struct hostent *hp; char hostname[2 * MAXHOSTNAMELEN + 1]; char c; alarm(60); read(f, &c, 1); if (c != 0) exit(1); #ifdef KERBEROS if (vacuous) fatal(f, "Remote host requires Kerberos authentication", 0); #endif alarm(0); fromp->sin_port = ntohs((u_short)fromp->sin_port); hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof(struct in_addr), fromp->sin_family); if (hp) (void)strcpy(hostname, hp->h_name); else (void)strcpy(hostname, inet_ntoa(fromp->sin_addr)); #ifdef KERBEROS if (use_kerberos) { retval = do_krb_login(fromp); if (retval == 0) authenticated++; else if (retval > 0) fatal(f, krb_err_txt[retval], 0); write(f, &c, 1); confirmed = 1; /* we sent the null! */ } else #endif { if (fromp->sin_family != AF_INET || fromp->sin_port >= IPPORT_RESERVED || fromp->sin_port < IPPORT_RESERVED/2) { syslog(LOG_NOTICE, "Connection from %s on illegal port", inet_ntoa(fromp->sin_addr)); fatal(f, "Permission denied", 0); } #ifdef IP_OPTIONS { u_char optbuf[BUFSIZ/3], *cp; char lbuf[BUFSIZ], *lp; int optsize = sizeof(optbuf), ipproto; struct protoent *ip; if ((ip = getprotobyname("ip")) != NULL) ipproto = ip->p_proto; else ipproto = IPPROTO_IP; if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, &optsize) == 0 && optsize != 0) { lp = lbuf; for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3) sprintf(lp, " %2.2x", *cp); syslog(LOG_NOTICE, "Connection received using IP options (ignored):%s", lbuf); if (setsockopt(0, ipproto, IP_OPTIONS, (char *)NULL, optsize) != 0) { syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m"); exit(1); } } } #endif if (do_rlogin(fromp) == 0) authenticated++; } if (confirmed == 0) { write(f, "", 1); confirmed = 1; /* we sent the null! */ } #ifdef KERBEROS #ifdef CRYPT if (doencrypt) (void) des_write(f, SECURE_MESSAGE, sizeof(SECURE_MESSAGE) - 1); #endif #endif netf = f; pid = forkpty(&master, line, NULL, &win); if (pid < 0) { if (errno == ENOENT) fatal(f, "Out of ptys", 0); else fatal(f, "Forkpty", 1); } if (pid == 0) { if (f > 2) /* f should always be 0, but... */ (void) close(f); setup_term(0); if (strchr(lusername, '-')) { syslog(LOG_ERR, "tried to pass user \"%s\" to login", lusername); fatal(STDERR_FILENO, "invalid user", 0); } if (authenticated) { #ifdef KERBEROS if (use_kerberos && (pwd->pw_uid == 0)) syslog(LOG_INFO|LOG_AUTH, "ROOT Kerberos login from %s.%s@%s on %s\n", kdata->pname, kdata->pinst, kdata->prealm, hostname); #endif execl(_PATH_LOGIN, "login", "-p", "-h", hostname, "-f", lusername, (char *)NULL); } else execl(_PATH_LOGIN, "login", "-p", "-h", hostname, lusername, (char *)NULL); fatal(STDERR_FILENO, _PATH_LOGIN, 1); /*NOTREACHED*/ } #ifdef CRYPT #ifdef KERBEROS /* * If encrypted, don't turn on NBIO or the des read/write * routines will croak. */ if (!doencrypt) #endif #endif ioctl(f, FIONBIO, &on); ioctl(master, FIONBIO, &on); ioctl(master, TIOCPKT, &on); signal(SIGCHLD, cleanup); protocol(f, master); signal(SIGCHLD, SIG_IGN); cleanup(0); } char magic[2] = { 0377, 0377 }; char oobdata[] = {TIOCPKT_WINDOW}; /* * Handle a "control" request (signaled by magic being present) * in the data stream. For now, we are only willing to handle * window size changes. */ int control(pty, cp, n) int pty; char *cp; int n; { struct winsize w; if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') return (0); oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */ bcopy(cp+4, (char *)&w, 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); return (4+sizeof (w)); } /* * rlogin "protocol" machine. */ void protocol(f, p) register int f, p; { char pibuf[1024+1], fibuf[1024], *pbp, *fbp; register pcc = 0, fcc = 0; int cc, nfd, n; 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). */ (void) signal(SIGTTOU, SIG_IGN); send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */ if (f > p) nfd = f + 1; else nfd = p + 1; if (nfd > FD_SETSIZE) { syslog(LOG_ERR, "select mask too small, increase FD_SETSIZE"); fatal(f, "internal error (select mask too small)", 0); } for (;;) { fd_set ibits, obits, ebits, *omask; FD_ZERO(&ebits); FD_ZERO(&ibits); FD_ZERO(&obits); omask = (fd_set *)NULL; if (fcc) { FD_SET(p, &obits); omask = &obits; } else FD_SET(f, &ibits); if (pcc >= 0) if (pcc) { FD_SET(f, &obits); omask = &obits; } else FD_SET(p, &ibits); FD_SET(p, &ebits); if ((n = select(nfd, &ibits, omask, &ebits, 0)) < 0) { if (errno == EINTR) continue; fatal(f, "select", 1); } if (n == 0) { /* shouldn't happen... */ sleep(5); continue; } #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) if (FD_ISSET(p, &ebits)) { cc = read(p, &cntl, 1); if (cc == 1 && pkcontrol(cntl)) { cntl |= oobdata[0]; send(f, &cntl, 1, MSG_OOB); if (cntl & TIOCPKT_FLUSHWRITE) { pcc = 0; FD_CLR(p, &ibits); } } } if (FD_ISSET(f, &ibits)) { #ifdef CRYPT #ifdef KERBEROS if (doencrypt) fcc = des_read(f, fibuf, sizeof(fibuf)); else #endif #endif fcc = read(f, fibuf, sizeof(fibuf)); if (fcc < 0 && errno == EWOULDBLOCK) fcc = 0; else { register char *cp; int left, n; if (fcc <= 0) break; fbp = fibuf; top: for (cp = fibuf; cp < fibuf+fcc-1; cp++) if (cp[0] == magic[0] && cp[1] == magic[1]) { left = fcc - (cp-fibuf); n = control(p, cp, left); if (n) { left -= n; if (left > 0) bcopy(cp+n, cp, left); fcc -= n; goto top; /* n^2 */ } } FD_SET(p, &obits); /* try write */ } } if (FD_ISSET(p, &obits) && fcc > 0) { cc = write(p, fbp, fcc); if (cc > 0) { fcc -= cc; fbp += cc; } } if (FD_ISSET(p, &ibits)) { pcc = read(p, pibuf, sizeof (pibuf)); pbp = pibuf; if (pcc < 0 && errno == EWOULDBLOCK) pcc = 0; else if (pcc <= 0) break; else if (pibuf[0] == 0) { pbp++, pcc--; #ifdef CRYPT #ifdef KERBEROS if (!doencrypt) #endif #endif FD_SET(f, &obits); /* try write */ } else { if (pkcontrol(pibuf[0])) { pibuf[0] |= oobdata[0]; send(f, &pibuf[0], 1, MSG_OOB); } pcc = 0; } } if ((FD_ISSET(f, &obits)) && pcc > 0) { #ifdef CRYPT #ifdef KERBEROS if (doencrypt) cc = des_write(f, pbp, pcc); else #endif #endif cc = write(f, pbp, pcc); if (cc < 0 && errno == EWOULDBLOCK) { /* * This happens when we try write after read * from p, but some old kernels balk at large * writes even when select returns true. */ if (!FD_ISSET(p, &ibits)) sleep(5); continue; } if (cc > 0) { pcc -= cc; pbp += cc; } } } } void cleanup(signo) int signo; { char *p; p = line + sizeof(_PATH_DEV) - 1; if (logout(p)) logwtmp(p, "", ""); (void)chmod(line, 0666); (void)chown(line, 0, 0); *p = 'p'; (void)chmod(line, 0666); (void)chown(line, 0, 0); shutdown(netf, 2); exit(1); } void fatal(f, msg, syserr) int f; char *msg; int syserr; { int len; char buf[BUFSIZ], *bp = buf; /* * Prepend binary one to message if we haven't sent * the magic null as confirmation. */ if (!confirmed) *bp++ = '\01'; /* error indicator */ if (syserr) len = sprintf(bp, "rlogind: %s: %s.\r\n", msg, strerror(errno)); else len = sprintf(bp, "rlogind: %s.\r\n", msg); (void) write(f, buf, bp + len - buf); exit(1); } int do_rlogin(dest) struct sockaddr_in *dest; { getstr(rusername, sizeof(rusername), "remuser too long"); getstr(lusername, sizeof(lusername), "locuser too long"); getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long"); pwd = getpwnam(lusername); if (pwd == NULL) return (-1); if (pwd->pw_uid == 0) return (-1); /* XXX why don't we syslog() failure? */ return (iruserok(dest->sin_addr.s_addr, 0, rusername, lusername)); } void getstr(buf, cnt, errmsg) char *buf; int cnt; char *errmsg; { char c; do { if (read(0, &c, 1) != 1) exit(1); if (--cnt < 0) fatal(STDOUT_FILENO, errmsg, 0); *buf++ = c; } while (c != 0); } extern char **environ; void setup_term(fd) int fd; { register char *cp = index(term+ENVSIZE, '/'); char *speed; struct termios tt; #ifndef notyet tcgetattr(fd, &tt); if (cp) { *cp++ = '\0'; speed = cp; cp = index(speed, '/'); if (cp) *cp++ = '\0'; cfsetspeed(&tt, atoi(speed)); } tt.c_iflag = TTYDEF_IFLAG; tt.c_oflag = TTYDEF_OFLAG; tt.c_lflag = TTYDEF_LFLAG; tcsetattr(fd, TCSAFLUSH, &tt); #else if (cp) { *cp++ = '\0'; speed = cp; cp = index(speed, '/'); if (cp) *cp++ = '\0'; tcgetattr(fd, &tt); cfsetspeed(&tt, atoi(speed)); tcsetattr(fd, TCSAFLUSH, &tt); } #endif env[0] = term; env[1] = 0; environ = env; } #ifdef KERBEROS #define VERSION_SIZE 9 /* * Do the remote kerberos login to the named host with the * given inet address * * Return 0 on valid authorization * Return -1 on valid authentication, no authorization * Return >0 for error conditions */ int do_krb_login(dest) struct sockaddr_in *dest; { int rc; char instance[INST_SZ], version[VERSION_SIZE]; long authopts = 0L; /* !mutual */ struct sockaddr_in faddr; kdata = (AUTH_DAT *) auth_buf; ticket = (KTEXT) tick_buf; instance[0] = '*'; instance[1] = '\0'; #ifdef CRYPT if (doencrypt) { rc = sizeof(faddr); if (getsockname(0, (struct sockaddr *)&faddr, &rc)) return (-1); authopts = KOPT_DO_MUTUAL; rc = krb_recvauth( authopts, 0, ticket, "rcmd", instance, dest, &faddr, kdata, "", schedule, version); - des_set_key(kdata->session, schedule); + des_set_key(&kdata->session, schedule); } else #endif rc = krb_recvauth( authopts, 0, ticket, "rcmd", instance, dest, (struct sockaddr_in *) 0, kdata, "", (bit_64 *) 0, version); if (rc != KSUCCESS) return (rc); getstr(lusername, sizeof(lusername), "locuser"); /* get the "cmd" in the rcmd protocol */ getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type"); pwd = getpwnam(lusername); if (pwd == NULL) return (-1); /* returns nonzero for no access */ if (kuserok(kdata, lusername) != 0) return (-1); return (0); } #endif /* KERBEROS */ void usage() { #ifdef KERBEROS syslog(LOG_ERR, "usage: rlogind [-aln] [-k | -v]"); #else syslog(LOG_ERR, "usage: rlogind [-aln]"); #endif } /* * Check whether host h is in our local domain, * defined as sharing the last two components of the domain part, * or the entire domain part if the local domain has only one component. * If either name is unqualified (contains no '.'), * assume that the host is local, as it will be * interpreted as such. */ int local_domain(h) char *h; { char localhost[MAXHOSTNAMELEN]; char *p1, *p2; localhost[0] = 0; (void) gethostname(localhost, sizeof(localhost)); p1 = topdomain(localhost); p2 = topdomain(h); if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2)) return (1); return (0); } char * topdomain(h) char *h; { register char *p; char *maybe = NULL; int dots = 0; for (p = h + strlen(h); p >= h; p--) { if (*p == '.') { if (++dots == 2) return (p); maybe = p; } } return (maybe); } diff --git a/usr.bin/rlogin/kcmd.c b/usr.bin/rlogin/kcmd.c index 3f6a138db3b9..14c03675ed1f 100644 --- a/usr.bin/rlogin/kcmd.c +++ b/usr.bin/rlogin/kcmd.c @@ -1,307 +1,310 @@ /* * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static char Xsccsid[] = "derived from @(#)rcmd.c 5.17 (Berkeley) 6/27/88"; static char sccsid[] = "@(#)kcmd.c 8.2 (Berkeley) 8/19/93"; #endif /* not lint */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "krb.h" #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 64 #endif #define START_PORT 5120 /* arbitrary */ int getport __P((int *)); int kcmd(sock, ahost, rport, locuser, remuser, cmd, fd2p, ticket, service, realm, cred, schedule, msg_data, laddr, faddr, authopts) int *sock; char **ahost; u_short rport; char *locuser, *remuser, *cmd; int *fd2p; KTEXT ticket; char *service; char *realm; CREDENTIALS *cred; Key_schedule schedule; MSG_DAT *msg_data; struct sockaddr_in *laddr, *faddr; long authopts; { int s, timo = 1, pid; long oldmask; struct sockaddr_in sin, from; char c; #ifdef ATHENA_COMPAT int lport = IPPORT_RESERVED - 1; #else int lport = START_PORT; #endif struct hostent *hp; int rc; char *host_save; int status; pid = getpid(); hp = gethostbyname(*ahost); if (hp == NULL) { /* fprintf(stderr, "%s: unknown host\n", *ahost); */ return (-1); } host_save = malloc(strlen(hp->h_name) + 1); strcpy(host_save, hp->h_name); *ahost = host_save; #ifdef KERBEROS /* If realm is null, look up from table */ if (realm == NULL || realm[0] == '\0') realm = krb_realmofhost(host_save); #endif /* KERBEROS */ oldmask = sigblock(sigmask(SIGURG)); for (;;) { s = getport(&lport); if (s < 0) { if (errno == EAGAIN) fprintf(stderr, "kcmd(socket): All ports in use\n"); else perror("kcmd: socket"); sigsetmask(oldmask); return (-1); } fcntl(s, F_SETOWN, pid); sin.sin_family = hp->h_addrtype; #if defined(ultrix) || defined(sun) bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length); #else bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr, hp->h_length); #endif 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 rcmd. */ if (errno == ECONNREFUSED && timo <= 4) { /* sleep(timo); don't wait at all here */ timo *= 2; continue; } #if !(defined(ultrix) || defined(sun)) if (hp->h_addr_list[1] != NULL) { int oerrno = errno; fprintf(stderr, "kcmd: connect to address %s: ", inet_ntoa(sin.sin_addr)); errno = oerrno; perror(NULL); hp->h_addr_list++; bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr, hp->h_length); fprintf(stderr, "Trying %s...\n", inet_ntoa(sin.sin_addr)); continue; } #endif /* !(defined(ultrix) || defined(sun)) */ if (errno != ECONNREFUSED) perror(hp->h_name); sigsetmask(oldmask); 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("kcmd(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("kcmd: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, "kcmd(socket): protocol failure in circuit setup.\n"); status = -1; goto bad2; } } /* * Kerberos-authenticated service. Don't have to send locuser, * since its already in the ticket, and we'll extract it on * the other side. */ /* (void) write(s, locuser, strlen(locuser)+1); */ /* set up the needed stuff for mutual auth, but only if necessary */ if (authopts & KOPT_DO_MUTUAL) { int sin_len; *faddr = sin; sin_len = sizeof(struct sockaddr_in); if (getsockname(s, (struct sockaddr *)laddr, &sin_len) < 0) { perror("kcmd(getsockname)"); status = -1; goto bad2; } } #ifdef KERBEROS if ((status = krb_sendauth(authopts, s, ticket, service, *ahost, realm, (unsigned long) getpid(), msg_data, cred, schedule, laddr, faddr, "KCMDV0.1")) != KSUCCESS) goto bad2; #endif /* KERBEROS */ (void) write(s, remuser, strlen(remuser)+1); (void) write(s, cmd, strlen(cmd)+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 bad2; } if (c != '\0') { while (read(s, &c, 1) == 1) { (void) write(2, &c, 1); if (c == '\n') break; } status = -1; goto bad2; } sigsetmask(oldmask); *sock = s; return (KSUCCESS); bad2: if (lport) (void) close(*fd2p); bad: (void) close(s); sigsetmask(oldmask); return (status); } int getport(alport) int *alport; { struct sockaddr_in sin; - int s; + int s, retval; - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = INADDR_ANY; s = socket(AF_INET, SOCK_STREAM, 0); + if ((retval = krb_get_local_addr(&sin)) != KSUCCESS) { + fprintf(stderr, "krb_get_local_addr: %s\n",krb_err_txt[retval]); + close(s); + return (-1); + } 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)--; #ifdef ATHENA_COMPAT if (*alport == IPPORT_RESERVED/2) { #else if (*alport == IPPORT_RESERVED) { #endif (void) close(s); errno = EAGAIN; /* close */ return (-1); } } } diff --git a/usr.bin/rlogin/rlogin.c b/usr.bin/rlogin/rlogin.c index 9de1daf3046c..320844f650d5 100644 --- a/usr.bin/rlogin/rlogin.c +++ b/usr.bin/rlogin/rlogin.c @@ -1,949 +1,949 @@ /* * Copyright (c) 1983, 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static char copyright[] = "@(#) Copyright (c) 1983, 1990, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint static char sccsid[] = "@(#)rlogin.c 8.1 (Berkeley) 6/6/93"; #endif /* not lint */ /* * rlogin - remote login */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __STDC__ #include #else #include #endif #ifdef KERBEROS #include #include #include "krb.h" CREDENTIALS cred; Key_schedule schedule; int use_kerberos = 1, doencrypt; char dst_realm_buf[REALM_SZ], *dest_realm = NULL; #endif #ifndef TIOCPKT_WINDOW #define TIOCPKT_WINDOW 0x80 #endif /* concession to Sun */ #ifndef SIGUSR1 #define SIGUSR1 30 #endif int eight, litout, rem; int noescape; u_char escapechar = '~'; char *speeds[] = { "0", "50", "75", "110", "134", "150", "200", "300", "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400", "57600", "115200" }; #ifdef OLDSUN struct winsize { unsigned short ws_row, ws_col; unsigned short ws_xpixel, ws_ypixel; }; #else #define get_window_size(fd, wp) ioctl(fd, TIOCGWINSZ, wp) #endif struct winsize winsize; void catch_child __P((int)); void copytochild __P((int)); __dead void doit __P((long)); __dead void done __P((int)); void echo __P((char)); u_int getescape __P((char *)); void lostpeer __P((int)); void mode __P((int)); void msg __P((char *)); void oob __P((int)); int reader __P((int)); void sendwindow __P((void)); void setsignal __P((int)); void sigwinch __P((int)); void stop __P((char)); __dead void usage __P((void)); void writer __P((void)); void writeroob __P((int)); #ifdef KERBEROS void warning __P((const char *, ...)); #endif #ifdef OLDSUN int get_window_size __P((int, struct winsize *)); #endif int main(argc, argv) int argc; char *argv[]; { extern char *optarg; extern int optind; struct passwd *pw; struct servent *sp; struct sgttyb ttyb; long omask; int argoff, ch, dflag, Dflag, one, uid; char *host, *p, *user, term[1024]; argoff = dflag = Dflag = 0; one = 1; host = user = NULL; if (p = rindex(argv[0], '/')) ++p; else p = argv[0]; if (strcmp(p, "rlogin")) host = p; /* handle "rlogin host flags" */ if (!host && argc > 2 && argv[1][0] != '-') { host = argv[1]; argoff = 1; } #ifdef KERBEROS #define OPTIONS "8DEKLde:k:l:x" #else #define OPTIONS "8DEKLde:l:" #endif while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF) switch(ch) { case '8': eight = 1; break; case 'D': Dflag = 1; break; case 'E': noescape = 1; break; case 'K': #ifdef KERBEROS use_kerberos = 0; #endif break; case 'L': litout = 1; break; case 'd': dflag = 1; break; case 'e': noescape = 0; escapechar = getescape(optarg); break; #ifdef KERBEROS case 'k': dest_realm = dst_realm_buf; (void)strncpy(dest_realm, optarg, REALM_SZ); break; #endif case 'l': user = optarg; break; #ifdef CRYPT #ifdef KERBEROS case 'x': doencrypt = 1; break; #endif #endif case '?': default: usage(); } optind += argoff; argc -= optind; argv += optind; /* if haven't gotten a host yet, do so */ if (!host && !(host = *argv++)) usage(); if (*argv) usage(); if (!(pw = getpwuid(uid = getuid()))) { (void)fprintf(stderr, "rlogin: unknown user id.\n"); exit(1); } if (!user) user = pw->pw_name; sp = NULL; #ifdef KERBEROS if (use_kerberos) { sp = getservbyname((doencrypt ? "eklogin" : "klogin"), "tcp"); if (sp == NULL) { use_kerberos = 0; warning("can't get entry for %s/tcp service", doencrypt ? "eklogin" : "klogin"); } } #endif if (sp == NULL) sp = getservbyname("login", "tcp"); if (sp == NULL) { (void)fprintf(stderr, "rlogin: login/tcp: unknown service.\n"); exit(1); } (void)strcpy(term, (p = getenv("TERM")) ? p : "network"); if (ioctl(0, TIOCGETP, &ttyb) == 0) { (void)strcat(term, "/"); (void)strcat(term, speeds[(int)ttyb.sg_ospeed]); } (void)get_window_size(0, &winsize); (void)signal(SIGPIPE, lostpeer); /* will use SIGUSR1 for window size hack, so hold it off */ omask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1)); /* * We set SIGURG and SIGUSR1 below so that an * incoming signal will be held pending rather than being * discarded. Note that these routines will be ready to get * a signal by the time that they are unblocked below. */ (void)signal(SIGURG, copytochild); (void)signal(SIGUSR1, writeroob); #ifdef KERBEROS try_connect: if (use_kerberos) { struct hostent *hp; /* Fully qualify hostname (needed for krb_realmofhost). */ hp = gethostbyname(host); if (hp != NULL && !(host = strdup(hp->h_name))) { (void)fprintf(stderr, "rlogin: %s\n", strerror(ENOMEM)); exit(1); } rem = KSUCCESS; errno = 0; if (dest_realm == NULL) dest_realm = krb_realmofhost(host); #ifdef CRYPT if (doencrypt) { rem = krcmd_mutual(&host, sp->s_port, user, term, 0, dest_realm, &cred, schedule); - des_set_key(cred.session, schedule); + des_set_key(&cred.session, schedule); } else #endif /* CRYPT */ rem = krcmd(&host, sp->s_port, user, term, 0, dest_realm); if (rem < 0) { use_kerberos = 0; sp = getservbyname("login", "tcp"); if (sp == NULL) { (void)fprintf(stderr, "rlogin: unknown service login/tcp.\n"); exit(1); } if (errno == ECONNREFUSED) warning("remote host doesn't support Kerberos"); if (errno == ENOENT) warning("can't provide Kerberos auth data"); goto try_connect; } } else { #ifdef CRYPT if (doencrypt) { (void)fprintf(stderr, "rlogin: the -x flag requires Kerberos authentication.\n"); exit(1); } #endif /* CRYPT */ rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0); } #else rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0); #endif /* KERBEROS */ if (rem < 0) exit(1); if (dflag && setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0) (void)fprintf(stderr, "rlogin: setsockopt: %s.\n", strerror(errno)); if (Dflag && setsockopt(rem, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)) < 0) perror("rlogin: setsockopt NODELAY (ignored)"); one = IPTOS_LOWDELAY; if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, sizeof(int)) < 0) perror("rlogin: setsockopt TOS (ignored)"); (void)setuid(uid); doit(omask); /*NOTREACHED*/ } int child, defflags, deflflags, tabflag; char deferase, defkill; struct tchars deftc; struct ltchars defltc; struct tchars notc = { -1, -1, -1, -1, -1, -1 }; struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; void doit(omask) long omask; { struct sgttyb sb; (void)ioctl(0, TIOCGETP, (char *)&sb); defflags = sb.sg_flags; tabflag = defflags & TBDELAY; defflags &= ECHO | CRMOD; deferase = sb.sg_erase; defkill = sb.sg_kill; (void)ioctl(0, TIOCLGET, &deflflags); (void)ioctl(0, TIOCGETC, &deftc); notc.t_startc = deftc.t_startc; notc.t_stopc = deftc.t_stopc; (void)ioctl(0, TIOCGLTC, &defltc); (void)signal(SIGINT, SIG_IGN); setsignal(SIGHUP); setsignal(SIGQUIT); child = fork(); if (child == -1) { (void)fprintf(stderr, "rlogin: fork: %s.\n", strerror(errno)); done(1); } if (child == 0) { mode(1); if (reader(omask) == 0) { msg("connection closed."); exit(0); } sleep(1); msg("\007connection closed."); exit(1); } /* * 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. When * one of these comes in, the trap copytochild simply copies such * signals to the child. We can now unblock SIGURG and SIGUSR1 * that were set above. */ (void)sigsetmask(omask); (void)signal(SIGCHLD, catch_child); writer(); msg("closed connection."); done(0); } /* trap a signal, unless it is being ignored. */ void setsignal(sig) int sig; { int omask = sigblock(sigmask(sig)); if (signal(sig, exit) == SIG_IGN) (void)signal(sig, SIG_IGN); (void)sigsetmask(omask); } __dead void done(status) int status; { int w, wstatus; mode(0); if (child > 0) { /* make sure catch_child does not snap it up */ (void)signal(SIGCHLD, SIG_DFL); if (kill(child, SIGKILL) >= 0) while ((w = wait(&wstatus)) > 0 && w != child); } exit(status); } int dosigwinch; /* * This is called when the reader process gets the out-of-band (urgent) * request to turn on the window-changing protocol. */ void writeroob(signo) int signo; { if (dosigwinch == 0) { sendwindow(); (void)signal(SIGWINCH, sigwinch); } dosigwinch = 1; } void catch_child(signo) int signo; { union wait status; int pid; for (;;) { pid = wait3((int *)&status, WNOHANG|WUNTRACED, NULL); if (pid == 0) return; /* if the child (reader) dies, just quit */ if (pid < 0 || (pid == child && !WIFSTOPPED(status))) done((int)(status.w_termsig | status.w_retcode)); } /* NOTREACHED */ } /* * writer: write to remote: 0 -> line. * ~. terminate * ~^Z suspend rlogin process. * ~ suspend rlogin process, but leave reader alone. */ void writer() { register int bol, local, n; char c; bol = 1; /* beginning of line */ local = 0; for (;;) { n = read(STDIN_FILENO, &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 (!noescape && c == escapechar) { local = 1; continue; } } else if (local) { local = 0; if (c == '.' || c == deftc.t_eofc) { echo(c); break; } if (c == defltc.t_suspc || c == defltc.t_dsuspc) { bol = 1; echo(c); stop(c); continue; } if (c != escapechar) #ifdef CRYPT #ifdef KERBEROS if (doencrypt) (void)des_write(rem, (char *)&escapechar, 1); else #endif #endif (void)write(rem, &escapechar, 1); } #ifdef CRYPT #ifdef KERBEROS if (doencrypt) { if (des_write(rem, &c, 1) == 0) { msg("line gone"); break; } } else #endif #endif if (write(rem, &c, 1) == 0) { msg("line gone"); break; } bol = c == defkill || c == deftc.t_eofc || c == deftc.t_intrc || c == defltc.t_suspc || c == '\r' || c == '\n'; } } void #if __STDC__ echo(register char c) #else echo(c) register char c; #endif { register char *p; char buf[8]; p = buf; c &= 0177; *p++ = escapechar; if (c < ' ') { *p++ = '^'; *p++ = c + '@'; } else if (c == 0177) { *p++ = '^'; *p++ = '?'; } else *p++ = c; *p++ = '\r'; *p++ = '\n'; (void)write(STDOUT_FILENO, buf, p - buf); } void #if __STDC__ stop(char cmdc) #else stop(cmdc) char cmdc; #endif { mode(0); (void)signal(SIGCHLD, SIG_IGN); (void)kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP); (void)signal(SIGCHLD, catch_child); mode(1); sigwinch(0); /* check for size changes */ } void sigwinch(signo) int signo; { struct winsize ws; if (dosigwinch && get_window_size(0, &ws) == 0 && bcmp(&ws, &winsize, sizeof(ws))) { winsize = ws; sendwindow(); } } /* * Send the window size to the server via the magic escape */ void sendwindow() { struct winsize *wp; char obuf[4 + sizeof (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); #ifdef CRYPT #ifdef KERBEROS if(doencrypt) (void)des_write(rem, obuf, sizeof(obuf)); else #endif #endif (void)write(rem, obuf, sizeof(obuf)); } /* * reader: read from remote: line -> 1 */ #define READING 1 #define WRITING 2 jmp_buf rcvtop; int ppid, rcvcnt, rcvstate; char rcvbuf[8 * 1024]; void oob(signo) int signo; { struct sgttyb sb; int atmark, n, out, rcvd; char waste[BUFSIZ], mark; out = O_RDWR; rcvd = 0; 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); sb.sg_flags &= ~CBREAK; sb.sg_flags |= RAW; (void)ioctl(0, TIOCSETN, (char *)&sb); notc.t_stopc = -1; notc.t_startc = -1; (void)ioctl(0, TIOCSETC, (char *)¬c); } if (!eight && (mark & TIOCPKT_DOSTOP)) { (void)ioctl(0, TIOCGETP, (char *)&sb); sb.sg_flags &= ~RAW; sb.sg_flags |= CBREAK; (void)ioctl(0, TIOCSETN, (char *)&sb); notc.t_stopc = deftc.t_stopc; notc.t_startc = deftc.t_startc; (void)ioctl(0, TIOCSETC, (char *)¬c); } if (mark & TIOCPKT_FLUSHWRITE) { (void)ioctl(1, TIOCFLUSH, (char *)&out); for (;;) { if (ioctl(rem, SIOCATMARK, &atmark) < 0) { (void)fprintf(stderr, "rlogin: ioctl: %s.\n", strerror(errno)); 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 */ int reader(omask) int omask; { int pid, n, remaining; char *bufp; #if BSD >= 43 || defined(SUNOS4) pid = getpid(); /* modern systems use positives for pid */ #else pid = -getpid(); /* old broken systems use negatives */ #endif (void)signal(SIGTTOU, SIG_IGN); (void)signal(SIGURG, oob); ppid = getppid(); (void)fcntl(rem, F_SETOWN, pid); (void)setjmp(rcvtop); (void)sigsetmask(omask); bufp = rcvbuf; for (;;) { while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) { rcvstate = WRITING; n = write(STDOUT_FILENO, bufp, remaining); if (n < 0) { if (errno != EINTR) return (-1); continue; } bufp += n; } bufp = rcvbuf; rcvcnt = 0; rcvstate = READING; #ifdef CRYPT #ifdef KERBEROS if (doencrypt) rcvcnt = des_read(rem, rcvbuf, sizeof(rcvbuf)); else #endif #endif rcvcnt = read(rem, rcvbuf, sizeof (rcvbuf)); if (rcvcnt == 0) return (0); if (rcvcnt < 0) { if (errno == EINTR) continue; (void)fprintf(stderr, "rlogin: read: %s.\n", strerror(errno)); return (-1); } } } void mode(f) int f; { struct ltchars *ltc; struct sgttyb sb; struct tchars *tc; int lflags; (void)ioctl(0, TIOCGETP, (char *)&sb); (void)ioctl(0, TIOCLGET, (char *)&lflags); switch(f) { case 0: sb.sg_flags &= ~(CBREAK|RAW|TBDELAY); sb.sg_flags |= defflags|tabflag; tc = &deftc; ltc = &defltc; sb.sg_kill = defkill; sb.sg_erase = deferase; lflags = deflflags; break; case 1: sb.sg_flags |= (eight ? RAW : CBREAK); sb.sg_flags &= ~defflags; /* preserve tab delays, but turn off XTABS */ if ((sb.sg_flags & TBDELAY) == XTABS) sb.sg_flags &= ~TBDELAY; tc = ¬c; ltc = &noltc; sb.sg_kill = sb.sg_erase = -1; if (litout) lflags |= LLITOUT; break; default: return; } (void)ioctl(0, TIOCSLTC, (char *)ltc); (void)ioctl(0, TIOCSETC, (char *)tc); (void)ioctl(0, TIOCSETN, (char *)&sb); (void)ioctl(0, TIOCLSET, (char *)&lflags); } void lostpeer(signo) int signo; { (void)signal(SIGPIPE, SIG_IGN); msg("\007connection closed."); done(1); } /* copy SIGURGs to the child process. */ void copytochild(signo) int signo; { (void)kill(child, SIGURG); } void msg(str) char *str; { (void)fprintf(stderr, "rlogin: %s\r\n", str); } #ifdef KERBEROS /* VARARGS */ void #if __STDC__ warning(const char *fmt, ...) #else warning(fmt, va_alist) char *fmt; va_dcl #endif { va_list ap; (void)fprintf(stderr, "rlogin: warning, using standard rlogin: "); #ifdef __STDC__ va_start(ap, fmt); #else va_start(ap); #endif vfprintf(stderr, fmt, ap); va_end(ap); (void)fprintf(stderr, ".\n"); } #endif __dead void usage() { (void)fprintf(stderr, "usage: rlogin [ -%s]%s[-e char] [ -l username ] host\n", #ifdef KERBEROS #ifdef CRYPT "8DEKLx", " [-k realm] "); #else "8DEKL", " [-k realm] "); #endif #else "8DEL", " "); #endif exit(1); } /* * The following routine provides compatibility (such as it is) between older * Suns and others. Suns have only a `ttysize', so we convert it to a winsize. */ #ifdef OLDSUN int get_window_size(fd, wp) int fd; struct winsize *wp; { struct ttysize ts; int error; if ((error = ioctl(0, TIOCGSIZE, &ts)) != 0) return (error); wp->ws_row = ts.ts_lines; wp->ws_col = ts.ts_cols; wp->ws_xpixel = 0; wp->ws_ypixel = 0; return (0); } #endif u_int getescape(p) register char *p; { long val; int len; if ((len = strlen(p)) == 1) /* use any single char, including '\' */ return ((u_int)*p); /* otherwise, \nnn */ if (*p == '\\' && len >= 2 && len <= 4) { val = strtol(++p, NULL, 8); for (;;) { if (!*++p) return ((u_int)val); if (*p < '0' || *p > '8') break; } } msg("illegal option value -- e"); usage(); /* NOTREACHED */ } diff --git a/usr.bin/rsh/rsh.c b/usr.bin/rsh/rsh.c index e2297d568a83..6b6c3966fb9c 100644 --- a/usr.bin/rsh/rsh.c +++ b/usr.bin/rsh/rsh.c @@ -1,478 +1,478 @@ /*- * Copyright (c) 1983, 1990, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static char copyright[] = "@(#) Copyright (c) 1983, 1990, 1993, 1994\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint static char sccsid[] = "From: @(#)rsh.c 8.3 (Berkeley) 4/6/94"; static char rcsid[] = - "$Id: rsh.c,v 1.3 1995/01/14 20:36:22 wollman Exp $"; + "$Id: rsh.c,v 1.4 1995/05/30 06:33:24 rgrimes Exp $"; #endif /* not lint */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pathnames.h" #ifdef KERBEROS #include #include CREDENTIALS cred; Key_schedule schedule; int use_kerberos = 1, doencrypt; char dst_realm_buf[REALM_SZ], *dest_realm; extern char *krb_realmofhost(); #endif /* * rsh - remote shell */ int rfd2; char *copyargs __P((char **)); void sendsig __P((int)); void talk __P((int, long, pid_t, int)); void usage __P((void)); void warning __P(()); int main(argc, argv) int argc; char **argv; { struct passwd *pw; struct servent *sp; long omask; int argoff, asrsh, ch, dflag, nflag, one, rem; pid_t pid; uid_t uid; char *args, *host, *p, *user; argoff = asrsh = dflag = nflag = 0; one = 1; host = user = NULL; /* if called as something other than "rsh", use it as the host name */ if (p = strrchr(argv[0], '/')) ++p; else p = argv[0]; if (strcmp(p, "rsh")) host = p; else asrsh = 1; /* handle "rsh host flags" */ if (!host && argc > 2 && argv[1][0] != '-') { host = argv[1]; argoff = 1; } #ifdef KERBEROS #ifdef CRYPT #define OPTIONS "8KLde:k:l:nwx" #else #define OPTIONS "8KLde:k:l:nw" #endif #else #define OPTIONS "8KLde:l:nw" #endif while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF) switch(ch) { case 'K': #ifdef KERBEROS use_kerberos = 0; #endif break; case 'L': /* -8Lew are ignored to allow rlogin aliases */ case 'e': case 'w': case '8': break; case 'd': dflag = 1; break; case 'l': user = optarg; break; #ifdef KERBEROS case 'k': dest_realm = dst_realm_buf; strncpy(dest_realm, optarg, REALM_SZ); break; #endif case 'n': nflag = 1; break; #ifdef KERBEROS #ifdef CRYPT case 'x': doencrypt = 1; break; #endif #endif case '?': default: usage(); } optind += argoff; /* if haven't gotten a host yet, do so */ if (!host && !(host = argv[optind++])) usage(); /* if no further arguments, must have been called as rlogin. */ if (!argv[optind]) { if (asrsh) *argv = "rlogin"; execv(_PATH_RLOGIN, argv); err(1, "can't exec %s", _PATH_RLOGIN); } argc -= optind; argv += optind; if (!(pw = getpwuid(uid = getuid()))) errx(1, "unknown user id"); if (!user) user = pw->pw_name; #ifdef KERBEROS #ifdef CRYPT /* -x turns off -n */ if (doencrypt) nflag = 0; #endif #endif args = copyargs(argv); sp = NULL; #ifdef KERBEROS if (use_kerberos) { sp = getservbyname((doencrypt ? "ekshell" : "kshell"), "tcp"); if (sp == NULL) { use_kerberos = 0; warning("can't get entry for %s/tcp service", doencrypt ? "ekshell" : "kshell"); } } #endif if (sp == NULL) sp = getservbyname("shell", "tcp"); if (sp == NULL) errx(1, "shell/tcp: unknown service"); #ifdef KERBEROS try_connect: if (use_kerberos) { struct hostent *hp; /* fully qualify hostname (needed for krb_realmofhost) */ hp = gethostbyname(host); if (hp != NULL && !(host = strdup(hp->h_name))) err(1, NULL); rem = KSUCCESS; errno = 0; if (dest_realm == NULL) dest_realm = krb_realmofhost(host); #ifdef CRYPT if (doencrypt) { rem = krcmd_mutual(&host, sp->s_port, user, args, &rfd2, dest_realm, &cred, schedule); - des_set_key(cred.session, schedule); + des_set_key(&cred.session, schedule); } else #endif rem = krcmd(&host, sp->s_port, user, args, &rfd2, dest_realm); if (rem < 0) { use_kerberos = 0; sp = getservbyname("shell", "tcp"); if (sp == NULL) errx(1, "shell/tcp: unknown service"); if (errno == ECONNREFUSED) warning("remote host doesn't support Kerberos"); if (errno == ENOENT) warning("can't provide Kerberos auth data"); goto try_connect; } } else { if (doencrypt) errx(1, "the -x flag requires Kerberos authentication"); rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2); } #else rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2); #endif if (rem < 0) exit(1); if (rfd2 < 0) errx(1, "can't establish stderr"); if (dflag) { if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0) warn("setsockopt"); if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0) warn("setsockopt"); } (void)setuid(uid); omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGTERM)); if (signal(SIGINT, SIG_IGN) != SIG_IGN) (void)signal(SIGINT, sendsig); if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) (void)signal(SIGQUIT, sendsig); if (signal(SIGTERM, SIG_IGN) != SIG_IGN) (void)signal(SIGTERM, sendsig); if (!nflag) { pid = fork(); if (pid < 0) err(1, "fork"); } #ifdef KERBEROS #ifdef CRYPT if (!doencrypt) #endif #endif { (void)ioctl(rfd2, FIONBIO, &one); (void)ioctl(rem, FIONBIO, &one); } talk(nflag, omask, pid, rem); if (!nflag) (void)kill(pid, SIGKILL); exit(0); } void talk(nflag, omask, pid, rem) int nflag; long omask; pid_t pid; int rem; { int cc, wc; fd_set readfrom, ready, rembits; char *bp, buf[BUFSIZ]; if (!nflag && pid == 0) { (void)close(rfd2); reread: errno = 0; if ((cc = read(0, buf, sizeof buf)) <= 0) goto done; bp = buf; rewrite: FD_ZERO(&rembits); FD_SET(rem, &rembits); if (select(16, 0, &rembits, 0, 0) < 0) { if (errno != EINTR) err(1, "select"); goto rewrite; } if (!FD_ISSET(rem, &rembits)) goto rewrite; #ifdef KERBEROS #ifdef CRYPT if (doencrypt) wc = des_write(rem, bp, cc); else #endif #endif wc = write(rem, bp, cc); if (wc < 0) { if (errno == EWOULDBLOCK) goto rewrite; goto done; } bp += wc; cc -= wc; if (cc == 0) goto reread; goto rewrite; done: (void)shutdown(rem, 1); exit(0); } (void)sigsetmask(omask); FD_ZERO(&readfrom); FD_SET(rfd2, &readfrom); FD_SET(rem, &readfrom); do { ready = readfrom; if (select(16, &ready, 0, 0, 0) < 0) { if (errno != EINTR) err(1, "select"); continue; } if (FD_ISSET(rfd2, &ready)) { errno = 0; #ifdef KERBEROS #ifdef CRYPT if (doencrypt) cc = des_read(rfd2, buf, sizeof buf); else #endif #endif cc = read(rfd2, buf, sizeof buf); if (cc <= 0) { if (errno != EWOULDBLOCK) FD_CLR(rfd2, &readfrom); } else (void)write(2, buf, cc); } if (FD_ISSET(rem, &ready)) { errno = 0; #ifdef KERBEROS #ifdef CRYPT if (doencrypt) cc = des_read(rem, buf, sizeof buf); else #endif #endif cc = read(rem, buf, sizeof buf); if (cc <= 0) { if (errno != EWOULDBLOCK) FD_CLR(rem, &readfrom); } else (void)write(1, buf, cc); } } while (FD_ISSET(rfd2, &readfrom) || FD_ISSET(rem, &readfrom)); } void sendsig(sig) int sig; { char signo; signo = sig; #ifdef KERBEROS #ifdef CRYPT if (doencrypt) (void)des_write(rfd2, &signo, 1); else #endif #endif (void)write(rfd2, &signo, 1); } #ifdef KERBEROS /* VARARGS */ void warning(va_alist) va_dcl { va_list ap; char *fmt; (void)fprintf(stderr, "rsh: warning, using standard rsh: "); va_start(ap); fmt = va_arg(ap, char *); vfprintf(stderr, fmt, ap); va_end(ap); (void)fprintf(stderr, ".\n"); } #endif char * copyargs(argv) char **argv; { int cc; char **ap, *args, *p; cc = 0; for (ap = argv; *ap; ++ap) cc += strlen(*ap) + 1; if (!(args = malloc((u_int)cc))) err(1, NULL); for (p = args, ap = argv; *ap; ++ap) { (void)strcpy(p, *ap); for (p = strcpy(p, *ap); *p; ++p); if (ap[1]) *p++ = ' '; } return (args); } void usage() { (void)fprintf(stderr, "usage: rsh [-nd%s]%s[-l login] host [command]\n", #ifdef KERBEROS #ifdef CRYPT "x", " [-k realm] "); #else "", " [-k realm] "); #endif #else "", " "); #endif exit(1); } diff --git a/usr.bin/su/su.c b/usr.bin/su/su.c index e8afb37a5bdc..521d88a730e0 100644 --- a/usr.bin/su/su.c +++ b/usr.bin/su/su.c @@ -1,461 +1,462 @@ /* * Copyright (c) 1988, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static char copyright[] = "@(#) Copyright (c) 1988, 1993, 1994\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint static char sccsid[] = "@(#)su.c 8.3 (Berkeley) 4/2/94"; #endif /* not lint */ #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef SKEY #include #endif #ifdef KERBEROS #include #include #include #define ARGSTR "-Kflm" int use_kerberos = 1; #else #define ARGSTR "-flm" #endif char *ontty __P((void)); int chshell __P((char *)); int main(argc, argv) int argc; char **argv; { extern char **environ; struct passwd *pwd; #ifdef WHEELSU char *targetpass; int iswheelsu; #endif /* WHEELSU */ char *p, **g, *user, *shell, *username, *cleanenv[20], **nargv, **np; struct group *gr; uid_t ruid; int asme, ch, asthem, fastlogin, prio, i; enum { UNSET, YES, NO } iscsh = UNSET; char shellbuf[MAXPATHLEN]; #ifdef WHEELSU iswheelsu = #endif /* WHEELSU */ asme = asthem = fastlogin = 0; user = "root"; while(optind < argc) if((ch = getopt(argc, argv, ARGSTR)) != EOF) switch((char)ch) { #ifdef KERBEROS case 'K': use_kerberos = 0; break; #endif case 'f': fastlogin = 1; break; case '-': case 'l': asme = 0; asthem = 1; break; case 'm': asme = 1; asthem = 0; break; case '?': default: (void)fprintf(stderr, "usage: su [%s] [login]\n", ARGSTR); exit(1); } else { user = argv[optind++]; break; } if((nargv = malloc (sizeof (char *) * (argc + 4))) == NULL) { errx(1, "malloc failure"); } nargv[argc + 3] = NULL; for (i = argc; i >= optind; i--) nargv[i + 3] = argv[i]; np = &nargv[i + 3]; argv += optind; errno = 0; prio = getpriority(PRIO_PROCESS, 0); if (errno) prio = 0; (void)setpriority(PRIO_PROCESS, 0, -2); openlog("su", LOG_CONS, 0); /* get current login name and shell */ ruid = getuid(); username = getlogin(); if (username == NULL || (pwd = getpwnam(username)) == NULL || pwd->pw_uid != ruid) pwd = getpwuid(ruid); if (pwd == NULL) errx(1, "who are you?"); username = strdup(pwd->pw_name); if (username == NULL) err(1, NULL); if (asme) if (pwd->pw_shell && *pwd->pw_shell) shell = strcpy(shellbuf, pwd->pw_shell); else { shell = _PATH_BSHELL; iscsh = NO; } /* get target login information, default to root */ if ((pwd = getpwnam(user)) == NULL) { errx(1, "unknown login: %s", user); } #ifdef WHEELSU targetpass = strdup(pwd->pw_passwd); #endif /* WHEELSU */ if (ruid) { #ifdef KERBEROS if (!use_kerberos || kerberos(username, user, pwd->pw_uid)) #endif { /* only allow those in group zero to su to root. */ if (pwd->pw_uid == 0 && (gr = getgrgid((gid_t)0))) for (g = gr->gr_mem;; ++g) { if (!*g) errx(1, "you are not in the correct group to su %s.", user); if (strcmp(username, *g) == 0) { #ifdef WHEELSU iswheelsu = 1; #endif /* WHEELSU */ break; } } /* if target requires a password, verify it */ if (*pwd->pw_passwd) { #ifdef SKEY #ifdef WHEELSU if (iswheelsu) { pwd = getpwnam(username); } #endif /* WHEELSU */ p = skey_getpass("Password:", pwd, 1); if (!(!strcmp(pwd->pw_passwd, skey_crypt(p, pwd->pw_passwd, pwd, 1)) #ifdef WHEELSU || (iswheelsu && !strcmp(targetpass, crypt(p, targetpass))) #endif /* WHEELSU */ )) { #else p = getpass("Password:"); if (strcmp(pwd->pw_passwd, crypt(p, pwd->pw_passwd))) { #endif fprintf(stderr, "Sorry\n"); syslog(LOG_AUTH|LOG_WARNING, "BAD SU %s to %s%s", username, user, ontty()); exit(1); } #ifdef WHEELSU if (iswheelsu) { pwd = getpwnam(user); } #endif /* WHEELSU */ } if (pwd->pw_expire && time(NULL) >= pwd->pw_expire) { fprintf(stderr, "Sorry - account expired\n"); syslog(LOG_AUTH|LOG_WARNING, "BAD SU %s to %s%s", username, user, ontty()); exit(1); } } } if (asme) { /* if asme and non-standard target shell, must be root */ if (!chshell(pwd->pw_shell) && ruid) errx(1, "permission denied (shell)."); } else if (pwd->pw_shell && *pwd->pw_shell) { shell = pwd->pw_shell; iscsh = UNSET; } else { shell = _PATH_BSHELL; iscsh = NO; } /* if we're forking a csh, we want to slightly muck the args */ if (iscsh == UNSET) { if (p = strrchr(shell, '/')) ++p; else p = shell; if ((iscsh = strcmp(p, "csh") ? NO : YES) == NO) iscsh = strcmp(p, "tcsh") ? NO : YES; } /* set permissions */ if (setgid(pwd->pw_gid) < 0) err(1, "setgid"); if (initgroups(user, pwd->pw_gid)) errx(1, "initgroups failed"); if (setuid(pwd->pw_uid) < 0) err(1, "setuid"); if (!asme) { if (asthem) { p = getenv("TERM"); cleanenv[0] = NULL; environ = cleanenv; (void)setenv("PATH", _PATH_DEFPATH, 1); (void)setenv("TERM", p, 1); if (chdir(pwd->pw_dir) < 0) errx(1, "no directory"); } if (asthem || pwd->pw_uid) (void)setenv("USER", pwd->pw_name, 1); (void)setenv("HOME", pwd->pw_dir, 1); (void)setenv("SHELL", shell, 1); } if (iscsh == YES) { if (fastlogin) *np-- = "-f"; if (asme) *np-- = "-m"; } /* csh strips the first character... */ *np = asthem ? "-su" : iscsh == YES ? "_su" : "su"; if (ruid != 0) syslog(LOG_NOTICE|LOG_AUTH, "%s to %s%s", username, user, ontty()); (void)setpriority(PRIO_PROCESS, 0, prio); execv(shell, np); err(1, "%s", shell); } int chshell(sh) char *sh; { char *cp; while ((cp = getusershell()) != NULL) if (strcmp(cp, sh) == 0) return (1); return (0); } char * ontty() { char *p; static char buf[MAXPATHLEN + 4]; buf[0] = 0; if (p = ttyname(STDERR_FILENO)) snprintf(buf, sizeof(buf), " on %s", p); return (buf); } #ifdef KERBEROS kerberos(username, user, uid) char *username, *user; int uid; { extern char *krb_err_txt[]; KTEXT_ST ticket; AUTH_DAT authdata; struct hostent *hp; char *p; int kerno; u_long faddr; + struct sockaddr_in local_addr; char lrealm[REALM_SZ], krbtkfile[MAXPATHLEN]; char hostname[MAXHOSTNAMELEN], savehost[MAXHOSTNAMELEN]; char *krb_get_phost(); if (krb_get_lrealm(lrealm, 1) != KSUCCESS) return (1); if (koktologin(username, lrealm, user) && !uid) { warnx("kerberos: not in %s's ACL.", user); return (1); } (void)sprintf(krbtkfile, "%s_%s_%d", TKT_ROOT, user, getuid()); (void)setenv("KRBTKFILE", krbtkfile, 1); (void)krb_set_tkt_string(krbtkfile); /* * Set real as well as effective ID to 0 for the moment, * to make the kerberos library do the right thing. */ if (setuid(0) < 0) { warn("setuid"); return (1); } /* * Little trick here -- if we are su'ing to root, * we need to get a ticket for "xxx.root", where xxx represents * the name of the person su'ing. Otherwise (non-root case), * we need to get a ticket for "yyy.", where yyy represents * the name of the person being su'd to, and the instance is null * * We should have a way to set the ticket lifetime, * with a system default for root. */ kerno = krb_get_pw_in_tkt((uid == 0 ? username : user), (uid == 0 ? "root" : ""), lrealm, "krbtgt", lrealm, DEFAULT_TKT_LIFE, 0); if (kerno != KSUCCESS) { if (kerno == KDC_PR_UNKNOWN) { warnx("kerberos: principal unknown: %s.%s@%s", (uid == 0 ? username : user), (uid == 0 ? "root" : ""), lrealm); return (1); } warnx("kerberos: unable to su: %s", krb_err_txt[kerno]); syslog(LOG_NOTICE|LOG_AUTH, "BAD Kerberos SU: %s to %s%s: %s", username, user, ontty(), krb_err_txt[kerno]); return (1); } if (chown(krbtkfile, uid, -1) < 0) { warn("chown"); (void)unlink(krbtkfile); return (1); } (void)setpriority(PRIO_PROCESS, 0, -2); if (gethostname(hostname, sizeof(hostname)) == -1) { warn("gethostname"); dest_tkt(); return (1); } (void)strncpy(savehost, krb_get_phost(hostname), sizeof(savehost)); savehost[sizeof(savehost) - 1] = '\0'; kerno = krb_mk_req(&ticket, "rcmd", savehost, lrealm, 33); if (kerno == KDC_PR_UNKNOWN) { warnx("Warning: TGT not verified."); syslog(LOG_NOTICE|LOG_AUTH, "%s to %s%s, TGT not verified (%s); %s.%s not registered?", username, user, ontty(), krb_err_txt[kerno], "rcmd", savehost); } else if (kerno != KSUCCESS) { warnx("Unable to use TGT: %s", krb_err_txt[kerno]); syslog(LOG_NOTICE|LOG_AUTH, "failed su: %s to %s%s: %s", username, user, ontty(), krb_err_txt[kerno]); dest_tkt(); return (1); } else { - if (!(hp = gethostbyname(hostname))) { - warnx("can't get addr of %s", hostname); + if ((kerno = krb_get_local_addr(&local_addr)) != KSUCCESS) { + warnx("Unable to get our local address: %s", + krb_err_txt[kerno]); dest_tkt(); return (1); } - memmove((char *)&faddr, (char *)hp->h_addr, sizeof(faddr)); - + faddr = local_addr.sin_addr.s_addr; if ((kerno = krb_rd_req(&ticket, "rcmd", savehost, faddr, &authdata, "")) != KSUCCESS) { warnx("kerberos: unable to verify rcmd ticket: %s\n", krb_err_txt[kerno]); syslog(LOG_NOTICE|LOG_AUTH, "failed su: %s to %s%s: %s", username, user, ontty(), krb_err_txt[kerno]); dest_tkt(); return (1); } } return (0); } koktologin(name, realm, toname) char *name, *realm, *toname; { AUTH_DAT *kdata; AUTH_DAT kdata_st; kdata = &kdata_st; memset((char *)kdata, 0, sizeof(*kdata)); (void)strcpy(kdata->pname, name); (void)strcpy(kdata->pinst, ((strcmp(toname, "root") == 0) ? "root" : "")); (void)strcpy(kdata->prealm, realm); return (kuserok(kdata, toname)); } #endif