9def2603ced80b01d56e8567d505c21046c4aef2
[krb5.git] / src / appl / simple / client / sim_client.c
1 /*
2  * appl/simple/client/sim_client.c
3  *
4  * Copyright 1989,1991 by the Massachusetts Institute of Technology.
5  * All Rights Reserved.
6  *
7  * Export of this software from the United States of America may
8  *   require a specific license from the United States Government.
9  *   It is the responsibility of any person or organization contemplating
10  *   export to obtain such a license before exporting.
11  * 
12  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13  * distribute this software and its documentation for any purpose and
14  * without fee is hereby granted, provided that the above copyright
15  * notice appear in all copies and that both that copyright notice and
16  * this permission notice appear in supporting documentation, and that
17  * the name of M.I.T. not be used in advertising or publicity pertaining
18  * to distribution of the software without specific, written prior
19  * permission.  M.I.T. makes no representations about the suitability of
20  * this software for any purpose.  It is provided "as is" without express
21  * or implied warranty.
22  * 
23  *
24  * Simple UDP-based sample client program.  For demonstration.
25  * This program performs no useful function.
26  */
27
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <netdb.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <ctype.h>
35
36 #include <krb5.h>
37 #include "com_err.h"
38
39 #include "simple.h"
40
41 #ifdef HAVE_STDLIB_H
42 #include <stdlib.h>
43 #else
44 extern char *malloc();
45 #endif
46
47 /* for old Unixes and friends ... */
48 #ifndef MAXHOSTNAMELEN
49 #define MAXHOSTNAMELEN 64
50 #endif
51
52 #define MSG "hi there!"                 /* message text */
53
54 void
55 usage(name)
56     char *name;
57 {
58         fprintf(stderr, "usage: %s [-p port] [-h host] [-m message] [-s service] [host]\n", name);
59 }       
60
61 int
62 main(argc, argv)
63     int argc;
64     char *argv[];
65 {
66     int sock, i;
67     int flags = 0;                      /* flags for sendto() */
68     struct servent *serv;
69     struct hostent *host;
70     char *cp;
71     char full_hname[MAXHOSTNAMELEN];
72 #ifdef BROKEN_STREAMS_SOCKETS
73     char my_hostname[MAXHOSTNAMELEN];
74 #endif
75     struct sockaddr_in s_sock;          /* server address */
76     struct sockaddr_in c_sock;          /* client address */
77     extern int opterr, optind;
78     extern char * optarg;
79     int ch;
80     
81     short port = 0;
82     char *message = MSG;
83     char *hostname = 0;
84     char *service = SIMPLE_SERVICE;
85     char *progname = 0;
86
87     krb5_error_code retval;
88     krb5_data packet, inbuf;
89     krb5_ccache ccdef;
90     krb5_address addr, *portlocal_addr;
91     krb5_rcache rcache;
92     krb5_data   rcache_name;
93
94     krb5_context          context;
95     krb5_auth_context     auth_context = NULL;
96     krb5_replay_data      replaydata;
97
98     retval = krb5_init_context(&context);
99     if (retval) {
100             com_err(argv[0], retval, "while initializing krb5");
101             exit(1);
102     }
103
104     progname = argv[0];
105
106     /*
107      * Parse command line arguments
108      *  
109      */
110     opterr = 0;
111     while ((ch = getopt(argc, argv, "p:m:h:s:")) != EOF)
112     switch (ch) {
113     case 'p':
114         port = atoi(optarg);
115         break;
116     case 'm':
117         message = optarg;
118         break;
119     case 'h':
120         hostname = optarg;
121         break;
122     case 's':
123         service = optarg;
124         break;
125     case '?':
126     default:
127         usage(progname);
128         exit(1);
129         break;
130     }
131     argc -= optind;
132     argv += optind;
133     if (argc > 0) {
134         if (hostname)
135             usage(progname);
136         hostname = argv[0];
137     }
138
139     if (hostname == 0) {
140         fprintf(stderr, "You must specify a hostname to contact.\n\n");
141         usage(progname);
142         exit(1);
143     }
144
145     if (!valid_cksumtype(CKSUMTYPE_CRC32)) {
146         com_err(progname, KRB5_PROG_SUMTYPE_NOSUPP, "while using CRC-32");
147         exit(1);
148     }
149
150     /* Look up server host */
151     if ((host = gethostbyname(hostname)) == (struct hostent *) 0) {
152         fprintf(stderr, "%s: unknown host\n", hostname);
153         exit(1);
154     }
155     strncpy(full_hname, host->h_name, sizeof(full_hname)-1);
156     full_hname[sizeof(full_hname)-1] = '\0';
157
158     /* lower-case to get name for "instance" part of service name */
159     for (cp = full_hname; *cp; cp++)
160         if (isupper(*cp))
161             *cp = tolower(*cp);
162
163     /* Set server's address */
164     (void) memset((char *)&s_sock, 0, sizeof(s_sock));
165
166     memcpy((char *)&s_sock.sin_addr, host->h_addr, host->h_length);
167 #ifdef DEBUG
168     printf("s_sock.sin_addr is %s\n", inet_ntoa(s_sock.sin_addr));
169 #endif
170     s_sock.sin_family = AF_INET;
171
172     if (port == 0) {
173         /* Look up service */
174         if ((serv = getservbyname(SIMPLE_PORT, "udp")) == NULL) {
175             fprintf(stderr, "service unknown: %s/udp\n", SIMPLE_PORT);
176             exit(1);
177         }
178         s_sock.sin_port = serv->s_port;
179     } else {
180         s_sock.sin_port = htons(port);
181     }
182
183     /* Open a socket */
184     if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
185         com_err(progname, errno, "opening datagram socket");
186         exit(1);
187     }
188
189     memset((char *)&c_sock, 0, sizeof(c_sock));
190     c_sock.sin_family = AF_INET;
191 #ifdef BROKEN_STREAMS_SOCKETS
192     if (gethostname(my_hostname, sizeof(my_hostname)) < 0) {
193         perror("gethostname");
194         exit(1);
195     }
196
197     if ((host = gethostbyname(my_hostname)) == (struct hostent *)0) {
198         fprintf(stderr, "%s: unknown host\n", hostname);
199         exit(1);
200     }
201     memcpy((char *)&c_sock.sin_addr, host->h_addr, host->h_length);
202 #endif
203     
204
205     /* Bind it to set the address; kernel will fill in port # */
206     if (bind(sock, (struct sockaddr *)&c_sock, sizeof(c_sock)) < 0) {
207         com_err(progname, errno, "while binding datagram socket");
208         exit(1);
209     }
210         
211     /* PREPARE KRB_AP_REQ MESSAGE */
212
213     inbuf.data = hostname;
214     inbuf.length = strlen(hostname);
215
216     /* Get credentials for server */
217     if ((retval = krb5_cc_default(context, &ccdef))) {
218         com_err(progname, retval, "while getting default ccache");
219         exit(1);
220     }
221
222     if ((retval = krb5_mk_req(context, &auth_context, 0, service, full_hname,
223                               &inbuf, ccdef, &packet))) {
224         com_err(progname, retval, "while preparing AP_REQ");
225         exit(1);
226     }
227     printf("Got credentials for %s.\n", service);
228
229     /* "connect" the datagram socket; this is necessary to get a local address
230        properly bound for getsockname() below. */
231
232     if (connect(sock, (struct sockaddr *)&s_sock, sizeof(s_sock)) == -1) {
233         com_err(progname, errno, "while connecting to server");
234         exit(1);
235     }
236     /* Send authentication info to server */
237     if ((i = send(sock, (char *)packet.data, packet.length, flags)) < 0) 
238         com_err(progname, errno, "while sending KRB_AP_REQ message");
239     printf("Sent authentication data: %d bytes\n", i);
240     krb5_xfree(packet.data);
241
242     /* PREPARE KRB_SAFE MESSAGE */
243
244     /* Get my address */
245     memset((char *) &c_sock, 0, sizeof(c_sock));
246     i = sizeof(c_sock);
247     if (getsockname(sock, (struct sockaddr *)&c_sock, &i) < 0) {
248         com_err(progname, errno, "while getting socket name");
249         exit(1);
250     }
251
252     addr.addrtype = ADDRTYPE_IPPORT;
253     addr.length = sizeof(c_sock.sin_port);
254     addr.contents = (krb5_octet *)&c_sock.sin_port;
255     if ((retval = krb5_auth_con_setports(context, auth_context,
256                                          &addr, NULL))) {
257         com_err(progname, retval, "while setting local port\n");
258         exit(1);
259     }
260
261     addr.addrtype = ADDRTYPE_INET;
262     addr.length = sizeof(c_sock.sin_addr);
263     addr.contents = (krb5_octet *)&c_sock.sin_addr;
264     if ((retval = krb5_auth_con_setaddrs(context, auth_context,
265                                          &addr, NULL))) {
266         com_err(progname, retval, "while setting local addr\n");
267         exit(1);
268     }
269
270     /* THIS IS UGLY */
271     if ((retval = krb5_gen_portaddr(context, &addr,
272                                     (krb5_pointer) &c_sock.sin_port,
273                                     &portlocal_addr))) {
274         com_err(progname, retval, "while generating port address");
275         exit(1);
276     }
277     
278     if ((retval = krb5_gen_replay_name(context,portlocal_addr,
279                                        "_sim_clt",&cp))) {
280         com_err(progname, retval, "while generating replay cache name");
281         exit(1);
282     }
283
284     rcache_name.length = strlen(cp);
285     rcache_name.data = cp;
286
287     if ((retval = krb5_get_server_rcache(context, &rcache_name, &rcache))) {
288         com_err(progname, retval, "while getting server rcache");
289         exit(1);
290     }
291
292     /* set auth_context rcache */
293     krb5_auth_con_setrcache(context, auth_context, rcache);
294
295     /* Make the safe message */
296     inbuf.data = message;
297     inbuf.length = strlen(message);
298
299     if ((retval = krb5_mk_safe(context, auth_context, &inbuf, &packet, NULL))){
300         com_err(progname, retval, "while making KRB_SAFE message");
301         exit(1);
302     }
303
304     /* Send it */
305     if ((i = send(sock, (char *)packet.data, packet.length, flags)) < 0)
306         com_err(progname, errno, "while sending SAFE message");
307     printf("Sent checksummed message: %d bytes\n", i);
308     krb5_xfree(packet.data);
309
310     /* PREPARE KRB_PRIV MESSAGE */
311
312     /* Make the encrypted message */
313     if ((retval = krb5_mk_priv(context, auth_context, &inbuf,
314                                &packet, NULL))) {
315         com_err(progname, retval, "while making KRB_PRIV message");
316         exit(1);
317     }
318
319     /* Send it */
320     if ((i = send(sock, (char *)packet.data, packet.length, flags)) < 0)
321         com_err(progname, errno, "while sending PRIV message");
322     printf("Sent encrypted message: %d bytes\n", i);
323     krb5_xfree(packet.data);
324
325     krb5_auth_con_free(context, auth_context);
326     krb5_free_context(context);
327     
328     exit(0);
329 }