#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <ctype.h>
#include <fcntl.h>
#include <grp.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <cups/cups.h>
#include <cups/md5.h>
#include <cups/string.h>
#define ADD 0
#define CHANGE 1
#define DELETE 2
static void usage(FILE *fp);
int
main(int argc,
char *argv[])
{
int i;
char *opt;
const char *username;
const char *groupname;
int op;
const char *passwd;
FILE *infile,
*outfile;
char line[256],
userline[17],
groupline[17],
md5line[33],
md5new[33];
const char *root;
char passwdmd5[1024],
passwdold[1024],
passwdnew[1024];
char *newpass,
*oldpass;
int flag;
int fd;
if (!getuid() && (root = getenv("CUPS_SERVERROOT")) != NULL)
{
snprintf(passwdmd5, sizeof(passwdmd5), "%s/passwd.md5", root);
snprintf(passwdold, sizeof(passwdold), "%s/passwd.old", root);
snprintf(passwdnew, sizeof(passwdnew), "%s/passwd.new", root);
}
else
{
strcpy(passwdmd5, CUPS_SERVERROOT "/passwd.md5");
strcpy(passwdold, CUPS_SERVERROOT "/passwd.old");
strcpy(passwdnew, CUPS_SERVERROOT "/passwd.new");
}
if (getgrnam("sys"))
groupname = "sys";
else if (getgrnam("system"))
groupname = "system";
else if (getgrnam("root"))
groupname = "root";
else
groupname = "unknown";
endgrent();
username = NULL;
op = CHANGE;
for (i = 1; i < argc; i ++)
if (argv[i][0] == '-')
for (opt = argv[i] + 1; *opt; opt ++)
switch (*opt)
{
case 'a' :
op = ADD;
break;
case 'x' :
op = DELETE;
break;
case 'g' :
i ++;
if (i >= argc)
usage(stderr);
groupname = argv[i];
break;
case 'h' :
usage(stdout);
break;
default :
usage(stderr);
break;
}
else if (!username)
username = argv[i];
else
usage(stderr);
if (getuid() && (op != CHANGE || username))
{
fputs("lppasswd: Only root can add or delete passwords!\n", stderr);
return (1);
}
if (!username)
username = cupsUser();
oldpass = newpass = NULL;
if (op == CHANGE && getuid())
{
if ((passwd = cupsGetPassword("Enter old password:")) == NULL)
return (1);
if ((oldpass = strdup(passwd)) == NULL)
{
perror("lppasswd: Unable to copy password string");
return (1);
}
}
if (op != DELETE)
{
if ((passwd = cupsGetPassword("Enter password:")) == NULL)
return (1);
if ((newpass = strdup(passwd)) == NULL)
{
perror("lppasswd: Unable to copy password string!");
return (1);
}
if ((passwd = cupsGetPassword("Enter password again:")) == NULL)
return (1);
if (strcmp(passwd, newpass) != 0)
{
fputs("lppasswd: Sorry, passwords don't match!\n", stderr);
return (1);
}
flag = 0;
for (passwd = newpass; *passwd; passwd ++)
if (isdigit(*passwd))
flag |= 1;
else if (isalpha(*passwd))
flag |= 2;
if (strlen(newpass) < 6 || strstr(newpass, username) != NULL || flag != 3)
{
fputs("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",
stderr);
return (1);
}
}
if ((fd = open(passwdnew, O_WRONLY | O_CREAT | O_EXCL, 0400)) < 0)
{
if (errno == EEXIST)
fputs("lppasswd: Password file busy!\n", stderr);
else
perror("lppasswd: Unable to open passwd file");
return (1);
}
if ((outfile = fdopen(fd, "w")) == NULL)
{
perror("lppasswd: Unable to open passwd file");
unlink(passwdnew);
return (1);
}
infile = fopen(passwdmd5, "r");
if (infile == NULL && errno != ENOENT && op != ADD)
{
fputs("lppasswd: No password file to change or delete from!\n", stderr);
fclose(outfile);
unlink(passwdnew);
return (1);
}
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;
fputs(line, outfile);
}
while (fgets(line, sizeof(line), infile) != NULL)
fputs(line, outfile);
}
else
{
userline[0] = '\0';
groupline[0] = '\0';
md5line[0] = '\0';
}
if (op == CHANGE &&
(strcmp(username, userline) != 0 ||
strcmp(groupname, groupline) != 0))
fprintf(stderr, "lppasswd: user \"%s\" and group \"%s\" do not exist.\n",
username, groupname);
else if (op != DELETE)
{
if (oldpass &&
strcmp(httpMD5(username, "CUPS", oldpass, md5new), md5line) != 0)
{
fputs("lppasswd: Sorry, password doesn't match!\n", stderr);
if (infile)
fclose(infile);
fclose(outfile);
unlink(passwdnew);
return (1);
}
fprintf(outfile, "%s:%s:%s\n", username, groupname,
httpMD5(username, "CUPS", newpass, md5new));
}
if (infile)
fclose(infile);
fclose(outfile);
unlink(passwdold);
link(passwdmd5, passwdold);
if (rename(passwdnew, passwdmd5) < 0)
{
perror("lppasswd: failed to rename passwd file");
unlink(passwdnew);
return (1);
}
return (0);
}
static void
usage(FILE *fp)
{
if (getuid())
{
fputs("Usage: lppasswd [-g groupname]\n", fp);
}
else
{
fputs("Usage: lppasswd [-g groupname] [username]\n", fp);
fputs(" lppasswd [-g groupname] -a [username]\n", fp);
fputs(" lppasswd [-g groupname] -x [username]\n", fp);
}
exit(1);
}