MBDyn-1.7.3
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups
mbsasl.c
Go to the documentation of this file.
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
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
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
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
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
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
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
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
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
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
322 mbdyn_sasl_fini(void)
323 {
324  sasl_done();
325 
326  return SASL_OK;
327 }
328 
329 int
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
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
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
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
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 
static int count
Definition: modules.cc:41
char * optarg
Definition: getopt.c:74
static doublereal buf[BUFSIZE]
Definition: discctrl.cc:333
static void * read(LoadableElem *pEl, DataManager *pDM, MBDynParser &HP)