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>
87 #include <gssapi/gssapi_ext.h>
92 #if !defined(IPV6_BINDV6ONLY) && defined(IN6P_IPV6_V6ONLY)
93 #define IPV6_BINDV6ONLY IN6P_BINDV6ONLY
95 #if !defined(IPV6_V6ONLY) && defined(IPV6_BINDV6ONLY)
96 #define IPV6_V6ONLY IPV6_BINDV6ONLY
98 #ifndef IPV6_BINDV6ONLY
103 enumerateAttributes(OM_uint32 *minor,
107 /* create a socket listening on port 'port' */
108 /* if af is PF_UNSPEC more than one socket may be returned */
109 /* the returned list is dynamically allocated, so caller needs to free it */
110 int *listensock(const char *port, const int af)
112 struct addrinfo hints, *ai, *r;
113 int err, maxs, *sock, *socks;
116 memset(&hints, 0, sizeof(hints));
117 hints.ai_flags = AI_PASSIVE;
118 hints.ai_family = af;
119 hints.ai_socktype = SOCK_STREAM;
120 err = getaddrinfo(NULL, port, &hints, &ai);
122 fprintf(stderr, "%s\n", gai_strerror(err));
126 /* Count max number of sockets we may open */
127 for (maxs = 0, r = ai; r; r = r->ai_next, maxs++)
129 socks = malloc((maxs + 1) * sizeof(int));
131 fprintf(stderr, "couldn't allocate memory for sockets\n");
136 socks[0] = 0; /* num of sockets counter at start of array */
138 for (r = ai; r; r = r->ai_next) {
139 fprintf(stderr, "trying %d, %d, %d\n",r->ai_family, r->ai_socktype, r->ai_protocol);
140 *sock = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
145 if (setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR,
146 (void *) &on, sizeof(on)) < 0) {
147 perror("setsockopt(SO_REUSEADDR)");
151 #if defined(IPV6_V6ONLY) && !(defined(__FreeBSD__) && __FreeBSD__ < 3)
152 if (r->ai_family == AF_INET6) {
153 if (setsockopt(*sock, IPPROTO_IPV6, IPV6_BINDV6ONLY,
154 (void *) &on, sizeof(on)) < 0) {
155 perror("setsockopt (IPV6_BINDV6ONLY)");
161 if (bind(*sock, r->ai_addr, r->ai_addrlen) < 0) {
167 if (listen(*sock, 5) < 0) {
180 fprintf(stderr, "Couldn't bind to any socket\n");
190 fprintf(stderr, "usage: server [-C] [-h hostname] [-p port] [-s service] [-m mech]\n");
194 /* globals because i'm lazy */
197 /* do the sasl negotiation; return -1 if it fails */
198 int mysasl_negotiate(FILE *in, FILE *out, sasl_conn_t *conn)
201 char chosenmech[128];
206 gss_name_t peer = GSS_C_NO_NAME;
208 /* generate the capability list */
210 dprintf(2, "forcing use of mechanism %s\n", mech);
216 dprintf(1, "generating client mechanism list... ");
217 r = sasl_listmech(conn, NULL, NULL, " ", NULL,
218 &data, &len, &count);
219 if (r != SASL_OK) saslfail(r, "generating mechanism list");
220 dprintf(1, "%d mechanisms\n", count);
223 /* send capability list to client */
224 send_string(out, data, len);
226 dprintf(1, "waiting for client mechanism...\n");
227 len = recv_string(in, chosenmech, sizeof chosenmech);
229 printf("client didn't choose mechanism\n");
230 fputc('N', out); /* send NO to client */
235 if (mech && strcasecmp(mech, chosenmech)) {
236 printf("client didn't choose mandatory mechanism\n");
237 fputc('N', out); /* send NO to client */
242 len = recv_string(in, buf, sizeof(buf));
244 saslerr(r, "didn't receive first-send parameter correctly");
251 /* receive initial response (if any) */
252 len = recv_string(in, buf, sizeof(buf));
254 /* start libsasl negotiation */
255 r = sasl_server_start(conn, chosenmech, buf, len,
258 r = sasl_server_start(conn, chosenmech, NULL, 0,
262 if (r != SASL_OK && r != SASL_CONTINUE) {
263 saslerr(r, "starting SASL negotiation");
264 fputc('N', out); /* send NO to client */
269 while (r == SASL_CONTINUE) {
271 dprintf(2, "sending response length %d...\n", len);
272 fputc('C', out); /* send CONTINUE to client */
273 send_string(out, data, len);
275 dprintf(2, "sending null response...\n");
276 fputc('C', out); /* send CONTINUE to client */
277 send_string(out, "", 0);
280 dprintf(1, "waiting for client reply...\n");
281 len = recv_string(in, buf, sizeof buf);
283 printf("client disconnected\n");
287 r = sasl_server_step(conn, buf, len, &data, &len);
288 if (r != SASL_OK && r != SASL_CONTINUE) {
289 saslerr(r, "performing SASL negotiation");
290 fputc('N', out); /* send NO to client */
297 saslerr(r, "incorrect authentication");
298 fputc('N', out); /* send NO to client */
303 fputc('O', out); /* send OK to client */
305 dprintf(1, "negotiation complete\n");
307 r = sasl_getprop(conn, SASL_USERNAME, (const void **) &userid);
308 printf("successful authentication '%s'\n", userid);
310 r = sasl_getprop(conn, SASL_GSS_PEER_NAME, (const void **) &peer);
311 if (peer != GSS_C_NO_NAME) {
313 enumerateAttributes(&minor, peer, 1);
319 int main(int argc, char *argv[])
322 char *port = "12345";
323 char *service = "rcmd";
324 char *hostname = NULL;
330 while ((c = getopt(argc, argv, "Cch:p:s:m:")) != EOF) {
333 cb_flag = 2; /* channel bindings are critical */
337 cb_flag = 1; /* channel bindings are present */
362 /* initialize the sasl library */
363 r = sasl_server_init(NULL, "sample");
364 if (r != SASL_OK) saslfail(r, "initializing libsasl");
366 /* get a listening socket */
367 if ((l = listensock(port, PF_UNSPEC)) == NULL) {
368 saslfail(SASL_FAIL, "allocating listensock");
371 for (i = 1; i <= l[0]; i++) {
377 char localaddr[NI_MAXHOST | NI_MAXSERV],
378 remoteaddr[NI_MAXHOST | NI_MAXSERV];
379 char myhostname[1024+1];
380 char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
381 struct sockaddr_storage local_ip, remote_ip;
387 sasl_channel_binding_t cb;
390 for (i = 1; i <= l[0]; i++)
391 FD_SET(l[i], &readfds);
393 nfds = select(maxfd + 1, &readfds, 0, 0, 0);
395 if (nfds < 0 && errno != EINTR)
400 for (i = 1; i <= l[0]; i++)
401 if (FD_ISSET(l[i], &readfds)) {
402 fd = accept(l[i], NULL, NULL);
412 printf("accepted new connection\n");
414 /* set ip addresses */
415 salen = sizeof(local_ip);
416 if (getsockname(fd, (struct sockaddr *)&local_ip, &salen) < 0) {
417 perror("getsockname");
419 niflags = (NI_NUMERICHOST | NI_NUMERICSERV);
420 #ifdef NI_WITHSCOPEID
421 if (((struct sockaddr *)&local_ip)->sa_family == AF_INET6)
422 niflags |= NI_WITHSCOPEID;
424 error = getnameinfo((struct sockaddr *)&local_ip, salen, hbuf,
425 sizeof(hbuf), pbuf, sizeof(pbuf), niflags);
427 fprintf(stderr, "getnameinfo: %s\n", gai_strerror(error));
428 strcpy(hbuf, "unknown");
429 strcpy(pbuf, "unknown");
431 snprintf(localaddr, sizeof(localaddr), "%s;%s", hbuf, pbuf);
433 salen = sizeof(remote_ip);
434 if (getpeername(fd, (struct sockaddr *)&remote_ip, &salen) < 0) {
435 perror("getpeername");
438 niflags = (NI_NUMERICHOST | NI_NUMERICSERV);
439 #ifdef NI_WITHSCOPEID
440 if (((struct sockaddr *)&remote_ip)->sa_family == AF_INET6)
441 niflags |= NI_WITHSCOPEID;
443 error = getnameinfo((struct sockaddr *)&remote_ip, salen, hbuf,
444 sizeof(hbuf), pbuf, sizeof(pbuf), niflags);
446 fprintf(stderr, "getnameinfo: %s\n", gai_strerror(error));
447 strcpy(hbuf, "unknown");
448 strcpy(pbuf, "unknown");
450 snprintf(remoteaddr, sizeof(remoteaddr), "%s;%s", hbuf, pbuf);
452 if (hostname == NULL) {
453 r = gethostname(myhostname, sizeof(myhostname)-1);
454 if(r == -1) saslfail(r, "getting hostname");
455 hostname = myhostname;
458 r = sasl_server_new(service, hostname, NULL, localaddr, remoteaddr,
460 if (r != SASL_OK) saslfail(r, "allocating connection state");
462 cb.name = "sasl-sample";
463 cb.critical = cb_flag > 1;
464 cb.data = "this is a test of channel binding";
465 cb.len = strlen(cb.data);
468 sasl_setprop(conn, SASL_CHANNEL_BINDING, &cb);
470 /* set external properties here
471 sasl_setprop(conn, SASL_SSF_EXTERNAL, &extprops); */
473 /* set required security properties here
474 sasl_setprop(conn, SASL_SEC_PROPS, &secprops); */
476 in = fdopen(fd, "r");
477 out = fdopen(fd, "w");
479 r = mysasl_negotiate(in, out, conn);
481 /* send/receive data */
486 printf("closing connection\n");
496 static void displayStatus_1(m, code, type)
501 OM_uint32 maj_stat, min_stat;
507 maj_stat = gss_display_status(&min_stat, code,
508 type, GSS_C_NULL_OID,
510 fprintf(stderr, "%s: %s\n", m, (char *)msg.value);
511 (void) gss_release_buffer(&min_stat, &msg);
518 static void displayStatus(msg, maj_stat, min_stat)
523 displayStatus_1(msg, maj_stat, GSS_C_GSS_CODE);
524 displayStatus_1(msg, min_stat, GSS_C_MECH_CODE);
528 dumpAttribute(OM_uint32 *minor,
530 gss_buffer_t attribute,
533 OM_uint32 major, tmp;
534 gss_buffer_desc value;
535 gss_buffer_desc display_value;
536 int authenticated = 0;
543 display_value.value = NULL;
545 major = gss_get_name_attribute(minor,
553 if (GSS_ERROR(major)) {
554 displayStatus("gss_get_name_attribute", major, *minor);
558 printf("Attribute %.*s %s %s\n\n%.*s\n",
559 (int)attribute->length, (char *)attribute->value,
560 authenticated ? "Authenticated" : "",
561 complete ? "Complete" : "",
562 (int)display_value.length, (char *)display_value.value);
565 for (i = 0; i < value.length; i++) {
568 printf("%02x", ((char *)value.value)[i] & 0xFF);
573 gss_release_buffer(&tmp, &value);
574 gss_release_buffer(&tmp, &display_value);
579 enumerateAttributes(OM_uint32 *minor,
583 OM_uint32 major, tmp;
585 gss_OID mech = GSS_C_NO_OID;
586 gss_buffer_set_t attrs = GSS_C_NO_BUFFER_SET;
589 major = gss_inquire_name(minor,
594 if (GSS_ERROR(major)) {
595 displayStatus("gss_inquire_name", major, *minor);
599 if (attrs != GSS_C_NO_BUFFER_SET) {
600 for (i = 0; i < attrs->count; i++)
601 dumpAttribute(minor, name, &attrs->elements[i], noisy);
605 gss_release_oid(&tmp, &mech);
607 gss_release_buffer_set(&tmp, &attrs);