📄 rpasswd-client.c
字号:
continue; } else if (strncmp (cp, "reqcert", 7) == 0 && isspace ((int) cp[7])) { char *p = &cp[7]; while (isspace (*p)) ++p; *reqcertp = parse_reqcert (p); continue; }#ifdef DO_VERBOSE_OUTPUT if (check_syntax) { PRINTF (STD_HANDLE, _("Entry \"%s\" is not valid!\n"), cp); ++bad_entries; } else PRINTF (ERR_HANDLE, _("Entry \"%s\" is not valid, ignored!\n"), cp);#endif } fclose (fp); if (buf) free (buf);#ifdef DO_VERBOSE_OUTPUT if (check_syntax) { if (bad_entries) { PRINTF (STD_HANDLE, _("Bad entries found.\n")); return 1; } if (!have_entries) { PRINTF (STD_HANDLE, _("No entry found.\n")); return 1; } }#endif if (!have_entries) {#ifdef DO_VERBOSE_OUTPUT if (verbose > 1) PRINTF (STD_HANDLE, _("No entry found."));#endif return 1; } return 0;}static intconnect_to_server (HANDLE const char *hostp, const char *portp, int family){#ifdef NI_WITHSCOPEID const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID;#else const int niflags = NI_NUMERICHOST;#endif struct addrinfo hints, *res, *res0; int error; int sock = -1; memset (&hints, 0, sizeof (hints)); hints.ai_family = family; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_CANONNAME; error = getaddrinfo (hostp, portp, &hints, &res0); if (error) { if (error == EAI_NONAME) { PRINTF (ERR_HANDLE, _ ("Hostname or service not known for specified protocol\n")); return -1; } else if (error == EAI_SERVICE) { /* if port cannot be resolved, try compiled in port number. If this works, don't abort here. */ char *cp; asprintf (&cp, "%d", RPASSWDD_PORT); error = getaddrinfo (hostp, cp, &hints, &res0); free (cp); if (error) { PRINTF (ERR_HANDLE, _("bad port: %s\n"), portp); return -1; } } else { PRINTF (ERR_HANDLE, "%s: %s\n", hostp, gai_strerror (error)); return -1; } } for (res = res0; res; res = res->ai_next) { char hbuf[NI_MAXHOST]; if (getnameinfo (res->ai_addr, res->ai_addrlen, hbuf, sizeof (hbuf), NULL, 0, niflags) != 0) strcpy (hbuf, "(invalid)"); switch (res->ai_family) { case AF_INET: { struct sockaddr_in s_in; memcpy (&s_in, res->ai_addr, sizeof (struct sockaddr_in)); PRINTF (STD_HANDLE, _("Trying %s port %d...\r\n"), hbuf, ntohs (s_in.sin_port)); break; } case AF_INET6: { struct sockaddr_in6 s_in6; memcpy (&s_in6, res->ai_addr, sizeof (struct sockaddr_in)); PRINTF (STD_HANDLE, _("Trying %s port %d...\r\n"), hbuf, ntohs (s_in6.sin6_port)); break; } default: PRINTF (STD_HANDLE, _("Trying %s...\r\n"), hbuf); break; } /* Create the socket. */ sock = socket (res->ai_family, res->ai_socktype, res->ai_protocol); if (sock < 0) continue; if (connect (sock, res->ai_addr, res->ai_addrlen) < 0) { if (getnameinfo (res->ai_addr, res->ai_addrlen, hbuf, sizeof (hbuf), NULL, 0, niflags) != 0) strcpy (hbuf, "(invalid)"); PRINTF (ERR_HANDLE, _("connect to address %s: %s\n"), hbuf, strerror (errno)); close (sock); sock = -1; continue; } PRINTF (STD_HANDLE, "\n"); break; } freeaddrinfo (res0); return sock;}#ifdef USE_GNUTLS#include <gnutls/x509.h>#ifndef HAVE_GNUTLS_PK_ALGORITHM_GET_NAMEstatic const char *gnutls_pk_algorithm_get_name (gnutls_pk_algorithm algorithm){ if (algorithm == GNUTLS_PK_RSA) return "RSA"; else if (algorithm == GNUTLS_PK_DSA) return "DSA"; else return "UNKNOWN";}#endif/* This function will print information about this session's peer * certificate. */static voidprint_x509_certificate_info (HANDLE gnutls_session session){ char dn[128]; size_t size; unsigned int algo, bits; time_t expiration_time, activation_time; const gnutls_datum *cert_list; unsigned int cert_list_size = 0; gnutls_x509_crt cert; /* This function only works for X.509 certificates. */ if (gnutls_certificate_type_get (session) != GNUTLS_CRT_X509) return; cert_list = gnutls_certificate_get_peers (session, &cert_list_size); if (cert_list_size <= 0) return; PRINTF (STD_HANDLE, _("Server certificate info:\n")); /* we only print information about the first certificate. */ gnutls_x509_crt_init (&cert); gnutls_x509_crt_import (cert, &cert_list[0], GNUTLS_X509_FMT_DER); expiration_time = gnutls_x509_crt_get_expiration_time (cert); activation_time = gnutls_x509_crt_get_activation_time (cert); PRINTF (STD_HANDLE, _(" Certificate is valid since: %s"), ctime (&activation_time)); PRINTF (STD_HANDLE, _(" Certificate expires: %s"), ctime (&expiration_time)); /* Extract some of the public key algorithm's parameters */ algo = gnutls_x509_crt_get_pk_algorithm (cert, &bits); PRINTF (STD_HANDLE, _(" Certificate public key: %s"), gnutls_pk_algorithm_get_name (algo)); /* Print the version of the X.509 * certificate. */ PRINTF (STD_HANDLE, _(" Certificate version: #%d\n"), gnutls_x509_crt_get_version (cert)); size = sizeof (dn); gnutls_x509_crt_get_dn (cert, dn, &size); PRINTF (STD_HANDLE, _(" DN: %s\n"), dn); size = sizeof (dn); gnutls_x509_crt_get_issuer_dn (cert, dn, &size); PRINTF (STD_HANDLE, _(" Issuer's DN: %s\n"), dn); PRINTF (STD_HANDLE, "\n"); gnutls_x509_crt_deinit (cert);}static intstart_ssl (HANDLE long sock, int reqcert, int verbose, gnutls_session session, gnutls_certificate_credentials *cred){ gnutls_certificate_credentials xcred; DIR *dir = opendir ("/etc/ssl/certs"); struct dirent *entry; int ret; /* Allow connections to servers that have OpenPGP keys as well. */ const int cert_type_priority[3] = { GNUTLS_CRT_X509, GNUTLS_CRT_OPENPGP, 0 }; /* X509 stuff */ gnutls_certificate_allocate_credentials (&xcred); /* sets the trusted cas files from /etc/ssl/certs and try to add /etc/rpasswdd.pem (default from server). */ if (dir != NULL) { while ((entry = readdir (dir)) != NULL) { /* Skip "." and ".." directory entries. */ if (strcmp (entry->d_name, ".") == 0 || strcmp (entry->d_name, "..") == 0) continue; else { char srcfile[strlen ("/etc/ssl/certs") + strlen (entry->d_name) + 2]; struct stat st; char *cp; /* create source and destination filename with full path. */ cp = stpcpy (srcfile, "/etc/ssl/certs"); *cp++ = '/'; strcpy (cp, entry->d_name); if (lstat (srcfile, &st) != 0) continue; if (!S_ISLNK(st.st_mode) && !S_ISDIR(st.st_mode) && !S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) { /* XXX error handling! */ gnutls_certificate_set_x509_trust_file (xcred, srcfile, GNUTLS_X509_FMT_PEM); } } } closedir (dir); } gnutls_certificate_set_x509_trust_file (xcred, "/etc/rpasswdd.pem", GNUTLS_X509_FMT_PEM); *cred = xcred; /* Use default priorities */ gnutls_set_default_priority (session); gnutls_certificate_type_set_priority (session, cert_type_priority); /* put the x509 credentials to the current session. */ gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, xcred); gnutls_transport_set_ptr (session, (gnutls_transport_ptr) sock); /* Perform the TLS handshake. */ ret = gnutls_handshake (session); if (ret < 0) { PRINTF (ERR_HANDLE, _("Handshake failed: %s\n"), gnutls_strerror (ret)); return E_SSL_FAILURE; } if (reqcert > 0 || verbose) { gnutls_kx_algorithm kx; unsigned int verify_result = 0; time_t now; /* print the key exchange's algorithm name. */ kx = gnutls_kx_get (session);#ifdef HAVE_GNUTLS_CERTIFICATE_VERIFY_PEERS2 ret = gnutls_certificate_verify_peers2 (session, &verify_result);#else ret = gnutls_certificate_verify_peers (session); if (ret > 0) verify_result = ret;#endif if (ret < 0) { PRINTF (ERR_HANDLE, _("TLS certificate error: %s\n"), gnutls_strerror (verify_result)); return E_SSL_FAILURE; } /* Following two steps are optional and not required for data exchange to be successful except the client couldn't verfiy the server certificate. */ if (verify_result || verbose) { /* Get the cipher. */ PRINTF (STD_HANDLE, _("%s connection using %s-%s (%s)\n\n"), gnutls_protocol_get_name (gnutls_protocol_get_version (session)), gnutls_cipher_get_name (gnutls_cipher_get (session)), gnutls_mac_get_name (gnutls_mac_get (session)), gnutls_certificate_type_get_name (gnutls_certificate_type_get (session)));#if defined(IAM_PAM_MODULE) print_x509_certificate_info (pamh, session);#else print_x509_certificate_info (session);#endif if (verify_result & GNUTLS_CERT_SIGNER_NOT_FOUND) { PRINTF (ERR_HANDLE, _ ("TLS authentication error: server certificate issuer is unknown.\n")); if (reqcert >= 2) return E_SSL_FAILURE; } else if (verify_result & GNUTLS_CERT_INVALID) { PRINTF (ERR_HANDLE, _ ("TLS authentication error: server certificate is NOT trusted.\n")); if (reqcert >= 2) return E_SSL_FAILURE; } } now = time (NULL); if (gnutls_certificate_activation_time_peers (session) > now) { PRINTF (ERR_HANDLE, _("TLS authentication error: server certificate not yet activated.\n")); if (reqcert >= 2) return E_SSL_FAILURE; } if (gnutls_certificate_expiration_time_peers (session) < now) { PRINTF (ERR_HANDLE, _("TLS authentication error: server certificate expired.\n")); if (reqcert >= 2) return E_SSL_FAILURE; } } return 0;}#elsestatic intstart_ssl (HANDLE int sock, int reqcert, int verbose, SSL_CTX ** ctx, SSL ** ssl){ X509 *server_cert; char *str; SSL_METHOD *meth; long verify_result; int err; SSLeay_add_ssl_algorithms (); meth = SSLv23_client_method (); SSL_load_error_strings (); *ctx = SSL_CTX_new (meth); if (*ctx == NULL) { PRINTF (ERR_HANDLE, ERR_error_string (ERR_get_error (), NULL)); return E_SSL_FAILURE; }#if 0 /* This is only necessary if we configure a unusual path. XXX Make this a program option. */ if (!SSL_CTX_load_verify_locations (*ctx, NULL, "/etc/ssl/certs")) { PRINTF (ERR_HANDLE, _("error loading default verify locations: %s\n"), ERR_error_string (ERR_get_error (), NULL)); if (reqcert > 1) return E_SSL_FAILURE; }#endif if (!SSL_CTX_set_default_verify_paths (*ctx)) { PRINTF (ERR_HANDLE, _("error setting default verify path: %s\n"), ERR_error_string (ERR_get_error (), NULL)); if (reqcert > 1) return E_SSL_FAILURE; } /* Now we have TCP conncetion. Start SSL negotiation. */ *ssl = SSL_new (*ctx); if (*ssl == NULL) { PRINTF (ERR_HANDLE, ERR_error_string (ERR_get_error (), NULL)); return E_SSL_FAILURE; } SSL_set_fd (*ssl, sock); err = SSL_connect (*ssl); if (err < 1) { PRINTF (ERR_HANDLE, "SSL_connect: %s", ERR_error_string (err, NULL)); close (sock); return E_SSL_FAILURE; } if (reqcert > 0 || verbose) { /* Get server's certificate (note: beware of dynamic allocation). */ server_cert = SSL_get_peer_certificate (*ssl); /* Verify severs certificate. */ verify_result = SSL_get_verify_result (*ssl); /* Following two steps are optional and not required for data exchange to be successful except the client couldn't verfiy the server certificate. */ if (verify_result || verbose) { /* Get the cipher. */ PRINTF (STD_HANDLE, _("SSL connection using %s\n\n"), SSL_get_cipher (*ssl)); if (server_cert == NULL) { PRINTF (ERR_HANDLE, _("Server does not have a certificate?\n")); if (reqcert >= 3) return E_SSL_FAILURE; } else { PRINTF (STD_HANDLE, _("Server certificate info:\n")); str = X509_NAME_oneline (X509_get_subject_name (server_cert), 0, 0); if (str) { PRINTF (STD_HANDLE, _(" DN: %s\n"), str); free (str); } str = X509_NAME_oneline (X509_get_issuer_name (server_cert), 0, 0); if (str) { PRINTF (STD_HANDLE, _(" Issuer's DN: %s\n"), str); free (str); } /* We could do all sorts of certificate verification stuff here before deallocating the certificate. */ PRINTF (STD_HANDLE, "\n"); } } if ((verify_result = SSL_get_verify_result (*ssl)) != X509_V_OK) { PRINTF (ERR_HANDLE, "Server certificate is not ok: %s!\n", X509_verify_cert_error_string (verify_result)); if (reqcert >= 2) return E_SSL_FAILURE; } X509_free (server_cert); } return 0;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -