1/* MODULE: auth_krb4 */
2
3/* COPYRIGHT
4 * Copyright (c) 1997 Messaging Direct Ltd.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY MESSAGING DIRECT LTD. ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL MESSAGING DIRECT LTD. OR
20 * ITS EMPLOYEES OR AGENTS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
23 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
25 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
26 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
27 * DAMAGE.
28 * END COPYRIGHT */
29
30#ifdef __GNUC__
31#ident "$Id: auth_krb4.c,v 1.9 2006/01/24 00:16:03 snsimon Exp $"
32#endif
33
34/* PUBLIC DEPENDENCIES */
35#include <unistd.h>
36#include "mechanisms.h"
37#include "globals.h"
38#include "cfile.h"
39#include "krbtf.h"
40
41#ifdef AUTH_KRB4
42
43# include <krb.h>
44
45# ifdef WITH_DES
46#  ifdef WITH_SSL_DES
47#   include <openssl/des.h>
48#  else
49#   include <des.h>
50#  endif /* WITH_SSL_DES */
51# endif /* WITH_DES */
52
53#endif /* AUTH_KRB4 */
54
55#include <errno.h>
56#include <stdio.h>
57#include <stdlib.h>
58#include <string.h>
59#include <syslog.h>
60#include <sys/stat.h>
61#include "auth_krb4.h"
62
63#ifdef DEADCODE
64extern int swap_bytes;			/* from libkrb.a   */
65#endif /* DEADCODE */
66/* END PUBLIC DEPENDENCIES */
67
68/* PRIVATE DEPENDENCIES */
69#ifdef AUTH_KRB4
70static char default_realm[REALM_SZ];
71static cfile config = 0;
72static char myhostname[BUFSIZ];    /* Is BUFSIZ right here? */
73static char *srvtabname = "";      /* "" means "system default srvtab" */
74static char *verify_principal = "rcmd"; /* A principal in the default srvtab */
75#endif /* AUTH_KRB4 */
76/* END PRIVATE DEPENDENCIES */
77
78#define TF_NAME_LEN 128
79
80/* Kerberos for Macintosh doesn't define this, so we will. (Thanks Fink!) */
81#ifndef KRB_TICKET_GRANTING_TICKET
82#define KRB_TICKET_GRANTING_TICKET "krbtgt"
83#endif /* !defined(KRB_TICKET_GRANTING_TICKET) */
84
85
86/* FUNCTION: auth_krb4_init */
87
88/* SYNOPSIS
89 * Initialize the Kerberos IV authentication environment.
90 *
91 * krb4 proxy authentication has a side effect of creating a ticket
92 * file for the user we are authenticating. We keep these in a private
93 * directory so as not to override a system ticket file that may be
94 * in use.
95 *
96 * This function tries to create the directory, and initializes the
97 * global variable tf_dir with the pathname of the directory.
98 * END SYNOPSIS */
99
100int					/* R: -1 on failure, else 0 */
101auth_krb4_init (
102  /* PARAMETERS */
103  void					/* no parameters */
104  /* END PARAMETERS */
105  )
106{
107#ifdef AUTH_KRB4
108    /* VARIABLES */
109    int rc;				/* return code holder */
110    char *configname = 0;
111    /* END VARIABLES */
112
113    if (mech_option)
114      configname = mech_option;
115    else if (access(SASLAUTHD_CONF_FILE_DEFAULT, F_OK) == 0)
116      configname = SASLAUTHD_CONF_FILE_DEFAULT;
117
118    if (configname) {
119      char complaint[1024];
120
121      config = cfile_read(configname, complaint, sizeof(complaint));
122      if (!config) {
123	syslog(LOG_ERR, "auth_krb4_init %s", complaint);
124	return -1;
125      }
126    }
127
128    if (config) {
129      srvtabname = cfile_getstring(config, "krb4_srvtab", srvtabname);
130      verify_principal = cfile_getstring(config, "krb4_verify_principal",
131					 verify_principal);
132    }
133
134    if (krbtf_init() == -1) {
135      syslog(LOG_ERR, "auth_krb4_init krbtf_init failed");
136      return -1;
137    }
138
139    rc = krb_get_lrealm(default_realm, 1);
140    if (rc) {
141	syslog(LOG_ERR, "auth_krb4: krb_get_lrealm: %s",
142	       krb_get_err_text(rc));
143	return -1;
144    }
145
146    if (gethostname(myhostname, sizeof(myhostname)) < 0) {
147      syslog(LOG_ERR, "auth_krb4: gethoanem(): %m");
148      return -1;
149    }
150    myhostname[sizeof(myhostname) - 1] = '\0';
151
152    return 0;
153#else /* ! AUTH_KRB4 */
154    return -1;
155#endif /* ! AUTH_KRB4 */
156}
157
158/* END FUNCTION: auth_krb4_init */
159
160/* FUNCTION: auth_krb4 */
161
162/* SYNOPSIS
163 * Authenticate against Kerberos IV.
164 * END SYNOPSIS */
165
166#ifdef AUTH_KRB4
167
168char *					/* R: allocated response string */
169auth_krb4 (
170  /* PARAMETERS */
171  const char *login,			/* I: plaintext authenticator */
172  const char *password,			/* I: plaintext password */
173  const char *service,
174  const char *realm_in
175  /* END PARAMETERS */
176  )
177{
178    /* VARIABLES */
179    char aname[ANAME_SZ];		/* Kerberos principal */
180    const char *realm;		        /* Kerberos realm to authenticate in */
181    int rc;				/* return code */
182    char tf_name[TF_NAME_LEN];		/* Ticket file name */
183    char *instance, *user_specified;
184    KTEXT_ST ticket;
185    AUTH_DAT kdata;
186    /* END VARIABLES */
187
188    /*
189     * Make sure we have a password. If this is NULL the call
190     * to krb_get_pw_in_tkt below would try to prompt for
191     * one interactively.
192     */
193    if (password == NULL) {
194	syslog(LOG_ERR, "auth_krb4: NULL password?");
195	return strdup("NO saslauthd internal error");
196    }
197
198    if (krbtf_name(tf_name, sizeof(tf_name)) != 0) {
199      syslog(LOG_ERR, "auth_krb4: could not generate ticket file name");
200      return strdup("NO saslauthd internal error");
201    }
202    krb_set_tkt_string(tf_name);
203
204    strncpy(aname, login, ANAME_SZ-1);
205    aname[ANAME_SZ-1] = '\0';
206
207    instance = "";
208
209    if (config) {
210      char keyname[1024];
211
212      snprintf(keyname, sizeof(keyname), "krb4_%s_instance", service);
213      instance = cfile_getstring(config, keyname, "");
214    }
215
216    user_specified = strchr(aname, '.');
217    if (user_specified) {
218      if (instance && instance[0]) {
219	/* sysadmin specified a (mandatory) instance */
220	if (strcmp(user_specified + 1, instance)) {
221	  return strdup("NO saslauthd principal name error");
222	}
223	/* nuke instance from "aname"-- matches what's already in "instance" */
224	*user_specified = '\0';
225      } else {
226	/* sysadmin has no preference, so we shift
227	 * instance name from "aname" to "instance"
228	 */
229	*user_specified = '\0';
230	instance = user_specified + 1;
231      }
232    }
233
234    if(realm_in && *realm_in != '\0') {
235	realm = realm_in;
236    } else {
237	realm = default_realm;
238    }
239
240    rc = krb_get_pw_in_tkt(aname, instance, realm,
241			   KRB_TICKET_GRANTING_TICKET,
242			   realm, 1, password);
243
244    if (rc == INTK_BADPW || rc == KDC_PR_UNKNOWN) {
245	return strdup("NO");
246    } else if (rc != KSUCCESS) {
247      syslog(LOG_ERR, "ERROR: auth_krb4: krb_get_pw_in_tkt: %s",
248	     krb_get_err_text(rc));
249
250      return strdup("NO saslauthd internal error");
251    }
252
253    /* if the TGT wasn't spoofed, it should entitle us to an rcmd ticket... */
254    rc = krb_mk_req(&ticket, verify_principal, myhostname, default_realm, 0);
255
256    if (rc != KSUCCESS) {
257      syslog(LOG_ERR, "ERROR: auth_krb4: krb_get_pw_in_tkt: %s",
258	     krb_get_err_text(rc));
259      dest_tkt();
260      return strdup("NO saslauthd internal error");
261    }
262
263    /* .. and that ticket should match our secret host key */
264    rc = krb_rd_req(&ticket, verify_principal, myhostname, 0, &kdata, srvtabname);
265
266    if (rc != RD_AP_OK) {
267      syslog(LOG_ERR, "ERROR: auth_krb4: krb_rd_req:%s",
268	     krb_get_err_text(rc));
269      dest_tkt();
270      return strdup("NO saslauthd internal error");
271    }
272
273    dest_tkt();
274
275    return strdup("OK");
276}
277
278#else /* ! AUTH_KRB4 */
279
280char *
281auth_krb4 (
282  const char *login __attribute__((unused)),
283  const char *password __attribute__((unused)),
284  const char *service __attribute__((unused)),
285  const char *realm __attribute__((unused))
286  )
287{
288    return NULL;
289}
290
291#endif /* ! AUTH_KRB4 */
292
293/* END FUNCTION: auth_krb4 */
294
295/* END MODULE: auth_krb4 */
296