Initial import from FreeBSD RELENG_4:
[games.git] / crypto / kerberosIV / lib / krb / recvauth.c
1 /* 
2   Copyright (C) 1989 by the Massachusetts Institute of Technology
3
4    Export of this software from the United States of America is assumed
5    to require a specific license from the United States Government.
6    It is the responsibility of any person or organization contemplating
7    export to obtain such a license before exporting.
8
9 WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
10 distribute this software and its documentation for any purpose and
11 without fee is hereby granted, provided that the above copyright
12 notice appear in all copies and that both that copyright notice and
13 this permission notice appear in supporting documentation, and that
14 the name of M.I.T. not be used in advertising or publicity pertaining
15 to distribution of the software without specific, written prior
16 permission.  M.I.T. makes no representations about the suitability of
17 this software for any purpose.  It is provided "as is" without express
18 or implied warranty.
19
20   */
21 /* $FreeBSD: src/crypto/kerberosIV/lib/krb/recvauth.c,v 1.1.1.2.2.1 2003/02/13 21:34:36 nectar Exp $ */
22
23 #include "krb_locl.h"
24
25 RCSID("$Id: recvauth.c,v 1.19 1998/06/09 19:25:25 joda Exp $");
26
27 /*
28  * krb_recvauth() reads (and optionally responds to) a message sent
29  * using krb_sendauth().  The "options" argument is a bit-field of
30  * selected options (see "sendauth.c" for options description).
31  * The only option relevant to krb_recvauth() is KOPT_DO_MUTUAL
32  * (mutual authentication requested).  The "fd" argument supplies
33  * a file descriptor to read from (and write to, if mutual authenti-
34  * cation is requested).
35  *
36  * Part of the received message will be a Kerberos ticket sent by the
37  * client; this is read into the "ticket" argument.  The "service" and
38  * "instance" arguments supply the server's Kerberos name.  If the
39  * "instance" argument is the string "*", it is treated as a wild card
40  * and filled in during the krb_rd_req() call (see read_service_key()).
41  *
42  * The "faddr" and "laddr" give the sending (client) and receiving
43  * (local server) network addresses.  ("laddr" may be left NULL unless
44  * mutual authentication is requested, in which case it must be set.)
45  *
46  * The authentication information extracted from the message is returned
47  * in "kdata".  The "filename" argument indicates the file where the
48  * server's key can be found.  (It is passed on to krb_rd_req().)  If
49  * left null, the default "/etc/srvtab" will be used.
50  *
51  * If mutual authentication is requested, the session key schedule must
52  * be computed in order to reply; this schedule is returned in the
53  * "schedule" argument.  A string containing the application version
54  * number from the received message is returned in "version", which
55  * should be large enough to hold a KRB_SENDAUTH_VLEN-character string.
56  *
57  * See krb_sendauth() for the format of the received client message.
58  *
59  * krb_recvauth() first reads the protocol version string from the
60  * given file descriptor.  If it doesn't match the current protocol
61  * version (KRB_SENDAUTH_VERS), the old-style format is assumed.  In
62  * that case, the string of characters up to the first space is read
63  * and interpreted as the ticket length, then the ticket is read.
64  *
65  * If the first string did match KRB_SENDAUTH_VERS, krb_recvauth()
66  * next reads the application protocol version string.  Then the
67  * ticket length and ticket itself are read.
68  *
69  * The ticket is decrypted and checked by the call to krb_rd_req().
70  * If no mutual authentication is required, the result of the
71  * krb_rd_req() call is retured by this routine.  If mutual authenti-
72  * cation is required, a message in the following format is returned
73  * on "fd":
74  *
75  * Size                 Variable                Field
76  * ----                 --------                -----
77  *
78  * 4 bytes              tkt_len                 length of ticket or -1
79  *                                              if error occurred
80  *
81  * priv_len             tmp_buf                 "private" message created
82  *                                              by krb_mk_priv() which
83  *                                              contains the incremented
84  *                                              checksum sent by the client
85  *                                              encrypted in the session
86  *                                              key.  (This field is not
87  *                                              present in case of error.)
88  *
89  * If all goes well, KSUCCESS is returned; otherwise KFAILURE or some
90  * other error code is returned.
91  */
92
93 static int
94 send_error_reply(int fd)
95 {
96     unsigned char tmp[4] = { 255, 255, 255, 255 };
97     if(krb_net_write(fd, tmp, sizeof(tmp)) != sizeof(tmp))
98         return -1;
99     return 0;
100 }
101
102 int
103 krb_recvauth(int32_t options,   /* bit-pattern of options */
104              int fd,            /* file descr. to read from */
105              KTEXT ticket,      /* storage for client's ticket */
106              char *service,     /* service expected */
107              char *instance,    /* inst expected (may be filled in) */
108              struct sockaddr_in *faddr, /* address of foreign host on fd */
109              struct sockaddr_in *laddr, /* local address */
110              AUTH_DAT *kdata,   /* kerberos data (returned) */
111              char *filename,    /* name of file with service keys */
112              des_key_schedule schedule, /* key schedule (return) */
113              char *version)     /* version string (filled in) */
114 {
115     int cc;
116     char krb_vers[KRB_SENDAUTH_VLEN + 1]; /* + 1 for the null terminator */
117     int rem;
118     int32_t priv_len;
119     u_char tmp_buf[MAX_KTXT_LEN+max(KRB_SENDAUTH_VLEN+1,21)];
120
121     if (!(options & KOPT_IGNORE_PROTOCOL)) {
122         /* read the protocol version number */
123         if (krb_net_read(fd, krb_vers, KRB_SENDAUTH_VLEN) != KRB_SENDAUTH_VLEN)
124             return(errno);
125         krb_vers[KRB_SENDAUTH_VLEN] = '\0';
126     }
127
128     /* read the application version string */
129     if (krb_net_read(fd, version, KRB_SENDAUTH_VLEN) != KRB_SENDAUTH_VLEN)
130         return(errno);
131     version[KRB_SENDAUTH_VLEN] = '\0';
132
133     /* get the length of the ticket */
134     {
135         char tmp[4];
136         if (krb_net_read(fd, tmp, 4) != 4)
137             return -1;
138         krb_get_int(tmp, &ticket->length, 4, 0);
139     }
140     
141     /* sanity check */
142     if (ticket->length <= 0 || ticket->length > MAX_KTXT_LEN) {
143         if (options & KOPT_DO_MUTUAL) {
144             if(send_error_reply(fd))
145                 return -1;
146             return KFAILURE;
147         } else
148             return KFAILURE; /* XXX there may still be junk on the fd? */
149     }
150
151     /* read the ticket */
152     if (krb_net_read(fd, ticket->dat, ticket->length) != ticket->length)
153         return -1;
154     /*
155      * now have the ticket.  decrypt it to get the authenticated
156      * data.
157      */
158     rem = krb_rd_req(ticket, service, instance, faddr->sin_addr.s_addr,
159                      kdata, filename);
160
161     /* if we are doing mutual auth, compose a response */
162     if (options & KOPT_DO_MUTUAL) {
163         if (rem != KSUCCESS){
164             /* the krb_rd_req failed */
165             if(send_error_reply(fd))
166                 return -1;
167             return rem;
168         }
169         
170         /* add one to the (formerly) sealed checksum, and re-seal it
171            for return to the client */
172         { 
173             unsigned char cs[4];
174             krb_put_int(kdata->checksum + 1, cs, sizeof(cs), 4);
175 #ifndef NOENCRYPTION
176             des_key_sched(&kdata->session,schedule);
177 #endif
178             priv_len = krb_mk_priv(cs, 
179                                    tmp_buf+4, 
180                                    4,
181                                    schedule,
182                                    &kdata->session,
183                                    laddr,
184                                    faddr);
185         }
186         /* mk_priv will never fail */
187         priv_len += krb_put_int(priv_len, tmp_buf, 4, 4);
188         
189         if((cc = krb_net_write(fd, tmp_buf, priv_len)) != priv_len)
190             return -1;
191     }
192     return rem;
193 }