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