Annotation of src/usr.bin/ssh/auth-krb4.c, Revision 1.21
1.1 deraadt 1: /*
1.18 deraadt 2: * Copyright (c) 1999 Dug Song. All rights reserved.
3: *
4: * Redistribution and use in source and binary forms, with or without
5: * modification, are permitted provided that the following conditions
6: * are met:
7: * 1. Redistributions of source code must retain the above copyright
8: * notice, this list of conditions and the following disclaimer.
9: * 2. Redistributions in binary form must reproduce the above copyright
10: * notice, this list of conditions and the following disclaimer in the
11: * documentation and/or other materials provided with the distribution.
12: *
13: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1.10 deraadt 23: */
1.1 deraadt 24:
25: #include "includes.h"
26: #include "packet.h"
27: #include "xmalloc.h"
28: #include "ssh.h"
1.21 ! markus 29: #include "ssh1.h"
1.11 markus 30: #include "servconf.h"
1.1 deraadt 31:
1.21 ! markus 32: RCSID("$OpenBSD: auth-krb4.c,v 1.20 2000/12/19 23:17:54 markus Exp $");
1.15 djm 33:
1.1 deraadt 34: #ifdef KRB4
1.6 markus 35: char *ticket = NULL;
1.11 markus 36:
37: extern ServerOptions options;
38:
39: /*
40: * try krb4 authentication,
41: * return 1 on success, 0 on failure, -1 if krb4 is not available
42: */
43:
1.14 markus 44: int
1.11 markus 45: auth_krb4_password(struct passwd * pw, const char *password)
46: {
47: AUTH_DAT adata;
48: KTEXT_ST tkt;
49: struct hostent *hp;
1.20 markus 50: u_long faddr;
1.11 markus 51: char localhost[MAXHOSTNAMELEN];
52: char phost[INST_SZ];
53: char realm[REALM_SZ];
54: int r;
55:
56: /*
57: * Try Kerberos password authentication only for non-root
58: * users and only if Kerberos is installed.
59: */
60: if (pw->pw_uid != 0 && krb_get_lrealm(realm, 1) == KSUCCESS) {
61:
62: /* Set up our ticket file. */
63: if (!krb4_init(pw->pw_uid)) {
64: log("Couldn't initialize Kerberos ticket file for %s!",
65: pw->pw_name);
66: goto kerberos_auth_failure;
67: }
68: /* Try to get TGT using our password. */
69: r = krb_get_pw_in_tkt((char *) pw->pw_name, "",
70: realm, "krbtgt", realm,
71: DEFAULT_TKT_LIFE, (char *) password);
72: if (r != INTK_OK) {
73: packet_send_debug("Kerberos V4 password "
74: "authentication for %s failed: %s",
75: pw->pw_name, krb_err_txt[r]);
76: goto kerberos_auth_failure;
77: }
78: /* Successful authentication. */
79: chown(tkt_string(), pw->pw_uid, pw->pw_gid);
80:
81: /*
82: * Now that we have a TGT, try to get a local
83: * "rcmd" ticket to ensure that we are not talking
84: * to a bogus Kerberos server.
85: */
86: (void) gethostname(localhost, sizeof(localhost));
87: (void) strlcpy(phost, (char *) krb_get_phost(localhost),
88: INST_SZ);
89: r = krb_mk_req(&tkt, KRB4_SERVICE_NAME, phost, realm, 33);
90:
91: if (r == KSUCCESS) {
92: if (!(hp = gethostbyname(localhost))) {
93: log("Couldn't get local host address!");
94: goto kerberos_auth_failure;
95: }
96: memmove((void *) &faddr, (void *) hp->h_addr,
97: sizeof(faddr));
98:
99: /* Verify our "rcmd" ticket. */
100: r = krb_rd_req(&tkt, KRB4_SERVICE_NAME, phost,
101: faddr, &adata, "");
102: if (r == RD_AP_UNDEC) {
103: /*
104: * Probably didn't have a srvtab on
1.16 provos 105: * localhost. Disallow login.
1.11 markus 106: */
107: log("Kerberos V4 TGT for %s unverifiable, "
108: "no srvtab installed? krb_rd_req: %s",
109: pw->pw_name, krb_err_txt[r]);
1.16 provos 110: goto kerberos_auth_failure;
1.11 markus 111: } else if (r != KSUCCESS) {
112: log("Kerberos V4 %s ticket unverifiable: %s",
113: KRB4_SERVICE_NAME, krb_err_txt[r]);
114: goto kerberos_auth_failure;
115: }
116: } else if (r == KDC_PR_UNKNOWN) {
117: /*
1.16 provos 118: * Disallow login if no rcmd service exists, and
1.11 markus 119: * log the error.
120: */
121: log("Kerberos V4 TGT for %s unverifiable: %s; %s.%s "
122: "not registered, or srvtab is wrong?", pw->pw_name,
123: krb_err_txt[r], KRB4_SERVICE_NAME, phost);
1.16 provos 124: goto kerberos_auth_failure;
1.11 markus 125: } else {
126: /*
127: * TGT is bad, forget it. Possibly spoofed!
128: */
129: packet_send_debug("WARNING: Kerberos V4 TGT "
130: "possibly spoofed for %s: %s",
131: pw->pw_name, krb_err_txt[r]);
132: goto kerberos_auth_failure;
133: }
134:
135: /* Authentication succeeded. */
136: return 1;
137:
138: kerberos_auth_failure:
139: krb4_cleanup_proc(NULL);
140:
141: if (!options.kerberos_or_local_passwd)
142: return 0;
143: } else {
144: /* Logging in as root or no local Kerberos realm. */
145: packet_send_debug("Unable to authenticate to Kerberos.");
146: }
147: /* Fall back to ordinary passwd authentication. */
148: return -1;
149: }
1.6 markus 150:
151: void
152: krb4_cleanup_proc(void *ignore)
1.1 deraadt 153: {
1.9 markus 154: debug("krb4_cleanup_proc called");
155: if (ticket) {
156: (void) dest_tkt();
157: xfree(ticket);
158: ticket = NULL;
159: }
1.6 markus 160: }
161:
1.14 markus 162: int
1.9 markus 163: krb4_init(uid_t uid)
1.6 markus 164: {
1.9 markus 165: static int cleanup_registered = 0;
1.13 markus 166: const char *tkt_root = TKT_ROOT;
1.9 markus 167: struct stat st;
168: int fd;
169:
170: if (!ticket) {
171: /* Set unique ticket string manually since we're still root. */
172: ticket = xmalloc(MAXPATHLEN);
1.1 deraadt 173: #ifdef AFS
1.9 markus 174: if (lstat("/ticket", &st) != -1)
175: tkt_root = "/ticket/";
1.1 deraadt 176: #endif /* AFS */
1.17 deraadt 177: snprintf(ticket, MAXPATHLEN, "%s%u_%d", tkt_root, uid, getpid());
1.9 markus 178: (void) krb_set_tkt_string(ticket);
179: }
180: /* Register ticket cleanup in case of fatal error. */
181: if (!cleanup_registered) {
182: fatal_add_cleanup(krb4_cleanup_proc, NULL);
183: cleanup_registered = 1;
184: }
185: /* Try to create our ticket file. */
186: if ((fd = mkstemp(ticket)) != -1) {
187: close(fd);
188: return 1;
189: }
190: /* Ticket file exists - make sure user owns it (just passed ticket). */
191: if (lstat(ticket, &st) != -1) {
192: if (st.st_mode == (S_IFREG | S_IRUSR | S_IWUSR) &&
193: st.st_uid == uid)
194: return 1;
195: }
196: /* Failure - cancel cleanup function, leaving bad ticket for inspection. */
197: log("WARNING: bad ticket file %s", ticket);
198: fatal_remove_cleanup(krb4_cleanup_proc, NULL);
199: cleanup_registered = 0;
200: xfree(ticket);
201: ticket = NULL;
202:
203: return 0;
1.1 deraadt 204: }
205:
1.14 markus 206: int
1.9 markus 207: auth_krb4(const char *server_user, KTEXT auth, char **client)
1.1 deraadt 208: {
1.9 markus 209: AUTH_DAT adat = {0};
210: KTEXT_ST reply;
211: char instance[INST_SZ];
212: int r, s;
1.12 markus 213: socklen_t slen;
1.9 markus 214: u_int cksum;
215: Key_schedule schedule;
216: struct sockaddr_in local, foreign;
217:
218: s = packet_get_connection_in();
219:
1.12 markus 220: slen = sizeof(local);
1.9 markus 221: memset(&local, 0, sizeof(local));
1.12 markus 222: if (getsockname(s, (struct sockaddr *) & local, &slen) < 0)
1.9 markus 223: debug("getsockname failed: %.100s", strerror(errno));
1.12 markus 224: slen = sizeof(foreign);
1.9 markus 225: memset(&foreign, 0, sizeof(foreign));
1.12 markus 226: if (getpeername(s, (struct sockaddr *) & foreign, &slen) < 0) {
1.9 markus 227: debug("getpeername failed: %.100s", strerror(errno));
228: fatal_cleanup();
229: }
230: instance[0] = '*';
231: instance[1] = 0;
232:
233: /* Get the encrypted request, challenge, and session key. */
234: if ((r = krb_rd_req(auth, KRB4_SERVICE_NAME, instance, 0, &adat, ""))) {
235: packet_send_debug("Kerberos V4 krb_rd_req: %.100s", krb_err_txt[r]);
236: return 0;
237: }
238: des_key_sched((des_cblock *) adat.session, schedule);
239:
240: *client = xmalloc(MAX_K_NAME_SZ);
241: (void) snprintf(*client, MAX_K_NAME_SZ, "%s%s%s@%s", adat.pname,
1.10 deraadt 242: *adat.pinst ? "." : "", adat.pinst, adat.prealm);
1.9 markus 243:
244: /* Check ~/.klogin authorization now. */
245: if (kuserok(&adat, (char *) server_user) != KSUCCESS) {
246: packet_send_debug("Kerberos V4 .klogin authorization failed!");
247: log("Kerberos V4 .klogin authorization failed for %s to account %s",
248: *client, server_user);
249: xfree(*client);
250: return 0;
251: }
252: /* Increment the checksum, and return it encrypted with the
253: session key. */
254: cksum = adat.checksum + 1;
255: cksum = htonl(cksum);
256:
257: /* If we can't successfully encrypt the checksum, we send back an
258: empty message, admitting our failure. */
259: if ((r = krb_mk_priv((u_char *) & cksum, reply.dat, sizeof(cksum) + 1,
1.10 deraadt 260: schedule, &adat.session, &local, &foreign)) < 0) {
1.9 markus 261: packet_send_debug("Kerberos V4 mk_priv: (%d) %s", r, krb_err_txt[r]);
262: reply.dat[0] = 0;
263: reply.length = 0;
264: } else
265: reply.length = r;
266:
267: /* Clear session key. */
268: memset(&adat.session, 0, sizeof(&adat.session));
269:
270: packet_start(SSH_SMSG_AUTH_KERBEROS_RESPONSE);
271: packet_put_string((char *) reply.dat, reply.length);
272: packet_send();
273: packet_write_wait();
274: return 1;
1.1 deraadt 275: }
276: #endif /* KRB4 */
277:
278: #ifdef AFS
1.14 markus 279: int
1.9 markus 280: auth_kerberos_tgt(struct passwd *pw, const char *string)
1.1 deraadt 281: {
1.9 markus 282: CREDENTIALS creds;
283:
1.19 markus 284: if (pw == NULL)
285: goto auth_kerberos_tgt_failure;
1.9 markus 286: if (!radix_to_creds(string, &creds)) {
287: log("Protocol error decoding Kerberos V4 tgt");
288: packet_send_debug("Protocol error decoding Kerberos V4 tgt");
289: goto auth_kerberos_tgt_failure;
290: }
291: if (strncmp(creds.service, "", 1) == 0) /* backward compatibility */
292: strlcpy(creds.service, "krbtgt", sizeof creds.service);
293:
294: if (strcmp(creds.service, "krbtgt")) {
295: log("Kerberos V4 tgt (%s%s%s@%s) rejected for %s", creds.pname,
1.10 deraadt 296: creds.pinst[0] ? "." : "", creds.pinst, creds.realm,
297: pw->pw_name);
1.9 markus 298: packet_send_debug("Kerberos V4 tgt (%s%s%s@%s) rejected for %s",
1.10 deraadt 299: creds.pname, creds.pinst[0] ? "." : "", creds.pinst,
300: creds.realm, pw->pw_name);
1.9 markus 301: goto auth_kerberos_tgt_failure;
302: }
303: if (!krb4_init(pw->pw_uid))
304: goto auth_kerberos_tgt_failure;
305:
306: if (in_tkt(creds.pname, creds.pinst) != KSUCCESS)
307: goto auth_kerberos_tgt_failure;
308:
309: if (save_credentials(creds.service, creds.instance, creds.realm,
1.10 deraadt 310: creds.session, creds.lifetime, creds.kvno,
311: &creds.ticket_st, creds.issue_date) != KSUCCESS) {
1.9 markus 312: packet_send_debug("Kerberos V4 tgt refused: couldn't save credentials");
313: goto auth_kerberos_tgt_failure;
314: }
315: /* Successful authentication, passed all checks. */
316: chown(tkt_string(), pw->pw_uid, pw->pw_gid);
317:
318: packet_send_debug("Kerberos V4 tgt accepted (%s.%s@%s, %s%s%s@%s)",
1.10 deraadt 319: creds.service, creds.instance, creds.realm, creds.pname,
320: creds.pinst[0] ? "." : "", creds.pinst, creds.realm);
1.9 markus 321: memset(&creds, 0, sizeof(creds));
322: packet_start(SSH_SMSG_SUCCESS);
323: packet_send();
324: packet_write_wait();
325: return 1;
326:
327: auth_kerberos_tgt_failure:
328: krb4_cleanup_proc(NULL);
329: memset(&creds, 0, sizeof(creds));
330: packet_start(SSH_SMSG_FAILURE);
331: packet_send();
332: packet_write_wait();
333: return 0;
1.1 deraadt 334: }
335:
1.14 markus 336: int
1.9 markus 337: auth_afs_token(struct passwd *pw, const char *token_string)
1.1 deraadt 338: {
1.9 markus 339: CREDENTIALS creds;
1.19 markus 340: uid_t uid;
1.1 deraadt 341:
1.19 markus 342: if (pw == NULL) {
343: /* XXX fake protocol error */
344: packet_send_debug("Protocol error decoding AFS token");
345: packet_start(SSH_SMSG_FAILURE);
346: packet_send();
347: packet_write_wait();
348: return 0;
349: }
1.9 markus 350: if (!radix_to_creds(token_string, &creds)) {
351: log("Protocol error decoding AFS token");
352: packet_send_debug("Protocol error decoding AFS token");
353: packet_start(SSH_SMSG_FAILURE);
354: packet_send();
355: packet_write_wait();
356: return 0;
357: }
358: if (strncmp(creds.service, "", 1) == 0) /* backward compatibility */
359: strlcpy(creds.service, "afs", sizeof creds.service);
360:
361: if (strncmp(creds.pname, "AFS ID ", 7) == 0)
362: uid = atoi(creds.pname + 7);
1.19 markus 363: else
364: uid = pw->pw_uid;
1.9 markus 365:
366: if (kafs_settoken(creds.realm, uid, &creds)) {
367: log("AFS token (%s@%s) rejected for %s", creds.pname, creds.realm,
368: pw->pw_name);
369: packet_send_debug("AFS token (%s@%s) rejected for %s", creds.pname,
1.10 deraadt 370: creds.realm, pw->pw_name);
1.9 markus 371: memset(&creds, 0, sizeof(creds));
372: packet_start(SSH_SMSG_FAILURE);
373: packet_send();
374: packet_write_wait();
375: return 0;
376: }
377: packet_send_debug("AFS token accepted (%s@%s, %s@%s)", creds.service,
1.10 deraadt 378: creds.realm, creds.pname, creds.realm);
1.9 markus 379: memset(&creds, 0, sizeof(creds));
380: packet_start(SSH_SMSG_SUCCESS);
381: packet_send();
382: packet_write_wait();
383: return 1;
1.1 deraadt 384: }
385: #endif /* AFS */