7c6029dd614ee4315bc45ef198d76610116b0c28
[userinfo.git] / src / modules / passwd.c
blob7c6029dd614ee4315bc45ef198d76610116b0c28
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 #ifndef ALLPERMS
64 #define ALLPERMS (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)
65 #endif
67 /* This is the order of options when the 'P' option is specified. It selects
68 * all available options. */
69 #define PASSWD_OPTION_ORDER "lpugicedsm"
70 #define PASSWD_OPTION_STRING "Plpugcedsmi:"
72 static int amroot;
73 static char **strings;
74 static char options[11]; /* NULL terminated. */
75 static char *gecos_options;
77 void add_string(char ***, const char *);
78 char *stamp(time_t, const char *);
79 char *safe_strncat(char *, const char *, size_t);
81 void ui_module_init(int *chainable)
84 * Keep the password file open if possible (*BSD).
86 #ifdef HAVE_SETPASSENT
87 setpassent(1);
88 #endif
90 if (getuid() == 0)
91 amroot = 1;
93 *chainable = 0;
96 void ui_module_exit()
98 #ifdef HAVE_GETSPNAM
99 if (amroot)
100 endspent();
101 #endif
103 endpwent();
104 endgrent();
107 /* See if the gecos options are valid. */
108 static int parse_gecos_options(const char *args)
110 int i = 0;
112 for (i = 0; i < strlen(args); i++) {
113 switch (args[i]) {
114 case 'n':
115 case '1':
116 case '2':
117 case '3':
118 case 'a':
119 break;
120 default:
121 return 1;
125 return 0;
128 /* Break up the gecos string into sections and add the sections to the output
129 * string array if needed. */
130 static void gecos_strings(char *str)
132 int i = 0;
133 char *buf;
134 const char *name, *first, *second, *third;
136 name = first = second = third = "-";
138 while ((buf = strsep(&str, ",")) != NULL) {
139 if (!buf[0])
140 continue;
142 switch (i++) {
143 case 0:
144 name = buf;
145 break;
146 case 1:
147 first = buf;
148 break;
149 case 2:
150 second = buf;
151 break;
152 case 3:
153 third = buf;
154 break;
155 default:
156 break;
160 for (i = 0; i < strlen(gecos_options); i++) {
161 switch (gecos_options[i]) {
162 case 'n':
163 add_string(&strings, name);
164 break;
165 case '1':
166 add_string(&strings, first);
167 break;
168 case '2':
169 add_string(&strings, second);
170 break;
171 case '3':
172 add_string(&strings, third);
173 break;
174 case 'a':
175 add_string(&strings, name);
176 add_string(&strings, first);
177 add_string(&strings, second);
178 add_string(&strings, third);
179 break;
180 default:
181 break;
186 /* Get all groups that a user is a member of. The primary group will be the
187 * first added. */
188 static void groups(const struct passwd *pw, const int multi,
189 const int verbose)
191 struct group *grp;
192 char tmp[255];
193 char line[LINE_MAX];
194 gid_t primary = -1;
196 line[0] = '\0';
198 if ((grp = getgrgid(pw->pw_gid)) == NULL) {
199 snprintf(tmp, sizeof(tmp), "%li%s%s%s", (long) pw->pw_gid,
200 (verbose) ? "(" : "", (verbose) ? "!" : "",
201 (verbose) ? ")" : "");
202 add_string(&strings, tmp);
203 return;
206 primary = grp->gr_gid;
207 snprintf(tmp, sizeof(tmp), "%li%s%s%s%c", (long) pw->pw_gid,
208 (verbose) ? "(" : "", (verbose) ? grp->gr_name : "",
209 (verbose) ? ")" : "", multi);
210 safe_strncat(line, tmp, sizeof(line));
212 #ifdef HAVE_SETGROUPENT
213 setgroupent(1);
214 #else
215 setgrent();
216 #endif
218 while ((grp = getgrent()) != NULL) {
219 char **members = grp->gr_mem;
221 while (*members) {
222 if (strcmp(*members++, pw->pw_name) == 0) {
223 if (grp->gr_gid == primary)
224 continue;
226 snprintf(tmp, sizeof(tmp), "%li%s%s%s%c", (long) grp->gr_gid,
227 (verbose) ? "(" : "", (verbose) ? grp->gr_name : "",
228 (verbose) ? ")" : "", multi);
229 safe_strncat(line, tmp, sizeof(line));
235 * Trim the remaining multi-string deliminator.
237 line[strlen(line) - 1] = '\0';
239 add_string(&strings, line);
242 /* This is output if the -h command line option is passed to the main program.
244 void ui_module_help()
246 printf(" Password/Group file information [-P (-%s)]:\n",
247 PASSWD_OPTION_ORDER);
248 printf("\t-l login name\t\t");
249 printf("\t-p encrypted password\n");
250 printf("\t-u user id (uid)\t");
251 printf("\t-g group id (gid)\n");
252 printf("\t-c password change time");
253 printf("\t-e password expire time\n");
254 printf("\t-d home directory\t");
255 printf("\t-m home directory mode\n");
256 printf("\t-s login shell\n");
257 printf("\t-i gecos (any of [n]ame,[1]st,[2]nd,[3]rd or [a]ll)\n\n");
260 /* This is the equivalent to main() only without argc and argv available. */
261 int ui_module_exec(char ***s, const struct passwd *pw, const int multi_char,
262 const int verbose, char *tf)
264 char *p = options;
265 struct stat st;
267 #ifdef HAVE_GETSPNAM
268 struct spwd *spwd = NULL;
269 #endif
271 #ifdef HAVE_GETSPNAM
272 if (amroot) {
273 if ((spwd = getspnam(pw->pw_name)) == NULL)
274 warnx("%s", "getspnam(): unknown error");
276 #endif
278 strings = *s;
280 while (*p) {
281 char tmp[256];
283 switch (*p) {
284 #ifdef HAVE_GETSPNAM
285 case 'c':
286 if (!amroot) {
287 add_string(&strings, "!");
288 break;
291 snprintf(tmp, sizeof(tmp), "%li", (long) spwd->sp_max);
292 add_string(&strings, tmp);
293 break;
294 case 'e':
295 if (!amroot) {
296 add_string(&strings, "!");
297 break;
300 snprintf(tmp, sizeof(tmp), "%li", (long) spwd->sp_expire);
301 add_string(&strings, tmp);
302 break;
303 #else
304 case 'c':
305 snprintf(tmp, sizeof(tmp), "%li", (long) pw->pw_change);
306 add_string(&strings, tmp);
307 break;
308 case 'e':
309 snprintf(tmp, sizeof(tmp), "%li", (long) pw->pw_expire);
310 add_string(&strings, tmp);
311 break;
312 #endif
313 case 'l':
314 add_string(&strings, pw->pw_name);
315 break;
316 case 'd':
317 add_string(&strings, (pw->pw_dir && pw->pw_dir[0]) ? pw->pw_dir : "-");
318 break;
319 case 's':
320 add_string(&strings, (pw->pw_shell && pw->pw_shell[0]) ? pw->pw_shell : "-");
321 break;
322 case 'p':
323 #ifdef HAVE_GETSPNAM
324 if (!amroot)
325 add_string(&strings, (pw->pw_passwd
326 && pw->pw_passwd[0]) ? pw->pw_passwd : "-");
327 else
328 add_string(&strings, (spwd->sp_pwdp
329 && spwd->sp_pwdp[0]) ? spwd->sp_pwdp : "-");
330 #else
331 add_string(&strings, (pw->pw_passwd
332 && pw->pw_passwd[0]) ? pw->pw_passwd : "-");
333 #endif
334 break;
335 case 'u':
336 sprintf(tmp, "%li", (long) pw->pw_uid);
337 add_string(&strings, tmp);
338 break;
339 case 'g':
340 groups(pw, multi_char, verbose);
341 break;
342 case 'm':
343 if (stat(pw->pw_dir, &st) == -1) {
344 add_string(&strings, "!");
345 break;
348 sprintf(tmp, "%.4o", (unsigned) st.st_mode & ALLPERMS);
349 add_string(&strings, tmp);
350 break;
351 case 'i':
352 gecos_strings(pw->pw_gecos);
353 break;
354 default:
355 break;
358 p++;
361 *s = strings;
362 return EXIT_SUCCESS;
365 char *ui_module_options_init(char **defaults)
367 *defaults = "P";
368 return PASSWD_OPTION_STRING;
371 /* Check module option validity. */
372 int ui_module_options(int argc, char **argv)
374 int opt;
375 char *p = options;
377 while ((opt = getopt(argc, argv, PASSWD_OPTION_STRING)) != -1) {
378 switch (opt) {
379 case 'i':
380 if (parse_gecos_options(optarg))
381 return 1;
383 gecos_options = optarg;
384 break;
385 case 'P':
386 strncpy(options, PASSWD_OPTION_ORDER, sizeof(options));
387 gecos_options = "a";
388 return 0;
389 case 'l':
390 case 'p':
391 case 'u':
392 case 'g':
393 case 'c':
394 case 'e':
395 case 'd':
396 case 's':
397 case 'm':
398 break;
399 case '?':
400 warnx("passwd: invalid option -- %c", optopt);
401 default:
402 return 1;
405 *p++ = opt;
406 *p = '\0';
409 return 0;