Initial check-in.
authorfredrik <fredrik@959494ce-11ee-0310-bf91-de5d638817bd>
Sun, 26 Nov 2006 05:25:03 +0000 (05:25 +0000)
committerfredrik <fredrik@959494ce-11ee-0310-bf91-de5d638817bd>
Sun, 26 Nov 2006 05:25:03 +0000 (05:25 +0000)
git-svn-id: svn+ssh://svn.dolda2000.com/srv/svn/repos/src/utils@773 959494ce-11ee-0310-bf91-de5d638817bd

userinit2.c [new file with mode: 0644]

diff --git a/userinit2.c b/userinit2.c
new file mode 100644 (file)
index 0000000..c27d548
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ *  userinit2 - Launch programs as user during boot (Kerberized v2)
+ *  Copyright (C) 2006 Fredrik Tolf (fredrik@dolda2000.com)
+ *  
+ *  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 2 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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <krb5.h>
+#include <pwd.h>
+#include <grp.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+krb5_context ctx;
+static int credsfwd;
+static int credsrnw;
+
+static int parsetime(char *ts)
+{
+    char *p;
+    int unit;
+    
+    p = ts + strlen(ts) - 1;
+    unit = 1;
+    if(*p == 'm')
+       unit = 60;
+    else if(*p == 'h')
+       unit = 3600;
+    else if(*p == 'd')
+       unit = 86400;
+    return(atoi(ts) * unit);
+}
+
+static void getcreds(struct passwd *pw, krb5_keytab kt, krb5_principal prn)
+{
+    int ret, fd;
+    krb5_get_init_creds_opt o;
+    krb5_creds c;
+    krb5_ccache cc;
+    char buf[1024], *ccnm, *fnm;
+    
+    krb5_get_init_creds_opt_init(&o);
+    krb5_get_init_creds_opt_set_forwardable(&o, credsfwd);
+    krb5_get_init_creds_opt_set_renew_life(&o, credsrnw);
+    if((ret = krb5_get_init_creds_keytab(ctx, &c, prn, kt, 0, NULL, &o)) != 0) {
+       fprintf(stderr, "userinit2: could not get krb credentials: %s\n", error_message(ret));
+       exit(1);
+    }
+    ccnm = buf + sprintf(buf, "KRB5CCNAME=");
+    fnm = ccnm + sprintf(ccnm, "FILE:");
+    sprintf(fnm, "/tmp/krb5cc_ui_%i_XXXXXX", pw->pw_uid);
+    if((fd = mkstemp(fnm)) < 0) {
+       fprintf(stderr, "userinit2: could not ccache file: %s", strerror(errno));
+       exit(1);
+    }
+    close(fd);
+    if((ret = krb5_cc_resolve(ctx, ccnm, &cc)) != 0) {
+       fprintf(stderr, "userinit2: could not resolve ccache %s: %s", ccnm, error_message(ret));
+       unlink(fnm);
+       exit(1);
+    }
+    if((ret = krb5_cc_initialize(ctx, cc, prn)) != 0) {
+       fprintf(stderr, "userinit2: could not initialize ccache: %s", error_message(ret));
+       unlink(fnm);
+       exit(1);
+    }
+    if((ret = krb5_cc_store_cred(ctx, cc, &c)) != 0) {
+       fprintf(stderr, "userinit2: could not store TGT: %s", error_message(ret));
+       unlink(fnm);
+       exit(1);
+    }
+    putenv(strdup(buf));
+    krb5_cc_close(ctx, cc);
+    krb5_free_cred_contents(ctx, &c);
+    if(chown(fnm, pw->pw_uid, pw->pw_gid)) {
+       fprintf(stderr, "userinit2: could not chown ccache file: %s", strerror(errno));
+       unlink(fnm);
+       exit(1);
+    }
+}
+
+static void dologin(struct passwd *pw)
+{
+    char ebuf[1024];
+    
+    if(chdir(pw->pw_dir)) {
+       fprintf(stderr, "userinit2: could not chdir to home directory %s: %s\n", pw->pw_dir, strerror(errno));
+       exit(1);
+    }
+    if(snprintf(ebuf, sizeof(ebuf), "HOME=%s", pw->pw_dir) < sizeof(ebuf))
+       putenv(strdup(ebuf));
+    if(snprintf(ebuf, sizeof(ebuf), "SHELL=%s", pw->pw_shell) < sizeof(ebuf))
+       putenv(strdup(ebuf));
+    if(snprintf(ebuf, sizeof(ebuf), "USER=%s", pw->pw_name) < sizeof(ebuf))
+       putenv(strdup(ebuf));
+    if(snprintf(ebuf, sizeof(ebuf), "LOGNAME=%s", pw->pw_name) < sizeof(ebuf))
+       putenv(strdup(ebuf));
+    if(snprintf(ebuf, sizeof(ebuf), "PATH=%s/bin:/usr/local/bin:/bin:/usr/bin", pw->pw_dir) < sizeof(ebuf))
+       putenv(strdup(ebuf));
+}
+
+static void dodir(void)
+{
+    DIR *dir;
+    struct dirent *de;
+    struct stat sb;
+
+    if((dir = opendir(".")) == NULL) {
+       fprintf(stderr, "userinit2: couldn't open cwd (%s)!\n", strerror(errno));
+       exit(1);
+    }
+    while((de = readdir(dir)) != NULL) {
+       if(de->d_name[0] == '.')
+           continue;
+       if(access(de->d_name, X_OK))
+           continue;
+       if(stat(de->d_name, &sb))
+           continue;
+       if(!S_ISREG(sb.st_mode))
+           continue;
+       if(!fork()) {
+           setpgrp();
+           execl(de->d_name, de->d_name, NULL);
+           exit(127);
+       }
+    }
+    closedir(dir);
+}
+
+static void runstuff(struct passwd *pw)
+{
+    int i, fd1, fd2;
+    char buf[1024];
+    
+    if(chdir(".userinit")) 
+       return;
+    for(i = 3; i < FD_SETSIZE; i++)
+       close(i);
+    if((fd1 = open("/dev/null", O_RDWR)) < 0) {
+       fprintf(stderr, "userinit2: /dev/null: %s\n", strerror(errno));
+       exit(1);
+    }
+    if((fd2 = open("stderr", O_WRONLY | O_CREAT | O_APPEND, 0666)) < 0) {
+       fprintf(stderr, "userinit2: stderr: %s\n", strerror(errno));
+       exit(1);
+    }
+    dup2(fd1, 0);
+    dup2(fd1, 1);
+    dup2(fd2, 2);
+    close(fd1);
+    close(fd2);
+    setsid();
+    dodir();
+    if(gethostname(buf, sizeof(buf)))
+       return;
+    if(chdir(buf))
+       return;
+    dodir();
+}
+
+int main(int argc, char **argv)
+{
+    int ret, c;
+    krb5_keytab kt;
+    krb5_kt_cursor ktc;
+    krb5_keytab_entry kte;
+    struct passwd *pw;
+    
+    while((c = getopt(argc, argv, "hfr:")) >= 0) {
+       switch(c) {
+       case 'f':
+           credsfwd = 1;
+           break;
+       case 'r':
+           credsrnw = parsetime(optarg);
+           break;
+       default:
+           fprintf(stderr, "usage: userinit2 [-hf] [-r renewlife]\n");
+           exit((c == 'h')?0:1);
+       }
+    }
+    if((ret = krb5_init_context(&ctx)) != 0) {
+       fprintf(stderr, "userinit2: could not get krb context: %s\n", error_message(ret));
+       exit(1);
+    }
+    if((ret = krb5_kt_default(ctx, &kt)) != 0) {
+       fprintf(stderr, "userinit2: could not get keytab: %s\n", error_message(ret));
+       exit(1);
+    }
+    if((ret = krb5_kt_start_seq_get(ctx, kt, &ktc)) != 0) {
+       fprintf(stderr, "userinit2: could not iterate keytab: %s\n", error_message(ret));
+       exit(1);
+    }
+    while(krb5_kt_next_entry(ctx, kt, &kte, &ktc) == 0) {
+       do {
+           if((kte.principal->length >= 2) && !strcmp(kte.principal->data[1].data, "userinit")) {
+               if((pw = getpwnam(kte.principal->data[0].data)) == NULL)
+                   break;
+               if(!(ret = fork())) {
+                   getcreds(pw, kt, kte.principal);
+                   if(getuid() == 0) {
+                       if(initgroups(pw->pw_name, pw->pw_gid)) {
+                           fprintf(stderr, "userinit2: initgroups: %s\n", strerror(errno));
+                           exit(1);
+                       }
+                       if(setgid(pw->pw_gid)) {
+                           fprintf(stderr, "userinit2: setgid: %s\n", strerror(errno));
+                           exit(1);
+                       }
+                       if(setuid(pw->pw_uid)) {
+                           fprintf(stderr, "userinit2: setuid: %s\n", strerror(errno));
+                           exit(1);
+                       }
+                   } else {
+                       if(pw->pw_uid != getuid())
+                           break;
+                   }
+                   dologin(pw);
+                   runstuff(pw);
+                   exit(0);
+               }
+               if(ret < 0) {
+                   fprintf(stderr, "userinit2: fork: %s\n", strerror(errno));
+                   exit(1);
+               }
+           }
+       } while(0);
+       krb5_free_keytab_entry_contents(ctx, &kte);
+    }
+    krb5_kt_end_seq_get(ctx, kt, &ktc);
+    krb5_kt_close(ctx, kt);
+    return(0);
+}
+
+/* 
+ * Local Variables:
+ * compile-command: "gcc -Wall -g -o userinit2 userinit2.c -lkrb5"
+ * End:
+ */