1 /* $Id: auth_krb5.c 7462 2005-12-12 01:06:54Z eagle $
3 ** Check an username and password against Kerberos v5.
5 ** Based on nnrpkrb5auth by Christopher P. Lindsey <lindsey@mallorn.com>
6 ** See <http://www.mallorn.com/tools/nnrpkrb5auth>
8 ** This program takes a username and password pair from nnrpd and checks
9 ** checks their validity against a Kerberos v5 KDC by attempting to obtain a
10 ** TGT. With the -i <instance> command line option, appends /<instance> to
11 ** the username prior to authentication.
13 ** Special thanks to Von Welch <vwelch@vwelch.com> for giving me the initial
14 ** code on which the Kerberos V authentication is based many years ago, and
15 ** for introducing me to Kerberos back in '96.
17 ** Also, thanks to Graeme Mathieson <graeme@mathie.cx> for his inspiration
18 ** through the pamckpasswd program.
24 #ifdef HAVE_ET_COM_ERR_H
25 # include <et/com_err.h>
30 /* krb5_get_in_tkt_with_password is deprecated. */
31 #define KRB5_DEPRECATED 1
34 #include "inn/messages.h"
38 * Default life of the ticket we are getting. Since we are just checking
39 * to see if the user can get one, it doesn't need a long lifetime.
41 #define KRB5_DEFAULT_LIFE 60 * 5 /* 5 minutes */
45 ** Check the username and password by attempting to get a TGT. Returns 1 on
46 ** success and 0 on failure. Errors are reported via com_err.
49 krb5_check_password (char *principal_name, char *password)
51 krb5_context kcontext;
53 krb5_principal user_principal;
54 krb5_data *user_realm;
55 krb5_principal service_principal;
57 krb5_address **addrs = (krb5_address **) NULL; /* Use default */
58 long lifetime = KRB5_DEFAULT_LIFE;
61 /* TGT service name for convenience */
62 krb5_data tgtname = { 0, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME };
64 krb5_preauthtype *preauth = NULL;
68 /* Our return code - 1 is success */
71 /* Initialize our Kerberos state */
72 code = krb5_init_context (&kcontext);
74 com_err (message_program_name, code, "initializing krb5 context");
78 #ifdef HAVE_KRB5_INIT_ETS
79 /* Initialize krb5 error tables */
80 krb5_init_ets (kcontext);
83 /* Get current time */
84 code = krb5_timeofday (kcontext, &now);
86 com_err (message_program_name, code, "getting time of day");
90 /* Set up credentials to be filled in */
91 memset (&creds, 0, sizeof(creds));
93 /* From here on, goto cleanup to exit */
95 /* Parse the username into a krb5 principal */
96 if (!principal_name) {
97 com_err (message_program_name, 0, "passed NULL principal name");
101 code = krb5_parse_name (kcontext, principal_name, &user_principal);
103 com_err (message_program_name, code,
104 "parsing user principal name %.100s", principal_name);
108 creds.client = user_principal;
110 /* Get the user's realm for building service principal */
111 user_realm = krb5_princ_realm (kcontext, user_principal);
114 * Build the service name into a principal. Right now this is
115 * a TGT for the user's realm.
117 code = krb5_build_principal_ext (kcontext,
127 com_err(message_program_name, code, "building service principal name");
131 creds.server = service_principal;
133 creds.times.starttime = 0; /* Now */
134 creds.times.endtime = now + lifetime;
135 creds.times.renew_till = 0; /* Unrenewable */
138 code = krb5_get_in_tkt_with_password (kcontext,
148 /* We are done with password at this point... */
151 /* FAILURE - Parse a few common errors here */
153 case KRB5KRB_AP_ERR_BAD_INTEGRITY:
154 com_err (message_program_name, 0, "bad password for %.100s",
157 case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN:
158 com_err (message_program_name, 0, "unknown user \"%.100s\"",
162 com_err (message_program_name, code,
163 "checking Kerberos password for %.100s", principal_name);
173 krb5_free_cred_contents (kcontext, &creds);
179 main (int argc, char *argv[])
181 struct auth_info *authinfo;
184 message_program_name = "auth_krb5";
186 /* Retrieve the username and passwd from nnrpd. */
187 authinfo = get_auth_info(stdin);
189 /* Must have a username/password, and no '@' in the address. @ checking
190 is there to prevent authentication against another Kerberos realm; there
191 should be a -r <realm> commandline option to make this check unnecessary
193 if (authinfo == NULL)
194 die("no authentication information from nnrpd");
195 if (authinfo->username[0] == '\0')
196 die("null username");
197 if (strchr(authinfo->username, '@') != NULL)
198 die("username contains @, not allowed");
200 /* May need to prepend instance name if -i option was given. */
202 if (argc == 3 && strcmp(argv[1], "-i") == 0) {
203 new_user = concat(authinfo->username, "/", argv[2], (char *) 0);
204 free(authinfo->username);
205 authinfo->username = new_user;
207 die("error parsing command-line options");
211 if (krb5_check_password(authinfo->username, authinfo->password)) {
212 printf("User:%s\r\n", authinfo->username);
215 die("failure validating password");