/* Copyright 2000, 2001, 2002 Laurent Wacrenier This file is part of libhome libhome is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. libhome 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with libhome; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" static char const rcsid[] UNUSED = "$Id: wrap.c,v 1.31 2005/06/27 16:16:05 lwa Exp $"; #define passwd system_passwd #include #include #include #if HAVE_CRYPT_H #include #endif #include #include #include #include #undef passwd #include "hparam.h" int home_stayopen = 0; extern struct param home_param; extern int hparam_done; static int is_pure(char *login) { char **pures = home_param.pures; if (pures) { while (*pures) { if (strcmp(*pures, login) == 0) { return 1; } pures++; } } return 0; } static struct passwd *pure_getpwnam2(char *login, int quiet) { extern struct home_driver hsystem_driver; struct passwd *p=NULL; struct home_driver *d = &hsystem_driver; void *res; if ((res = d->query(login)) == NULL || (p = d->store(res, NULL))==NULL) if (!quiet) home_retry("unable to found pure user %s", login); if (!home_stayopen) d->clean(); return p; } void home_blocsignal(int mode) { static sigset_t saved_sigmask; static sigset_t block_sigmask; static int block_sigmask_ok=0; static int suspended; if (mode) { if (!block_sigmask_ok) { sigfillset(&block_sigmask); sigdelset(&block_sigmask, SIGTRAP); /* let's debug */ block_sigmask_ok=1; } if (!suspended) { if (sigprocmask(SIG_BLOCK, &block_sigmask, &saved_sigmask)==-1) { home_retry("sigprocmask: %s", strerror(errno)); return; } suspended=1; } } else { if (suspended) { if (sigprocmask(SIG_SETMASK, &saved_sigmask, NULL)==-1) { home_retry("sigprocmask: %s", strerror(errno)); return; } suspended=0; } } } struct passwd *home_getpwent(void) { return NULL; } static struct passwd *home_getpinfo(char *rentry) { struct passwd *p=NULL; struct home_driver *d; void *res; #if WITH_DB int from_cache = 0; #endif if (rentry==NULL) return NULL; #if WITH_DB if ((p=retrfromcache(rentry, home_param.cachettl))!=NULL) { free(rentry); return home_getpwnam_return(p); } #endif d = home_param.driver; if (d==NULL || d->query==NULL || d->store==NULL) { free(rentry); home_cleanup(); home_retry("libhome: invalid driver"); return home_getpwnam_return(NULL); } home_blocsignal(1); /* lock signals */ if ((res=home_query(d->query, rentry))!=NULL) { char *alias=NULL; if ((p=d->store(res, &alias))==NULL && !home_has_transcient_condition()) { char *fentry=NULL; if (alias) { /* account is an alias */ res=home_query(d->query, alias); free(alias); alias=NULL; p=d->store(res, &alias); if (alias) { free(alias); alias=NULL; home_retry("alias of '%s' points to an alias (%s)", rentry, alias); p=NULL; } } /* fallback user */ if (p == NULL && home_param.fallback != NULL && !home_has_transcient_condition() && (fentry=hexpand_user(rentry, home_param.fallback)) != NULL && (res=home_query(d->query, fentry)) != NULL && (p=d->store(res, NULL)) != NULL) { ; } if (fentry) free(fentry); } if (!home_stayopen && d->clean) d->clean(); } else { #if WITH_DB if (home_has_transcient_condition() && home_param.cacherevivettl >= 0 && home_param.cacherevivettl > home_param.cachettl) { p = retrfromcache(rentry, home_param.cacherevivettl); if (p) { from_cache = 1; home_clear_transcient_condition(); } } #endif if (d->clean) d->clean(); } /* home directory cannot be NULL */ if (p && ( p->pw_dir == NULL || p->pw_dir[0] != '/' )) { p = NULL; } if (p) { char *pass= p->pw_passwd; if (pass == NULL) pass = strdup(""); pass = hrewrite(home_param.passwd_rew, pass, HREW_NONULL|HREW_FREE); if (pass==NULL || *pass==0) p=NULL; else p->pw_passwd=pass; } #if WITH_DB if (p && !from_cache) storecache(rentry, p); #endif home_blocsignal(0); /* unlock signals */ free(rentry); return home_getpwnam_return(p); } struct passwd *home_getpwuid(uid_t uid) { char uidc[100]; struct passwd *ret = NULL; char **method; if (hparam_done==0 && home_init(NULL)==NULL) { return home_getpwnam_return(NULL); } method = home_param.pwuid; if (method) { sprintf(uidc, "\xff%lu", home_uncalc(uid, home_param.uid_calc)); while(*method && !ret && !home_has_transcient_condition()) { if (**method == 'l') { /* lib */ ret = home_getpinfo(strdup(uidc)); } else if (**method == 's') { /* system */ ret = pure_getpwnam2(uidc, 1); } method ++; } } return ret; } struct passwd *home_getpwnam(char *login) { char *rentry; if (IS_UID(login)) /* hack: login begining by 0xFF does not work */ return NULL; if (hparam_done==0 && home_init(NULL)==NULL) { return home_getpwnam_return(NULL); } if (is_pure(login)) { return pure_getpwnam2(login, 0); } rentry=hexpand_user(login, home_param.rewrite); if (rentry == NULL) return home_getpwnam_return(NULL); return home_getpinfo(rentry); } int home_setpassent(int stayopen) { home_stayopen = stayopen; if (!stayopen && home_param.driver && home_param.driver->clean) home_param.driver->clean(); return 1; } void home_setpwent(void) { home_setpassent(0); } void home_endpwent(void) { home_cleanup(); } char *home_canon(char *user) { if (home_init(NULL)==NULL) return NULL; return hexpand_user(user, home_param.rewrite); } int home_crypted(char *passwd) { if (strncasecmp(passwd, "{crypt}", sizeof("{crypt}")-1)==0) return HOME_CRYPTED_CRYPT; return HOME_CRYPTED_PLAIN; } char *home_crypt(char *key, char *salt) { if (home_param.crypt_always_crypted) { return crypt(key, salt); } switch(home_crypted(salt)) { case HOME_CRYPTED_CRYPT: { static char scp[sizeof("{crypt}") + 13 + HOME_CRYPT_CRYPT_EXTRA_CHARS]; char *cp; cp=crypt(key, salt+sizeof("{crypt}")-1); strncpy(scp, salt, sizeof("{crypt}")); scp[sizeof("{crypt}")-1]=0; strncpy(scp+sizeof("{crypt}")-1, cp, sizeof(scp)-sizeof("{crypt}")); scp[sizeof(scp)-1]=0; return scp; } case HOME_CRYPTED_PLAIN: if (salt==NULL) { return NULL; } return key; } return NULL; }