/* ptloader.c -- AFS group loader daemon */ /* * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The name "Carnegie Mellon University" must not be used to * endorse or promote products derived from this software without * prior written permission. For permission or any other legal * details, please contact * Office of Technology Transfer * Carnegie Mellon University * 5000 Forbes Avenue * Pittsburgh, PA 15213-3890 * (412) 268-4387, fax: (412) 268-7395 * tech-transfer@andrew.cmu.edu * * 4. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Computing Services * at Carnegie Mellon University (http://www.cmu.edu/computing/)." * * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ static char rcsid[] __attribute__((unused)) = "$Id: ptloader.c,v 1.30 2003/02/13 20:15:56 rjs3 Exp $"; #include #include #include "auth_krb_pts.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "xmalloc.h" #include "lock.h" #include "retry.h" #include "hash.h" /* blame transarc i've been told */ #ifndef AFSCONF_CLIENTNAME #include #define AFSCONF_CLIENTNAME AFSDIR_CLIENT_ETC_DIRPATH #endif static char ptclient_debug = 0; static void newclient(); static int reauth(); int key_to_key(user,instance,realm,passwd,key) char *user, *instance, *realm, *passwd; C_Block key; { memcpy(key, passwd, sizeof(des_cblock)); return (0); } #define AUTH_USER "postman" #define AUTH_INTERVAL (60*60*10) /* every 10 hours*/ int main(argc, argv) int argc; char *argv[]; { int s, c, r, len; int opt; struct sockaddr_un srvaddr; struct sockaddr_un clientaddr; char fnamebuf[1024]; mode_t oldumask; int listen_queue = 5; extern char *optarg; char *user; char *pw_file = NULL; time_t next_auth_time = 0; unsigned int auth_interval; int do_reauth = 1, use_srvtab = 0; int use_newpag = 0; auth_interval = AUTH_INTERVAL; user = AUTH_USER; /* normally LOCAL6, but do this while we're logging keys */ openlog("ptloader", LOG_PID, LOG_LOCAL7); syslog(LOG_NOTICE, "starting: $Id: ptloader.c,v 1.30 2003/02/13 20:15:56 rjs3 Exp $"); while ((opt = getopt(argc, argv, "Uspd:l:f:u:t:")) != EOF) { switch (opt) { case 'U': do_reauth = 0; break; case 's': use_srvtab = 1; break; case 'p': use_newpag = 1; break; case 'd': ptclient_debug = atoi(optarg); if (ptclient_debug < 1) { ptclient_debug = 1; } break; case 'l': listen_queue = atoi(optarg); break; case 'f': pw_file = optarg; break; case 'u': user = optarg; break; case 't': auth_interval = atoi(optarg); break; case '?': fprintf(stderr,"usage: -Udlfut" "\n\t-d \tdebug level" "\n\t-l \tlisten(2) queue backlog" "\n\t-U\tDo not reauthenticate" "\n\t-s\tAssume file is srvtab" "\n\t-u \tuser to authenticate as" "\n\t-f \tfile for the users password" "\n\t-t \tinterval between authentications" "\n\t-p\tset a new pag" "\n"); syslog(LOG_ERR, "Invalid command line option specified"); exit(-1); break; default: break; /* just pass through */ } } if (listen_queue < 5) { if (ptclient_debug) { syslog(LOG_ERR, "Invalid listen_queue specified (%d), resetting to 5", listen_queue); listen_queue = 5; } } s = socket(AF_UNIX, SOCK_STREAM, 0); if (s == -1) { syslog(LOG_ERR, "socket: %m"); exit(1); } strcpy(fnamebuf, STATEDIR); strcat(fnamebuf, PTS_DBSOCKET); (void) unlink(fnamebuf); memset((char *)&srvaddr, 0, sizeof(srvaddr)); srvaddr.sun_family = AF_UNIX; strcpy(srvaddr.sun_path, fnamebuf); /* Most Unixen make sockets 777 by default Not Linux, not DUX. */ oldumask = umask((mode_t) 0); /* for Linux */ r = bind(s, (struct sockaddr *)&srvaddr, sizeof(srvaddr)); umask(oldumask); /* for Linux */ chmod(fnamebuf, 0777); /* for DUX */ if (r == -1) { syslog(LOG_ERR, "bind: %s: %m", fnamebuf); exit(1); } r = listen(s, listen_queue); if (r == -1) { syslog(LOG_ERR, "listen: %m"); exit(1); } if (do_reauth) { if (pw_file == NULL) { syslog(LOG_ERR, "Invalid password file specified. Exiting..."); exit(-1); } if (reauth(user, pw_file, use_newpag, use_srvtab) < 0) { syslog(LOG_ERR, "initialization failed. exiting..."); exit(-1); } next_auth_time = time(0) + auth_interval; if (ptclient_debug > 10) { syslog(LOG_DEBUG, "Authenticated as %s; next reauth at %d", user, next_auth_time); } } else { r = pr_Initialize (1L, AFSCONF_CLIENTNAME, 0); if (r) { syslog(LOG_DEBUG, "pr_Initialize failed: %d", r); } } len = sizeof(clientaddr); for (;;) { c = accept(s, (struct sockaddr *)&clientaddr, &len); if (c == -1) { syslog(LOG_WARNING, "WARNING: accept: %m"); continue; } if (do_reauth && (time(0) > next_auth_time)) { if (ptclient_debug > 10) { syslog(LOG_DEBUG, "Reauthenticating at %d", time(0)); } if (reauth(user, pw_file, use_newpag, use_srvtab) < 0) { syslog(LOG_ERR, "error reauthenticating. continuing..."); } else { next_auth_time = time(0) + auth_interval; if (ptclient_debug) { syslog(LOG_DEBUG, "Successfully re-authenticated."); } } } newclient(c); } /* NOTREACHED */ } static void newclient(c) int c; { char fnamebuf[1024]; char keyinhex[512]; const char *reply; DB *ptdb; DBT key, data; char indata[PTS_DB_KEYSIZE]; char user[PR_MAXNAMELEN]; char user_tmp[PR_MAXNAMELEN]; namelist groups; int i,fd,rc; size_t size; struct auth_state *newstate; memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); (void)memset(&size, 0, sizeof(size)); if (read(c, &size, sizeof(size_t)) < 0) { syslog(LOG_ERR, "socket (size): %m"); reply = "Error reading request (size)"; goto sendreply; } if (size > PTS_DB_KEYSIZE) { syslog(LOG_ERR, "size sent %d is greater than buffer size %d", size, PTS_DB_KEYSIZE); reply = "Error: invalid request size"; goto sendreply; } memset(&indata, 0, PTS_DB_KEYSIZE); if (read(c, &indata, size) < 0) { syslog(LOG_ERR,"socket (indata; size = %d): %m", size); reply = "Error reading request (key)"; goto sendreply; } /* convert request to hex */ for (i=0; iuserid.id, user); newstate->userid.hash = hash(user); kname_parse(newstate->aname, newstate->inst, newstate->realm, user); newstate->mark = time(0); newstate->ngroups = groups.namelist_len; /* store group list in contiguous array for easy storage in the database */ memset(newstate->groups, 0, newstate->ngroups * sizeof(struct auth_ident)); for (i = 0; i < newstate->ngroups; i++) { strcpy(newstate->groups[i].id, groups.namelist_val[i]); newstate->groups[i].hash = hash(groups.namelist_val[i]); /* don't free groups.namelist_val[i]. Something else currently * takes care of that data. */ } if (groups.namelist_val != NULL) { free(groups.namelist_val); } /* lock database */ strcpy(fnamebuf, STATEDIR); strcat(fnamebuf, PTS_DBLOCK); fd=open(fnamebuf, O_CREAT|O_TRUNC|O_RDWR, 0664); if (fd == -1) { syslog(LOG_ERR, "IOERROR: creating lock file %s: %m", fnamebuf); reply="Couldn't create lock file"; free(newstate); goto sendreply; } if (lock_blocking(fd) < 0) { syslog(LOG_ERR, "IOERROR: locking lock file %s: %m", fnamebuf); reply ="Couldn't lock database"; free(newstate); goto sendreply; } /* store to database */ strcpy(fnamebuf, STATEDIR); strcat(fnamebuf, PTS_DBFIL); rc = db_create(&ptdb, NULL, 0); if (!rc) { #if DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1 rc = ptdb->open(ptdb, NULL, fnamebuf, NULL, DB_HASH, DB_AUTO_COMMIT, 0664); #else rc = ptdb->open(ptdb, fnamebuf, NULL, DB_HASH, 0, 0664); #endif } if (rc == ENOENT) { rc = db_create(&ptdb, NULL, 0); if (!rc) { #if DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1 rc = ptdb->open(ptdb, NULL, fnamebuf, NULL, DB_HASH, DB_CREATE | DB_AUTO_COMMIT, 0664); #else rc = ptdb->open(ptdb, fnamebuf, NULL, DB_HASH, DB_CREATE, 0664); #endif } } if (rc != 0) { syslog(LOG_ERR, "IOERROR: opening database %s: %s", fnamebuf, db_strerror(rc)); close(fd); reply="Couldn't open database"; free(newstate); goto sendreply; } rc = ptdb->put(ptdb, NULL, &key, &data, 0); free(newstate); ptdb->close(ptdb, 0); close(fd); if (rc != 0) { syslog(LOG_ERR, "IOERROR: writing header into database %s: %s", fnamebuf, db_strerror(rc)); reply = "Couldn't write database"; goto sendreply; } /* and we're done */ reply = "OK"; sendreply: if (retry_write(c, reply, strlen(reply)) <0) { syslog(LOG_WARNING, "retry_write: %m"); } close(c); } static int reauth(name, file, newpag, is_srvtab) char *name; char *file; int newpag; int is_srvtab; { int rc; char *reason; char password[256]; char *c; FILE *fp; static char pr_init = 0; if (pr_init) { #ifdef HAVE_PR_END /* this doesn't really do anything other than attempt to * clean up the ubik connection. Calling pr_Initialize * later in the code will most likely leak memory until * the AFS libraries get cleaned up. */ pr_End(); #else /* this destroys existing ubik connections... */ pr_Initialize(1L,"/", 0); if (!pr_Initialize (1L, AFSCONF_CLIENTNAME, 0)) #endif } if (is_srvtab) { /* Not done yet */ char lrealm[REALM_SZ]; int bkvno = 0, kerrno; C_Block use_as_key; CREDENTIALS c; struct ktc_principal aserver; struct ktc_principal aclient; struct ktc_token atoken; if (newpag) setpag(); if ((kerrno = krb_get_lrealm(lrealm, 1)) != 0) { syslog(LOG_ERR, "krb_get_lrealm: %d", kerrno); return(-1); } (void)memset(password, 0, sizeof(password)); kerrno = read_service_key(name, "", lrealm, bkvno, file, (char *)password); if (kerrno != 0) { syslog(LOG_ERR, "read_service_key: %d", kerrno); return(-1); } (void)memcpy(use_as_key, password, 8); kerrno = krb_get_in_tkt(name, "", lrealm, "krbtgt", lrealm, DEFAULT_TKT_LIFE, key_to_key, NULL, use_as_key); (void)memset(use_as_key, 0, sizeof(use_as_key)); if (kerrno != 0) { syslog(LOG_ERR, "get_in_tkt: %d", kerrno); return(-1); } if ((kerrno = krb_get_cred("afs", "", lrealm, &c)) != 0) { if ((kerrno = get_ad_tkt("afs", "", lrealm, 255)) != 0) { syslog(LOG_ERR,"get_ad_tkt: %d", kerrno); return(-1); } else { if ((kerrno = krb_get_cred("afs", "", lrealm, &c)) != 0) { syslog(LOG_ERR,"get_cred: %d", kerrno); return(-1); } } } strncpy(aserver.name, "afs", MAXKTCNAMELEN - 1); strncpy(aserver.instance, "", MAXKTCNAMELEN - 1); strncpy(aserver.cell, lrealm, MAXKTCREALMLEN - 1); { char *t = aserver.cell; char *s = aserver.cell; int c; while ((c = *t++)) { if (isupper((unsigned char) c)) c = tolower(c); *s++ = c; } *s++ = 0; } atoken.kvno = c.kvno; atoken.startTime = c.issue_date; #ifdef HAVE_KRB_LIFE_TO_TIME atoken.endTime = krb_life_to_time(c.issue_date, c.lifetime); #else atoken.endTime = c.issue_date + ((unsigned char)c.lifetime * 5 * 60); #endif memcpy(&atoken.sessionKey, c.session, 8); atoken.ticketLen = c.ticket_st.length; memcpy(atoken.ticket, c.ticket_st.dat, atoken.ticketLen); if ((kerrno = ktc_SetToken(&aserver, &atoken, &aclient)) != 0) { syslog(LOG_ERR, "ktc_SetToken: %d", kerrno); return(-1); } } else { /* not using srvtab but using a regular file */ if ((fp = fopen(file, "r")) == NULL) { syslog(LOG_ERR, "fopen: password file: %m"); return(-1); } if (fgets(password, sizeof(password), fp) == NULL) { syslog(LOG_ERR, "fgets: unable to read password: %m"); return(-1); } if (feof(fp) != 0) { syslog(LOG_ERR, "internal error: password longer than max length(%d)\n", sizeof(password)); return(-1); } fclose(fp); /* if the file has an ending \n, nuke it. */ if ((c = strrchr(password, '\n')) != NULL) { *c='\0'; } /* so we probably should allow instances but it isn't worth * the overhead right now */ if (ka_UserAuthenticate(name, /*inst*/ "", /*realm*/0, password, newpag, &reason)) { syslog(LOG_ERR, "Unable to authenticate to AFS: %s", reason); return (-1); } (void)memset(&password, 0, sizeof(password)); } if ((rc = pr_Initialize(1L, AFSCONF_CLIENTNAME, 0))) { syslog(LOG_ERR, "pr_Initialize: %s", error_message(rc)); return (-1); } pr_init = 1; return 0; } /* we need to have this function here 'cause libcyrus.a * makes calls to this function. */ void fatal(const char *msg, int exitcode) { syslog(LOG_ERR, "%s", msg); exit(-1); } /* $Header: /cvs/src/cyrus/ptclient/ptloader.c,v 1.30 2003/02/13 20:15:56 rjs3 Exp $ */