1 /* $Id: server.c,v 1.9 2004/03/29 14:56:40 rjs3 Exp $ */
3 * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in
14 * the documentation and/or other materials provided with the
17 * 3. The name "Carnegie Mellon University" must not be used to
18 * endorse or promote products derived from this software without
19 * prior written permission. For permission or any other legal
20 * details, please contact
21 * Office of Technology Transfer
22 * Carnegie Mellon University
24 * Pittsburgh, PA 15213-3890
25 * (412) 268-4387, fax: (412) 268-7395
26 * tech-transfer@andrew.cmu.edu
28 * 4. Redistributions of any form whatsoever must retain the following
30 * "This product includes software developed by Computing Services
31 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
33 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
34 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
35 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
36 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
37 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
38 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
39 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
55 #include <sys/socket.h>
56 #include <netinet/in.h>
57 #include <arpa/inet.h>
64 #if !defined(IPV6_BINDV6ONLY) && defined(IN6P_IPV6_V6ONLY)
65 #define IPV6_BINDV6ONLY IN6P_BINDV6ONLY
67 #if !defined(IPV6_V6ONLY) && defined(IPV6_BINDV6ONLY)
68 #define IPV6_V6ONLY IPV6_BINDV6ONLY
70 #ifndef IPV6_BINDV6ONLY
74 /* create a socket listening on port 'port' */
75 /* if af is PF_UNSPEC more than one socket may be returned */
76 /* the returned list is dynamically allocated, so caller needs to free it */
77 int *listensock(const char *port, const int af)
79 struct addrinfo hints, *ai, *r;
80 int err, maxs, *sock, *socks;
83 memset(&hints, 0, sizeof(hints));
84 hints.ai_flags = AI_PASSIVE;
86 hints.ai_socktype = SOCK_STREAM;
87 err = getaddrinfo(NULL, port, &hints, &ai);
89 fprintf(stderr, "%s\n", gai_strerror(err));
93 /* Count max number of sockets we may open */
94 for (maxs = 0, r = ai; r; r = r->ai_next, maxs++)
96 socks = malloc((maxs + 1) * sizeof(int));
98 fprintf(stderr, "couldn't allocate memory for sockets\n");
103 socks[0] = 0; /* num of sockets counter at start of array */
105 for (r = ai; r; r = r->ai_next) {
106 fprintf(stderr, "trying %d, %d, %d\n",r->ai_family, r->ai_socktype, r->ai_protocol);
107 *sock = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
112 if (setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR,
113 (void *) &on, sizeof(on)) < 0) {
114 perror("setsockopt(SO_REUSEADDR)");
118 #if defined(IPV6_V6ONLY) && !(defined(__FreeBSD__) && __FreeBSD__ < 3)
119 if (r->ai_family == AF_INET6) {
120 if (setsockopt(*sock, IPPROTO_IPV6, IPV6_BINDV6ONLY,
121 (void *) &on, sizeof(on)) < 0) {
122 perror("setsockopt (IPV6_BINDV6ONLY)");
128 if (bind(*sock, r->ai_addr, r->ai_addrlen) < 0) {
134 if (listen(*sock, 5) < 0) {
147 fprintf(stderr, "Couldn't bind to any socket\n");
157 fprintf(stderr, "usage: server [-p port] [-s service] [-m mech]\n");
161 /* globals because i'm lazy */
164 /* do the sasl negotiation; return -1 if it fails */
165 int mysasl_negotiate(FILE *in, FILE *out, sasl_conn_t *conn)
168 char chosenmech[128];
174 /* generate the capability list */
176 dprintf(2, "forcing use of mechanism %s\n", mech);
182 dprintf(1, "generating client mechanism list... ");
183 r = sasl_listmech(conn, NULL, NULL, " ", NULL,
184 &data, &len, &count);
185 if (r != SASL_OK) saslfail(r, "generating mechanism list");
186 dprintf(1, "%d mechanisms\n", count);
189 /* send capability list to client */
190 send_string(out, data, len);
192 dprintf(1, "waiting for client mechanism...\n");
193 len = recv_string(in, chosenmech, sizeof chosenmech);
195 printf("client didn't choose mechanism\n");
196 fputc('N', out); /* send NO to client */
201 if (mech && strcasecmp(mech, chosenmech)) {
202 printf("client didn't choose mandatory mechanism\n");
203 fputc('N', out); /* send NO to client */
208 len = recv_string(in, buf, sizeof(buf));
210 saslerr(r, "didn't receive first-send parameter correctly");
217 /* receive initial response (if any) */
218 len = recv_string(in, buf, sizeof(buf));
220 /* start libsasl negotiation */
221 r = sasl_server_start(conn, chosenmech, buf, len,
224 r = sasl_server_start(conn, chosenmech, NULL, 0,
228 if (r != SASL_OK && r != SASL_CONTINUE) {
229 saslerr(r, "starting SASL negotiation");
230 fputc('N', out); /* send NO to client */
235 while (r == SASL_CONTINUE) {
237 dprintf(2, "sending response length %d...\n", len);
238 fputc('C', out); /* send CONTINUE to client */
239 send_string(out, data, len);
241 dprintf(2, "sending null response...\n");
242 fputc('C', out); /* send CONTINUE to client */
243 send_string(out, "", 0);
246 dprintf(1, "waiting for client reply...\n");
247 len = recv_string(in, buf, sizeof buf);
249 printf("client disconnected\n");
253 r = sasl_server_step(conn, buf, len, &data, &len);
254 if (r != SASL_OK && r != SASL_CONTINUE) {
255 saslerr(r, "performing SASL negotiation");
256 fputc('N', out); /* send NO to client */
263 saslerr(r, "incorrect authentication");
264 fputc('N', out); /* send NO to client */
269 fputc('O', out); /* send OK to client */
271 dprintf(1, "negotiation complete\n");
273 r = sasl_getprop(conn, SASL_USERNAME, (const void **) &userid);
274 printf("successful authentication '%s'\n", userid);
279 int main(int argc, char *argv[])
282 char *port = "12345";
283 char *service = "rcmd";
288 while ((c = getopt(argc, argv, "p:s:m:")) != EOF) {
308 /* initialize the sasl library */
309 r = sasl_server_init(NULL, "sample");
310 if (r != SASL_OK) saslfail(r, "initializing libsasl");
312 /* get a listening socket */
313 if ((l = listensock(port, PF_UNSPEC)) == NULL) {
314 saslfail(SASL_FAIL, "allocating listensock");
317 for (i = 1; i <= l[0]; i++) {
323 char localaddr[NI_MAXHOST | NI_MAXSERV],
324 remoteaddr[NI_MAXHOST | NI_MAXSERV];
325 char myhostname[1024+1];
326 char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
327 struct sockaddr_storage local_ip, remote_ip;
335 for (i = 1; i <= l[0]; i++)
336 FD_SET(l[i], &readfds);
338 nfds = select(maxfd + 1, &readfds, 0, 0, 0);
340 if (nfds < 0 && errno != EINTR)
345 for (i = 1; i <= l[0]; i++)
346 if (FD_ISSET(l[i], &readfds)) {
347 fd = accept(l[i], NULL, NULL);
357 printf("accepted new connection\n");
359 /* set ip addresses */
360 salen = sizeof(local_ip);
361 if (getsockname(fd, (struct sockaddr *)&local_ip, &salen) < 0) {
362 perror("getsockname");
364 niflags = (NI_NUMERICHOST | NI_NUMERICSERV);
365 #ifdef NI_WITHSCOPEID
366 if (((struct sockaddr *)&local_ip)->sa_family == AF_INET6)
367 niflags |= NI_WITHSCOPEID;
369 error = getnameinfo((struct sockaddr *)&local_ip, salen, hbuf,
370 sizeof(hbuf), pbuf, sizeof(pbuf), niflags);
372 fprintf(stderr, "getnameinfo: %s\n", gai_strerror(error));
373 strcpy(hbuf, "unknown");
374 strcpy(pbuf, "unknown");
376 snprintf(localaddr, sizeof(localaddr), "%s;%s", hbuf, pbuf);
378 salen = sizeof(remote_ip);
379 if (getpeername(fd, (struct sockaddr *)&remote_ip, &salen) < 0) {
380 perror("getpeername");
383 niflags = (NI_NUMERICHOST | NI_NUMERICSERV);
384 #ifdef NI_WITHSCOPEID
385 if (((struct sockaddr *)&remote_ip)->sa_family == AF_INET6)
386 niflags |= NI_WITHSCOPEID;
388 error = getnameinfo((struct sockaddr *)&remote_ip, salen, hbuf,
389 sizeof(hbuf), pbuf, sizeof(pbuf), niflags);
391 fprintf(stderr, "getnameinfo: %s\n", gai_strerror(error));
392 strcpy(hbuf, "unknown");
393 strcpy(pbuf, "unknown");
395 snprintf(remoteaddr, sizeof(remoteaddr), "%s;%s", hbuf, pbuf);
397 r = gethostname(myhostname, sizeof(myhostname)-1);
398 if(r == -1) saslfail(r, "getting hostname");
400 r = sasl_server_new(service, myhostname, NULL, localaddr, remoteaddr,
402 if (r != SASL_OK) saslfail(r, "allocating connection state");
404 /* set external properties here
405 sasl_setprop(conn, SASL_SSF_EXTERNAL, &extprops); */
407 /* set required security properties here
408 sasl_setprop(conn, SASL_SEC_PROPS, &secprops); */
410 in = fdopen(fd, "r");
411 out = fdopen(fd, "w");
413 r = mysasl_negotiate(in, out, conn);
415 /* send/receive data */
420 printf("closing connection\n");