X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=etc%2Fafpd%2Fuam.c;h=d99d381edd38cc4408a5076039ef47f53d4e7899;hb=84c3a8f52deced7429f9d72276232ee282b3b823;hp=682fa885f8d5351369b93b44ccefa6b2328a5127;hpb=cd1a15e63bb244ccd4b3efa3159c933de4ef6467;p=netatalk.git diff --git a/etc/afpd/uam.c b/etc/afpd/uam.c index 682fa885..d99d381e 100644 --- a/etc/afpd/uam.c +++ b/etc/afpd/uam.c @@ -1,5 +1,5 @@ /* - * $Id: uam.c,v 1.17 2001-12-10 20:16:54 srittau Exp $ + * $Id: uam.c,v 1.35 2009-11-08 01:15:31 didg Exp $ * * Copyright (c) 1999 Adrian Sun (asun@zoology.washington.edu) * All Rights Reserved. See COPYRIGHT. @@ -11,30 +11,11 @@ #include #include - -/* STDC check */ -#if STDC_HEADERS #include -#else /* STDC_HEADERS */ -#ifndef HAVE_STRCHR -#define strchr index -#define strrchr index -#endif /* HAVE_STRCHR */ -char *strchr (), *strrchr (); -#ifndef HAVE_MEMCPY -#define memcpy(d,s,n) bcopy ((s), (d), (n)) -#define memmove(d,s,n) bcopy ((s), (d), (n)) -#endif /* ! HAVE_MEMCPY */ -#endif /* STDC_HEADERS */ - -#ifdef HAVE_UNISTD_H #include -#endif /* HAVE_UNISTD_H */ -#ifdef HAVE_FCNTL_H #include -#endif /* HAVE_FCNTL_H */ #include -#include +#include #include #include #include @@ -45,19 +26,21 @@ char *strchr (), *strrchr (); #include #include -#include -#include #include #include #include +#include +#include -#include "globals.h" #include "afp_config.h" #include "auth.h" #include "uam_auth.h" #ifdef TRU64 #include +#include +#include +#include #endif /* TRU64 */ /* --- server uam functions -- */ @@ -70,29 +53,29 @@ struct uam_mod *uam_load(const char *path, const char *name) void *module; if ((module = mod_open(path)) == NULL) { - syslog(LOG_ERR, "uam_load(%s): failed to load: %s", name, mod_error()); + LOG(log_error, logtype_afpd, "uam_load(%s): failed to load: %s", name, mod_error()); return NULL; } if ((mod = (struct uam_mod *) malloc(sizeof(struct uam_mod))) == NULL) { - syslog(LOG_ERR, "uam_load(%s): malloc failed", name); + LOG(log_error, logtype_afpd, "uam_load(%s): malloc failed", name); goto uam_load_fail; } - strncpy(buf, name, sizeof(buf)); - buf[sizeof(buf) - 1] = '\0'; + strlcpy(buf, name, sizeof(buf)); if ((p = strchr(buf, '.'))) *p = '\0'; + if ((mod->uam_fcn = mod_symbol(module, buf)) == NULL) { - syslog(LOG_ERR, "uam_load(%s): mod_symbol error for symbol %s", - name, - buf); + LOG(log_error, logtype_afpd, "uam_load(%s): mod_symbol error for symbol %s", + name, + buf); goto uam_load_err; } if (mod->uam_fcn->uam_type != UAM_MODULE_SERVER) { - syslog(LOG_ERR, "uam_load(%s): attempted to load a non-server module", - name); + LOG(log_error, logtype_afpd, "uam_load(%s): attempted to load a non-server module", + name); goto uam_load_err; } @@ -100,7 +83,7 @@ struct uam_mod *uam_load(const char *path, const char *name) if (!mod->uam_fcn->uam_setup || ((*mod->uam_fcn->uam_setup)(name) < 0)) { - syslog(LOG_ERR, "uam_load(%s): uam_setup failed", name); + LOG(log_error, logtype_afpd, "uam_load(%s): uam_setup failed", name); goto uam_load_err; } @@ -121,17 +104,18 @@ void uam_unload(struct uam_mod *mod) { if (mod->uam_fcn->uam_cleanup) (*mod->uam_fcn->uam_cleanup)(); + mod_close(mod->uam_module); free(mod); } /* -- client-side uam functions -- */ - /* set up stuff for this uam. */ int uam_register(const int type, const char *path, const char *name, ...) { va_list ap; struct uam_obj *uam; + int ret; if (!name) return -1; @@ -140,8 +124,8 @@ int uam_register(const int type, const char *path, const char *name, ...) if ((uam = auth_uamfind(type, name, strlen(name)))) { if (strcmp(uam->uam_path, path)) { /* it exists, but it's not the same module. */ - syslog(LOG_ERR, "uam_register: \"%s\" already loaded by %s", - name, path); + LOG(log_error, logtype_afpd, "uam_register: \"%s\" already loaded by %s", + name, path); return -1; } uam->uam_count++; @@ -158,7 +142,15 @@ int uam_register(const int type, const char *path, const char *name, ...) va_start(ap, name); switch (type) { + case UAM_SERVER_LOGIN_EXT: /* expect four arguments */ + uam->u.uam_login.login = va_arg(ap, void *); + uam->u.uam_login.logincont = va_arg(ap, void *); + uam->u.uam_login.logout = va_arg(ap, void *); + uam->u.uam_login.login_ext = va_arg(ap, void *); + break; + case UAM_SERVER_LOGIN: /* expect three arguments */ + uam->u.uam_login.login_ext = NULL; uam->u.uam_login.login = va_arg(ap, void *); uam->u.uam_login.logincont = va_arg(ap, void *); uam->u.uam_login.logout = va_arg(ap, void *); @@ -173,13 +165,13 @@ int uam_register(const int type, const char *path, const char *name, ...) va_end(ap); /* attach to other uams */ - if (auth_register(type, uam) < 0) { + ret = auth_register(type, uam); + if ( ret) { free(uam->uam_path); free(uam); - return -1; } - return 0; + return ret; } void uam_unregister(const int type, const char *name) @@ -198,33 +190,71 @@ void uam_unregister(const int type, const char *name) free(uam); } -/* --- helper functions for plugin uams --- */ +/* --- helper functions for plugin uams --- + * name: user name + * len: size of name buffer. +*/ -struct passwd *uam_getname(char *name, const int len) +struct passwd *uam_getname(void *private, char *name, const int len) { + AFPObj *obj = private; struct passwd *pwent; - char *user; - int i; + static char username[256]; + static char user[256]; + static char pwname[256]; + char *p; + size_t namelen, gecoslen = 0, pwnamelen = 0; if ((pwent = getpwnam(name))) return pwent; - + + /* if we have a NT domain name try with it */ + if (obj->options.ntdomain && obj->options.ntseparator) { + /* FIXME What about charset ? */ + size_t ulen = strlen(obj->options.ntdomain) + strlen(obj->options.ntseparator) + strlen(name); + if ((p = malloc(ulen +1))) { + strcpy(p, obj->options.ntdomain); + strcat(p, obj->options.ntseparator); + strcat(p, name); + pwent = getpwnam(p); + free(p); + if (pwent) { + int len = strlen(pwent->pw_name); + if (len < MAXUSERLEN) { + strncpy(name,pwent->pw_name, MAXUSERLEN); + }else{ + LOG(log_error, logtype_uams, "MAJOR:The name %s is longer than %d",pwent->pw_name,MAXUSERLEN); + } + + return pwent; + } + } + } #ifndef NO_REAL_USER_NAME - for (i = 0; i < len; i++) - name[i] = tolower(name[i]); + + if ( (size_t) -1 == (namelen = convert_string((utf8_encoding(obj))?CH_UTF8_MAC:obj->options.maccharset, + CH_UCS2, name, -1, username, sizeof(username)))) + return NULL; setpwent(); while ((pwent = getpwent())) { - if ((user = strchr(pwent->pw_gecos, ','))) - *user = '\0'; - user = pwent->pw_gecos; + if ((p = strchr(pwent->pw_gecos, ','))) + *p = '\0'; + + gecoslen = convert_string(obj->options.unixcharset, CH_UCS2, + pwent->pw_gecos, -1, user, sizeof(username)); + pwnamelen = convert_string(obj->options.unixcharset, CH_UCS2, + pwent->pw_name, -1, pwname, sizeof(username)); + if ((size_t)-1 == gecoslen && (size_t)-1 == pwnamelen) + continue; + /* check against both the gecos and the name fields. the user * might have just used a different capitalization. */ - if ((strncasecmp(user, name, len) == 0) || - (strncasecmp(pwent->pw_name, name, len) == 0)) { - strncpy(name, pwent->pw_name, len); - name[len - 1] = '\0'; + + if ( (namelen == gecoslen && strncasecmp_w((ucs2_t*)user, (ucs2_t*)username, len) == 0) || + ( namelen == pwnamelen && strncasecmp_w ( (ucs2_t*) pwname, (ucs2_t*) username, len) == 0)) { + strlcpy(name, pwent->pw_name, len); break; } } @@ -239,18 +269,23 @@ int uam_checkuser(const struct passwd *pwd) { const char *p; - if (!pwd || !pwd->pw_shell || (*pwd->pw_shell == '\0')) + if (!pwd) return -1; +#ifndef DISABLE_SHELLCHECK + if (!pwd->pw_shell || (*pwd->pw_shell == '\0')) { + LOG(log_info, logtype_afpd, "uam_checkuser: User %s does not have a shell", pwd->pw_name); + return -1; + } + while ((p = getusershell())) { if ( strcmp( p, pwd->pw_shell ) == 0 ) break; } endusershell(); -#ifndef DISABLE_SHELLCHECK if (!p) { - syslog( LOG_INFO, "illegal shell %s for %s", pwd->pw_shell, pwd->pw_name); + LOG(log_info, logtype_afpd, "illegal shell %s for %s", pwd->pw_shell, pwd->pw_name); return -1; } #endif /* DISABLE_SHELLCHECK */ @@ -258,27 +293,57 @@ int uam_checkuser(const struct passwd *pwd) return 0; } +int uam_random_string (AFPObj *obj, char *buf, int len) +{ + uint32_t result; + int ret; + int fd; + + if ( (len <= 0) || (len % sizeof(result))) + return -1; + + /* construct a random number */ + if ((fd = open("/dev/urandom", O_RDONLY)) < 0) { + struct timeval tv; + struct timezone tz; + int i; + + if (gettimeofday(&tv, &tz) < 0) + return -1; + srandom(tv.tv_sec + (unsigned long) obj + (unsigned long) obj->dsi); + for (i = 0; i < len; i += sizeof(result)) { + result = random(); + memcpy(buf + i, &result, sizeof(result)); + } + } else { + ret = read(fd, buf, len); + close(fd); + if (ret <= 0) + return -1; + } + return 0; +} + /* afp-specific functions */ int uam_afpserver_option(void *private, const int what, void *option, - int *len) + size_t *len) { -AFPObj *obj = private; - char **buf = (char **) option; /* most of the options are this */ - int32_t result; - int fd; + AFPObj *obj = private; + const char **buf = (const char **) option; /* most of the options are this */ + struct session_info **sinfo = (struct session_info **) option; if (!obj || !option) return -1; switch (what) { case UAM_OPTION_USERNAME: - *buf = (void *) obj->username; + *buf = &(obj->username[0]); if (len) *len = sizeof(obj->username) - 1; break; case UAM_OPTION_GUEST: - *buf = (void *) obj->options.guest; + *buf = obj->options.guest; if (len) *len = strlen(obj->options.guest); break; @@ -289,7 +354,7 @@ AFPObj *obj = private; switch (*len) { case UAM_PASSWD_FILENAME: - *buf = (void *) obj->options.passwdfile; + *buf = obj->options.passwdfile; *len = strlen(obj->options.passwdfile); break; @@ -298,11 +363,6 @@ AFPObj *obj = private; *len = sizeof(obj->options.passwdminlen); break; - case UAM_PASSWD_MAXFAIL: - *((int *) option) = obj->options.loginmaxfail; - *len = sizeof(obj->options.loginmaxfail); - break; - case UAM_PASSWD_EXPIRETIME: /* not implemented */ default: return -1; @@ -311,60 +371,38 @@ AFPObj *obj = private; break; case UAM_OPTION_SIGNATURE: - *buf = (void *) (((AFPConfig *)obj->config)->signature); + *buf = (void *)obj->dsi->signature; if (len) *len = 16; break; case UAM_OPTION_RANDNUM: /* returns a random number in 4-byte units. */ - if (!len || (*len < 0) || (*len % sizeof(result))) + if (!len) return -1; - /* construct a random number */ - if ((fd = open("/dev/urandom", O_RDONLY)) < 0) { - struct timeval tv; - struct timezone tz; - char *randnum = (char *) option; - int i; - - if (gettimeofday(&tv, &tz) < 0) - return -1; - srandom(tv.tv_sec + (unsigned long) obj + (unsigned long) obj->handle); - for (i = 0; i < *len; i += sizeof(result)) { - result = random(); - memcpy(randnum + i, &result, sizeof(result)); - } - } else { - result = read(fd, option, *len); - close(fd); - if (result < 0) - return -1; - } + return uam_random_string(obj, option, *len); break; case UAM_OPTION_HOSTNAME: - *buf = (void *) obj->options.hostname; + *buf = obj->options.hostname; if (len) *len = strlen(obj->options.hostname); break; - case UAM_OPTION_PROTOCOL: - *buf = (void *) obj->proto; - break; case UAM_OPTION_CLIENTNAME: - { - struct DSI *dsi = obj->handle; - struct hostent *hp; - - hp = gethostbyaddr( (char *) &dsi->client.sin_addr, - sizeof( struct in_addr ), - dsi->client.sin_family ); - if( hp ) - *buf = (void *) hp->h_name; - else - *buf = (void *) inet_ntoa( dsi->client.sin_addr ); - } + { + struct DSI *dsi = obj->dsi; + const struct sockaddr *sa; + static char hbuf[NI_MAXHOST]; + + sa = (struct sockaddr *)&dsi->client; + if (getnameinfo(sa, sizeof(dsi->client), hbuf, sizeof(hbuf), NULL, 0, 0) == 0) + *buf = hbuf; + else + *buf = getip_string((struct sockaddr *)&dsi->client); + break; + } case UAM_OPTION_COOKIE: /* it's up to the uam to actually store something useful here. * this just passes back a handle to the cookie. the uam side @@ -372,7 +410,32 @@ AFPObj *obj = private; * the cookie. */ *buf = (void *) &obj->uam_cookie; break; - + case UAM_OPTION_KRB5SERVICE: + *buf = obj->options.k5service; + if (len) + *len = (*buf)?strlen(*buf):0; + break; + case UAM_OPTION_KRB5REALM: + *buf = obj->options.k5realm; + if (len) + *len = (*buf)?strlen(*buf):0; + break; + case UAM_OPTION_FQDN: + *buf = obj->options.fqdn; + if (len) + *len = (*buf)?strlen(*buf):0; + break; + case UAM_OPTION_MACCHARSET: + *((int *) option) = obj->options.maccharset; + *len = sizeof(obj->options.maccharset); + break; + case UAM_OPTION_UNIXCHARSET: + *((int *) option) = obj->options.unixcharset; + *len = sizeof(obj->options.unixcharset); + break; + case UAM_OPTION_SESSIONINFO: + *sinfo = &(obj->sinfo); + break; default: return -1; break; @@ -384,7 +447,7 @@ AFPObj *obj = private; /* if we need to maintain a connection, this is how we do it. * because an action pointer gets passed in, we can stream * DSI connections */ -int uam_afp_read(void *handle, char *buf, int *buflen, +int uam_afp_read(void *handle, char *buf, size_t *buflen, int (*action)(void *, void *, const int)) { AFPObj *obj = handle; @@ -393,28 +456,18 @@ int uam_afp_read(void *handle, char *buf, int *buflen, if (!obj) return AFPERR_PARAM; - switch (obj->proto) { - case AFPPROTO_ASP: - if ((len = asp_wrtcont(obj->handle, buf, buflen )) < 0) - goto uam_afp_read_err; - return action(handle, buf, *buflen); - break; - - case AFPPROTO_DSI: - len = dsi_writeinit(obj->handle, buf, *buflen); + len = dsi_writeinit(obj->dsi, buf, *buflen); if (!len || ((len = action(handle, buf, len)) < 0)) { - dsi_writeflush(obj->handle); + dsi_writeflush(obj->dsi); goto uam_afp_read_err; } - while ((len = (dsi_write(obj->handle, buf, *buflen)))) { + while ((len = (dsi_write(obj->dsi, buf, *buflen)))) { if ((len = action(handle, buf, len)) < 0) { - dsi_writeflush(obj->handle); + dsi_writeflush(obj->dsi); goto uam_afp_read_err; } } - break; - } return 0; uam_afp_read_err: @@ -427,10 +480,56 @@ void uam_afp_getcmdline( int *ac, char ***av ) { afp_get_cmdline( ac, av ); } + +int uam_sia_validate_user(sia_collect_func_t * collect, int argc, char **argv, + char *hostname, char *username, char *tty, + int colinput, char *gssapi, char *passphrase) +/* A clone of the Tru64 system function sia_validate_user() that calls + * sia_ses_authent() rather than sia_ses_reauthent() + * Added extra code to take into account suspected SIA bug whereby it clobbers + * the signal handler on SIGALRM (tickle) installed by Netatalk/afpd + */ +{ + SIAENTITY *entity = NULL; + struct sigaction act; + int rc; + + if ((rc=sia_ses_init(&entity, argc, argv, hostname, username, tty, + colinput, gssapi)) != SIASUCCESS) { + LOG(log_error, logtype_afpd, "cannot initialise SIA"); + return SIAFAIL; + } + + /* save old action for restoration later */ + if (sigaction(SIGALRM, NULL, &act)) + LOG(log_error, logtype_afpd, "cannot save SIGALRM handler"); + + if ((rc=sia_ses_authent(collect, passphrase, entity)) != SIASUCCESS) { + /* restore old action after clobbering by sia_ses_authent() */ + if (sigaction(SIGALRM, &act, NULL)) + LOG(log_error, logtype_afpd, "cannot restore SIGALRM handler"); + + LOG(log_info, logtype_afpd, "unsuccessful login for %s", +(hostname?hostname:"(null)")); + return SIAFAIL; + } + LOG(log_info, logtype_afpd, "successful login for %s", +(hostname?hostname:"(null)")); + + /* restore old action after clobbering by sia_ses_authent() */ + if (sigaction(SIGALRM, &act, NULL)) + LOG(log_error, logtype_afpd, "cannot restore SIGALRM handler"); + + sia_ses_release(&entity); + + return SIASUCCESS; +} #endif /* TRU64 */ /* --- papd-specific functions (just placeholders) --- */ -void append(void *pf, char *data, int len) +struct papfile; + +UAM_MODULE_EXPORT void append(struct papfile *pf _U_, const char *data _U_, int len _U_) { return; }