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