Updated email address and copyright.
[userinfo.git] / src / modules / passwd.c
blobce9d990fa0cf3e3438bd17d7f656d29aa5432628
1 /*
2 Copyright (C) 2001-2006 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 02111-1307 USA
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 #include <pwd.h>
24 #include <grp.h>
25 #include <errno.h>
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
31 #include "passwd.h"
33 #ifndef HAVE_STRSEP
34 #include "../strsep.c"
35 #endif
37 #ifndef HAVE_ERR_H
38 #include "../err.c"
39 #endif
41 void ui_module_init(int *chainable)
43 #ifdef DEBUG
44 fprintf(stderr, "%s: ui_module_init()\n", __FILE__);
45 #endif
48 * Keep the password file open if possible (*BSD).
50 #ifdef HAVE_SETPASSENT
51 setpassent(1);
52 #endif
54 if (getuid() == 0)
55 amroot = 1;
57 *chainable = 0;
58 return;
61 void ui_module_exit()
63 #ifdef DEBUG
64 fprintf(stderr, "%s: ui_module_exit()\n", __FILE__);
65 #endif
67 #ifdef HAVE_GETSPNAM
68 if (amroot)
69 endspent();
70 #endif
72 endpwent();
73 endgrent();
74 return;
77 /* See if the gecos options are valid. */
78 static int parse_gecos_options(const char *args)
80 int i = 0;
82 for (i = 0; i < strlen(args); i++) {
83 switch (args[i]) {
84 case 'n':
85 case '1':
86 case '2':
87 case '3':
88 case 'a':
89 break;
90 default:
91 return 1;
95 return 0;
98 /* Break up the gecos string into sections and add the sections to the output
99 * string array if needed. */
100 static void gecos_strings(char *str)
102 int i = 0;
103 char *buf;
104 const char *name, *first, *second, *third;
106 name = first = second = third = "-";
108 while ((buf = strsep(&str, ",")) != NULL) {
109 if (!buf[0])
110 continue;
112 switch (i++) {
113 case 0:
114 name = buf;
115 break;
116 case 1:
117 first = buf;
118 break;
119 case 2:
120 second = buf;
121 break;
122 case 3:
123 third = buf;
124 break;
125 default:
126 break;
130 for (i = 0; i < strlen(gecos_options); i++) {
131 switch (gecos_options[i]) {
132 case 'n':
133 add_string(&strings, name);
134 break;
135 case '1':
136 add_string(&strings, first);
137 break;
138 case '2':
139 add_string(&strings, second);
140 break;
141 case '3':
142 add_string(&strings, third);
143 break;
144 case 'a':
145 add_string(&strings, name);
146 add_string(&strings, first);
147 add_string(&strings, second);
148 add_string(&strings, third);
149 break;
150 default:
151 break;
155 return;
158 /* Get all groups that a user is a member of. The primary group will be the
159 * first added. */
160 static void groups(const struct passwd *pw, const int multi,
161 const int verbose)
163 struct group *grp;
164 char tmp[255];
165 char line[LINE_MAX];
166 gid_t primary = -1;
168 line[0] = '\0';
170 if ((grp = getgrgid(pw->pw_gid)) == NULL) {
171 snprintf(tmp, sizeof(tmp), "%li%s%s%s", (long) pw->pw_gid,
172 (verbose) ? "(" : "", (verbose) ? "!" : "",
173 (verbose) ? ")" : "");
174 add_string(&strings, tmp);
175 return;
178 primary = grp->gr_gid;
179 snprintf(tmp, sizeof(tmp), "%li%s%s%s%c", (long) pw->pw_gid,
180 (verbose) ? "(" : "", (verbose) ? grp->gr_name : "",
181 (verbose) ? ")" : "", multi);
182 strncat(line, tmp, sizeof(line));
184 #ifdef HAVE_SETGROUPENT
185 setgroupent(1);
186 #else
187 setgrent();
188 #endif
190 while ((grp = getgrent()) != NULL) {
191 char **members = grp->gr_mem;
193 while (*members) {
194 if (strcmp(*members++, pw->pw_name) == 0) {
195 if (grp->gr_gid == primary)
196 continue;
198 snprintf(tmp, sizeof(tmp), "%li%s%s%s%c", (long) grp->gr_gid,
199 (verbose) ? "(" : "", (verbose) ? grp->gr_name : "",
200 (verbose) ? ")" : "", multi);
201 strncat(line, tmp, sizeof(line));
207 * Trim the remaining multi-string deliminator.
209 line[strlen(line) - 1] = '\0';
211 add_string(&strings, line);
212 return;
215 /* This is output if the -h command line option is passed to the main program.
217 void ui_module_help()
219 #ifdef DEBUG
220 fprintf(stderr, "%s: ui_module_help()\n", __FILE__);
221 #endif
223 printf(" Password/Group file information [-P (-%s)]:\n",
224 PASSWD_OPTION_ORDER);
225 printf("\t-l login name\t\t");
226 printf("\t-p encrypted password\n");
227 printf("\t-u user id (uid)\t");
228 printf("\t-g group id (gid)\n");
229 printf("\t-c password change time");
230 printf("\t-e password expire time\n");
231 printf("\t-d home directory\t");
232 printf("\t-m home directory mode\n");
233 printf("\t-s login shell\n");
234 printf("\t-i gecos (any of [n]ame,[1]st,[2]nd,[3]rd or [a]ll)\n\n");
235 return;
238 /* This is the equivalent to main() only without argc and argv available. */
239 int ui_module_exec(char ***s, const struct passwd *pw, const int multi_char,
240 const int verbose, char *tf)
242 char *p = options;
243 struct stat st;
245 #ifdef HAVE_GETSPNAM
246 struct spwd *spwd = NULL;
247 #endif
249 #ifdef DEBUG
250 fprintf(stderr, "%s: ui_module_exec()\n", __FILE__);
251 #endif
253 #ifdef HAVE_GETSPNAM
254 if (amroot) {
255 if ((spwd = getspnam(pw->pw_name)) == NULL)
256 warnx("%s", "getspnam(): unknown error");
258 #endif
260 strings = *s;
262 while (*p) {
263 char tmp[32];
265 switch (*p) {
266 #ifdef HAVE_GETSPNAM
267 case 'c':
268 if (!amroot) {
269 add_string(&strings, "!");
270 break;
273 snprintf(tmp, sizeof(tmp), "%li", (long) spwd->sp_max);
274 add_string(&strings, tmp);
275 break;
276 case 'e':
277 if (!amroot) {
278 add_string(&strings, "!");
279 break;
282 snprintf(tmp, sizeof(tmp), "%li", (long) spwd->sp_expire);
283 add_string(&strings, tmp);
284 break;
285 #else
286 case 'c':
287 snprintf(tmp, sizeof(tmp), "%li", (long) pw->pw_change);
288 add_string(&strings, tmp);
289 break;
290 case 'e':
291 snprintf(tmp, sizeof(tmp), "%li", (long) pw->pw_expire);
292 add_string(&strings, tmp);
293 break;
294 #endif
295 case 'l':
296 add_string(&strings, pw->pw_name);
297 break;
298 case 'd':
299 add_string(&strings, (pw->pw_dir && pw->pw_dir[0]) ? pw->pw_dir : "-");
300 break;
301 case 's':
302 add_string(&strings, (pw->pw_shell && pw->pw_shell[0]) ? pw->pw_shell : "-");
303 break;
304 case 'p':
305 #ifdef HAVE_GETSPNAM
306 if (!amroot)
307 add_string(&strings, (pw->pw_passwd
308 && pw->pw_passwd[0]) ? pw->pw_passwd : "-");
309 else
310 add_string(&strings, (spwd->sp_pwdp
311 && spwd->sp_pwdp[0]) ? spwd->sp_pwdp : "-");
312 #else
313 add_string(&strings, (pw->pw_passwd
314 && pw->pw_passwd[0]) ? pw->pw_passwd : "-");
315 #endif
316 break;
317 case 'u':
318 sprintf(tmp, "%li", (long) pw->pw_uid);
319 add_string(&strings, tmp);
320 break;
321 case 'g':
322 groups(pw, multi_char, verbose);
323 break;
324 case 'm':
325 if (stat(pw->pw_dir, &st) == -1) {
326 add_string(&strings, "!");
327 break;
330 sprintf(tmp, "%.4o", (unsigned) st.st_mode & ALLPERMS);
331 add_string(&strings, tmp);
332 break;
333 case 'i':
334 gecos_strings(pw->pw_gecos);
335 break;
336 default:
337 break;
340 p++;
343 *s = strings;
344 return EXIT_SUCCESS;
347 char *ui_module_options_init(char **defaults)
349 *defaults = "P";
350 return PASSWD_OPTION_STRING;
353 /* Check module option validity. */
354 int ui_module_options(int argc, char **argv)
356 int opt;
357 char *p = options;
359 #ifdef DEBUG
360 fprintf(stderr, "%s: ui_module_options()\n", __FILE__);
361 #endif
363 while ((opt = getopt(argc, argv, PASSWD_OPTION_STRING)) != -1) {
364 switch (opt) {
365 case 'i':
366 gecos_options = optarg;
367 break;
368 case 'P':
369 case 'l':
370 case 'p':
371 case 'u':
372 case 'g':
373 case 'c':
374 case 'e':
375 case 'd':
376 case 's':
377 case 'm':
378 break;
379 case '?':
380 warnx("passwd: invalid option -- %c", optopt);
381 default:
382 return 1;
385 if (opt == 'i') {
386 if (parse_gecos_options(gecos_options))
387 return 1;
391 * This option '-P' sets all available options for this module.
393 if (opt == 'P') {
394 strncpy(options, PASSWD_OPTION_ORDER, sizeof(options));
395 gecos_options = "a";
396 break;
399 *p++ = opt;
400 *p = '\0';
403 return 0;