libnuclient.c

Go to the documentation of this file.
00001 /*
00002  ** Copyright 2004-2008 - INL
00003  ** Written by Eric Leblond <regit@inl.fr>
00004  **            Vincent Deffontaines <vincent@inl.fr>
00005  ** INL http://www.inl.fr/
00006  **
00007  ** $Id: libnuclient.c 5267 2008-11-20 16:08:36Z 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 
00038 #define USE_GCRYPT_MALLOC_SECURE
00039 
00040 #include "libnuclient.h"
00041 #include "nuclient.h"
00042 #include "nufw_source.h"
00043 #include <sasl/sasl.h>
00044 #include <sasl/saslutil.h>
00045 #include <stdarg.h>             /* va_list, va_start, ... */
00046 #include <langinfo.h>
00047 #include <proto.h>
00048 #include "security.h"
00049 #include "sys_config.h"
00050 #include "internal.h"
00051 #include "tcptable.h"
00052 #include <sys/utsname.h>
00053 
00054 #include <nussl.h>
00055 #include <nubase.h>
00056 
00057 
00058 void nu_exit_clean(nuauth_session_t * session)
00059 {
00060         if (session->ct) {
00061                 tcptable_free(session->ct);
00062         }
00063 
00064         if(session->nussl)
00065         {
00066                 nussl_session_destroy(session->nussl);
00067                 session->nussl = NULL;
00068         }
00069 
00070         secure_str_free(session->username);
00071         secure_str_free(session->password);
00072 
00073         free(session);
00074 }
00075 
00101 void nu_client_delete(nuauth_session_t * session)
00102 {
00103         ask_session_end(session);
00104         /* destroy session */
00105         nu_exit_clean(session);
00106 }
00107 
00118 int nu_client_global_init(nuclient_error_t * err)
00119 {
00120         int ret;
00121 
00122         if (nussl_init() != NUSSL_OK)
00123         {
00124                 SET_ERROR(err, INTERNAL_ERROR, NUSSL_INIT_ERR); /* TODO: patch nussl to handle errors correctly in nussl_sock_init */
00125                 return 0;
00126         }
00127 
00128         /* initialize the sasl library */
00129         ret = sasl_client_init(NULL);
00130         if (ret != SASL_OK) {
00131                 SET_ERROR(err, SASL_ERROR, ret);
00132                 return 0;
00133         }
00134         /* get local charset */
00135         nu_locale_charset = nl_langinfo(CODESET);
00136         if (nu_locale_charset == NULL) {
00137                 fprintf(stderr, "Can't get locale charset!\n");
00138                 exit(EXIT_FAILURE);
00139         }
00140 
00141         load_sys_config();
00142 
00143         return 1;
00144 }
00145 
00152 void nu_client_global_deinit()
00153 {
00154         sasl_done();
00155 }
00156 
00162 void nu_client_set_username(nuauth_session_t *session,
00163                             const char *username)
00164 {
00165         char *utf8username = nu_client_to_utf8(username, nu_locale_charset);
00166         session->username = secure_str_copy(utf8username);
00167         free(utf8username);
00168 }
00169 
00175 void nu_client_set_password(nuauth_session_t *session,
00176                                     const char *password)
00177 {
00178         char *utf8pass = nu_client_to_utf8(password, nu_locale_charset);
00179         session->password = secure_str_copy(utf8pass);
00180         free(utf8pass);
00181 }
00182 
00183 void nu_client_set_debug(nuauth_session_t * session, unsigned char enabled);
00184 
00192 char *nu_get_home_dir()
00193 {
00194         uid_t uid;
00195         struct passwd *pwd;
00196         char *dir = NULL;
00197 
00198         uid = getuid();
00199         if (!(pwd = getpwuid(uid))) {
00200                 printf("Unable to get password file record\n");
00201                 endpwent();
00202                 return NULL;
00203         }
00204         dir = strdup(pwd->pw_dir);
00205         endpwent();
00206         return dir;
00207 }
00208 
00216 char *nu_get_user_name()
00217 {
00218         uid_t uid;
00219         struct passwd *pwd;
00220         char *name = NULL;
00221 
00222         uid = getuid();
00223         if (!(pwd = getpwuid(uid))) {
00224                 printf("Unable to get password file record\n");
00225                 endpwent();
00226                 return NULL;
00227         }
00228         name = strdup(pwd->pw_name);
00229         endpwent();
00230         return name;
00231 }
00232 
00233 int nu_client_set_key(nuauth_session_t* session, char* keyfile, char* certfile, nuclient_error_t* err)
00234 {
00235         if (session->pem_key)
00236                 free(session->pem_key);
00237 
00238         if (session->pem_cert)
00239                 free(session->pem_cert);
00240 
00241         if (keyfile)
00242         {
00243                 session->pem_key = strdup(keyfile);
00244                 printf("Using key: %s\n", keyfile);
00245         }
00246 
00247         if (certfile)
00248         {
00249                 session->pem_cert = strdup(certfile);
00250                 printf("Using certificate: %s\n", certfile);
00251         }
00252 
00253         return 1;
00254 }
00255 
00256 int nu_client_set_ca(nuauth_session_t* session, char* cafile, nuclient_error_t* err)
00257 {
00258         if (session->pem_ca)
00259                 free(session->pem_ca);
00260 
00261         if (cafile)
00262                 session->pem_ca = strdup(cafile);
00263 
00264         printf("Using CA: %s\n", cafile);
00265         return 1;
00266 }
00267 
00268 int nu_client_set_pkcs12(nuauth_session_t* session, char* key_file, char* key_password, nuclient_error_t* err)
00269 {
00270         if (session->pkcs12_file)
00271                 free(session->pkcs12_file);
00272 
00273         if (session->pkcs12_password)
00274                 free(session->pkcs12_password);
00275 
00276         if (key_file)
00277         {
00278                 printf("Using key: %s\n", key_file);
00279                 session->pkcs12_file = strdup(key_file);
00280         }
00281 
00282         if (key_password)
00283                 session->pkcs12_password = strdup(key_password);
00284 
00285         return 1;
00286 }
00299 int nu_client_load_key(nuauth_session_t * session,
00300                         char *keyfile, char *certfile,
00301                         nuclient_error_t * err)
00302 {
00303         char certstring[256];
00304         char keystring[256];
00305         char *home = nu_get_home_dir();
00306         int exit_on_error = 0;
00307         int ret;
00308 
00309         /* If the user specified a certficate and a key on command line,
00310          * exit if we fail loading them.
00311          * Elsewise, try loading certs from ~/.nufw/, but continue if we fail
00312          */
00313         if (certfile || keyfile)
00314                 exit_on_error = 1;
00315 
00316         /* compute patch keyfile */
00317         if (keyfile == NULL && home != NULL) {
00318                 ret = secure_snprintf(keystring, sizeof(keystring),
00319                                      "%s/.nufw/key.pem", home);
00320                 if (ret)
00321                         keyfile = keystring;
00322         }
00323 
00324         if (certfile == NULL && home != NULL) {
00325                 ret = secure_snprintf(certstring, sizeof(certstring),
00326                                      "%s/.nufw/cert.pem", home);
00327                 if (ret)
00328                         certfile = certstring;
00329         }
00330 
00331         if (certfile != NULL || keyfile != NULL) {
00332                 ret =
00333                     nussl_ssl_set_keypair(session->nussl, certfile, keyfile);
00334 
00335                 if (ret != NUSSL_OK) {
00336                         if (exit_on_error) {
00337                                 if (home)
00338                                         free(home);
00339                                 SET_ERROR(err, NUSSL_ERR, ret);
00340                                 return 0;
00341                         }
00342                         else {
00343                                 printf("Warning: Failed to load default certificate and key.\n");
00344                         }
00345                 }
00346         }
00347 
00348         if (home)
00349                 free(home);
00350 
00351         return 1;
00352 }
00353 
00354 
00367 int nu_client_load_pkcs12(nuauth_session_t * session,
00368                         char *pkcs12file, char *pkcs12password,
00369                         nuclient_error_t * err)
00370 {
00371         int ret = nussl_ssl_set_pkcs12_keypair(session->nussl, pkcs12file, pkcs12password);
00372         if (ret != NUSSL_OK)
00373         {
00374                 SET_ERROR(err, NUSSL_ERR, ret);
00375                 return 0;
00376         }
00377         return 1;
00378 }
00379 
00380 
00391 int nu_client_load_ca(nuauth_session_t * session,
00392                         char *cafile,
00393                         nuclient_error_t * err)
00394 {
00395         char castring[256];
00396         char *home = nu_get_home_dir();
00397         int exit_on_error = 0;
00398         int ret;
00399 
00400         if (cafile != NULL)
00401                 exit_on_error = 1;
00402 
00403         if (cafile == NULL && home != NULL) {
00404                 ret = secure_snprintf(castring, sizeof(castring),
00405                                      "%s/.nufw/cacert.pem", home);
00406                 if (ret)
00407                         cafile = castring;
00408         }
00409 
00410         if (cafile != NULL) {
00411                 ret = nussl_ssl_trust_cert_file(session->nussl, cafile);
00412                 if (ret != NUSSL_OK) {
00413                         if (exit_on_error) {
00414                                 if (home)
00415                                         free(home);
00416                                 SET_ERROR(err, NUSSL_ERR, ret);
00417                                 return 0;
00418                         }
00419                         else {
00420                                 if (!session->suppress_ca_warning) {
00421                                         fprintf(stderr,"\nWARNING: you have not provided any certificate authority.\n"
00422                                                         "nutcpc will *NOT* verify server certificate trust.\n"
00423                                                         "Use the -A <cafile> option to set up CA.\n\n"
00424                                                );
00425                                 }
00426                                 session->suppress_fqdn_verif = 1;
00427                                 nussl_set_session_flag(session->nussl, NUSSL_SESSFLAG_IGNORE_ID_MISMATCH, 1);
00428                         }
00429                 }
00430         } else {
00431                 fprintf(stderr, "Could not load any CA !\n");
00432                 return 0;
00433         }
00434         return 1;
00435 }
00436 
00437 int nu_client_load_crl(nuauth_session_t *session, const char *crlfile,
00438         const char *cafile, nuclient_error_t * err)
00439 {
00440         int ret;
00441         if (crlfile && *crlfile) {
00442                 ret = nussl_ssl_set_crl_file(session->nussl, crlfile);
00443                 if (ret != NUSSL_OK) {
00444                         fprintf(stderr,"TLS error with CRL: %s",
00445                                 nussl_get_error(session->nussl));
00446                         return 0;
00447                 }
00448                 printf("Using crl: %s\n", crlfile);
00449         }
00450         return 1;
00451 }
00452 
00460 char* nu_client_get_cert_infos(nuauth_session_t * session)
00461 {
00462         return nussl_get_cert_infos(session->nussl);
00463 }
00464 
00465 
00473 char* nu_client_get_server_cert_infos(nuauth_session_t * session)
00474 {
00475         return nussl_get_server_cert_infos(session->nussl);
00476 }
00477 
00478 
00482 int nu_client_set_nuauth_cert_dn(nuauth_session_t * session,
00483                                 char *nuauth_cert_dn,
00484                                 nuclient_error_t *err)
00485 {
00486         if (*nuauth_cert_dn) {
00487                 session->nuauth_cert_dn = nuauth_cert_dn;
00488         }
00489         return 1;
00490 }
00491 
00495 int nu_client_set_crlfile(nuauth_session_t * session,
00496                 char *crlfile,
00497                 nuclient_error_t *err)
00498 {
00499         if (session->pem_crl)
00500                 free(session->pem_crl);
00501 
00502         if (crlfile)
00503                 session->pem_crl = strdup(crlfile);
00504 
00505         return 1;
00506 }
00507 
00511 int nu_client_set_krb5_service(nuauth_session_t * session,
00512                                 char *service)
00513 {
00514         if (service) {
00515                 session->krb5_service = service;
00516         }
00517         return 1;
00518 }
00519 
00523 int nu_client_set_ca_suppress_warning(nuauth_session_t * session,
00524                                 int suppress_ca_warning)
00525 {
00526         session->suppress_ca_warning = suppress_ca_warning;
00527         return 1;
00528 }
00529 
00533 int nu_client_set_fqdn_suppress_verif(nuauth_session_t * session,
00534                                 int suppress_fqdn_verif)
00535 {
00536         session->suppress_fqdn_verif = suppress_fqdn_verif;
00537         return 1;
00538 }
00539 
00547 void nu_client_set_source(nuauth_session_t *session, struct sockaddr_storage *addr)
00548 {
00549         session->has_src_addr = 1;
00550         session->src_addr = *addr;
00551 }
00552 
00568 nuauth_session_t *_nu_client_new(nuclient_error_t * err)
00569 {
00570         conntable_t *new;
00571         nuauth_session_t *session;
00572 
00573         /* First reset error */
00574         SET_ERROR(err, INTERNAL_ERROR, NO_ERR);
00575 
00576         /* Allocate a new session */
00577         session = (nuauth_session_t *) calloc(1, sizeof(nuauth_session_t));
00578         if (session == NULL) {
00579                 SET_ERROR(err, INTERNAL_ERROR, MEMORY_ERR);
00580                 return NULL;
00581         }
00582 
00583         /* Set basic fields */
00584         session->userid = getuid();
00585         session->connected = 0;
00586         session->auth_by_default = 1;
00587         session->packet_seq = 0;
00588         session->ct = NULL;
00589         session->debug_mode = 0;
00590         session->verbose = 1;
00591         session->timestamp_last_sent = time(NULL);
00592         session->min_sleep_delay.tv_sec = MIN_DELAY_SEC;
00593         session->min_sleep_delay.tv_usec = MIN_DELAY_USEC;
00594         session->max_sleep_delay.tv_sec = MAX_DELAY_SEC;
00595         session->max_sleep_delay.tv_usec = MAX_DELAY_USEC;
00596         session->sleep_delay.tv_sec = MIN_DELAY_SEC;
00597         session->sleep_delay.tv_usec = MIN_DELAY_USEC;
00598 
00599         if (tcptable_init(&new) == 0) {
00600                 SET_ERROR(err, INTERNAL_ERROR, MEMORY_ERR);
00601                 nu_exit_clean(session);
00602                 return NULL;
00603         }
00604         session->ct = new;
00605 
00606         return session;
00607 }
00608 
00624 nuauth_session_t *nu_client_new_callback(void *username_callback,
00625                       void *passwd_callback,
00626                       unsigned char diffie_hellman, nuclient_error_t * err)
00627 {
00628         nuauth_session_t *session = NULL;
00629 
00630         if (username_callback == NULL || passwd_callback == NULL) {
00631                 SET_ERROR(err, INTERNAL_ERROR, BAD_CREDENTIALS_ERR);
00632                 return NULL;
00633         }
00634 
00635         session = _nu_client_new(err);
00636 
00637         session->username_callback = username_callback;
00638         session->passwd_callback = passwd_callback;
00639 
00640         return session;
00641 }
00642 
00658 nuauth_session_t *nu_client_new(const char *username,
00659                       const char *password,
00660                       unsigned char diffie_hellman, nuclient_error_t * err)
00661 {
00662         nuauth_session_t *session = NULL;
00663 
00664         if (username == NULL || password == NULL) {
00665                 SET_ERROR(err, INTERNAL_ERROR, BAD_CREDENTIALS_ERR);
00666                 return NULL;
00667         }
00668 
00669         session = _nu_client_new(err);
00670 
00671         session->username = secure_str_copy(username);
00672         session->password = secure_str_copy(password);
00673         if (session->username == NULL || session->password == NULL) {
00674                 SET_ERROR(err, INTERNAL_ERROR, MEMORY_ERR);
00675                 return NULL;
00676         }
00677 
00678         return session;
00679 }
00680 
00686 void nu_client_reset(nuauth_session_t * session)
00687 {
00688         ask_session_end(session);
00689 
00690         /* reset fields */
00691         session->connected = 0;
00692         session->timestamp_last_sent = time(NULL);
00693 }
00694 
00709 int nu_client_connect(nuauth_session_t * session,
00710                       const char *hostname, const char *service,
00711                       nuclient_error_t * err)
00712 {
00713         int ret;
00714         unsigned int port = atoi(service);
00715 
00716         session->nussl = nussl_session_create();
00717 
00718         if (session->suppress_fqdn_verif)
00719                 nussl_set_session_flag(session->nussl, NUSSL_SESSFLAG_IGNORE_ID_MISMATCH, 1);
00720 
00721         nussl_set_hostinfo(session->nussl, hostname, port);
00722         if(session->pkcs12_file)
00723         {
00724                 if (!nu_client_load_pkcs12(session, session->pkcs12_file, session->pkcs12_password, err))
00725                         return 0;
00726         }
00727         else
00728         {
00729                 if (!nu_client_load_key(session, session->pem_key, session->pem_cert, err))
00730                         return 0;
00731         }
00732 
00733         if (!nu_client_load_ca(session, session->pem_ca, err))
00734                 return 0;
00735 
00736         if (session->pem_crl) {
00737                 if (!nu_client_load_crl(session, session->pem_crl, session->pem_ca, err))
00738                         return 0;
00739         }
00740 
00741         ret = nussl_open_connection(session->nussl);
00742         if (ret != NUSSL_OK) {
00743                 nussl_session_destroy(session->nussl);
00744                 session->nussl = NULL;
00745                 SET_ERROR(err, NUSSL_ERR, ret);
00746                 return 0;
00747         }
00748 
00749         if (!init_sasl(session, hostname, err)) {
00750                 return 0;
00751         }
00752 
00753         if (!send_os(session, err)) {
00754                 return 0;
00755         }
00756         session->connected = 1;
00757         return 1;
00758 }
00759 
00767 void nu_client_set_debug(nuauth_session_t * session, unsigned char enabled)
00768 {
00769         session->debug_mode = enabled;
00770 }
00771 
00772 
00780 void nu_client_set_verbose(nuauth_session_t * session, unsigned char enabled)
00781 {
00782         session->verbose = enabled;
00783 }
00784 
00793 void nu_client_set_min_delay(nuauth_session_t * session, unsigned int delay)
00794 {
00795         session->min_sleep_delay.tv_sec = delay / 1000;
00796         session->min_sleep_delay.tv_usec = (delay * 1000) % 1000000;
00797 }
00798 
00807 void nu_client_set_max_delay(nuauth_session_t * session, unsigned int delay)
00808 {
00809         session->max_sleep_delay.tv_sec = delay / 1000;
00810         session->max_sleep_delay.tv_usec = (delay * 1000) % 1000000;
00811 }
00812 
00817 int nu_client_error_init(nuclient_error_t ** err)
00818 {
00819         if (*err != NULL)
00820                 return -1;
00821         *err = malloc(sizeof(nuclient_error_t));
00822         if (*err == NULL)
00823                 return -1;
00824         return 0;
00825 }
00826 
00831 void nu_client_error_destroy(nuclient_error_t * err)
00832 {
00833         if (err != NULL)
00834                 free(err);
00835 }
00836 
00841 const char *nu_client_strerror(nuauth_session_t * session, nuclient_error_t * err)
00842 {
00843         if (err == NULL) {
00844                 return "Error structure was not initialised";
00845         }
00846 
00847         switch (err->family) {
00848         case NUSSL_ERR:
00849                 if(session == NULL || session->nussl == NULL)
00850                         return "NuSSL initialization error.";
00851                 return nussl_get_error(session->nussl);
00852         case SASL_ERROR:
00853                 return sasl_errstring(err->error, NULL, NULL);
00854                 break;
00855         case INTERNAL_ERROR:
00856                 switch (err->error) {
00857                 case NO_ERR:
00858                         return "No error";
00859                 case SESSION_NOT_CONNECTED_ERR:
00860                         return "Session not connected";
00861                 case TIMEOUT_ERR:
00862                         return "Connection timeout";
00863                 case DNS_RESOLUTION_ERR:
00864                         return "DNS resolution error";
00865                 case NO_ADDR_ERR:
00866                         return "Address not recognized";
00867                 case FILE_ACCESS_ERR:
00868                         return "File access error";
00869                 case CANT_CONNECT_ERR:
00870                         return "Connection failed";
00871                 case MEMORY_ERR:
00872                         return "No more memory";
00873                 case TCPTABLE_ERR:
00874                         return "Unable to read connection table";
00875                 case SEND_ERR:
00876                         return "Unable to send packet to nuauth";
00877                 case BAD_CREDENTIALS_ERR:
00878                         return "Bad credentials";
00879                 case BINDING_ERR:
00880                         return "Binding (source address) error";
00881                 case NUSSL_INIT_ERR:
00882                         return "NuSSL initialisation failed.";
00883                 default:
00884                         return "Unknown internal error code";
00885                 }
00886                 break;
00887         default:
00888                 return "Unknown family error";
00889         }
00890 }
00891 
00898 const char *nu_get_version()
00899 {
00900         return NUCLIENT_VERSION;
00901 }
00902 
00910 int nu_check_version(const char *version)
00911 {
00912         if (strcmp(NUCLIENT_VERSION, version) == 0)
00913                 return 1;
00914         else
00915                 return 0;
00916 }
00917 

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