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