Updates for 2.1.
[userinfo.git] / src / modules / passwd.c
blob467d2a590f17884eed52d49ae8376890eab0d1d3
1 /* $Id: passwd.c,v 1.1 2005-07-30 13:00:15 bjk Exp $ */
2 /*
3 Copyright (C) 2001-2005 Ben Kibbey <bjk@arbornet.org>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
24 #include <pwd.h>
25 #include <grp.h>
26 #include <errno.h>
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
32 #include "passwd.h"
34 #ifndef HAVE_STRSEP
35 #include "strsep.c"
36 #endif
38 #ifndef HAVE_ERR_H
39 #include "err.c"
40 #endif
42 void ui_module_init(int *chainable)
44 #ifdef DEBUG
45 fprintf(stderr, "%s: ui_module_init()\n", __FILE__);
46 #endif
49 * Keep the password file open if possible (*BSD).
51 #ifdef HAVE_SETPASSENT
52 setpassent(1);
53 #endif
55 if (getuid() == 0)
56 amroot = 1;
58 *chainable = 0;
59 return;
62 void ui_module_exit()
64 #ifdef DEBUG
65 fprintf(stderr, "%s: ui_module_exit()\n", __FILE__);
66 #endif
68 #ifdef HAVE_GETSPNAM
69 if (amroot)
70 endspent();
71 #endif
73 endpwent();
74 endgrent();
75 return;
78 /* See if the gecos options are valid. */
79 static int parse_gecos_options(const char *args)
81 int i = 0;
83 for (i = 0; i < strlen(args); i++) {
84 switch (args[i]) {
85 case 'n':
86 case '1':
87 case '2':
88 case '3':
89 case 'a':
90 break;
91 default:
92 return 1;
96 return 0;
99 /* Break up the gecos string into sections and add the sections to the output
100 * string array if needed. */
101 static void gecos_strings(char *str)
103 int i = 0;
104 char *buf;
105 const char *name, *first, *second, *third;
107 name = first = second = third = "-";
109 while ((buf = strsep(&str, ",")) != NULL) {
110 if (!buf[0])
111 continue;
113 switch (i++) {
114 case 0:
115 name = buf;
116 break;
117 case 1:
118 first = buf;
119 break;
120 case 2:
121 second = buf;
122 break;
123 case 3:
124 third = buf;
125 break;
126 default:
127 break;
131 for (i = 0; i < strlen(gecos_options); i++) {
132 switch (gecos_options[i]) {
133 case 'n':
134 add_string(&strings, name);
135 break;
136 case '1':
137 add_string(&strings, first);
138 break;
139 case '2':
140 add_string(&strings, second);
141 break;
142 case '3':
143 add_string(&strings, third);
144 break;
145 case 'a':
146 add_string(&strings, name);
147 add_string(&strings, first);
148 add_string(&strings, second);
149 add_string(&strings, third);
150 break;
151 default:
152 break;
156 return;
159 /* Get all groups that a user is a member of. The primary group will be the
160 * first added. */
161 static void groups(const struct passwd *pw, const int multi,
162 const int verbose)
164 struct group *grp;
165 char tmp[255];
166 char line[LINE_MAX];
167 gid_t primary = -1;
169 line[0] = '\0';
171 if ((grp = getgrgid(pw->pw_gid)) == NULL) {
172 snprintf(tmp, sizeof(tmp), "%li%s%s%s", (long) pw->pw_gid,
173 (verbose) ? "(" : "", (verbose) ? "!" : "",
174 (verbose) ? ")" : "");
175 add_string(&strings, tmp);
176 return;
179 primary = grp->gr_gid;
180 snprintf(tmp, sizeof(tmp), "%li%s%s%s%c", (long) pw->pw_gid,
181 (verbose) ? "(" : "", (verbose) ? grp->gr_name : "",
182 (verbose) ? ")" : "", multi);
183 strncat(line, tmp, sizeof(line));
185 #ifdef HAVE_SETGROUPENT
186 setgroupent(1);
187 #else
188 setgrent();
189 #endif
191 while ((grp = getgrent()) != NULL) {
192 char **members = grp->gr_mem;
194 while (*members) {
195 if (strcmp(*members++, pw->pw_name) == 0) {
196 if (grp->gr_gid == primary)
197 continue;
199 snprintf(tmp, sizeof(tmp), "%li%s%s%s%c", (long) grp->gr_gid,
200 (verbose) ? "(" : "", (verbose) ? grp->gr_name : "",
201 (verbose) ? ")" : "", multi);
202 strncat(line, tmp, sizeof(line));
208 * Trim the remaining multi-string deliminator.
210 line[strlen(line) - 1] = '\0';
212 add_string(&strings, line);
213 return;
216 /* This is output if the -h command line option is passed to the main program.
218 void ui_module_help()
220 #ifdef DEBUG
221 fprintf(stderr, "%s: ui_module_help()\n", __FILE__);
222 #endif
224 printf(" Password/Group file information [-P (-%s)]:\n",
225 PASSWD_OPTION_ORDER);
226 printf("\t-l login name\t\t");
227 printf("\t-p encrypted password\n");
228 printf("\t-u user id (uid)\t");
229 printf("\t-g group id (gid)\n");
230 printf("\t-c password change time");
231 printf("\t-e password expire time\n");
232 printf("\t-d home directory\t");
233 printf("\t-m home directory mode\n");
234 printf("\t-s login shell\n");
235 printf("\t-i gecos (any of [n]ame,[1]st,[2]nd,[3]rd or [a]ll)\n\n");
236 return;
239 /* This is the equivalent to main() only without argc and argv available. */
240 int ui_module_exec(char ***s, const struct passwd *pw, const int multi_char,
241 const int verbose, char *tf)
243 char *p = options;
244 struct stat st;
246 #ifdef HAVE_GETSPNAM
247 struct spwd *spwd = NULL;
248 #endif
250 #ifdef DEBUG
251 fprintf(stderr, "%s: ui_module_exec()\n", __FILE__);
252 #endif
254 #ifdef HAVE_GETSPNAM
255 if (amroot) {
256 if ((spwd = getspnam(pw->pw_name)) == NULL)
257 warnx("%s", "getspnam(): unknown error");
259 #endif
261 strings = *s;
263 while (*p) {
264 char tmp[32];
266 switch (*p) {
267 #ifdef HAVE_GETSPNAM
268 case 'c':
269 if (!amroot) {
270 add_string(&strings, "!");
271 break;
274 snprintf(tmp, sizeof(tmp), "%li", (long) spwd->sp_max);
275 add_string(&strings, tmp);
276 break;
277 case 'e':
278 if (!amroot) {
279 add_string(&strings, "!");
280 break;
283 snprintf(tmp, sizeof(tmp), "%li", (long) spwd->sp_expire);
284 add_string(&strings, tmp);
285 break;
286 #else
287 case 'c':
288 snprintf(tmp, sizeof(tmp), "%li", (long) pw->pw_change);
289 add_string(&strings, tmp);
290 break;
291 case 'e':
292 snprintf(tmp, sizeof(tmp), "%li", (long) pw->pw_expire);
293 add_string(&strings, tmp);
294 break;
295 #endif
296 case 'l':
297 add_string(&strings, pw->pw_name);
298 break;
299 case 'd':
300 add_string(&strings, (pw->pw_dir && pw->pw_dir[0]) ? pw->pw_dir : "-");
301 break;
302 case 's':
303 add_string(&strings, (pw->pw_shell && pw->pw_shell[0]) ? pw->pw_shell : "-");
304 break;
305 case 'p':
306 #ifdef HAVE_GETSPNAM
307 if (!amroot)
308 add_string(&strings, (pw->pw_passwd
309 && pw->pw_passwd[0]) ? pw->pw_passwd : "-");
310 else
311 add_string(&strings, (spwd->sp_pwdp
312 && spwd->sp_pwdp[0]) ? spwd->sp_pwdp : "-");
313 #else
314 add_string(&strings, (pw->pw_passwd
315 && pw->pw_passwd[0]) ? pw->pw_passwd : "-");
316 #endif
317 break;
318 case 'u':
319 sprintf(tmp, "%li", (long) pw->pw_uid);
320 add_string(&strings, tmp);
321 break;
322 case 'g':
323 groups(pw, multi_char, verbose);
324 break;
325 case 'm':
326 if (stat(pw->pw_dir, &st) == -1) {
327 add_string(&strings, "!");
328 break;
331 sprintf(tmp, "%.4o", (unsigned) st.st_mode & ALLPERMS);
332 add_string(&strings, tmp);
333 break;
334 case 'i':
335 gecos_strings(pw->pw_gecos);
336 break;
337 default:
338 break;
341 p++;
344 *s = strings;
345 return EXIT_SUCCESS;
348 char *ui_module_options_init(char **defaults)
350 *defaults = "P";
351 return PASSWD_OPTION_STRING;
354 /* Check module option validity. */
355 int ui_module_options(int argc, char **argv)
357 int opt;
358 char *p = options;
360 #ifdef DEBUG
361 fprintf(stderr, "%s: ui_module_options()\n", __FILE__);
362 #endif
364 while ((opt = getopt(argc, argv, PASSWD_OPTION_STRING)) != -1) {
365 switch (opt) {
366 case 'i':
367 gecos_options = optarg;
368 break;
369 case 'P':
370 case 'l':
371 case 'p':
372 case 'u':
373 case 'g':
374 case 'c':
375 case 'e':
376 case 'd':
377 case 's':
378 case 'm':
379 break;
380 case '?':
381 warnx("passwd: invalid option -- %c", optopt);
382 default:
383 return 1;
386 if (opt == 'i') {
387 if (parse_gecos_options(gecos_options))
388 return 1;
392 * This option '-P' sets all available options for this module.
394 if (opt == 'P') {
395 strncpy(options, PASSWD_OPTION_ORDER, sizeof(options));
396 gecos_options = "a";
397 break;
400 *p++ = opt;
401 *p = '\0';
404 return 0;