diff options
Diffstat (limited to 'contrib/cvs/src/client.c')
-rw-r--r-- | contrib/cvs/src/client.c | 167 |
1 files changed, 129 insertions, 38 deletions
diff --git a/contrib/cvs/src/client.c b/contrib/cvs/src/client.c index eafe916..3119613 100644 --- a/contrib/cvs/src/client.c +++ b/contrib/cvs/src/client.c @@ -1,3 +1,5 @@ +/* JT thinks BeOS is worth the trouble. */ + /* CVS client-related stuff. This program is free software; you can redistribute it and/or modify @@ -64,7 +66,6 @@ extern char *strerror (); #if HAVE_KERBEROS #define CVS_PORT 1999 -#if HAVE_KERBEROS #include <krb.h> extern char *krb_realmofhost (); @@ -78,8 +79,6 @@ static Key_schedule sched; #endif /* HAVE_KERBEROS */ -#endif /* HAVE_KERBEROS */ - #ifdef HAVE_GSSAPI #ifdef HAVE_GSSAPI_H @@ -1119,7 +1118,7 @@ call_in_directory (pathname, func, data) strcpy (r, "/."); Create_Admin (".", ".", repo, (char *) NULL, - (char *) NULL, 0, 1); + (char *) NULL, 0, 1, 1); free (repo); } @@ -1256,7 +1255,7 @@ warning: server is not creating directories one at a time"); strcpy (r, reposdirname); Create_Admin (dir, dir, repo, - (char *)NULL, (char *)NULL, 0, 0); + (char *)NULL, (char *)NULL, 0, 0, 1); free (repo); b = strrchr (dir, '/'); @@ -1764,6 +1763,7 @@ update_entries (data_arg, ent_list, short_pathname, filename) } free (mode_string); + free (scratch_entries); free (entries_line); /* The Mode, Mod-time, and Checksum responses should not carry @@ -1851,7 +1851,8 @@ update_entries (data_arg, ent_list, short_pathname, filename) if (use_gzip) { - if (gunzip_and_write (fd, short_pathname, buf, size)) + if (gunzip_and_write (fd, short_pathname, + (unsigned char *) buf, size)) error (1, 0, "aborting due to compression error"); } else if (write (fd, buf, size) != size) @@ -2029,6 +2030,8 @@ update_entries (data_arg, ent_list, short_pathname, filename) free (mode_string); free (buf); + free (scratch_entries); + free (entries_line); return; } @@ -2127,8 +2130,8 @@ update_entries (data_arg, ent_list, short_pathname, filename) if (file_timestamp) free (file_timestamp); - free (scratch_entries); } + free (scratch_entries); free (entries_line); } @@ -2494,7 +2497,11 @@ handle_set_checkin_prog (args, len) { char *prog; struct save_prog *p; + read_line (&prog); + if (strcmp (command_name, "export") == 0) + return; + p = (struct save_prog *) xmalloc (sizeof (struct save_prog)); p->next = checkin_progs; p->dir = xstrdup (args); @@ -2509,7 +2516,11 @@ handle_set_update_prog (args, len) { char *prog; struct save_prog *p; + read_line (&prog); + if (strcmp (command_name, "export") == 0) + return; + p = (struct save_prog *) xmalloc (sizeof (struct save_prog)); p->next = update_progs; p->dir = xstrdup (args); @@ -2687,7 +2698,7 @@ send_repository (dir, repos, update_dir) { Node *n; n = getnode (); - n->type = UNKNOWN; + n->type = NT_UNKNOWN; n->key = xstrdup (update_dir); n->data = NULL; @@ -3598,19 +3609,15 @@ get_responses_and_close () && waitpid (rsh_pid, (int *) 0, 0) == -1) error (1, errno, "waiting for process %d", rsh_pid); + buf_free (to_server); + buf_free (from_server); server_started = 0; - /* see if we need to sleep before returning */ + /* see if we need to sleep before returning to avoid time-stamp races */ if (last_register_time) { - time_t now; - - for (;;) - { - (void) time (&now); - if (now != last_register_time) break; - sleep (1); /* to avoid time-stamp races */ - } + while (time ((time_t *) NULL) == last_register_time) + sleep (1); } return errs; @@ -3778,6 +3785,7 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi) int port_number; struct sockaddr_in client_sai; struct hostent *hostinfo; + char no_passwd = 0; /* gets set if no password found */ sock = socket (AF_INET, SOCK_STREAM, 0); if (sock == -1) @@ -3822,6 +3830,14 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi) /* Get the password, probably from ~/.cvspass. */ password = get_cvs_password (); + + /* Send the empty string by default. This is so anonymous CVS + access doesn't require client to have done "cvs login". */ + if (password == NULL) + { + no_passwd = 1; + password = scramble (""); + } /* Announce that we're starting the authorization protocol. */ if (send (sock, begin, strlen (begin), 0) < 0) @@ -3845,8 +3861,8 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi) if (send (sock, end, strlen (end), 0) < 0) error (1, 0, "cannot send: %s", SOCK_STRERROR (SOCK_ERRNO)); - /* Paranoia. */ - memset (password, 0, strlen (password)); + /* Paranoia. */ + memset (password, 0, strlen (password)); } { @@ -3939,20 +3955,28 @@ connect_to_pserver (tofdp, fromfdp, verify_only, do_gssapi) return; rejected: + error (0, 0, + "authorization failed: server %s rejected access to %s for user %s", + CVSroot_hostname, CVSroot_directory, CVSroot_username); + + /* Output a special error message if authentication was attempted + with no password -- the user should be made aware that they may + have missed a step. */ + if (no_passwd) + { + error (0, 0, + "used empty password; try \"cvs login\" with a real password"); + } + if (shutdown (sock, 2) < 0) { - error (0, 0, - "authorization failed: server %s rejected access", - CVSroot_hostname); - error (1, 0, + error (0, 0, "shutdown() failed (server %s): %s", CVSroot_hostname, SOCK_STRERROR (SOCK_ERRNO)); } - error (1, 0, - "authorization failed: server %s rejected access", - CVSroot_hostname); + error_exit(); } #endif /* AUTH_CLIENT_SUPPORT */ @@ -4115,9 +4139,16 @@ connect_to_gserver (sock, hostinfo) if (stat_maj != GSS_S_COMPLETE && stat_maj != GSS_S_CONTINUE_NEEDED) { OM_uint32 message_context; + OM_uint32 new_stat_min; + + message_context = 0; + gss_display_status (&new_stat_min, stat_maj, GSS_C_GSS_CODE, + GSS_C_NULL_OID, &message_context, &tok_out); + error (0, 0, "GSSAPI authentication failed: %s", + (char *) tok_out.value); message_context = 0; - gss_display_status (&stat_min, stat_maj, GSS_C_GSS_CODE, + gss_display_status (&new_stat_min, stat_min, GSS_C_MECH_CODE, GSS_C_NULL_OID, &message_context, &tok_out); error (1, 0, "GSSAPI authentication failed: %s", (char *) tok_out.value); @@ -4141,7 +4172,29 @@ connect_to_gserver (sock, hostinfo) recv_bytes (sock, cbuf, 2); need = ((cbuf[0] & 0xff) << 8) | (cbuf[1] & 0xff); - assert (need <= sizeof buf); + + if (need > sizeof buf) + { + int got; + + /* This usually means that the server sent us an error + message. Read it byte by byte and print it out. + FIXME: This is a terrible error handling strategy. + However, even if we fix the server, we will still + want to do this to work with older servers. */ + buf[0] = cbuf[0]; + buf[1] = cbuf[1]; + got = recv (sock, buf + 2, sizeof buf - 2, 0); + if (got < 0) + error (1, 0, "recv() from server %s: %s", + CVSroot_hostname, SOCK_STRERROR (SOCK_ERRNO)); + buf[got + 2] = '\0'; + if (buf[got + 1] == '\n') + buf[got + 1] = '\0'; + error (1, 0, "error from server %s: %s", CVSroot_hostname, + buf); + } + recv_bytes (sock, buf, need); tok_in.length = need; } @@ -4175,7 +4228,7 @@ send_variable_proc (node, closure) void start_server () { - int tofd, fromfd; + int tofd, fromfd, rootless; char *log = getenv ("CVS_CLIENT_LOG"); @@ -4354,7 +4407,8 @@ the :server: access method is not supported by this port of CVS"); stored_mode = NULL; } - if (strcmp (command_name, "init") != 0) + rootless = (strcmp (command_name, "init") == 0); + if (!rootless) { send_to_server ("Root ", 0); send_to_server (CVSroot_directory, 0); @@ -4478,7 +4532,7 @@ the :server: access method is not supported by this port of CVS"); } } - if (cvsencrypt) + if (cvsencrypt && !rootless) { #ifdef ENCRYPTION /* Turn on encryption before turning on compression. We do @@ -4525,7 +4579,7 @@ the :server: access method is not supported by this port of CVS"); #endif /* ! ENCRYPTION */ } - if (gzip_level) + if (gzip_level && !rootless) { if (supported_request ("Gzip-stream")) { @@ -4567,7 +4621,7 @@ the :server: access method is not supported by this port of CVS"); } } - if (cvsauthenticate && ! cvsencrypt) + if (cvsauthenticate && ! cvsencrypt && !rootless) { /* Turn on authentication after turning on compression, so that we can compress the authentication information. We @@ -4598,7 +4652,7 @@ the :server: access method is not supported by this port of CVS"); } #ifdef FILENAMES_CASE_INSENSITIVE - if (supported_request ("Case")) + if (supported_request ("Case") && !rootless) send_to_server ("Case\012", 0); #endif @@ -4968,6 +5022,7 @@ struct send_data int build_dirs; int force; int no_contents; + int backup_modified; }; static int send_fileproc PROTO ((void *callerdat, struct file_info *finfo)); @@ -5089,6 +5144,18 @@ warning: ignoring -k options due to server limitations"); } else send_modified (filename, finfo->fullname, vers); + + if (args->backup_modified) + { + char *bakname; + bakname = backup_file (filename, vers->vn_user); + /* This behavior is sufficiently unexpected to + justify overinformativeness, I think. */ + if (! really_quiet) + printf ("(Locally modified %s moved to %s)\n", + filename, bakname); + free (bakname); + } } else { @@ -5197,9 +5264,6 @@ send_dirent_proc (callerdat, dir, repository, update_dir, entries) dir_exists = isdir (cvsadm_name); free (cvsadm_name); - /* initialize the ignore list for this directory */ - ignlist = getlist (); - /* * If there is an empty directory (e.g. we are doing `cvs add' on a * newly-created directory), the server still needs to know about it. @@ -5215,6 +5279,9 @@ send_dirent_proc (callerdat, dir, repository, update_dir, entries) char *repos = Name_Repository (dir, update_dir); send_a_repository (dir, repos, update_dir); free (repos); + + /* initialize the ignore list for this directory */ + ignlist = getlist (); } else { @@ -5239,6 +5306,29 @@ send_dirent_proc (callerdat, dir, repository, update_dir, entries) return (dir_exists ? R_PROCESS : R_SKIP_ALL); } +static int send_dirleave_proc PROTO ((void *, char *, int, char *, List *)); + +/* + * send_dirleave_proc () is called back by the recursion code upon leaving + * a directory. All it does is delete the ignore list if it hasn't already + * been done (by send_filesdone_proc). + */ +/* ARGSUSED */ +static int +send_dirleave_proc (callerdat, dir, err, update_dir, entries) + void *callerdat; + char *dir; + int err; + char *update_dir; + List *entries; +{ + + /* Delete the ignore list if it hasn't already been done. */ + if (ignlist) + dellist (&ignlist); + return err; +} + /* * Send each option in a string to the server, one by one. * This assumes that the options are separated by spaces, for example @@ -5430,9 +5520,10 @@ send_files (argc, argv, local, aflag, flags) args.build_dirs = flags & SEND_BUILD_DIRS; args.force = flags & SEND_FORCE; args.no_contents = flags & SEND_NO_CONTENTS; + args.backup_modified = flags & BACKUP_MODIFIED_FILES; err = start_recursion (send_fileproc, send_filesdoneproc, - send_dirent_proc, (DIRLEAVEPROC)NULL, (void *) &args, + send_dirent_proc, send_dirleave_proc, (void *) &args, argc, argv, local, W_LOCAL, aflag, 0, (char *)NULL, 0); if (err) error_exit (); |