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