1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 /* appl/simple/server/sim_server.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 * Usage: 29 * sample_server servername 30 * 31 * Simple UDP-based server application. For demonstration. 32 * This program performs no useful function. 33 */ 34 35 #include "krb5.h" 36 #include "port-sockets.h" 37 #include <stdio.h> 38 #include <string.h> 39 #include <unistd.h> 40 #include <stdlib.h> 41 #include <sys/types.h> 42 #include <sys/socket.h> 43 #include <netinet/in.h> 44 #include <netdb.h> 45 #include <arpa/inet.h> 46 47 #include "com_err.h" 48 49 #include "simple.h" 50 51 /* for old Unixes and friends ... */ 52 #ifndef MAXHOSTNAMELEN 53 #define MAXHOSTNAMELEN 64 54 #endif 55 56 #define PROGNAME argv[0] 57 58 static void 59 usage(char *name) 60 { 61 fprintf(stderr, "usage: %s [-p port] [-s service] [-S keytab]\n", name); 62 } 63 64 int 65 main(int argc, char *argv[]) 66 { 67 int sock, i; 68 socklen_t len; 69 int flags = 0; /* for recvfrom() */ 70 int on = 1; 71 struct servent *serv; 72 struct sockaddr_in s_sock; /* server's address */ 73 struct sockaddr_in c_sock; /* client's address */ 74 char *cp; 75 extern char * optarg; 76 int ch; 77 78 short port = 0; /* If user specifies port */ 79 krb5_keytab keytab = NULL; /* Allow specification on command line */ 80 char *service = SIMPLE_SERVICE; 81 82 krb5_error_code retval; 83 krb5_data packet, message; 84 unsigned char pktbuf[BUFSIZ]; 85 krb5_principal sprinc; 86 krb5_context context; 87 krb5_auth_context auth_context = NULL; 88 krb5_address addr; 89 krb5_ticket *ticket = NULL; 90 91 retval = krb5_init_context(&context); 92 if (retval) { 93 com_err(argv[0], retval, "while initializing krb5"); 94 exit(1); 95 } 96 97 /* 98 * Parse command line arguments 99 * 100 */ 101 while ((ch = getopt(argc, argv, "p:s:S:")) != -1) { 102 switch (ch) { 103 case 'p': 104 port = atoi(optarg); 105 break; 106 case 's': 107 service = optarg; 108 break; 109 case 'S': 110 if ((retval = krb5_kt_resolve(context, optarg, &keytab))) { 111 com_err(PROGNAME, retval, 112 "while resolving keytab file %s", optarg); 113 exit(2); 114 } 115 break; 116 117 case '?': 118 default: 119 usage(PROGNAME); 120 exit(1); 121 break; 122 } 123 } 124 125 if ((retval = krb5_sname_to_principal(context, NULL, service, 126 KRB5_NT_SRV_HST, &sprinc))) { 127 com_err(PROGNAME, retval, "while generating service name %s", service); 128 exit(1); 129 } 130 131 /* Set up server address */ 132 memset(&s_sock, 0, sizeof(s_sock)); 133 s_sock.sin_family = AF_INET; 134 s_sock.sin_addr.s_addr = INADDR_ANY; 135 136 if (port == 0) { 137 /* Look up service */ 138 if ((serv = getservbyname(SIMPLE_PORT, "udp")) == NULL) { 139 fprintf(stderr, "service unknown: %s/udp\n", SIMPLE_PORT); 140 exit(1); 141 } 142 s_sock.sin_port = serv->s_port; 143 } else { 144 s_sock.sin_port = htons(port); 145 } 146 147 /* Open socket */ 148 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 149 perror("opening datagram socket"); 150 exit(1); 151 } 152 153 /* Let the socket be reused right away */ 154 (void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, 155 sizeof(on)); 156 157 /* Bind the socket */ 158 if (bind(sock, (struct sockaddr *)&s_sock, sizeof(s_sock))) { 159 perror("binding datagram socket"); 160 exit(1); 161 } 162 163 printf("starting...\n"); 164 fflush(stdout); 165 166 #ifdef DEBUG 167 printf("socket has port # %d\n", ntohs(s_sock.sin_port)); 168 #endif 169 170 /* GET KRB_AP_REQ MESSAGE */ 171 172 /* use "recvfrom" so we know client's address */ 173 len = sizeof(struct sockaddr_in); 174 if ((i = recvfrom(sock, (char *)pktbuf, sizeof(pktbuf), flags, 175 (struct sockaddr *)&c_sock, &len)) < 0) { 176 perror("receiving datagram"); 177 exit(1); 178 } 179 180 printf("Received %d bytes\n", i); 181 packet.length = i; 182 packet.data = (krb5_pointer) pktbuf; 183 184 /* Check authentication info */ 185 if ((retval = krb5_rd_req(context, &auth_context, &packet, 186 sprinc, keytab, NULL, &ticket))) { 187 com_err(PROGNAME, retval, "while reading request"); 188 exit(1); 189 } 190 if ((retval = krb5_unparse_name(context, ticket->enc_part2->client, 191 &cp))) { 192 com_err(PROGNAME, retval, "while unparsing client name"); 193 exit(1); 194 } 195 printf("Got authentication info from %s\n", cp); 196 free(cp); 197 198 /* Set foreign_addr for rd_safe() and rd_priv() */ 199 addr.addrtype = ADDRTYPE_INET; 200 addr.length = sizeof(c_sock.sin_addr); 201 addr.contents = (krb5_octet *)&c_sock.sin_addr; 202 if ((retval = krb5_auth_con_setaddrs(context, auth_context, 203 NULL, &addr))) { 204 com_err(PROGNAME, retval, "while setting foreign addr"); 205 exit(1); 206 } 207 208 addr.addrtype = ADDRTYPE_IPPORT; 209 addr.length = sizeof(c_sock.sin_port); 210 addr.contents = (krb5_octet *)&c_sock.sin_port; 211 if ((retval = krb5_auth_con_setports(context, auth_context, 212 NULL, &addr))) { 213 com_err(PROGNAME, retval, "while setting foreign port"); 214 exit(1); 215 } 216 217 /* GET KRB_MK_SAFE MESSAGE */ 218 219 /* use "recvfrom" so we know client's address */ 220 len = sizeof(struct sockaddr_in); 221 if ((i = recvfrom(sock, (char *)pktbuf, sizeof(pktbuf), flags, 222 (struct sockaddr *)&c_sock, &len)) < 0) { 223 perror("receiving datagram"); 224 exit(1); 225 } 226 #ifdef DEBUG 227 printf("&c_sock.sin_addr is %s\n", inet_ntoa(c_sock.sin_addr)); 228 #endif 229 printf("Received %d bytes\n", i); 230 231 packet.length = i; 232 packet.data = (krb5_pointer) pktbuf; 233 234 if ((retval = krb5_rd_safe(context, auth_context, &packet, 235 &message, NULL))) { 236 com_err(PROGNAME, retval, "while verifying SAFE message"); 237 exit(1); 238 } 239 printf("Safe message is: '%.*s'\n", (int) message.length, message.data); 240 241 krb5_free_data_contents(context, &message); 242 243 /* NOW GET ENCRYPTED MESSAGE */ 244 245 /* use "recvfrom" so we know client's address */ 246 len = sizeof(struct sockaddr_in); 247 if ((i = recvfrom(sock, (char *)pktbuf, sizeof(pktbuf), flags, 248 (struct sockaddr *)&c_sock, &len)) < 0) { 249 perror("receiving datagram"); 250 exit(1); 251 } 252 printf("Received %d bytes\n", i); 253 254 packet.length = i; 255 packet.data = (krb5_pointer) pktbuf; 256 257 if ((retval = krb5_rd_priv(context, auth_context, &packet, 258 &message, NULL))) { 259 com_err(PROGNAME, retval, "while verifying PRIV message"); 260 exit(1); 261 } 262 printf("Decrypted message is: '%.*s'\n", (int) message.length, 263 message.data); 264 265 krb5_auth_con_free(context, auth_context); 266 krb5_free_context(context); 267 268 exit(0); 269 } 270