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