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