xref: /freebsd/crypto/krb5/src/appl/sample/sserver/sserver.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
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