source: trunk/third/openssh/auth-krb4.c @ 18759

Revision 18759, 10.3 KB checked in by zacheiss, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18758, which included commits to RCS files with non-trunk default branches.
Line 
1/*
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.
23 */
24
25#include "includes.h"
26RCSID("$OpenBSD: auth-krb4.c,v 1.28 2002/09/26 11:38:43 markus Exp $");
27
28#include "ssh.h"
29#include "ssh1.h"
30#include "packet.h"
31#include "xmalloc.h"
32#include "log.h"
33#include "servconf.h"
34#include "uidswap.h"
35#include "auth.h"
36
37#ifdef AFS
38#include "radix.h"
39#endif
40
41#ifdef KRB4
42extern ServerOptions options;
43
44static int
45krb4_init(void *context)
46{
47        static int cleanup_registered = 0;
48        Authctxt *authctxt = (Authctxt *)context;
49        const char *tkt_root = TKT_ROOT;
50        struct stat st;
51        int fd;
52
53        if (!authctxt->krb4_ticket_file) {
54                /* Set unique ticket string manually since we're still root. */
55                authctxt->krb4_ticket_file = xmalloc(MAXPATHLEN);
56#ifdef AFS
57                if (lstat("/ticket", &st) != -1)
58                        tkt_root = "/ticket/";
59#endif /* AFS */
60                snprintf(authctxt->krb4_ticket_file, MAXPATHLEN, "%s%u_%ld",
61                    tkt_root, authctxt->pw->pw_uid, (long)getpid());
62                krb_set_tkt_string(authctxt->krb4_ticket_file);
63        }
64        /* Register ticket cleanup in case of fatal error. */
65        if (!cleanup_registered) {
66                fatal_add_cleanup(krb4_cleanup_proc, authctxt);
67                cleanup_registered = 1;
68        }
69        /* Try to create our ticket file. */
70        if ((fd = mkstemp(authctxt->krb4_ticket_file)) != -1) {
71                close(fd);
72                return (1);
73        }
74        /* Ticket file exists - make sure user owns it (just passed ticket). */
75        if (lstat(authctxt->krb4_ticket_file, &st) != -1) {
76                if (st.st_mode == (S_IFREG | S_IRUSR | S_IWUSR) &&
77                    st.st_uid == authctxt->pw->pw_uid)
78                        return (1);
79        }
80        /* Failure - cancel cleanup function, leaving ticket for inspection. */
81        log("WARNING: bad ticket file %s", authctxt->krb4_ticket_file);
82
83        fatal_remove_cleanup(krb4_cleanup_proc, authctxt);
84        cleanup_registered = 0;
85
86        xfree(authctxt->krb4_ticket_file);
87        authctxt->krb4_ticket_file = NULL;
88
89        return (0);
90}
91
92/*
93 * try krb4 authentication,
94 * return 1 on success, 0 on failure, -1 if krb4 is not available
95 */
96int
97auth_krb4_password(Authctxt *authctxt, const char *password)
98{
99        AUTH_DAT adata;
100        KTEXT_ST tkt;
101        struct hostent *hp;
102        struct passwd *pw;
103        char localhost[MAXHOSTNAMELEN], phost[INST_SZ], realm[REALM_SZ];
104        u_int32_t faddr;
105        int r;
106
107        if ((pw = authctxt->pw) == NULL)
108                return (0);
109
110        /*
111         * Try Kerberos password authentication only for non-root
112         * users and only if Kerberos is installed.
113         */
114        if (pw->pw_uid != 0 && krb_get_lrealm(realm, 1) == KSUCCESS) {
115                /* Set up our ticket file. */
116                if (!krb4_init(authctxt)) {
117                        log("Couldn't initialize Kerberos ticket file for %s!",
118                            pw->pw_name);
119                        goto failure;
120                }
121                /* Try to get TGT using our password. */
122                r = krb_get_pw_in_tkt((char *) pw->pw_name, "", realm,
123                    "krbtgt", realm, DEFAULT_TKT_LIFE, (char *)password);
124                if (r != INTK_OK) {
125                        debug("Kerberos v4 password authentication for %s "
126                            "failed: %s", pw->pw_name, krb_err_txt[r]);
127                        goto failure;
128                }
129                /* Successful authentication. */
130                chown(tkt_string(), pw->pw_uid, pw->pw_gid);
131
132                /*
133                 * Now that we have a TGT, try to get a local
134                 * "rcmd" ticket to ensure that we are not talking
135                 * to a bogus Kerberos server.
136                 */
137                gethostname(localhost, sizeof(localhost));
138                strlcpy(phost, (char *)krb_get_phost(localhost),
139                    sizeof(phost));
140                r = krb_mk_req(&tkt, KRB4_SERVICE_NAME, phost, realm, 33);
141
142                if (r == KSUCCESS) {
143                        if ((hp = gethostbyname(localhost)) == NULL) {
144                                log("Couldn't get local host address!");
145                                goto failure;
146                        }
147                        memmove((void *)&faddr, (void *)hp->h_addr,
148                            sizeof(faddr));
149
150                        /* Verify our "rcmd" ticket. */
151                        r = krb_rd_req(&tkt, KRB4_SERVICE_NAME, phost,
152                            faddr, &adata, "");
153                        if (r == RD_AP_UNDEC) {
154                                /*
155                                 * Probably didn't have a srvtab on
156                                 * localhost. Disallow login.
157                                 */
158                                log("Kerberos v4 TGT for %s unverifiable, "
159                                    "no srvtab installed? krb_rd_req: %s",
160                                    pw->pw_name, krb_err_txt[r]);
161                                goto failure;
162                        } else if (r != KSUCCESS) {
163                                log("Kerberos v4 %s ticket unverifiable: %s",
164                                    KRB4_SERVICE_NAME, krb_err_txt[r]);
165                                goto failure;
166                        }
167                } else if (r == KDC_PR_UNKNOWN) {
168                        /*
169                         * Disallow login if no rcmd service exists, and
170                         * log the error.
171                         */
172                        log("Kerberos v4 TGT for %s unverifiable: %s; %s.%s "
173                            "not registered, or srvtab is wrong?", pw->pw_name,
174                            krb_err_txt[r], KRB4_SERVICE_NAME, phost);
175                        goto failure;
176                } else {
177                        /*
178                         * TGT is bad, forget it. Possibly spoofed!
179                         */
180                        debug("WARNING: Kerberos v4 TGT possibly spoofed "
181                            "for %s: %s", pw->pw_name, krb_err_txt[r]);
182                        goto failure;
183                }
184                /* Authentication succeeded. */
185                return (1);
186        } else
187                /* Logging in as root or no local Kerberos realm. */
188                debug("Unable to authenticate to Kerberos.");
189
190 failure:
191        krb4_cleanup_proc(authctxt);
192
193        if (!options.kerberos_or_local_passwd)
194                return (0);
195
196        /* Fall back to ordinary passwd authentication. */
197        return (-1);
198}
199
200void
201krb4_cleanup_proc(void *context)
202{
203        Authctxt *authctxt = (Authctxt *)context;
204        debug("krb4_cleanup_proc called");
205        if (authctxt->krb4_ticket_file) {
206                (void) dest_tkt();
207                xfree(authctxt->krb4_ticket_file);
208                authctxt->krb4_ticket_file = NULL;
209        }
210}
211
212int
213auth_krb4(Authctxt *authctxt, KTEXT auth, char **client, KTEXT reply)
214{
215        AUTH_DAT adat = {0};
216        Key_schedule schedule;
217        struct sockaddr_in local, foreign;
218        char instance[INST_SZ];
219        socklen_t slen;
220        u_int cksum;
221        int r, s;
222
223        s = packet_get_connection_in();
224
225        slen = sizeof(local);
226        memset(&local, 0, sizeof(local));
227        if (getsockname(s, (struct sockaddr *) & local, &slen) < 0)
228                debug("getsockname failed: %.100s", strerror(errno));
229        slen = sizeof(foreign);
230        memset(&foreign, 0, sizeof(foreign));
231        if (getpeername(s, (struct sockaddr *) & foreign, &slen) < 0) {
232                debug("getpeername failed: %.100s", strerror(errno));
233                fatal_cleanup();
234        }
235        instance[0] = '*';
236        instance[1] = 0;
237
238        /* Get the encrypted request, challenge, and session key. */
239        if ((r = krb_rd_req(auth, KRB4_SERVICE_NAME, instance,
240            0, &adat, ""))) {
241                debug("Kerberos v4 krb_rd_req: %.100s", krb_err_txt[r]);
242                return (0);
243        }
244        des_key_sched((des_cblock *) adat.session, schedule);
245
246        *client = xmalloc(MAX_K_NAME_SZ);
247        (void) snprintf(*client, MAX_K_NAME_SZ, "%s%s%s@%s", adat.pname,
248            *adat.pinst ? "." : "", adat.pinst, adat.prealm);
249
250        /* Check ~/.klogin authorization now. */
251        if (kuserok(&adat, authctxt->user) != KSUCCESS) {
252                log("Kerberos v4 .klogin authorization failed for %s to "
253                    "account %s", *client, authctxt->user);
254                xfree(*client);
255                *client = NULL;
256                return (0);
257        }
258        /* Increment the checksum, and return it encrypted with the
259           session key. */
260        cksum = adat.checksum + 1;
261        cksum = htonl(cksum);
262
263        /* If we can't successfully encrypt the checksum, we send back an
264           empty message, admitting our failure. */
265        if ((r = krb_mk_priv((u_char *) & cksum, reply->dat, sizeof(cksum) + 1,
266            schedule, &adat.session, &local, &foreign)) < 0) {
267                debug("Kerberos v4 mk_priv: (%d) %s", r, krb_err_txt[r]);
268                reply->dat[0] = 0;
269                reply->length = 0;
270        } else
271                reply->length = r;
272
273        /* Clear session key. */
274        memset(&adat.session, 0, sizeof(&adat.session));
275        return (1);
276}
277#endif /* KRB4 */
278
279#ifdef AFS
280int
281auth_krb4_tgt(Authctxt *authctxt, const char *string)
282{
283        CREDENTIALS creds;
284        struct passwd *pw;
285
286        if ((pw = authctxt->pw) == NULL)
287                goto failure;
288
289        temporarily_use_uid(pw);
290
291        if (!radix_to_creds(string, &creds)) {
292                log("Protocol error decoding Kerberos v4 TGT");
293                goto failure;
294        }
295        if (strncmp(creds.service, "", 1) == 0) /* backward compatibility */
296                strlcpy(creds.service, "krbtgt", sizeof creds.service);
297
298        if (strcmp(creds.service, "krbtgt")) {
299                log("Kerberos v4 TGT (%s%s%s@%s) rejected for %s",
300                    creds.pname, creds.pinst[0] ? "." : "", creds.pinst,
301                    creds.realm, pw->pw_name);
302                goto failure;
303        }
304        if (!krb4_init(authctxt))
305                goto failure;
306
307        if (in_tkt(creds.pname, creds.pinst) != KSUCCESS)
308                goto failure;
309
310        if (save_credentials(creds.service, creds.instance, creds.realm,
311            creds.session, creds.lifetime, creds.kvno, &creds.ticket_st,
312            creds.issue_date) != KSUCCESS) {
313                debug("Kerberos v4 TGT refused: couldn't save credentials");
314                goto failure;
315        }
316        /* Successful authentication, passed all checks. */
317        chown(tkt_string(), pw->pw_uid, pw->pw_gid);
318
319        debug("Kerberos v4 TGT accepted (%s%s%s@%s)",
320            creds.pname, creds.pinst[0] ? "." : "", creds.pinst, creds.realm);
321        memset(&creds, 0, sizeof(creds));
322
323        restore_uid();
324
325        return (1);
326
327 failure:
328        krb4_cleanup_proc(authctxt);
329        memset(&creds, 0, sizeof(creds));
330        restore_uid();
331
332        return (0);
333}
334
335int
336auth_afs_token(Authctxt *authctxt, const char *token_string)
337{
338        CREDENTIALS creds;
339        struct passwd *pw;
340        uid_t uid;
341
342        if ((pw = authctxt->pw) == NULL)
343                return (0);
344
345        if (!radix_to_creds(token_string, &creds)) {
346                log("Protocol error decoding AFS token");
347                return (0);
348        }
349        if (strncmp(creds.service, "", 1) == 0) /* backward compatibility */
350                strlcpy(creds.service, "afs", sizeof creds.service);
351
352        if (strncmp(creds.pname, "AFS ID ", 7) == 0)
353                uid = atoi(creds.pname + 7);
354        else
355                uid = pw->pw_uid;
356
357        if (kafs_settoken(creds.realm, uid, &creds)) {
358                log("AFS token (%s@%s) rejected for %s",
359                    creds.pname, creds.realm, pw->pw_name);
360                memset(&creds, 0, sizeof(creds));
361                return (0);
362        }
363        debug("AFS token accepted (%s@%s)", creds.pname, creds.realm);
364        memset(&creds, 0, sizeof(creds));
365
366        return (1);
367}
368#endif /* AFS */
Note: See TracBrowser for help on using the repository browser.