目录
一.前言
上次说要使用Waland来构建基础图形,但想了想,先是完成一些简单基础的内容才是正道
本文里的代码是在 Ubuntu23.04 里完成的,使用了C与Rust混合编写
二.Linux发行版的用户管理
Linux发行版中的用户管理是操作系统管理的一个重要部分,它涉及到用户账户的创建、配置、维护和删除。
-
安全性:
不同用户可以拥有不同的权限和访问控制,通过用户管理,管理员能够确保只有授权用户才可以访问特定资源和敏感信息。这有助于保护系统和数据不被未授权访问。 -
资源控制:
系统资源(如 CPU、内存、存储和网络等)的分配和使用可以通过用户管理进行监控和控制,以确保资源得到公平合理的分配。 -
活动审计:
用户管理使得系统管理员能够追踪和监视用户活动,这有助于发现并解决安全事件,进行合规审计。 -
多用户环境:
Linux 支持多用户使用,在同一系统上可以有多个用户共享资源而不相互干扰,用户管理提供了用户隔离和资源分配的机制。 -
方便系统管理:
通过用户管理,管理员可以批量管理用户(如添加、删除、修改用户信息),提高系统管理的效率。
可以看出用户管理对的重要性
三.GenesisOS的用户管理
目前是这样设计的:
可能看起来有点简单,先这样
四.动手实践
值得注意的是,我们的数据存储在/etc里,是一个数据库,这一点与其他发行版不同,后面将实现权限设置,以确保该数据库只能被系统应用所访问
使用数据库,我认为有几个优点:
- 数据持久性:数据库能够存储数据,即使系统重启或出现故障,数据依然存在。
- 并发访问:多个用户可以同时访问和操作数据库中的数据,数据库管理系统负责处理并发问题。
- 数据完整性:数据库管理系统通常会提供机制以确保数据的完整性和一致性。
- 灵活查询:通过使用 SQL,用户可以灵活地查询和分析数据。
当然,不同设计有不同看法,以上均为个人观点,接下来我们来看以下代码
code.h
#ifndef GENESISOS_CODE_H
#define GENESISOS_CODE_H
#define WRONG -2
#define UNDONE -1
#define UNEXIST 0
#define DONE 1
#define EXIST 2
#endif //GENESISOS_CODE_H
定义了一些能用得到的状态,字面意思,应该不用解释...
GError.c
#include <GError.h>
int Warning(const char* app, const char* value)
{
printf("\033[31m%s(Warning): %s\n\033[0m", app, value);
return 0;
}
int Error(const char* app, const char* value)
{
printf("\033[31m%s(Error): %s\n\033[0m", app, value);
exit(1);
}
实现了两个函数,用于警告与错误输出 ,其实就是为了方便处理
GError.h
#ifndef GENESISOS_GERROR_H
#define GENESISOS_GERROR_H
#include <code.h>
#include <stdio.h>
#include <stdlib.h>
int Error(const char* app, const char* value);
int Warning(const char* app,const char* value);
#endif //GENESISOS_GERROR_H
usr_db.c
#include <usr_db.h>
const char* new_usr_table_i = "CREATE TABLE usr ("
"usr_name CHAR(50) NOT NULL,"
"password CHAR(50) NOT NULL,"
"uid INT NOT NULL,"
"home CHAR(50) NOT NULL,"
"shell CHAR(50) NOT NULL,"
"things CHAR(200) NOT NULL,"
"account CHAR(100),"
"account_s CHAR(3) NOT NULL"
");"
"CREATE TABLE lia ("
"usr_name CHAR(50) NOT NULL,"
"uid INT NOT NULL,"
"home CHAR(50) NOT NULL,"
"shell CHAR(50) NOT NULL"
");";
const char* lia_del_all_i = "DELETE FROM lia;";
const char* lia_del_i = "DELETE FROM lia WHERE usr_name = ?;";
const char* lia_check_i = "SELECT 1 FROM lia WHERE usr_name = ? LIMIT 1;";
const char* check_usr_db_i = "SELECT 1 FROM usr WHERE usr_name = ? LIMIT 1;";
const char* check_usr_password_i = "SELECT password FROM usr WHERE usr_name = ?;";
const char* lia_add_i = "INSERT INTO lia (usr_name,uid,home,shell) VALUES (?,?,?,?);";
const char* get_usr_info_db_i = "SELECT uid, home, shell FROM usr WHERE usr_name = ?;";
const char* add_usr_db_i = "INSERT INTO usr (usr_name,password,uid,home,shell,things,account,account_s) VALUES (?,?,?,?,?,?,?,?);";
char *app = "usrcontrol";
int new_usr_table() {
sqlite3 *db;
char msg[100];
if (sqlite3_open(DB, &db) != SQLITE_OK) {
snprintf(msg, sizeof(msg), "%s", sqlite3_errmsg(db));
Error(app,msg);
}
char *errMsg;
if (sqlite3_exec(db, new_usr_table_i, NULL, NULL, &errMsg) != SQLITE_OK) {
snprintf(msg, sizeof(msg), "%s", errMsg);
sqlite3_free(errMsg);
Error(app,msg);
}
sqlite3_close(db);
return DONE;
}
int add_usr_db(const char* name, const char* password, int uid, const char* home, const char* shell, const char* things) {
sqlite3 *db;
sqlite3_stmt *stmt;
char msg[100];
if (sqlite3_open_v2(DB, &db, SQLITE_OPEN_READWRITE, NULL) != SQLITE_OK) {
Error(app,"Unable to open the database, please check the system integrity or initialize the database with 'usrcontrol -i'!");
}
if (sqlite3_prepare_v2(db, add_usr_db_i, -1, &stmt, NULL) != SQLITE_OK) {
snprintf(msg, sizeof(msg), "%s", sqlite3_errmsg(db));
sqlite3_close(db);
Error(app,msg);
}
sqlite3_bind_text(stmt, 1, name, -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 2, password, -1, SQLITE_TRANSIENT);
sqlite3_bind_int(stmt, 3, uid);
sqlite3_bind_text(stmt, 4, home, -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 5, shell, -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 6, things, -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 7, "", -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 8, "NO", -1, SQLITE_TRANSIENT);
if (sqlite3_step(stmt) != SQLITE_DONE) {
snprintf(msg, sizeof(msg), "%s", sqlite3_errmsg(db));
sqlite3_finalize(stmt);
sqlite3_close(db);
Error(app,msg);
}
sqlite3_finalize(stmt);
sqlite3_close(db);
return DONE;
}
int check_usr_db(const char* name, const char* password) {
sqlite3 *db;
sqlite3_stmt *stmt;
char msg[100];
int state = UNDONE;
if (sqlite3_open_v2(DB, &db, SQLITE_OPEN_READWRITE, NULL) != SQLITE_OK) {
Error(app,"Unable to open the database, please check the system integrity or initialize the database with 'usrcontrol -i'!");
}
if (sqlite3_prepare_v2(db, check_usr_db_i, -1, &stmt, NULL) != SQLITE_OK) {
snprintf(msg, sizeof(msg), "Error preparing statement: %s", sqlite3_errmsg(db));
sqlite3_close(db);
Error(app,msg);
}
sqlite3_bind_text(stmt, 1, name, -1, SQLITE_TRANSIENT);
if (sqlite3_step(stmt) != SQLITE_ROW) {
snprintf(msg, sizeof(msg), "The target user does not exist: %s", name);
sqlite3_finalize(stmt);
sqlite3_close(db);
Error(app,msg);
}
sqlite3_finalize(stmt);
if (sqlite3_prepare_v2(db, check_usr_password_i, -1, &stmt, NULL) != SQLITE_OK) {
snprintf(msg, sizeof(msg), "Error preparing statement for password check: %s", sqlite3_errmsg(db));
sqlite3_finalize(stmt);
sqlite3_close(db);
Error(app,msg);
}
sqlite3_bind_text(stmt, 1, password, -1, SQLITE_TRANSIENT);
if (sqlite3_step(stmt) == SQLITE_ROW) {
state = DONE;
} else {
state = UNDONE;
}
sqlite3_finalize(stmt);
sqlite3_close(db);
return state;
}
int get_usr_info_db(const char* name, const char* password, int *uid, char **home, char **shell) {
sqlite3 *db;
sqlite3_stmt *stmt;
char msg[100];
int state = UNDONE;
if (sqlite3_open_v2(DB, &db, SQLITE_OPEN_READONLY, NULL) != SQLITE_OK) {
Error(app,"Unable to open the database for reading user info!");
}
if (sqlite3_prepare_v2(db, get_usr_info_db_i, -1, &stmt, NULL) != SQLITE_OK) {
snprintf(msg, sizeof(msg), "%s", sqlite3_errmsg(db));
sqlite3_close(db);
Error(app,msg);
}
if (check_usr_db(name, password) != DONE){
return UNDONE;
}
sqlite3_bind_text(stmt, 1, name, -1, SQLITE_TRANSIENT);
if (sqlite3_step(stmt) == SQLITE_ROW) {
*uid = sqlite3_column_int(stmt, 0);
*home = strdup((const char *)sqlite3_column_text(stmt, 1));
*shell = strdup((const char *)sqlite3_column_text(stmt, 2));
state = DONE;
} else {
sqlite3_finalize(stmt);
sqlite3_close(db);
return UNDONE;
}
sqlite3_finalize(stmt);
sqlite3_close(db);
return state;
}
int lia_check(const char* name){
sqlite3 *db;
sqlite3_stmt *stmt;
char msg[100];
int state = UNEXIST;
if (sqlite3_open_v2(DB, &db, SQLITE_OPEN_READWRITE, NULL) != SQLITE_OK) {
Error(app,"Unable to open the database, please check the system integrity or initialize the database with 'usrcontrol -i'!");
}
if (sqlite3_prepare_v2(db, lia_check_i, -1, &stmt, NULL) != SQLITE_OK) {
snprintf(msg, sizeof(msg), "Error preparing statement: %s", sqlite3_errmsg(db));
sqlite3_close(db);
Error(app,msg);
}
sqlite3_bind_text(stmt, 1, name, -1, SQLITE_TRANSIENT);
if (sqlite3_step(stmt) != SQLITE_ROW) {
state = UNEXIST;
} else {
state = EXIST;
}
sqlite3_finalize(stmt);
sqlite3_close(db);
return state;
}
int lia_add(const char* name, const char* password){
sqlite3 *db;
sqlite3_stmt *stmt;
int uid = 0;
char *home = NULL;
char *shell = NULL;
char msg[100];
int state = UNDONE;
if (sqlite3_open_v2(DB, &db, SQLITE_OPEN_READWRITE, NULL) != SQLITE_OK) {
Error(app,"Unable to open the database for reading user info!");
}
if (sqlite3_prepare_v2(db, lia_add_i, -1, &stmt, NULL) != SQLITE_OK) {
snprintf(msg, sizeof(msg), "%s", sqlite3_errmsg(db));
sqlite3_close(db);
Error(app,msg);
}
if (get_usr_info_db(name, password, &uid, &home, &shell) != DONE) {
return UNDONE;
}
sqlite3_bind_text(stmt, 1, name, -1, SQLITE_TRANSIENT);
sqlite3_bind_int(stmt, 2, uid);
sqlite3_bind_text(stmt, 3, home, -1, SQLITE_TRANSIENT);
sqlite3_bind_text(stmt, 4, shell, -1, SQLITE_TRANSIENT);
state = DONE;
if (sqlite3_step(stmt) != SQLITE_DONE) {
snprintf(msg, sizeof(msg), "%s", sqlite3_errmsg(db));
sqlite3_finalize(stmt);
sqlite3_close(db);
Error(app,msg);
}
sqlite3_finalize(stmt);
sqlite3_close(db);
free(home);
free(shell);
return state;
}
int lia_del(const char* name){
sqlite3 *db;
sqlite3_stmt *stmt;
char msg[100];
int state = UNDONE;
if (sqlite3_open_v2(DB, &db, SQLITE_OPEN_READWRITE, NULL) != SQLITE_OK) {
Error(app,"Unable to open the database for reading user info!");
}
if (sqlite3_prepare_v2(db, lia_del_i, -1, &stmt, NULL) != SQLITE_OK) {
snprintf(msg, sizeof(msg), "%s", sqlite3_errmsg(db));
sqlite3_close(db);
Error(app,msg);
}
if (lia_check(name) != EXIST){
sqlite3_close(db);
Error(app,"The user is not logged in!");
}
sqlite3_bind_text(stmt, 1, name, -1, SQLITE_TRANSIENT);
state = DONE;
if (sqlite3_step(stmt) != SQLITE_DONE) {
snprintf(msg, sizeof(msg), "%s", sqlite3_errmsg(db));
sqlite3_finalize(stmt);
sqlite3_close(db);
Error(app,msg);
}
sqlite3_finalize(stmt);
sqlite3_close(db);
return state;
}
int lia_del_all(){
sqlite3 *db;
char msg[100];
char *errMsg = 0;
if (sqlite3_open_v2(DB, &db, SQLITE_OPEN_READWRITE, NULL) != SQLITE_OK) {
Error(app,"Unable to open the database for reading user info!");
}
if (sqlite3_exec(db, lia_del_all_i, 0, 0, &errMsg) != SQLITE_OK){
snprintf(msg, sizeof(msg), "%s", errMsg);
sqlite3_free(errMsg);
sqlite3_close(db);
Error(app,msg);
}
sqlite3_close(db);
return DONE;
}
这是今天最重要的,应该容易理解,调用sqlite3,初始化数据库,准备语句,绑定参数,提交更改,关闭数据库
这只是一个最基础的部分,提供的函数,不能够服务与usrcontrol,下次在记录更多代码。
注意,Error()函数已经提供了exit(1),所以Error()后的代码不会被执行。
usr_db.h
#ifndef GENESISOS_USR_DB_H
#define GENESISOS_USR_DB_H
#include <code.h>
#include <GError.h>
#include <stdlib.h>
#include <string.h>
#include <sqlite3.h>
#define DB "./usr.db"
extern char *app;
extern const char* lia_add_i;
extern const char* lia_del_i;
extern const char* lia_check_i;
extern const char* add_usr_db_i;
extern const char* lia_del_all_i;
extern const char* check_usr_db_i;
extern const char* new_usr_table_i;
extern const char* get_usr_info_db_i;
extern const char* check_usr_password_i;
int lia_del_all();
int new_usr_table();
int lia_del(const char* name);
int lia_check(const char* name);
int lia_add(const char* name, const char* password);
int check_usr_db(const char* name,const char* password);
int get_usr_info_db(const char* name, const char* password, int *uid, char **home, char **shell);
int add_usr_db(const char* name,const char* password,int uid,const char* home,const char* shell,const char* things);
#endif //GENESISOS_USR_DB_H
对usr_db.c的声明,DB这个定义之后会进行修改,目前为了方便,先这样写着。
Makefile
# 定义变量
CC = gcc
CFLAGS = -Wall -I./ -I./../sys_api
LDFLAGS = -lsqlite3
# 源文件
SRCS = usr_db.c ../sys_api/GError.c
OBJS = $(SRCS:.c=.o)
# 输出的可执行文件名
TARGET = usrcontrol
# 默认目标
all: $(TARGET)
# 链接目标
$(TARGET): $(OBJS)
$(CC) -o $@ $^ $(LDFLAGS)
# 编译源文件为目标文件
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
# 清理目标文件和可执行文件
clean:
rm -f $(OBJS) $(TARGET)
.PHONY: all clean
对了,说起makefile,你应该这样放置文件
.
├── sys_api
│ ├── code.h
│ ├── GError.c
│ └── GError.h
└── usr
├── Makefile
├── usr.db
├── usr_db.c
└── usr_db.h
五.结尾
这只是一个雏形(可能雏形都算不上),但只有经过不断尝试,完善,才会更好。
这次的代码我把他们上传到了Gitee:冰之/GenesisOShttps://gitee.com/mf2022/genesis-os.git
对了,这里面的代码都经过测试,都可以去编写main()函数去调用的