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.
42 * Copyright 2009 by the Massachusetts Institute of Technology.
43 * All Rights Reserved.
45 * Export of this software from the United States of America may
46 * require a specific license from the United States Government.
47 * It is the responsibility of any person or organization contemplating
48 * export to obtain such a license before exporting.
50 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
51 * distribute this software and its documentation for any purpose and
52 * without fee is hereby granted, provided that the above copyright
53 * notice appear in all copies and that both that copyright notice and
54 * this permission notice appear in supporting documentation, and that
55 * the name of M.I.T. not be used in advertising or publicity pertaining
56 * to distribution of the software without specific, written prior
57 * permission. Furthermore if you modify this software you must label
58 * your software as modified software and not distribute it in such a
59 * fashion that it might be confused with the original M.I.T. software.
60 * M.I.T. makes no representations about the suitability of
61 * this software for any purpose. It is provided "as is" without express
62 * or implied warranty.
79 #include <sys/socket.h>
80 #include <netinet/in.h>
81 #include <arpa/inet.h>
85 #include <gssapi/gssapi.h>
86 #include <gssapi/gssapi_ext.h>
90 #if !defined(IPV6_BINDV6ONLY) && defined(IN6P_IPV6_V6ONLY)
91 #define IPV6_BINDV6ONLY IN6P_BINDV6ONLY
93 #if !defined(IPV6_V6ONLY) && defined(IPV6_BINDV6ONLY)
94 #define IPV6_V6ONLY IPV6_BINDV6ONLY
96 #ifndef IPV6_BINDV6ONLY
101 enumerateAttributes(OM_uint32 *minor,
105 /* create a socket listening on port 'port' */
106 /* if af is PF_UNSPEC more than one socket may be returned */
107 /* the returned list is dynamically allocated, so caller needs to free it */
108 int *listensock(const char *port, const int af)
110 struct addrinfo hints, *ai, *r;
111 int err, maxs, *sock, *socks;
114 memset(&hints, 0, sizeof(hints));
115 hints.ai_flags = AI_PASSIVE;
116 hints.ai_family = af;
117 hints.ai_socktype = SOCK_STREAM;
118 err = getaddrinfo(NULL, port, &hints, &ai);
120 fprintf(stderr, "%s\n", gai_strerror(err));
124 /* Count max number of sockets we may open */
125 for (maxs = 0, r = ai; r; r = r->ai_next, maxs++)
127 socks = malloc((maxs + 1) * sizeof(int));
129 fprintf(stderr, "couldn't allocate memory for sockets\n");
134 socks[0] = 0; /* num of sockets counter at start of array */
136 for (r = ai; r; r = r->ai_next) {
137 fprintf(stderr, "trying %d, %d, %d\n",r->ai_family, r->ai_socktype, r->ai_protocol);
138 *sock = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
143 if (setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR,
144 (void *) &on, sizeof(on)) < 0) {
145 perror("setsockopt(SO_REUSEADDR)");
149 #if defined(IPV6_V6ONLY) && !(defined(__FreeBSD__) && __FreeBSD__ < 3)
150 if (r->ai_family == AF_INET6) {
151 if (setsockopt(*sock, IPPROTO_IPV6, IPV6_BINDV6ONLY,
152 (void *) &on, sizeof(on)) < 0) {
153 perror("setsockopt (IPV6_BINDV6ONLY)");
159 if (bind(*sock, r->ai_addr, r->ai_addrlen) < 0) {
165 if (listen(*sock, 5) < 0) {
178 fprintf(stderr, "Couldn't bind to any socket\n");
188 fprintf(stderr, "usage: server [-p port] [-s service] [-m mech]\n");
192 /* globals because i'm lazy */
195 /* do the sasl negotiation; return -1 if it fails */
196 int mysasl_negotiate(FILE *in, FILE *out, sasl_conn_t *conn)
199 char chosenmech[128];
204 gss_name_t peer = GSS_C_NO_NAME;
206 /* generate the capability list */
208 dprintf(2, "forcing use of mechanism %s\n", mech);
214 dprintf(1, "generating client mechanism list... ");
215 r = sasl_listmech(conn, NULL, NULL, " ", NULL,
216 &data, &len, &count);
217 if (r != SASL_OK) saslfail(r, "generating mechanism list");
218 dprintf(1, "%d mechanisms\n", count);
221 /* send capability list to client */
222 send_string(out, data, len);
224 dprintf(1, "waiting for client mechanism...\n");
225 len = recv_string(in, chosenmech, sizeof chosenmech);
227 printf("client didn't choose mechanism\n");
228 fputc('N', out); /* send NO to client */
233 if (mech && strcasecmp(mech, chosenmech)) {
234 printf("client didn't choose mandatory mechanism\n");
235 fputc('N', out); /* send NO to client */
240 len = recv_string(in, buf, sizeof(buf));
242 saslerr(r, "didn't receive first-send parameter correctly");
249 /* receive initial response (if any) */
250 len = recv_string(in, buf, sizeof(buf));
252 /* start libsasl negotiation */
253 r = sasl_server_start(conn, chosenmech, buf, len,
256 r = sasl_server_start(conn, chosenmech, NULL, 0,
260 if (r != SASL_OK && r != SASL_CONTINUE) {
261 saslerr(r, "starting SASL negotiation");
262 fputc('N', out); /* send NO to client */
267 while (r == SASL_CONTINUE) {
269 dprintf(2, "sending response length %d...\n", len);
270 fputc('C', out); /* send CONTINUE to client */
271 send_string(out, data, len);
273 dprintf(2, "sending null response...\n");
274 fputc('C', out); /* send CONTINUE to client */
275 send_string(out, "", 0);
278 dprintf(1, "waiting for client reply...\n");
279 len = recv_string(in, buf, sizeof buf);
281 printf("client disconnected\n");
285 r = sasl_server_step(conn, buf, len, &data, &len);
286 if (r != SASL_OK && r != SASL_CONTINUE) {
287 saslerr(r, "performing SASL negotiation");
288 fputc('N', out); /* send NO to client */
295 saslerr(r, "incorrect authentication");
296 fputc('N', out); /* send NO to client */
301 fputc('O', out); /* send OK to client */
303 dprintf(1, "negotiation complete\n");
305 r = sasl_getprop(conn, SASL_USERNAME, (const void **) &userid);
306 printf("successful authentication '%s'\n", userid);
308 r = sasl_getprop(conn, SASL_GSS_PEER_NAME, (const void **) &peer);
309 if (peer != GSS_C_NO_NAME) {
311 enumerateAttributes(&minor, peer, 1);
317 int main(int argc, char *argv[])
320 char *port = "12345";
321 char *service = "rcmd";
327 while ((c = getopt(argc, argv, "cp:s:m:")) != EOF) {
351 /* initialize the sasl library */
352 r = sasl_server_init(NULL, "sample");
353 if (r != SASL_OK) saslfail(r, "initializing libsasl");
355 /* get a listening socket */
356 if ((l = listensock(port, PF_UNSPEC)) == NULL) {
357 saslfail(SASL_FAIL, "allocating listensock");
360 for (i = 1; i <= l[0]; i++) {
366 char localaddr[NI_MAXHOST | NI_MAXSERV],
367 remoteaddr[NI_MAXHOST | NI_MAXSERV];
368 char myhostname[1024+1];
369 char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
370 struct sockaddr_storage local_ip, remote_ip;
376 sasl_channel_binding cb;
379 for (i = 1; i <= l[0]; i++)
380 FD_SET(l[i], &readfds);
382 nfds = select(maxfd + 1, &readfds, 0, 0, 0);
384 if (nfds < 0 && errno != EINTR)
389 for (i = 1; i <= l[0]; i++)
390 if (FD_ISSET(l[i], &readfds)) {
391 fd = accept(l[i], NULL, NULL);
401 printf("accepted new connection\n");
403 /* set ip addresses */
404 salen = sizeof(local_ip);
405 if (getsockname(fd, (struct sockaddr *)&local_ip, &salen) < 0) {
406 perror("getsockname");
408 niflags = (NI_NUMERICHOST | NI_NUMERICSERV);
409 #ifdef NI_WITHSCOPEID
410 if (((struct sockaddr *)&local_ip)->sa_family == AF_INET6)
411 niflags |= NI_WITHSCOPEID;
413 error = getnameinfo((struct sockaddr *)&local_ip, salen, hbuf,
414 sizeof(hbuf), pbuf, sizeof(pbuf), niflags);
416 fprintf(stderr, "getnameinfo: %s\n", gai_strerror(error));
417 strcpy(hbuf, "unknown");
418 strcpy(pbuf, "unknown");
420 snprintf(localaddr, sizeof(localaddr), "%s;%s", hbuf, pbuf);
422 salen = sizeof(remote_ip);
423 if (getpeername(fd, (struct sockaddr *)&remote_ip, &salen) < 0) {
424 perror("getpeername");
427 niflags = (NI_NUMERICHOST | NI_NUMERICSERV);
428 #ifdef NI_WITHSCOPEID
429 if (((struct sockaddr *)&remote_ip)->sa_family == AF_INET6)
430 niflags |= NI_WITHSCOPEID;
432 error = getnameinfo((struct sockaddr *)&remote_ip, salen, hbuf,
433 sizeof(hbuf), pbuf, sizeof(pbuf), niflags);
435 fprintf(stderr, "getnameinfo: %s\n", gai_strerror(error));
436 strcpy(hbuf, "unknown");
437 strcpy(pbuf, "unknown");
439 snprintf(remoteaddr, sizeof(remoteaddr), "%s;%s", hbuf, pbuf);
441 r = gethostname(myhostname, sizeof(myhostname)-1);
442 if(r == -1) saslfail(r, "getting hostname");
444 r = sasl_server_new(service, myhostname, NULL, localaddr, remoteaddr,
446 if (r != SASL_OK) saslfail(r, "allocating connection state");
448 cb.type = "sasl-sample";
449 cb.critical = cb_flag;
450 cb.data = "this is a test of channel binding";
451 cb.len = strlen(cb.data);
453 sasl_setprop(conn, SASL_CHANNEL_BINDING, &cb);
455 /* set external properties here
456 sasl_setprop(conn, SASL_SSF_EXTERNAL, &extprops); */
458 /* set required security properties here
459 sasl_setprop(conn, SASL_SEC_PROPS, &secprops); */
461 in = fdopen(fd, "r");
462 out = fdopen(fd, "w");
464 r = mysasl_negotiate(in, out, conn);
466 /* send/receive data */
471 printf("closing connection\n");
481 static void displayStatus_1(m, code, type)
486 OM_uint32 maj_stat, min_stat;
492 maj_stat = gss_display_status(&min_stat, code,
493 type, GSS_C_NULL_OID,
495 fprintf(stderr, "%s: %s\n", m, (char *)msg.value);
496 (void) gss_release_buffer(&min_stat, &msg);
503 static void displayStatus(msg, maj_stat, min_stat)
508 displayStatus_1(msg, maj_stat, GSS_C_GSS_CODE);
509 displayStatus_1(msg, min_stat, GSS_C_MECH_CODE);
513 dumpAttribute(OM_uint32 *minor,
515 gss_buffer_t attribute,
518 OM_uint32 major, tmp;
519 gss_buffer_desc value;
520 gss_buffer_desc display_value;
521 int authenticated = 0;
528 display_value.value = NULL;
530 major = gss_get_name_attribute(minor,
538 if (GSS_ERROR(major)) {
539 displayStatus("gss_get_name_attribute", major, *minor);
543 printf("Attribute %.*s %s %s\n\n%.*s\n",
544 (int)attribute->length, (char *)attribute->value,
545 authenticated ? "Authenticated" : "",
546 complete ? "Complete" : "",
547 (int)display_value.length, (char *)display_value.value);
550 for (i = 0; i < value.length; i++) {
553 printf("%02x", ((char *)value.value)[i] & 0xFF);
558 gss_release_buffer(&tmp, &value);
559 gss_release_buffer(&tmp, &display_value);
564 enumerateAttributes(OM_uint32 *minor,
568 OM_uint32 major, tmp;
570 gss_OID mech = GSS_C_NO_OID;
571 gss_buffer_set_t attrs = GSS_C_NO_BUFFER_SET;
574 major = gss_inquire_name(minor,
579 if (GSS_ERROR(major)) {
580 displayStatus("gss_inquire_name", major, *minor);
584 if (attrs != GSS_C_NO_BUFFER_SET) {
585 for (i = 0; i < attrs->count; i++)
586 dumpAttribute(minor, name, &attrs->elements[i], noisy);
589 gss_release_oid(&tmp, &mech);
590 gss_release_buffer_set(&tmp, &attrs);