2 * "$Id: lppasswd.c 9384 2010-11-22 07:06:39Z mike $"
4 * MD5 password program for CUPS.
6 * Copyright 2007-2010 by Apple Inc.
7 * Copyright 1997-2006 by Easy Software Products.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
17 * main() - Add, change, or delete passwords from the MD5 password file.
18 * usage() - Show program usage.
22 * Include necessary headers...
25 #include <cups/cups-private.h>
26 #include <cups/md5-private.h>
29 #include <sys/types.h>
51 static void usage(FILE *fp);
55 * 'main()' - Add, change, or delete passwords from the MD5 password file.
58 int /* O - Exit status */
59 main(int argc, /* I - Number of command-line arguments */
60 char *argv[]) /* I - Command-line arguments */
62 int i; /* Looping var */
63 char *opt; /* Option pointer */
64 const char *username; /* Pointer to username */
65 const char *groupname; /* Pointer to group name */
66 int op; /* Operation (add, change, delete) */
67 const char *passwd; /* Password string */
68 FILE *infile, /* Input file */
69 *outfile; /* Output file */
70 char line[256], /* Line from file */
71 userline[17], /* User from line */
72 groupline[17], /* Group from line */
73 md5line[33], /* MD5-sum from line */
74 md5new[33]; /* New MD5 sum */
75 char passwdmd5[1024], /* passwd.md5 file */
76 passwdold[1024], /* passwd.old file */
77 passwdnew[1024]; /* passwd.tmp file */
78 char *newpass, /* new password */
79 *oldpass; /* old password */
80 int flag; /* Password check flags... */
81 int fd; /* Password file descriptor */
82 int error; /* Write error */
83 _cups_globals_t *cg = _cupsGlobals(); /* Global data */
84 cups_lang_t *lang; /* Language info */
85 #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
86 struct sigaction action; /* Signal action */
87 #endif /* HAVE_SIGACTION && !HAVE_SIGSET*/
91 lang = cupsLangDefault();
94 * Check to see if stdin, stdout, and stderr are still open...
97 if (fcntl(0, F_GETFD, &i) ||
98 fcntl(1, F_GETFD, &i) ||
99 fcntl(2, F_GETFD, &i))
102 * No, return exit status 2 and don't try to send any output since
103 * someone is trying to bypass the security on the server.
110 * Find the server directory...
113 snprintf(passwdmd5, sizeof(passwdmd5), "%s/passwd.md5", cg->cups_serverroot);
114 snprintf(passwdold, sizeof(passwdold), "%s/passwd.old", cg->cups_serverroot);
115 snprintf(passwdnew, sizeof(passwdnew), "%s/passwd.new", cg->cups_serverroot);
118 * Find the default system group...
121 if (getgrnam(CUPS_DEFAULT_GROUP))
122 groupname = CUPS_DEFAULT_GROUP;
124 groupname = "unknown";
132 * Parse command-line options...
135 for (i = 1; i < argc; i ++)
136 if (argv[i][0] == '-')
137 for (opt = argv[i] + 1; *opt; opt ++)
143 case 'x' : /* Delete */
146 case 'g' : /* Group */
153 case 'h' : /* Help */
156 default : /* Bad option */
166 * See if we are trying to add or delete a password when we aren't logged in
170 if (getuid() && getuid() != geteuid() && (op != CHANGE || username))
172 _cupsLangPuts(stderr,
173 _("lppasswd: Only root can add or delete passwords."));
178 * Fill in missing info...
182 username = cupsUser();
184 oldpass = newpass = NULL;
187 * Obtain old and new password _before_ locking the database
188 * to keep users from locking the file indefinitely.
191 if (op == CHANGE && getuid())
193 if ((passwd = cupsGetPassword(_("Enter old password:"))) == NULL)
196 if ((oldpass = strdup(passwd)) == NULL)
198 _cupsLangPrintf(stderr,
199 _("lppasswd: Unable to copy password string: %s"),
206 * Now get the new password, if necessary...
211 if ((passwd = cupsGetPassword(
212 _cupsLangString(lang, _("Enter password:")))) == NULL)
215 if ((newpass = strdup(passwd)) == NULL)
217 _cupsLangPrintf(stderr,
218 _("lppasswd: Unable to copy password string: %s"),
223 if ((passwd = cupsGetPassword(
224 _cupsLangString(lang, _("Enter password again:")))) == NULL)
227 if (strcmp(passwd, newpass) != 0)
229 _cupsLangPuts(stderr,
230 _("lppasswd: Sorry, passwords don't match."));
235 * Check that the password contains at least one letter and number.
240 for (passwd = newpass; *passwd; passwd ++)
241 if (isdigit(*passwd & 255))
243 else if (isalpha(*passwd & 255))
247 * Only allow passwords that are at least 6 chars, have a letter and
248 * a number, and don't contain the username.
251 if (strlen(newpass) < 6 || strstr(newpass, username) != NULL || flag != 3)
253 _cupsLangPuts(stderr, _("lppasswd: Sorry, password rejected."));
254 _cupsLangPuts(stderr, _("Your password must be at least 6 characters "
255 "long, cannot contain your username, and must "
256 "contain at least one letter and number."));
262 * Ignore SIGHUP, SIGINT, SIGTERM, and SIGXFSZ (if defined) for the
263 * remainder of the time so that we won't end up with bogus password
268 # if defined(HAVE_SIGSET)
269 sigset(SIGHUP, SIG_IGN);
270 sigset(SIGINT, SIG_IGN);
271 sigset(SIGTERM, SIG_IGN);
273 sigset(SIGXFSZ, SIG_IGN);
274 # endif /* SIGXFSZ */
275 # elif defined(HAVE_SIGACTION)
276 memset(&action, 0, sizeof(action));
277 action.sa_handler = SIG_IGN;
279 sigaction(SIGHUP, &action, NULL);
280 sigaction(SIGINT, &action, NULL);
281 sigaction(SIGTERM, &action, NULL);
283 sigaction(SIGXFSZ, &action, NULL);
284 # endif /* SIGXFSZ */
286 signal(SIGHUP, SIG_IGN);
287 signal(SIGINT, SIG_IGN);
288 signal(SIGTERM, SIG_IGN);
290 signal(SIGXFSZ, SIG_IGN);
291 # endif /* SIGXFSZ */
296 * Open the output file.
299 if ((fd = open(passwdnew, O_WRONLY | O_CREAT | O_EXCL, 0400)) < 0)
302 _cupsLangPuts(stderr, _("lppasswd: Password file busy."));
304 _cupsLangPrintf(stderr, _("lppasswd: Unable to open password file: %s"),
310 if ((outfile = fdopen(fd, "w")) == NULL)
312 _cupsLangPrintf(stderr, _("lppasswd: Unable to open password file: %s"),
320 setbuf(outfile, NULL);
323 * Open the existing password file and create a new one...
326 infile = fopen(passwdmd5, "r");
327 if (infile == NULL && errno != ENOENT && op != ADD)
329 _cupsLangPrintf(stderr, _("lppasswd: Unable to open password file: %s"),
340 * Read lines from the password file; the format is:
342 * username:group:MD5-sum
352 while (fgets(line, sizeof(line), infile) != NULL)
354 if (sscanf(line, "%16[^:]:%16[^:]:%32s", userline, groupline, md5line) != 3)
357 if (strcmp(username, userline) == 0 &&
358 strcmp(groupname, groupline) == 0)
361 if (fputs(line, outfile) == EOF)
363 _cupsLangPrintf(stderr,
364 _("lppasswd: Unable to write to password file: %s"),
373 while (fgets(line, sizeof(line), infile) != NULL)
374 if (fputs(line, outfile) == EOF)
376 _cupsLangPrintf(stderr,
377 _("lppasswd: Unable to write to password file: %s"),
386 (strcmp(username, userline) || strcmp(groupname, groupline)))
388 _cupsLangPrintf(stderr,
389 _("lppasswd: user \"%s\" and group \"%s\" do not exist."),
390 username, groupname);
393 else if (op != DELETE)
396 strcmp(httpMD5(username, "CUPS", oldpass, md5new), md5line) != 0)
398 _cupsLangPuts(stderr, _("lppasswd: Sorry, password doesn't match."));
403 snprintf(line, sizeof(line), "%s:%s:%s\n", username, groupname,
404 httpMD5(username, "CUPS", newpass, md5new));
405 if (fputs(line, outfile) == EOF)
407 _cupsLangPrintf(stderr,
408 _("lppasswd: Unable to write to password file: %s"),
422 if (fclose(outfile) == EOF)
426 * Error out gracefully as needed...
431 _cupsLangPuts(stderr, _("lppasswd: Password file not updated."));
439 * Save old passwd file
443 if (link(passwdmd5, passwdold) && errno != ENOENT)
445 _cupsLangPrintf(stderr,
446 _("lppasswd: failed to backup old password file: %s"),
453 * Install new password file
456 if (rename(passwdnew, passwdmd5) < 0)
458 _cupsLangPrintf(stderr, _("lppasswd: failed to rename password file: %s"),
469 * 'usage()' - Show program usage.
473 usage(FILE *fp) /* I - File to send usage to */
476 _cupsLangPuts(fp, _("Usage: lppasswd [-g groupname]"));
479 _("Usage: lppasswd [-g groupname] [username]\n"
480 " lppasswd [-g groupname] -a [username]\n"
481 " lppasswd [-g groupname] -x [username]"));
488 * End of "$Id: lppasswd.c 9384 2010-11-22 07:06:39Z mike $".