static TS_REQ *create_query(BIO *data_bio, char *digest, const EVP_MD *md, const char *policy, int no_nonce, int cert) { int ret = 0; TS_REQ *ts_req = NULL; int len; TS_MSG_IMPRINT *msg_imprint = NULL; X509_ALGOR *algo = NULL; unsigned char *data = NULL; ASN1_OBJECT *policy_obj = NULL; ASN1_INTEGER *nonce_asn1 = NULL; if (md == NULL && (md = EVP_get_digestbyname("sha1")) == NULL) goto err; if ((ts_req = TS_REQ_new()) == NULL) goto err; if (!TS_REQ_set_version(ts_req, 1)) goto err; if ((msg_imprint = TS_MSG_IMPRINT_new()) == NULL) goto err; if ((algo = X509_ALGOR_new()) == NULL) goto err; if ((algo->algorithm = OBJ_nid2obj(EVP_MD_type(md))) == NULL) goto err; if ((algo->parameter = ASN1_TYPE_new()) == NULL) goto err; algo->parameter->type = V_ASN1_NULL; if (!TS_MSG_IMPRINT_set_algo(msg_imprint, algo)) goto err; if ((len = create_digest(data_bio, digest, md, &data)) == 0) goto err; if (!TS_MSG_IMPRINT_set_msg(msg_imprint, data, len)) goto err; if (!TS_REQ_set_msg_imprint(ts_req, msg_imprint)) goto err; if (policy && (policy_obj = txt2obj(policy)) == NULL) goto err; if (policy_obj && !TS_REQ_set_policy_id(ts_req, policy_obj)) goto err; /* Setting nonce if requested. */ if (!no_nonce && (nonce_asn1 = create_nonce(NONCE_LENGTH)) == NULL) goto err; if (nonce_asn1 && !TS_REQ_set_nonce(ts_req, nonce_asn1)) goto err; if (!TS_REQ_set_cert_req(ts_req, cert)) goto err; ret = 1; err: if (!ret) { TS_REQ_free(ts_req); ts_req = NULL; BIO_printf(bio_err, "could not create query\n"); ERR_print_errors(bio_err); } TS_MSG_IMPRINT_free(msg_imprint); X509_ALGOR_free(algo); OPENSSL_free(data); ASN1_OBJECT_free(policy_obj); ASN1_INTEGER_free(nonce_asn1); return ts_req; }
// register_files(tracker_task, myalias) // Registers this peer with the tracker, using 'myalias' as this peer's // alias. Also register all files in the current directory, allowing // other peers to upload those files from us. static void register_files(task_t *tracker_task, const char *myalias) { DIR *dir; struct dirent *ent; struct stat s; char buf[PATH_MAX]; size_t messagepos; assert(tracker_task->type == TASK_TRACKER); // Register address with the tracker. osp2p_writef(tracker_task->peer_fd, "ADDR %s %I:%d\n", myalias, listen_addr, listen_port); messagepos = read_tracker_response(tracker_task); message("* Tracker's response to our IP address registration:\n%s", &tracker_task->buf[messagepos]); if (tracker_task->buf[messagepos] != '2') { message("* The tracker reported an error, so I will not register files with it.\n"); return; } // Register files with the tracker. message("* Registering our files with tracker\n"); if ((dir = opendir(".")) == NULL) die("open directory: %s", strerror(errno)); while ((ent = readdir(dir)) != NULL) { int namelen = strlen(ent->d_name); // don't depend on unreliable parts of the dirent structure // and only report regular files. Do not change these lines. if (stat(ent->d_name, &s) < 0 || !S_ISREG(s.st_mode) || (namelen > 2 && ent->d_name[namelen - 2] == '.' && (ent->d_name[namelen - 1] == 'c' || ent->d_name[namelen - 1] == 'h')) || (namelen > 1 && ent->d_name[namelen - 1] == '~')) continue; char *digest; digest = create_digest(ent->d_name); osp2p_writef(tracker_task->peer_fd, "HAVE %s [%s]\n", ent->d_name, digest); message("* Registered file: %s, digest: %s\n", ent->d_name, digest); messagepos = read_tracker_response(tracker_task); if (tracker_task->buf[messagepos] != '2') error("* Tracker error message while registering '%s':\n%s", ent->d_name, &tracker_task->buf[messagepos]); } closedir(dir); }
/* Verify incoming Authorization/Proxy-Authorization header against existing * credentials. Will return TRUE if the authorization request matches any of * the credential. */ PJ_DEF(pj_bool_t) pjsip_auth_verify(const pjsip_authorization_hdr *hdr, const pj_str_t *method, const pjsip_cred_info *cred_info ) { if (pj_stricmp(&hdr->scheme, &pjsip_DIGEST_STR) == 0) { char digest_buf[MD5STRLEN]; pj_str_t digest; const pjsip_digest_credential *dig = &hdr->credential.digest; /* Check that username match. */ if (pj_strcmp(&dig->username, &cred_info->username) != 0) return PJ_FALSE; /* Check that realm match. */ if (pj_strcmp(&dig->realm, &cred_info->realm) != 0) return PJ_FALSE; /* Prepare for our digest calculation. */ digest.ptr = digest_buf; digest.slen = MD5STRLEN; /* Create digest for comparison. */ create_digest( &digest, &hdr->credential.digest.nonce, &hdr->credential.digest.nc, &hdr->credential.digest.cnonce, &hdr->credential.digest.qop, &hdr->credential.digest.uri, cred_info, method ); return pj_stricmp(&digest, &hdr->credential.digest.response) == 0; } else { pj_assert(0); return PJ_FALSE; } }
int main(int argc, char **argv) { pamc_handle_t pch; pamc_bp_t prompt = NULL; struct internal_packet packet_data, *packet; char *temp_string, *secret, *user, *a_cookie, *seqid, *digest; const char *cookie = "123451234512345"; int retval; packet = &packet_data; packet->length = 0; packet->at = 0; packet->buffer = NULL; pch = pamc_start(); if (pch == NULL) { fprintf(stderr, "server: unable to get a handle from libpamc\n"); exit(1); } temp_string = getlogin(); if (temp_string == NULL) { fprintf(stderr, "server: who are you?\n"); exit(1); } #define DOMAIN "@local.host" user = malloc(1+strlen(temp_string)+strlen(DOMAIN)); if (user == NULL) { fprintf(stderr, "server: out of memory for user id\n"); exit(1); } sprintf(user, "%s%s", temp_string, DOMAIN); append_string(packet, "secret@here/", 0); append_string(packet, user, 0); append_string(packet, "|", 0); append_string(packet, cookie, 0); packet_to_prompt(&prompt, PAM_BPC_SELECT, packet); /* get the library to accept the first packet (which should load the secret@here agent) */ retval = pamc_converse(pch, &prompt); fprintf(stderr, "server: after conversation\n"); if (PAM_BP_RCONTROL(prompt) != PAM_BPC_OK) { fprintf(stderr, "server: prompt had unexpected control type: %u\n", PAM_BP_RCONTROL(prompt)); exit(1); } fprintf(stderr, "server: got a prompt back\n"); prompt_to_packet(prompt, packet); temp_string = strtok(packet->buffer, "|"); if (temp_string == NULL) { fprintf(stderr, "server: prompt does not contain anything"); exit(1); } seqid = strdup(temp_string); if (seqid == NULL) { fprintf(stderr, "server: unable to store sequence id\n"); } temp_string = strtok(NULL, "|"); if (temp_string == NULL) { fprintf(stderr, "server: no cookie from agent\n"); exit(1); } a_cookie = strdup(temp_string); if (a_cookie == NULL) { fprintf(stderr, "server: no memory to store agent cookie\n"); exit(1); } fprintf(stderr, "server: agent responded with {%s|%s}\n", seqid, a_cookie); secret = identify_secret(user); fprintf(stderr, "server: secret=%s\n", secret); /* now, we construct the response */ packet->at = 0; append_string(packet, a_cookie, 0); append_string(packet, "|", 0); append_string(packet, cookie, 0); append_string(packet, "|", 0); append_string(packet, secret, 0); fprintf(stderr, "server: get digest of %s\n", packet->buffer); digest = create_digest(packet->at, packet->buffer); fprintf(stderr, "server: secret=%s, digest=%s\n", secret, digest); packet->at = 0; append_string(packet, seqid, 0); append_string(packet, "|", 0); append_string(packet, digest, 0); packet_to_prompt(&prompt, PAM_BPC_OK, packet); retval = pamc_converse(pch, &prompt); fprintf(stderr, "server: after 2nd conversation\n"); if (PAM_BP_RCONTROL(prompt) != PAM_BPC_DONE) { fprintf(stderr, "server: 2nd prompt had unexpected control type: %u\n", PAM_BP_RCONTROL(prompt)); exit(1); } prompt_to_packet(prompt, packet); PAM_BP_RENEW(&prompt, 0, 0); temp_string = strtok(packet->buffer, "|"); if (temp_string == NULL) { fprintf(stderr, "no digest from agent\n"); exit(1); } temp_string = strdup(temp_string); packet->at = 0; append_string(packet, secret, 0); append_string(packet, "|", 0); append_string(packet, cookie, 0); append_string(packet, "|", 0); append_string(packet, a_cookie, 0); fprintf(stderr, "server: get digest of %s\n", packet->buffer); digest = create_digest(packet->at, packet->buffer); fprintf(stderr, "server: digest=%s\n", digest); if (strcmp(digest, temp_string)) { fprintf(stderr, "server: agent doesn't know the secret\n"); fprintf(stderr, "server: agent says: [%s]\n" "server: server says: [%s]\n", temp_string, digest); exit(1); } else { fprintf(stderr, "server: agent seems to know the secret\n"); packet->at = 0; append_string(packet, cookie, 0); append_string(packet, "|", 0); append_string(packet, secret, 0); append_string(packet, "|", 0); append_string(packet, a_cookie, 0); digest = create_digest(packet->at, packet->buffer); fprintf(stderr, "server: putenv(\"AUTH_SESSION_TICKET=%s\")\n", digest); } retval = pamc_end(&pch); fprintf(stderr, "server: agent(s) were %shappy to terminate\n", retval == PAM_BPC_TRUE ? "":"un"); exit(!retval); }
// task_download(t, tracker_task) // Downloads the file specified by the input task 't' into the current // directory. 't' was created by start_download(). // Starts with the first peer on 't's peer list, then tries all peers // until a download is successful. static void task_download(task_t *t, task_t *tracker_task) { int i, ret = -1; size_t messagepos; assert((!t || t->type == TASK_DOWNLOAD) && tracker_task->type == TASK_TRACKER); //Read the checksum of the file from tracker: char *file_digest = 0; osp2p_writef(tracker_task->peer_fd, "MD5SUM %s\n", t->filename); messagepos = read_tracker_response(tracker_task); message("Tracker buf: %s\n", tracker_task->buf); if (tracker_task->buf[messagepos] != '2') { error("* Tracker error message while requesting checksum of '%s':\n%s", t->filename, &tracker_task->buf[messagepos]); } else{ file_digest = malloc(MD5_TEXT_DIGEST_SIZE+1); memcpy(file_digest, tracker_task->buf, MD5_TEXT_DIGEST_SIZE); file_digest[MD5_TEXT_DIGEST_SIZE] = 0; } // Quit if no peers, and skip this peer if (!t || !t->peer_list) { error("* No peers are willing to serve '%s'\n", (t ? t->filename : "that file")); task_free(t); return; } else if (t->peer_list->addr.s_addr == listen_addr.s_addr && t->peer_list->port == listen_port) goto try_again; t->disk_fd = open(t->disk_filename, O_WRONLY | O_CREAT | O_EXCL, 0666); if (t->disk_fd == -1 && errno != EEXIST) { error("* Cannot open local file"); goto try_again; } else if (t->disk_fd != -1) message("* Saving result to '%s'\n", t->disk_filename); int blockno = 0; int i_peer = 0; peer_t *apeer; while(1){ apeer = get_peer(t->peer_list, i_peer); // Connect to the peer and write the GET command message("* Connecting to %s:%d to download '%s'\n", inet_ntoa(apeer->addr), apeer->port, t->filename); t->peer_fd = open_socket(apeer->addr, apeer->port); if (t->peer_fd == -1) { error("* Cannot connect to peer: %s\n", strerror(errno)); goto try_again; } if(evil_mode == 0) osp2p_writef(t->peer_fd, "GET %s%d OSP2P\n", t->filename, blockno); else{ //******************************* //Exercise 3: try to overflow a peer's buffer by requesting a file with a long name char evil_name[2*FILENAMESIZ]; int i_name; for(i_name = 0; i_name < 2*FILENAMESIZ - 1; i_name++) evil_name[i_name] = 'a'; evil_name[i_name] = 0; osp2p_writef(t->peer_fd, "GET %s OSP2P\n", evil_name); //********************************** } // Open disk file for the result. // If the filename already exists, save the file in a name like // "foo.txt~1~". However, if there are 50 local files, don't download // at all. /* for (i = 0; i < 50; i++) { if (i == 0) strcpy(t->disk_filename, t->filename); else sprintf(t->disk_filename, "%s~%d~", t->filename, i); t->disk_fd = open(t->disk_filename, O_WRONLY | O_CREAT | O_EXCL, 0666); if (t->disk_fd == -1 && errno != EEXIST) { error("* Cannot open local file"); goto try_again; } else if (t->disk_fd != -1) { message("* Saving result to '%s'\n", t->disk_filename); break; } } if (t->disk_fd == -1) { error("* Too many local files like '%s' exist already.\n\ * Try 'rm %s.~*~' to remove them.\n", t->filename, t->filename); task_free(t); return; }*/ lseek(t->disk_fd, BLKSIZE, SEEK_CUR); // Read the file into the task buffer from the peer, // and write it from the task buffer onto disk. while (1) { int ret = read_to_taskbuf(t->peer_fd, t); if (ret == TBUF_ERROR) { error("* Peer read error"); goto try_again; } else if (ret == TBUF_END && t->head == t->tail) /* End of file */ break; ret = write_from_taskbuf(t->disk_fd, t); if (ret == TBUF_ERROR) { error("* Disk write error"); goto try_again; } //********************************* //Exercise 2: prevent from downloading a file that is too large if(t->total_written > MAX_FILE_SIZE){ error("* Error: file too big for download\n"); goto try_again; } //********************************** } if(ret == TBUF_END && t->head == t->tail) break; //Compare the checksum of file on disk to checksum reported by tracker: if(file_digest){ char *download_digest = create_digest(t->disk_filename); message("* Tracker's checksum for file '%s' is: %s\n", t->filename, file_digest); message("* Checksum of the downloaded file is: %s\n", download_digest); if(strcmp(file_digest, download_digest) != 0){ error("* Downloaded a corrupted file!!! Try download again...\n"); } } blockno++; i_peer++; } // Empty files are usually a symptom of some error. if (t->total_written > 0) { message("* Downloaded '%s' was %lu bytes long\n", t->disk_filename, (unsigned long) t->total_written); // Inform the tracker that we now have the file, // and can serve it to others! (But ignore tracker errors.) if (strcmp(t->filename, t->disk_filename) == 0) { osp2p_writef(tracker_task->peer_fd, "HAVE %s\n", t->filename); (void) read_tracker_response(tracker_task); } task_free(t); return; } error("* Download was empty, trying next peer\n"); try_again: if (t->disk_filename[0]) unlink(t->disk_filename); // recursive call task_pop_peer(t); task_download(t, tracker_task); }
/* * Generate response digest. * Most of the parameters to generate the digest (i.e. username, realm, uri, * and nonce) are expected to be in the credential. Additional parameters (i.e. * password and method param) should be supplied in the argument. * * The resulting digest will be stored in cred->response. * The pool is used to allocate 32 bytes to store the digest in cred->response. */ static pj_status_t respond_digest( pj_pool_t *pool, pjsip_digest_credential *cred, const pjsip_digest_challenge *chal, const pj_str_t *uri, const pjsip_cred_info *cred_info, const pj_str_t *cnonce, pj_uint32_t nc, const pj_str_t *method) { /* Check algorithm is supported. We only support MD5. */ if (chal->algorithm.slen && pj_stricmp(&chal->algorithm, &pjsip_MD5_STR)) { PJ_LOG(4,(THIS_FILE, "Unsupported digest algorithm \"%.*s\"", chal->algorithm.slen, chal->algorithm.ptr)); return -1; } /* Build digest credential from arguments. */ pj_strdup(pool, &cred->username, &cred_info->username); pj_strdup(pool, &cred->realm, &chal->realm); pj_strdup(pool, &cred->nonce, &chal->nonce); pj_strdup(pool, &cred->uri, uri); cred->algorithm = pjsip_MD5_STR; pj_strdup(pool, &cred->opaque, &chal->opaque); /* Allocate memory. */ cred->response.ptr = pj_pool_alloc(pool, MD5STRLEN); cred->response.slen = MD5STRLEN; if (chal->qop.slen == 0) { /* Server doesn't require quality of protection. */ /* Convert digest to string and store in chal->response. */ create_digest( &cred->response, &cred->nonce, NULL, NULL, NULL, uri, cred_info, method); } else if (has_auth_qop(pool, &chal->qop)) { /* Server requires quality of protection. * We respond with selecting "qop=auth" protection. */ cred->qop = pjsip_AUTH_STR; cred->nc.ptr = pj_pool_alloc(pool, 16); sprintf(cred->nc.ptr, "%06u", nc); if (cnonce && cnonce->slen) { pj_strdup(pool, &cred->cnonce, cnonce); } else { pj_str_t dummy_cnonce = { "b39971", 6}; pj_strdup(pool, &cred->cnonce, &dummy_cnonce); } create_digest( &cred->response, &cred->nonce, &cred->nc, cnonce, &pjsip_AUTH_STR, uri, cred_info, method ); } else { /* Server requires quality protection that we don't support. */ PJ_LOG(4,(THIS_FILE, "Unsupported qop offer %.*s", chal->qop.slen, chal->qop.ptr)); return -1; } return 0; }