]> Nishi Git Mirror - sp.git/commitdiff
最初コミット
author諏訪子 <suwako@076.moe>
Wed, 29 Nov 2023 12:19:53 +0000 (21:19 +0900)
committer諏訪子 <suwako@076.moe>
Wed, 29 Nov 2023 12:29:21 +0000 (21:29 +0900)
.gitignore [new file with mode: 0644]
Makefile [new file with mode: 0644]
addpass.c [new file with mode: 0644]
addpass.h [new file with mode: 0644]
main.c [new file with mode: 0644]
showpass.c [new file with mode: 0644]
showpass.h [new file with mode: 0644]
yankpass.c [new file with mode: 0644]
yankpass.h [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..324e468
--- /dev/null
@@ -0,0 +1,3 @@
+sp
+.ccls-cache
+*.o
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..1817151
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,24 @@
+NAME=sp
+VERSION=0.0.1
+# Linux、Haiku、かIllumos = /usr、FreeBSDかOpenBSD = /usr/local、NetBSD = /usr/pkg
+PREFIX=/usr
+CC=cc
+FILES=main.c showpass.c yankpass.c addpass.c
+CFLAGS=-Wall -Wextra -g
+LDFLAGS=-lgpgme
+
+all:
+       ${CC} ${CFLAGS} -o ${NAME} ${FILES} ${LDFLAGS}
+
+clean:
+       rm -f ${NAME}
+
+install: all
+       mkdir -p ${DESTDIR}${PREFIX}/bin
+       cp -f ${NAME} ${DESTDIR}${PREFIX}/bin
+       chmod 755 ${DESTDIR}${PREFIX}/bin/${NAME}
+
+uninstall:
+       rm -f ${DESTDIR}${PREFIX}/bin/${NAME}
+
+.PHONY: all clean install uninstall
diff --git a/addpass.c b/addpass.c
new file mode 100644 (file)
index 0000000..d4ac8f9
--- /dev/null
+++ b/addpass.c
@@ -0,0 +1,250 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#include <gpgme.h>
+#include <termios.h>
+
+#include "addpass.h"
+
+int mkdir_r(const char *path, mode_t mode) {
+  char tmp[256];
+  char *p = NULL;
+  size_t len;
+
+  snprintf(tmp, sizeof(tmp), "%s", path);
+  len = strlen(tmp);
+  if (tmp[len - 1] == '/') {
+    tmp[len - 1] = 0; // 最後の「/」文字を取り消す
+  }
+
+  for (p = tmp + 1; *p; p++) {
+    if (*p == '/') {
+      *p = 0; // 最後の「/」文字を取り消す
+      if (mkdir(tmp, mode) != 0 && errno != EEXIST) return -1;
+      *p = '/'; // また追加
+    }
+  }
+
+  if (mkdir(tmp, mode) != 0 && errno != EEXIST) {
+    return -1;
+  }
+
+  return 0;
+}
+
+void getpasswd(char* prompt, char*pw, size_t pwlen) {
+  struct termios old, new;
+  printf("%s", prompt);
+
+  // 端末設定を受け取る
+  tcgetattr(fileno(stdin), &old);
+  new = old;
+
+  // echoを無効にして
+  new.c_lflag &= ~ECHO;
+  tcsetattr(fileno(stdin), TCSANOW, &new);
+
+  // パスワードを読み込む
+  fgets(pw, pwlen, stdin);
+
+  // 端末設定をもとに戻す
+  tcsetattr(fileno(stdin), TCSANOW, &old);
+
+  // 改行文字を取り消す
+  pw[strcspn(pw, "\n")] = 0;
+}
+
+void addpass(char* file) {
+  char pass[100];
+  char knin[100];
+
+  // パスワードを受け取る
+  getpasswd("パスワード: ", pass, sizeof(pass));
+  puts("");
+  getpasswd("パスワード(確認用): ", knin, sizeof(knin));
+  puts("");
+
+  // パスワードが一致するかどうか確認
+  if (strcmp(pass, knin) != 0) {
+    fprintf(stderr, "パスワードが一致していません。終了…\n");
+    return;
+  }
+
+  // パスワードを保存する
+  gpgme_ctx_t ctx;
+  gpgme_error_t err;
+  gpgme_key_t key;
+  gpgme_data_t in, out;
+  FILE *gpgfile;
+
+  // GPGMEライブラリを設置
+  setlocale(LC_ALL, "");
+  gpgme_check_version(NULL);
+  gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
+
+  // GPGMEを創作
+  err = gpgme_new(&ctx);
+  if (err) {
+    fprintf(stderr, "GPGMEを創作に失敗:%s\n", gpgme_strerror(err));
+    return;
+  }
+
+  // GPGMEは非対話的モードに設定
+  err = gpgme_set_pinentry_mode(ctx, GPGME_PINENTRY_MODE_LOOPBACK);
+  if (err) {
+    fprintf(stderr, "pinentryモードを設定に失敗: %s\n", gpgme_strerror(err));
+    gpgme_release(ctx);
+    return;
+  }
+
+  // パスワードからデータオブジェクトを創作
+  err = gpgme_data_new_from_mem(&in, pass, strlen(pass), 0);
+  if (err) {
+    fprintf(stderr, "データオブジェクトを創作に失敗: %s\n", gpgme_strerror(err));
+    gpgme_release(ctx);
+    return;
+  }
+
+  gpgme_data_new(&out);
+
+  // パスを準備
+  char* homedir = getenv("HOME");
+  if (homedir == NULL) {
+    perror("ホームディレクトリを受取に失敗。");
+    return;
+  }
+
+  char* basedir = "/.local/share/sp/";
+
+  // 鍵を受け取る
+  char keypath[256];
+  snprintf(keypath, sizeof(keypath), "%s%s%s", homedir, basedir, ".gpg-id");
+  keypath[sizeof(keypath) - 1] = '\0';
+
+  FILE* keyfile = fopen(keypath, "rb");
+  if (keyfile == NULL) {
+    perror(".gpg-idファイルを開くに失敗。");
+    printf("失敗したパス: %s\n", keypath);
+    return;
+  }
+
+  char* keyid = malloc(100);
+  if (!fgets(keyid, 100, keyfile)) {
+    perror("鍵IDを読込に失敗。");
+    fclose(keyfile);
+    free(keyid);
+    return;
+  }
+
+  keyid[strcspn(keyid, "\n")] = 0;
+  fclose(keyfile);
+
+  err = gpgme_get_key(ctx, keyid, &key, 0);
+  if (err) {
+    fprintf(stderr, "鍵を受取に失敗: %s\n", gpgme_strerror(err));
+    free(keyid);
+    return;
+  }
+
+  if (key == NULL) {
+    fprintf(stderr, "エラー:鍵はNULLです。\n");
+    free(keyid);
+    return;
+  }
+
+  free(keyid);
+
+  // 暗号化
+  gpgme_key_t recp[1] = {key};
+  err = gpgme_op_encrypt(ctx, recp, GPGME_ENCRYPT_ALWAYS_TRUST, in, out);
+  if (err) {
+    fprintf(stderr, "暗号化に失敗: %s\n", gpgme_strerror(err));
+    gpgme_data_release(in);
+    gpgme_data_release(out);
+    gpgme_release(ctx);
+    gpgme_key_release(key);
+    return;
+  }
+
+  // 暗号化したタイルを開く
+  char* ext = ".gpg";
+  int alllen = snprintf(NULL, 0, "%s%s%s%s", homedir, basedir, file, ext) + 1;
+  char* gpgpath = malloc(alllen);
+  if (gpgpath == NULL) {
+    gpgme_data_release(in);
+    gpgme_data_release(out);
+    gpgme_release(ctx);
+    gpgme_key_release(key);
+    perror("メモリを割当に失敗。");
+    return;
+  }
+
+  // ディレクトリを創作
+  char dirpath[512];
+  snprintf(dirpath, sizeof(dirpath), "%s%s%s", homedir, basedir, file);
+  dirpath[sizeof(dirpath) - 1] = '\0';
+
+  char* lastsla = strrchr(dirpath, '/');
+  if (lastsla != NULL) {
+    *lastsla = '\0';
+    if (mkdir_r(dirpath, 0755) != 0) {
+      free(gpgpath);
+      gpgme_data_release(in);
+      gpgme_data_release(out);
+      gpgme_release(ctx);
+      gpgme_key_release(key);
+      perror("ディレクトリを創作に失敗。");
+      return;
+    }
+  }
+
+  sprintf(gpgpath, "%s%s%s%s", homedir, basedir, file, ext);
+  gpgfile = fopen(gpgpath, "wb");
+  if (gpgfile == NULL) {
+    perror("ファイルを開くに失敗。");
+    printf("失敗したパス: %s\n", gpgpath);
+    free(gpgpath);
+    gpgme_data_release(in);
+    gpgme_data_release(out);
+    gpgme_release(ctx);
+    gpgme_key_release(key);
+    return;
+  }
+
+  // データが保存したかどうか確認
+  ssize_t encrypted_data_size = gpgme_data_seek(out, 0, SEEK_END);
+  if (encrypted_data_size <= 0) {
+    fprintf(stderr, "データを保存に失敗。\n");
+    fclose(gpgfile);
+    free(gpgpath);
+    gpgme_data_release(in);
+    gpgme_data_release(out);
+    gpgme_release(ctx);
+    gpgme_key_release(key);
+    return;
+  }
+
+  // 復号化したパスワードを表示する
+  gpgme_data_seek(out, 0, SEEK_SET);
+
+  char buffer[512];
+  ssize_t read_bytes;
+  while ((read_bytes = gpgme_data_read(out, buffer, sizeof(buffer))) > 0) {
+    fwrite(buffer, 1, read_bytes, gpgfile);
+  }
+
+  // 掃除
+  fclose(gpgfile);
+  free(gpgpath);
+  gpgme_data_release(in);
+  gpgme_data_release(out);
+  gpgme_release(ctx);
+  gpgme_key_release(key);
+
+  printf("パスワードを保存出来ました。\n");
+}
diff --git a/addpass.h b/addpass.h
new file mode 100644 (file)
index 0000000..2fdff4f
--- /dev/null
+++ b/addpass.h
@@ -0,0 +1,6 @@
+#ifndef ADDPASS_H
+#define ADDPASS_H
+
+void addpass(char* file);
+
+#endif
diff --git a/main.c b/main.c
new file mode 100644 (file)
index 0000000..2ea0579
--- /dev/null
+++ b/main.c
@@ -0,0 +1,52 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include <gpgme.h>
+
+void initpass(char* gpgid);
+#include "showpass.h"
+#include "yankpass.h"
+void listpass(char* dir);
+#include "addpass.h"
+void delpass(char* file);
+void genpass(char* file, int count, bool issecure);
+void otppass(char* file);
+void helpme();
+
+const char* sofname = "sp";
+const char* version = "0.0.1";
+
+void helpme() {
+  printf("使い方:\n");
+  //printf("%s -i <gpg-id>                              :GPGと使ってパスワードストレージを初期設定\n", sofname);
+  printf("%s -s <パスワード名>                        :パスワードを表示\n", sofname);
+  printf("%s -y <パスワード名>                        :パスワードを表示せずクリップボードにコピーする\n", sofname);
+  //printf("%s -l                                       :パスワード一覧を表示\n", sofname);
+  printf("%s -a <パスワード名>                        :パスワードを追加\n", sofname);
+  //printf("%s -d <パスワード名>                        :パスワードを削除\n", sofname);
+  //printf("%s -g <文字数> [risk|secure] <パスワード名> :希望文字数でパスワードをランダムに作成して、追加する。risk=英数字のみ(不安)、secure=英数字+特別文字(デフォルト)を使用\n", sofname);
+  //printf("%s -o <パスワード名>\n                      :ワンタイムパスワード(TOTP)を表示。存在しなければ、創作する", sofname);
+  printf("%s -h                                       :ヘルプを表示\n", sofname);
+  printf("%s -v                                       :バージョンを表示\n", sofname);
+}
+
+int main (int argc, char* argv[]) {
+  if (argc < 2) {
+    helpme();
+    return 1;
+  }
+
+  if (argc == 3 && strcmp(argv[1], "-i") == 0) printf("TODO: 初期設定\n");
+  else if (argc == 3 && strcmp(argv[1], "-s") == 0) showpass(argv[2]);
+  else if (argc == 3 && strcmp(argv[1], "-y") == 0) yankpass(argv[2]);
+  else if (argc == 2 && strcmp(argv[1], "-l") == 0) printf("TODO: 一覧\n");
+  else if (argc == 3 && strcmp(argv[1], "-a") == 0) addpass(argv[2]);
+  else if (argc == 3 && strcmp(argv[1], "-d") == 0) printf("TODO: 削除\n");
+  else if ((argc == 4 || argc == 5) && strcmp(argv[1], "-g") == 0) printf("TODO: パスワードを創作\n");
+  else if (argc == 3 && strcmp(argv[1], "-o") == 0) printf("TODO: otp\n");
+  else if (argc == 2 && strcmp(argv[1], "-v") == 0) printf("%s-%s\n", sofname, version);
+  else helpme();
+
+  return 0;
+}
diff --git a/showpass.c b/showpass.c
new file mode 100644 (file)
index 0000000..8cb8dc8
--- /dev/null
@@ -0,0 +1,90 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <locale.h>
+
+#include <gpgme.h>
+
+#include "showpass.h"
+
+void showpass(char* file) {
+  gpgme_ctx_t ctx;
+  gpgme_error_t err;
+  gpgme_data_t in, out;
+  FILE *gpgfile;
+
+  // GPGMEライブラリを設置
+  setlocale(LC_ALL, "");
+  gpgme_check_version(NULL);
+  gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
+
+  // GPGMEを創作
+  err = gpgme_new(&ctx);
+  if (err) {
+    fprintf(stderr, "GPGMEを創作に失敗:%s\n", gpgme_strerror(err));
+    return;
+  }
+
+  // OpenPGPプロトコールを設定
+  gpgme_set_protocol(ctx, GPGME_PROTOCOL_OpenPGP);
+
+  // 暗号化したタイルを開く
+  char* homedir = getenv("HOME");
+  if (homedir == NULL) {
+    perror("ホームディレクトリを受取に失敗。");
+    return;
+  }
+
+  char* basedir = "/.local/share/sp/";
+  char* ext = ".gpg";
+  int alllen = snprintf(NULL, 0, "%s%s%s%s", homedir, basedir, file, ext) + 1;
+  char* gpgpath = malloc(alllen);
+  if (gpgpath == NULL) {
+    perror("メモリを割当に失敗。");
+    return;
+  }
+
+  sprintf(gpgpath, "%s%s%s%s", homedir, basedir, file, ext);
+  gpgfile = fopen(gpgpath, "rb");
+  if (gpgfile == NULL) {
+    perror("ファイルを開くに失敗。");
+    printf("失敗したパス: %s\n", gpgpath);
+    free(gpgpath);
+    return;
+  }
+  gpgme_data_new_from_stream(&in, gpgfile);
+
+  // データオブジェクトを創作
+  gpgme_data_new(&out);
+
+  // 復号化して
+  err = gpgme_op_decrypt(ctx, in, out);
+  if (err) {
+    fprintf(stderr, "復号化に失敗: %s\n", gpgme_strerror(err));
+
+    // 掃除
+    fclose(gpgfile);
+    free(gpgpath);
+    gpgme_data_release(in);
+    gpgme_data_release(out);
+    gpgme_release(ctx);
+    return;
+  }
+
+  // 復号化したパスワードを表示する
+  gpgme_data_seek(out, 0, SEEK_SET);
+
+  char buffer[512];
+  ssize_t read_bytes;
+  while ((read_bytes = gpgme_data_read(out, buffer, sizeof(buffer))) > 0) {
+    buffer[read_bytes] = '\0';
+    printf("%s", buffer);
+  }
+  puts("");
+
+  // 掃除
+  fclose(gpgfile);
+  free(gpgpath);
+  gpgme_data_release(in);
+  gpgme_data_release(out);
+  gpgme_release(ctx);
+}
diff --git a/showpass.h b/showpass.h
new file mode 100644 (file)
index 0000000..3c47d0f
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef SHOWPASS_H
+#define SHOWPASS_H
+
+void showpass(char* file);
+
+#endif
diff --git a/yankpass.c b/yankpass.c
new file mode 100644 (file)
index 0000000..e79fc51
--- /dev/null
@@ -0,0 +1,116 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <unistd.h>
+
+#include <gpgme.h>
+
+#include "yankpass.h"
+#include "showpass.h"
+
+void yankpass(char* file) {
+  // Xセッションではない場合(例えば、SSH、TTY、Gayland等)、showpass()を実行して
+  if (getenv("DISPLAY") == NULL) {
+    printf("Xセッションではありませんので、「sp -s」を実行します。\n");
+    showpass(file);
+    return;
+  }
+
+  gpgme_ctx_t ctx;
+  gpgme_error_t err;
+  gpgme_data_t in, out;
+  FILE *gpgfile;
+
+  // GPGMEライブラリを設置
+  setlocale(LC_ALL, "");
+  gpgme_check_version(NULL);
+  gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
+
+  // GPGMEを創作
+  err = gpgme_new(&ctx);
+  if (err) {
+    fprintf(stderr, "GPGMEを創作に失敗:%s\n", gpgme_strerror(err));
+    return;
+  }
+
+  // OpenPGPプロトコールを設定
+  gpgme_set_protocol(ctx, GPGME_PROTOCOL_OpenPGP);
+
+  // 暗号化したタイルを開く
+  char* homedir = getenv("HOME");
+  if (homedir == NULL) {
+    perror("ホームディレクトリを受取に失敗。");
+    return;
+  }
+
+  char* basedir = "/.local/share/sp/";
+  char* ext = ".gpg";
+  int alllen = snprintf(NULL, 0, "%s%s%s%s", homedir, basedir, file, ext) + 1;
+  char* gpgpath = malloc(alllen);
+  if (gpgpath == NULL) {
+    perror("メモリを割当に失敗。");
+    return;
+  }
+
+  sprintf(gpgpath, "%s%s%s%s", homedir, basedir, file, ext);
+  gpgfile = fopen(gpgpath, "rb");
+  if (gpgfile == NULL) {
+    perror("ファイルを開くに失敗。");
+    printf("失敗したパス: %s\n", gpgpath);
+    free(gpgpath);
+    return;
+  }
+  gpgme_data_new_from_stream(&in, gpgfile);
+
+  // データオブジェクトを創作
+  gpgme_data_new(&out);
+
+  // 復号化して
+  err = gpgme_op_decrypt(ctx, in, out);
+  if (err) {
+    fprintf(stderr, "復号化に失敗: %s\n", gpgme_strerror(err));
+
+    // 掃除
+    fclose(gpgfile);
+    free(gpgpath);
+    gpgme_data_release(in);
+    gpgme_data_release(out);
+    gpgme_release(ctx);
+    return;
+  }
+
+  // xclipを準備して
+  FILE *pipe = popen("xclip -selection clipboard", "w");
+  if (pipe == NULL) {
+
+    // 掃除
+    fclose(gpgfile);
+    free(gpgpath);
+    gpgme_data_release(in);
+    gpgme_data_release(out);
+    gpgme_release(ctx);
+    perror("クリップボードを見つけられませんでした。");
+    return;
+  }
+
+  // 復号化したパスワードを表示する
+  gpgme_data_seek(out, 0, SEEK_SET);
+
+  char buffer[512];
+  ssize_t read_bytes;
+  while ((read_bytes = gpgme_data_read(out, buffer, 511)) > 0) {
+    fwrite(buffer, 1, read_bytes, pipe);
+  }
+  pclose(pipe);
+
+  // 45秒後、クリップボードから削除する
+  sleep(45);
+  system("echo -n | xclip -selection clipboard");
+
+  // 掃除
+  fclose(gpgfile);
+  free(gpgpath);
+  gpgme_data_release(in);
+  gpgme_data_release(out);
+  gpgme_release(ctx);
+}
diff --git a/yankpass.h b/yankpass.h
new file mode 100644 (file)
index 0000000..7219787
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef YANKPASS_H
+#define YANKPASS_H
+
+void yankpass(char* file);
+
+#endif