1/* 2 * Copyright (C) 1986-2005 The Free Software Foundation, Inc. 3 * 4 * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, 5 * and others. 6 * 7 * Portions Copyright (c) 1995, Cyclic Software, Bloomington, IN, USA 8 * 9 * You may distribute under the terms of the GNU General Public License as 10 * specified in the README file that comes with CVS. 11 * 12 * Allow user to log in for an authenticating server. 13 */ 14 15#include "cvs.h" 16#include "getline.h" 17 18#ifdef AUTH_CLIENT_SUPPORT /* This covers the rest of the file. */ 19 20/* There seems to be very little agreement on which system header 21 getpass is declared in. With a lot of fancy autoconfiscation, 22 we could perhaps detect this, but for now we'll just rely on 23 _CRAY, since Cray is perhaps the only system on which our own 24 declaration won't work (some Crays declare the 2#$@% thing as 25 varadic, believe it or not). On Cray, getpass will be declared 26 in either stdlib.h or unistd.h. */ 27 28#ifndef CVS_PASSWORD_FILE 29#define CVS_PASSWORD_FILE ".cvspass" 30#endif 31 32/* If non-NULL, get_cvs_password() will just return this. */ 33static char *cvs_password = NULL; 34 35static char *construct_cvspass_filename PROTO ((void)); 36 37/* The return value will need to be freed. */ 38static char * 39construct_cvspass_filename () 40{ 41 char *homedir; 42 char *passfile; 43 44 /* Environment should override file. */ 45 if ((passfile = getenv ("CVS_PASSFILE")) != NULL) 46 return xstrdup (passfile); 47 48 /* Construct absolute pathname to user's password file. */ 49 /* todo: does this work under OS/2 ? */ 50 homedir = get_homedir (); 51 if (! homedir) 52 { 53 /* FIXME? This message confuses a lot of users, at least 54 on Win95 (which doesn't set HOMEDRIVE and HOMEPATH like 55 NT does). I suppose the answer for Win95 is to store the 56 passwords in the registry or something (??). And .cvsrc 57 and such too? Wonder what WinCVS does (about .cvsrc, the 58 right thing for a GUI is to just store the password in 59 memory only)... */ 60 error (1, 0, "could not find out home directory"); 61 return (char *) NULL; 62 } 63 64 passfile = strcat_filename_onto_homedir (homedir, CVS_PASSWORD_FILE); 65 66 /* Safety first and last, Scouts. */ 67 if (isfile (passfile)) 68 /* xchmod() is too polite. */ 69 chmod (passfile, 0600); 70 71 return passfile; 72} 73 74 75 76/* 77 * static char * 78 * password_entry_parseline ( 79 * const char *cvsroot_canonical, 80 * const unsigned char warn, 81 * const int linenumber, 82 * char *linebuf 83 * ); 84 * 85 * Internal function used by password_entry_operation. Parse a single line 86 * from a ~/.cvsroot password file and return a pointer to the password if the 87 * line refers to the same cvsroot as cvsroot_canonical 88 * 89 * INPUTS 90 * cvsroot_canonical the root we are looking for 91 * warn Boolean: print warnings for invalid lines? 92 * linenumber the line number for error messages 93 * linebuf the current line 94 * 95 * RETURNS 96 * NULL if the line doesn't match 97 * char *password as a pointer into linebuf 98 * 99 * NOTES 100 * This function temporarily alters linebuf, so it isn't thread safe when 101 * called on the same linebuf 102 */ 103static char * 104password_entry_parseline (cvsroot_canonical, warn, linenumber, linebuf) 105 const char *cvsroot_canonical; 106 const unsigned char warn; 107 const int linenumber; 108 char *linebuf; 109{ 110 char *password = NULL; 111 char *p; 112 113 /* look for '^/' */ 114 if (*linebuf == '/') 115 { 116 /* Yes: slurp '^/\d+\D' and parse the rest of the line according to version number */ 117 char *q; 118 unsigned long int entry_version = 0; 119 120 if (isspace(*(linebuf + 1))) 121 { 122 /* special case since strtoul ignores leading white space */ 123 q = linebuf + 1; 124 } 125 else 126 { 127 entry_version = strtoul (linebuf + 1, &q, 10); 128 if (q != linebuf + 1) 129 /* assume a delimiting seperator */ 130 q++; 131 } 132 133 switch (entry_version) 134 { 135 case 1: 136 /* this means the same normalize_cvsroot we are using was 137 * used to create this entry. strcmp is good enough for 138 * us. 139 */ 140 p = strchr (q, ' '); 141 if (p == NULL) 142 { 143 if (warn && !really_quiet) 144 error (0, 0, "warning: skipping invalid entry in password file at line %d", 145 linenumber); 146 } 147 else 148 { 149 *p = '\0'; 150 if (strcmp (cvsroot_canonical, q) == 0) 151 password = p + 1; 152 *p = ' '; 153 } 154 break; 155 case ULONG_MAX: 156 if (warn && !really_quiet) 157 { 158 error (0, errno, "warning: unable to convert version number in password file at line %d", 159 linenumber); 160 error (0, 0, "skipping entry"); 161 } 162 break; 163 case 0: 164 if (warn && !really_quiet) 165 error (0, 0, "warning: skipping entry with invalid version string in password file at line %d", 166 linenumber); 167 break; 168 default: 169 if (warn && !really_quiet) 170 error (0, 0, "warning: skipping entry with unknown version (%lu) in password file at line %d", 171 entry_version, linenumber); 172 break; 173 } 174 } 175 else 176 { 177 /* No: assume: 178 * 179 * ^cvsroot Aencoded_password$ 180 * 181 * as header comment specifies and parse accordingly 182 */ 183 cvsroot_t *tmp_root; 184 char *tmp_root_canonical; 185 186 p = strchr (linebuf, ' '); 187 if (p == NULL) 188 { 189 if (warn && !really_quiet) 190 error (0, 0, "warning: skipping invalid entry in password file at line %d", linenumber); 191 return NULL;; 192 } 193 194 *p = '\0'; 195 if ((tmp_root = parse_cvsroot (linebuf)) == NULL) 196 { 197 if (warn && !really_quiet) 198 error (0, 0, "warning: skipping invalid entry in password file at line %d", linenumber); 199 *p = ' '; 200 return NULL; 201 } 202 *p = ' '; 203 tmp_root_canonical = normalize_cvsroot (tmp_root); 204 if (strcmp (cvsroot_canonical, tmp_root_canonical) == 0) 205 password = p + 1; 206 207 free (tmp_root_canonical); 208 free_cvsroot_t (tmp_root); 209 } 210 211 return password; 212} 213 214 215 216/* 217 * static char * 218 * password_entry_operation ( 219 * password_entry_operation_t operation, 220 * cvsroot_t *root, 221 * char *newpassword 222 * ); 223 * 224 * Search the password file and depending on the value of operation: 225 * 226 * Mode Action 227 * password_entry_lookup Return the password 228 * password_entry_delete Delete the entry from the file, if it 229 * exists. 230 * password_entry_add Replace the line with the new one, else 231 * append it. 232 * 233 * Because the user might be accessing multiple repositories, with 234 * different passwords for each one, the format of ~/.cvspass is: 235 * 236 * [user@]host:[port]/path Aencoded_password 237 * [user@]host:[port]/path Aencoded_password 238 * ... 239 * 240 * New entries are always of the form: 241 * 242 * /1 user@host:port/path Aencoded_password 243 * 244 * but the old format is supported for backwards compatibility. 245 * The entry version string wasn't strictly necessary, but it avoids the 246 * overhead of parsing some entries since we know it is already in canonical 247 * form and allows room for expansion later, say, if we want to allow spaces 248 * and/or other characters to be escaped in the string. Also, the new entries 249 * would have been ignored by old versions of CVS anyhow since those versions 250 * didn't know how to parse a port number. 251 * 252 * The "A" before "encoded_password" is a literal capital A. It's a 253 * version number indicating which form of scrambling we're doing on 254 * the password -- someday we might provide something more secure than 255 * the trivial encoding we do now, and when that day comes, it would 256 * be nice to remain backward-compatible. 257 * 258 * Like .netrc, the file's permissions are the only thing preventing 259 * it from being read by others. Unlike .netrc, we will not be 260 * fascist about it, at most issuing a warning, and never refusing to 261 * work. 262 * 263 * INPUTS 264 * operation operation to perform 265 * root cvsroot_t to look up 266 * newpassword prescrambled new password, for password_entry_add_mode 267 * 268 * RETURNS 269 * -1 if password_entry_lookup_mode not specified 270 * NULL on failed lookup 271 * pointer to a copy of the password string otherwise, which the caller is 272 * responsible for disposing of 273 */ 274 275typedef enum password_entry_operation_e { 276 password_entry_lookup, 277 password_entry_delete, 278 password_entry_add 279} password_entry_operation_t; 280 281static char * 282password_entry_operation (operation, root, newpassword) 283 password_entry_operation_t operation; 284 cvsroot_t *root; 285 char *newpassword; 286{ 287 char *passfile; 288 FILE *fp; 289 char *cvsroot_canonical = NULL; 290 char *password = NULL; 291 int line_length; 292 long line = -1; 293 char *linebuf = NULL; 294 size_t linebuf_len; 295 char *p; 296 int save_errno = 0; 297 298 if (root->method != pserver_method) 299 { 300 error (0, 0, "\ 301internal error: can only call password_entry_operation with pserver method"); 302 error (1, 0, "CVSROOT: %s", root->original); 303 } 304 305 cvsroot_canonical = normalize_cvsroot (root); 306 307 /* Yes, the method below reads the user's password file twice when we have 308 * to delete an entry. It's inefficient, but we're not talking about a gig of 309 * data here. 310 */ 311 312 passfile = construct_cvspass_filename (); 313 fp = CVS_FOPEN (passfile, "r"); 314 if (fp == NULL) 315 { 316 error (0, errno, "warning: failed to open %s for reading", passfile); 317 goto process; 318 } 319 320 /* Check each line to see if we have this entry already. */ 321 line = 0; 322 while ((line_length = getline (&linebuf, &linebuf_len, fp)) >= 0) 323 { 324 line++; 325 password = password_entry_parseline (cvsroot_canonical, 1, line, 326 linebuf); 327 if (password != NULL) 328 /* this is it! break out and deal with linebuf */ 329 break; 330 } 331 if (line_length < 0 && !feof (fp)) 332 { 333 error (0, errno, "cannot read %s", passfile); 334 goto error_exit; 335 } 336 if (fclose (fp) < 0) 337 /* not fatal, unless it cascades */ 338 error (0, errno, "cannot close %s", passfile); 339 fp = NULL; 340 341 /* Utter, total, raving paranoia, I know. */ 342 chmod (passfile, 0600); 343 344 /* a copy to return or keep around so we can reuse linebuf */ 345 if (password != NULL) 346 { 347 /* chomp the EOL */ 348 p = strchr (password, '\n'); 349 if (p != NULL) 350 *p = '\0'; 351 password = xstrdup (password); 352 } 353 354process: 355 356 /* might as well return now */ 357 if (operation == password_entry_lookup) 358 goto out; 359 360 /* same here */ 361 if (operation == password_entry_delete && password == NULL) 362 { 363 error (0, 0, "Entry not found."); 364 goto out; 365 } 366 367 /* okay, file errors can simply be fatal from now on since we don't do 368 * anything else if we're in lookup mode 369 */ 370 371 /* copy the file with the entry deleted unless we're in add 372 * mode and the line we found contains the same password we're supposed to 373 * add 374 */ 375 if (!noexec && password != NULL && (operation == password_entry_delete 376 || (operation == password_entry_add 377 && strcmp (password, newpassword)))) 378 { 379 long found_at = line; 380 char *tmp_name; 381 FILE *tmp_fp; 382 383 /* open the original file again */ 384 fp = CVS_FOPEN (passfile, "r"); 385 if (fp == NULL) 386 error (1, errno, "failed to open %s for reading", passfile); 387 388 /* create and open a temp file */ 389 if ((tmp_fp = cvs_temp_file (&tmp_name)) == NULL) 390 error (1, errno, "unable to open temp file %s", 391 tmp_name ? tmp_name : "(null)"); 392 393 line = 0; 394 while ((line_length = getline (&linebuf, &linebuf_len, fp)) >= 0) 395 { 396 line++; 397 if (line < found_at 398 || (line != found_at 399 && !password_entry_parseline (cvsroot_canonical, 0, line, 400 linebuf))) 401 { 402 if (fprintf (tmp_fp, "%s", linebuf) == EOF) 403 { 404 /* try and clean up anyhow */ 405 error (0, errno, "fatal error: cannot write %s", tmp_name); 406 if (fclose (tmp_fp) == EOF) 407 error (0, errno, "cannot close %s", tmp_name); 408 /* call CVS_UNLINK instead of unlink_file since the file 409 * got created in noexec mode 410 */ 411 if (CVS_UNLINK (tmp_name) < 0) 412 error (0, errno, "cannot remove %s", tmp_name); 413 /* but quit so we don't remove all the entries from a 414 * user's password file accidentally 415 */ 416 error (1, 0, "exiting"); 417 } 418 } 419 } 420 if (line_length < 0 && !feof (fp)) 421 { 422 error (0, errno, "cannot read %s", passfile); 423 goto error_exit; 424 } 425 if (fclose (fp) < 0) 426 /* not fatal, unless it cascades */ 427 error (0, errno, "cannot close %s", passfile); 428 if (fclose (tmp_fp) < 0) 429 /* not fatal, unless it cascades */ 430 /* FIXME - does copy_file return correct results if the file wasn't 431 * closed? should this be fatal? 432 */ 433 error (0, errno, "cannot close %s", tmp_name); 434 435 /* FIXME: rename_file would make more sense (e.g. almost 436 * always faster). 437 * 438 * I don't think so, unless we change the way rename_file works to 439 * attempt a cp/rm sequence when rename fails since rename doesn't 440 * work across file systems and it isn't uncommon to have /tmp 441 * on its own partition. 442 * 443 * For that matter, it's probably not uncommon to have a home 444 * directory on an NFS mount. 445 */ 446 copy_file (tmp_name, passfile); 447 if (CVS_UNLINK (tmp_name) < 0) 448 error (0, errno, "cannot remove %s", tmp_name); 449 free (tmp_name); 450 } 451 452 /* in add mode, if we didn't find an entry or found an entry with a 453 * different password, append the new line 454 */ 455 if (!noexec && operation == password_entry_add 456 && (password == NULL || strcmp (password, newpassword))) 457 { 458 if ((fp = CVS_FOPEN (passfile, "a")) == NULL) 459 error (1, errno, "could not open %s for writing", passfile); 460 461 if (fprintf (fp, "/1 %s %s\n", cvsroot_canonical, newpassword) == EOF) 462 error (1, errno, "cannot write %s", passfile); 463 if (fclose (fp) < 0) 464 error (1, errno, "cannot close %s", passfile); 465 } 466 467 /* Utter, total, raving paranoia, I know. */ 468 chmod (passfile, 0600); 469 470 if (password) 471 { 472 free (password); 473 password = NULL; 474 } 475 if (linebuf) 476 free (linebuf); 477 478out: 479 free (cvsroot_canonical); 480 free (passfile); 481 return password; 482 483error_exit: 484 /* just exit when we're not in lookup mode */ 485 if (operation != password_entry_lookup) 486 error (1, 0, "fatal error: exiting"); 487 /* clean up and exit in lookup mode so we can try a login with a NULL 488 * password anyhow in case that's what we would have found 489 */ 490 save_errno = errno; 491 if (fp != NULL) 492 { 493 /* Utter, total, raving paranoia, I know. */ 494 chmod (passfile, 0600); 495 if(fclose (fp) < 0) 496 error (0, errno, "cannot close %s", passfile); 497 } 498 if (linebuf) 499 free (linebuf); 500 if (cvsroot_canonical) 501 free (cvsroot_canonical); 502 free (passfile); 503 errno = save_errno; 504 return NULL; 505} 506 507 508 509/* Prompt for a password, and store it in the file "CVS/.cvspass". 510 */ 511 512static const char *const login_usage[] = 513{ 514 "Usage: %s %s\n", 515 "(Specify the --help global option for a list of other help options)\n", 516 NULL 517}; 518 519int 520login (argc, argv) 521 int argc; 522 char **argv; 523{ 524 char *typed_password; 525 char *cvsroot_canonical; 526 527 if (argc < 0) 528 usage (login_usage); 529 530 if (current_parsed_root->method != pserver_method) 531 { 532 error (0, 0, "can only use `login' command with the 'pserver' method"); 533 error (1, 0, "CVSROOT: %s", current_parsed_root->original); 534 } 535 536 cvsroot_canonical = normalize_cvsroot(current_parsed_root); 537 printf ("Logging in to %s\n", cvsroot_canonical); 538 fflush (stdout); 539 540 if (current_parsed_root->password) 541 { 542 typed_password = scramble (current_parsed_root->password); 543 } 544 else 545 { 546 char *tmp; 547 tmp = getpass ("CVS password: "); 548 /* Must deal with a NULL return value here. I haven't managed to 549 * disconnect the CVS process from the tty and force a NULL return 550 * in sanity.sh, but the Linux version of getpass is documented 551 * to return NULL when it can't open /dev/tty... 552 */ 553 if (!tmp) error (1, errno, "login: Failed to read password."); 554 typed_password = scramble (tmp); 555 memset (tmp, 0, strlen (tmp)); 556 } 557 558 /* Force get_cvs_password() to use this one (when the client 559 * confirms the new password with the server), instead of 560 * consulting the file. We make a new copy because cvs_password 561 * will get zeroed by connect_to_server(). */ 562 cvs_password = xstrdup (typed_password); 563 564 connect_to_pserver (current_parsed_root, NULL, NULL, 1, 0); 565 566 password_entry_operation (password_entry_add, current_parsed_root, 567 typed_password); 568 569 free_cvs_password (typed_password); 570 free (cvsroot_canonical); 571 572 return 0; 573} 574 575 576 577/* Free the password returned by get_cvs_password() and also free the 578 * saved cvs_password if they are different pointers. Be paranoid 579 * about the in-memory copy of the password and overwrite it with zero 580 * bytes before doing the free(). 581 */ 582void 583free_cvs_password (char *password) 584{ 585 if (password && password != cvs_password) 586 { 587 memset (password, 0, strlen (password)); 588 free (password); 589 } 590 591 if (cvs_password) 592 { 593 memset (cvs_password, 0, strlen (cvs_password)); 594 free (cvs_password); 595 cvs_password = NULL; 596 } 597} 598 599/* Returns the _scrambled_ password in freshly allocated memory. The server 600 * must descramble before hashing and comparing. If password file not found, 601 * or password not found in the file, just return NULL. 602 */ 603char * 604get_cvs_password () 605{ 606 if (current_parsed_root->password) 607 return scramble (current_parsed_root->password); 608 609 /* If someone (i.e., login()) is calling connect_to_pserver() out of 610 context, then assume they have supplied the correct, scrambled 611 password. */ 612 if (cvs_password) 613 return xstrdup (cvs_password); 614 615 if (getenv ("CVS_PASSWORD") != NULL) 616 { 617 /* In previous versions of CVS one could specify a password in 618 * CVS_PASSWORD. This is a bad idea, because in BSD variants 619 * of unix anyone can see the environment variable with 'ps'. 620 * But for users who were using that feature we want to at 621 * least let them know what is going on. After printing this 622 * warning, we should fall through to the regular error where 623 * we tell them to run "cvs login" (unless they already ran 624 * it, of course). 625 */ 626 error (0, 0, "CVS_PASSWORD is no longer supported; ignored"); 627 } 628 629 if (current_parsed_root->method != pserver_method) 630 { 631 error (0, 0, "can only call get_cvs_password with pserver method"); 632 error (1, 0, "CVSROOT: %s", current_parsed_root->original); 633 } 634 635 return password_entry_operation (password_entry_lookup, 636 current_parsed_root, NULL); 637} 638 639 640 641static const char *const logout_usage[] = 642{ 643 "Usage: %s %s\n", 644 "(Specify the --help global option for a list of other help options)\n", 645 NULL 646}; 647 648/* Remove any entry for the CVSRoot repository found in .cvspass. */ 649int 650logout (argc, argv) 651 int argc; 652 char **argv; 653{ 654 char *cvsroot_canonical; 655 656 if (argc < 0) 657 usage (logout_usage); 658 659 if (current_parsed_root->method != pserver_method) 660 { 661 error (0, 0, "can only use pserver method with `logout' command"); 662 error (1, 0, "CVSROOT: %s", current_parsed_root->original); 663 } 664 665 /* Hmm. Do we want a variant of this command which deletes _all_ 666 the entries from the current .cvspass? Might be easier to 667 remember than "rm ~/.cvspass" but then again if people are 668 mucking with HOME (common in Win95 as the system doesn't set 669 it), then this variant of "cvs logout" might give a false sense 670 of security, in that it wouldn't delete entries from any 671 .cvspass files but the current one. */ 672 673 if (!quiet) 674 { 675 cvsroot_canonical = normalize_cvsroot(current_parsed_root); 676 printf ("Logging out of %s\n", cvsroot_canonical); 677 fflush (stdout); 678 free (cvsroot_canonical); 679 } 680 681 password_entry_operation (password_entry_delete, current_parsed_root, NULL); 682 683 return 0; 684} 685 686#endif /* AUTH_CLIENT_SUPPORT from beginning of file. */ 687