00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "nufw_source.h"
00024 #include "libnuclient.h"
00025 #include "sending.h"
00026 #include "tcptable.h"
00027 #include <sasl/saslutil.h>
00028 #include <stdarg.h>
00029 #include <langinfo.h>
00030 #include <proto.h>
00031 #include "security.h"
00032 #include "internal.h"
00033 #include <sys/utsname.h>
00034
00035 #include <nussl.h>
00036 #include <nubase.h>
00037
00038 char* nu_locale_charset;
00039
00052 void do_panic(const char *filename, unsigned long line, const char *fmt,
00053 ...)
00054 {
00055 va_list args;
00056 va_start(args, fmt);
00057 printf("\n");
00058 if (filename != NULL && line != 0) {
00059 printf("%s:%lu:", filename, line);
00060 }
00061 printf("Fatal error: ");
00062 vprintf(fmt, args);
00063 printf("\n");
00064 fflush(stdout);
00065 exit(EXIT_FAILURE);
00066 va_end(args);
00067 }
00068
00069
00070 static int samp_send(nuauth_session_t* session, const char *buffer,
00071 unsigned length, nuclient_error_t * err)
00072 {
00073 char *buf;
00074 unsigned len, alloclen;
00075 int result;
00076
00077
00078 alloclen = 3 + ((length+2)/3)*4 + 1;
00079 buf = malloc(alloclen);
00080 if (buf == NULL) {
00081 SET_ERROR(err, INTERNAL_ERROR, MEMORY_ERR);
00082 return 0;
00083 }
00084
00085 result = sasl_encode64(buffer, length, buf + 3, alloclen, &len);
00086 if (result != SASL_OK) {
00087 SET_ERROR(err, SASL_ERROR, result);
00088 free(buf);
00089 return 0;
00090 }
00091
00092 memcpy(buf, "C: ", 3);
00093
00094 result = nussl_write(session->nussl, buf, len + 3);
00095 if (result < 0) {
00096 SET_ERROR(err, NUSSL_ERR, result);
00097 return 0;
00098 }
00099
00100 return 1;
00101 }
00102
00103
00104
00105 static unsigned samp_recv(nuauth_session_t* session, char *buf, int bufsize,
00106 nuclient_error_t * err)
00107 {
00108 unsigned len;
00109 int result;
00110 int tls_len;
00111
00112 tls_len = nussl_read(session->nussl, buf, bufsize);
00113 if (tls_len <= 0) {
00114 printf("ERROR nussl_read returned %d (requested %d bytes)\n", tls_len, bufsize);
00115 SET_ERROR(err, NUSSL_ERR, tls_len);
00116 return 0;
00117 }
00118
00119 result = sasl_decode64(buf + 3, (unsigned) strlen(buf + 3), buf,
00120 bufsize, &len);
00121 if (result != SASL_OK) {
00122 printf("ERROR sasl_decode64 returned %d\n", result);
00123 SET_ERROR(err, SASL_ERROR, result);
00124 return 0;
00125 }
00126 buf[len] = '\0';
00127 return len;
00128 }
00129
00130
00131
00132 int mysasl_negotiate(nuauth_session_t * session, sasl_conn_t * conn,
00133 nuclient_error_t * err)
00134 {
00135 char buf[8192];
00136 const char *data;
00137 const char *chosenmech;
00138 unsigned len;
00139 int result;
00140
00141
00142 memset(buf, 0, sizeof buf);
00143
00144 len = samp_recv(session, buf, 8192, err);
00145 if (len == 0) {
00146 return SASL_FAIL;
00147 }
00148
00149 result = sasl_client_start(conn,
00150 buf, NULL, &data, &len, &chosenmech);
00151
00152 if (session->verbose) {
00153 printf("Using mechanism %s\n", chosenmech);
00154 }
00155
00156 if (result != SASL_OK && result != SASL_CONTINUE) {
00157 if (session->verbose) {
00158 printf("Error starting SASL negotiation");
00159 printf("\n%s\n", sasl_errdetail(conn));
00160 }
00161 SET_ERROR(err, SASL_ERROR, result);
00162 return SASL_FAIL;
00163 }
00164
00165 strcpy(buf, chosenmech);
00166 if (data) {
00167 if (8192 - strlen(buf) - 1 < len) {
00168 return SASL_FAIL;
00169 }
00170 memcpy(buf + strlen(buf) + 1, data, len);
00171 len += (unsigned) strlen(buf) + 1;
00172 data = NULL;
00173 } else {
00174 len = (unsigned) strlen(buf);
00175 }
00176
00177 if (!samp_send(session, buf, len, err)) {
00178 return SASL_FAIL;
00179 }
00180
00181 while (result == SASL_CONTINUE) {
00182 if (session->verbose) {
00183 printf("Waiting for server reply...\n");
00184 }
00185 memset(buf, 0, sizeof(buf));
00186 len = samp_recv(session, buf, sizeof(buf), err);
00187 if (len <= 0) {
00188 printf("server problem, recv fail...\n");
00189 return SASL_FAIL;
00190 }
00191 result =
00192 sasl_client_step(conn, buf, len, NULL, &data, &len);
00193 if (result != SASL_OK && result != SASL_CONTINUE) {
00194 if (session->verbose)
00195 printf("Performing SASL negotiation\n");
00196 SET_ERROR(err, SASL_ERROR, result);
00197 }
00198 if (data && len) {
00199 if (session->verbose)
00200 puts("Sending response...\n");
00201 if (!samp_send(session, data, len, err)) {
00202 return SASL_FAIL;
00203 }
00204 } else if (result != SASL_OK) {
00205 if (!samp_send(session, "", 0, err)) {
00206 return SASL_FAIL;
00207 }
00208 }
00209 }
00210
00211 len = samp_recv(session, buf, 42, err);
00212 if (buf[0] != 'Y') {
00213 result = SASL_BADAUTH;
00214 SET_ERROR(err, SASL_ERROR, SASL_BADAUTH);
00215 }
00216
00217 if (result != SASL_OK) {
00218 if (session->verbose)
00219 puts("Authentication failed...");
00220 return SASL_FAIL;
00221 } else {
00222 if (session->verbose)
00223 puts("Authentication started...\n");
00224 }
00225
00226 return SASL_OK;
00227 }
00228
00229 static int add_packet_to_send(nuauth_session_t * session, conn_t ** auth,
00230 int *count_p, conn_t * bucket)
00231 {
00232 int count = *count_p;
00233 if (count < CONN_MAX - 1) {
00234 auth[count] = bucket;
00235 (*count_p)++;
00236 } else {
00237 int i;
00238 auth[count] = bucket;
00239 if (send_user_pckt(session, auth) != 1) {
00240
00241 #if DEBUG
00242 printf("error when sending\n");
00243 #endif
00244
00245 return -1;
00246 }
00247 for (i = 0; i < CONN_MAX; i++) {
00248 auth[i] = NULL;
00249 }
00250 *count_p = 0;
00251 }
00252 return 1;
00253 }
00254
00264 int compare(nuauth_session_t * session, conntable_t * old, conntable_t * new,
00265 nuclient_error_t * err)
00266 {
00267 int i;
00268 int count = 0;
00269 conn_t *auth[CONN_MAX];
00270 int nb_packets = 0;
00271
00272 assert(old != NULL);
00273 assert(new != NULL);
00274 for (i = 0; i < CONNTABLE_BUCKETS; i++) {
00275 conn_t *bucket;
00276 conn_t *same_bucket;
00277
00278 bucket = new->buckets[i];
00279 while (bucket != NULL) {
00280 same_bucket = tcptable_find(old, bucket);
00281 if (same_bucket == NULL) {
00282 #if DEBUG
00283 printf("sending new\n");
00284 #endif
00285 if (add_packet_to_send
00286 (session, auth, &count,
00287 bucket) == -1) {
00288
00289 return -1;
00290 }
00291 nb_packets++;
00292 } else {
00293
00294 if (bucket->retransmit >
00295 same_bucket->retransmit) {
00296 #if DEBUG
00297 printf("sending retransmit\n");
00298 #endif
00299 if (add_packet_to_send
00300 (session, auth, &count,
00301 bucket) == -1) {
00302
00303 return -1;
00304
00305 }
00306 nb_packets++;
00307 }
00308
00309
00310 if (bucket->protocol == IPPROTO_UDP) {
00311
00312 if (same_bucket->createtime <
00313 time(NULL) - UDP_TIMEOUT) {
00314 #if DEBUG
00315 printf
00316 ("working on timeout issue\n");
00317 #endif
00318 if (add_packet_to_send
00319 (session, auth, &count,
00320 bucket) == -1) {
00321 return -1;
00322 }
00323 nb_packets++;
00324 } else {
00325 bucket->createtime =
00326 same_bucket->
00327 createtime;
00328 }
00329 }
00330 }
00331 bucket = bucket->next;
00332 }
00333 }
00334 if (count > 0) {
00335 if (count < CONN_MAX) {
00336 auth[count] = NULL;
00337 }
00338 if (send_user_pckt(session, auth) != 1) {
00339
00340 return -1;
00341 }
00342 }
00343 return nb_packets;
00344 }
00345
00353 int send_os(nuauth_session_t * session, nuclient_error_t * err)
00354 {
00355
00356 struct utsname info;
00357 struct nu_authfield osfield;
00358 char *oses;
00359 char *enc_oses;
00360 char *pointer;
00361 char *buf;
00362 unsigned stringlen;
00363 unsigned actuallen;
00364 int osfield_length;
00365 int ret;
00366
00367
00368 uname(&info);
00369
00370
00371 stringlen = strlen(info.sysname) + 1
00372 + strlen(info.release) + 1 + strlen(info.version) + 1;
00373 #ifdef LINUX
00374 oses = alloca(stringlen);
00375 #else
00376 oses = calloc(stringlen, sizeof(char));
00377 #endif
00378 enc_oses = calloc(4 * stringlen, sizeof(char));
00379 (void) secure_snprintf(oses, stringlen,
00380 "%s;%s;%s",
00381 info.sysname, info.release, info.version);
00382 if (sasl_encode64
00383 (oses, strlen(oses), enc_oses, 4 * stringlen,
00384 &actuallen) == SASL_BUFOVER) {
00385 enc_oses = realloc(enc_oses, actuallen);
00386 sasl_encode64(oses, strlen(oses), enc_oses, actuallen,
00387 &actuallen);
00388 }
00389 #ifndef LINUX
00390 free(oses);
00391 #endif
00392
00393
00394 osfield.type = OS_FIELD;
00395 osfield.option = OS_SRV;
00396 osfield.length = sizeof(osfield) + actuallen;
00397
00398
00399 #ifdef LINUX
00400 buf = alloca(osfield.length);
00401 #else
00402 buf = calloc(osfield.length, sizeof(char));
00403 #endif
00404 osfield_length = osfield.length;
00405 osfield.length = htons(osfield.length);
00406 pointer = buf;
00407 memcpy(buf, &osfield, sizeof osfield);
00408 pointer += sizeof osfield;
00409 memcpy(pointer, enc_oses, actuallen);
00410 free(enc_oses);
00411
00412
00413 ret = nussl_write(session->nussl, buf, osfield_length);
00414 if (ret < 0) {
00415 if (session->verbose)
00416 printf("Error sending tls data: ...");
00417 SET_ERROR(err, NUSSL_ERR, ret);
00418 return 0;
00419 }
00420
00421
00422 ret = nussl_read(session->nussl, buf, osfield_length);
00423 if (ret <= 0) {
00424 errno = EACCES;
00425 SET_ERROR(err, NUSSL_ERR, ret);
00426 #ifndef LINUX
00427 free(buf);
00428 #endif
00429 return 0;
00430 }
00431
00432 #ifndef LINUX
00433 free(buf);
00434 #endif
00435
00436 if (buf[0] == SRV_TYPE) {
00437 session->server_mode = buf[1];
00438 } else {
00439 SET_ERROR(err, NUSSL_ERR, ret);
00440 }
00441 return 1;
00442 }
00443
00449 static int nu_get_usersecret(sasl_conn_t * conn __attribute__ ((unused)),
00450 void *context __attribute__ ((unused)), int id,
00451 sasl_secret_t ** psecret)
00452 {
00453 size_t len;
00454 nuauth_session_t *session = (nuauth_session_t *) context;
00455 if (id != SASL_CB_PASS) {
00456 if (session->verbose)
00457 printf("getsecret not looking for pass");
00458 return SASL_BADPARAM;
00459 }
00460 if ((session->password == NULL) && session->passwd_callback) {
00461 #if USE_UTF8
00462 char *utf8pass;
00463 #endif
00464 char *givenpass=session->passwd_callback();
00465 if (!givenpass){
00466 return SASL_FAIL;
00467 }
00468 #if USE_UTF8
00469 utf8pass = nu_client_to_utf8(givenpass, nu_locale_charset);
00470 free(givenpass);
00471 givenpass = utf8pass;
00472 if (!givenpass){
00473 return SASL_FAIL;
00474 }
00475 #endif
00476 session->password = givenpass;
00477 }
00478 if (!psecret)
00479 return SASL_BADPARAM;
00480
00481 len = strlen(session->password);
00482 *psecret =
00483 (sasl_secret_t *) calloc(sizeof(sasl_secret_t) + len + 1,
00484 sizeof(char));
00485 (*psecret)->len = len;
00486 SECURE_STRNCPY((char *) (*psecret)->data, session->password,
00487 len + 1);
00488 return SASL_OK;
00489 }
00490
00491 static int nu_get_userdatas(void *context __attribute__ ((unused)),
00492 int id, const char **result, unsigned *len)
00493 {
00494 nuauth_session_t *session = (nuauth_session_t *) context;
00495
00496 if (!result)
00497 return SASL_BADPARAM;
00498
00499 switch (id) {
00500 case SASL_CB_USER:
00501 case SASL_CB_AUTHNAME:
00502 if ((session->username == NULL) && session->username_callback) {
00503 #if USE_UTF8
00504 char *utf8name;
00505 #endif
00506 char *givenuser=session->username_callback();
00507 #if USE_UTF8
00508 utf8name = nu_client_to_utf8(givenuser, nu_locale_charset);
00509 free(givenuser);
00510 givenuser = utf8name;
00511 if (givenuser == NULL){
00512 return SASL_FAIL;
00513 }
00514 #endif
00515 session->username = givenuser;
00516 }
00517 *result = session->username;
00518 break;
00519 default:
00520 return SASL_BADPARAM;
00521 }
00522
00523 if (len)
00524 *len = strlen(*result);
00525
00526 return SASL_OK;
00527 }
00528
00529
00530
00539 int init_sasl(nuauth_session_t * session, const char *hostname, nuclient_error_t * err)
00540 {
00541 int ret;
00542 sasl_conn_t *conn;
00543 sasl_ssf_t extssf = 0;
00544 char * krb5_service = NULL;
00545 const char * server_fqdn = hostname;
00546 sasl_security_properties_t secprops;
00547
00548
00549 sasl_callback_t callbacks[] = {
00550 {SASL_CB_USER, &nu_get_userdatas, session},
00551 {SASL_CB_AUTHNAME, &nu_get_userdatas, session},
00552 {SASL_CB_PASS, &nu_get_usersecret, session},
00553 {SASL_CB_LIST_END, NULL, NULL}
00554 };
00555
00556 ret = nussl_write(session->nussl, "PROTO 5", strlen("PROTO 5"));
00557 if (ret < 0) {
00558 SET_ERROR(err, NUSSL_ERR, ret);
00559 return 0;
00560 }
00561
00562 krb5_service = session->krb5_service;
00563 if (krb5_service == NULL)
00564 krb5_service = DEFAULT_KRB5_REALM;
00565
00566
00567 ret = sasl_client_new(krb5_service, server_fqdn, NULL, NULL, callbacks, 0, &conn);
00568 if (ret != SASL_OK) {
00569 if (session->verbose)
00570 printf("Failed allocating connection state");
00571 errno = EAGAIN;
00572 SET_ERROR(err, SASL_ERROR, ret);
00573 return 0;
00574 }
00575
00576 if (! session->username){
00577
00578 if (session->username_callback){
00579 session->username = session->username_callback();
00580 } else {
00581 if (session->verbose)
00582 printf("Can't call username callback\n");
00583 }
00584 }
00585
00586 secprops.min_ssf = 0;
00587 secprops.max_ssf = UINT_MAX;
00588 secprops.property_names = NULL;
00589 secprops.property_values = NULL;
00590 secprops.security_flags = SASL_SEC_NOANONYMOUS;
00591 secprops.maxbufsize = 65536;
00592 sasl_setprop(conn, SASL_SEC_PROPS, &secprops);
00593
00594 sasl_setprop(conn, SASL_SSF_EXTERNAL, &extssf);
00595 ret = sasl_setprop(conn, SASL_AUTH_EXTERNAL, session->username);
00596 if (ret != SASL_OK) {
00597 errno = EACCES;
00598 SET_ERROR(err, SASL_ERROR, ret);
00599 return 0;
00600 }
00601
00602 ret = mysasl_negotiate(session, conn, err);
00603 if (ret != SASL_OK) {
00604 errno = EACCES;
00605
00606 return 0;
00607 }
00608 sasl_dispose(&conn);
00609
00610 return 1;
00611 }
00612
00623 char *secure_str_copy(const char *orig)
00624 {
00625 #ifdef USE_GCRYPT_MALLOC_SECURE
00626 size_t len = strlen(orig);
00627 char *new = gcry_calloc_secure(len + 1, sizeof(char));
00628 if (new != NULL) {
00629 SECURE_STRNCPY(new, orig, len + 1);
00630 }
00631 return new;
00632 #else
00633 return strdup(orig);
00634 #endif
00635 }
00636
00637 void ask_session_end(nuauth_session_t * session)
00638 {
00639
00640 if (session == NULL) {
00641 return;
00642 }
00643 if(session->nussl) {
00644 nussl_session_destroy(session->nussl);
00645 session->nussl = NULL;
00646 }
00647 session->connected = 0;
00648 }
00649
00650