passwd.c revision 1.23 1 /* $NetBSD: passwd.c,v 1.23 2003/08/07 11:15:27 agc Exp $ */
2
3 /*
4 * Copyright (c) 1988, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __COPYRIGHT("@(#) Copyright (c) 1988, 1993, 1994\n\
35 The Regents of the University of California. All rights reserved.\n");
36 #endif /* not lint */
37
38 #ifndef lint
39 #if 0
40 static char sccsid[] = "from: @(#)passwd.c 8.3 (Berkeley) 4/2/94";
41 #else
42 __RCSID("$NetBSD: passwd.c,v 1.23 2003/08/07 11:15:27 agc Exp $");
43 #endif
44 #endif /* not lint */
45
46 #include <err.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <unistd.h>
51 #include <pwd.h>
52
53 #include "extern.h"
54
55 static struct pw_module_s {
56 const char *argv0;
57 const char *args;
58 const char *usage;
59 int (*pw_init) __P((const char *));
60 int (*pw_arg) __P((char, const char *));
61 int (*pw_arg_end) __P((void));
62 void (*pw_end) __P((void));
63
64 int (*pw_chpw) __P((const char*));
65 int invalid;
66 #define INIT_INVALID 1
67 #define ARG_INVALID 2
68 int use_class;
69 } pw_modules[] = {
70 #ifdef KERBEROS5
71 { NULL, "5ku:", "[-5] [-k] [-u principal]",
72 krb5_init, krb5_arg, krb5_arg_end, krb5_end, krb5_chpw, 0, 0 },
73 { "kpasswd", "5ku:", "[-5] [-k] [-u principal]",
74 krb5_init, krb5_arg, krb5_arg_end, krb5_end, krb5_chpw, 0, 0 },
75 #endif
76 #ifdef KERBEROS
77 { NULL, "4ku:i:r:", "[-4] [-k] [-u user] [-i instance] [-r realm]",
78 krb4_init, krb4_arg, krb4_arg_end, krb4_end, krb4_chpw, 0, 0 },
79 { "kpasswd", "4ku:i:r:", "[-4] [-k] [-u user] [-i instance] [-r realm]",
80 krb4_init, krb4_arg, krb4_arg_end, krb4_end, krb4_chpw, 0, 0 },
81 #endif
82 #ifdef YP
83 { NULL, "y", "[-y]",
84 yp_init, yp_arg, yp_arg_end, yp_end, yp_chpw, 0, 0 },
85 { "yppasswd", "", "[-y]",
86 yp_init, yp_arg, yp_arg_end, yp_end, yp_chpw, 0, 0 },
87 #endif
88 /* local */
89 { NULL, "l", "[-l]",
90 local_init, local_arg, local_arg_end, local_end, local_chpw, 0, 0 },
91
92 /* terminator */
93 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
94 };
95
96 void usage __P((void));
97
98 int main __P((int, char **));
99
100 int
101 main(argc, argv)
102 int argc;
103 char **argv;
104 {
105 int ch;
106 char *username;
107 char optstring[64]; /* if we ever get more than 64 args, shoot me. */
108 const char *curopt, *optopt;
109 int i, j;
110 int valid;
111 int use_always;
112
113 /* allow passwd modules to do argv[0] specific processing */
114 use_always = 0;
115 valid = 0;
116 for (i = 0; pw_modules[i].pw_init != NULL; i++) {
117 pw_modules[i].invalid = 0;
118 if (pw_modules[i].argv0) {
119 /*
120 * If we have a module that matches this progname, be
121 * sure that no modules but those that match this
122 * progname can be used. If we have a module that
123 * matches against a particular progname, but does NOT
124 * match this one, don't use that module.
125 */
126 if ((strcmp(getprogname(), pw_modules[i].argv0) == 0) &&
127 use_always == 0) {
128 for (j = 0; j < i; j++) {
129 pw_modules[j].invalid |= INIT_INVALID;
130 (*pw_modules[j].pw_end)();
131 }
132 use_always = 1;
133 } else if (use_always == 0)
134 pw_modules[i].invalid |= INIT_INVALID;
135 } else if (use_always)
136 pw_modules[i].invalid |= INIT_INVALID;
137
138 if (pw_modules[i].invalid)
139 continue;
140
141 pw_modules[i].invalid |=
142 (*pw_modules[i].pw_init)(getprogname()) ?
143 /* zero on success, non-zero on error */
144 INIT_INVALID : 0;
145
146 if (! pw_modules[i].invalid)
147 valid = 1;
148 }
149
150 if (valid == 0)
151 errx(1, "Can't change password.");
152
153 /* Build the option string from the individual modules' option
154 * strings. Note that two modules can share a single option
155 * letter. */
156 optstring[0] = '\0';
157 j = 0;
158 for (i = 0; pw_modules[i].pw_init != NULL; i++) {
159 if (pw_modules[i].invalid)
160 continue;
161
162 curopt = pw_modules[i].args;
163 while (*curopt != '\0') {
164 if ((optopt = strchr(optstring, *curopt)) == NULL) {
165 optstring[j++] = *curopt;
166 if (curopt[1] == ':') {
167 curopt++;
168 optstring[j++] = *curopt;
169 }
170 optstring[j] = '\0';
171 } else if ((optopt[1] == ':' && curopt[1] != ':') ||
172 (optopt[1] != ':' && curopt[1] == ':')) {
173 errx(1, "NetBSD ERROR! Different password "
174 "modules have two different ideas about "
175 "%c argument format.", curopt[0]);
176 }
177 curopt++;
178 }
179 }
180
181 while ((ch = getopt(argc, argv, optstring)) != -1)
182 {
183 valid = 0;
184 for (i = 0; pw_modules[i].pw_init != NULL; i++) {
185 if (pw_modules[i].invalid)
186 continue;
187 if ((optopt = strchr(pw_modules[i].args, ch)) != NULL) {
188 j = (optopt[1] == ':') ?
189 ! (*pw_modules[i].pw_arg)(ch, optarg) :
190 ! (*pw_modules[i].pw_arg)(ch, NULL);
191 if (j != 0)
192 pw_modules[i].invalid |= ARG_INVALID;
193 if (pw_modules[i].invalid)
194 (*pw_modules[i].pw_end)();
195 } else {
196 /* arg doesn't match this module */
197 pw_modules[i].invalid |= ARG_INVALID;
198 (*pw_modules[i].pw_end)();
199 }
200 if (! pw_modules[i].invalid)
201 valid = 1;
202 }
203 if (! valid) {
204 usage();
205 exit(1);
206 }
207 }
208
209 /* select which module to use to actually change the password. */
210 use_always = 0;
211 valid = 0;
212 for (i = 0; pw_modules[i].pw_init != NULL; i++)
213 if (! pw_modules[i].invalid) {
214 pw_modules[i].use_class = (*pw_modules[i].pw_arg_end)();
215 if (pw_modules[i].use_class != PW_DONT_USE)
216 valid = 1;
217 if (pw_modules[i].use_class == PW_USE_FORCE)
218 use_always = 1;
219 }
220
221
222 if (! valid)
223 /* hang the DJ */
224 errx(1, "No valid password module specified.");
225
226 argc -= optind;
227 argv += optind;
228
229 username = getlogin();
230 if (username == NULL)
231 errx(1, "who are you ??");
232
233 switch(argc) {
234 case 0:
235 break;
236 case 1:
237 username = argv[0];
238 break;
239 default:
240 usage();
241 exit(1);
242 }
243
244 /* allow for fallback to other chpw() methods. */
245 for (i = 0; pw_modules[i].pw_init != NULL; i++) {
246 if (pw_modules[i].invalid)
247 continue;
248 if ((use_always && pw_modules[i].use_class == PW_USE_FORCE) ||
249 (!use_always && pw_modules[i].use_class == PW_USE)) {
250 valid = (*pw_modules[i].pw_chpw)(username);
251 (*pw_modules[i].pw_end)();
252 if (valid >= 0)
253 exit(valid);
254 /* return value < 0 indicates continuation. */
255 }
256 }
257 exit(1);
258 }
259
260 void
261 usage()
262 {
263 int i;
264
265 fprintf(stderr, "usage:\n");
266 for (i = 0; pw_modules[i].pw_init != NULL; i++)
267 if (! (pw_modules[i].invalid & INIT_INVALID))
268 fprintf(stderr, "\t%s %s [user]\n", getprogname(),
269 pw_modules[i].usage);
270 exit(1);
271 }
272