http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.14.tar.gz
[xscreensaver] / driver / passwd-kerberos.c
1 /* kpasswd.c --- verify kerberos passwords.
2  * written by Nat Lanza (magus@cs.cmu.edu) for
3  * xscreensaver, Copyright (c) 1993-1997, 1998, 2000, 2003
4  *  Jamie Zawinski <jwz@jwz.org>
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that
9  * copyright notice and this permission notice appear in supporting
10  * documentation.  No representations are made about the suitability of this
11  * software for any purpose.  It is provided "as is" without express or 
12  * implied warranty.
13  */
14
15 #ifdef HAVE_CONFIG_H
16 # include "config.h"
17 #endif
18
19 #ifndef NO_LOCKING  /* whole file */
20
21 #include <stdlib.h>
22 #ifdef HAVE_UNISTD_H
23 # include <unistd.h>
24 #endif
25
26 #include <stdio.h>
27 #include <string.h>
28 #include <sys/types.h>
29
30 /* I'm not sure if this is exactly the right test...
31    Might __APPLE__ be defined if this is apple hardware, but not
32    an Apple OS?
33
34    Thanks to Alexei Kosut <akosut@stanford.edu> for the MacOS X code.
35  */
36 #ifdef __APPLE__
37 # define HAVE_DARWIN
38 #endif
39
40
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) */
47 # include <krb.h>
48 # include <des.h>
49 #endif /* !HAVE_KERBEROS5 */
50
51 #if !defined(VMS) && !defined(HAVE_ADJUNCT_PASSWD)
52 # include <pwd.h>
53 #endif
54
55
56 #ifdef __bsdi__
57 # include <sys/param.h>
58 # if _BSDI_VERSION >= 199608
59 #  define BSD_AUTH
60 # endif
61 #endif /* __bsdi__ */
62
63 /* blargh */
64 #undef  Bool
65 #undef  True
66 #undef  False
67 #define Bool  int
68 #define True  1
69 #define False 0
70
71 /* The user information we need to store */
72 #ifdef HAVE_DARWIN
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 char *tk_file;
79 #endif /* !HAVE_DARWIN */
80
81
82 /* Called at startup to grab user, instance, and realm information
83    from the user's ticketfile (remember, name.inst@realm). Since we're
84    using tf_get_pname(), this should work even if your kerberos username
85    isn't the same as your local username. We grab the ticket at startup
86    time so that even if your ticketfile dies while the screen's locked
87    we'll still have the information to unlock it.
88
89    Problems: the password dialog currently displays local username, so if
90      you have some non-standard name/instance when you run xscreensaver,
91      you'll need to remember what it was when unlocking, or else you lose.
92
93      Also, we use des_string_to_key(), so if you have an AFS password
94      (encrypted with ka_StringToKey()), you'll lose. Get a kerberos password;
95      it isn't that hard.
96
97    Like the original lock_init, we return false if something went wrong.
98    We don't use the arguments we're given, though.
99  */
100 Bool
101 kerberos_lock_init (int argc, char **argv, Bool verbose_p)
102 {
103 # ifdef HAVE_DARWIN
104
105     KLBoolean found;
106     return ((klNoErr == (KLCacheHasValidTickets (NULL, kerberosVersion_Any,
107                                                  &found, &princ, NULL)))
108             && found);
109
110 # else /* !HAVE_DARWIN */
111
112     /* Perhaps we should be doing it the Mac way (above) all the time?
113        The following code assumes Unix-style file-based Kerberos credentials
114        cache, which Mac OS X doesn't use.  But is there any real reason to
115        do it this way at all, even on other Unixen?
116      */
117     int k_errno;
118     
119     memset(name, 0, sizeof(name));
120     memset(inst, 0, sizeof(inst));
121     
122     /* find out where the user's keeping his tickets.
123        squirrel it away for later use. */
124     tk_file = tkt_string();
125
126     /* open ticket file or die trying. */
127     if ((k_errno = tf_init(tk_file, R_TKT_FIL))) {
128         return False;
129     }
130
131     /* same with principal and instance names */
132     if ((k_errno = tf_get_pname(name)) ||
133         (k_errno = tf_get_pinst(inst))) {
134         return False;
135     }
136
137     /* close the ticketfile to release the lock on it. */
138     tf_close();
139
140     /* figure out what realm we're authenticated to. this ought
141        to be the local realm, but it pays to be sure. */
142     if ((k_errno = krb_get_tf_realm(tk_file, realm))) {
143         return False;
144     }
145
146     /* last-minute sanity check on what we got. */
147     if ((strlen(name)+strlen(inst)+strlen(realm)+3) >
148         (REALM_SZ + ANAME_SZ + INST_SZ + 3)) {
149         return False;
150     }
151
152     /* success */
153     return True;
154
155 # endif /* !HAVE_DARWIN */
156 }
157
158
159 /* des_string_to_key() wants this. If C didn't suck, we could have an
160    anonymous function do this. Even a local one. But it does, so here
161    we are. Calling it ive_got_your_local_function_right_here_buddy()
162    would have been rude.
163  */
164 #ifndef HAVE_DARWIN
165 static int 
166 key_to_key(char *user, char *instance, char *realm, char *passwd, C_Block key)
167 {
168   memcpy(key, passwd, sizeof(des_cblock));
169   return (0);
170 }
171 #endif /* !HAVE_DARWIN */
172
173 /* Called to see if the user's typed password is valid. We do this by asking
174    the kerberos server for a ticket and checking to see if it gave us one.
175    We need to move the ticketfile first, or otherwise we end up updating the
176    user's tkfile with new tickets. This would break services like zephyr that
177    like to stay authenticated, and it would screw with AFS authentication at
178    some sites. So, we do a quick, painful hack with a tmpfile.
179  */
180 Bool
181 kerberos_passwd_valid_p (const char *typed_passwd, Bool verbose_p)
182 {
183 # ifdef HAVE_DARWIN
184     return (klNoErr ==
185             KLAcquireNewInitialTicketsWithPassword (princ, NULL,
186                                                     typed_passwd, NULL));
187 # else /* !HAVE_DARWIN */
188
189     /* See comments in kerberos_lock_init -- should we do it the Mac Way
190        on all systems?
191      */
192     C_Block mitkey;
193     Bool success;
194     char *newtkfile;
195
196     /* temporarily switch to a new ticketfile.
197        I'm not using tmpnam() because it isn't entirely portable.
198        this could probably be fixed with autoconf. */
199     newtkfile = malloc(80 * sizeof(char));
200     memset(newtkfile, 0, sizeof(newtkfile));
201
202     sprintf(newtkfile, "/tmp/xscrn-%i", getpid());
203
204     krb_set_tkt_string(newtkfile);
205
206     /* encrypt the typed password. if you have an AFS password instead
207        of a kerberos one, you lose *right here*. If you want to use AFS
208        passwords, you can use ka_StringToKey() instead. As always, ymmv. */
209     des_string_to_key(typed_passwd, mitkey);
210
211     if (krb_get_in_tkt(name, inst, realm, "krbtgt", realm, DEFAULT_TKT_LIFE,
212                        key_to_key, NULL, mitkey) != 0) {
213         success = False;
214     } else {
215         success = True;
216     }
217
218     /* quickly block out the tempfile and password to prevent snooping,
219        then restore the old ticketfile and cleean up a bit. */
220     
221     dest_tkt();
222     krb_set_tkt_string(tk_file);
223     free(newtkfile);
224     memset(mitkey, 0, sizeof(mitkey));
225     
226
227     /* Did we verify successfully? */
228     return success;
229
230 # endif /* !HAVE_DARWIN */
231 }
232
233 #endif /* NO_LOCKING -- whole file */