summaryrefslogtreecommitdiffstats
path: root/driver/passwd-kerberos.c
blob: 202e0eb10982395a2f1c1186545c55e7ec4da38e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
/* kpasswd.c --- verify kerberos passwords.
 * written by Nat Lanza (magus@cs.cmu.edu) for
 * xscreensaver, Copyright (c) 1993-2004 Jamie Zawinski <jwz@jwz.org>
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation.  No representations are made about the suitability of this
 * software for any purpose.  It is provided "as is" without express or 
 * implied warranty.
 */

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#ifndef NO_LOCKING  /* whole file */

#include <stdlib.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>

/* I'm not sure if this is exactly the right test...
   Might __APPLE__ be defined if this is apple hardware, but not
   an Apple OS?

   Thanks to Alexei Kosut <akosut@stanford.edu> for the MacOS X code.
 */
#ifdef __APPLE__
# define HAVE_DARWIN
#endif


#if defined(HAVE_DARWIN)
# include <Kerberos/Kerberos.h>
#elif defined(HAVE_KERBEROS5)
# include <kerberosIV/krb.h>
# include <kerberosIV/des.h>
#else /* !HAVE_KERBEROS5 (meaning Kerberos 4) */
# include <krb.h>
# include <des.h>
#endif /* !HAVE_KERBEROS5 */

#if !defined(VMS) && !defined(HAVE_ADJUNCT_PASSWD)
# include <pwd.h>
#endif


#ifdef __bsdi__
# include <sys/param.h>
# if _BSDI_VERSION >= 199608
#  define BSD_AUTH
# endif
#endif /* __bsdi__ */

/* blargh */
#undef  Bool
#undef  True
#undef  False
#define Bool  int
#define True  1
#define False 0

/* The user information we need to store */
#ifdef HAVE_DARWIN
 static KLPrincipal princ;
#else /* !HAVE_DARWIN */
 static char realm[REALM_SZ];
 static char  name[ANAME_SZ];
 static char  inst[INST_SZ];
 static const char *tk_file;
#endif /* !HAVE_DARWIN */

/* warning suppression: duplicated in passwd.c */
extern Bool kerberos_lock_init (int argc, char **argv, Bool verbose_p);
extern Bool kerberos_passwd_valid_p (const char *typed_passwd, Bool verbose_p);


/* Called at startup to grab user, instance, and realm information
   from the user's ticketfile (remember, name.inst@realm). Since we're
   using tf_get_pname(), this should work even if your kerberos username
   isn't the same as your local username. We grab the ticket at startup
   time so that even if your ticketfile dies while the screen's locked
   we'll still have the information to unlock it.

   Problems: the password dialog currently displays local username, so if
     you have some non-standard name/instance when you run xscreensaver,
     you'll need to remember what it was when unlocking, or else you lose.

     Also, we use des_string_to_key(), so if you have an AFS password
     (encrypted with ka_StringToKey()), you'll lose. Get a kerberos password;
     it isn't that hard.

   Like the original lock_init, we return false if something went wrong.
   We don't use the arguments we're given, though.
 */
Bool
kerberos_lock_init (int argc, char **argv, Bool verbose_p)
{
# ifdef HAVE_DARWIN

    KLBoolean found;
    return ((klNoErr == (KLCacheHasValidTickets (NULL, kerberosVersion_Any,
                                                 &found, &princ, NULL)))
            && found);

# else /* !HAVE_DARWIN */

    /* Perhaps we should be doing it the Mac way (above) all the time?
       The following code assumes Unix-style file-based Kerberos credentials
       cache, which Mac OS X doesn't use.  But is there any real reason to
       do it this way at all, even on other Unixen?
     */
    int k_errno;
    
    memset(name, 0, sizeof(name));
    memset(inst, 0, sizeof(inst));
    
    /* find out where the user's keeping his tickets.
       squirrel it away for later use. */
    tk_file = tkt_string();

    /* open ticket file or die trying. */
    if ((k_errno = tf_init(tk_file, R_TKT_FIL))) {
	return False;
    }

    /* same with principal and instance names */
    if ((k_errno = tf_get_pname(name)) ||
	(k_errno = tf_get_pinst(inst))) {
	return False;
    }

    /* close the ticketfile to release the lock on it. */
    tf_close();

    /* figure out what realm we're authenticated to. this ought
       to be the local realm, but it pays to be sure. */
    if ((k_errno = krb_get_tf_realm(tk_file, realm))) {
	return False;
    }

    /* last-minute sanity check on what we got. */
    if ((strlen(name)+strlen(inst)+strlen(realm)+3) >
	(REALM_SZ + ANAME_SZ + INST_SZ + 3)) {
	return False;
    }

    /* success */
    return True;

# endif /* !HAVE_DARWIN */
}


/* des_string_to_key() wants this. If C didn't suck, we could have an
   anonymous function do this. Even a local one. But it does, so here
   we are. Calling it ive_got_your_local_function_right_here_buddy()
   would have been rude.
 */
#ifndef HAVE_DARWIN
static int 
key_to_key(char *user, char *instance, char *realm, char *passwd, C_Block key)
{
  memcpy(key, passwd, sizeof(des_cblock));
  return (0);
}
#endif /* !HAVE_DARWIN */

/* Called to see if the user's typed password is valid. We do this by asking
   the kerberos server for a ticket and checking to see if it gave us one.
   We need to move the ticketfile first, or otherwise we end up updating the
   user's tkfile with new tickets. This would break services like zephyr that
   like to stay authenticated, and it would screw with AFS authentication at
   some sites. So, we do a quick, painful hack with a tmpfile.
 */
Bool
kerberos_passwd_valid_p (const char *typed_passwd, Bool verbose_p)
{
# ifdef HAVE_DARWIN
    return (klNoErr ==
            KLAcquireNewInitialTicketsWithPassword (princ, NULL,
                                                    typed_passwd, NULL));
# else /* !HAVE_DARWIN */

    /* See comments in kerberos_lock_init -- should we do it the Mac Way
       on all systems?
     */
    C_Block mitkey;
    Bool success;
    char *newtkfile;
    int fh = -1;

    /* temporarily switch to a new ticketfile.
       I'm not using tmpnam() because it isn't entirely portable.
       this could probably be fixed with autoconf. */
    newtkfile = malloc(80 * sizeof(char));
    memset(newtkfile, 0, sizeof(newtkfile));

    sprintf(newtkfile, "/tmp/xscrn-%i.XXXXXX", getpid());

    if( (fh = mkstemp(newtkfile)) < 0)
    {
        free(newtkfile);
        return(False);
    }
    if( fchmod(fh, 0600) < 0)
    {
        free(newtkfile);
        return(False);
    }


    krb_set_tkt_string(newtkfile);

    /* encrypt the typed password. if you have an AFS password instead
       of a kerberos one, you lose *right here*. If you want to use AFS
       passwords, you can use ka_StringToKey() instead. As always, ymmv. */
    des_string_to_key(typed_passwd, mitkey);

    if (krb_get_in_tkt(name, inst, realm, "krbtgt", realm, DEFAULT_TKT_LIFE,
		       key_to_key, NULL, (char *) mitkey) != 0) {
	success = False;
    } else {
	success = True;
    }

    /* quickly block out the tempfile and password to prevent snooping,
       then restore the old ticketfile and cleean up a bit. */
    
    dest_tkt();
    krb_set_tkt_string(tk_file);
    free(newtkfile);
    memset(mitkey, 0, sizeof(mitkey));
    close(fh); /* #### tom: should the file be removed? */
    

    /* Did we verify successfully? */
    return success;

# endif /* !HAVE_DARWIN */
}

#endif /* NO_LOCKING -- whole file */