More checks for limits.h and LINE_MAX.
[userinfo.git] / src / modules / passwd.c
blob6c6be87d658d2aff9d0fbc11878d5b82ced5c67f
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 #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 endgrent();
114 /* See if the gecos options are valid. */
115 static int parse_gecos_options(const char *args)
117 int i = 0;
119 for (i = 0; i < strlen(args); i++) {
120 switch (args[i]) {
121 case 'n':
122 case '1':
123 case '2':
124 case '3':
125 case 'a':
126 break;
127 default:
128 return 1;
132 return 0;
135 /* Break up the gecos string into sections and add the sections to the output
136 * string array if needed. */
137 static void gecos_strings(char *str)
139 int i = 0;
140 char *buf;
141 const char *name, *first, *second, *third;
143 name = first = second = third = "-";
145 while ((buf = strsep(&str, ",")) != NULL) {
146 if (!buf[0])
147 continue;
149 switch (i++) {
150 case 0:
151 name = buf;
152 break;
153 case 1:
154 first = buf;
155 break;
156 case 2:
157 second = buf;
158 break;
159 case 3:
160 third = buf;
161 break;
162 default:
163 break;
167 for (i = 0; i < strlen(gecos_options); i++) {
168 switch (gecos_options[i]) {
169 case 'n':
170 add_string(&strings, name);
171 break;
172 case '1':
173 add_string(&strings, first);
174 break;
175 case '2':
176 add_string(&strings, second);
177 break;
178 case '3':
179 add_string(&strings, third);
180 break;
181 case 'a':
182 add_string(&strings, name);
183 add_string(&strings, first);
184 add_string(&strings, second);
185 add_string(&strings, third);
186 break;
187 default:
188 break;
193 /* Get all groups that a user is a member of. The primary group will be the
194 * first added. */
195 static void groups(const struct passwd *pw, const int multi,
196 const int verbose)
198 struct group *grp;
199 char tmp[255];
200 char line[LINE_MAX];
201 gid_t primary = -1;
203 line[0] = '\0';
205 if ((grp = getgrgid(pw->pw_gid)) == NULL) {
206 snprintf(tmp, sizeof(tmp), "%li%s%s%s", (long) pw->pw_gid,
207 (verbose) ? "(" : "", (verbose) ? "!" : "",
208 (verbose) ? ")" : "");
209 add_string(&strings, tmp);
210 return;
213 primary = grp->gr_gid;
214 snprintf(tmp, sizeof(tmp), "%li%s%s%s%c", (long) pw->pw_gid,
215 (verbose) ? "(" : "", (verbose) ? grp->gr_name : "",
216 (verbose) ? ")" : "", multi);
217 safe_strncat(line, tmp, sizeof(line));
219 #ifdef HAVE_SETGROUPENT
220 setgroupent(1);
221 #else
222 setgrent();
223 #endif
225 while ((grp = getgrent()) != NULL) {
226 char **members = grp->gr_mem;
228 while (*members) {
229 if (strcmp(*members++, pw->pw_name) == 0) {
230 if (grp->gr_gid == primary)
231 continue;
233 snprintf(tmp, sizeof(tmp), "%li%s%s%s%c", (long) grp->gr_gid,
234 (verbose) ? "(" : "", (verbose) ? grp->gr_name : "",
235 (verbose) ? ")" : "", multi);
236 safe_strncat(line, tmp, sizeof(line));
242 * Trim the remaining multi-string deliminator.
244 line[strlen(line) - 1] = '\0';
246 add_string(&strings, line);
249 /* This is output if the -h command line option is passed to the main program.
251 void ui_module_help()
253 printf(" Password/Group file information [-P (-%s)]:\n",
254 PASSWD_OPTION_ORDER);
255 printf("\t-l login name\t\t");
256 printf("\t-p encrypted password\n");
257 printf("\t-u user id (uid)\t");
258 printf("\t-g group id (gid)\n");
259 printf("\t-c password change time");
260 printf("\t-e password expire time\n");
261 printf("\t-d home directory\t");
262 printf("\t-m home directory mode\n");
263 printf("\t-s login shell\n");
264 printf("\t-i gecos (any of [n]ame,[1]st,[2]nd,[3]rd or [a]ll)\n\n");
267 /* This is the equivalent to main() only without argc and argv available. */
268 int ui_module_exec(char ***s, const struct passwd *pw, const int multi_char,
269 const int verbose, char *tf)
271 char *p = options;
272 struct stat st;
274 #ifdef HAVE_GETSPNAM
275 struct spwd *spwd = NULL;
276 #endif
278 #ifdef HAVE_GETSPNAM
279 if (amroot) {
280 if ((spwd = getspnam(pw->pw_name)) == NULL)
281 warnx("%s", "getspnam(): unknown error");
283 #endif
285 strings = *s;
287 while (*p) {
288 char tmp[256];
290 switch (*p) {
291 #ifdef HAVE_GETSPNAM
292 case 'c':
293 if (!amroot) {
294 add_string(&strings, "!");
295 break;
298 snprintf(tmp, sizeof(tmp), "%li", (long) spwd->sp_max);
299 add_string(&strings, tmp);
300 break;
301 case 'e':
302 if (!amroot) {
303 add_string(&strings, "!");
304 break;
307 snprintf(tmp, sizeof(tmp), "%li", (long) spwd->sp_expire);
308 add_string(&strings, tmp);
309 break;
310 #else
311 case 'c':
312 snprintf(tmp, sizeof(tmp), "%li", (long) pw->pw_change);
313 add_string(&strings, tmp);
314 break;
315 case 'e':
316 snprintf(tmp, sizeof(tmp), "%li", (long) pw->pw_expire);
317 add_string(&strings, tmp);
318 break;
319 #endif
320 case 'l':
321 add_string(&strings, pw->pw_name);
322 break;
323 case 'd':
324 add_string(&strings, (pw->pw_dir && pw->pw_dir[0]) ? pw->pw_dir : "-");
325 break;
326 case 's':
327 add_string(&strings, (pw->pw_shell && pw->pw_shell[0]) ? pw->pw_shell : "-");
328 break;
329 case 'p':
330 #ifdef HAVE_GETSPNAM
331 if (!amroot)
332 add_string(&strings, (pw->pw_passwd
333 && pw->pw_passwd[0]) ? pw->pw_passwd : "-");
334 else
335 add_string(&strings, (spwd->sp_pwdp
336 && spwd->sp_pwdp[0]) ? spwd->sp_pwdp : "-");
337 #else
338 add_string(&strings, (pw->pw_passwd
339 && pw->pw_passwd[0]) ? pw->pw_passwd : "-");
340 #endif
341 break;
342 case 'u':
343 sprintf(tmp, "%li", (long) pw->pw_uid);
344 add_string(&strings, tmp);
345 break;
346 case 'g':
347 groups(pw, multi_char, verbose);
348 break;
349 case 'm':
350 if (stat(pw->pw_dir, &st) == -1) {
351 add_string(&strings, "!");
352 break;
355 sprintf(tmp, "%.4o", (unsigned) st.st_mode & ALLPERMS);
356 add_string(&strings, tmp);
357 break;
358 case 'i':
359 gecos_strings(pw->pw_gecos);
360 break;
361 default:
362 break;
365 p++;
368 *s = strings;
369 return EXIT_SUCCESS;
372 char *ui_module_options_init(char **defaults)
374 *defaults = "P";
375 return PASSWD_OPTION_STRING;
378 /* Check module option validity. */
379 int ui_module_options(int argc, char **argv)
381 int opt;
382 char *p = options;
384 while ((opt = getopt(argc, argv, PASSWD_OPTION_STRING)) != -1) {
385 switch (opt) {
386 case 'i':
387 if (parse_gecos_options(optarg))
388 return 1;
390 gecos_options = optarg;
391 break;
392 case 'P':
393 strncpy(options, PASSWD_OPTION_ORDER, sizeof(options));
394 gecos_options = "a";
395 return 0;
396 case 'l':
397 case 'p':
398 case 'u':
399 case 'g':
400 case 'c':
401 case 'e':
402 case 'd':
403 case 's':
404 case 'm':
405 break;
406 case '?':
407 warnx("passwd: invalid option -- %c", optopt);
408 default:
409 return 1;
412 *p++ = opt;
413 *p = '\0';
416 return 0;