xref: /freebsd/crypto/krb5/src/appl/sample/sclient/sclient.c (revision b670c9bafc0e31c7609969bf374b2e80bdc00211)
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
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
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