Fix handling of errors with strtol(), factor out port parsing
[trust_router.git] / gsscon / test / gsscon_server.c
1 /*
2  * Copyright (c) 2012, JANET(UK)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * 3. Neither the name of JANET(UK) nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
31  * OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  * This code was adapted from the MIT Kerberos Consortium's
34  * GSS example code, which was distributed under the following
35  * license:
36  *
37  * Copyright 2004-2006 Massachusetts Institute of Technology.
38  * All Rights Reserved.
39  *
40  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
41  * distribute this software and its documentation for any purpose and
42  * without fee is hereby granted, provided that the above copyright
43  * notice appear in all copies and that both that copyright notice and
44  * this permission notice appear in supporting documentation, and that
45  * the name of M.I.T. not be used in advertising or publicity pertaining
46  * to distribution of the software without specific, written prior
47  * permission.  Furthermore if you modify this software you must label
48  * your software as modified software and not distribute it in such a
49  * fashion that it might be confused with the original M.I.T. software.
50  * M.I.T. makes no representations about the suitability of
51  * this software for any purpose.  It is provided "as is" without express
52  * or implied warranty.
53  */
54
55 #include <gsscon.h>
56 #include <assert.h>
57
58 static int cb_print_names(gss_name_t clientName,
59                           gss_buffer_t displayName,
60                           void *data)
61 {
62   assert(clientName != NULL);
63   assert(data == NULL);
64   printf("Gss name: %-*s\n",
65          displayName->length, displayName->value);
66   return 0;
67 }
68
69   
70 /* --------------------------------------------------------------------------- */
71
72 static int SetupListeningSocket (int  inPort, 
73                                  int *outFD)
74 {
75     int err = 0;
76     int fd = -1;
77     
78     if (!outFD) { err = EINVAL; }
79     
80     if (!err) {
81         fd = socket (AF_INET, SOCK_STREAM, 0);
82         if (fd < 0) { err = errno; }
83     }
84     
85     if (!err) {
86         struct sockaddr_storage addressStorage;
87         struct sockaddr_in *saddr = (struct sockaddr_in *) &addressStorage;
88         
89         saddr->sin_port = htons (inPort);
90         //        saddr->sin_len = sizeof (struct sockaddr_in);
91         saddr->sin_family = AF_INET;
92         saddr->sin_addr.s_addr = INADDR_ANY;
93         
94         err = bind (fd, (struct sockaddr *) saddr, sizeof(struct sockaddr_in));
95         if (err < 0) { err = errno; }
96     }
97     
98     if (!err) {
99         err = listen (fd, 5);
100         if (err < 0) { err = errno; }
101     }
102     
103     if (!err) {
104         printf ("listening on port %d\n", inPort);
105         *outFD = fd;
106         fd = -1; /* only close on error */
107     } else {
108         gsscon_print_error (err, "SetupListeningSocket failed");
109     }
110     
111     if (fd >= 0) { close (fd); }
112     
113     return err; 
114 }
115
116 /* --------------------------------------------------------------------------- */
117
118 static void Usage (const char *argv[])
119 {
120     fprintf (stderr, "Usage: %s [--port portNumber] [--service serviceName]\n", 
121              argv[0]);
122     exit (1);
123 }
124
125 /* --------------------------------------------------------------------------- */
126
127 int main (int argc, const char *argv[])
128 {
129     int err = 0;
130     OM_uint32 minorStatus;
131     int port = kDefaultPort;
132     long tmp;
133     int listenFD = -1;
134     gss_ctx_id_t gssContext = GSS_C_NO_CONTEXT;
135     int i = 0;
136     gss_buffer_desc nameBuffer = {0, "trustidentity"};
137
138     for (i = 1; (i < argc) && !err; i++) {
139         if ((strcmp (argv[i], "--port") == 0) && (i < (argc - 1))) {
140             errno = 0; /* ensure this starts off at 0 */
141             tmp = strtol (argv[++i], NULL, 0);
142             if (errno)
143                 err = errno;
144             else if ((tmp <= 0) || (tmp > 65535))
145                 err = ERANGE;
146             else
147                 port = (int) tmp;
148         } else if ((strcmp(argv[i], "--service") == 0) && (i < (argc - 1))) {
149             gServiceName = argv[++i];
150         } else {
151             err = EINVAL;
152         }
153     }
154
155     if (!err) {
156         printf ("%s: Starting up...\n", argv[0]);
157         
158         err = SetupListeningSocket (port, &listenFD);
159     }
160     
161     while (!err) {
162         int connectionErr = 0;
163         int connectionFD = -1;
164         int authorized = 0;
165         int authorizationError = 0;
166         
167         connectionFD = accept (listenFD, NULL, NULL);
168
169         if (connectionFD < 0) {
170             if (errno != EINTR) { 
171                 err = errno;
172             }
173             continue;  /* Try again */
174         }
175         
176         printf ("Accepting new connection...\n");
177         connectionErr = gsscon_passive_authenticate (connectionFD, nameBuffer, &gssContext,
178                                                      cb_print_names, NULL);
179         
180         if (!connectionErr) {
181             connectionErr = gsscon_authorize (gssContext, 
182                                        &authorized, 
183                                        &authorizationError);
184         }
185         
186         if (!connectionErr) {
187             char buffer[1024];
188             memset (buffer, 0, sizeof (buffer));                
189
190             /* 
191              * Here is where your protocol would go.  This sample server just
192              * writes a nul terminated string to the client telling whether 
193              * it was authorized.
194              */
195             if (authorized) {
196                 snprintf (buffer, sizeof (buffer), "SUCCESS!"); 
197             } else {
198                 snprintf (buffer, sizeof(buffer), "FAILURE! %s (err = %d)", 
199                           error_message (authorizationError), 
200                           authorizationError); 
201             }
202             connectionErr = gsscon_write_encrypted_token (connectionFD, gssContext, 
203                                                  buffer, strlen (buffer) + 1);
204         }
205         
206         if (connectionErr) {
207             gsscon_print_error (connectionErr, "Connection failed");
208         }
209         
210         if (connectionFD >= 0) { 
211             printf ("Closing connection.\n"); 
212             close (connectionFD); 
213         }
214     }
215     
216     if (err) { 
217         if (err == EINVAL) {
218             Usage (argv);
219         } else {
220             gsscon_print_error (err, "Server failed");
221         }
222     }
223     
224     if (listenFD >= 0) { close (listenFD); }
225     if (gssContext != GSS_C_NO_CONTEXT) { 
226         gss_delete_sec_context (&minorStatus, &gssContext, GSS_C_NO_BUFFER); }
227     
228     return err ? -1 : 0;
229 }
230