1/* Add passphrases to the tpasswd file. Use the last entry in the config 2file by default or a particular one specified by index. */ 3 4#include <stdio.h> 5#include <stdlib.h> 6#include <string.h> 7#include <unistd.h> 8#include <sys/types.h> 9#include <sys/stat.h> 10#include "config.h" 11#include "t_pwd.h" 12#include "t_read.h" 13#include "t_sha.h" 14#include "t_defines.h" 15 16char *Progname; 17char Usage[] = "usage: %s [-n configindex] [-p passfile] user\n"; 18#define USAGE() fprintf(stderr, Usage, Progname) 19 20void doit(char *); 21 22int Configindex = -1; 23char *Passfile = DEFAULT_PASSWD; 24 25int main(int argc, char **argv) 26{ 27 int c; 28 29 Progname = *argv; 30 31 /* Parse option arguments. */ 32 33 while ((c = getopt(argc, argv, "n:p:")) != EOF) { 34 switch (c) { 35 36 case 'n': 37 Configindex = atoi(optarg); 38 break; 39 40 case 'p': 41 Passfile = optarg; 42 break; 43 44 default: 45 USAGE(); 46 exit(1); 47 } 48 } 49 argc -= optind; 50 argv += optind; 51 52 if (argc != 1) { 53 USAGE(); 54 exit(1); 55 } 56 doit(argv[0]); 57 58 return 0; 59} 60 61void doit(char *name) 62{ 63 char passphrase[128], passphrase1[128]; 64 FILE *f; 65 struct t_confent *tcent; 66 struct t_pw eps_passwd; 67 68 /* Get the config entry. */ 69 70 if (Configindex <= 0) { 71 Configindex = t_getprecount(); 72 } 73 tcent = gettcid(Configindex); 74 if (tcent == NULL) { 75 fprintf(stderr, "Invalid configuration file entry.\n"); 76 exit(1); 77 } 78 79 /* Ask for the passphrase twice. */ 80 81 printf("Setting passphrase for %s\n", name); 82 83 if (t_getpass(passphrase, sizeof(passphrase), "Enter passphrase: ") < 0) { 84 exit(1); 85 } 86 if (t_getpass(passphrase1, sizeof(passphrase1), "Verify: ") < 0) { 87 exit(1); 88 } 89 if (strcmp(passphrase, passphrase1) != 0) { 90 fprintf(stderr, "mismatch\n"); 91 exit(1); 92 } 93 94 /* Create the passphrase verifier. */ 95 96 t_makepwent(&eps_passwd, name, passphrase, NULL, tcent); 97 98 /* Don't need these anymore. */ 99 100 memset(passphrase, 0, sizeof(passphrase)); 101 memset(passphrase1, 0, sizeof(passphrase1)); 102 103 /* See if the passphrase file is there; create it if not. */ 104 105 if ((f = fopen(Passfile, "r+")) == NULL) { 106 creat(Passfile, 0400); 107 } else { 108 fclose(f); 109 } 110 111 /* Change the passphrase. */ 112 113 if (t_changepw(Passfile, &eps_passwd.pebuf) < 0) { 114 fprintf(stderr, "Error changing passphrase\n"); 115 exit(1); 116 } 117} 118 119/* TODO: Implement a more general method to handle delete/change */ 120 121_TYPE( int ) 122t_changepw(pwname, diff) 123 const char * pwname; 124 const struct t_pwent * diff; 125{ 126 char * bakfile; 127 char * bakfile2; 128 struct stat st; 129 FILE * passfp; 130 FILE * bakfp; 131 132 if(pwname == NULL) 133 pwname = DEFAULT_PASSWD; 134 135 if((passfp = fopen(pwname, "rb")) == NULL || fstat(fileno(passfp), &st) < 0) 136 return -1; 137 138 if((bakfile = malloc(strlen(pwname) + 5)) == NULL) { 139 fclose(passfp); 140 return -1; 141 } 142 else if((bakfile2 = malloc(strlen(pwname) + 5)) == NULL) { 143 fclose(passfp); 144 free(bakfile); 145 return -1; 146 } 147 148 sprintf(bakfile, "%s.bak", pwname); 149 sprintf(bakfile2, "%s.sav", pwname); 150 151 if((bakfp = fopen(bakfile2, "wb")) == NULL && 152 (unlink(bakfile2) < 0 || (bakfp = fopen(bakfile2, "wb")) == NULL)) { 153 fclose(passfp); 154 free(bakfile); 155 free(bakfile2); 156 return -1; 157 } 158 159#ifdef NO_FCHMOD 160 chmod(bakfile2, st.st_mode & 0777); 161#else 162 fchmod(fileno(bakfp), st.st_mode & 0777); 163#endif 164 165 t_pwcopy(bakfp, passfp, diff); 166 167 fclose(bakfp); 168 fclose(passfp); 169 170#ifdef USE_RENAME 171 unlink(bakfile); 172 if(rename(pwname, bakfile) < 0) { 173 free(bakfile); 174 free(bakfile2); 175 return -1; 176 } 177 if(rename(bakfile2, pwname) < 0) { 178 free(bakfile); 179 free(bakfile2); 180 return -1; 181 } 182#else 183 unlink(bakfile); 184 link(pwname, bakfile); 185 unlink(pwname); 186 link(bakfile2, pwname); 187 unlink(bakfile2); 188#endif 189 free(bakfile); 190 free(bakfile2); 191 192 return 0; 193} 194 195_TYPE( struct t_pwent * ) 196t_makepwent(tpw, user, pass, salt, confent) 197 struct t_pw * tpw; 198 const char * user; 199 const char * pass; 200 const struct t_num * salt; 201 const struct t_confent * confent; 202{ 203 BigInteger x, v, n, g; 204 unsigned char dig[SHA_DIGESTSIZE]; 205 SHA1_CTX ctxt; 206 207 tpw->pebuf.name = tpw->userbuf; 208 tpw->pebuf.password.data = tpw->pwbuf; 209 tpw->pebuf.salt.data = tpw->saltbuf; 210 211 strncpy(tpw->pebuf.name, user, MAXUSERLEN); 212 tpw->pebuf.index = confent->index; 213 214 if(salt) { 215 tpw->pebuf.salt.len = salt->len; 216 memcpy(tpw->pebuf.salt.data, salt->data, salt->len); 217 } 218 else { 219 memset(dig, 0, SALTLEN); /* salt is 80 bits */ 220 tpw->pebuf.salt.len = SALTLEN; 221 do { 222 t_random(tpw->pebuf.salt.data, SALTLEN); 223 } while(memcmp(tpw->pebuf.salt.data, dig, SALTLEN) == 0); 224 if(tpw->pebuf.salt.data[0] == 0) 225 tpw->pebuf.salt.data[0] = 0xff; 226 } 227 228 n = BigIntegerFromBytes(confent->modulus.data, confent->modulus.len); 229 g = BigIntegerFromBytes(confent->generator.data, confent->generator.len); 230 v = BigIntegerFromInt(0); 231 232 SHA1Init(&ctxt); 233 SHA1Update(&ctxt, user, strlen(user)); 234 SHA1Update(&ctxt, ":", 1); 235 SHA1Update(&ctxt, pass, strlen(pass)); 236 SHA1Final(dig, &ctxt); 237 238 SHA1Init(&ctxt); 239 SHA1Update(&ctxt, tpw->pebuf.salt.data, tpw->pebuf.salt.len); 240 SHA1Update(&ctxt, dig, sizeof(dig)); 241 SHA1Final(dig, &ctxt); 242 243 /* x = H(s, H(u, ':', p)) */ 244 x = BigIntegerFromBytes(dig, sizeof(dig)); 245 246 BigIntegerModExp(v, g, x, n); 247 tpw->pebuf.password.len = BigIntegerToBytes(v, tpw->pebuf.password.data); 248 249 BigIntegerFree(v); 250 BigIntegerFree(x); 251 BigIntegerFree(g); 252 BigIntegerFree(n); 253 254 return &tpw->pebuf; 255} 256 257int 258t_pwcopy(pwdest, pwsrc, diff) 259 FILE * pwdest; 260 FILE * pwsrc; 261 struct t_pwent * diff; 262{ 263 struct t_pw * src; 264 struct t_pwent * ent; 265 266 if((src = t_openpw(pwsrc)) == NULL) 267 return -1; 268 269 while((ent = t_getpwent(src)) != NULL) 270 if(diff && strcmp(diff->name, ent->name) == 0) { 271 t_putpwent(diff, pwdest); 272 diff = NULL; 273 } 274 else 275 t_putpwent(ent, pwdest); 276 277 if(diff) 278 t_putpwent(diff, pwdest); 279 280 return 0; 281} 282 283_TYPE( struct t_pwent * ) 284t_getpwent(tpw) 285 struct t_pw * tpw; 286{ 287 char indexbuf[16]; 288 char passbuf[MAXB64PARAMLEN]; 289 char saltstr[MAXB64SALTLEN]; 290 291#ifdef ENABLE_YP 292 struct t_passwd * nisent; 293 /* FIXME: should tell caller to get conf entry from NIS also */ 294 295 if(tpw->state == IN_NIS) { 296 nisent = _yp_gettpent(); 297 if(nisent != NULL) { 298 savepwent(tpw, &nisent->tp); 299 return &tpw->pebuf; 300 } 301 tpw->state = FILE_NIS; 302 } 303#endif 304 305 while(1) { 306 if(t_nextfield(tpw->instream, tpw->userbuf, MAXUSERLEN) > 0) { 307#ifdef ENABLE_YP 308 if(tpw->state == FILE_NIS && *tpw->userbuf == '+') { 309 t_nextline(tpw->instream); 310 if(strlen(tpw->userbuf) > 1) { /* +name:... */ 311 nisent = _yp_gettpnam(tpw->userbuf + 1); 312 if(nisent != NULL) { 313 savepwent(tpw, nisent); 314 return &tpw->pebuf; 315 } 316 } 317 else { /* +:... */ 318 tpw->state = IN_NIS; 319 _yp_settpent(); 320 return t_getpwent(tpw); 321 } 322 } 323#endif 324 if(t_nextfield(tpw->instream, passbuf, MAXB64PARAMLEN) > 0 && 325 (tpw->pebuf.password.len = t_fromb64(tpw->pwbuf, passbuf)) > 0 && 326 t_nextfield(tpw->instream, saltstr, MAXB64SALTLEN) > 0 && 327 (tpw->pebuf.salt.len = t_fromb64(tpw->saltbuf, saltstr)) > 0 && 328 t_nextfield(tpw->instream, indexbuf, 16) > 0 && 329 (tpw->pebuf.index = atoi(indexbuf)) > 0) { 330 tpw->pebuf.name = tpw->userbuf; 331 tpw->pebuf.password.data = tpw->pwbuf; 332 tpw->pebuf.salt.data = tpw->saltbuf; 333 t_nextline(tpw->instream); 334 return &tpw->pebuf; 335 } 336 } 337 if(t_nextline(tpw->instream) < 0) 338 return NULL; 339 } 340} 341 342_TYPE( void ) 343t_putpwent(ent, fp) 344 const struct t_pwent * ent; 345 FILE * fp; 346{ 347 char strbuf[MAXB64PARAMLEN]; 348 char saltbuf[MAXB64SALTLEN]; 349 350 fprintf(fp, "%s:%s:%s:%d\n", ent->name, 351 t_tob64(strbuf, ent->password.data, ent->password.len), 352 t_tob64(saltbuf, ent->salt.data, ent->salt.len), ent->index); 353} 354 355