├── .gitignore ├── LICENSE ├── Readme.md └── src ├── Makefile ├── autox.c └── autox.pam /.gitignore: -------------------------------------------------------------------------------- 1 | src/autox 2 | 3 | # Created by .ignore support plugin (hsz.mobi) 4 | ### C template 5 | # Object files 6 | *.o 7 | *.ko 8 | *.obj 9 | *.elf 10 | 11 | # Precompiled Headers 12 | *.gch 13 | *.pch 14 | 15 | # Libraries 16 | *.lib 17 | *.a 18 | *.la 19 | *.lo 20 | 21 | # Shared objects (inc. Windows DLLs) 22 | *.dll 23 | *.so 24 | *.so.* 25 | *.dylib 26 | 27 | # Executables 28 | *.exe 29 | *.out 30 | *.app 31 | *.i*86 32 | *.x86_64 33 | *.hex 34 | 35 | # Debug files 36 | *.dSYM/ 37 | ### JetBrains template 38 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio 39 | 40 | *.iml 41 | 42 | ## Directory-based project format: 43 | .idea/ 44 | # if you remove the above rule, at least ignore the following: 45 | 46 | # User-specific stuff: 47 | # .idea/workspace.xml 48 | # .idea/tasks.xml 49 | # .idea/dictionaries 50 | 51 | # Sensitive or high-churn files: 52 | # .idea/dataSources.ids 53 | # .idea/dataSources.xml 54 | # .idea/sqlDataSources.xml 55 | # .idea/dynamic.xml 56 | # .idea/uiDesigner.xml 57 | 58 | # Gradle: 59 | # .idea/gradle.xml 60 | # .idea/libraries 61 | 62 | # Mongo Explorer plugin: 63 | # .idea/mongoSettings.xml 64 | 65 | ## File-based project format: 66 | *.ipr 67 | *.iws 68 | 69 | ## Plugin-specific files: 70 | 71 | # IntelliJ 72 | /out/ 73 | 74 | # mpeltonen/sbt-idea plugin 75 | .idea_modules/ 76 | 77 | # JIRA plugin 78 | atlassian-ide-plugin.xml 79 | 80 | # Crashlytics plugin (for Android Studio and IntelliJ) 81 | com_crashlytics_export_strings.xml 82 | crashlytics.properties 83 | crashlytics-build.properties 84 | 85 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | THE MIT LICENSE (MIT) 2 | Copyright © 2016 James Sumners 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # autox 2 | 3 | This program automatically logs in a specified user in and runs the xinit 4 | program. 5 | 6 | On a sysvinit system, the benefit of using this, rather than starting xinit 7 | directly from inittab, is that you get the privileges as defined in the PAM 8 | rules. Also, the program terminates when X is quit. Thus it can be run 9 | repeatedly from inittab and automatically log the user in every time. 10 | 11 | *autox* has successfully been used for the same purpose in on an 12 | [Upstart][upstart] based system, and a [Runit][runit] based system. 13 | 14 | [upstart]: http://upstart.ubuntu.com/ 15 | [runit]: http://smarden.org/runit/ 16 | 17 | # Install 18 | 19 | Simply `make` and put the binary where you want it. Make sure you install 20 | `autox.pam` as `/etc/pam.d/autox`. 21 | 22 | ## Upstart Script 23 | 24 | ``` 25 | env USER=username 26 | env DISPLAY=:0.0 27 | 28 | description "autox startup script" 29 | author "Start in X session on boot" 30 | 31 | emits login-session-start 32 | emits desktop-session-start 33 | 34 | start on runlevel [5] #(filesystem and stopped udevtrigger) 35 | stop on runlevel [0136] 36 | 37 | respawn 38 | 39 | #script 40 | exec /usr/local/bin/autox $USER 2>/tmp/autox.log 41 | #end script 42 | ``` 43 | 44 | ## Runit Script 45 | 46 | ```bash 47 | #!/bin/sh 48 | USER=username 49 | 50 | exec 2>&1 51 | exec setsid -w agetty -a $USER -n -l /usr/local/bin/autox -o $USER tty7 38400 linux 52 | ``` 53 | 54 | Note: your `.xinitrc` should only `exec` *one* program, and it should remain 55 | in the foreground. If you `exec` anything as a background process then it will 56 | run outside of the `runsvdir` process tree and will not be managed by it. 57 | 58 | # License 59 | 60 | [MIT License](http://jsumners.mit-license.org/) 61 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | 2 | SRC := autox.c 3 | PROGRAM := autox 4 | 5 | all: autox.c 6 | $(CC) $(CFLAGS) -o $(PROGRAM) -lpam -lpam_misc $(LDFLAGS) $(SRC) 7 | debug: autox.c 8 | $(CC) $(CFLAGS) -o $(PROGRAM) -lpam -lpam_misc -g $(LDFLAGS) $(SRC) 9 | -------------------------------------------------------------------------------- /src/autox.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | //#include 11 | 12 | const char* PAM_DOMAIN = "autox"; 13 | 14 | static struct pam_conv conv = { 15 | misc_conv, 16 | NULL 17 | }; 18 | 19 | int pam_check_ret(pam_handle_t *handle, int ret, char msg[]); 20 | int setup_pam(pam_handle_t *pamh, char user[]); 21 | 22 | int main(int argc, char *argv[]) { 23 | int retval = 0; 24 | 25 | /*struct tm *curtime; 26 | time_t *time; 27 | curtime = localtime(time); 28 | fprintf(stderr, "Start time = %i:%i on %i/%i/%i\n", curtime->tm_hour, curtime->tm_min, curtime->tm_mon, curtime->tm_mday, curtime->tm_year); */ 29 | 30 | if (argc == 1) { 31 | printf("You mush supply a username!\n\te.g `autox myuser`\n"); 32 | return (retval = 1); 33 | } 34 | 35 | if (argc > 2) { 36 | fprintf(stderr, "Too many arguments supplied!\n"); 37 | return (retval = 1); 38 | } 39 | 40 | char *user = argv[1]; 41 | pam_handle_t *pamh = NULL; 42 | pid_t cpid = 0; 43 | pid_t wpid = 0; 44 | cpid = fork(); 45 | 46 | if (cpid == -1) { 47 | /* Could not start the X process. */ 48 | fprintf(stderr, "Could not fork child process!\n"); 49 | return 1; 50 | } 51 | 52 | /* Start the X session. */ 53 | if (cpid == 0) { 54 | /* Setup the user's environment. */ 55 | struct passwd *pw; 56 | pw = getpwnam(user); 57 | 58 | setenv("HOME", pw->pw_dir, 1); 59 | setenv("SHELL", pw->pw_shell, 1); 60 | setenv("USER", pw->pw_name, 1); 61 | setenv("LOGNAME", pw->pw_name, 1); 62 | /*setenv("DISPLAY", displayname, 1); */ 63 | chdir(pw->pw_dir); 64 | 65 | /* Setup the user's groups list. */ 66 | retval = initgroups(user, pw->pw_gid); 67 | if (retval == -1) { 68 | fprintf(stderr, "Could not set the user's groups!\n"); 69 | switch (errno) { 70 | case EPERM: 71 | fprintf(stderr, "Insufficient priviliges to create group list!\n"); 72 | break; 73 | case ENOMEM: 74 | fprintf(stderr, "Insufficient memory to create group list!\n"); 75 | break; 76 | } 77 | return errno; 78 | } 79 | 80 | /* Check with PAM. */ 81 | /* This must be done before the process uid and gid are changed. */ 82 | retval = setup_pam(pamh, user); 83 | if (retval) { 84 | return retval; 85 | } 86 | 87 | /* Change the process' uid and gid. */ 88 | setgid(pw->pw_gid); 89 | setuid(pw->pw_uid); 90 | 91 | /* All systems are a go! */ 92 | system("xinit"); 93 | } 94 | 95 | /* Wait for the X session to terminate so we can close the PAM session. */ 96 | do { 97 | wpid = waitpid(cpid, &retval, WUNTRACED | WCONTINUED); 98 | } while (!WIFEXITED(retval) && !WIFSIGNALED(retval)); 99 | 100 | retval = pam_close_session(pamh, 0); 101 | if (pam_check_ret(pamh, retval, "Close session error")) { 102 | return retval; 103 | } 104 | pam_end(pamh, retval); 105 | 106 | 107 | return retval; 108 | } 109 | 110 | int setup_pam(pam_handle_t *pamh, char user[]) { 111 | int retval = 0; 112 | 113 | /* Start PAM authentication. */ 114 | retval = pam_start(PAM_DOMAIN, user, &conv, &pamh); 115 | if ( pam_check_ret(pamh, retval, "Open authentication error") ) { 116 | return retval; 117 | } 118 | 119 | /* Set the PAM user variable. */ 120 | retval = pam_set_item(pamh, PAM_USER, user); 121 | if ( pam_check_ret(pamh, retval, "Set PAM user error") ) { 122 | return retval; 123 | } 124 | 125 | /* Establish the user's credentials. */ 126 | retval = pam_setcred(pamh, PAM_ESTABLISH_CRED); 127 | if ( pam_check_ret(pamh, retval, "Establish credentials error") ) { 128 | return retval; 129 | } 130 | 131 | /* Make sure the user still has permissions to login. */ 132 | retval = pam_acct_mgmt(pamh, 0); 133 | if ( pam_check_ret(pamh, retval, "Account management error") ) { 134 | return retval; 135 | } 136 | 137 | /* Start the session. */ 138 | retval = pam_open_session(pamh, 0); 139 | if ( pam_check_ret(pamh, retval, "Open session error") ) { 140 | return retval; 141 | } 142 | 143 | return 0; 144 | } 145 | 146 | int pam_check_ret(pam_handle_t *handle, int ret, char msg[]) { 147 | switch (ret) { 148 | case PAM_ABORT: 149 | case PAM_ACCT_EXPIRED: 150 | case PAM_AUTH_ERR: 151 | case PAM_BUF_ERR: 152 | case PAM_CRED_ERR: 153 | case PAM_CRED_EXPIRED: 154 | case PAM_CRED_UNAVAIL: 155 | case PAM_PERM_DENIED: 156 | case PAM_SYSTEM_ERR: 157 | case PAM_USER_UNKNOWN: 158 | fprintf(stderr, "%s: %s\n", msg, pam_strerror(handle, ret)); 159 | return ret; 160 | } 161 | 162 | return 0; 163 | } 164 | -------------------------------------------------------------------------------- /src/autox.pam: -------------------------------------------------------------------------------- 1 | #%PAM-1.0 2 | auth requisite pam_nologin.so 3 | auth required pam_env.so 4 | auth required pam_permit.so 5 | account required pam_unix.so 6 | password required pam_unix.so 7 | session required pam_limits.so 8 | session required pam_unix.so 9 | --------------------------------------------------------------------------------