int auth_login(struct config *config) { struct stream *s; char hostbuf[MAXHOSTNAMELEN]; char *login, *host; int error; s = config->server; error = gethostname(hostbuf, sizeof(hostbuf)); hostbuf[sizeof(hostbuf) - 1] = '\0'; if (error) host = NULL; else host = hostbuf; login = getlogin(); proto_printf(s, "USER %s %s\n", login != NULL ? login : "******", host != NULL ? host : "?"); stream_flush(s); error = auth_domd5auth(config); return (error); }
static int auth_domd5auth(struct config *config) { struct stream *s; char *line, *cmd, *challenge, *realm, *client, *srvresponse, *msg; char shrdsecret[MD5_CHARS_MAX], response[MD5_CHARS_MAX]; char clichallenge[MD5_CHARS_MAX]; struct srvrecord auth; int error; lprintf(2, "MD5 authentication started\n"); s = config->server; line = stream_getln(s, NULL); cmd = proto_get_ascii(&line); realm = proto_get_ascii(&line); challenge = proto_get_ascii(&line); if (challenge == NULL || line != NULL || (strcmp(cmd, "AUTHMD5") != 0)) { lprintf(-1, "Invalid server reply to USER\n"); return (STATUS_FAILURE); } client = NULL; response[0] = clichallenge[0] = '.'; response[1] = clichallenge[1] = 0; if (config->reqauth || (strcmp(challenge, ".") != 0)) { if (strcmp(realm, ".") == 0) { lprintf(-1, "Authentication required, but not enabled on server\n"); return (STATUS_FAILURE); } error = auth_lookuprecord(realm, &auth); if (error != STATUS_SUCCESS) return (error); client = auth.client; auth_makesecret(&auth, shrdsecret); } if (strcmp(challenge, ".") != 0) auth_makeresponse(challenge, shrdsecret, response); if (config->reqauth) auth_makechallenge(config, clichallenge); proto_printf(s, "AUTHMD5 %s %s %s\n", client == NULL ? "." : client, response, clichallenge); stream_flush(s); line = stream_getln(s, NULL); cmd = proto_get_ascii(&line); if (cmd == NULL || line == NULL) goto bad; if (strcmp(cmd, "OK") == 0) { srvresponse = proto_get_ascii(&line); if (srvresponse == NULL) goto bad; if (config->reqauth && !auth_checkresponse(srvresponse, clichallenge, shrdsecret)) { lprintf(-1, "Server failed to authenticate itself to client\n"); return (STATUS_FAILURE); } lprintf(2, "MD5 authentication successful\n"); return (STATUS_SUCCESS); } if (strcmp(cmd, "!") == 0) { msg = proto_get_rest(&line); if (msg == NULL) goto bad; lprintf(-1, "Server error: %s\n", msg); return (STATUS_FAILURE); } bad: lprintf(-1, "Invalid server reply to AUTHMD5\n"); return (STATUS_FAILURE); }
/* * Close the status file and free any resource associated with it. * It is OK to pass NULL for errmsg only if the status file was * opened read-only. If it wasn't opened read-only, status_close() * can produce an error and errmsg is not allowed to be NULL. If * there was no errors, errmsg is set to NULL. */ void status_close(struct status *st, char **errmsg) { struct statusrec *sr; char *line, *name; int error, type; if (st->wr != NULL) { if (st->dirty) { if (st->current != NULL) { error = status_wr(st, st->current); if (error) { *errmsg = status_errmsg(st); goto bad; } st->current = NULL; } /* Copy the rest of the file. */ while ((sr = status_rdraw(st, &line)) != NULL) { error = status_wrraw(st, sr, line); if (error) { *errmsg = status_errmsg(st); goto bad; } } if (st->error) { *errmsg = status_errmsg(st); goto bad; } /* Close off all the open directories. */ pathcomp_finish(st->pc); while (pathcomp_get(st->pc, &type, &name)) { assert(type == PC_DIRUP); error = proto_printf(st->wr, "U %s %f\n", name, fattr_bogus); if (error) { st->error = STATUS_ERR_WRITE; st->suberror = errno; *errmsg = status_errmsg(st); goto bad; } } /* Rename tempfile. */ error = rename(st->tempfile, st->path); if (error) { st->error = STATUS_ERR_RENAME; st->suberror = errno; *errmsg = status_errmsg(st); goto bad; } } else { /* Just discard the tempfile. */ unlink(st->tempfile); } *errmsg = NULL; } status_free(st); return; bad: status_free(st); }
/* * Open the status file. If scantime is not -1, the file is opened * for updating, otherwise, it is opened read-only. If the status file * couldn't be opened, NULL is returned and errmsg is set to the error * message. */ struct status * status_open(struct coll *coll, time_t scantime, char **errmsg) { struct status *st; struct stream *file; struct fattr *fa; char *destpath, *path; int error, rv; path = coll_statuspath(coll); file = stream_open_file(path, O_RDONLY); if (file == NULL) { if (errno != ENOENT) { xasprintf(errmsg, "Could not open \"%s\": %s\n", path, strerror(errno)); free(path); return (NULL); } st = status_fromnull(path); } else { st = status_fromrd(path, file); if (st == NULL) { xasprintf(errmsg, "Error in \"%s\": Bad header line", path); free(path); return (NULL); } } if (scantime != -1) { /* Open for writing too. */ xasprintf(&destpath, "%s/%s/%s/", coll->co_base, coll->co_colldir, coll->co_name); st->tempfile = tempname(destpath); if (mkdirhier(destpath, coll->co_umask) != 0) { xasprintf(errmsg, "Cannot create directories leading " "to \"%s\": %s", destpath, strerror(errno)); free(destpath); status_free(st); return (NULL); } free(destpath); st->wr = stream_open_file(st->tempfile, O_CREAT | O_TRUNC | O_WRONLY, 0644); if (st->wr == NULL) { xasprintf(errmsg, "Cannot create \"%s\": %s", st->tempfile, strerror(errno)); status_free(st); return (NULL); } fa = fattr_new(FT_FILE, -1); fattr_mergedefault(fa); fattr_umask(fa, coll->co_umask); rv = fattr_install(fa, st->tempfile, NULL); fattr_free(fa); if (rv == -1) { xasprintf(errmsg, "Cannot set attributes for \"%s\": %s", st->tempfile, strerror(errno)); status_free(st); return (NULL); } if (scantime != st->scantime) st->dirty = 1; error = proto_printf(st->wr, "F %d %t\n", STATUS_VERSION, scantime); if (error) { st->error = STATUS_ERR_WRITE; st->suberror = errno; *errmsg = status_errmsg(st); status_free(st); return (NULL); } } return (st); }
static int status_wrraw(struct status *st, struct statusrec *sr, char *line) { char *name; char cmd; int error, ret, type; if (st->wr == NULL) return (0); /* * Keep the compressor in sync. At this point, the necessary * DirDowns and DirUps should have already been emitted, so the * compressor should return exactly one value in the PC_DIRDOWN * and PC_DIRUP case and none in the PC_FILE case. */ if (sr->sr_type == SR_DIRDOWN) pathcomp_put(st->pc, PC_DIRDOWN, sr->sr_file); else if (sr->sr_type == SR_DIRUP) pathcomp_put(st->pc, PC_DIRUP, sr->sr_file); else pathcomp_put(st->pc, PC_FILE, sr->sr_file); if (sr->sr_type == SR_DIRDOWN || sr->sr_type == SR_DIRUP) { ret = pathcomp_get(st->pc, &type, &name); assert(ret); if (sr->sr_type == SR_DIRDOWN) assert(type == PC_DIRDOWN); else assert(type == PC_DIRUP); } ret = pathcomp_get(st->pc, &type, &name); assert(!ret); switch (sr->sr_type) { case SR_DIRDOWN: cmd = 'D'; break; case SR_DIRUP: cmd = 'U'; break; case SR_CHECKOUTLIVE: cmd = 'C'; break; case SR_CHECKOUTDEAD: cmd = 'c'; break; case SR_FILELIVE: cmd = 'V'; break; case SR_FILEDEAD: cmd = 'v'; break; default: assert(0); return (-1); } if (sr->sr_type == SR_DIRDOWN) error = proto_printf(st->wr, "%c %S\n", cmd, sr->sr_file); else error = proto_printf(st->wr, "%c %s %S\n", cmd, sr->sr_file, line); if (error) { st->error = STATUS_ERR_WRITE; st->suberror = errno; return (-1); } return (0); }
static int status_wr(struct status *st, struct statusrec *sr) { struct pathcomp *pc; const struct fattr *fa; char *name; int error, type, usedirupattr; pc = st->pc; error = 0; usedirupattr = 0; if (sr->sr_type == SR_DIRDOWN) { pathcomp_put(pc, PC_DIRDOWN, sr->sr_file); } else if (sr->sr_type == SR_DIRUP) { pathcomp_put(pc, PC_DIRUP, sr->sr_file); usedirupattr = 1; } else { pathcomp_put(pc, PC_FILE, sr->sr_file); } while (pathcomp_get(pc, &type, &name)) { if (type == PC_DIRDOWN) { error = proto_printf(st->wr, "D %s\n", name); } else if (type == PC_DIRUP) { if (usedirupattr) fa = sr->sr_clientattr; else fa = fattr_bogus; usedirupattr = 0; error = proto_printf(st->wr, "U %s %f\n", name, fa); } if (error) goto bad; } switch (sr->sr_type) { case SR_DIRDOWN: case SR_DIRUP: /* Already emitted above. */ break; case SR_CHECKOUTLIVE: error = proto_printf(st->wr, "C %s %s %s %f %s %s %f\n", sr->sr_file, sr->sr_tag, sr->sr_date, sr->sr_serverattr, sr->sr_revnum, sr->sr_revdate, sr->sr_clientattr); break; case SR_CHECKOUTDEAD: error = proto_printf(st->wr, "c %s %s %s %f\n", sr->sr_file, sr->sr_tag, sr->sr_date, sr->sr_serverattr); break; case SR_FILELIVE: error = proto_printf(st->wr, "V %s %f\n", sr->sr_file, sr->sr_clientattr); break; case SR_FILEDEAD: error = proto_printf(st->wr, "v %s %f\n", sr->sr_file, sr->sr_clientattr); break; } if (error) goto bad; return (0); bad: st->error = STATUS_ERR_WRITE; st->suberror = errno; return (-1); }