1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* appl/user_user/client.c - Other end of user-user client/server pair */
3 /*
4 * Copyright 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 #include "k5-int.h"
28 #include "com_err.h"
29
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
34 #include <netdb.h>
35
main(int argc,char * argv[])36 int main (int argc, char *argv[])
37 {
38 int s;
39 int retval, i;
40 char *hname; /* full name of server */
41 char **srealms; /* realm(s) of server */
42 char *princ; /* principal in credentials cache */
43 struct servent *serv;
44 struct hostent *host;
45 struct sockaddr_in serv_net_addr, cli_net_addr;
46 krb5_ccache cc;
47 krb5_creds creds, *new_creds;
48 krb5_data reply, msg, princ_data;
49 krb5_auth_context auth_context = NULL;
50 krb5_ticket * ticket = NULL;
51 krb5_context context;
52 unsigned short port;
53
54 if (argc < 2 || argc > 4) {
55 fputs ("usage: uu-client <hostname> [message [port]]\n", stderr);
56 exit(1);
57 }
58
59 retval = krb5_init_context(&context);
60 if (retval) {
61 com_err(argv[0], retval, "while initializing krb5");
62 exit(1);
63 }
64
65 if (argc == 4) {
66 port = htons(atoi(argv[3]));
67 }
68 else if ((serv = getservbyname ("uu-sample", "tcp")) == NULL)
69 {
70 fputs ("uu-client: unknown service \"uu-sample/tcp\"\n", stderr);
71 exit(2);
72 } else {
73 port = serv->s_port;
74 }
75
76 if ((host = gethostbyname (argv[1])) == NULL) {
77 fprintf (stderr, "uu-client: can't get address of host \"%s\".\n",
78 argv[1]);
79 exit(3);
80 }
81
82 if (host->h_addrtype != AF_INET) {
83 fprintf (stderr, "uu-client: bad address type %d for \"%s\".\n",
84 host->h_addrtype, argv[1]);
85 exit(3);
86 }
87
88 hname = strdup (host->h_name);
89
90 #ifndef USE_STDOUT
91 if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
92 com_err ("uu-client", errno, "creating socket");
93 exit(4);
94 } else {
95 cli_net_addr.sin_family = AF_INET;
96 cli_net_addr.sin_port = 0;
97 cli_net_addr.sin_addr.s_addr = 0;
98 if (bind (s, (struct sockaddr *)&cli_net_addr,
99 sizeof (cli_net_addr)) < 0) {
100 com_err ("uu-client", errno, "binding socket");
101 exit(4);
102 }
103 }
104
105 serv_net_addr.sin_family = AF_INET;
106 serv_net_addr.sin_port = port;
107
108 i = 0;
109 while (1) {
110 if (host->h_addr_list[i] == 0) {
111 fprintf (stderr, "uu-client: unable to connect to \"%s\"\n", hname);
112 exit(5);
113 }
114
115 memcpy (&serv_net_addr.sin_addr, host->h_addr_list[i++],
116 sizeof(serv_net_addr.sin_addr));
117
118 if (connect(s, (struct sockaddr *)&serv_net_addr,
119 sizeof (serv_net_addr)) == 0)
120 break;
121 com_err ("uu-client", errno, "connecting to \"%s\" (%s).",
122 hname, inet_ntoa(serv_net_addr.sin_addr));
123 }
124 #else
125 s = 1;
126 #endif
127
128 retval = krb5_cc_default(context, &cc);
129 if (retval) {
130 com_err("uu-client", retval, "getting credentials cache");
131 exit(6);
132 }
133
134 memset (&creds, 0, sizeof(creds));
135
136 retval = krb5_cc_get_principal(context, cc, &creds.client);
137 if (retval) {
138 com_err("uu-client", retval, "getting principal name");
139 exit(6);
140 }
141
142 retval = krb5_unparse_name(context, creds.client, &princ);
143 if (retval) {
144 com_err("uu-client", retval, "printing principal name");
145 exit(7);
146 }
147 else
148 fprintf(stderr, "uu-client: client principal is \"%s\".\n", princ);
149
150 retval = krb5_get_host_realm(context, hname, &srealms);
151 if (retval) {
152 com_err("uu-client", retval, "getting realms for \"%s\"", hname);
153 exit(7);
154 }
155
156 retval =
157 krb5_build_principal_ext(context, &creds.server,
158 krb5_princ_realm(context,
159 creds.client)->length,
160 krb5_princ_realm(context,
161 creds.client)->data,
162 6, "krbtgt",
163 krb5_princ_realm(context,
164 creds.client)->length,
165 krb5_princ_realm(context,
166 creds.client)->data,
167 0);
168 if (retval) {
169 com_err("uu-client", retval, "setting up tgt server name");
170 exit(7);
171 }
172
173 /* Get TGT from credentials cache */
174 retval = krb5_get_credentials(context, KRB5_GC_CACHED, cc,
175 &creds, &new_creds);
176 if (retval) {
177 com_err("uu-client", retval, "getting TGT");
178 exit(6);
179 }
180
181 i = strlen(princ) + 1;
182
183 fprintf(stderr, "uu-client: sending %d bytes\n",
184 new_creds->ticket.length + i);
185 princ_data.data = princ;
186 princ_data.length = i; /* include null terminator for
187 server's convenience */
188 retval = krb5_write_message(context, (krb5_pointer) &s, &princ_data);
189 if (retval) {
190 com_err("uu-client", retval, "sending principal name to server");
191 exit(8);
192 }
193
194 free(princ);
195
196 retval = krb5_write_message(context, (krb5_pointer) &s,
197 &new_creds->ticket);
198 if (retval) {
199 com_err("uu-client", retval, "sending ticket to server");
200 exit(8);
201 }
202
203 retval = krb5_read_message(context, (krb5_pointer) &s, &reply);
204 if (retval) {
205 com_err("uu-client", retval, "reading reply from server");
206 exit(9);
207 }
208
209 retval = krb5_auth_con_init(context, &auth_context);
210 if (retval) {
211 com_err("uu-client", retval, "initializing the auth_context");
212 exit(9);
213 }
214
215 retval =
216 krb5_auth_con_genaddrs(context, auth_context, s,
217 KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR |
218 KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR);
219 if (retval) {
220 com_err("uu-client", retval, "generating addrs for auth_context");
221 exit(9);
222 }
223
224 retval = krb5_auth_con_setflags(context, auth_context,
225 KRB5_AUTH_CONTEXT_DO_SEQUENCE);
226 if (retval) {
227 com_err("uu-client", retval, "initializing the auth_context flags");
228 exit(9);
229 }
230
231 retval = krb5_auth_con_setuseruserkey(context, auth_context,
232 &new_creds->keyblock);
233 if (retval) {
234 com_err("uu-client", retval, "setting useruserkey for authcontext");
235 exit(9);
236 }
237
238 /* read the ap_req to get the session key */
239 retval = krb5_rd_req(context, &auth_context, &reply, creds.client, NULL,
240 NULL, &ticket);
241 krb5_free_data_contents(context, &reply);
242 if (retval) {
243 com_err("uu-client", retval, "reading AP_REQ from server");
244 exit(9);
245 }
246
247 retval = krb5_unparse_name(context, ticket->enc_part2->client, &princ);
248 if (retval)
249 com_err("uu-client", retval, "while unparsing client name");
250 else {
251 printf("server is named \"%s\"\n", princ);
252 free(princ);
253 }
254
255 retval = krb5_read_message(context, (krb5_pointer) &s, &reply);
256 if (retval) {
257 com_err("uu-client", retval, "reading reply from server");
258 exit(9);
259 }
260
261 retval = krb5_rd_safe(context, auth_context, &reply, &msg, NULL);
262 if (retval) {
263 com_err("uu-client", retval, "decoding reply from server");
264 exit(10);
265 }
266
267 printf ("uu-client: server says \"%s\".\n", msg.data);
268
269 #ifndef USE_STDOUT
270 close(s);
271 #endif
272 krb5_free_ticket(context, ticket);
273 krb5_free_host_realm(context, srealms);
274 free(hname);
275 krb5_free_cred_contents(context, &creds);
276 krb5_free_creds(context, new_creds);
277 krb5_free_data_contents(context, &msg);
278 krb5_free_data_contents(context, &reply);
279 krb5_cc_close(context, cc);
280 krb5_auth_con_free(context, auth_context);
281 krb5_free_context(context);
282 return 0;
283 }
284