📄 rpasswdd.c
字号:
dbg_log ("SSL connection using %s", SSL_get_cipher (ssl));#if 0 /* Get client's certificate (note: beware of dynamic allocation) - opt */ client_cert = SSL_get_peer_certificate (ssl); if (client_cert != NULL) { printf ("Client certificate:\n"); str = X509_NAME_oneline (X509_get_subject_name (client_cert), 0, 0); CHK_NULL(str); printf ("\t subject: %s\n", str); free (str); str = X509_NAME_oneline (X509_get_issuer_name (client_cert), 0, 0); CHK_NULL(str); printf ("\t issuer: %s\n", str); free (str); /* We could do all sorts of certificate verification stuff here before deallocating the certificate. */ X509_free (client_cert); } else printf ("Client does not have certificate.\n");#endif /* Now read the request. */ errno = 0; if (TEMP_FAILURE_RETRY (SSL_read (ssl, &req, sizeof (req))) != sizeof (req)) { if (debug_level > 0) { if (errno == 0) dbg_log (_("error while reading request: %s"), _("wrong data received")); else dbg_log (_("error while reading request: %s"), strerror_r (errno, buf, sizeof (buf))); } close (fd); continue; }#endif /* It should not be possible to crash the rpasswdd with a silly request (i.e., a terribly large key). We limit the size to 1kb for locale and username. */ if (req.locale_len < 0 || req.locale_len > 1024) { if (debug_level > 0) dbg_log (_("locale length in request too long: %d"), req.locale_len); continue; } else if (req.locale_len != 0) { /* Get the locale. */ char localebuf[req.locale_len + 1]; if (safe_read (ssl, localebuf, req.locale_len, 1) != req.locale_len) { if (debug_level > 0) { char err_buf[256]; if (errno == 0) dbg_log (_("error while reading request locale: %s"), _("wrong data received")); else dbg_log (_("error while reading request locale: %s"), strerror_r (errno, err_buf, sizeof (err_buf))); } continue; } /* Don't assume the string is NUL-terminated */ localebuf[req.locale_len] = '\0'; if ((locale = strdup (localebuf)) == NULL) { dbg_log ("running out of memory!"); continue; } } else locale = NULL; if (req.data_len < 0 || req.data_len > 1024) { if (debug_level > 0) dbg_log (_("data length in request too long: %d"), req.data_len); if (locale) free (locale); continue; } else if (req.data_len != 0) { /* Get the data. */ char databuf[req.data_len + 1]; if (safe_read (ssl, databuf, req.data_len, 1) != req.data_len) { if (debug_level > 0) { char err_buf[256]; if (errno == 0) dbg_log (_("error while reading request username: %s"), _("wrong data received")); else dbg_log (_("error while reading request username: %s"), strerror_r (errno, err_buf, sizeof (err_buf))); } if (locale) free (locale); continue; } /* Don't assume the string is NUL-terminated */ databuf[req.data_len] = '\0'; if ((username = strdup (databuf)) == NULL) { dbg_log ("running out of memory!"); if (locale) free (locale); continue; } } else { dbg_log (_("No username supplied")); if (locale) free (locale); continue; } /* To avoid a DoS attack, fork at first and let the child handle the request. */ switch (fork ()) { case 0: /* Child: get all the data and process it. */ { int ret = handle_request (ssl, &req, locale, username, program); close (fd); exit (ret); } break; case -1: { char *cp; if (asprintf (&cp, "fork: %s", strerror (errno)) > 0) { dbg_log (cp); send_string (ssl, ERROR_MSG, cp); free (cp);#ifdef USE_GNUTLS /* do not wait for the peer to close the connection. */ gnutls_bye (ssl, GNUTLS_SHUT_WR); close (fd); gnutls_deinit (ssl);#else close (fd); SSL_free (ssl);#endif if (locale) free (locale); free (username); } } break; default: /* Parent: we are done. */#ifdef USE_GNUTLS /* do not wait for the peer to close the connection. */ gnutls_bye (ssl, GNUTLS_SHUT_WR); close (fd); gnutls_deinit (ssl);#else close (fd); SSL_free (ssl);#endif if (locale) free (locale); free (username); } } } }}/* Cleanup. */static voidtermination_handler (int sig __attribute__ ((unused))){ close_sockets ();#ifdef USE_SLP /* Remove from local SLP server. */ if (use_slp) deregister_slp ();#endif /* Clean up pid file. */ unlink (_PATH_RPASSWDDPID); exit (EXIT_SUCCESS);}/* Make sure there are no zombies left. */static voidsig_child (int sig __attribute__ ((unused))){ int st; /* Clear all childs */ while (waitpid(-1, &st, WNOHANG) > 0) ;}static voidinit_limits (void){ struct rlimit rlim; /* Don't create a core file. */ rlim.rlim_cur = rlim.rlim_max = 0; setrlimit (RLIMIT_CORE, &rlim); /* Set all limits to unlimited to avoid to run in any problems later. */ rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; setrlimit (RLIMIT_AS, &rlim); setrlimit (RLIMIT_CPU, &rlim); setrlimit (RLIMIT_DATA, &rlim); setrlimit (RLIMIT_FSIZE, &rlim); setrlimit (RLIMIT_NOFILE, &rlim); setrlimit (RLIMIT_RSS, &rlim); setrlimit (RLIMIT_STACK, &rlim);}intmain (int argc, char **argv){ /* ipv4 and/or ipv6 binding. */ int ipv4 = 0; int ipv6 = 0; int go_background = 1; const char *program = "rpasswdd"; char *certificate = "/etc/rpasswdd.pem"; char *privatekey = "/etc/rpasswdd.pem"; int port = -1;#ifdef USE_SLP int slp_timeout = 3600; char *slp_descr = NULL;#endif#ifndef USE_GNUTLS SSL_METHOD *meth;#endif /* Set locale via LC_ALL. */ setlocale (LC_ALL, "C"); /* Set the text message domain. */ textdomain (PACKAGE); /* Parse program arguments */ while (1) { int c; int option_index = 0; static struct option long_options[] = { {"port", required_argument, NULL, 'p'}, {"debug", no_argument, NULL, 'd'}, {"ipv4", no_argument, NULL, '4'}, {"ipv6", no_argument, NULL, '6'}, {"certificate", required_argument, NULL, 'c'}, {"privatekey", required_argument, NULL, 'k'}, {"slp-descr", required_argument, NULL, '\250'}, {"slp-timeout", required_argument, NULL, '\251'}, {"slp", no_argument, NULL, '\252'}, {"version", no_argument, NULL, '\255'}, {"usage", no_argument, NULL, '\254'}, {"help", no_argument, NULL, '\253'}, {NULL, 0, NULL, '\0'} }; c = getopt_long (argc, argv, "46c:dk:p:", long_options, &option_index); if (c == EOF) break; switch (c) { case '4': ipv4 = 1; break; case '6': ipv6 = 1; break; case 'c': certificate = optarg; break; case 'k': privatekey = optarg; break; case 'd': ++debug_level; go_background = 0; break; case 'p': port = htons (atol (optarg)); break;#ifdef USE_SLP case '\250': slp_descr = optarg; break; case '\251': slp_timeout = atol (optarg); break; case '\252': use_slp = 1; break;#endif case '\253': print_help (program); return 0; case '\255': print_version (program); return 0; case '\254': print_usage (stdout, program); return E_USAGE; default: print_error (program); return E_BAD_ARG; } } argc -= optind; argv += optind; if (argc != 0) { fprintf (stderr, _("%s: Too many arguments.\n"), program); print_error (program); return E_USAGE; } if (ipv4 == 0 && ipv6 == 0) ipv4 = ipv6 = 1; /* Check if we are already running. */ if (check_pid (_PATH_RPASSWDDPID)) error (EXIT_FAILURE, 0, _("already running"));#ifdef USE_GNUTLS /* this must be called once in the program. */ gnutls_global_init ();#else /* Initialize SSL data. We need to do this before we go in background, else we cannot read the PEM phass phrase. */ SSL_load_error_strings (); SSLeay_add_ssl_algorithms (); meth = SSLv23_server_method (); ctx = SSL_CTX_new (meth); if (!ctx) { dbg_log (ERR_error_string (ERR_get_error (), NULL)); return E_SSL_FAILURE; } if (SSL_CTX_use_certificate_file (ctx, certificate, SSL_FILETYPE_PEM) <= 0) { dbg_log ("Loading certificate (%s): %s", certificate, ERR_error_string (ERR_get_error (), NULL)); return E_SSL_FAILURE; } if (SSL_CTX_use_PrivateKey_file (ctx, privatekey, SSL_FILETYPE_PEM) <= 0) { dbg_log ("Loading privatekey (%s): %s", privatekey, ERR_error_string (ERR_get_error (), NULL)); return E_SSL_FAILURE; } if (!SSL_CTX_check_private_key (ctx)) { dbg_log (ERR_error_string (ERR_get_error (), NULL)); return E_SSL_FAILURE; }#endif /* Behave like a daemon. */ if (go_background) { int i; if (fork ()) exit (0); for (i = 0; i < getdtablesize (); i++) close (i); if (fork ()) exit (0); setsid (); if (chdir ("/") < 0) dbg_log ("chdir(\"/\") failed: %s", strerror (errno)); openlog (program, LOG_CONS | LOG_ODELAY, LOG_DAEMON); if (write_pid (_PATH_RPASSWDDPID) < 0) dbg_log ("%s: %s", _PATH_RPASSWDDPID, strerror (errno)); /* Ignore job control signals. */ signal (SIGTTOU, SIG_IGN); signal (SIGTTIN, SIG_IGN); signal (SIGTSTP, SIG_IGN); } /* Install sig child handler to get ride of zombies. */ signal (SIGCHLD, sig_child); /* Ignore "File size limit exceeded" signals. */ signal (SIGXFSZ, SIG_IGN); /* We don't support SIGHUP yet. */ signal (SIGHUP, SIG_IGN); signal (SIGINT, termination_handler); signal (SIGPIPE, SIG_IGN); signal (SIGQUIT, termination_handler); signal (SIGTERM, termination_handler); /* Set the limits to a usefull value. */ init_limits (); /* If port was not specified on commandline, try at first a lookup in the service database, if this fails, use the compiled in default port. */ if (port == -1) { struct servent *serv = getservbyname ("rpasswd", "tcp"); if (serv) port = serv->s_port; else port = htons (RPASSWDD_PORT); } /* Init databases. */ server_init (port, ipv4, ipv6);#ifdef USE_SLP /* Register at local SLP server. */ if (use_slp) register_slp (ntohs(port), slp_timeout, slp_descr);#endif /* Handle incoming requests. */#ifdef USE_GNUTLS server_run (certificate, privatekey, program);#else server_run (program);#endif return E_SUCCESS;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -