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

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