1*7f2fe78bSCy Schubert /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2*7f2fe78bSCy Schubert /* appl/sample/sserver/sserver.c */
3*7f2fe78bSCy Schubert /*
4*7f2fe78bSCy Schubert * Copyright 1990,1991 by the Massachusetts Institute of Technology.
5*7f2fe78bSCy Schubert * All Rights Reserved.
6*7f2fe78bSCy Schubert *
7*7f2fe78bSCy Schubert * Export of this software from the United States of America may
8*7f2fe78bSCy Schubert * require a specific license from the United States Government.
9*7f2fe78bSCy Schubert * It is the responsibility of any person or organization contemplating
10*7f2fe78bSCy Schubert * export to obtain such a license before exporting.
11*7f2fe78bSCy Schubert *
12*7f2fe78bSCy Schubert * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13*7f2fe78bSCy Schubert * distribute this software and its documentation for any purpose and
14*7f2fe78bSCy Schubert * without fee is hereby granted, provided that the above copyright
15*7f2fe78bSCy Schubert * notice appear in all copies and that both that copyright notice and
16*7f2fe78bSCy Schubert * this permission notice appear in supporting documentation, and that
17*7f2fe78bSCy Schubert * the name of M.I.T. not be used in advertising or publicity pertaining
18*7f2fe78bSCy Schubert * to distribution of the software without specific, written prior
19*7f2fe78bSCy Schubert * permission. Furthermore if you modify this software you must label
20*7f2fe78bSCy Schubert * your software as modified software and not distribute it in such a
21*7f2fe78bSCy Schubert * fashion that it might be confused with the original M.I.T. software.
22*7f2fe78bSCy Schubert * M.I.T. makes no representations about the suitability of
23*7f2fe78bSCy Schubert * this software for any purpose. It is provided "as is" without express
24*7f2fe78bSCy Schubert * or implied warranty.
25*7f2fe78bSCy Schubert */
26*7f2fe78bSCy Schubert
27*7f2fe78bSCy Schubert /*
28*7f2fe78bSCy Schubert * Sample Kerberos v5 server.
29*7f2fe78bSCy Schubert *
30*7f2fe78bSCy Schubert * sample_server:
31*7f2fe78bSCy Schubert * A sample Kerberos server, which reads an AP_REQ from a TCP socket,
32*7f2fe78bSCy Schubert * decodes it, and writes back the results (in ASCII) to the client.
33*7f2fe78bSCy Schubert *
34*7f2fe78bSCy Schubert * Usage:
35*7f2fe78bSCy Schubert * sample_server servername
36*7f2fe78bSCy Schubert *
37*7f2fe78bSCy Schubert * file descriptor 0 (zero) should be a socket connected to the requesting
38*7f2fe78bSCy Schubert * client (this will be correct if this server is started by inetd).
39*7f2fe78bSCy Schubert */
40*7f2fe78bSCy Schubert
41*7f2fe78bSCy Schubert #include "k5-int.h"
42*7f2fe78bSCy Schubert #include "com_err.h"
43*7f2fe78bSCy Schubert
44*7f2fe78bSCy Schubert #include <stdio.h>
45*7f2fe78bSCy Schubert #include <string.h>
46*7f2fe78bSCy Schubert #include <ctype.h>
47*7f2fe78bSCy Schubert #include <sys/types.h>
48*7f2fe78bSCy Schubert #include <sys/socket.h>
49*7f2fe78bSCy Schubert #include <netinet/in.h>
50*7f2fe78bSCy Schubert #include <netdb.h>
51*7f2fe78bSCy Schubert #include <syslog.h>
52*7f2fe78bSCy Schubert
53*7f2fe78bSCy Schubert #ifdef HAVE_UNISTD_H
54*7f2fe78bSCy Schubert #include <unistd.h>
55*7f2fe78bSCy Schubert #endif
56*7f2fe78bSCy Schubert
57*7f2fe78bSCy Schubert #include "../sample.h"
58*7f2fe78bSCy Schubert
59*7f2fe78bSCy Schubert extern krb5_deltat krb5_clockskew;
60*7f2fe78bSCy Schubert
61*7f2fe78bSCy Schubert #ifndef GETPEERNAME_ARG3_TYPE
62*7f2fe78bSCy Schubert #define GETPEERNAME_ARG3_TYPE int
63*7f2fe78bSCy Schubert #endif
64*7f2fe78bSCy Schubert
65*7f2fe78bSCy Schubert static void
usage(char * name)66*7f2fe78bSCy Schubert usage(char *name)
67*7f2fe78bSCy Schubert {
68*7f2fe78bSCy Schubert fprintf(stderr, "usage: %s [-p port] [-s service] [-S keytab]\n",
69*7f2fe78bSCy Schubert name);
70*7f2fe78bSCy Schubert }
71*7f2fe78bSCy Schubert
72*7f2fe78bSCy Schubert int
main(int argc,char * argv[])73*7f2fe78bSCy Schubert main(int argc, char *argv[])
74*7f2fe78bSCy Schubert {
75*7f2fe78bSCy Schubert krb5_context context;
76*7f2fe78bSCy Schubert krb5_auth_context auth_context = NULL;
77*7f2fe78bSCy Schubert krb5_ticket * ticket;
78*7f2fe78bSCy Schubert struct sockaddr_in peername;
79*7f2fe78bSCy Schubert GETPEERNAME_ARG3_TYPE namelen = sizeof(peername);
80*7f2fe78bSCy Schubert int sock = -1; /* incoming connection fd */
81*7f2fe78bSCy Schubert krb5_data recv_data;
82*7f2fe78bSCy Schubert short xmitlen;
83*7f2fe78bSCy Schubert krb5_error_code retval;
84*7f2fe78bSCy Schubert krb5_principal server;
85*7f2fe78bSCy Schubert char repbuf[BUFSIZ];
86*7f2fe78bSCy Schubert char *cname;
87*7f2fe78bSCy Schubert char *service = SAMPLE_SERVICE;
88*7f2fe78bSCy Schubert short port = 0; /* If user specifies port */
89*7f2fe78bSCy Schubert extern int opterr, optind;
90*7f2fe78bSCy Schubert extern char * optarg;
91*7f2fe78bSCy Schubert int ch;
92*7f2fe78bSCy Schubert krb5_keytab keytab = NULL; /* Allow specification on command line */
93*7f2fe78bSCy Schubert char *progname;
94*7f2fe78bSCy Schubert int on = 1;
95*7f2fe78bSCy Schubert
96*7f2fe78bSCy Schubert progname = *argv;
97*7f2fe78bSCy Schubert
98*7f2fe78bSCy Schubert retval = krb5_init_context(&context);
99*7f2fe78bSCy Schubert if (retval) {
100*7f2fe78bSCy Schubert com_err(argv[0], retval, "while initializing krb5");
101*7f2fe78bSCy Schubert exit(1);
102*7f2fe78bSCy Schubert }
103*7f2fe78bSCy Schubert
104*7f2fe78bSCy Schubert /* open a log connection */
105*7f2fe78bSCy Schubert openlog("sserver", 0, LOG_DAEMON);
106*7f2fe78bSCy Schubert
107*7f2fe78bSCy Schubert /*
108*7f2fe78bSCy Schubert * Parse command line arguments
109*7f2fe78bSCy Schubert *
110*7f2fe78bSCy Schubert */
111*7f2fe78bSCy Schubert opterr = 0;
112*7f2fe78bSCy Schubert while ((ch = getopt(argc, argv, "p:S:s:")) != -1) {
113*7f2fe78bSCy Schubert switch (ch) {
114*7f2fe78bSCy Schubert case 'p':
115*7f2fe78bSCy Schubert port = atoi(optarg);
116*7f2fe78bSCy Schubert break;
117*7f2fe78bSCy Schubert case 's':
118*7f2fe78bSCy Schubert service = optarg;
119*7f2fe78bSCy Schubert break;
120*7f2fe78bSCy Schubert case 'S':
121*7f2fe78bSCy Schubert if ((retval = krb5_kt_resolve(context, optarg, &keytab))) {
122*7f2fe78bSCy Schubert com_err(progname, retval,
123*7f2fe78bSCy Schubert "while resolving keytab file %s", optarg);
124*7f2fe78bSCy Schubert exit(2);
125*7f2fe78bSCy Schubert }
126*7f2fe78bSCy Schubert break;
127*7f2fe78bSCy Schubert
128*7f2fe78bSCy Schubert case '?':
129*7f2fe78bSCy Schubert default:
130*7f2fe78bSCy Schubert usage(progname);
131*7f2fe78bSCy Schubert exit(1);
132*7f2fe78bSCy Schubert break;
133*7f2fe78bSCy Schubert }
134*7f2fe78bSCy Schubert }
135*7f2fe78bSCy Schubert
136*7f2fe78bSCy Schubert argc -= optind;
137*7f2fe78bSCy Schubert argv += optind;
138*7f2fe78bSCy Schubert
139*7f2fe78bSCy Schubert /* Backwards compatibility, allow port to be specified at end */
140*7f2fe78bSCy Schubert if (argc > 1) {
141*7f2fe78bSCy Schubert port = atoi(argv[1]);
142*7f2fe78bSCy Schubert }
143*7f2fe78bSCy Schubert
144*7f2fe78bSCy Schubert retval = krb5_sname_to_principal(context, NULL, service,
145*7f2fe78bSCy Schubert KRB5_NT_SRV_HST, &server);
146*7f2fe78bSCy Schubert if (retval) {
147*7f2fe78bSCy Schubert syslog(LOG_ERR, "while generating service name (%s): %s",
148*7f2fe78bSCy Schubert service, error_message(retval));
149*7f2fe78bSCy Schubert exit(1);
150*7f2fe78bSCy Schubert }
151*7f2fe78bSCy Schubert
152*7f2fe78bSCy Schubert /*
153*7f2fe78bSCy Schubert * If user specified a port, then listen on that port; otherwise,
154*7f2fe78bSCy Schubert * assume we've been started out of inetd.
155*7f2fe78bSCy Schubert */
156*7f2fe78bSCy Schubert
157*7f2fe78bSCy Schubert if (port) {
158*7f2fe78bSCy Schubert int acc;
159*7f2fe78bSCy Schubert struct sockaddr_in sockin;
160*7f2fe78bSCy Schubert
161*7f2fe78bSCy Schubert if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
162*7f2fe78bSCy Schubert syslog(LOG_ERR, "socket: %m");
163*7f2fe78bSCy Schubert exit(3);
164*7f2fe78bSCy Schubert }
165*7f2fe78bSCy Schubert /* Let the socket be reused right away */
166*7f2fe78bSCy Schubert (void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
167*7f2fe78bSCy Schubert sizeof(on));
168*7f2fe78bSCy Schubert
169*7f2fe78bSCy Schubert sockin.sin_family = AF_INET;
170*7f2fe78bSCy Schubert sockin.sin_addr.s_addr = 0;
171*7f2fe78bSCy Schubert sockin.sin_port = htons(port);
172*7f2fe78bSCy Schubert if (bind(sock, (struct sockaddr *) &sockin, sizeof(sockin))) {
173*7f2fe78bSCy Schubert syslog(LOG_ERR, "bind: %m");
174*7f2fe78bSCy Schubert exit(3);
175*7f2fe78bSCy Schubert }
176*7f2fe78bSCy Schubert if (listen(sock, 1) == -1) {
177*7f2fe78bSCy Schubert syslog(LOG_ERR, "listen: %m");
178*7f2fe78bSCy Schubert exit(3);
179*7f2fe78bSCy Schubert }
180*7f2fe78bSCy Schubert
181*7f2fe78bSCy Schubert printf("starting...\n");
182*7f2fe78bSCy Schubert fflush(stdout);
183*7f2fe78bSCy Schubert
184*7f2fe78bSCy Schubert if ((acc = accept(sock, (struct sockaddr *)&peername, &namelen)) == -1){
185*7f2fe78bSCy Schubert syslog(LOG_ERR, "accept: %m");
186*7f2fe78bSCy Schubert exit(3);
187*7f2fe78bSCy Schubert }
188*7f2fe78bSCy Schubert dup2(acc, 0);
189*7f2fe78bSCy Schubert close(sock);
190*7f2fe78bSCy Schubert sock = 0;
191*7f2fe78bSCy Schubert } else {
192*7f2fe78bSCy Schubert /*
193*7f2fe78bSCy Schubert * To verify authenticity, we need to know the address of the
194*7f2fe78bSCy Schubert * client.
195*7f2fe78bSCy Schubert */
196*7f2fe78bSCy Schubert if (getpeername(0, (struct sockaddr *)&peername, &namelen) < 0) {
197*7f2fe78bSCy Schubert syslog(LOG_ERR, "getpeername: %m");
198*7f2fe78bSCy Schubert exit(1);
199*7f2fe78bSCy Schubert }
200*7f2fe78bSCy Schubert sock = 0;
201*7f2fe78bSCy Schubert }
202*7f2fe78bSCy Schubert
203*7f2fe78bSCy Schubert retval = krb5_recvauth(context, &auth_context, (krb5_pointer)&sock,
204*7f2fe78bSCy Schubert SAMPLE_VERSION, server,
205*7f2fe78bSCy Schubert 0, /* no flags */
206*7f2fe78bSCy Schubert keytab, /* default keytab is NULL */
207*7f2fe78bSCy Schubert &ticket);
208*7f2fe78bSCy Schubert if (retval) {
209*7f2fe78bSCy Schubert syslog(LOG_ERR, "recvauth failed--%s", error_message(retval));
210*7f2fe78bSCy Schubert exit(1);
211*7f2fe78bSCy Schubert }
212*7f2fe78bSCy Schubert
213*7f2fe78bSCy Schubert /* Get client name */
214*7f2fe78bSCy Schubert repbuf[sizeof(repbuf) - 1] = '\0';
215*7f2fe78bSCy Schubert retval = krb5_unparse_name(context, ticket->enc_part2->client, &cname);
216*7f2fe78bSCy Schubert if (retval){
217*7f2fe78bSCy Schubert syslog(LOG_ERR, "unparse failed: %s", error_message(retval));
218*7f2fe78bSCy Schubert strncpy(repbuf, "You are <unparse error>\n", sizeof(repbuf) - 1);
219*7f2fe78bSCy Schubert } else {
220*7f2fe78bSCy Schubert strncpy(repbuf, "You are ", sizeof(repbuf) - 1);
221*7f2fe78bSCy Schubert strncat(repbuf, cname, sizeof(repbuf) - 1 - strlen(repbuf));
222*7f2fe78bSCy Schubert strncat(repbuf, "\n", sizeof(repbuf) - 1 - strlen(repbuf));
223*7f2fe78bSCy Schubert free(cname);
224*7f2fe78bSCy Schubert }
225*7f2fe78bSCy Schubert xmitlen = htons(strlen(repbuf));
226*7f2fe78bSCy Schubert recv_data.length = strlen(repbuf);
227*7f2fe78bSCy Schubert recv_data.data = repbuf;
228*7f2fe78bSCy Schubert if ((retval = krb5_net_write(context, 0, (char *)&xmitlen,
229*7f2fe78bSCy Schubert sizeof(xmitlen))) < 0) {
230*7f2fe78bSCy Schubert syslog(LOG_ERR, "%m: while writing len to client");
231*7f2fe78bSCy Schubert exit(1);
232*7f2fe78bSCy Schubert }
233*7f2fe78bSCy Schubert if ((retval = krb5_net_write(context, 0, (char *)recv_data.data,
234*7f2fe78bSCy Schubert recv_data.length)) < 0) {
235*7f2fe78bSCy Schubert syslog(LOG_ERR, "%m: while writing data to client");
236*7f2fe78bSCy Schubert exit(1);
237*7f2fe78bSCy Schubert }
238*7f2fe78bSCy Schubert
239*7f2fe78bSCy Schubert krb5_free_ticket(context, ticket);
240*7f2fe78bSCy Schubert if(keytab)
241*7f2fe78bSCy Schubert krb5_kt_close(context, keytab);
242*7f2fe78bSCy Schubert krb5_free_principal(context, server);
243*7f2fe78bSCy Schubert krb5_auth_con_free(context, auth_context);
244*7f2fe78bSCy Schubert krb5_free_context(context);
245*7f2fe78bSCy Schubert exit(0);
246*7f2fe78bSCy Schubert }
247