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
usage(char * name)59 usage(char *name)
60 {
61 fprintf(stderr, "usage: %s [-p port] [-s service] [-S keytab]\n", name);
62 }
63
64 int
main(int argc,char * argv[])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