]> git.ipfire.org Git - thirdparty/cups.git/blame - systemv/lppasswd.c
Load cups into easysw/current.
[thirdparty/cups.git] / systemv / lppasswd.c
CommitLineData
ef416fc2 1/*
f7deaa1a 2 * "$Id: lppasswd.c 5925 2006-09-05 19:43:11Z mike $"
ef416fc2 3 *
4 * MD5 password program for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2006 by Easy Software Products.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * Contents:
25 *
26 * main() - Add, change, or delete passwords from the MD5 password file.
27 * usage() - Show program usage.
28 */
29
30/*
31 * Include necessary headers...
32 */
33
34#include <stdio.h>
35#include <stdlib.h>
36#include <errno.h>
37#include <ctype.h>
38#include <fcntl.h>
39#include <grp.h>
40#include <sys/types.h>
41#include <sys/stat.h>
42
43#include <cups/string.h>
44#include <cups/cups.h>
45#include <cups/i18n.h>
46#include <cups/md5.h>
47
48#ifndef WIN32
49# include <unistd.h>
50# include <signal.h>
51#endif /* !WIN32 */
52
53
54/*
55 * Operations...
56 */
57
58#define ADD 0
59#define CHANGE 1
60#define DELETE 2
61
62
63/*
64 * Local functions...
65 */
66
67static void usage(FILE *fp);
68
69
70/*
71 * 'main()' - Add, change, or delete passwords from the MD5 password file.
72 */
73
74int /* O - Exit status */
75main(int argc, /* I - Number of command-line arguments */
76 char *argv[]) /* I - Command-line arguments */
77{
78 int i; /* Looping var */
79 char *opt; /* Option pointer */
80 const char *username; /* Pointer to username */
81 const char *groupname; /* Pointer to group name */
82 int op; /* Operation (add, change, delete) */
83 const char *passwd; /* Password string */
84 FILE *infile, /* Input file */
85 *outfile; /* Output file */
86 char line[256], /* Line from file */
87 userline[17], /* User from line */
88 groupline[17], /* Group from line */
89 md5line[33], /* MD5-sum from line */
90 md5new[33]; /* New MD5 sum */
91 const char *root; /* CUPS server root directory */
92 char passwdmd5[1024], /* passwd.md5 file */
93 passwdold[1024], /* passwd.old file */
94 passwdnew[1024]; /* passwd.tmp file */
95 char *newpass, /* new password */
96 *oldpass; /* old password */
97 int flag; /* Password check flags... */
98 int fd; /* Password file descriptor */
99 int error; /* Write error */
100#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
101 struct sigaction action; /* Signal action */
102#endif /* HAVE_SIGACTION && !HAVE_SIGSET*/
103
104
07725fee 105 _cupsSetLocale(argv);
d09495fa 106
ef416fc2 107 /*
108 * Check to see if stdin, stdout, and stderr are still open...
109 */
110
111 if (fcntl(0, F_GETFD, &i) ||
112 fcntl(1, F_GETFD, &i) ||
113 fcntl(2, F_GETFD, &i))
114 {
115 /*
116 * No, return exit status 2 and don't try to send any output since
117 * someone is trying to bypass the security on the server.
118 */
119
120 return (2);
121 }
122
123 /*
124 * Find the server directory...
125 *
126 * We use the CUPS_SERVERROOT environment variable when we are running
127 * as root or when lppasswd is not setuid...
128 */
129
130 if ((root = getenv("CUPS_SERVERROOT")) == NULL ||
131 (getuid() != geteuid() && getuid()))
132 root = CUPS_SERVERROOT;
133
134 snprintf(passwdmd5, sizeof(passwdmd5), "%s/passwd.md5", root);
135 snprintf(passwdold, sizeof(passwdold), "%s/passwd.old", root);
136 snprintf(passwdnew, sizeof(passwdnew), "%s/passwd.new", root);
137
138 /*
139 * Find the default system group...
140 */
141
142 if (getgrnam(CUPS_DEFAULT_GROUP))
143 groupname = CUPS_DEFAULT_GROUP;
144 else
145 groupname = "unknown";
146
147 endgrent();
148
149 username = NULL;
150 op = CHANGE;
151
152 /*
153 * Parse command-line options...
154 */
155
156 for (i = 1; i < argc; i ++)
157 if (argv[i][0] == '-')
158 for (opt = argv[i] + 1; *opt; opt ++)
159 switch (*opt)
160 {
161 case 'a' : /* Add */
162 op = ADD;
163 break;
164 case 'x' : /* Delete */
165 op = DELETE;
166 break;
167 case 'g' : /* Group */
168 i ++;
169 if (i >= argc)
170 usage(stderr);
171
172 groupname = argv[i];
173 break;
174 case 'h' : /* Help */
175 usage(stdout);
176 break;
177 default : /* Bad option */
178 usage(stderr);
179 break;
180 }
181 else if (!username)
182 username = argv[i];
183 else
184 usage(stderr);
185
186 /*
187 * See if we are trying to add or delete a password when we aren't logged in
188 * as root...
189 */
190
191 if (getuid() && getuid() != geteuid() && (op != CHANGE || username))
192 {
fa73b229 193 _cupsLangPuts(stderr,
ef416fc2 194 _("lppasswd: Only root can add or delete passwords!\n"));
195 return (1);
196 }
197
198 /*
199 * Fill in missing info...
200 */
201
202 if (!username)
203 username = cupsUser();
204
205 oldpass = newpass = NULL;
206
207 /*
208 * Obtain old and new password _before_ locking the database
209 * to keep users from locking the file indefinitely.
210 */
211
212 if (op == CHANGE && getuid())
213 {
214 if ((passwd = cupsGetPassword(_("Enter old password:"))) == NULL)
215 return (1);
216
217 if ((oldpass = strdup(passwd)) == NULL)
218 {
fa73b229 219 _cupsLangPrintf(stderr,
ef416fc2 220 _("lppasswd: Unable to copy password string: %s\n"),
221 strerror(errno));
222 return (1);
223 }
224 }
225
226 /*
227 * Now get the new password, if necessary...
228 */
229
230 if (op != DELETE)
231 {
232 if ((passwd = cupsGetPassword(_("Enter password:"))) == NULL)
233 return (1);
234
235 if ((newpass = strdup(passwd)) == NULL)
236 {
fa73b229 237 _cupsLangPrintf(stderr,
ef416fc2 238 _("lppasswd: Unable to copy password string: %s\n"),
239 strerror(errno));
240 return (1);
241 }
242
243 if ((passwd = cupsGetPassword(_("Enter password again:"))) == NULL)
244 return (1);
245
246 if (strcmp(passwd, newpass) != 0)
247 {
fa73b229 248 _cupsLangPuts(stderr,
ef416fc2 249 _("lppasswd: Sorry, passwords don't match!\n"));
250 return (1);
251 }
252
253 /*
254 * Check that the password contains at least one letter and number.
255 */
256
257 flag = 0;
258
259 for (passwd = newpass; *passwd; passwd ++)
260 if (isdigit(*passwd & 255))
261 flag |= 1;
262 else if (isalpha(*passwd & 255))
263 flag |= 2;
264
265 /*
266 * Only allow passwords that are at least 6 chars, have a letter and
267 * a number, and don't contain the username.
268 */
269
270 if (strlen(newpass) < 6 || strstr(newpass, username) != NULL || flag != 3)
271 {
fa73b229 272 _cupsLangPuts(stderr,
ef416fc2 273 _("lppasswd: Sorry, password rejected.\n"
274 "Your password must be at least 6 characters long, "
275 "cannot contain\n"
276 "your username, and must contain at least one letter "
277 "and number.\n"));
278 return (1);
279 }
280 }
281
282 /*
283 * Ignore SIGHUP, SIGINT, SIGTERM, and SIGXFSZ (if defined) for the
284 * remainder of the time so that we won't end up with bogus password
285 * files...
286 */
287
288#ifndef WIN32
289# if defined(HAVE_SIGSET)
290 sigset(SIGHUP, SIG_IGN);
291 sigset(SIGINT, SIG_IGN);
292 sigset(SIGTERM, SIG_IGN);
293# ifdef SIGXFSZ
294 sigset(SIGXFSZ, SIG_IGN);
295# endif /* SIGXFSZ */
296# elif defined(HAVE_SIGACTION)
297 memset(&action, 0, sizeof(action));
298 action.sa_handler = SIG_IGN;
299
300 sigaction(SIGHUP, &action, NULL);
301 sigaction(SIGINT, &action, NULL);
302 sigaction(SIGTERM, &action, NULL);
303# ifdef SIGXFSZ
304 sigaction(SIGXFSZ, &action, NULL);
305# endif /* SIGXFSZ */
306# else
307 signal(SIGHUP, SIG_IGN);
308 signal(SIGINT, SIG_IGN);
309 signal(SIGTERM, SIG_IGN);
310# ifdef SIGXFSZ
311 signal(SIGXFSZ, SIG_IGN);
312# endif /* SIGXFSZ */
313# endif
314#endif /* !WIN32 */
315
316 /*
317 * Open the output file.
318 */
319
320 if ((fd = open(passwdnew, O_WRONLY | O_CREAT | O_EXCL, 0400)) < 0)
321 {
322 if (errno == EEXIST)
fa73b229 323 _cupsLangPuts(stderr, _("lppasswd: Password file busy!\n"));
ef416fc2 324 else
fa73b229 325 _cupsLangPrintf(stderr,
ef416fc2 326 _("lppasswd: Unable to open password file: %s\n"),
327 strerror(errno));
328
329 return (1);
330 }
331
332 if ((outfile = fdopen(fd, "w")) == NULL)
333 {
fa73b229 334 _cupsLangPrintf(stderr,
ef416fc2 335 _("lppasswd: Unable to open password file: %s\n"),
336 strerror(errno));
337
338 unlink(passwdnew);
339
340 return (1);
341 }
342
343 setbuf(outfile, NULL);
344
345 /*
346 * Open the existing password file and create a new one...
347 */
348
349 infile = fopen(passwdmd5, "r");
350 if (infile == NULL && errno != ENOENT && op != ADD)
351 {
fa73b229 352 _cupsLangPrintf(stderr,
ef416fc2 353 _("lppasswd: Unable to open password file: %s\n"),
354 strerror(errno));
355
356 fclose(outfile);
357
358 unlink(passwdnew);
359
360 return (1);
361 }
362
363 /*
364 * Read lines from the password file; the format is:
365 *
366 * username:group:MD5-sum
367 */
368
369 error = 0;
370 userline[0] = '\0';
371 groupline[0] = '\0';
372 md5line[0] = '\0';
373
374 if (infile)
375 {
376 while (fgets(line, sizeof(line), infile) != NULL)
377 {
378 if (sscanf(line, "%16[^:]:%16[^:]:%32s", userline, groupline, md5line) != 3)
379 continue;
380
381 if (strcmp(username, userline) == 0 &&
382 strcmp(groupname, groupline) == 0)
383 break;
384
385 if (fputs(line, outfile) == EOF)
386 {
fa73b229 387 _cupsLangPrintf(stderr,
ef416fc2 388 _("lppasswd: Unable to write to password file: %s\n"),
389 strerror(errno));
390 error = 1;
391 break;
392 }
393 }
394
395 if (!error)
396 {
397 while (fgets(line, sizeof(line), infile) != NULL)
398 if (fputs(line, outfile) == EOF)
399 {
fa73b229 400 _cupsLangPrintf(stderr,
ef416fc2 401 _("lppasswd: Unable to write to password file: %s\n"),
402 strerror(errno));
403 error = 1;
404 break;
405 }
406 }
407 }
408
409 if (op == CHANGE &&
410 (strcmp(username, userline) || strcmp(groupname, groupline)))
411 {
fa73b229 412 _cupsLangPrintf(stderr,
ef416fc2 413 _("lppasswd: user \"%s\" and group \"%s\" do not exist.\n"),
414 username, groupname);
415 error = 1;
416 }
417 else if (op != DELETE)
418 {
419 if (oldpass &&
420 strcmp(httpMD5(username, "CUPS", oldpass, md5new), md5line) != 0)
421 {
fa73b229 422 _cupsLangPuts(stderr,
ef416fc2 423 _("lppasswd: Sorry, password doesn't match!\n"));
424 error = 1;
425 }
426 else
427 {
428 snprintf(line, sizeof(line), "%s:%s:%s\n", username, groupname,
429 httpMD5(username, "CUPS", newpass, md5new));
430 if (fputs(line, outfile) == EOF)
431 {
fa73b229 432 _cupsLangPrintf(stderr,
ef416fc2 433 _("lppasswd: Unable to write to password file: %s\n"),
434 strerror(errno));
435 error = 1;
436 }
437 }
438 }
439
440 /*
441 * Close the files...
442 */
443
444 if (infile)
445 fclose(infile);
446
447 if (fclose(outfile) == EOF)
448 error = 1;
449
450 /*
451 * Error out gracefully as needed...
452 */
453
454 if (error)
455 {
fa73b229 456 _cupsLangPuts(stderr, _("lppasswd: Password file not updated!\n"));
ef416fc2 457
458 unlink(passwdnew);
459
460 return (1);
461 }
462
463 /*
464 * Save old passwd file
465 */
466
467 unlink(passwdold);
468 if (link(passwdmd5, passwdold) && errno != ENOENT)
469 {
fa73b229 470 _cupsLangPrintf(stderr,
ef416fc2 471 _("lppasswd: failed to backup old password file: %s\n"),
472 strerror(errno));
473 unlink(passwdnew);
474 return (1);
475 }
476
477 /*
478 * Install new password file
479 */
480
481 if (rename(passwdnew, passwdmd5) < 0)
482 {
fa73b229 483 _cupsLangPrintf(stderr,
ef416fc2 484 _("lppasswd: failed to rename password file: %s\n"),
485 strerror(errno));
486 unlink(passwdnew);
487 return (1);
488 }
489
490 return (0);
491}
492
493
494/*
495 * 'usage()' - Show program usage.
496 */
497
498static void
499usage(FILE *fp) /* I - File to send usage to */
500{
501 if (getuid())
fa73b229 502 _cupsLangPuts(fp, _("Usage: lppasswd [-g groupname]\n"));
ef416fc2 503 else
fa73b229 504 _cupsLangPuts(fp,
ef416fc2 505 _("Usage: lppasswd [-g groupname] [username]\n"
506 " lppasswd [-g groupname] -a [username]\n"
507 " lppasswd [-g groupname] -x [username]\n"));
ef416fc2 508
509 exit(1);
510}
511
512
513/*
f7deaa1a 514 * End of "$Id: lppasswd.c 5925 2006-09-05 19:43:11Z mike $".
ef416fc2 515 */