📄 rpasswd-client.c
字号:
/* Copyright (C) 2002, 2003, 2004, 2005 Thorsten Kukuk Author: Thorsten Kukuk <kukuk@suse.de> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include <ctype.h>#include <netdb.h>#include <sys/socket.h>#include <sys/types.h>#ifdef HAVE_DIRENT_H#include <dirent.h>#endif#ifdef USE_SLP#include <slp.h>#endif#ifdef USE_GNUTLSstatic intstart_request (HANDLE gnutls_session ssl, char *username, int admin_mode){ request_header req; char *locale = getenv ("LANG"); int ret; if (admin_mode) req.request = START_ADMIN; else req.request = START; req.version = RPASSWD_VERSION; req.data_len = strlen (username) + 1; if (locale) req.locale_len = strlen (locale) + 1; else req.locale_len = 0; if ((ret = gnutls_record_send (ssl, &req, sizeof (request_header))) <= 0) { if (ret == 0) PRINTF (ERR_HANDLE, _("error while sending start request: %s\n"), _("Peer has closed the TLS connection")); else PRINTF (ERR_HANDLE, _("error while sending start request: %s\n"), gnutls_strerror (ret)); return -1; } if (locale) { if ((ret = gnutls_record_send (ssl, locale, req.locale_len)) <= 0) { if (ret == 0) PRINTF (ERR_HANDLE, _("error while sending locale data: %s\n"), _("Peer has closed the TLS connection")); else PRINTF (ERR_HANDLE, _("error while sending locale data: %s\n"), gnutls_strerror (ret)); return -1; } } if ((ret = gnutls_record_send (ssl, username, req.data_len)) <= 0) { if (ret == 0) PRINTF (ERR_HANDLE, _("error while sending username: %s\n"), _("Peer has closed the TLS connection")); else PRINTF (ERR_HANDLE, _("error while sending username: %s\n"), gnutls_strerror (ret)); return -1; } return 0;}static intsend_string (HANDLE gnutls_session ssl, u_int32_t retval, const char *str){ int ret; conv_header resp; resp.retval = retval; if (str == NULL) resp.data_len = 0; else resp.data_len = strlen (str) + 1; if ((ret = gnutls_record_send (ssl, &resp, sizeof (resp))) <= 0) { if (ret == 0) PRINTF (ERR_HANDLE, _("error while sending string: %s\n"), _("Peer has closed the TLS connection")); else PRINTF (ERR_HANDLE, _("error while sending string: %s\n"), gnutls_strerror (ret)); return E_FAILURE; } if (str) { if ((ret = gnutls_record_send (ssl, str, resp.data_len)) <= 0) { if (ret == 0) PRINTF (ERR_HANDLE, _("error while sending string: %s\n"), _("Peer has closed the TLS connection")); else PRINTF (ERR_HANDLE, _("error while sending string: %s\n"), gnutls_strerror (ret)); return E_FAILURE; } } return E_SUCCESS;}#elsestatic intstart_request (SSL *ssl, char *username, int admin_mode){ request_header req; char *locale = getenv ("LANG"); if (admin_mode) req.request = START_ADMIN; else req.request = START; req.version = RPASSWD_VERSION; req.data_len = strlen (username) + 1; if (locale) req.locale_len = strlen (locale) + 1; else req.locale_len = 0; if (SSL_write (ssl, &req, sizeof (request_header)) != sizeof (request_header)) return -1; if (locale) if (SSL_write (ssl, locale, req.locale_len) != req.locale_len) return -1; if (SSL_write (ssl, username, req.data_len) != req.data_len) return -1; return 0;}static intsend_string (SSL *ssl, u_int32_t ret, const char *str){ conv_header resp; resp.retval = ret; if (str == NULL) resp.data_len = 0; else resp.data_len = strlen (str) + 1; if (TEMP_FAILURE_RETRY (SSL_write (ssl, &resp, sizeof (resp))) != sizeof (resp)) return E_FAILURE; if (str) if (TEMP_FAILURE_RETRY (SSL_write (ssl, str, resp.data_len)) != resp.data_len) return E_FAILURE; return E_SUCCESS;}#endif#ifdef USE_SLP/* Ask SLP server for rpasswd service. */struct slpcb{ char *srvurl; SLPError err; struct slpcb *next; char *hostp; char *portp; char *descr;};static voidfree_slpcb (struct slpcb *cb){ struct slpcb *tcb; free (cb->srvurl); cb = cb->next; while (cb) { tcb = cb; cb = cb->next; free (tcb->srvurl); if (tcb->descr) free (tcb->descr); free (tcb); }}static voidparse_slpcb (struct slpcb *cb){#define NEEDLE "://" size_t needle_length = strlen (NEEDLE); cb->hostp = strstr (cb->srvurl, NEEDLE); if (cb->hostp == NULL || strlen (cb->hostp) < needle_length + 1) return; cb->hostp += needle_length; cb->portp = strchr (cb->hostp, ':'); if (cb->portp) { char *cp; cb->portp[0] = '\0'; cb->portp += 1; cp = cb->portp; while (isdigit (*cp)) cp++; if (*cp != '\0') *cp = '\0'; }}static SLPBooleanMySLPSrvURLCallback (SLPHandle hslp __attribute__ ((unused)), const char *srvurl, unsigned short lifetime __attribute__ ((unused)), SLPError errcode, void *cookie){ struct slpcb *cb = (struct slpcb *) cookie; if (errcode == SLP_OK) { if (cb->srvurl != NULL) { struct slpcb *cbt = malloc (sizeof (struct slpcb)); if (cbt == NULL) return SLP_FALSE; cbt->srvurl = cb->srvurl; cbt->hostp = cb->hostp; cbt->portp = cb->portp; cbt->err = cb->err; cbt->next = cb->next; cb->next = cbt; cb->descr = NULL; } cb->srvurl = strdup (srvurl); parse_slpcb (cb); cb->err = SLP_OK; return SLP_TRUE; } else if (errcode != SLP_LAST_CALL) cb->err = errcode; return SLP_FALSE; /* We don't wan't to be called again. */}static SLPBooleanMySLPAttrCallback (SLPHandle hslp __attribute__ ((unused)), const char *attrlist, SLPError errcode, void *cookie){ char **descr = (char **) cookie; if (errcode == SLP_OK) { char *cp = strstr (attrlist, "(description="); if (cp == NULL) return SLP_FALSE; *descr = strdup (cp + 13); cp = strchr (*descr, ')'); if (cp != NULL) *cp = '\0'; } return SLP_FALSE;}static intquery_slp (HANDLE char **hostp, char **portp, char **descrp){ struct slpcb *cb, callbackres = { NULL, 0, NULL, NULL, NULL, NULL }; SLPError err; SLPHandle hslp; *hostp = NULL; *portp = NULL; *descrp = NULL; PRINTF (STD_HANDLE, _("Searching a server...\n")); err = SLPOpen ("en", SLP_FALSE, &hslp); if (err != SLP_OK) { PRINTF (ERR_HANDLE, _("Error opening SLP handle: %i.\n"), err); return err; } err = SLPFindSrvs (hslp, "rpasswdd", 0, 0, MySLPSrvURLCallback, &callbackres); /* err may contain an error code that occurred as the slp library _prepared_ to make the call. */ if (err != SLP_OK || callbackres.err != SLP_OK) { PRINTF (STD_HANDLE, _("No service found with SLP.\n")); return -1; } cb = &callbackres; while (cb != NULL) { char *buf; asprintf (&buf, "service:rpasswdd://%s:%s/", cb->hostp, cb->portp ? : "774"); err = SLPFindAttrs (hslp, buf, "", "", /* use configured scopes */ MySLPAttrCallback, &(cb->descr)); free (buf); if (err != SLP_OK) { PRINTF (STD_HANDLE, _("Error while searching for SLP description.\n")); return -1; } cb = cb->next; } /* Now that we're done using slp, close the slp handle */ SLPClose (hslp); cb = &callbackres;#if defined(SELECT_SRVURL) if (cb->next != NULL) /* Only if we have more than one entry. */ { /* Ask the user which one to use. */ struct slpcb *tcb = &callbackres; int choice = 0; /* index of the user's choice. */ char response[20]; /* string to hold the user's response. */ int i = 0; printf (_("\nPlease select a server:\n")); while (tcb != NULL) { ++i; printf ("[%2d] %s", i, tcb->hostp); if (tcb->portp) printf (_(" (port %s)"), tcb->portp); if (tcb->descr) printf (" - %s", tcb->descr); fputs ("\n", stdout); tcb = tcb->next; } while ((choice < 1) || (choice > i)) { char *cp; printf (_("Enter number of choice [1-%d]: "), i); fflush (stdin); cp = fgets (response, sizeof (response), stdin); fflush (stdin); if (cp == NULL) choice = 0; else choice = strtol (response, NULL, 10); } printf ("\n"); for (i = 0; i < (choice - 1); i++) cb = cb->next; }#endif if (cb->hostp != NULL) { *hostp = strdup (cb->hostp); if (cb->portp) *portp = strdup (cb->portp); if (cb->descr) *descrp = strdup (cb->descr); free_slpcb (&callbackres); return 0; } free_slpcb (&callbackres); return -1;}#endifstatic intparse_reqcert (const char *str){ if (strcmp (str, "never") == 0) return 0; else if (strcmp (str, "allow") == 0) return 1; else if (strcmp (str, "try") == 0) return 2; else if (strcmp (str, "demand") == 0 || strcmp (str, "hard") == 0) return 3; /* If we cannot parse it, use saftest mode. */ return 3;}/* Load the config file (/etc/rpasswd.conf) */static intload_config (const char *configfile, char **hostp, char **portp, int *reqcertp#ifdef DO_VERBOSE_OUTPUT , int verbose, int check_syntax#endif ){ FILE *fp; char *buf = NULL; size_t buflen = 0; int have_entries = 0; /* # of entries we found in config file */#ifdef DO_VERBOSE_OUTPUT int bad_entries = 0;#endif fp = fopen (configfile, "r"); if (NULL == fp) return 1;#ifdef DO_VERBOSE_OUTPUT if (verbose > 1) PRINTF (STD_HANDLE, _("parsing config file"));#endif while (!feof (fp)) { char *tmp, *cp;#if defined(HAVE_GETLINE) ssize_t n = getline (&buf, &buflen, fp);#elif defined (HAVE_GETDELIM) ssize_t n = getdelim (&buf, &buflen, '\n', fp);#else ssize_t n; if (buf == NULL) { buflen = 8096; buf = malloc (buflen); } buf[0] = '\0'; fgets (buf, buflen - 1, fp); if (buf != NULL) n = strlen (buf); else n = 0;#endif /* HAVE_GETLINE / HAVE_GETDELIM */ cp = buf; if (n < 1) break; tmp = strchr (cp, '#'); /* remove comments */ if (tmp) *tmp = '\0'; while (isspace ((int) *cp)) /* remove spaces and tabs */ ++cp; if (*cp == '\0') /* ignore empty lines */ continue; if (cp[strlen (cp) - 1] == '\n') cp[strlen (cp) - 1] = '\0';#ifdef DO_VERBOSE_OUTPUT if (verbose > 1) PRINTF (STD_HANDLE, "%s %s", _("Trying entry:"), cp); if (check_syntax) PRINTF (STD_HANDLE, "%s %s\n", _("Trying entry:"), cp);#endif if (strncmp (cp, "server", 6) == 0 && isspace ((int) cp[6])) { if (hostp != NULL) { char tmpserver[MAXHOSTNAMELEN + 1]; if (sscanf (cp, "server %s", tmpserver) == 1) *hostp = strdup (tmpserver); } continue; } else if (strncmp (cp, "port", 4) == 0 && isspace ((int) cp[4])) { if (portp != NULL) { char tmpport[30]; if (sscanf (cp, "port %s", tmpport) == 1) *portp = strdup (tmpport); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -