Beispiel #1
0
int					/* O - 0 on success, -1 on error */
cupsDoAuthentication(
    http_t     *http,			/* I - Connection to server or @code CUPS_HTTP_DEFAULT@ */
    const char *method,			/* I - Request method ("GET", "POST", "PUT") */
    const char *resource)		/* I - Resource path */
{
  const char	*password,		/* Password string */
		*www_auth;		/* WWW-Authenticate header */
  char		prompt[1024],		/* Prompt for user */
		realm[HTTP_MAX_VALUE],	/* realm="xyz" string */
		nonce[HTTP_MAX_VALUE];	/* nonce="xyz" string */
  int		localauth;		/* Local authentication result */
  _cups_globals_t *cg;			/* Global data */


  DEBUG_printf(("cupsDoAuthentication(http=%p, method=\"%s\", resource=\"%s\")",
                http, method, resource));

  if (!http)
    http = _cupsConnect();

  if (!http || !method || !resource)
    return (-1);

  DEBUG_printf(("2cupsDoAuthentication: digest_tries=%d, userpass=\"%s\"",
                http->digest_tries, http->userpass));
  DEBUG_printf(("2cupsDoAuthentication: WWW-Authenticate=\"%s\"",
                httpGetField(http, HTTP_FIELD_WWW_AUTHENTICATE)));

 /*
  * Clear the current authentication string...
  */

  httpSetAuthString(http, NULL, NULL);

 /*
  * See if we can do local authentication...
  */

  if (http->digest_tries < 3)
  {
    if ((localauth = cups_local_auth(http)) == 0)
    {
      DEBUG_printf(("2cupsDoAuthentication: authstring=\"%s\"",
                    http->authstring));

      if (http->status == HTTP_STATUS_UNAUTHORIZED)
	http->digest_tries ++;

      return (0);
    }
    else if (localauth == -1)
    {
      http->status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED;
      return (-1);			/* Error or canceled */
    }
  }

 /*
  * Nope, see if we should retry the current username:password...
  */

  www_auth = http->fields[HTTP_FIELD_WWW_AUTHENTICATE];

  if ((http->digest_tries > 1 || !http->userpass[0]) &&
      (!_cups_strncasecmp(www_auth, "Basic", 5) ||
       !_cups_strncasecmp(www_auth, "Digest", 6)))
  {
   /*
    * Nope - get a new password from the user...
    */

    char default_username[HTTP_MAX_VALUE];
					/* Default username */

    cg = _cupsGlobals();

    if (!cg->lang_default)
      cg->lang_default = cupsLangDefault();

    if (httpGetSubField(http, HTTP_FIELD_WWW_AUTHENTICATE, "username",
                        default_username))
      cupsSetUser(default_username);

    snprintf(prompt, sizeof(prompt),
             _cupsLangString(cg->lang_default, _("Password for %s on %s? ")),
	     cupsUser(),
	     http->hostname[0] == '/' ? "localhost" : http->hostname);

    http->digest_tries  = _cups_strncasecmp(www_auth, "Digest", 6) != 0;
    http->userpass[0]   = '\0';

    if ((password = cupsGetPassword2(prompt, http, method, resource)) == NULL)
    {
      http->status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED;
      return (-1);
    }

    snprintf(http->userpass, sizeof(http->userpass), "%s:%s", cupsUser(),
             password);
  }
  else if (http->status == HTTP_STATUS_UNAUTHORIZED)
    http->digest_tries ++;

  if (http->status == HTTP_STATUS_UNAUTHORIZED && http->digest_tries >= 3)
  {
    DEBUG_printf(("1cupsDoAuthentication: Too many authentication tries (%d)",
		  http->digest_tries));

    http->status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED;
    return (-1);
  }

 /*
  * Got a password; encode it for the server...
  */

#ifdef HAVE_GSSAPI
  if (!_cups_strncasecmp(www_auth, "Negotiate", 9))
  {
   /*
    * Kerberos authentication...
    */

    if (_cupsSetNegotiateAuthString(http, method, resource))
    {
      http->status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED;
      return (-1);
    }
  }
  else
#endif /* HAVE_GSSAPI */
  if (!_cups_strncasecmp(www_auth, "Basic", 5))
  {
   /*
    * Basic authentication...
    */

    char	encode[256];		/* Base64 buffer */


    httpEncode64_2(encode, sizeof(encode), http->userpass,
                   (int)strlen(http->userpass));
    httpSetAuthString(http, "Basic", encode);
  }
  else if (!_cups_strncasecmp(www_auth, "Digest", 6))
  {
   /*
    * Digest authentication...
    */

    char	encode[33],		/* MD5 buffer */
		digest[1024];		/* Digest auth data */

    httpGetSubField(http, HTTP_FIELD_WWW_AUTHENTICATE, "realm", realm);
    httpGetSubField(http, HTTP_FIELD_WWW_AUTHENTICATE, "nonce", nonce);

    httpMD5(cupsUser(), realm, strchr(http->userpass, ':') + 1, encode);
    httpMD5Final(nonce, method, resource, encode);
    snprintf(digest, sizeof(digest),
	     "username=\"%s\", realm=\"%s\", nonce=\"%s\", uri=\"%s\", "
	     "response=\"%s\"", cupsUser(), realm, nonce, resource, encode);
    httpSetAuthString(http, "Digest", digest);
  }
  else
  {
    DEBUG_printf(("1cupsDoAuthentication: Unknown auth type: \"%s\"",
                  www_auth));
    http->status = HTTP_STATUS_CUPS_AUTHORIZATION_CANCELED;
    return (-1);
  }

  DEBUG_printf(("1cupsDoAuthentication: authstring=\"%s\"", http->authstring));

  return (0);
}
Beispiel #2
0
int					/* O - Exit status */
main(int  argc,				/* I - Number of command-line arguments */
     char *argv[])			/* I - Command-line arguments */
{
  int		i;			/* Looping var */
  char		*opt;			/* Option pointer */
  const char	*username;		/* Pointer to username */
  const char	*groupname;		/* Pointer to group name */
  int		op;			/* Operation (add, change, delete) */
  const char	*passwd;		/* Password string */
  FILE		*infile,		/* Input file */
		*outfile;		/* Output file */
  char		line[256],		/* Line from file */
		userline[17],		/* User from line */
		groupline[17],		/* Group from line */
		md5line[33],		/* MD5-sum from line */
		md5new[33];		/* New MD5 sum */
  char		passwdmd5[1024],	/* passwd.md5 file */
		passwdold[1024],	/* passwd.old file */
		passwdnew[1024];	/* passwd.tmp file */
  char		*newpass,		/* new password */
  		*oldpass;		/* old password */
  int		flag;			/* Password check flags... */
  int		fd;			/* Password file descriptor */
  int		error;			/* Write error */
  _cups_globals_t *cg = _cupsGlobals();	/* Global data */
  cups_lang_t	*lang;			/* Language info */
#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
  struct sigaction action;		/* Signal action */
#endif /* HAVE_SIGACTION && !HAVE_SIGSET*/


  _cupsSetLocale(argv);
  lang = cupsLangDefault();

 /*
  * Check to see if stdin, stdout, and stderr are still open...
  */

  if (fcntl(0, F_GETFD, &i) ||
      fcntl(1, F_GETFD, &i) ||
      fcntl(2, F_GETFD, &i))
  {
   /*
    * No, return exit status 2 and don't try to send any output since
    * someone is trying to bypass the security on the server.
    */

    return (2);
  }

 /*
  * Find the server directory...
  */

  snprintf(passwdmd5, sizeof(passwdmd5), "%s/passwd.md5", cg->cups_serverroot);
  snprintf(passwdold, sizeof(passwdold), "%s/passwd.old", cg->cups_serverroot);
  snprintf(passwdnew, sizeof(passwdnew), "%s/passwd.new", cg->cups_serverroot);

 /*
  * Find the default system group...
  */

  if (getgrnam(CUPS_DEFAULT_GROUP))
    groupname = CUPS_DEFAULT_GROUP;
  else
    groupname = "unknown";

  endgrent();

  username = NULL;
  op       = CHANGE;

 /*
  * Parse command-line options...
  */

  for (i = 1; i < argc; i ++)
    if (argv[i][0] == '-')
      for (opt = argv[i] + 1; *opt; opt ++)
        switch (*opt)
	{
	  case 'a' : /* Add */
	      op = ADD;
	      break;
	  case 'x' : /* Delete */
	      op = DELETE;
	      break;
	  case 'g' : /* Group */
	      i ++;
	      if (i >= argc)
	        usage(stderr);

              groupname = argv[i];
	      break;
	  case 'h' : /* Help */
	      usage(stdout);
	      break;
	  default : /* Bad option */
	      usage(stderr);
	      break;
	}
    else if (!username)
      username = argv[i];
    else
      usage(stderr);

 /*
  * See if we are trying to add or delete a password when we aren't logged in
  * as root...
  */

  if (getuid() && getuid() != geteuid() && (op != CHANGE || username))
  {
    _cupsLangPuts(stderr,
                  _("lppasswd: Only root can add or delete passwords!\n"));
    return (1);
  }

 /*
  * Fill in missing info...
  */

  if (!username)
    username = cupsUser();

  oldpass = newpass = NULL;

 /*
  * Obtain old and new password _before_ locking the database
  * to keep users from locking the file indefinitely.
  */

  if (op == CHANGE && getuid())
  {
    if ((passwd = cupsGetPassword(_("Enter old password:"******"lppasswd: Unable to copy password string: %s\n"),
		      strerror(errno));
      return (1);
    }
  }

 /*
  * Now get the new password, if necessary...
  */

  if (op != DELETE)
  {
    if ((passwd = cupsGetPassword(
            _cupsLangString(lang, _("Enter password:"******"lppasswd: Unable to copy password string: %s\n"),
		      strerror(errno));
      return (1);
    }

    if ((passwd = cupsGetPassword(
            _cupsLangString(lang, _("Enter password again:")))) == NULL)
      return (1);

    if (strcmp(passwd, newpass) != 0)
    {
      _cupsLangPuts(stderr,
                    _("lppasswd: Sorry, passwords don't match!\n"));
      return (1);
    }

   /*
    * Check that the password contains at least one letter and number.
    */

    flag = 0;

    for (passwd = newpass; *passwd; passwd ++)
      if (isdigit(*passwd & 255))
	flag |= 1;
      else if (isalpha(*passwd & 255))
	flag |= 2;

   /*
    * Only allow passwords that are at least 6 chars, have a letter and
    * a number, and don't contain the username.
    */

    if (strlen(newpass) < 6 || strstr(newpass, username) != NULL || flag != 3)
    {
      _cupsLangPuts(stderr,
                    _("lppasswd: Sorry, password rejected.\n"
		      "Your password must be at least 6 characters long, "
		      "cannot contain\n"
		      "your username, and must contain at least one letter "
		      "and number.\n"));
      return (1);
    }
  }

 /*
  * Ignore SIGHUP, SIGINT, SIGTERM, and SIGXFSZ (if defined) for the
  * remainder of the time so that we won't end up with bogus password
  * files...
  */

#ifndef WIN32
#  if defined(HAVE_SIGSET)
  sigset(SIGHUP, SIG_IGN);
  sigset(SIGINT, SIG_IGN);
  sigset(SIGTERM, SIG_IGN);
#    ifdef SIGXFSZ
  sigset(SIGXFSZ, SIG_IGN);
#    endif /* SIGXFSZ */
#  elif defined(HAVE_SIGACTION)
  memset(&action, 0, sizeof(action));
  action.sa_handler = SIG_IGN;

  sigaction(SIGHUP, &action, NULL);
  sigaction(SIGINT, &action, NULL);
  sigaction(SIGTERM, &action, NULL);
#    ifdef SIGXFSZ
  sigaction(SIGXFSZ, &action, NULL);
#    endif /* SIGXFSZ */
#  else
  signal(SIGHUP, SIG_IGN);
  signal(SIGINT, SIG_IGN);
  signal(SIGTERM, SIG_IGN);
#    ifdef SIGXFSZ
  signal(SIGXFSZ, SIG_IGN);
#    endif /* SIGXFSZ */
#  endif
#endif /* !WIN32 */

 /*
  * Open the output file.
  */

  if ((fd = open(passwdnew, O_WRONLY | O_CREAT | O_EXCL, 0400)) < 0)
  {
    if (errno == EEXIST)
      _cupsLangPuts(stderr, _("lppasswd: Password file busy!\n"));
    else
      _cupsLangPrintf(stderr,
                      _("lppasswd: Unable to open password file: %s\n"),
		      strerror(errno));

    return (1);
  }

  if ((outfile = fdopen(fd, "w")) == NULL)
  {
    _cupsLangPrintf(stderr,
                    _("lppasswd: Unable to open password file: %s\n"),
		    strerror(errno));

    unlink(passwdnew);

    return (1);
  }

  setbuf(outfile, NULL);

 /*
  * Open the existing password file and create a new one...
  */

  infile = fopen(passwdmd5, "r");
  if (infile == NULL && errno != ENOENT && op != ADD)
  {
    _cupsLangPrintf(stderr,
                    _("lppasswd: Unable to open password file: %s\n"),
		    strerror(errno));

    fclose(outfile);

    unlink(passwdnew);

    return (1);
  }

 /*
  * Read lines from the password file; the format is:
  *
  *   username:group:MD5-sum
  */

  error        = 0;
  userline[0]  = '\0';
  groupline[0] = '\0';
  md5line[0]   = '\0';

  if (infile)
  {
    while (fgets(line, sizeof(line), infile) != NULL)
    {
      if (sscanf(line, "%16[^:]:%16[^:]:%32s", userline, groupline, md5line) != 3)
        continue;

      if (strcmp(username, userline) == 0 &&
          strcmp(groupname, groupline) == 0)
	break;

      if (fputs(line, outfile) == EOF)
      {
	_cupsLangPrintf(stderr,
                	_("lppasswd: Unable to write to password file: %s\n"),
			strerror(errno));
        error = 1;
	break;
      }
    }

    if (!error)
    {
      while (fgets(line, sizeof(line), infile) != NULL)
	if (fputs(line, outfile) == EOF)
	{
	  _cupsLangPrintf(stderr,
                	  _("lppasswd: Unable to write to password file: %s\n"),
			  strerror(errno));
	  error = 1;
	  break;
	}
    }
  }

  if (op == CHANGE &&
      (strcmp(username, userline) || strcmp(groupname, groupline)))
  {
    _cupsLangPrintf(stderr,
                    _("lppasswd: user \"%s\" and group \"%s\" do not exist.\n"),
        	    username, groupname);
    error = 1;
  }
  else if (op != DELETE)
  {
    if (oldpass &&
        strcmp(httpMD5(username, "CUPS", oldpass, md5new), md5line) != 0)
    {
      _cupsLangPuts(stderr,
                    _("lppasswd: Sorry, password doesn't match!\n"));
      error = 1;
    }
    else
    {
      snprintf(line, sizeof(line), "%s:%s:%s\n", username, groupname,
               httpMD5(username, "CUPS", newpass, md5new));
      if (fputs(line, outfile) == EOF)
      {
	_cupsLangPrintf(stderr,
                	_("lppasswd: Unable to write to password file: %s\n"),
			strerror(errno));
        error = 1;
      }
    }
  }

 /*
  * Close the files...
  */

  if (infile)
    fclose(infile);

  if (fclose(outfile) == EOF)
    error = 1;

 /*
  * Error out gracefully as needed...
  */

  if (error)
  {
    _cupsLangPuts(stderr, _("lppasswd: Password file not updated!\n"));
    
    unlink(passwdnew);

    return (1);
  }

 /*
  * Save old passwd file
  */

  unlink(passwdold);
  if (link(passwdmd5, passwdold) && errno != ENOENT)
  {
    _cupsLangPrintf(stderr,
                    _("lppasswd: failed to backup old password file: %s\n"),
		    strerror(errno));
    unlink(passwdnew);
    return (1);
  }

 /*
  * Install new password file
  */

  if (rename(passwdnew, passwdmd5) < 0)
  {
    _cupsLangPrintf(stderr,
                    _("lppasswd: failed to rename password file: %s\n"),
		    strerror(errno));
    unlink(passwdnew);
    return (1);
  }

  return (0);
}