source: trunk/athena/bin/rkinit/rkinitd/krb.c @ 6602

Revision 6602, 9.1 KB checked in by miki, 32 years ago (diff)
ported to Solaris2.1
Line 
1/*
2 * $Id: krb.c,v 1.5 1993-04-30 18:10:01 miki Exp $
3 * $Source: /afs/dev.mit.edu/source/repository/athena/bin/rkinit/rkinitd/krb.c,v $
4 * $Author: miki $
5 *
6 * This file contains all of the kerberos part of rkinitd.
7 */
8
9#if !defined(lint) && !defined(SABER) && !defined(LOCORE) && defined(RCS_HDRS)
10static char *rcsid = "$Id: krb.c,v 1.5 1993-04-30 18:10:01 miki Exp $";
11#endif /* lint || SABER || LOCORE || RCS_HDRS */
12
13#include <stdio.h>
14#include <sys/types.h>
15#include <errno.h>
16#include <syslog.h>
17#include <netinet/in.h>
18#include <setjmp.h>
19#ifdef SYSV
20#include <netdb.h>
21#endif
22#include <pwd.h>
23#include <krb.h>
24#include <des.h>
25
26#include <rkinit.h>
27#include <rkinit_private.h>
28#include <rkinit_err.h>
29
30#include "rkinitd.h"
31
32#define FAILURE (!RKINIT_SUCCESS)
33
34extern int errno;
35extern char *sys_errlist[];
36
37static char errbuf[BUFSIZ];
38
39typedef struct {
40    jmp_buf env;
41} rkinitd_intkt_info;
42
43
44#if defined(_AIX) && defined(_IBMR2)
45
46#include <sys/id.h>
47
48/*
49 * The RIOS has bizzarre ideas about changing uids around.  They are
50 * such that the seteuid and setruid calls here fail.  For this reason
51 * we are replacing the seteuid and setruid calls.
52 *
53 * The bizzarre ideas are as follows:
54 *
55 * The effective ID may be changed only to the current real or
56 * saved IDs.
57 *
58 * The saved uid may be set only if the real and effective
59 * uids are being set to the same value.
60 *
61 * The real uid may be set only if the effective
62 * uid is being set to the same value.
63 */
64
65#ifdef __STDC__
66static int setruid(uid_t ruid)
67#else
68static int setruid(ruid)
69  uid_t ruid;
70#endif /* __STDC__ */
71{
72    uid_t euid;
73
74    euid = geteuid();
75
76    if (setuidx(ID_REAL | ID_EFFECTIVE, ruid) == -1)
77        return (-1);
78   
79    return (setuidx(ID_EFFECTIVE, euid));
80}
81
82
83#ifdef __STDC__
84static int seteuid(uid_t euid)
85#else
86static int seteuid(euid)
87  uid_t euid;
88#endif /* __STDC__ */
89{
90    uid_t ruid;
91
92    ruid = getuid();
93
94    if (setuidx(ID_SAVED | ID_REAL | ID_EFFECTIVE, euid) == -1)
95        return (-1);
96   
97    return (setruid(ruid));
98}
99
100
101#ifdef __STDC__
102static int setreuid(uid_t ruid, uid_t euid)
103#else
104static int setreuid(ruid, euid)
105  uid_t ruid;
106  uid_t euid;
107#endif /* __STDC__ */
108{
109    if (seteuid(euid) == -1)
110        return (-1);
111
112    return (setruid(ruid));
113}
114
115
116#ifdef __STDC__
117static int setuid(uid_t uid)
118#else
119static int setuid(uid)
120  uid_t uid;
121#endif /* __STDC__ */
122{
123    return (setreuid(uid, uid));
124}
125
126#endif /* RIOS */
127
128
129#ifdef __STDC__
130static void this_phost(char *host, int hostlen)
131#else
132static void this_phost(host, hostlen)
133  char *host;
134  int hostlen;
135#endif /* __STDC__ */
136{
137    char this_host[MAXHOSTNAMELEN + 1];
138
139    BCLEAR(this_host);
140   
141    if (gethostname(this_host, sizeof(this_host)) < 0) {
142        sprintf(errbuf, "gethostname: %s", sys_errlist[errno]);
143        rkinit_errmsg(errbuf);
144        error();
145        exit(1);
146    }
147
148    strncpy(host, krb_get_phost(this_host), hostlen - 1);
149}
150
151#ifdef __STDC__
152static int decrypt_tkt(char *user, char *instance, char *realm, char *arg,
153                       int (*key_proc)(), KTEXT *cipp)
154#else
155static int decrypt_tkt(user, instance, realm, arg, key_proc, cipp)
156  char *user;
157  char *instance;
158  char *realm;
159  char *arg;
160  int (*key_proc)();
161  KTEXT *cipp;
162#endif /* __STDC__ */
163{
164    MSG_DAT msg_data;           /* Message data containing decrypted data */
165    KTEXT_ST auth;              /* Authenticator */
166    AUTH_DAT auth_dat;          /* Authentication data */
167    KTEXT cip = *cipp;
168    MSG_DAT scip;
169    int status = 0;
170    des_cblock key;
171    des_key_schedule sched;
172    char phost[MAXHOSTNAMELEN + 1];
173    struct sockaddr_in caddr;   /* client internet address */
174    struct sockaddr_in saddr;   /* server internet address */
175
176    rkinitd_intkt_info *rii = (rkinitd_intkt_info *)arg;
177
178    u_char enc_data[MAX_KTXT_LEN];
179
180    SBCLEAR(auth);
181    SBCLEAR(auth_dat);
182    SBCLEAR(scip);
183    BCLEAR(enc_data);
184
185    scip.app_data = enc_data;
186
187    /*
188     * Exchange with the client our response from the KDC (ticket encrypted
189     * in user's private key) for the same ticket encrypted in our
190     * (not yet known) session key.
191     */
192
193    rpc_exchange_tkt(cip, &scip);
194
195    /*
196     * Get the authenticator
197     */
198
199    SBCLEAR(auth);
200
201    rpc_getauth(&auth, &caddr, &saddr);
202
203    /*
204     * Decode authenticator and extract session key.  The first zero
205     * means we don't care what host this comes from.  This needs to
206     * be done with euid of root so that /etc/srvtab can be read.
207     */
208
209    BCLEAR(phost);
210    this_phost(phost, sizeof(phost));
211
212    /*
213     * This function has to use longjmp to return to the caller
214     * because the kerberos library routine that calls it doesn't
215     * pay attention to the return value it gives.  That means that
216     * if any of these routines failed, the error returned to the client
217     * would be "password incorrect".
218     */
219
220    if (status = krb_rd_req(&auth, KEY, phost, caddr.sin_addr.s_addr,
221                            &auth_dat, KEYFILE)) {
222        sprintf(errbuf, "krb_rd_req: %s", krb_err_txt[status]);
223        rkinit_errmsg(errbuf);
224        longjmp(rii->env, status);
225    }
226
227    bcopy(auth_dat.session, key, sizeof(key));
228    if (des_key_sched(key, sched)) {
229        sprintf(errbuf, "Error in des_key_sched");
230        rkinit_errmsg(errbuf);
231        longjmp(rii->env, RKINIT_DES);
232    }
233
234    /* Decrypt the data. */
235    if ((status =
236         krb_rd_priv((u_char *)scip.app_data, scip.app_length,
237                     sched, key, &caddr, &saddr, &msg_data)) == KSUCCESS) {
238        cip->length = msg_data.app_length;
239        bcopy(msg_data.app_data, cip->dat, msg_data.app_length);
240        cip->dat[cip->length] = 0;
241    }
242    else {
243        sprintf(errbuf, "krb_rd_priv: %s", krb_err_txt[status]);
244        rkinit_errmsg(errbuf);
245        longjmp(rii->env, status);
246    }
247   
248    return(status);
249}
250
251#ifdef __STDC__
252static int validate_user(char *aname, char *inst, char *realm,
253                         char *username, char *errmsg)
254#else
255static int validate_user(aname, inst, realm, username, errmsg)
256  char *aname;
257  char *inst;
258  char *realm;
259  char *username;
260  char *errmsg;
261#endif /* __STDC__ */
262{
263    struct passwd *pwnam;       /* For access_check and uid */
264    AUTH_DAT auth_dat;
265    int kstatus = KSUCCESS;
266
267    SBCLEAR(auth_dat);
268
269    if ((pwnam = getpwnam(username)) == NULL) {
270        sprintf(errmsg, "%s does not exist on the remote host.", username);
271        return(FAILURE);
272    }
273
274    strcpy(auth_dat.pname, aname);
275    strcpy(auth_dat.pinst, inst);
276    strcpy(auth_dat.prealm, realm);
277
278    if (seteuid(pwnam->pw_uid) < 0) {
279        sprintf(errmsg, "Failure setting euid to %d: %s\n", pwnam->pw_uid,
280                sys_errlist[errno]);
281        strcpy(errbuf, errmsg);
282        error();
283        return(FAILURE);
284    }
285    kstatus = kuserok(&auth_dat, username);
286    if (seteuid(0) < 0) {
287        sprintf(errmsg, "Failure setting euid to 0: %s\n",
288                sys_errlist[errno]);
289        strcpy(errbuf, errmsg);
290        error();
291        return(FAILURE);
292    }
293   
294    if (kstatus != KSUCCESS) {
295        sprintf(errmsg, "%s has not allowed you to log in with", username);
296        if (strlen(auth_dat.pinst))
297            sprintf(errmsg, "%s %s.%s", errmsg, auth_dat.pname,
298                    auth_dat.pinst);
299        else
300            sprintf(errmsg, "%s %s", errmsg, auth_dat.pname);
301        sprintf(errmsg, "%s@%s tickets.", errmsg, auth_dat.prealm);
302        return(FAILURE);
303    }
304   
305    /*
306     * Set real uid to owner of ticket file.  The library takes care
307     * of making the appropriate change.
308     */
309#ifdef SOLARIS
310    if (setreuid(pwnam->pw_uid) < 0) {
311#else
312    if (setruid(pwnam->pw_uid) < 0) {
313#endif
314        sprintf(errmsg, "Failure setting ruid to %d: %s\n", pwnam->pw_uid,
315                sys_errlist[errno]);
316        strcpy(errbuf, errmsg);
317        error();
318        return(FAILURE);
319    }
320       
321    return(RKINIT_SUCCESS);
322}
323
324#ifdef __STDC__
325int get_tickets(int version)
326#else
327int get_tickets(version)
328  int version;
329#endif /* __STDC__ */
330{
331    rkinit_info info;
332    AUTH_DAT auth_dat;
333
334    int status;
335    char errmsg[BUFSIZ];        /* error message for client */
336
337    rkinitd_intkt_info rii;
338
339    SBCLEAR(info);
340    SBCLEAR(auth_dat);
341    BCLEAR(errmsg);
342    SBCLEAR(rii);
343
344    rpc_get_rkinit_info(&info);
345
346    /*
347     * The validate_user routine makes sure that the principal in question
348     * is allowed to log in as username, and if so, does a setuid(localuid).
349     * If there is an access violation or an error in setting the uid,
350     * an error is returned and the string errmsg is initialized with
351     * an error message that will be sent back to the client.
352     */
353    if ((status = validate_user(info.aname, info.inst, info.realm,
354                                info.username, errmsg)) != RKINIT_SUCCESS) {
355        rpc_send_error(errmsg);
356        exit(0);
357    }
358    else
359        rpc_send_success();
360
361    /*
362     * If the name of a ticket file was specified, set it; otherwise,
363     * just use the default.
364     */
365    if (strlen(info.tktfilename))
366        krb_set_tkt_string(info.tktfilename);
367   
368    /*
369     * Call internal kerberos library routine so that we can supply
370     * our own ticket decryption routine.
371     */
372
373    /*
374     * We need a setjmp here because krb_get_in_tkt ignores the
375     * return value of decrypt_tkt.  Thus if we want any of its
376     * return values to reach the client, we have to jump out of
377     * the routine.
378     */
379
380    if (setjmp(rii.env) == 0) {
381        if (status = krb_get_in_tkt(info.aname, info.inst, info.realm,
382                                    info.sname, info.sinst, info.lifetime,
383                                    NULL, decrypt_tkt, (char *)&rii)) {
384            strcpy(errmsg, krb_err_txt[status]);
385            rpc_send_error(errmsg);
386        }
387        else
388            rpc_send_success();
389    }
390    else
391        rpc_send_error(errbuf);
392   
393    return(RKINIT_SUCCESS);
394}
Note: See TracBrowser for help on using the repository browser.