/* RegisterEmail A webservice for selfhosted email servers to make it easy registering Emails (And optionally Enabling SSH) Copyright (C) 2024 Mike Nolan This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include const char* required_user = "tesses"; const char* mail = "mail"; const char* deny_group = "no_ssh"; const char* sudoer_group = "sudo"; void create_user(const char* username, const char* password, const char* fullname) { char cmdline[1024]; snprintf(cmdline,sizeof(cmdline),"/sbin/adduser %s",username); FILE* f=popen(cmdline,"w"); fprintf(f,"%s\n%s\n%s\n\n\n\n\ny\n",password,password,fullname); fflush(f); fclose(f); snprintf(cmdline,sizeof(cmdline),"/sbin/usermod -aG %s %s",mail, username); system(cmdline); } void block_ssh(const char* username) { char cmdline[1024]; snprintf(cmdline,sizeof(cmdline),"/sbin/usermod -aG %s %s",deny_group,username); system(cmdline); } void enable_sudo(const char* username) { char cmdline[1024]; snprintf(cmdline,sizeof(cmdline),"/sbin/usermod -aG %s %s",sudoer_group,username); system(cmdline); } //https://stackoverflow.com/a/63173069 bool password_correct(const char* user, const char* password) { struct passwd* passwdEntry = getpwnam( user ); if ( !passwdEntry ) { printf( "User '%s' doesn't exist\n", user ); return false; } if ( 0 != strcmp( passwdEntry->pw_passwd, "x" ) ) { return strcmp( passwdEntry->pw_passwd, crypt( password, passwdEntry->pw_passwd ) ) == 0; } else { // password is in shadow file struct spwd* shadowEntry = getspnam( user ); if ( !shadowEntry ) { printf( "Failed to read shadow entry for user '%s'\n", user ); return false; } return strcmp( shadowEntry->sp_pwdp, crypt( password, shadowEntry->sp_pwdp ) ) == 0; } } int main(int argc,char** argv) { struct json_t* json=json_loadf(stdin,0,NULL); if(json) { struct json_t* username= json_object_get(json,"username"); struct json_t* password=json_object_get(json,"password"); struct json_t* admin_username = json_object_get(json,"admin_user"); struct json_t* admin_password = json_object_get(json,"admin_pass"); struct json_t* full_name = json_object_get(json,"fullname"); struct json_t* has_sudo = json_object_get(json,"has_sudo"); struct json_t* can_login_ssh = json_object_get(json,"can_login_ssh"); if(json_typeof(username) == JSON_STRING && json_typeof(password) == JSON_STRING && json_typeof(admin_username) == JSON_STRING && json_typeof(admin_password) == JSON_STRING && json_typeof(full_name) == JSON_STRING) { if(json_string_length(username) > 256) return 1; const char* _username = json_string_value(username); const char* _password = json_string_value(password); const char* _admin_user = json_string_value(admin_username); const char* _admin_pass = json_string_value(admin_password); const char* _fullname = json_string_value(full_name); if(strcmp(_admin_user,required_user) != 0 || !password_correct(_admin_user,_admin_pass)) { return EX_NOPERM; } create_user(_username,_password,_fullname); if(json_typeof(has_sudo) == JSON_TRUE) { enable_sudo(_username); } if(json_typeof(can_login_ssh) == JSON_FALSE) { block_ssh(_username); } json_decref(json); return 0; } json_decref(json); return EX_DATAERR; } return EX_DATAERR; }