internal.c

Go to the documentation of this file.
00001 /*
00002  ** Copyright 2004-2007 - INL
00003  ** Written by Eric Leblond <regit@inl.fr>
00004  **            Vincent Deffontaines <vincent@inl.fr>
00005  ** INL http://www.inl.fr/
00006  **
00007  ** $Id: internal.c 5255 2008-11-20 14:02:40Z pollux $
00008  **
00009  ** This program is free software; you can redistribute it and/or modify
00010  ** it under the terms of the GNU General Public License as published by
00011  ** the Free Software Foundation, version 3 of the License.
00012  **
00013  ** This program is distributed in the hope that it will be useful,
00014  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  ** GNU General Public License for more details.
00017  **
00018  ** You should have received a copy of the GNU General Public License
00019  ** along with this program; if not, write to the Free Software
00020  ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
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>             /* va_list, va_start, ... */
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         /* prefix ("C: ") + base64 length + 1 nul byte */
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 /* XXX: Move this fuction into nussl */
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         /* gnutls_session session = session->tls; */
00141 
00142         memset(buf, 0, sizeof buf);
00143         /* get the capability list */
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                         /* error sending */
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                                         /* problem when sending we exit */
00289                                         return -1;
00290                                 }
00291                                 nb_packets++;
00292                         } else {
00293                                 /* compare values of retransmit */
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                                                 /* problem when sending we exit */
00303                                                 return -1;
00304 
00305                                         }
00306                                         nb_packets++;
00307                                 }
00308 
00309                                 /* solve timeout issue on UDP */
00310                                 if (bucket->protocol == IPPROTO_UDP) {
00311                                         /* send an auth packet if netfilter timeout may have been reached */
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                         /* error sending */
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         /* announce our OS */
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         /* read OS informations */
00368         uname(&info);
00369 
00370         /* encode OS informations in base64 */
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         /* build packet header */
00394         osfield.type = OS_FIELD;
00395         osfield.option = OS_SRV;
00396         osfield.length = sizeof(osfield) + actuallen;
00397 
00398         /* add packet body */
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         /* Send OS field over network */
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         /* wait for message of server about mode */
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         /* paranoia check */
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         /* SASL time */
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         /* client new connection */
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                 /* set username taken from console */
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; /* as appropriate */
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                 /*        SET_ERROR(err, SASL_ERROR, ret); */
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         /* sanity checks */
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 

Generated on Sat Nov 22 04:00:37 2008 for NuFW by  doxygen 1.4.7