2 * userinit2 - Launch programs as user during boot (Kerberized v2)
3 * Copyright (C) 2006 Fredrik Tolf (fredrik@dolda2000.com)
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
36 static int parsetime(char *ts)
41 p = ts + strlen(ts) - 1;
49 return(atoi(ts) * unit);
52 static void getcreds(struct passwd *pw, krb5_keytab kt, krb5_principal prn)
55 krb5_get_init_creds_opt o;
58 char buf[1024], *ccnm, *fnm;
60 krb5_get_init_creds_opt_init(&o);
61 krb5_get_init_creds_opt_set_forwardable(&o, credsfwd);
62 krb5_get_init_creds_opt_set_renew_life(&o, credsrnw);
63 if((ret = krb5_get_init_creds_keytab(ctx, &c, prn, kt, 0, NULL, &o)) != 0) {
64 fprintf(stderr, "userinit2: could not get krb credentials: %s\n", error_message(ret));
67 ccnm = buf + sprintf(buf, "KRB5CCNAME=");
68 fnm = ccnm + sprintf(ccnm, "FILE:");
69 sprintf(fnm, "/tmp/krb5cc_ui_%i_XXXXXX", pw->pw_uid);
70 if((fd = mkstemp(fnm)) < 0) {
71 fprintf(stderr, "userinit2: could not ccache file: %s", strerror(errno));
75 if((ret = krb5_cc_resolve(ctx, ccnm, &cc)) != 0) {
76 fprintf(stderr, "userinit2: could not resolve ccache %s: %s", ccnm, error_message(ret));
80 if((ret = krb5_cc_initialize(ctx, cc, prn)) != 0) {
81 fprintf(stderr, "userinit2: could not initialize ccache: %s", error_message(ret));
85 if((ret = krb5_cc_store_cred(ctx, cc, &c)) != 0) {
86 fprintf(stderr, "userinit2: could not store TGT: %s", error_message(ret));
91 krb5_cc_close(ctx, cc);
92 krb5_free_cred_contents(ctx, &c);
93 if(chown(fnm, pw->pw_uid, pw->pw_gid)) {
94 fprintf(stderr, "userinit2: could not chown ccache file: %s", strerror(errno));
100 static void dologin(struct passwd *pw)
104 if(chdir(pw->pw_dir)) {
105 fprintf(stderr, "userinit2: could not chdir to home directory %s: %s\n", pw->pw_dir, strerror(errno));
108 if(snprintf(ebuf, sizeof(ebuf), "HOME=%s", pw->pw_dir) < sizeof(ebuf))
109 putenv(strdup(ebuf));
110 if(snprintf(ebuf, sizeof(ebuf), "SHELL=%s", pw->pw_shell) < sizeof(ebuf))
111 putenv(strdup(ebuf));
112 if(snprintf(ebuf, sizeof(ebuf), "USER=%s", pw->pw_name) < sizeof(ebuf))
113 putenv(strdup(ebuf));
114 if(snprintf(ebuf, sizeof(ebuf), "LOGNAME=%s", pw->pw_name) < sizeof(ebuf))
115 putenv(strdup(ebuf));
116 if(snprintf(ebuf, sizeof(ebuf), "PATH=%s/bin:/usr/local/bin:/bin:/usr/bin", pw->pw_dir) < sizeof(ebuf))
117 putenv(strdup(ebuf));
120 static void dodir(void)
126 if((dir = opendir(".")) == NULL) {
127 fprintf(stderr, "userinit2: couldn't open cwd (%s)!\n", strerror(errno));
130 while((de = readdir(dir)) != NULL) {
131 if(de->d_name[0] == '.')
133 if(access(de->d_name, X_OK))
135 if(stat(de->d_name, &sb))
137 if(!S_ISREG(sb.st_mode))
141 execl(de->d_name, de->d_name, NULL);
148 static void runstuff(struct passwd *pw)
153 if(chdir(".userinit"))
155 for(i = 3; i < FD_SETSIZE; i++)
157 if((fd1 = open("/dev/null", O_RDWR)) < 0) {
158 fprintf(stderr, "userinit2: /dev/null: %s\n", strerror(errno));
161 if((fd2 = open("stderr", O_WRONLY | O_CREAT | O_APPEND, 0666)) < 0) {
162 fprintf(stderr, "userinit2: stderr: %s\n", strerror(errno));
172 if(gethostname(buf, sizeof(buf)))
179 int main(int argc, char **argv)
184 krb5_keytab_entry kte;
187 while((c = getopt(argc, argv, "hfr:")) >= 0) {
193 credsrnw = parsetime(optarg);
196 fprintf(stderr, "usage: userinit2 [-hf] [-r renewlife]\n");
197 exit((c == 'h')?0:1);
200 if((ret = krb5_init_context(&ctx)) != 0) {
201 fprintf(stderr, "userinit2: could not get krb context: %s\n", error_message(ret));
204 if((ret = krb5_kt_default(ctx, &kt)) != 0) {
205 fprintf(stderr, "userinit2: could not get keytab: %s\n", error_message(ret));
208 if((ret = krb5_kt_start_seq_get(ctx, kt, &ktc)) != 0) {
209 fprintf(stderr, "userinit2: could not iterate keytab: %s\n", error_message(ret));
212 while(krb5_kt_next_entry(ctx, kt, &kte, &ktc) == 0) {
214 if((kte.principal->length >= 2) && !strcmp(kte.principal->data[1].data, "userinit")) {
215 if((pw = getpwnam(kte.principal->data[0].data)) == NULL)
217 if(!(ret = fork())) {
218 getcreds(pw, kt, kte.principal);
220 if(initgroups(pw->pw_name, pw->pw_gid)) {
221 fprintf(stderr, "userinit2: initgroups: %s\n", strerror(errno));
224 if(setgid(pw->pw_gid)) {
225 fprintf(stderr, "userinit2: setgid: %s\n", strerror(errno));
228 if(setuid(pw->pw_uid)) {
229 fprintf(stderr, "userinit2: setuid: %s\n", strerror(errno));
233 if(pw->pw_uid != getuid())
241 fprintf(stderr, "userinit2: fork: %s\n", strerror(errno));
246 krb5_free_keytab_entry_contents(ctx, &kte);
248 krb5_kt_end_seq_get(ctx, kt, &ktc);
249 krb5_kt_close(ctx, kt);
255 * compile-command: "gcc -Wall -g -o userinit2 userinit2.c -lkrb5"