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