Update copyright year.
[userinfo.git] / src / modules / passwd.c
blob487cd96decd3a1fd3ff7187a16860a81daf6d06d
1 /*
2 Copyright (C) 2001-2013 Ben Kibbey <bjk@luxsci.net>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02110-1301 USA
18 #ifdef HAVE_CONFIG_H
19 #include <config.h>
20 #endif
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 #include <pwd.h>
28 #include <grp.h>
29 #include <errno.h>
31 #ifdef HAVE_LIMITS_H
32 #include <limits.h>
33 #ifndef LINE_MAX
34 #ifdef _POSIX2_LINE_MAX
35 #define LINE_MAX _POSIX2_LINE_MAX
36 #else
37 #define LINE_MAX 2048
38 #endif
39 #endif
40 #endif
42 #ifdef HAVE_GETOPT_H
43 #include <getopt.h>
44 #endif
46 #ifdef HAVE_STRING_H
47 #include <string.h>
48 #endif
50 #ifdef HAVE_GETSPNAM
51 #include <shadow.h>
52 #endif
54 #ifdef HAVE_ERR_H
55 #include <err.h>
56 #endif
58 #ifndef HAVE_STRSEP
59 #include "../strsep.c"
60 #endif
62 #ifndef HAVE_ERR_H
63 #include "../err.c"
64 #endif
66 #ifdef WITH_DMALLOC
67 #include <dmalloc.h>
68 #endif
70 #ifndef ALLPERMS
71 #define ALLPERMS (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)
72 #endif
74 /* This is the order of options when the 'P' option is specified. It selects
75 * all available options. */
76 #define PASSWD_OPTION_ORDER "lpugicedsm"
77 #define PASSWD_OPTION_STRING "Plpugcedsmi:"
79 static int amroot;
80 static char **strings;
81 static char options[11]; /* NULL terminated. */
82 static char *gecos_options;
84 void add_string(char ***, const char *);
85 char *stamp(time_t, const char *);
86 char *safe_strncat(char *, const char *, size_t);
88 void ui_module_init(int *chainable)
91 * Keep the password file open if possible (*BSD).
93 #ifdef HAVE_SETPASSENT
94 setpassent(1);
95 #endif
97 if (getuid() == 0)
98 amroot = 1;
100 *chainable = 0;
103 void ui_module_exit()
105 #ifdef HAVE_GETSPNAM
106 if (amroot)
107 endspent();
108 #endif
110 endpwent();
111 #ifdef HAVE_GETGRENT
112 endgrent();
113 #endif
116 /* See if the gecos options are valid. */
117 static int parse_gecos_options(const char *args)
119 int i = 0;
121 for (i = 0; i < strlen(args); i++) {
122 switch (args[i]) {
123 case 'n':
124 case '1':
125 case '2':
126 case '3':
127 case 'a':
128 break;
129 default:
130 return 1;
134 return 0;
137 /* Break up the gecos string into sections and add the sections to the output
138 * string array if needed. */
139 static void gecos_strings(char *str)
141 int i = 0;
142 char *buf;
143 const char *name, *first, *second, *third;
145 name = first = second = third = "-";
147 while ((buf = strsep(&str, ",")) != NULL) {
148 if (!buf[0])
149 continue;
151 switch (i++) {
152 case 0:
153 name = buf;
154 break;
155 case 1:
156 first = buf;
157 break;
158 case 2:
159 second = buf;
160 break;
161 case 3:
162 third = buf;
163 break;
164 default:
165 break;
169 for (i = 0; i < strlen(gecos_options); i++) {
170 switch (gecos_options[i]) {
171 case 'n':
172 add_string(&strings, name);
173 break;
174 case '1':
175 add_string(&strings, first);
176 break;
177 case '2':
178 add_string(&strings, second);
179 break;
180 case '3':
181 add_string(&strings, third);
182 break;
183 case 'a':
184 add_string(&strings, name);
185 add_string(&strings, first);
186 add_string(&strings, second);
187 add_string(&strings, third);
188 break;
189 default:
190 break;
195 /* Get all groups that a user is a member of. The primary group will be the
196 * first added. */
197 static void groups(const struct passwd *pw, const int multi,
198 const int verbose)
200 struct group *grp;
201 char tmp[255];
202 char line[LINE_MAX];
203 gid_t primary = -1;
205 line[0] = '\0';
207 if ((grp = getgrgid(pw->pw_gid)) == NULL) {
208 snprintf(tmp, sizeof(tmp), "%li%s%s%s", (long) pw->pw_gid,
209 (verbose) ? "(" : "", (verbose) ? "!" : "",
210 (verbose) ? ")" : "");
211 add_string(&strings, tmp);
212 return;
215 primary = grp->gr_gid;
216 snprintf(tmp, sizeof(tmp), "%li%s%s%s%c", (long) pw->pw_gid,
217 (verbose) ? "(" : "", (verbose) ? grp->gr_name : "",
218 (verbose) ? ")" : "", multi);
219 safe_strncat(line, tmp, sizeof(line));
220 #ifdef HAVE_GETGRENT
221 #ifdef HAVE_SETGROUPENT
222 setgroupent(1);
223 #else
224 setgrent();
225 #endif
227 while ((grp = getgrent()) != NULL) {
228 char **members = grp->gr_mem;
230 while (*members) {
231 if (strcmp(*members++, pw->pw_name) == 0) {
232 if (grp->gr_gid == primary)
233 continue;
235 snprintf(tmp, sizeof(tmp), "%li%s%s%s%c", (long) grp->gr_gid,
236 (verbose) ? "(" : "", (verbose) ? grp->gr_name : "",
237 (verbose) ? ")" : "", multi);
238 safe_strncat(line, tmp, sizeof(line));
242 #endif
245 * Trim the remaining multi-string deliminator.
247 line[strlen(line) - 1] = '\0';
249 add_string(&strings, line);
252 /* This is output if the -h command line option is passed to the main program.
254 void ui_module_help()
256 printf(" Password/Group file information [-P (-%s)]:\n",
257 PASSWD_OPTION_ORDER);
258 printf("\t-l login name\t\t");
259 printf("\t-p encrypted password\n");
260 printf("\t-u user id (uid)\t");
261 printf("\t-g group id (gid)\n");
262 printf("\t-c password change time");
263 printf("\t-e password expire time\n");
264 printf("\t-d home directory\t");
265 printf("\t-m home directory mode\n");
266 printf("\t-s login shell\n");
267 printf("\t-i gecos (any of [n]ame,[1]st,[2]nd,[3]rd or [a]ll)\n\n");
270 /* This is the equivalent to main() only without argc and argv available. */
271 int ui_module_exec(char ***s, const struct passwd *pw, const int multi_char,
272 const int verbose, char *tf)
274 char *p = options;
275 struct stat st;
277 #ifdef HAVE_GETSPNAM
278 struct spwd *spwd = NULL;
279 #endif
281 #ifdef HAVE_GETSPNAM
282 if (amroot) {
283 if ((spwd = getspnam(pw->pw_name)) == NULL)
284 warnx("%s", "getspnam(): unknown error");
286 #endif
288 strings = *s;
290 while (*p) {
291 char tmp[256];
293 switch (*p) {
294 #ifdef HAVE_GETSPNAM
295 case 'c':
296 if (!amroot) {
297 add_string(&strings, "!");
298 break;
301 snprintf(tmp, sizeof(tmp), "%li", (long) spwd->sp_max);
302 add_string(&strings, tmp);
303 break;
304 case 'e':
305 if (!amroot) {
306 add_string(&strings, "!");
307 break;
310 snprintf(tmp, sizeof(tmp), "%li", (long) spwd->sp_expire);
311 add_string(&strings, tmp);
312 break;
313 #else
314 case 'c':
315 #ifdef HAVE_PASSWD_CHANGE
316 snprintf(tmp, sizeof(tmp), "%li", (long) pw->pw_change);
317 add_string(&strings, tmp);
318 #else
319 add_string(&strings, "!");
320 #endif
321 break;
322 case 'e':
323 #ifdef HAVE_PASSWD_EXPIRE
324 snprintf(tmp, sizeof(tmp), "%li", (long) pw->pw_expire);
325 add_string(&strings, tmp);
326 #else
327 add_string(&strings, "!");
328 #endif
329 break;
330 #endif
331 case 'l':
332 add_string(&strings, pw->pw_name);
333 break;
334 case 'd':
335 add_string(&strings, (pw->pw_dir && pw->pw_dir[0]) ? pw->pw_dir : "-");
336 break;
337 case 's':
338 add_string(&strings, (pw->pw_shell && pw->pw_shell[0]) ? pw->pw_shell : "-");
339 break;
340 case 'p':
341 #ifdef HAVE_GETSPNAM
342 if (!amroot)
343 add_string(&strings, (pw->pw_passwd
344 && pw->pw_passwd[0]) ? pw->pw_passwd : "-");
345 else
346 add_string(&strings, (spwd->sp_pwdp
347 && spwd->sp_pwdp[0]) ? spwd->sp_pwdp : "-");
348 #else
349 add_string(&strings, (pw->pw_passwd
350 && pw->pw_passwd[0]) ? pw->pw_passwd : "-");
351 #endif
352 break;
353 case 'u':
354 sprintf(tmp, "%li", (long) pw->pw_uid);
355 add_string(&strings, tmp);
356 break;
357 case 'g':
358 groups(pw, multi_char, verbose);
359 break;
360 case 'm':
361 if (stat(pw->pw_dir, &st) == -1) {
362 add_string(&strings, "!");
363 break;
366 sprintf(tmp, "%.4o", (unsigned) st.st_mode & ALLPERMS);
367 add_string(&strings, tmp);
368 break;
369 case 'i':
370 #ifdef HAVE_PASSWD_GECOS
371 gecos_strings(pw->pw_gecos);
372 #else
373 add_string(&strings, "!");
374 #endif
375 break;
376 default:
377 break;
380 p++;
383 *s = strings;
384 return EXIT_SUCCESS;
387 char *ui_module_options_init(char **defaults)
389 *defaults = "P";
390 return PASSWD_OPTION_STRING;
393 /* Check module option validity. */
394 int ui_module_options(int argc, char **argv)
396 int opt;
397 char *p = options;
399 while ((opt = getopt(argc, argv, PASSWD_OPTION_STRING)) != -1) {
400 switch (opt) {
401 case 'i':
402 if (parse_gecos_options(optarg))
403 return 1;
405 gecos_options = optarg;
406 break;
407 case 'P':
408 strncpy(options, PASSWD_OPTION_ORDER, sizeof(options));
409 gecos_options = "a";
410 return 0;
411 case 'l':
412 case 'p':
413 case 'u':
414 case 'g':
415 case 'c':
416 case 'e':
417 case 'd':
418 case 's':
419 case 'm':
420 break;
421 case '?':
422 warnx("passwd: invalid option -- %c", optopt);
423 default:
424 return 1;
427 *p++ = opt;
428 *p = '\0';
431 return 0;