ca3f13ea889d35b913a6def81b17bfb92ed4eeab
[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
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 #ifdef HAVE_KERBEROS5
31 # include <kerberosIV/krb.h>
32 # include <kerberosIV/des.h>
33 #else /* !HAVE_KERBEROS5 (meaning Kerberos 4) */
34 # include <krb.h>
35 # include <des.h>
36 #endif /* !HAVE_KERBEROS5 */
37
38 #if !defined(VMS) && !defined(HAVE_ADJUNCT_PASSWD)
39 # include <pwd.h>
40 #endif
41
42
43 #ifdef __bsdi__
44 # include <sys/param.h>
45 # if _BSDI_VERSION >= 199608
46 #  define BSD_AUTH
47 # endif
48 #endif /* __bsdi__ */
49
50 /* blargh */
51 #undef  Bool
52 #undef  True
53 #undef  False
54 #define Bool  int
55 #define True  1
56 #define False 0
57
58 /* The user information we need to store */
59 static char realm[REALM_SZ];
60 static char  name[ANAME_SZ];
61 static char  inst[INST_SZ];
62 static char *tk_file;
63
64
65 /* Called at startup to grab user, instance, and realm information
66    from the user's ticketfile (remember, name.inst@realm). Since we're
67    using tf_get_pname(), this should work even if your kerberos username
68    isn't the same as your local username. We grab the ticket at startup
69    time so that even if your ticketfile dies while the screen's locked
70    we'll still have the information to unlock it.
71
72    Problems: the password dialog currently displays local username, so if
73      you have some non-standard name/instance when you run xscreensaver,
74      you'll need to remember what it was when unlocking, or else you lose.
75
76      Also, we use des_string_to_key(), so if you have an AFS password
77      (encrypted with ka_StringToKey()), you'll lose. Get a kerberos password;
78      it isn't that hard.
79
80    Like the original lock_init, we return false if something went wrong.
81    We don't use the arguments we're given, though.
82  */
83 Bool
84 kerberos_lock_init (int argc, char **argv, Bool verbose_p)
85 {
86     int k_errno;
87     
88     memset(name, 0, sizeof(name));
89     memset(inst, 0, sizeof(inst));
90     
91     /* find out where the user's keeping his tickets.
92        squirrel it away for later use. */
93     tk_file = tkt_string();
94
95     /* open ticket file or die trying. */
96     if ((k_errno = tf_init(tk_file, R_TKT_FIL))) {
97         return False;
98     }
99
100     /* same with principal and instance names */
101     if ((k_errno = tf_get_pname(name)) ||
102         (k_errno = tf_get_pinst(inst))) {
103         return False;
104     }
105
106     /* close the ticketfile to release the lock on it. */
107     tf_close();
108
109     /* figure out what realm we're authenticated to. this ought
110        to be the local realm, but it pays to be sure. */
111     if ((k_errno = krb_get_tf_realm(tk_file, realm))) {
112         return False;
113     }
114
115     /* last-minute sanity check on what we got. */
116     if ((strlen(name)+strlen(inst)+strlen(realm)+3) >
117         (REALM_SZ + ANAME_SZ + INST_SZ + 3)) {
118         return False;
119     }
120
121     /* success */
122     return True;
123 }
124
125
126 /* des_string_to_key() wants this. If C didn't suck, we could have an
127    anonymous function do this. Even a local one. But it does, so here
128    we are. Calling it ive_got_your_local_function_right_here_buddy()
129    would have been rude.
130  */
131 static int 
132 key_to_key(char *user, char *instance, char *realm, char *passwd, C_Block key)
133 {
134   memcpy(key, passwd, sizeof(des_cblock));
135   return (0);
136 }
137
138 /* Called to see if the user's typed password is valid. We do this by asking
139    the kerberos server for a ticket and checking to see if it gave us one.
140    We need to move the ticketfile first, or otherwise we end up updating the
141    user's tkfile with new tickets. This would break services like zephyr that
142    like to stay authenticated, and it would screw with AFS authentication at
143    some sites. So, we do a quick, painful hack with a tmpfile.
144  */
145 Bool
146 kerberos_passwd_valid_p (const char *typed_passwd, Bool verbose_p)
147 {
148     C_Block mitkey;
149     Bool success;
150     char *newtkfile;
151
152     /* temporarily switch to a new ticketfile.
153        I'm not using tmpnam() because it isn't entirely portable.
154        this could probably be fixed with autoconf. */
155     newtkfile = malloc(80 * sizeof(char));
156     memset(newtkfile, 0, sizeof(newtkfile));
157
158     sprintf(newtkfile, "/tmp/xscrn-%i", getpid());
159
160     krb_set_tkt_string(newtkfile);
161
162     /* encrypt the typed password. if you have an AFS password instead
163        of a kerberos one, you lose *right here*. If you want to use AFS
164        passwords, you can use ka_StringToKey() instead. As always, ymmv. */
165     des_string_to_key(typed_passwd, mitkey);
166
167     if (krb_get_in_tkt(name, inst, realm, "krbtgt", realm, DEFAULT_TKT_LIFE,
168                        key_to_key, NULL, mitkey) != 0) {
169         success = False;
170     } else {
171         success = True;
172     }
173
174     /* quickly block out the tempfile and password to prevent snooping,
175        then restore the old ticketfile and cleean up a bit. */
176     
177     dest_tkt();
178     krb_set_tkt_string(tk_file);
179     free(newtkfile);
180     memset(mitkey, 0, sizeof(mitkey));
181     
182
183     /* Did we verify successfully? */
184     return success;
185 }
186
187 #endif /* NO_LOCKING -- whole file */