blob: 6e8a6bac4959cabf633ec2ae839a4bdd4f9ea8b2 [file] [log] [blame]
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001/*
2
3 auth-kerberos.c
4
5 Dug Song <dugsong@UMICH.EDU>
6
7 Kerberos v4 authentication and ticket-passing routines.
8
Damien Miller68cb7571999-11-08 15:49:41 +11009 $Id: auth-krb4.c,v 1.2 1999/11/08 04:49:41 damien Exp $
Damien Millerd4a8b7e1999-10-27 13:42:43 +100010*/
11
12#include "includes.h"
13#include "packet.h"
14#include "xmalloc.h"
15#include "ssh.h"
16
17#ifdef KRB4
18int ssh_tf_init(uid_t uid)
19{
20 extern char *ticket;
21 char *tkt_root = TKT_ROOT;
22 struct stat st;
23 int fd;
24
25 /* Set unique ticket string manually since we're still root. */
26 ticket = xmalloc(MAXPATHLEN);
27#ifdef AFS
28 if (lstat("/ticket", &st) != -1)
29 tkt_root = "/ticket/";
30#endif /* AFS */
31 snprintf(ticket, MAXPATHLEN, "%s%d_%d", tkt_root, uid, getpid());
32 (void) krb_set_tkt_string(ticket);
33
34 /* Make sure we own this ticket file, and we created it. */
35 if (lstat(ticket, &st) == -1 && errno == ENOENT) {
36 /* good, no ticket file exists. create it. */
37 if ((fd = open(ticket, O_RDWR|O_CREAT|O_EXCL, 0600)) != -1) {
38 close(fd);
39 return 1;
40 }
41 }
42 else {
43 /* file exists. make sure server_user owns it (e.g. just passed ticket),
44 and that it isn't a symlink, and that it is mode 600. */
45 if (st.st_mode == (S_IFREG|S_IRUSR|S_IWUSR) && st.st_uid == uid)
46 return 1;
47 }
48 /* Failure. */
49 log("WARNING: bad ticket file %s", ticket);
50 return 0;
51}
52
53int auth_krb4(const char *server_user, KTEXT auth, char **client)
54{
55 AUTH_DAT adat = { 0 };
56 KTEXT_ST reply;
57 char instance[INST_SZ];
58 int r, s;
59 u_int cksum;
60 Key_schedule schedule;
61 struct sockaddr_in local, foreign;
62
63 s = packet_get_connection_in();
64
65 r = sizeof(local);
66 memset(&local, 0, sizeof(local));
67 if (getsockname(s, (struct sockaddr *) &local, &r) < 0)
68 debug("getsockname failed: %.100s", strerror(errno));
69 r = sizeof(foreign);
70 memset(&foreign, 0, sizeof(foreign));
71 if (getpeername(s, (struct sockaddr *)&foreign, &r) < 0)
72 debug("getpeername failed: %.100s", strerror(errno));
73
74 instance[0] = '*'; instance[1] = 0;
75
76 /* Get the encrypted request, challenge, and session key. */
77 if ((r = krb_rd_req(auth, KRB4_SERVICE_NAME, instance, 0, &adat, ""))) {
78 packet_send_debug("Kerberos V4 krb_rd_req: %.100s", krb_err_txt[r]);
79 return 0;
80 }
81 des_key_sched((des_cblock *)adat.session, schedule);
82
83 *client = xmalloc(MAX_K_NAME_SZ);
84 (void) snprintf(*client, MAX_K_NAME_SZ, "%s%s%s@%s", adat.pname,
85 *adat.pinst ? "." : "", adat.pinst, adat.prealm);
86
87 /* Check ~/.klogin authorization now. */
88 if (kuserok(&adat, (char *)server_user) != KSUCCESS) {
89 packet_send_debug("Kerberos V4 .klogin authorization failed!");
90 log("Kerberos V4 .klogin authorization failed for %s to account %s",
91 *client, server_user);
92 return 0;
93 }
94 /* Increment the checksum, and return it encrypted with the session key. */
95 cksum = adat.checksum + 1;
96 cksum = htonl(cksum);
97
98 /* If we can't successfully encrypt the checksum, we send back an empty
99 message, admitting our failure. */
100 if ((r = krb_mk_priv((u_char *)&cksum, reply.dat, sizeof(cksum)+1,
101 schedule, &adat.session, &local, &foreign)) < 0) {
102 packet_send_debug("Kerberos V4 mk_priv: (%d) %s", r, krb_err_txt[r]);
103 reply.dat[0] = 0;
104 reply.length = 0;
105 }
106 else
107 reply.length = r;
108
109 /* Clear session key. */
110 memset(&adat.session, 0, sizeof(&adat.session));
111
112 packet_start(SSH_SMSG_AUTH_KERBEROS_RESPONSE);
113 packet_put_string((char *) reply.dat, reply.length);
114 packet_send();
115 packet_write_wait();
116 return 1;
117}
118#endif /* KRB4 */
119
120#ifdef AFS
121int auth_kerberos_tgt(struct passwd *pw, const char *string)
122{
123 CREDENTIALS creds;
124 extern char *ticket;
125 int r;
126
127 if (!radix_to_creds(string, &creds)) {
128 log("Protocol error decoding Kerberos V4 tgt");
129 packet_send_debug("Protocol error decoding Kerberos V4 tgt");
130 goto auth_kerberos_tgt_failure;
131 }
132 if (strncmp(creds.service, "", 1) == 0) /* backward compatibility */
133 strlcpy(creds.service, "krbtgt", sizeof creds.service);
134
135 if (strcmp(creds.service, "krbtgt")) {
136 log("Kerberos V4 tgt (%s%s%s@%s) rejected for uid %d",
137 creds.pname, creds.pinst[0] ? "." : "", creds.pinst, creds.realm,
138 pw->pw_uid);
139 packet_send_debug("Kerberos V4 tgt (%s%s%s@%s) rejected for uid %d",
140 creds.pname, creds.pinst[0] ? "." : "", creds.pinst,
141 creds.realm, pw->pw_uid);
142 goto auth_kerberos_tgt_failure;
143 }
144 if (!ssh_tf_init(pw->pw_uid) ||
145 (r = in_tkt(creds.pname, creds.pinst)) ||
146 (r = save_credentials(creds.service, creds.instance, creds.realm,
147 creds.session, creds.lifetime, creds.kvno,
148 &creds.ticket_st, creds.issue_date))) {
149 xfree(ticket);
150 ticket = NULL;
151 packet_send_debug("Kerberos V4 tgt refused: couldn't save credentials");
152 goto auth_kerberos_tgt_failure;
153 }
154 /* Successful authentication, passed all checks. */
155 chown(ticket, pw->pw_uid, pw->pw_gid);
156 packet_send_debug("Kerberos V4 tgt accepted (%s.%s@%s, %s%s%s@%s)",
157 creds.service, creds.instance, creds.realm,
158 creds.pname, creds.pinst[0] ? "." : "",
159 creds.pinst, creds.realm);
160
161 packet_start(SSH_SMSG_SUCCESS);
162 packet_send();
163 packet_write_wait();
164 return 1;
165
166auth_kerberos_tgt_failure:
167 memset(&creds, 0, sizeof(creds));
168 packet_start(SSH_SMSG_FAILURE);
169 packet_send();
170 packet_write_wait();
171 return 0;
172}
173
Damien Miller68cb7571999-11-08 15:49:41 +1100174int auth_afs_token(struct passwd *pw, const char *token_string)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000175{
176 CREDENTIALS creds;
Damien Miller68cb7571999-11-08 15:49:41 +1100177 uid_t uid = pw->pw_uid;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000178
Damien Miller68cb7571999-11-08 15:49:41 +1100179 if (!radix_to_creds(token_string, &creds)) {
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000180 log("Protocol error decoding AFS token");
181 packet_send_debug("Protocol error decoding AFS token");
182 packet_start(SSH_SMSG_FAILURE);
183 packet_send();
184 packet_write_wait();
185 return 0;
186 }
187 if (strncmp(creds.service, "", 1) == 0) /* backward compatibility */
188 strlcpy(creds.service, "afs", sizeof creds.service);
189
190 if (strncmp(creds.pname, "AFS ID ", 7) == 0)
191 uid = atoi(creds.pname + 7);
192
193 if (kafs_settoken(creds.realm, uid, &creds)) {
194 log("AFS token (%s@%s) rejected for uid %d", creds.pname,
195 creds.realm, uid);
196 packet_send_debug("AFS token (%s@%s) rejected for uid %d", creds.pname,
197 creds.realm, uid);
198 packet_start(SSH_SMSG_FAILURE);
199 packet_send();
200 packet_write_wait();
201 return 0;
202 }
203 packet_send_debug("AFS token accepted (%s@%s, %s@%s)", creds.service,
204 creds.realm, creds.pname, creds.realm);
205 packet_start(SSH_SMSG_SUCCESS);
206 packet_send();
207 packet_write_wait();
208 return 1;
209}
210#endif /* AFS */