1 /* $Header: /var/cvs/mbdyn/mbdyn/mbdyn-1.0/libraries/libmbutil/mbsasl.c,v 1.20 2017/01/12 14:44:05 masarati Exp $ */
2 /*
3 * MBDyn (C) is a multibody analysis code.
4 * http://www.mbdyn.org
5 *
6 * Copyright (C) 1996-2017
7 *
8 * Pierangelo Masarati <masarati@aero.polimi.it>
9 * Paolo Mantegazza <mantegazza@aero.polimi.it>
10 *
11 * Dipartimento di Ingegneria Aerospaziale - Politecnico di Milano
12 * via La Masa, 34 - 20156 Milano, Italy
13 * http://www.aero.polimi.it
14 *
15 * Changing this copyright notice is forbidden.
16 *
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation (version 2 of the License).
20 *
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 */
31
32 /*
33 * The protocol is very simple. It is client-initiated (of course),
34 * by sending
35 *
36 * C: M
37 * S: M<length><mechanism list>
38 * C: S<length><mechanism chosen><length><additional data>
39 *
40 * S: C<length><additional data>
41 * C: C<length><additional data>
42 *
43 * S: O | F
44 *
45 * where M means "Methods", C means "Continuation" (with data),
46 * O means "OK" and F means "Fail"
47 */
48
49 #include "mbconfig.h" /* This goes first in every *.c,*.cc file */
50
51 #ifdef HAVE_SASL2
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <unistd.h>
56 #include <errno.h>
57 #include <sys/mman.h>
58 #include <fcntl.h>
59 #include <signal.h>
60 #include <netdb.h>
61 #include <netinet/in.h>
62 #include <sys/types.h>
63 #include <sys/poll.h>
64 #include <sys/socket.h>
65
66 #include <sasl/sasl.h>
67 #include "mbsasl.h"
68
69 /* global vars that contain the auth data */
70 static struct mbdyn_sasl_t global_mbdyn_sasl = MBDYN_SASL_INIT;
71
72 static int
get_secret_default_f(sasl_conn_t * conn,void * context,int id,sasl_secret_t ** psecret)73 get_secret_default_f(sasl_conn_t *conn,
74 void *context,
75 int id,
76 sasl_secret_t **psecret)
77 {
78 size_t credlen;
79 const char *cred = global_mbdyn_sasl.sasl_cred;
80
81 if (id != SASL_CB_PASS) return SASL_FAIL;
82
83 if (cred == NULL) {
84 cred = getpass("password: ");
85 }
86
87 credlen = strlen(cred);
88 *psecret = malloc(sizeof(sasl_secret_t) + credlen);
89 (*psecret)->len = credlen;
90 memcpy(&(*psecret)->data[0], cred, credlen);
91
92 return SASL_OK;
93 }
94
95 static int
get_authname_default_f(void * context,int id,const char ** result,unsigned * len)96 get_authname_default_f(void *context,
97 int id,
98 const char **result,
99 unsigned *len)
100 {
101 const char *authz = global_mbdyn_sasl.sasl_authz;
102 char buf[MBDYN_SASL_BUFSIZE];
103
104 if (id != SASL_CB_AUTHNAME) return SASL_FAIL;
105
106 if (!authz && (global_mbdyn_sasl.sasl_flags & MBDYN_SASL_FLAG_USERAUTHZ)) {
107 authz = global_mbdyn_sasl.sasl_user;
108 }
109
110 if (!authz) {
111 size_t buflen;
112
113 printf("authzname: ");
114 if (fgets(buf, sizeof(buf), stdin) == NULL) {
115 return SASL_FAIL;
116 }
117
118 buflen = strlen(buf);
119 if (buf[buflen - 1] == '\n') {
120 --buflen;
121 buf[buflen] = '\0';
122 }
123
124 if (buflen > 0) {
125 authz = buf;
126 }
127 }
128
129 if (authz) {
130 *result = strdup(authz);
131 if (len) {
132 *len = strlen(*result);
133 }
134 } else {
135 *result = NULL;
136 if (len) {
137 *len = 0;
138 }
139 }
140
141 return SASL_OK;
142 }
143
144 static int
get_user_default_f(void * context,int id,const char ** result,unsigned * len)145 get_user_default_f(void *context,
146 int id,
147 const char **result,
148 unsigned *len)
149 {
150 const char *user = global_mbdyn_sasl.sasl_user;
151 char buf[MBDYN_SASL_BUFSIZE];
152
153 if (id != SASL_CB_USER) return SASL_FAIL;
154
155 if (!user) {
156 size_t buflen;
157
158 printf("username: ");
159 if (fgets(buf, sizeof(buf), stdin) == NULL) {
160 return SASL_FAIL;
161 }
162
163 buflen = strlen(buf);
164 if (buf[buflen - 1] == '\n') {
165 --buflen;
166 buf[buflen] = '\0';
167 }
168 user = buf;
169 }
170
171 *result = strdup(user);
172 if (len) {
173 *len = strlen(*result);
174 }
175
176 return SASL_OK;
177 }
178
179 static int
get_realm_default_f(void * context,int id,const char ** availrealms,const char ** result)180 get_realm_default_f(void *context,
181 int id,
182 const char **availrealms,
183 const char **result)
184 {
185 const char *realm = global_mbdyn_sasl.sasl_realm;
186 char buf[MBDYN_SASL_BUFSIZE];
187
188 if (id != SASL_CB_GETREALM) return SASL_FAIL;
189
190 if (!realm) {
191 size_t buflen;
192
193 printf("realm: ");
194 if (fgets(buf, sizeof(buf), stdin) == NULL) {
195 return SASL_FAIL;
196 }
197
198 buflen = strlen(buf);
199 if (buf[buflen - 1] == '\n') {
200 --buflen;
201 buf[buflen] = '\0';
202 }
203
204 if (buflen > 0) {
205 realm = buf;
206 }
207 }
208
209 if (realm) {
210 *result = strdup(realm);
211 } else {
212 *result = NULL;
213 }
214
215 return SASL_OK;
216 }
217
218 static int
log_server_default_f(void * context,int level,const char * message)219 log_server_default_f(void *context,
220 int level,
221 const char *message)
222 {
223 fprintf(stderr, "[server %d] %s\n", level, message);
224 return 0;
225 }
226
227 static int
log_client_default_f(void * context,int level,const char * message)228 log_client_default_f(void *context,
229 int level,
230 const char *message)
231 {
232 fprintf(stderr, "[client %d] %s\n", level, message);
233 return 0;
234 }
235
236 sasl_log_t *log_server_f = &log_server_default_f;
237 sasl_log_t *log_client_f = &log_client_default_f;
238 sasl_getsimple_t *get_user_f = &get_user_default_f;
239 sasl_getsimple_t *get_authname_f = &get_authname_default_f;
240 sasl_getsecret_t *get_secret_f = &get_secret_default_f;
241 sasl_getrealm_t *get_realm_f = &get_realm_default_f;
242
243 static sasl_callback_t server_callbacks[] = {
244 { SASL_CB_LOG, NULL /* log_server_f */ , NULL },
245 { SASL_CB_LIST_END, NULL, NULL }
246 };
247
248 static sasl_callback_t client_callbacks[] = {
249 { SASL_CB_GETREALM, NULL /* get_realm_f */ , NULL },
250 { SASL_CB_USER, NULL /* get_user_f */ , NULL },
251 { SASL_CB_AUTHNAME, NULL /* get_authname_f */ , NULL },
252 { SASL_CB_PASS, NULL /* get_secret_f */ , NULL },
253 { SASL_CB_LOG, NULL /* log_client_f */ , NULL },
254 { SASL_CB_LIST_END, NULL, NULL }
255 };
256
257 int
mbdyn_sasl_client_init(struct mbdyn_sasl_t * mbdyn_sasl)258 mbdyn_sasl_client_init(struct mbdyn_sasl_t *mbdyn_sasl)
259 {
260 int rc;
261
262 client_callbacks[0].proc = get_realm_f;
263 client_callbacks[1].proc = get_user_f;
264 client_callbacks[2].proc = get_authname_f;
265 client_callbacks[3].proc = get_secret_f;
266 client_callbacks[4].proc = log_client_f;
267
268 if (mbdyn_sasl) {
269 global_mbdyn_sasl = *mbdyn_sasl;
270 }
271
272 rc = sasl_client_init(client_callbacks); /* Callbacks supported */
273 if (rc != SASL_OK) {
274 printf("[client] sasl_client_init() failed: %d (%s)\n",
275 rc, sasl_errstring(rc, NULL, NULL));
276 }
277
278 return rc;
279 }
280
281 int
mbdyn_sasl_server_init(struct mbdyn_sasl_t * mbdyn_sasl)282 mbdyn_sasl_server_init(struct mbdyn_sasl_t *mbdyn_sasl)
283 {
284 int rc;
285
286 server_callbacks[0].proc = log_server_f;
287
288 rc = sasl_server_init(server_callbacks, /* Callbacks supported */
289 MBDYN_SASL_CONFFILE); /* Name of the application,
290 * used to look for rtai.conf
291 * file in /usr/lib/sasl2/ */
292 if (rc != SASL_OK) {
293 printf("[server] sasl_server_init() failed: %d (%s)\n",
294 rc, sasl_errstring(rc, NULL, NULL));
295 }
296
297 return rc;
298 }
299
300 int
mbdyn_sasl_init(struct mbdyn_sasl_t * mbdyn_sasl)301 mbdyn_sasl_init(struct mbdyn_sasl_t *mbdyn_sasl)
302 {
303 switch (mbdyn_sasl->use_sasl) {
304 case MBDYN_SASL_SERVER:
305 return mbdyn_sasl_server_init(mbdyn_sasl);
306 break;
307
308 case MBDYN_SASL_CLIENT:
309 return mbdyn_sasl_client_init(mbdyn_sasl);
310 break;
311
312 default:
313 /* if SASL is critical, return SASL_FAIL */
314 if (mbdyn_sasl->sasl_flags & MBDYN_SASL_FLAG_CRITICAL) {
315 return SASL_FAIL;
316 }
317 return SASL_OK;
318 }
319 }
320
321 int
mbdyn_sasl_fini(void)322 mbdyn_sasl_fini(void)
323 {
324 sasl_done();
325
326 return SASL_OK;
327 }
328
329 int
mbdyn_sasl_client_auth(int sock,struct sockaddr * bindaddr,struct mbdyn_sasl_t * mbdyn_sasl)330 mbdyn_sasl_client_auth(int sock, struct sockaddr *bindaddr,
331 struct mbdyn_sasl_t *mbdyn_sasl)
332 {
333 int rc = 0;
334 sasl_conn_t *conn = NULL;
335 sasl_interact_t *client_interact = NULL;
336 const char *out = NULL, *mechusing = NULL;
337 unsigned outlen = 0;
338 #if 0 /* will be used later */
339 sasl_security_properties_t secprops;
340 #endif
341
342 int count = 0;
343 char op;
344 char serverin[MBDYN_SASL_BUFSIZE] = { '\0' };
345 const char *mech = NULL;
346 unsigned serverinlen = 0;
347
348 int oldflags, currflags;
349
350 oldflags = fcntl (sock, F_GETFL, 0);
351 if (oldflags == -1) {
352 return SASL_FAIL;
353 }
354 currflags = oldflags & ~O_NONBLOCK;
355 if (fcntl(sock, F_SETFL, currflags) == -1) {
356 return SASL_FAIL;
357 }
358
359 rc = sasl_client_new(MBDYN_SASL_SERVICE, /* name of service */
360 mbdyn_sasl->sasl_hostname,
361 /* The fully qualified domain name
362 * of the server we're connecting to */
363 mbdyn_sasl->sasl_local_ip,
364 mbdyn_sasl->sasl_remote_ip,
365 /* Local and remote IP address strings
366 * (NULL disables mechanisms which
367 * require this info)*/
368 NULL, /* connection-specific callbacks */
369 0, /* security flags */
370 &conn); /* allocated on success */
371 if (rc != SASL_OK) {
372 printf("[client] sasl_client_new() failed: %d (%s)\n",
373 rc, sasl_errstring(rc, NULL, NULL));
374 goto cleanup;
375 }
376
377 retry:;
378 count = write(sock, "M", 1);
379 if (count != 1) {
380 if (count == -1) {
381 if (errno == EINVAL && mbdyn_sasl->sasl_usleep) {
382 usleep(mbdyn_sasl->sasl_usleep);
383 goto retry;
384 }
385 printf("[client] write() failed errno=%d\n", errno);
386 } else {
387 printf("[client] write() failed (%d instead of %d)\n", count , 1);
388 }
389 rc = SASL_FAIL;
390 goto cleanup;
391 }
392
393 count = read(sock, &op, 1);
394 if (count != 1) {
395 if (count == -1) {
396 printf("[client] read(M) failed errno=%d\n", errno);
397 } else {
398 printf("[client] read(M) failed (%d instead of %d)\n", count, 1);
399 }
400 rc = SASL_FAIL;
401 goto cleanup;
402 }
403 if (op != 'M') {
404 if (op != 'A') { /* 'A' means abort */
405 printf("[client] expecting \"M\" with methods\n");
406 }
407 rc = SASL_FAIL;
408 goto cleanup;
409 }
410
411 count = read(sock, &serverinlen, sizeof(unsigned));
412 if (count != sizeof(unsigned)) {
413 if (count == -1) {
414 printf("[client] read(Ml) failed errno=%d\n", errno);
415 } else {
416 printf("[client] read(Ml) failed (%d instead of %u)\n",
417 count, (unsigned)sizeof(unsigned));
418 }
419 rc = SASL_FAIL;
420 goto cleanup;
421 }
422 if (serverinlen >= sizeof(serverin)) {
423 printf("[client] buffer for mechanism list is too small\n");
424 rc = SASL_FAIL;
425 goto cleanup;
426 }
427 count = read(sock, serverin, serverinlen);
428 if (count < 0 || (unsigned)count != serverinlen) {
429 if (count < 0) {
430 printf("[client] read(Md) failed errno=%d\n", errno);
431 } else {
432 printf("[client] read(Md) failed (%d instead of %d)\n",
433 count, serverinlen);
434 }
435 rc = SASL_FAIL;
436 goto cleanup;
437 }
438 serverin[count] = '\0';
439
440 mech = mbdyn_sasl->sasl_mech;
441 if (!mech) {
442 mech = serverin;
443 }
444
445 #if 0 /* will be used later */
446 memset(&secprops, 0, sizeof(secprops));
447 secprops.min_ssf = 1;
448 secprops.max_ssf = 256;
449 secprops.maxbufsize = MBDYN_SASL_BUFSIZE;
450
451 secprops.property_names = NULL;
452 secprops.property_values = NULL;
453 secprops.security_flags = SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT | SASL_SEC_MUTUAL_AUTH; /* as appropriate */
454
455 sasl_setprop(conn, SASL_SEC_PROPS, &secprops);
456 #endif
457
458 do {
459 char buf[MBDYN_SASL_BUFSIZE];
460
461 rc = sasl_client_start(conn, /* same context from above */
462 mech, /* the list of mechanisms
463 * from the server */
464 &client_interact, /* filled in if an
465 * interaction
466 * is needed */
467 &out, /* filled in on success */
468 &outlen, /* filled in on success */
469 &mechusing); /* selected mech */
470
471 if (rc == SASL_INTERACT) {
472 if (!(mbdyn_sasl->sasl_flags & MBDYN_SASL_FLAG_INTERACT)) {
473 printf("[client] interaction disabled\n");
474 rc = SASL_FAIL;
475 goto cleanup;
476 }
477
478 /* FIXME: handle interaction ... */
479 printf("[client] sasl_client_start() requested "
480 "interaction \"%s\"; mech=%s\n",
481 client_interact->prompt, mechusing);
482 }
483
484 if (outlen >= sizeof(buf)) {
485 printf("[client] buf is too small\n");
486 rc = SASL_FAIL;
487 goto cleanup;
488 }
489 memcpy(buf, out, outlen);
490 buf[outlen] = '\0';
491 } while (rc == SASL_INTERACT);
492
493 switch (rc) {
494 case SASL_FAIL:
495 goto cleanup;
496
497 case SASL_OK:
498 case SASL_CONTINUE:
499 break;
500
501 default:
502 printf("[client] sasl start failure\n");
503 rc = SASL_FAIL;
504 goto cleanup;
505 }
506
507 count = write(sock, "S", 1);
508 if (count != 1) {
509 if (count == -1) {
510 printf("[client] write() failed errno=%d\n", errno);
511 } else {
512 printf("[client] write() failed (%d instead of %d)\n", count, 1);
513 }
514 rc = SASL_FAIL;
515 goto cleanup;
516 }
517 serverinlen = strlen(mechusing);
518 count = write(sock, &serverinlen, sizeof(unsigned));
519 if (count != sizeof(unsigned)) {
520 if (count == -1) {
521 printf("[client] write() failed errno=%d\n", errno);
522 } else {
523 printf("[client] write() failed (%d instead of %u)\n",
524 count, (unsigned)sizeof(unsigned));
525 }
526 rc = SASL_FAIL;
527 goto cleanup;
528 }
529 count = write(sock, mechusing, serverinlen);
530 if (count < 0 || (unsigned)count != serverinlen) {
531 if (count == -1) {
532 printf("[client] mech=\"%s\" write failed errno=%d\n",
533 mechusing, errno);
534 } else {
535 printf("[client] mech=\"%s\" write failed "
536 "(%d instead of %d)\n",
537 mechusing, count, serverinlen);
538 }
539 rc = SASL_FAIL;
540 goto cleanup;
541 }
542
543 count = write(sock, &outlen, sizeof(unsigned));
544 if (count < 0 || (unsigned)count != sizeof(unsigned)) {
545 if (count == -1) {
546 printf("[client] write() failed errno=%d\n", errno);
547 } else {
548 printf("[client] write() failed (%d instead of %u)\n",
549 count, (unsigned)sizeof(unsigned));
550 }
551 rc = SASL_FAIL;
552 goto cleanup;
553 }
554 count = write(sock, out ? out : "", outlen);
555 if (count < 0 || (unsigned)count != outlen) {
556 if (count == -1) {
557 printf("[client] mech=\"%s\" write failed errno=%d\n",
558 mechusing, errno);
559 } else {
560 printf("[client] mech=\"%s\" write failed "
561 "(%d instead of %d)\n",
562 mechusing, count, outlen);
563 }
564 rc = SASL_FAIL;
565 goto cleanup;
566 }
567
568 do {
569 serverin[0] = '\0';
570 serverinlen = 0;
571
572 count = read(sock, &op, 1);
573 if (count != 1) {
574 if (count == -1) {
575 printf("[client] read(c) failed errno=%d\n", errno);
576 } else {
577 printf("[client] read(c) failed (%d instead of %d)\n", count, 1);
578 }
579 rc = SASL_FAIL;
580 goto cleanup;
581 }
582
583 switch (op) {
584 case 'O': /* ok; but continue, to check the library's response ... */
585 if (rc == SASL_OK) {
586 goto cleanup;
587 }
588 break;
589
590 case 'F': /* fail */
591 case 'A': /* abort */
592 rc = SASL_FAIL;
593 goto cleanup;
594
595 case 'C': /* continue ... */
596 count = read(sock, serverin, sizeof(unsigned));
597 if (count != sizeof(unsigned)) {
598 if (count == -1) {
599 printf("[client] read(Cd) failed errno=%d\n", errno);
600 } else {
601 printf("[client] read(Cd) failed "
602 "(%d instead of %u)\n",
603 count, (unsigned)sizeof(unsigned));
604 }
605 rc = SASL_FAIL;
606 goto cleanup;
607 }
608 serverinlen = ((unsigned *)(serverin))[0];
609 if (serverinlen >= sizeof(serverin)) {
610 printf("[client] buffer for "
611 "sasl_client_step() "
612 "continuation data "
613 "is too small\n");
614 rc = SASL_FAIL;
615 goto cleanup;
616 }
617 count = read(sock, serverin, serverinlen);
618 if (count < 0 || (unsigned)count != serverinlen) {
619 if (count == -1) {
620 printf("[client] read() failed errno=%d\n", errno);
621 } else {
622 printf("[client] read() failed (%d instead of %d)\n",
623 count, serverinlen);
624 }
625 rc = SASL_FAIL;
626 goto cleanup;
627 }
628 serverin[serverinlen] = '\0';
629 break;
630
631 default:
632 break;
633 }
634
635 rc = sasl_client_step(conn, /* our context */
636 serverin, /* the data from the server */
637 serverinlen, /* its length */
638 &client_interact, /* this should be
639 * unallocated
640 * and NULL */
641 &out, /* filled in on success */
642 &outlen); /* filled in on success */
643
644 count = write(sock, "C", 1);
645 if (count != 1) {
646 if (count == -1) {
647 printf("[client] write failed errno=%d\n", errno);
648 } else {
649 printf("[client] write failed (%d instead of %d)\n", count, 1);
650 }
651 rc = SASL_FAIL;
652 goto cleanup;
653 }
654
655 count = write(sock, &outlen, sizeof(unsigned));
656 if (count != sizeof(unsigned)) {
657 if (count == -1) {
658 printf("[client] write failed errno=%d\n", errno);
659 } else {
660 printf("[client] write failed "
661 "(%d instead of %u)\n",
662 count, (unsigned)sizeof(unsigned));
663 }
664 rc = SASL_FAIL;
665 goto cleanup;
666 }
667 count = write(sock, out ? out : "", outlen);
668 if (count < 0 || (unsigned)count != outlen) {
669 if (count == -1) {
670 printf("[client] write failed errno=%d\n", errno);
671 } else {
672 printf("[client] write failed (%d instead of %d)\n", count, outlen);
673 }
674 rc = SASL_FAIL;
675 goto cleanup;
676 }
677
678 switch (rc) {
679 case SASL_INTERACT:
680 /* FIXME: interaction */
681 case SASL_CONTINUE:
682 break;
683
684 case SASL_OK:
685 break;
686
687 case SASL_FAIL:
688 goto cleanup;
689
690 default:
691 break;
692 }
693 } while (rc == SASL_INTERACT || rc == SASL_CONTINUE || rc == SASL_OK);
694
695 if (rc != SASL_OK) {
696 printf("[client] sasl step failure\n");
697 goto cleanup;
698 }
699
700 cleanup:;
701
702 #if 0 /* will use later */
703 if (rc == SASL_OK) {
704 int i;
705 char buf[MBDYN_SASL_BUFSIZE];
706 int ssf = 0, outbufsize = MBDYN_SASL_BUFSIZE;
707 const int *ssfp = &ssf, *outbufsizep = &outbufsize;
708
709 rc = sasl_getprop(conn, SASL_SSF, (const void **)&ssfp);
710 if (rc != SASL_OK) {
711 fprintf(stderr, "[client] unable to retrieve ssf\n");
712 exit(EXIT_FAILURE);
713 }
714 if (*ssfp > 0) {
715 ssf = *ssfp;
716 rc = sasl_getprop(conn, SASL_MAXOUTBUF, (const void **)&outbufsizep);
717 if (rc != SASL_OK) {
718 fprintf(stderr, "[client] unable to retrieve out buf size\n");
719 exit(EXIT_FAILURE);
720 }
721 outbufsize = *outbufsizep;
722 }
723
724 fprintf(stderr, "[client] SASL_OK (ssf=%d, outbufsize=%d)\n", ssf, outbufsize);
725 }
726 #endif
727
728 /* FIXME: don't dispose if using encoding */
729 if (conn) {
730 sasl_dispose(&conn);
731 }
732
733 if (fcntl (sock, F_SETFL, oldflags) == -1) {
734 rc = SASL_FAIL;
735 }
736
737 return rc;
738 }
739
740 int
mbdyn_sasl_server_auth(int sock,struct sockaddr * bindaddr,struct mbdyn_sasl_t * mbdyn_sasl)741 mbdyn_sasl_server_auth(int sock, struct sockaddr *bindaddr,
742 struct mbdyn_sasl_t *mbdyn_sasl)
743 {
744 int rc = SASL_FAIL;
745 sasl_conn_t *conn = NULL;
746 const char *result_string = NULL;
747 unsigned string_length = 0;
748 int number_of_mechanisms = 0;
749 const char *out = NULL;
750 unsigned outlen = 0;
751 #if 0 /* will be used later */
752 sasl_security_properties_t secprops;
753 #endif
754
755 int count = 0;
756 char op = '\0';
757 char mechanism_client_chose[MBDYN_SASL_BUFSIZE] = { '\0' };
758 char clientin[MBDYN_SASL_BUFSIZE] = { '\0' };
759 unsigned clientinlen = 0;
760
761 int oldflags, currflags;
762
763 oldflags = fcntl (sock, F_GETFL, 0);
764 if (oldflags == -1) {
765 return SASL_FAIL;
766 }
767 currflags = oldflags & ~O_NONBLOCK;
768 if (fcntl(sock, F_SETFL, currflags) == -1) {
769 return SASL_FAIL;
770 }
771
772 rc = sasl_server_new(MBDYN_SASL_SERVICE, /* name of service */
773 NULL, /* my fully qualified domain name;
774 * NULL says use gethostname() */
775 mbdyn_sasl->sasl_realm,/* The user realm used for password
776 * lookups; NULL means default
777 * to serverFQDN. Note: This does
778 * not affect Kerberos */
779 mbdyn_sasl->sasl_local_ip,
780 mbdyn_sasl->sasl_remote_ip, /* IP Address information
781 * strings */
782 NULL, /* Callbacks supported only
783 * for this connection */
784 0, /* security flags (security layers
785 are enabled using security
786 properties, separately) */
787 &conn); /* allocated on success */
788 if (rc != SASL_OK) {
789 printf("[server] sasl_server_new() failed: %d (%s)\n",
790 rc, sasl_errstring(rc, NULL, NULL));
791 goto cleanup;
792 }
793
794 #if 0 /* will be used later */
795 memset(&secprops, 0, sizeof(secprops));
796 secprops.min_ssf = 1;
797 secprops.max_ssf = 256;
798 secprops.maxbufsize = MBDYN_SASL_BUFSIZE;
799
800 secprops.property_names = NULL;
801 secprops.property_values = NULL;
802 secprops.security_flags = SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT | SASL_SEC_MUTUAL_AUTH; /* as appropriate */
803
804 sasl_setprop(conn, SASL_SEC_PROPS, &secprops);
805 #endif
806
807 retry:;
808 count = read(sock, &op, 1);
809 if (count != 1) {
810 if (count == -1) {
811 if (errno == EINVAL && mbdyn_sasl->sasl_usleep) {
812 usleep(mbdyn_sasl->sasl_usleep);
813 goto retry;
814 }
815 printf("[server] read failed errno=%d\n", errno);
816 } else {
817 printf("[server] read failed (%d instead of %d)\n", count, 2);
818 }
819 rc = SASL_FAIL;
820 goto cleanup;
821 }
822
823 if (op != 'M') {
824 printf("[server] \"M\" expected\n");
825 rc = SASL_FAIL;
826 goto cleanup;
827 }
828
829 rc = sasl_listmech(conn, /* The context for this connection */
830 NULL, /* not supported */
831 "", /* What to prepend the string with */
832 " ", /* What to separate mechanisms with */
833 "", /* What to append to the string */
834 &result_string, /* The produced string. */
835 &string_length, /* length of the string */
836 &number_of_mechanisms); /* Number of mechanisms
837 * in the string */
838 if (rc != SASL_OK) {
839 printf("[server] sasl_listmech() failed: %s\n",
840 sasl_errdetail(conn));
841 rc = SASL_FAIL;
842 goto cleanup;
843 }
844
845 count = write(sock, "M", 1);
846 if (count != 1) {
847 if (count == -1) {
848 printf("[server] write() failed errno=%d\n", errno);
849 } else {
850 printf("[server] write() failed (%d instead of %d)\n", count, 1);
851 }
852 rc = SASL_FAIL;
853 goto cleanup;
854 }
855 count = write(sock, &string_length, sizeof(unsigned));
856 if (count != sizeof(unsigned)) {
857 if (count == -1) {
858 printf("[server] write() failed errno=%d\n", errno);
859 } else {
860 printf("[server] write() failed (%d instead of %u)\n",
861 count, (unsigned)sizeof(unsigned));
862 }
863 rc = SASL_FAIL;
864 goto cleanup;
865 }
866 count = write(sock, result_string, string_length);
867 if (count < 0 || (unsigned)count != string_length) {
868 if (count == -1) {
869 printf("[server] write() failed errno=%d\n", errno);
870 } else {
871 printf("[server] write() failed (%d instead of %d)\n",
872 count, string_length);
873 }
874 rc = SASL_FAIL;
875 goto cleanup;
876 }
877
878 /* read client's choice and more */
879 count = read(sock, &op, 1);
880 if (count != 1) {
881 if (count == -1) {
882 printf("[server] read() failed errno=%d\n", errno);
883 } else {
884 printf("[server] read() failed (%d instead of %d)\n",
885 count, 1);
886 }
887 rc = SASL_FAIL;
888 goto cleanup;
889 }
890 if (op != 'S') {
891 /* send abort? */
892 if (op != 'A') {
893 printf("[server] expecting \"S\" to start auth\n");
894 }
895 rc = SASL_FAIL;
896 goto cleanup;
897 }
898 count = read(sock, &clientinlen, sizeof(unsigned));
899 if (count != sizeof(unsigned)) {
900 if (count == -1) {
901 printf("[server] read() failed errno=%d\n", errno);
902 } else {
903 printf("[server] read() failed (%d instead of %u)\n",
904 count, (unsigned)sizeof(unsigned));
905 }
906 rc = SASL_FAIL;
907 goto cleanup;
908 }
909 if (clientinlen >= sizeof(mechanism_client_chose)) {
910 printf("[server] buffer for mechanism too small\n");
911 rc = SASL_FAIL;
912 goto cleanup;
913 }
914 count = read(sock, mechanism_client_chose, clientinlen);
915 if (count < 0 || (unsigned)count != clientinlen) {
916 if (count == -1) {
917 printf("[server] read() failed errno=%d\n", errno);
918 } else {
919 printf("[server] read() failed (%d instead of %u)\n",
920 count, clientinlen);
921 }
922 rc = SASL_FAIL;
923 goto cleanup;
924 }
925 mechanism_client_chose[clientinlen] = '\0';
926
927 /* read client's additional string ... */
928 count = read(sock, &clientinlen, sizeof(unsigned));
929 if (count != sizeof(unsigned)) {
930 if (count == -1) {
931 printf("[server] read() failed errno=%d\n", errno);
932 } else {
933 printf("[server] read() failed (%d instead of %u)\n",
934 count, (unsigned)sizeof(unsigned));
935 }
936 rc = SASL_FAIL;
937 goto cleanup;
938 }
939 if (clientinlen >= sizeof(clientin)) {
940 printf("[server] buffer for client optional string "
941 "is too small\n");
942 rc = SASL_FAIL;
943 goto cleanup;
944 }
945 count = read(sock, clientin, clientinlen);
946 if (count < 0 || (unsigned)count != clientinlen) {
947 if (count == -1) {
948 printf("[server] read() failed errno=%d\n", errno);
949 } else {
950 printf("[server] read() failed (%d instead of %u)\n",
951 count, clientinlen);
952 }
953 rc = SASL_FAIL;
954 goto cleanup;
955 }
956 clientin[clientinlen] = '\0';
957
958 rc = sasl_server_start(conn, /* context */
959 mechanism_client_chose, /* selected mechanism */
960 clientinlen ? clientin : NULL, /* the optional string
961 * the client gave us */
962 clientinlen, /* and its length */
963 &out, /* The output of the library.
964 * Might not be NULL terminated */
965 &outlen); /* its lenght */
966
967 do {
968 switch (rc) {
969 case SASL_OK:
970 count = write(sock, "O", 1);
971 if (count != 1) {
972 if (count == -1) {
973 printf("[server] write() failed errno=%d\n", errno);
974 } else {
975 printf("[server] write() failed (%d instead of %d)\n", count, 1);
976 }
977 rc = SASL_FAIL;
978 }
979 goto cleanup;
980
981 case SASL_CONTINUE: {
982 char buf[MBDYN_SASL_BUFSIZE];
983
984 if (1 + outlen + sizeof(unsigned) >= sizeof(buf)) {
985 printf("[server] buffer for "
986 "sasl_server_step() "
987 "continuation data "
988 "is too small\n");
989 rc = SASL_FAIL;
990 goto cleanup;
991 }
992
993 memcpy(buf, "C", 1);
994 memcpy(buf + 1, &outlen, sizeof(unsigned));
995 memcpy(buf + 1 + sizeof(unsigned), out, outlen);
996
997 count = write(sock, buf, 1 + outlen + sizeof(unsigned));
998 if (count < 0 || (unsigned)count != 1 + outlen + sizeof(unsigned)) {
999 if (count == -1) {
1000 printf("[server] write() failed errno=%d\n", count);
1001 } else {
1002 printf("[server] write() failed "
1003 "(%d instead of %u)\n",
1004 count,
1005 (unsigned)(1 + outlen + sizeof(unsigned)));
1006 }
1007 rc = SASL_FAIL;
1008 goto cleanup;
1009 }
1010 }
1011 break;
1012
1013 default:
1014 count = write(sock, "F", 1);
1015 if (count != 1) {
1016 if (count == -1) {
1017 printf("[server] write() failed errno=%d\n", errno);
1018 } else {
1019 printf("[server] write() failed (%d instead of %d)\n", count, 1);
1020 }
1021 rc = SASL_FAIL;
1022 }
1023 goto cleanup;
1024 }
1025
1026 count = read(sock, &op, 1);
1027 if (count != 1) {
1028 if (count == -1) {
1029 printf("[server] read() failed errno=%d\n", errno);
1030 } else {
1031 printf("[server] read() failed (%d instead of %d)\n", count, 1);
1032 }
1033 rc = SASL_FAIL;
1034 goto cleanup;
1035 }
1036 if (op != 'C') {
1037 if (op != 'A') {
1038 printf("[server] expecting \"C\" to continue\n");
1039 }
1040 rc = SASL_FAIL;
1041 goto cleanup;
1042 }
1043
1044 clientin[0] = '\0';
1045 clientinlen = 0;
1046
1047 count = read(sock, &clientinlen, sizeof(unsigned));
1048 if (count != sizeof(unsigned)) {
1049 if (count == -1) {
1050 printf("[server] read() failed errno=%d\n", errno);
1051 } else {
1052 printf("[server] read() failed "
1053 "(%d instead of %u)\n",
1054 count, (unsigned)sizeof(unsigned));
1055 }
1056 rc = SASL_FAIL;
1057 goto cleanup;
1058 }
1059 if (clientinlen >= sizeof(clientin)) {
1060 printf("[server] buffer for sasl_server_step() "
1061 "client data is too small\n");
1062 rc = SASL_FAIL;
1063 goto cleanup;
1064 }
1065 count = read(sock, clientin, clientinlen);
1066 if (count < 0 || (unsigned)count != clientinlen) {
1067 if (count == -1) {
1068 printf("[server] read() failed errno=%d\n", errno);
1069 } else {
1070 printf("[server] read() failed "
1071 "(%d instead of %u)\n",
1072 count, clientinlen);
1073 }
1074 rc = SASL_FAIL;
1075 goto cleanup;
1076 }
1077
1078 rc = sasl_server_step(conn, /* context */
1079 clientin, /* what the client gave */
1080 clientinlen, /* its length */
1081 &out, /* allocated by library
1082 * on success. Might not
1083 * be NULL terminated */
1084 &outlen); /* its length */
1085 } while (1);
1086
1087 cleanup:;
1088 /* FIXME: don't dispose if encoding connection */
1089 if (conn) {
1090 sasl_dispose(&conn);
1091 }
1092
1093 if (fcntl (sock, F_SETFL, oldflags) == -1) {
1094 rc = SASL_FAIL;
1095 }
1096
1097 return rc;
1098 }
1099
1100 int
mbdyn_sasl_auth(int sock,struct sockaddr * bindaddr,struct mbdyn_sasl_t * mbdyn_sasl)1101 mbdyn_sasl_auth(int sock, struct sockaddr *bindaddr,
1102 struct mbdyn_sasl_t *mbdyn_sasl)
1103 {
1104 switch (mbdyn_sasl->use_sasl) {
1105 case MBDYN_SASL_SERVER:
1106 return mbdyn_sasl_server_auth(sock, bindaddr, mbdyn_sasl);
1107 break;
1108
1109 case MBDYN_SASL_CLIENT:
1110 return mbdyn_sasl_client_auth(sock, bindaddr, mbdyn_sasl);
1111 break;
1112
1113 default:
1114 /* if SASL is critical, return SASL_FAIL */
1115 if (mbdyn_sasl->sasl_flags & MBDYN_SASL_FLAG_CRITICAL) {
1116 return SASL_FAIL;
1117 }
1118 return SASL_OK;
1119 }
1120 }
1121
1122 int
mbdyn_sasl_validate(struct mbdyn_sasl_t * mbdyn_sasl)1123 mbdyn_sasl_validate(struct mbdyn_sasl_t *mbdyn_sasl)
1124 {
1125 switch (mbdyn_sasl->use_sasl) {
1126 case MBDYN_SASL_NONE:
1127 return SASL_FAIL;
1128
1129 case MBDYN_SASL_SERVER:
1130 if (mbdyn_sasl->sasl_user != NULL) {
1131 return SASL_FAIL;
1132 }
1133
1134 if (mbdyn_sasl->sasl_cred != NULL) {
1135 return SASL_FAIL;
1136 }
1137
1138 if (mbdyn_sasl->sasl_authz != NULL) {
1139 return SASL_FAIL;
1140 }
1141
1142 return SASL_OK;
1143
1144 case MBDYN_SASL_CLIENT:
1145 if (mbdyn_sasl->sasl_hostname == NULL) {
1146 mbdyn_sasl->sasl_hostname = "localhost";
1147 }
1148
1149 return SASL_OK;
1150
1151 }
1152
1153 return SASL_FAIL;
1154 }
1155
1156 /*
1157 * a=<authz> client: authorization identity (optional)
1158 * f=<flag>[=<value>]
1159 * i=<remoteip> remote ip
1160 * l=<localip> local ip
1161 * m=<method> (list of) acceptable method(s)
1162 * r=<realm> client: user realm;
1163 * server: server realm
1164 * s={server|client} use SASL to negotiate auth
1165 * as server or client
1166 * u=<user> client: user identity
1167 * w=<cred> client: user credential
1168 */
1169 int
mbdyn_sasl_parse_args(int opt,const char * optarg,struct mbdyn_sasl_t * mbdyn_sasl)1170 mbdyn_sasl_parse_args(int opt, const char *optarg,
1171 struct mbdyn_sasl_t *mbdyn_sasl)
1172 {
1173 switch (opt) {
1174 case 'a':
1175 mbdyn_sasl->sasl_authz = optarg[0] ? optarg : NULL;
1176 break;
1177
1178 case 'f':
1179 if (strcasecmp(optarg, "userauthz") == 0) {
1180 mbdyn_sasl->sasl_flags |= MBDYN_SASL_FLAG_USERAUTHZ;
1181
1182 } else if (strcasecmp(optarg, "interact") == 0) {
1183 mbdyn_sasl->sasl_flags |= MBDYN_SASL_FLAG_INTERACT;
1184
1185 } else {
1186 printf("UNKNOWN FLAG '%s'\n", optarg);
1187 }
1188 break;
1189
1190 case 'h':
1191 mbdyn_sasl->sasl_hostname = optarg[0] ? optarg : NULL;
1192 break;
1193
1194 case 'i':
1195 mbdyn_sasl->sasl_remote_ip = optarg[0] ? optarg : NULL;
1196 break;
1197
1198 case 'l':
1199 mbdyn_sasl->sasl_local_ip = optarg[0] ? optarg : NULL;
1200 break;
1201
1202 case 'm':
1203 mbdyn_sasl->sasl_mech = optarg[0] ? optarg : NULL;
1204 break;
1205
1206 case 'r':
1207 mbdyn_sasl->sasl_realm = optarg[0] ? optarg : NULL;
1208 break;
1209
1210 case 's':
1211 if (strcasecmp(optarg, "server") == 0) {
1212 mbdyn_sasl->use_sasl = MBDYN_SASL_SERVER;
1213 } else if (strcasecmp(optarg, "client") == 0) {
1214 mbdyn_sasl->use_sasl = MBDYN_SASL_CLIENT;
1215 } else if (strcasecmp(optarg, "none") == 0) {
1216 mbdyn_sasl->use_sasl = MBDYN_SASL_NONE;
1217 } else {
1218 printf("UNKNOWN SASL MODE; SASL DISABLED\n");
1219 mbdyn_sasl->use_sasl = MBDYN_SASL_NONE;
1220 }
1221 break;
1222
1223 case 't': {
1224 char *next = NULL;
1225 unsigned long l;
1226
1227 errno = 0;
1228 l = strtoul(optarg, &next, 10);
1229 int save_errno = errno;
1230 if (next == NULL || next[0] != '\0') {
1231 printf("ILLEGAL SLEEP TIME '%s'\n", optarg);
1232
1233 } else if (save_errno == ERANGE) {
1234 printf("SLEEP TIME '%s' OVERFLOWS\n", optarg);
1235
1236 } else {
1237 mbdyn_sasl->sasl_usleep = l;
1238 }
1239 }
1240 break;
1241
1242 case 'u':
1243 mbdyn_sasl->sasl_user = optarg[0] ? optarg : NULL;
1244 break;
1245
1246 case 'w':
1247 mbdyn_sasl->sasl_cred = optarg[0] ? optarg : NULL;
1248 break;
1249
1250 default:
1251 return -1;
1252 }
1253
1254 return 0;
1255 }
1256
1257 #endif /* HAVE_SASL2 */
1258
1259