1/*
2 * Copyright (c) 1995-2004 Kungliga Tekniska H�gskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the Institute nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifdef HAVE_CONFIG_H
35#include <config.h>
36RCSID("$Id: verify.c 14203 2004-09-08 09:02:59Z joda $");
37#endif
38#include <unistd.h>
39#include <sys/types.h>
40#include <pwd.h>
41#ifdef KRB5
42#include <krb5.h>
43#endif
44#ifdef KRB4
45#include <krb.h>
46#include <kafs.h>
47#endif
48#include <roken.h>
49
50#ifdef KRB5
51static char krb5ccname[128];
52#endif
53#ifdef KRB4
54static char krbtkfile[128];
55#endif
56
57/*
58   In some cases is afs_gettktstring called twice (once before
59   afs_verify and once after afs_verify).
60   In some cases (rlogin with access allowed via .rhosts)
61   afs_verify is not called!
62   So we can't rely on correct value in krbtkfile in some
63   cases!
64*/
65
66static int correct_tkfilename=0;
67static int pag_set=0;
68
69#ifdef KRB4
70static void
71set_krbtkfile(uid_t uid)
72{
73    snprintf (krbtkfile, sizeof(krbtkfile), "%s%d", TKT_ROOT, (unsigned)uid);
74    krb_set_tkt_string (krbtkfile);
75    correct_tkfilename = 1;
76}
77#endif
78
79/* XXX this has to be the default cache name, since the KRB5CCNAME
80 * environment variable isn't exported by login/xdm
81 */
82
83#ifdef KRB5
84static void
85set_krb5ccname(uid_t uid)
86{
87    snprintf (krb5ccname, sizeof(krb5ccname), "FILE:/tmp/krb5cc_%d", uid);
88#ifdef KRB4
89    snprintf (krbtkfile, sizeof(krbtkfile), "%s%d", TKT_ROOT, (unsigned)uid);
90#endif
91    correct_tkfilename = 1;
92}
93#endif
94
95static void
96set_spec_krbtkfile(void)
97{
98    int fd;
99#ifdef KRB4
100    snprintf (krbtkfile, sizeof(krbtkfile), "%s_XXXXXX", TKT_ROOT);
101    fd = mkstemp(krbtkfile);
102    close(fd);
103    unlink(krbtkfile);
104    krb_set_tkt_string (krbtkfile);
105#endif
106#ifdef KRB5
107    snprintf(krb5ccname, sizeof(krb5ccname),"FILE:/tmp/krb5cc_XXXXXX");
108    fd=mkstemp(krb5ccname+5);
109    close(fd);
110    unlink(krb5ccname+5);
111#endif
112}
113
114#ifdef KRB5
115static int
116verify_krb5(struct passwd *pwd,
117	    char *password,
118	    int32_t *exp,
119	    int quiet)
120{
121    krb5_context context;
122    krb5_error_code ret;
123    krb5_ccache ccache;
124    krb5_principal principal;
125
126    ret = krb5_init_context(&context);
127    if (ret) {
128	syslog(LOG_AUTH|LOG_DEBUG, "krb5_init_context failed: %d", ret);
129	goto out;
130    }
131
132    ret = krb5_parse_name (context, pwd->pw_name, &principal);
133    if (ret) {
134	syslog(LOG_AUTH|LOG_DEBUG, "krb5_parse_name: %s",
135	       krb5_get_err_text(context, ret));
136	goto out;
137    }
138
139    set_krb5ccname(pwd->pw_uid);
140    ret = krb5_cc_resolve(context, krb5ccname, &ccache);
141    if(ret) {
142	syslog(LOG_AUTH|LOG_DEBUG, "krb5_cc_resolve: %s",
143	       krb5_get_err_text(context, ret));
144	goto out;
145    }
146
147    ret = krb5_verify_user_lrealm(context,
148				  principal,
149				  ccache,
150				  password,
151				  TRUE,
152				  NULL);
153    if(ret) {
154	syslog(LOG_AUTH|LOG_DEBUG, "krb5_verify_user: %s",
155	       krb5_get_err_text(context, ret));
156	goto out;
157    }
158
159    if(chown(krb5_cc_get_name(context, ccache), pwd->pw_uid, pwd->pw_gid)) {
160	syslog(LOG_AUTH|LOG_DEBUG, "chown: %s",
161	       krb5_get_err_text(context, errno));
162	goto out;
163    }
164
165#ifdef KRB4
166    {
167	krb5_realm realm = NULL;
168	krb5_boolean get_v4_tgt;
169
170	krb5_get_default_realm(context, &realm);
171	krb5_appdefault_boolean(context, "afskauthlib",
172				realm,
173				"krb4_get_tickets", FALSE, &get_v4_tgt);
174	if (get_v4_tgt) {
175	    CREDENTIALS c;
176	    krb5_creds mcred, cred;
177
178	    krb5_cc_clear_mcred(&mcred);
179
180	    krb5_make_principal(context, &mcred.server, realm,
181				"krbtgt",
182				realm,
183				NULL);
184	    ret = krb5_cc_retrieve_cred(context, ccache, 0, &mcred, &cred);
185	    if(ret == 0) {
186		ret = krb524_convert_creds_kdc_ccache(context, ccache, &cred, &c);
187		if(ret)
188		    krb5_warn(context, ret, "converting creds");
189		else {
190		    set_krbtkfile(pwd->pw_uid);
191		    tf_setup(&c, c.pname, c.pinst);
192		}
193		memset(&c, 0, sizeof(c));
194		krb5_free_cred_contents(context, &cred);
195	    } else
196		syslog(LOG_AUTH|LOG_DEBUG, "krb5_cc_retrieve_cred: %s",
197		       krb5_get_err_text(context, ret));
198
199	    krb5_free_principal(context, mcred.server);
200	}
201	free (realm);
202	if (!pag_set && k_hasafs()) {
203	    k_setpag();
204	    pag_set = 1;
205	}
206
207	if (pag_set)
208	    krb5_afslog_uid_home(context, ccache, NULL, NULL,
209				 pwd->pw_uid, pwd->pw_dir);
210    }
211#endif
212 out:
213    if(ret && !quiet)
214	printf ("%s\n", krb5_get_err_text (context, ret));
215    return ret;
216}
217#endif
218
219#ifdef KRB4
220static int
221verify_krb4(struct passwd *pwd,
222	    char *password,
223	    int32_t *exp,
224	    int quiet)
225{
226    int ret = 1;
227    char lrealm[REALM_SZ];
228
229    if (krb_get_lrealm (lrealm, 1) != KFAILURE) {
230	set_krbtkfile(pwd->pw_uid);
231	ret = krb_verify_user (pwd->pw_name, "", lrealm, password,
232			       KRB_VERIFY_SECURE, NULL);
233	if (ret == KSUCCESS) {
234	    if (!pag_set && k_hasafs()) {
235		k_setpag ();
236		pag_set = 1;
237            }
238            if (pag_set)
239		krb_afslog_uid_home (0, 0, pwd->pw_uid, pwd->pw_dir);
240	} else if (!quiet)
241	    printf ("%s\n", krb_get_err_text (ret));
242    }
243    return ret;
244}
245#endif
246
247int
248afs_verify(char *name,
249	   char *password,
250	   int32_t *exp,
251	   int quiet)
252{
253    int ret = 1;
254    struct passwd *pwd = k_getpwnam (name);
255
256    if(pwd == NULL)
257	return 1;
258
259    if (!pag_set && k_hasafs()) {
260        k_setpag();
261        pag_set=1;
262    }
263
264    if (ret)
265	ret = unix_verify_user (name, password);
266#ifdef KRB5
267    if (ret)
268	ret = verify_krb5(pwd, password, exp, quiet);
269#endif
270#ifdef KRB4
271    if(ret)
272	ret = verify_krb4(pwd, password, exp, quiet);
273#endif
274    return ret;
275}
276
277char *
278afs_gettktstring (void)
279{
280    char *ptr;
281    struct passwd *pwd;
282
283    if (!correct_tkfilename) {
284	ptr = getenv("LOGNAME");
285	if (ptr != NULL && ((pwd = getpwnam(ptr)) != NULL)) {
286	    set_krb5ccname(pwd->pw_uid);
287#ifdef KRB4
288	    set_krbtkfile(pwd->pw_uid);
289	    if (!pag_set && k_hasafs()) {
290                k_setpag();
291                pag_set=1;
292	    }
293#endif
294	} else {
295	    set_spec_krbtkfile();
296	}
297    }
298#ifdef KRB5
299    esetenv("KRB5CCNAME",krb5ccname,1);
300#endif
301#ifdef KRB4
302    esetenv("KRBTKFILE",krbtkfile,1);
303    return krbtkfile;
304#else
305    return "";
306#endif
307}
308