/** * \ingroup nuclientAPI * Initialize TLS: * - Set key filename (and test if the file does exist) * - Set certificate (if key and cert. are present) * * \param session Pointer to client session * \param keyfile Complete path to a key file stored in PEM format (can be NULL) * \param certfile Complete path to a certificate file stored in PEM format (can be NULL) * \param err Pointer to a nuclient_error_t: which contains the error * \return Returns 0 on error (error description in err), 1 otherwise */ int nu_client_load_key(nuauth_session_t * session, const char *keyfile, const char *certfile, nuclient_error_t * err) { char certstring[256]; char keystring[256]; char *home = nu_get_home_dir(); int exit_on_error = 0; int ret; /* If the user specified a certficate and a key on command line, * exit if we fail loading them. * Elsewise, try loading certs from ~/.nufw/, but continue if we fail */ if (certfile || keyfile) exit_on_error = 1; /* compute patch keyfile */ if (keyfile == NULL && home != NULL) { ret = secure_snprintf(keystring, sizeof(keystring), "%s/.nufw/key.pem", home); if (ret) keyfile = keystring; } if (certfile == NULL && home != NULL) { ret = secure_snprintf(certstring, sizeof(certstring), "%s/.nufw/cert.pem", home); if (ret) certfile = certstring; } if (certfile != NULL || keyfile != NULL) { ret = nussl_ssl_set_keypair(session->nussl, certfile, keyfile); if (ret != NUSSL_OK) { if (exit_on_error) { if (home) free(home); SET_ERROR(err, NUSSL_ERR, ret); return 0; } else { log_printf(DEBUG_LEVEL_WARNING, "Warning: Failed to load default certificate and key."); } } } if (home) free(home); return 1; }
char *compute_user_config_path() { char path_dir[254]; char *home = nu_get_home_dir(); if (home == NULL) return NULL; secure_snprintf(path_dir, sizeof(path_dir), "%s/.nufw", home); if (access(path_dir, R_OK) != 0) { return NULL; } secure_snprintf(path_dir, sizeof(path_dir), "%s/.nufw/ufwiclient.conf", home); free(home); if (access(path_dir, R_OK) != 0) { return NULL; } return strdup(path_dir); }
/** * Load program cache */ void prg_cache_load() { char path_process[PATH_MAX]; char path_fd[PATH_MAX]; DIR *dirproc = NULL; DIR *dirfd = NULL; struct dirent *file; if (prg_cache_loaded) return; prg_cache_loaded = 1; /* open directory "/proc" */ dirproc = opendir("/proc"); if (dirproc == NULL) panic("Fail to open /proc directory!"); while ((file = readdir(dirproc)) != NULL) { #ifdef HAVE_STRUCT_DIRENT_D_TYPE if (file->d_type != DT_DIR) continue; #endif if (!str_is_integer(file->d_name)) continue; /* create path like "/proc/123" */ if (!secure_snprintf (path_process, sizeof(path_process), "/proc/%s", file->d_name)) continue; /* create path like "/proc/123/fd" */ if (!secure_snprintf (path_fd, sizeof(path_fd), "%s/fd", path_process)) continue; /* open directory like "/proc/123/fd" */ dirfd = opendir(path_fd); if (dirfd != NULL) { prg_cache_load_sub(dirfd, path_process, path_fd); closedir(dirfd); } } closedir(dirproc); }
/** * Walk in directoty like "/proc/123/fd/" */ void prg_cache_load_sub(DIR * dir, const char *path_process, const char *path_fd) { char path[PATH_MAX]; char lname[30]; char finbuf[PROGNAME_WIDTH]; unsigned long inode; struct dirent *file; while ((file = readdir(dir)) != NULL) { #ifdef HAVE_STRUCT_DIRENT_D_TYPE if (file->d_type != DT_LNK) continue; #endif /* read link of "/proc/123/fd/FILENAME" */ if (!secure_snprintf (path, sizeof(path), "%s/%s", path_fd, file->d_name)) continue; if (!secure_readlink(path, lname, sizeof(lname))) continue; /* * extract inode number from name like "socket:[12345]" * or "[0000]:12345" */ if (extract_type_1_socket_inode(lname, &inode) < 0) if (extract_type_2_socket_inode(lname, &inode) < 0) continue; /* get exec fullpath */ if (!secure_snprintf (path, sizeof(path), "%s/exe", path_process)) continue; if (!secure_readlink(path, finbuf, sizeof(finbuf))) continue; /* add item to the cache */ prg_cache_add(inode, finbuf); } }
/** * \ingroup nuclientAPI * Initialize TLS: * - Set trust file of credentials (if needed) * * \param session Pointer to client session * \param cafile Complete path to a certificate authority file stored in PEM format (can be NULL) * \param err Pointer to a nuclient_error_t: which contains the error * \return Returns 0 on error (error description in err), 1 otherwise */ int nu_client_load_ca(nuauth_session_t * session, const char *cafile, nuclient_error_t * err) { char castring[256]; char *home = nu_get_home_dir(); int exit_on_error = 0; int ret; if (cafile != NULL) exit_on_error = 1; if (cafile == NULL && home != NULL) { ret = secure_snprintf(castring, sizeof(castring), "%s/.nufw/cacert.pem", home); if (ret) cafile = castring; } if (cafile != NULL) { ret = nussl_ssl_trust_cert_file(session->nussl, cafile); if (ret != NUSSL_OK) { if (exit_on_error) { if (home) free(home); SET_ERROR(err, NUSSL_ERR, ret); return 0; } else { if (!session->suppress_ca_warning) { log_printf(DEBUG_LEVEL_WARNING, "\nWARNING: you have not provided any certificate authority.\n" "nutcpc will *NOT* verify server certificate trust.\n" "Use the -A <cafile> option to set up CA.\n" ); } session->suppress_fqdn_verif = 1; nussl_set_session_flag(session->nussl, NUSSL_SESSFLAG_IGNORE_ID_MISMATCH, 1); } } } else { log_printf(DEBUG_LEVEL_WARNING, "Could not load any CA !"); return 0; } return 1; }
/** * Parse a Linux connection table (/proc/net/tcp or /proc/net/udp) and filter * connection: only keep session user connections in state "SYN packet sent". * Add connections to the our table using tcptable_add(). */ int parse_tcptable_file(nuauth_session_t * session, conntable_t * ct, char *filename, FILE ** file, int protocol, int use_ipv6) { char *buf; char fullbuf[1024*256]; conn_t c; const char state_char = '2'; /* TCP_SYN_SENT written in hexadecimal */ int state_pos; int uid_pos; char session_uid[20]; int session_uid_len; int ret; char *pos; int fdfile; int i = 0; int readlen = 0; fdfile = open(filename, O_RDONLY); if (fdfile == -1) { panic("Unable to open proc file"); } /* read all file */ buf = fullbuf; while ( ((1024*256 - (buf - fullbuf)) > 0) && (i = read(fdfile, buf, 1024*256 - (buf - fullbuf)))) { buf += i; readlen += i; } close(fdfile); /* convert session user identifier to string */ secure_snprintf(session_uid, sizeof(session_uid), "%5lu", (long)session->userid); session_uid_len = strlen(session_uid); /* get state field position in header */ pos = strstr(fullbuf, " st "); if (pos == NULL) panic ("Can't find position of state field in /proc/net/tcp header!"); state_pos = pos - fullbuf + 2; /* get user identifier position in header (it's just after 'retrnsmt' field) */ pos = strstr(fullbuf, " retrnsmt "); if (pos == NULL) panic ("Can't find position of user identifier field in /proc/net/tcp header!"); uid_pos = pos - fullbuf + strlen(" retrnsmt "); buf = fullbuf; while (buf - fullbuf < readlen - uid_pos) { buf = strchr(buf, '\n') + 1; /* only keep connections in state "SYN packet sent" */ if (buf[state_pos] != state_char) { continue; } /* only keep session user connections */ if (strncmp(buf + uid_pos, session_uid, session_uid_len) != 0) { continue; } /* get all fields */ if (!use_ipv6) { uint32_t src, dst; ret = sscanf(buf, "%*d: " "%" SCNx32 ":%hx " "%" SCNx32 ":%hx " "%*x %*x:%*x %*x:%*x %x " "%lu %*d %lu", &src, &c.port_src, &dst, &c.port_dst, &c.retransmit, &c.uid, &c.inode); if (ret != 7) { continue; } uint32_to_ipv6(src, &c.ip_src); uint32_to_ipv6(dst, &c.ip_dst); } else { char ip_src[33]; char ip_dst[33]; ret = sscanf(buf, "%*d: " "%32s" ":%hx " "%32s" ":%hx " "%*x %*x:%*x %*x:%*x %x " "%lu %*d %lu", ip_src, &c.port_src, ip_dst, &c.port_dst, &c.retransmit, &c.uid, &c.inode); if (ret != 7) { continue; } if (!hex2ipv6(ip_src, &c.ip_src)) continue; if (!hex2ipv6(ip_dst, &c.ip_dst)) continue; } /* skip nul inodes */ if (c.inode == 0) { continue; } #if DEBUG /* Check if there is a matching rule in the filters list */ printf("Packet dst = %ld (%lx)\n", c.rmt, c.rmt); #endif c.protocol = protocol; tcptable_add(ct, &c); } return 1; }