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