int add_host_to_hostfile(const char *filename, const char *host, const Key *key, int store_hash) { FILE *f; int success = 0; char *hashed_host = NULL; if (key == NULL) return 1; /* XXX ? */ f = fopen(filename, "a"); if (!f) return 0; if (store_hash) { if ((hashed_host = host_hash(host, NULL, 0)) == NULL) { error("add_host_to_hostfile: host_hash failed"); fclose(f); return 0; } } fprintf(f, "%s ", store_hash ? hashed_host : host); if (key_write(key, f)) { success = 1; } else { error("add_host_to_hostfile: saving key in %s failed", filename); } fprintf(f, "\n"); fclose(f); return success; }
static void keyprint(con *c, Key *key) { char *host = c->c_output_name ? c->c_output_name : c->c_name; if (!key) return; if (hash_hosts && (host = host_hash(host, NULL, 0)) == NULL) fatal("host_hash failed"); fprintf(stdout, "%s ", host); key_write(key, stdout); fputs("\n", stdout); }
/** * ubifs_jrn_write_data - write a data node to the journal. * @c: UBIFS file-system description object * @inode: inode the data node belongs to * @key: node key * @buf: buffer to write * @len: data length (must not exceed %UBIFS_BLOCK_SIZE) * * This function writes a data node to the journal. Returns %0 if the data node * was successfully written, and a negative error code in case of failure. */ int ubifs_jrn_write_data(struct ubifs_info *c, const struct inode *inode, const union ubifs_key *key, const void *buf, int len) { int err, lnum, offs, compr_type, out_len; int dlen = UBIFS_DATA_NODE_SZ + UBIFS_BLOCK_SIZE * WORST_COMPR_FACTOR; const struct ubifs_inode *ui = ubifs_inode(inode); struct ubifs_data_node *data; dbg_jrn_key(c, key, "ino %lu, blk %u, len %d, key ", key_ino(c, key), key_block(c, key), len); ubifs_assert(len <= UBIFS_BLOCK_SIZE); data = kmalloc(dlen, GFP_NOFS); if (!data) return -ENOMEM; data->ch.node_type = UBIFS_DATA_NODE; key_write(c, key, &data->key); data->size = cpu_to_le32(len); zero_data_node_unused(data); if (!(ui->flags && UBIFS_COMPR_FL)) /* Compression is disabled for this inode */ compr_type = UBIFS_COMPR_NONE; else compr_type = ui->compr_type; out_len = dlen - UBIFS_DATA_NODE_SZ; ubifs_compress(buf, len, &data->data, &out_len, &compr_type); ubifs_assert(out_len <= UBIFS_BLOCK_SIZE); dlen = UBIFS_DATA_NODE_SZ + out_len; data->compr_type = cpu_to_le16(compr_type); err = make_reservation(c, DATAHD, dlen); if (err) goto out_free; err = write_node(c, DATAHD, data, dlen, &lnum, &offs); if (!err) ubifs_wbuf_add_ino_nolock(&c->jheads[DATAHD].wbuf, key_ino(c, key)); release_head(c, DATAHD); if (err) goto out_ro; err = ubifs_tnc_add(c, key, lnum, offs, dlen); if (err) goto out_ro; finish_reservation(c); kfree(data); return 0; out_ro: ubifs_ro_mode(c, err); finish_reservation(c); out_free: kfree(data); return err; }
/** * ubifs_jrn_update - update inode. * @c: UBIFS file-system description object * @dir: parent inode or host inode in case of extended attributes * @nm: directory entry name * @inode: inode * @deletion: indicates a directory entry deletion i.e unlink or rmdir * @sync: non-zero if the write-buffer has to be synchronized * @xent: non-zero if the directory entry is an extended attribute entry * * This function updates an inode by writing a directory entry (or extended * attribute entry), the inode itself, and the parent directory inode (or the * host inode) to the journal. * * The function writes the host inode @dir last, which is important in case of * extended attributes. Indeed, then we guarantee that if the host inode gets * synchronized, and the write-buffer it sits in gets flushed, the extended * attribute inode gets flushed too. And this is exactly what the user expects - * synchronizing the host inode synchronizes its extended attributes. * Similarly, this guarantees that if @dir is synchronized, its directory entry * corresponding to @nm gets synchronized too. * * This function returns %0 on success and a negative error code on failure. */ int ubifs_jrn_update(struct ubifs_info *c, const struct inode *dir, const struct qstr *nm, const struct inode *inode, int deletion, int sync, int xent) { int err, dlen, ilen, len, lnum, ino_offs, dent_offs; int aligned_dlen, aligned_ilen; int last_reference = !!(deletion && inode->i_nlink == 0); struct ubifs_dent_node *dent; struct ubifs_ino_node *ino; union ubifs_key dent_key, ino_key; dbg_jrn("ino %lu, dent '%.*s', data len %d in dir ino %lu", inode->i_ino, nm->len, nm->name, ubifs_inode(inode)->data_len, dir->i_ino); ubifs_assert(ubifs_inode(dir)->data_len == 0); dlen = UBIFS_DENT_NODE_SZ + nm->len + 1; ilen = UBIFS_INO_NODE_SZ; /* * If the last reference to the inode is being deleted, then there is no * need to attach and write inode data, it is being deleted anyway. */ if (!last_reference) ilen += ubifs_inode(inode)->data_len; aligned_dlen = ALIGN(dlen, 8); aligned_ilen = ALIGN(ilen, 8); len = aligned_dlen + aligned_ilen + UBIFS_INO_NODE_SZ; dent = kmalloc(len, GFP_NOFS); if (!dent) return -ENOMEM; if (!xent) { dent->ch.node_type = UBIFS_DENT_NODE; dent_key_init(c, &dent_key, dir->i_ino, nm); } else { dent->ch.node_type = UBIFS_XENT_NODE; xent_key_init(c, &dent_key, dir->i_ino, nm); } key_write(c, &dent_key, dent->key); dent->inum = deletion ? 0 : cpu_to_le64(inode->i_ino); dent->type = get_dent_type(inode->i_mode); dent->nlen = cpu_to_le16(nm->len); memcpy(dent->name, nm->name, nm->len); dent->name[nm->len] = '\0'; zero_dent_node_unused(dent); ubifs_prep_grp_node(c, dent, dlen, 0); ino = (void *)dent + aligned_dlen; pack_inode(c, ino, inode, 0, last_reference); ino = (void *)ino + aligned_ilen; pack_inode(c, ino, dir, 1, 0); err = make_reservation(c, BASEHD, len); if (err) goto out_free; if (last_reference) { err = ubifs_add_orphan(c, inode->i_ino); if (err) { release_head(c, BASEHD); goto out_finish; } } err = write_head(c, BASEHD, dent, len, &lnum, &dent_offs, sync); if (!sync && !err) { struct ubifs_wbuf *wbuf = &c->jheads[BASEHD].wbuf; ubifs_wbuf_add_ino_nolock(wbuf, inode->i_ino); ubifs_wbuf_add_ino_nolock(wbuf, dir->i_ino); } release_head(c, BASEHD); kfree(dent); if (err) goto out_ro; if (deletion) { err = ubifs_tnc_remove_nm(c, &dent_key, nm); if (err) goto out_ro; err = ubifs_add_dirt(c, lnum, dlen); } else err = ubifs_tnc_add_nm(c, &dent_key, lnum, dent_offs, dlen, nm); if (err) goto out_ro; /* * Note, we do not remove the inode from TNC even if the last reference * to it has just been deleted, because the inode may still be opened. * Instead, the inode has been added to orphan lists and the orphan * subsystem will take further care about it. */ ino_key_init(c, &ino_key, inode->i_ino); ino_offs = dent_offs + aligned_dlen; err = ubifs_tnc_add(c, &ino_key, lnum, ino_offs, ilen); if (err) goto out_ro; ino_key_init(c, &ino_key, dir->i_ino); ino_offs += aligned_ilen; err = ubifs_tnc_add(c, &ino_key, lnum, ino_offs, UBIFS_INO_NODE_SZ); if (err) goto out_ro; finish_reservation(c); return 0; out_finish: finish_reservation(c); out_free: kfree(dent); return err; out_ro: ubifs_ro_mode(c, err); if (last_reference) ubifs_delete_orphan(c, inode->i_ino); finish_reservation(c); return err; }
int ubifs_jrn_delete_xattr(struct ubifs_info *c, const struct inode *host, const struct inode *inode, const struct qstr *nm, int sync) { int err, xlen, hlen, len, lnum, xent_offs, aligned_xlen; struct ubifs_dent_node *xent; struct ubifs_ino_node *ino; union ubifs_key xent_key, key1, key2; dbg_jrn("host %lu, xattr ino %lu, name '%s', data len %d", host->i_ino, inode->i_ino, nm->name, ubifs_inode(inode)->data_len); ubifs_assert(inode->i_nlink == 0); /* * Since we are deleting the inode, we do not bother to attach any data * to it and assume its length is %UBIFS_INO_NODE_SZ. */ xlen = UBIFS_DENT_NODE_SZ + nm->len + 1; aligned_xlen = ALIGN(xlen, 8); hlen = ubifs_inode(host)->data_len + UBIFS_INO_NODE_SZ; len = aligned_xlen + UBIFS_INO_NODE_SZ + ALIGN(hlen, 8); xent = kmalloc(len, GFP_NOFS); if (!xent) return -ENOMEM; xent->ch.node_type = UBIFS_XENT_NODE; xent_key_init(c, &xent_key, host->i_ino, nm); key_write(c, &xent_key, xent->key); xent->inum = 0; xent->type = get_dent_type(inode->i_mode); xent->nlen = cpu_to_le16(nm->len); memcpy(xent->name, nm->name, nm->len); xent->name[nm->len] = '\0'; zero_dent_node_unused(xent); ubifs_prep_grp_node(c, xent, xlen, 0); ino = (void *)xent + aligned_xlen; pack_inode(c, ino, inode, 0, 1); ino = (void *)ino + UBIFS_INO_NODE_SZ; pack_inode(c, ino, host, 1, 0); err = make_reservation(c, BASEHD, len); if (err) { kfree(xent); return err; } err = write_head(c, BASEHD, xent, len, &lnum, &xent_offs, sync); if (!sync && !err) ubifs_wbuf_add_ino_nolock(&c->jheads[BASEHD].wbuf, host->i_ino); release_head(c, BASEHD); kfree(xent); if (err) goto out_ro; /* Remove the extended attribute entry from TNC */ err = ubifs_tnc_remove_nm(c, &xent_key, nm); if (err) goto out_ro; err = ubifs_add_dirt(c, lnum, xlen); if (err) goto out_ro; /* * Remove all nodes belonging to the extended attribute inode from TNC. * Well, there actually must be only one node - the inode itself. */ lowest_ino_key(c, &key1, inode->i_ino); highest_ino_key(c, &key2, inode->i_ino); err = ubifs_tnc_remove_range(c, &key1, &key2); if (err) goto out_ro; err = ubifs_add_dirt(c, lnum, UBIFS_INO_NODE_SZ); if (err) goto out_ro; /* And update TNC with the new host inode position */ ino_key_init(c, &key1, host->i_ino); err = ubifs_tnc_add(c, &key1, lnum, xent_offs + len - hlen, hlen); if (err) goto out_ro; finish_reservation(c); return 0; out_ro: ubifs_ro_mode(c, err); finish_reservation(c); return err; }
/* check to see if the script specified by file can authorize the key * * the script will have the key written to STDIN, which is identical * to the normal public key format. * * the script must exit with either 0 for success or 1 for failure. * the script can print login options (if any) to STDOUT. No whitepace should be added * to the output. * * Use with caution: the script can hang sshd. It is recommended you code the script * with a timeout set if it cannot determine authenication quickly. */ static int user_key_found_by_script(struct passwd *pw, Key *key, char *file) { pid_t pid; char line[SSH_MAX_PUBKEY_BYTES]; int pipe_in[2]; int pipe_out[2]; int exit_code = 1; int success = 0; FILE *f; //mysig_t oldsig; pipe(pipe_in); pipe(pipe_out); //oldsig = signal(SIGCHLD, SIG_IGN); temporarily_use_uid(pw); debug3("user_key_found_by_script: executing %s", file); switch ((pid = fork())) { case -1: error("fork(): %s", strerror(errno)); restore_uid(); return (-1); case 0: /* setup input pipe */ close(pipe_in[1]); dup2(pipe_in[0], 0); close(pipe_in[0]); /* setup output pipe */ close(pipe_out[0]); dup2(pipe_out[1], 1); close(pipe_out[1]); execl(file, file, NULL); /* exec failed */ error("execl(): %s", strerror(errno)); _exit(1); default: debug3("user_key_found_by_script: script pid %d", pid); close(pipe_in[0]); close(pipe_out[1]); f = fdopen(pipe_in[1], "w"); key_write(key, f); fclose(f); while(waitpid(pid, &exit_code, 0) < 0) { switch(errno) { case EINTR: debug3("user_key_found_by_script: waitpid() EINTR, continuing"); continue; default: error("waitpid(): %s", strerror(errno)); goto waitpid_error; } } if (WIFEXITED(exit_code) && WEXITSTATUS(exit_code) == 0) { int amt_read = read(pipe_out[0], line, sizeof(line) - 1); line[amt_read] = ' '; line[amt_read + 1] = 0; debug3("user_key_found_by_script: options: %s", line); if (auth_parse_options(pw, line, file, 0) == 1) success = 1; } waitpid_error: close(pipe_out[0]); } restore_uid(); //signal(SIGCHLD, oldsig); return success; }