xref: /freebsd/crypto/krb5/src/appl/simple/client/sim_client.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
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.  Furthermore if you modify this software you must label
20  * your software as modified software and not distribute it in such a
21  * fashion that it might be confused with the original M.I.T. software.
22  * M.I.T. makes no representations about the suitability of
23  * this software for any purpose.  It is provided "as is" without express
24  * or implied warranty.
25  */
26 
27 /*
28  * Simple UDP-based sample client program.  For demonstration.
29  * This program performs no useful function.
30  */
31 
32 #include <krb5.h>
33 #include "com_err.h"
34 
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <errno.h>
41 #include <netdb.h>
42 #include <unistd.h>
43 
44 #include "simple.h"
45 
46 /* for old Unixes and friends ... */
47 #ifndef MAXHOSTNAMELEN
48 #define MAXHOSTNAMELEN 64
49 #endif
50 
51 #define MSG "hi there!"                 /* message text */
52 
53 void usage (char *);
54 
55 void
usage(char * name)56 usage(char *name)
57 {
58     fprintf(stderr, "usage: %s [-p port] [-h host] [-m message] [-s service] [host]\n", name);
59 }
60 
61 int
main(int argc,char * argv[])62 main(int argc, char *argv[])
63 {
64     int sock, i;
65     socklen_t len;
66     int flags = 0;                      /* flags for sendto() */
67     struct servent *serv;
68     struct hostent *host;
69 #ifdef BROKEN_STREAMS_SOCKETS
70     char my_hostname[MAXHOSTNAMELEN];
71 #endif
72     struct sockaddr_in s_sock;          /* server address */
73     struct sockaddr_in c_sock;          /* client address */
74     extern int opterr, optind;
75     extern char * optarg;
76     int ch;
77 
78     short port = 0;
79     char *message = MSG;
80     char *hostname = 0;
81     char *service = SIMPLE_SERVICE;
82     char *progname = 0;
83 
84     krb5_error_code retval;
85     krb5_data packet, inbuf;
86     krb5_ccache ccdef;
87     krb5_address addr;
88 
89     krb5_context          context;
90     krb5_auth_context     auth_context = NULL;
91 
92     retval = krb5_init_context(&context);
93     if (retval) {
94         com_err(argv[0], retval, "while initializing krb5");
95         exit(1);
96     }
97 
98     progname = argv[0];
99 
100     /*
101      * Parse command line arguments
102      *
103      */
104     opterr = 0;
105     while ((ch = getopt(argc, argv, "p:m:h:s:")) != -1)
106         switch (ch) {
107         case 'p':
108             port = atoi(optarg);
109             break;
110         case 'm':
111             message = optarg;
112             break;
113         case 'h':
114             hostname = optarg;
115             break;
116         case 's':
117             service = optarg;
118             break;
119         case '?':
120         default:
121             usage(progname);
122             exit(1);
123             break;
124         }
125     argc -= optind;
126     argv += optind;
127     if (argc > 0) {
128         if (hostname)
129             usage(progname);
130         hostname = argv[0];
131     }
132 
133     if (hostname == 0) {
134         fprintf(stderr, "You must specify a hostname to contact.\n\n");
135         usage(progname);
136         exit(1);
137     }
138 
139     /* Look up server host */
140     if ((host = gethostbyname(hostname)) == (struct hostent *) 0) {
141         fprintf(stderr, "%s: unknown host\n", hostname);
142         exit(1);
143     }
144 
145     /* Set server's address */
146     (void) memset(&s_sock, 0, sizeof(s_sock));
147 
148     memcpy(&s_sock.sin_addr, host->h_addr, sizeof(s_sock.sin_addr));
149 #ifdef DEBUG
150     printf("s_sock.sin_addr is %s\n", inet_ntoa(s_sock.sin_addr));
151 #endif
152     s_sock.sin_family = AF_INET;
153 
154     if (port == 0) {
155         /* Look up service */
156         if ((serv = getservbyname(SIMPLE_PORT, "udp")) == NULL) {
157             fprintf(stderr, "service unknown: %s/udp\n", SIMPLE_PORT);
158             exit(1);
159         }
160         s_sock.sin_port = serv->s_port;
161     } else {
162         s_sock.sin_port = htons(port);
163     }
164 
165     /* Open a socket */
166     if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
167         com_err(progname, errno, "opening datagram socket");
168         exit(1);
169     }
170 
171     memset(&c_sock, 0, sizeof(c_sock));
172     c_sock.sin_family = AF_INET;
173 #ifdef BROKEN_STREAMS_SOCKETS
174     if (gethostname(my_hostname, sizeof(my_hostname)) < 0) {
175         perror("gethostname");
176         exit(1);
177     }
178 
179     if ((host = gethostbyname(my_hostname)) == (struct hostent *)0) {
180         fprintf(stderr, "%s: unknown host\n", hostname);
181         exit(1);
182     }
183     memcpy(&c_sock.sin_addr, host->h_addr, sizeof(c_sock.sin_addr));
184 #endif
185 
186 
187     /* Bind it to set the address; kernel will fill in port # */
188     if (bind(sock, (struct sockaddr *)&c_sock, sizeof(c_sock)) < 0) {
189         com_err(progname, errno, "while binding datagram socket");
190         exit(1);
191     }
192 
193     /* PREPARE KRB_AP_REQ MESSAGE */
194 
195     inbuf.data = hostname;
196     inbuf.length = strlen(hostname);
197 
198     /* Get credentials for server */
199     if ((retval = krb5_cc_default(context, &ccdef))) {
200         com_err(progname, retval, "while getting default ccache");
201         exit(1);
202     }
203 
204     retval = krb5_mk_req(context, &auth_context, AP_OPTS_USE_SUBKEY, service,
205                          hostname, &inbuf, ccdef, &packet);
206     if (retval) {
207         com_err(progname, retval, "while preparing AP_REQ");
208         exit(1);
209     }
210     printf("Got credentials for %s.\n", service);
211 
212     /* "connect" the datagram socket; this is necessary to get a local address
213        properly bound for getsockname() below. */
214 
215     if (connect(sock, (struct sockaddr *)&s_sock, sizeof(s_sock)) == -1) {
216         com_err(progname, errno, "while connecting to server");
217         exit(1);
218     }
219     /* Send authentication info to server */
220     if ((i = send(sock, (char *)packet.data, (unsigned) packet.length,
221                   flags)) < 0)
222         com_err(progname, errno, "while sending KRB_AP_REQ message");
223     printf("Sent authentication data: %d bytes\n", i);
224     krb5_free_data_contents(context, &packet);
225 
226     /* PREPARE KRB_SAFE MESSAGE */
227 
228     /* Get my address */
229     memset(&c_sock, 0, sizeof(c_sock));
230     len = sizeof(c_sock);
231     if (getsockname(sock, (struct sockaddr *)&c_sock, &len) < 0) {
232         com_err(progname, errno, "while getting socket name");
233         exit(1);
234     }
235 
236     addr.addrtype = ADDRTYPE_IPPORT;
237     addr.length = sizeof(c_sock.sin_port);
238     addr.contents = (krb5_octet *)&c_sock.sin_port;
239     if ((retval = krb5_auth_con_setports(context, auth_context,
240                                          &addr, NULL))) {
241         com_err(progname, retval, "while setting local port\n");
242         exit(1);
243     }
244 
245     addr.addrtype = ADDRTYPE_INET;
246     addr.length = sizeof(c_sock.sin_addr);
247     addr.contents = (krb5_octet *)&c_sock.sin_addr;
248     if ((retval = krb5_auth_con_setaddrs(context, auth_context,
249                                          &addr, NULL))) {
250         com_err(progname, retval, "while setting local addr\n");
251         exit(1);
252     }
253 
254     /* Make the safe message */
255     inbuf.data = message;
256     inbuf.length = strlen(message);
257 
258     if ((retval = krb5_mk_safe(context, auth_context, &inbuf, &packet, NULL))){
259         com_err(progname, retval, "while making KRB_SAFE message");
260         exit(1);
261     }
262 
263     /* Send it */
264     if ((i = send(sock, (char *)packet.data, (unsigned) packet.length,
265                   flags)) < 0)
266         com_err(progname, errno, "while sending SAFE message");
267     printf("Sent checksummed message: %d bytes\n", i);
268     krb5_free_data_contents(context, &packet);
269 
270     /* PREPARE KRB_PRIV MESSAGE */
271 
272     /* Make the encrypted message */
273     if ((retval = krb5_mk_priv(context, auth_context, &inbuf,
274                                &packet, NULL))) {
275         com_err(progname, retval, "while making KRB_PRIV message");
276         exit(1);
277     }
278 
279     /* Send it */
280     if ((i = send(sock, (char *)packet.data, (unsigned) packet.length,
281                   flags)) < 0)
282         com_err(progname, errno, "while sending PRIV message");
283     printf("Sent encrypted message: %d bytes\n", i);
284     krb5_free_data_contents(context, &packet);
285 
286     krb5_auth_con_free(context, auth_context);
287     krb5_free_context(context);
288 
289     exit(0);
290 }
291