1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* appl/sample/sclient/sclient.c */
3 /*
4 * Copyright 1990,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 *
29 * Sample Kerberos v5 client.
30 *
31 * Usage: sample_client hostname
32 */
33
34 #include "krb5.h"
35 #include "com_err.h"
36
37 #include <stdio.h>
38 #include <string.h>
39 #include <ctype.h>
40 #include <errno.h>
41
42 #include <sys/types.h>
43 #include <sys/socket.h>
44 #include <netinet/in.h>
45 #include <netdb.h>
46 #include "fake-addrinfo.h" /* not everyone implements getaddrinfo yet */
47
48 #include <signal.h>
49
50 #ifdef HAVE_UNISTD_H
51 #include <unistd.h>
52 #endif
53
54 #include <stdlib.h>
55
56 #include "../sample.h"
57
58 #ifndef GETSOCKNAME_ARG3_TYPE
59 #define GETSOCKNAME_ARG3_TYPE int
60 #endif
61
62 static int
net_read(int fd,char * buf,int len)63 net_read(int fd, char *buf, int len)
64 {
65 int cc, len2 = 0;
66
67 do {
68 cc = SOCKET_READ((SOCKET)fd, buf, len);
69 if (cc < 0) {
70 if (SOCKET_ERRNO == SOCKET_EINTR)
71 continue;
72
73 /* XXX this interface sucks! */
74 errno = SOCKET_ERRNO;
75
76 return(cc); /* errno is already set */
77 }
78 else if (cc == 0) {
79 return(len2);
80 } else {
81 buf += cc;
82 len2 += cc;
83 len -= cc;
84 }
85 } while (len > 0);
86 return(len2);
87 }
88
89 int
main(int argc,char * argv[])90 main(int argc, char *argv[])
91 {
92 struct addrinfo *ap, aihints, *apstart;
93 int aierr;
94 int sock;
95 krb5_context context;
96 krb5_data recv_data;
97 krb5_data cksum_data;
98 krb5_error_code retval;
99 krb5_ccache ccdef;
100 krb5_principal client, server;
101 krb5_error *err_ret;
102 krb5_ap_rep_enc_part *rep_ret;
103 krb5_auth_context auth_context = 0;
104 short xmitlen;
105 char *portstr;
106 char *service = SAMPLE_SERVICE;
107
108 if (argc != 2 && argc != 3 && argc != 4) {
109 fprintf(stderr, "usage: %s <hostname> [port] [service]\n",argv[0]);
110 exit(1);
111 }
112
113 retval = krb5_init_context(&context);
114 if (retval) {
115 com_err(argv[0], retval, "while initializing krb5");
116 exit(1);
117 }
118
119 (void) signal(SIGPIPE, SIG_IGN);
120
121 if (argc > 2)
122 portstr = argv[2];
123 else
124 portstr = SAMPLE_PORT;
125
126 memset(&aihints, 0, sizeof(aihints));
127 aihints.ai_socktype = SOCK_STREAM;
128 aihints.ai_flags = AI_ADDRCONFIG;
129 aierr = getaddrinfo(argv[1], portstr, &aihints, &ap);
130 if (aierr) {
131 fprintf(stderr, "%s: error looking up host '%s' port '%s'/tcp: %s\n",
132 argv[0], argv[1], portstr, gai_strerror(aierr));
133 exit(1);
134 }
135 if (ap == 0) {
136 /* Should never happen. */
137 fprintf(stderr, "%s: error looking up host '%s' port '%s'/tcp: no addresses returned?\n",
138 argv[0], argv[1], portstr);
139 exit(1);
140 }
141
142 if (argc > 3) {
143 service = argv[3];
144 }
145
146 retval = krb5_sname_to_principal(context, argv[1], service,
147 KRB5_NT_SRV_HST, &server);
148 if (retval) {
149 com_err(argv[0], retval, "while creating server name for host %s service %s",
150 argv[1], service);
151 exit(1);
152 }
153
154 /* set up the address of the foreign socket for connect() */
155 apstart = ap; /* For freeing later */
156 for (sock = -1; ap && sock == -1; ap = ap->ai_next) {
157 char abuf[NI_MAXHOST], pbuf[NI_MAXSERV];
158 char mbuf[NI_MAXHOST + NI_MAXSERV + 64];
159 if (getnameinfo(ap->ai_addr, ap->ai_addrlen, abuf, sizeof(abuf),
160 pbuf, sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV)) {
161 memset(abuf, 0, sizeof(abuf));
162 memset(pbuf, 0, sizeof(pbuf));
163 strncpy(abuf, "[error, cannot print address?]",
164 sizeof(abuf)-1);
165 strncpy(pbuf, "[?]", sizeof(pbuf)-1);
166 }
167 memset(mbuf, 0, sizeof(mbuf));
168 strncpy(mbuf, "error contacting ", sizeof(mbuf)-1);
169 strncat(mbuf, abuf, sizeof(mbuf) - strlen(mbuf) - 1);
170 strncat(mbuf, " port ", sizeof(mbuf) - strlen(mbuf) - 1);
171 strncat(mbuf, pbuf, sizeof(mbuf) - strlen(mbuf) - 1);
172 sock = socket(ap->ai_family, SOCK_STREAM, 0);
173 if (sock < 0) {
174 fprintf(stderr, "%s: socket: %s\n", mbuf, strerror(errno));
175 continue;
176 }
177 if (connect(sock, ap->ai_addr, ap->ai_addrlen) < 0) {
178 fprintf(stderr, "%s: connect: %s\n", mbuf, strerror(errno));
179 close(sock);
180 sock = -1;
181 continue;
182 }
183 /* connected, yay! */
184 }
185 if (sock == -1)
186 /* Already printed error message above. */
187 exit(1);
188 printf("connected\n");
189
190 cksum_data.data = argv[1];
191 cksum_data.length = strlen(argv[1]);
192
193 retval = krb5_cc_default(context, &ccdef);
194 if (retval) {
195 com_err(argv[0], retval, "while getting default ccache");
196 exit(1);
197 }
198
199 retval = krb5_cc_get_principal(context, ccdef, &client);
200 if (retval) {
201 com_err(argv[0], retval, "while getting client principal name");
202 exit(1);
203 }
204 retval = krb5_sendauth(context, &auth_context, (krb5_pointer) &sock,
205 SAMPLE_VERSION, client, server,
206 AP_OPTS_MUTUAL_REQUIRED,
207 &cksum_data,
208 0, /* no creds, use ccache instead */
209 ccdef, &err_ret, &rep_ret, NULL);
210
211 krb5_free_principal(context, server); /* finished using it */
212 krb5_free_principal(context, client);
213 krb5_cc_close(context, ccdef);
214 if (auth_context) krb5_auth_con_free(context, auth_context);
215
216 if (retval && retval != KRB5_SENDAUTH_REJECTED) {
217 com_err(argv[0], retval, "while using sendauth");
218 exit(1);
219 }
220 if (retval == KRB5_SENDAUTH_REJECTED) {
221 /* got an error */
222 printf("sendauth rejected, error reply is:\n\t\"%*s\"\n",
223 err_ret->text.length, err_ret->text.data);
224 } else if (rep_ret) {
225 /* got a reply */
226 krb5_free_ap_rep_enc_part(context, rep_ret);
227
228 printf("sendauth succeeded, reply is:\n");
229 if ((retval = net_read(sock, (char *)&xmitlen,
230 sizeof(xmitlen))) <= 0) {
231 if (retval == 0)
232 errno = ECONNABORTED;
233 com_err(argv[0], errno, "while reading data from server");
234 exit(1);
235 }
236 recv_data.length = ntohs(xmitlen);
237 if (!(recv_data.data = (char *)malloc((size_t) recv_data.length + 1))) {
238 com_err(argv[0], ENOMEM,
239 "while allocating buffer to read from server");
240 exit(1);
241 }
242 if ((retval = net_read(sock, (char *)recv_data.data,
243 recv_data.length)) <= 0) {
244 if (retval == 0)
245 errno = ECONNABORTED;
246 com_err(argv[0], errno, "while reading data from server");
247 exit(1);
248 }
249 recv_data.data[recv_data.length] = '\0';
250 printf("reply len %d, contents:\n%s\n",
251 recv_data.length,recv_data.data);
252 free(recv_data.data);
253 } else {
254 com_err(argv[0], 0, "no error or reply from sendauth!");
255 exit(1);
256 }
257 freeaddrinfo(apstart);
258 krb5_free_context(context);
259 exit(0);
260 }
261