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