[C言語] ユーザID

全てのユーザにはuidという個別の数値が割り当てられる

$ id root
uid=0(root) gid=0(root) groups=0(root)
$ id vagrant
uid=1000(vagrant) gid=1000(vagrant) groups=1000(vagrant),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),110(lxd)

hacking.h

void fatal(char *message) {
    char error_message[100];

    strcpy(error_message, "[!!]致命的なエラー:");
    strncat(error_message, message, 83);
    perror(error_message);
    exit(-1);
}

void *ec_malloc(unsigned int size) {
    void *ptr;
    ptr = malloc(size);
    if(ptr == NULL)
        fatal("ec_malloc()内でメモリ割り当てに失敗しました。");
    return ptr;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "hacking.h"

void usage(char *prog_name, char *filename){
    printf("使用方法: %s <%sに追加するデータ>\n", prog_name, filename);
    exit(0);
}

void fatal(char *);
void *ec_malloc(unsigned int);

int main(int argc, char *argv[]) {
    int userid, fd;
    char *buffer, *datafile;

    buffer = (char *) ec_malloc(100);
    datafile = (char *) ec_malloc(20);
    strcpy(datafile, "./notes");

    if(argc < 2)
        usage(argv[0], datafile);

    strcpy(buffer, argv[1]);

    printf("[DEBUG] buffer @ %p: \'%s\'\n", buffer, buffer);
    printf("[DEBUG] datafile @ %p: \'%s\'\n", datafile, datafile);

    fd = open(datafile, O_WRONLY|O_CREAT|O_APPEND, S_IRUSR|S_IWUSR);
    if(fd == -1)
        fatal("main()内、ファイルのオープン中にエラーが発生しました。");
    printf("[DEBUG] ファイル記述子]:%d\n", fd);

    userid = getuid();

    if(write(fd, &userid, 4) == -1)
        fatal("main()内、ファイルへのユーザIDの書き込みでエラーが発生しました。");
    write(fd, "\n", 1);

    if(write(fd, buffer, strlen(buffer)) == -1)
        fatal("main()内、ファイルへのバッファの書き込みでエラーが発生しました。");
    write(fd, "\n", 1);

    if(close(fd) == -1)
        fatal("main()内、ファイルのクローズ中にエラーが発生しました。");

    printf("メモが保存されました。\n");
    free(buffer);
    free(datafile);

    return 0;
}

$ gcc -o main main.c
$ ls -l ./main
-rwxrwxr-x 1 vagrant vagrant 13664 Feb 12 02:26 ./main

$ sudo chown root:root ./main
$ sudo chmod u+s ./main
$ ls -l ./main
-rwsrwxr-x 1 root root 13664 Feb 12 02:26 ./main

$ ./main “this is a test of multiuser notes”
[DEBUG] buffer @ 0xaaaaf83ba2a0: ‘this is a test of multiuser notes’
[DEBUG] datafile @ 0xaaaaf83ba310: ‘./notes’
[DEBUG] ファイル記述子]:3
メモが保存されました。
$ ls -l ./notes
-rw——- 1 root vagrant 39 Feb 12 02:31 ./notes
$ sudo cat ./notes

this is a test of multiuser notes
$ sudo hexdump -C ./notes
00000000 e8 03 00 00 0a 74 68 69 73 20 69 73 20 61 20 74 |…..this is a t|
00000010 65 73 74 20 6f 66 20 6d 75 6c 74 69 75 73 65 72 |est of multiuser|
00000020 20 6e 6f 74 65 73 0a | notes.|

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "hacking.h"
#define FILENAME "./notes"

int print_notes(int, int, char *);
int find_user_note(int, int);
int search_note(char *, char *);
void fatal(char *);

int main(int argc, char *argv[]) {
    int userid, printing=1, fd;
    char searchstring[100];

    if(argc > 1)
        strcpy(searchstring, argv[1]);
    else
        searchstring[0] = 0;

    userid = getuid();
    fd = open(FILENAME, O_RDONLY);
    if(fd == -1)
        fatal("main()内、ファイルの読み込みオープンでエラーが発生しました。");

    while(printing)
        printing = print_notes(fd, userid, searchstring);
    printf("-----[ メモの終わり ]------\n");
    close(fd);    

    return 0;
}

int print_notes(int fd, int uid, char *searchstring) {
    int note_length;
    char byte=0, note_buffer[100];

    note_length = find_user_note(fd, uid);
    if(note_length == -1)
        return 0;

    read(fd, note_buffer, note_length);
    note_buffer[note_length] = 0;

    if(search_note(note_buffer, searchstring))
        printf(note_buffer);
    return 1;
}

int find_user_note(int fd, int user_uid) {
    int note_uid = -1;
    unsigned char byte;
    int length;

    while(note_uid != user_uid){
        if(read(fd, &note_uid, 4) != 4)
            return -1;
        if(read(fd, &byte, 1) != 1)
            return -1;

        byte = length = 0;
        while(byte != '\n'){
            if(read(fd, &byte, 1) != 1)
                return -1;
            length++;
        }
    }
    lseek(fd, length * -1L, SEEK_CUR);

    printf("[DEBUG] uid %dの%dバイトのメモを見つけました\n", note_uid, length);
    return length;
}

int search_note(char *note, char *keyword){
    int i, keyword_length, match=0;

    keyword_length = strlen(keyword);
    if(keyword_length == 0)
        return 1;

    for(i=0; i<strlen(note); i++){
        if(note[i] == keyword[match])
            match++;
        else {
            if(note[i] == keyword[0])
                match = 1;
            else
                match = 0;
        }
        if(match == keyword_length)
            return 1;
    }
    return 0;
}

$ ./main
[DEBUG] uid 1000の34バイトのメモを見つけました
this is a test of multiuser notes
—–[ メモの終わり ]——