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 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 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