1 /*- 2 * Copyright (c) 1990, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)klogin.c 8.3 (Berkeley) 04/02/94"; 10 #endif /* not lint */ 11 12 #ifdef KERBEROS 13 #include <sys/param.h> 14 #include <sys/syslog.h> 15 #include <kerberosIV/des.h> 16 #include <kerberosIV/krb.h> 17 18 #include <err.h> 19 #include <netdb.h> 20 #include <pwd.h> 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <unistd.h> 25 26 #define INITIAL_TICKET "krbtgt" 27 #define VERIFY_SERVICE "rcmd" 28 29 extern int notickets; 30 extern char *krbtkfile_env; 31 32 /* 33 * Attempt to log the user in using Kerberos authentication 34 * 35 * return 0 on success (will be logged in) 36 * 1 if Kerberos failed (try local password in login) 37 */ 38 int 39 klogin(pw, instance, localhost, password) 40 struct passwd *pw; 41 char *instance, *localhost, *password; 42 { 43 int kerror; 44 AUTH_DAT authdata; 45 KTEXT_ST ticket; 46 struct hostent *hp; 47 unsigned long faddr; 48 char realm[REALM_SZ], savehost[MAXHOSTNAMELEN]; 49 char tkt_location[MAXPATHLEN]; 50 char *krb_get_phost(); 51 52 /* 53 * Root logins don't use Kerberos. 54 * If we have a realm, try getting a ticket-granting ticket 55 * and using it to authenticate. Otherwise, return 56 * failure so that we can try the normal passwd file 57 * for a password. If that's ok, log the user in 58 * without issuing any tickets. 59 */ 60 if (strcmp(pw->pw_name, "root") == 0 || 61 krb_get_lrealm(realm, 0) != KSUCCESS) 62 return (1); 63 64 /* 65 * get TGT for local realm 66 * tickets are stored in a file named TKT_ROOT plus uid 67 * except for user.root tickets. 68 */ 69 70 if (strcmp(instance, "root") != 0) 71 (void)sprintf(tkt_location, "%s%d", TKT_ROOT, pw->pw_uid); 72 else { 73 (void)sprintf(tkt_location, "%s_root_%d", TKT_ROOT, pw->pw_uid); 74 krbtkfile_env = tkt_location; 75 } 76 (void)krb_set_tkt_string(tkt_location); 77 78 /* 79 * Set real as well as effective ID to 0 for the moment, 80 * to make the kerberos library do the right thing. 81 */ 82 if (setuid(0) < 0) { 83 warnx("setuid"); 84 return (1); 85 } 86 kerror = krb_get_pw_in_tkt(pw->pw_name, instance, 87 realm, INITIAL_TICKET, realm, DEFAULT_TKT_LIFE, password); 88 /* 89 * If we got a TGT, get a local "rcmd" ticket and check it so as to 90 * ensure that we are not talking to a bogus Kerberos server. 91 * 92 * There are 2 cases where we still allow a login: 93 * 1: the VERIFY_SERVICE doesn't exist in the KDC 94 * 2: local host has no srvtab, as (hopefully) indicated by a 95 * return value of RD_AP_UNDEC from krb_rd_req(). 96 */ 97 if (kerror != INTK_OK) { 98 if (kerror != INTK_BADPW && kerror != KDC_PR_UNKNOWN) { 99 syslog(LOG_ERR, "Kerberos intkt error: %s", 100 krb_err_txt[kerror]); 101 dest_tkt(); 102 } 103 return (1); 104 } 105 106 if (chown(TKT_FILE, pw->pw_uid, pw->pw_gid) < 0) 107 syslog(LOG_ERR, "chown tkfile (%s): %m", TKT_FILE); 108 109 (void)strncpy(savehost, krb_get_phost(localhost), sizeof(savehost)); 110 savehost[sizeof(savehost)-1] = NULL; 111 112 /* 113 * if the "VERIFY_SERVICE" doesn't exist in the KDC for this host, 114 * still allow login with tickets, but log the error condition. 115 */ 116 117 kerror = krb_mk_req(&ticket, VERIFY_SERVICE, savehost, realm, 33); 118 if (kerror == KDC_PR_UNKNOWN) { 119 syslog(LOG_NOTICE, 120 "warning: TGT not verified (%s); %s.%s not registered, or srvtab is wrong?", 121 krb_err_txt[kerror], VERIFY_SERVICE, savehost); 122 notickets = 0; 123 return (0); 124 } 125 126 if (kerror != KSUCCESS) { 127 warnx("unable to use TGT: (%s)", krb_err_txt[kerror]); 128 syslog(LOG_NOTICE, "unable to use TGT: (%s)", 129 krb_err_txt[kerror]); 130 dest_tkt(); 131 return (1); 132 } 133 134 if (!(hp = gethostbyname(localhost))) { 135 syslog(LOG_ERR, "couldn't get local host address"); 136 dest_tkt(); 137 return (1); 138 } 139 140 memmove((void *)&faddr, (void *)hp->h_addr, sizeof(faddr)); 141 142 kerror = krb_rd_req(&ticket, VERIFY_SERVICE, savehost, faddr, 143 &authdata, ""); 144 145 if (kerror == KSUCCESS) { 146 notickets = 0; 147 return (0); 148 } 149 150 /* undecipherable: probably didn't have a srvtab on the local host */ 151 if (kerror = RD_AP_UNDEC) { 152 syslog(LOG_NOTICE, "krb_rd_req: (%s)\n", krb_err_txt[kerror]); 153 dest_tkt(); 154 return (1); 155 } 156 /* failed for some other reason */ 157 warnx("unable to verify %s ticket: (%s)", VERIFY_SERVICE, 158 krb_err_txt[kerror]); 159 syslog(LOG_NOTICE, "couldn't verify %s ticket: %s", VERIFY_SERVICE, 160 krb_err_txt[kerror]); 161 dest_tkt(); 162 return (1); 163 } 164 #endif 165