1 /* kpasswd.c --- verify kerberos passwords.
2 * written by Nat Lanza (magus@cs.cmu.edu) for
3 * xscreensaver, Copyright (c) 1993-2004 Jamie Zawinski <jwz@jwz.org>
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation. No representations are made about the suitability of this
10 * software for any purpose. It is provided "as is" without express or
18 #ifndef NO_LOCKING /* whole file */
27 #include <sys/types.h>
30 /* I'm not sure if this is exactly the right test...
31 Might __APPLE__ be defined if this is apple hardware, but not
34 Thanks to Alexei Kosut <akosut@stanford.edu> for the MacOS X code.
41 #if defined(HAVE_DARWIN)
42 # include <Kerberos/Kerberos.h>
43 #elif defined(HAVE_KERBEROS5)
44 # include <kerberosIV/krb.h>
45 # include <kerberosIV/des.h>
46 #else /* !HAVE_KERBEROS5 (meaning Kerberos 4) */
49 #endif /* !HAVE_KERBEROS5 */
51 #if !defined(VMS) && !defined(HAVE_ADJUNCT_PASSWD)
57 # include <sys/param.h>
58 # if _BSDI_VERSION >= 199608
71 /* The user information we need to store */
73 static KLPrincipal princ;
74 #else /* !HAVE_DARWIN */
75 static char realm[REALM_SZ];
76 static char name[ANAME_SZ];
77 static char inst[INST_SZ];
78 static const char *tk_file;
79 #endif /* !HAVE_DARWIN */
81 /* warning suppression: duplicated in passwd.c */
82 extern Bool kerberos_lock_init (int argc, char **argv, Bool verbose_p);
83 extern Bool kerberos_passwd_valid_p (const char *typed_passwd, Bool verbose_p);
86 /* Called at startup to grab user, instance, and realm information
87 from the user's ticketfile (remember, name.inst@realm). Since we're
88 using tf_get_pname(), this should work even if your kerberos username
89 isn't the same as your local username. We grab the ticket at startup
90 time so that even if your ticketfile dies while the screen's locked
91 we'll still have the information to unlock it.
93 Problems: the password dialog currently displays local username, so if
94 you have some non-standard name/instance when you run xscreensaver,
95 you'll need to remember what it was when unlocking, or else you lose.
97 Also, we use des_string_to_key(), so if you have an AFS password
98 (encrypted with ka_StringToKey()), you'll lose. Get a kerberos password;
101 Like the original lock_init, we return false if something went wrong.
102 We don't use the arguments we're given, though.
105 kerberos_lock_init (int argc, char **argv, Bool verbose_p)
110 return ((klNoErr == (KLCacheHasValidTickets (NULL, kerberosVersion_Any,
111 &found, &princ, NULL)))
114 # else /* !HAVE_DARWIN */
116 /* Perhaps we should be doing it the Mac way (above) all the time?
117 The following code assumes Unix-style file-based Kerberos credentials
118 cache, which Mac OS X doesn't use. But is there any real reason to
119 do it this way at all, even on other Unixen?
123 memset(name, 0, sizeof(name));
124 memset(inst, 0, sizeof(inst));
126 /* find out where the user's keeping his tickets.
127 squirrel it away for later use. */
128 tk_file = tkt_string();
130 /* open ticket file or die trying. */
131 if ((k_errno = tf_init(tk_file, R_TKT_FIL))) {
135 /* same with principal and instance names */
136 if ((k_errno = tf_get_pname(name)) ||
137 (k_errno = tf_get_pinst(inst))) {
141 /* close the ticketfile to release the lock on it. */
144 /* figure out what realm we're authenticated to. this ought
145 to be the local realm, but it pays to be sure. */
146 if ((k_errno = krb_get_tf_realm(tk_file, realm))) {
150 /* last-minute sanity check on what we got. */
151 if ((strlen(name)+strlen(inst)+strlen(realm)+3) >
152 (REALM_SZ + ANAME_SZ + INST_SZ + 3)) {
159 # endif /* !HAVE_DARWIN */
163 /* des_string_to_key() wants this. If C didn't suck, we could have an
164 anonymous function do this. Even a local one. But it does, so here
165 we are. Calling it ive_got_your_local_function_right_here_buddy()
166 would have been rude.
170 key_to_key(char *user, char *instance, char *realm, char *passwd, C_Block key)
172 memcpy(key, passwd, sizeof(des_cblock));
175 #endif /* !HAVE_DARWIN */
177 /* Called to see if the user's typed password is valid. We do this by asking
178 the kerberos server for a ticket and checking to see if it gave us one.
179 We need to move the ticketfile first, or otherwise we end up updating the
180 user's tkfile with new tickets. This would break services like zephyr that
181 like to stay authenticated, and it would screw with AFS authentication at
182 some sites. So, we do a quick, painful hack with a tmpfile.
185 kerberos_passwd_valid_p (const char *typed_passwd, Bool verbose_p)
189 KLAcquireNewInitialTicketsWithPassword (princ, NULL,
190 typed_passwd, NULL));
191 # else /* !HAVE_DARWIN */
193 /* See comments in kerberos_lock_init -- should we do it the Mac Way
201 /* temporarily switch to a new ticketfile.
202 I'm not using tmpnam() because it isn't entirely portable.
203 this could probably be fixed with autoconf. */
204 newtkfile = malloc(80 * sizeof(char));
205 memset(newtkfile, 0, sizeof(newtkfile));
207 sprintf(newtkfile, "/tmp/xscrn-%i.XXXXXX", getpid());
209 if( (fh = mkstemp(newtkfile)) < 0)
214 if( fchmod(fh, 0600) < 0)
221 krb_set_tkt_string(newtkfile);
223 /* encrypt the typed password. if you have an AFS password instead
224 of a kerberos one, you lose *right here*. If you want to use AFS
225 passwords, you can use ka_StringToKey() instead. As always, ymmv. */
226 des_string_to_key(typed_passwd, mitkey);
228 if (krb_get_in_tkt(name, inst, realm, "krbtgt", realm, DEFAULT_TKT_LIFE,
229 key_to_key, NULL, (char *) mitkey) != 0) {
235 /* quickly block out the tempfile and password to prevent snooping,
236 then restore the old ticketfile and cleean up a bit. */
239 krb_set_tkt_string(tk_file);
241 memset(mitkey, 0, sizeof(mitkey));
242 close(fh); /* #### tom: should the file be removed? */
245 /* Did we verify successfully? */
248 # endif /* !HAVE_DARWIN */
251 #endif /* NO_LOCKING -- whole file */