Updated the copyright year.
[userinfo.git] / src / modules / passwd.c
blob7e279431ed3e1a4688cc9e3f40c96c4a5bd640b6
1 /*
2 Copyright (C) 2001-2011 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 #endif
35 #ifdef HAVE_GETOPT_H
36 #include <getopt.h>
37 #endif
39 #ifdef HAVE_STRING_H
40 #include <string.h>
41 #endif
43 #ifdef HAVE_GETSPNAM
44 #include <shadow.h>
45 #endif
47 #ifdef HAVE_ERR_H
48 #include <err.h>
49 #endif
51 #ifndef HAVE_STRSEP
52 #include "../strsep.c"
53 #endif
55 #ifndef HAVE_ERR_H
56 #include "../err.c"
57 #endif
59 #ifdef WITH_DMALLOC
60 #include <dmalloc.h>
61 #endif
63 #include "common.h"
65 #ifndef ALLPERMS
66 #define ALLPERMS (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)
67 #endif
69 /* This is the order of options when the 'P' option is specified. It selects
70 * all available options. */
71 #define PASSWD_OPTION_ORDER "lpugicedsm"
72 #define PASSWD_OPTION_STRING "Plpugcedsmi:"
74 static int amroot;
75 static char **strings;
76 static char options[11]; /* NULL terminated. */
77 static char *gecos_options;
79 void add_string(char ***, const char *);
80 char *stamp(time_t, const char *);
82 void ui_module_init(int *chainable)
85 * Keep the password file open if possible (*BSD).
87 #ifdef HAVE_SETPASSENT
88 setpassent(1);
89 #endif
91 if (getuid() == 0)
92 amroot = 1;
94 *chainable = 0;
97 void ui_module_exit()
99 #ifdef HAVE_GETSPNAM
100 if (amroot)
101 endspent();
102 #endif
104 endpwent();
105 endgrent();
108 /* See if the gecos options are valid. */
109 static int parse_gecos_options(const char *args)
111 int i = 0;
113 for (i = 0; i < strlen(args); i++) {
114 switch (args[i]) {
115 case 'n':
116 case '1':
117 case '2':
118 case '3':
119 case 'a':
120 break;
121 default:
122 return 1;
126 return 0;
129 /* Break up the gecos string into sections and add the sections to the output
130 * string array if needed. */
131 static void gecos_strings(char *str)
133 int i = 0;
134 char *buf;
135 const char *name, *first, *second, *third;
137 name = first = second = third = "-";
139 while ((buf = strsep(&str, ",")) != NULL) {
140 if (!buf[0])
141 continue;
143 switch (i++) {
144 case 0:
145 name = buf;
146 break;
147 case 1:
148 first = buf;
149 break;
150 case 2:
151 second = buf;
152 break;
153 case 3:
154 third = buf;
155 break;
156 default:
157 break;
161 for (i = 0; i < strlen(gecos_options); i++) {
162 switch (gecos_options[i]) {
163 case 'n':
164 add_string(&strings, name);
165 break;
166 case '1':
167 add_string(&strings, first);
168 break;
169 case '2':
170 add_string(&strings, second);
171 break;
172 case '3':
173 add_string(&strings, third);
174 break;
175 case 'a':
176 add_string(&strings, name);
177 add_string(&strings, first);
178 add_string(&strings, second);
179 add_string(&strings, third);
180 break;
181 default:
182 break;
187 /* Get all groups that a user is a member of. The primary group will be the
188 * first added. */
189 static void groups(const struct passwd *pw, const int multi,
190 const int verbose)
192 struct group *grp;
193 char tmp[255];
194 char line[LINE_MAX];
195 gid_t primary = -1;
197 line[0] = '\0';
199 if ((grp = getgrgid(pw->pw_gid)) == NULL) {
200 snprintf(tmp, sizeof(tmp), "%li%s%s%s", (long) pw->pw_gid,
201 (verbose) ? "(" : "", (verbose) ? "!" : "",
202 (verbose) ? ")" : "");
203 add_string(&strings, tmp);
204 return;
207 primary = grp->gr_gid;
208 snprintf(tmp, sizeof(tmp), "%li%s%s%s%c", (long) pw->pw_gid,
209 (verbose) ? "(" : "", (verbose) ? grp->gr_name : "",
210 (verbose) ? ")" : "", multi);
211 safe_strncat(line, tmp, sizeof(line));
213 #ifdef HAVE_SETGROUPENT
214 setgroupent(1);
215 #else
216 setgrent();
217 #endif
219 while ((grp = getgrent()) != NULL) {
220 char **members = grp->gr_mem;
222 while (*members) {
223 if (strcmp(*members++, pw->pw_name) == 0) {
224 if (grp->gr_gid == primary)
225 continue;
227 snprintf(tmp, sizeof(tmp), "%li%s%s%s%c", (long) grp->gr_gid,
228 (verbose) ? "(" : "", (verbose) ? grp->gr_name : "",
229 (verbose) ? ")" : "", multi);
230 safe_strncat(line, tmp, sizeof(line));
236 * Trim the remaining multi-string deliminator.
238 line[strlen(line) - 1] = '\0';
240 add_string(&strings, line);
243 /* This is output if the -h command line option is passed to the main program.
245 void ui_module_help()
247 printf(" Password/Group file information [-P (-%s)]:\n",
248 PASSWD_OPTION_ORDER);
249 printf("\t-l login name\t\t");
250 printf("\t-p encrypted password\n");
251 printf("\t-u user id (uid)\t");
252 printf("\t-g group id (gid)\n");
253 printf("\t-c password change time");
254 printf("\t-e password expire time\n");
255 printf("\t-d home directory\t");
256 printf("\t-m home directory mode\n");
257 printf("\t-s login shell\n");
258 printf("\t-i gecos (any of [n]ame,[1]st,[2]nd,[3]rd or [a]ll)\n\n");
261 /* This is the equivalent to main() only without argc and argv available. */
262 int ui_module_exec(char ***s, const struct passwd *pw, const int multi_char,
263 const int verbose, char *tf)
265 char *p = options;
266 struct stat st;
268 #ifdef HAVE_GETSPNAM
269 struct spwd *spwd = NULL;
270 #endif
272 #ifdef HAVE_GETSPNAM
273 if (amroot) {
274 if ((spwd = getspnam(pw->pw_name)) == NULL)
275 warnx("%s", "getspnam(): unknown error");
277 #endif
279 strings = *s;
281 while (*p) {
282 char tmp[256];
284 switch (*p) {
285 #ifdef HAVE_GETSPNAM
286 case 'c':
287 if (!amroot) {
288 add_string(&strings, "!");
289 break;
292 snprintf(tmp, sizeof(tmp), "%li", (long) spwd->sp_max);
293 add_string(&strings, tmp);
294 break;
295 case 'e':
296 if (!amroot) {
297 add_string(&strings, "!");
298 break;
301 snprintf(tmp, sizeof(tmp), "%li", (long) spwd->sp_expire);
302 add_string(&strings, tmp);
303 break;
304 #else
305 case 'c':
306 snprintf(tmp, sizeof(tmp), "%li", (long) pw->pw_change);
307 add_string(&strings, tmp);
308 break;
309 case 'e':
310 snprintf(tmp, sizeof(tmp), "%li", (long) pw->pw_expire);
311 add_string(&strings, tmp);
312 break;
313 #endif
314 case 'l':
315 add_string(&strings, pw->pw_name);
316 break;
317 case 'd':
318 add_string(&strings, (pw->pw_dir && pw->pw_dir[0]) ? pw->pw_dir : "-");
319 break;
320 case 's':
321 add_string(&strings, (pw->pw_shell && pw->pw_shell[0]) ? pw->pw_shell : "-");
322 break;
323 case 'p':
324 #ifdef HAVE_GETSPNAM
325 if (!amroot)
326 add_string(&strings, (pw->pw_passwd
327 && pw->pw_passwd[0]) ? pw->pw_passwd : "-");
328 else
329 add_string(&strings, (spwd->sp_pwdp
330 && spwd->sp_pwdp[0]) ? spwd->sp_pwdp : "-");
331 #else
332 add_string(&strings, (pw->pw_passwd
333 && pw->pw_passwd[0]) ? pw->pw_passwd : "-");
334 #endif
335 break;
336 case 'u':
337 sprintf(tmp, "%li", (long) pw->pw_uid);
338 add_string(&strings, tmp);
339 break;
340 case 'g':
341 groups(pw, multi_char, verbose);
342 break;
343 case 'm':
344 if (stat(pw->pw_dir, &st) == -1) {
345 add_string(&strings, "!");
346 break;
349 sprintf(tmp, "%.4o", (unsigned) st.st_mode & ALLPERMS);
350 add_string(&strings, tmp);
351 break;
352 case 'i':
353 gecos_strings(pw->pw_gecos);
354 break;
355 default:
356 break;
359 p++;
362 *s = strings;
363 return EXIT_SUCCESS;
366 char *ui_module_options_init(char **defaults)
368 *defaults = "P";
369 return PASSWD_OPTION_STRING;
372 /* Check module option validity. */
373 int ui_module_options(int argc, char **argv)
375 int opt;
376 char *p = options;
378 while ((opt = getopt(argc, argv, PASSWD_OPTION_STRING)) != -1) {
379 switch (opt) {
380 case 'i':
381 if (parse_gecos_options(optarg))
382 return 1;
384 gecos_options = optarg;
385 break;
386 case 'P':
387 strncpy(options, PASSWD_OPTION_ORDER, sizeof(options));
388 gecos_options = "a";
389 return 0;
390 case 'l':
391 case 'p':
392 case 'u':
393 case 'g':
394 case 'c':
395 case 'e':
396 case 'd':
397 case 's':
398 case 'm':
399 break;
400 case '?':
401 warnx("passwd: invalid option -- %c", optopt);
402 default:
403 return 1;
406 *p++ = opt;
407 *p = '\0';
410 return 0;