X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=netatalk.git;a=blobdiff_plain;f=etc%2Fafpd%2Fuam.c;h=92173915c5f5cc5e7dfa8934c00f1a1ba34a1d85;hp=d22dcf196eddb777fadfa788e1a26facfd626164;hb=4054f4b3c85ecab060dafd46c0d3632cadbb5803;hpb=a24a8fa9f80174f42fc8d35af3354f53702b1a66 diff --git a/etc/afpd/uam.c b/etc/afpd/uam.c index d22dcf19..92173915 100644 --- a/etc/afpd/uam.c +++ b/etc/afpd/uam.c @@ -1,5 +1,5 @@ /* - * $Id: uam.c,v 1.8 2001-05-31 18:48:32 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. @@ -7,21 +7,43 @@ #ifdef HAVE_CONFIG_H #include "config.h" -#endif +#endif /* HAVE_CONFIG_H */ #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 +#ifdef HAVE_DLFCN_H +#include +#endif /* HAVE_DLFCN_H */ -#ifdef SHADOWPW -#include -#endif SHADOWPW +#include +#include #include #include @@ -34,57 +56,67 @@ #include "auth.h" #include "uam_auth.h" +#define utf8_encoding() (afp_version >= 30) + +#ifdef TRU64 +#include +#include +#include +#include +#endif /* TRU64 */ + /* --- server uam functions -- */ /* uam_load. uams must have a uam_setup function. */ struct uam_mod *uam_load(const char *path, const char *name) { - char buf[MAXPATHLEN + 1], *p; - struct uam_mod *mod; - void *module; + char buf[MAXPATHLEN + 1], *p; + struct uam_mod *mod; + void *module; - if ((module = mod_open(path)) == NULL) { - syslog(LOG_ERR, "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); - goto uam_load_fail; - } - - strncpy(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); - 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); - goto uam_load_err; - } - - /* version check would go here */ - - if (!mod->uam_fcn->uam_setup || - ((*mod->uam_fcn->uam_setup)(name) < 0)) { - syslog(LOG_ERR, "uam_load(%s): uam_setup failed", name); - goto uam_load_err; - } - - mod->uam_module = module; - return mod; + if ((module = mod_open(path)) == NULL) { + 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) { + LOG(log_error, logtype_afpd, "uam_load(%s): malloc failed", name); + goto uam_load_fail; + } + + strlcpy(buf, name, sizeof(buf)); + if ((p = strchr(buf, '.'))) + *p = '\0'; + + if ((mod->uam_fcn = mod_symbol(module, buf)) == NULL) { + 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) { + LOG(log_error, logtype_afpd, "uam_load(%s): attempted to load a non-server module", + name); + goto uam_load_err; + } + + /* version check would go here */ + + if (!mod->uam_fcn->uam_setup || + ((*mod->uam_fcn->uam_setup)(name) < 0)) { + LOG(log_error, logtype_afpd, "uam_load(%s): uam_setup failed", name); + goto uam_load_err; + } + + mod->uam_module = module; + return mod; uam_load_err: - free(mod); + free(mod); uam_load_fail: - mod_close(module); - return NULL; + mod_close(module); + return NULL; } /* unload the module. we check for a cleanup function, but we don't @@ -92,297 +124,453 @@ uam_load_fail: */ 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); + 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; - - if (!name) - return -1; - - /* see if it already exists. */ - 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); - return -1; + va_list ap; + struct uam_obj *uam; + int ret; + + if (!name) + return -1; + + /* see if it already exists. */ + if ((uam = auth_uamfind(type, name, strlen(name)))) { + if (strcmp(uam->uam_path, path)) { + /* it exists, but it's not the same module. */ + LOG(log_error, logtype_afpd, "uam_register: \"%s\" already loaded by %s", + name, path); + return -1; + } + uam->uam_count++; + return 0; } + + /* allocate space for uam */ + if ((uam = calloc(1, sizeof(struct uam_obj))) == NULL) + return -1; + + uam->uam_name = name; + uam->uam_path = strdup(path); uam->uam_count++; - return 0; - } - - /* allocate space for uam */ - if ((uam = calloc(1, sizeof(struct uam_obj))) == NULL) - return -1; - - uam->uam_name = name; - uam->uam_path = strdup(path); - uam->uam_count++; - - va_start(ap, name); - switch (type) { - case UAM_SERVER_LOGIN: /* expect three 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 *); - break; - case UAM_SERVER_CHANGEPW: /* one argument */ - uam->u.uam_changepw = va_arg(ap, void *); - break; - case UAM_SERVER_PRINTAUTH: /* x arguments */ - default: - break; - } - va_end(ap); - - /* attach to other uams */ - if (auth_register(type, uam) < 0) { - free(uam->uam_path); - free(uam); - return -1; - } - return 0; + 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 *); + break; + case UAM_SERVER_CHANGEPW: /* one argument */ + uam->u.uam_changepw = va_arg(ap, void *); + break; + case UAM_SERVER_PRINTAUTH: /* x arguments */ + default: + break; + } + va_end(ap); + + /* attach to other uams */ + ret = auth_register(type, uam); + if ( ret) { + free(uam->uam_path); + free(uam); + } + + return ret; } void uam_unregister(const int type, const char *name) { - struct uam_obj *uam; + struct uam_obj *uam; - if (!name) - return; + if (!name) + return; - uam = auth_uamfind(type, name, strlen(name)); - if (!uam || --uam->uam_count > 0) - return; + uam = auth_uamfind(type, name, strlen(name)); + if (!uam || --uam->uam_count > 0) + return; - auth_unregister(uam); - free(uam->uam_path); - free(uam); + auth_unregister(uam); + free(uam->uam_path); + 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) { - struct passwd *pwent; - char *user; - int i; + AFPObj *obj = private; + struct passwd *pwent; + 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 - if ((pwent = getpwnam(name))) - return pwent; + if ( (size_t) -1 == (namelen = convert_string((utf8_encoding())?CH_UTF8_MAC:obj->options.maccharset, + CH_UCS2, name, -1, username, sizeof(username)))) + return NULL; -#ifndef NO_REAL_USER_NAME - for (i = 0; i < len; i++) - name[i] = tolower(name[i]); - - setpwent(); - while ((pwent = getpwent())) { - if ((user = strchr(pwent->pw_gecos, ','))) - *user = '\0'; - user = pwent->pw_gecos; - - /* 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); - break; + setpwent(); + while ((pwent = getpwent())) { + if ((p = strchr(pwent->pw_gecos, ','))) + *p = '\0'; + + if ((size_t)-1 == ( gecoslen = convert_string(obj->options.unixcharset, CH_UCS2, + pwent->pw_gecos, -1, user, sizeof(username))) ) + continue; + if ((size_t)-1 == ( pwnamelen = convert_string(obj->options.unixcharset, CH_UCS2, + pwent->pw_name, -1, pwname, sizeof(username))) ) + continue; + + + /* check against both the gecos and the name fields. the user + * might have just used a different capitalization. */ + + 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; + } } - } - endpwent(); -#endif + endpwent(); +#endif /* ! NO_REAL_USER_NAME */ - /* os x server doesn't keep anything useful if we do getpwent */ - return pwent ? getpwnam(name) : NULL; + /* os x server doesn't keep anything useful if we do getpwent */ + return pwent ? getpwnam(name) : NULL; } int uam_checkuser(const struct passwd *pwd) { - char *p; - - if (!pwd || !pwd->pw_shell || (*pwd->pw_shell == '\0')) - return -1; - - while ((p = getusershell())) { - if ( strcmp( p, pwd->pw_shell ) == 0 ) - break; - } - endusershell(); - -#ifdef DISABLE_SHELLCHECK - if (!p) { - syslog( LOG_INFO, "illegal shell %s for %s", pwd->pw_shell, pwd->pw_name); - return -1; - } + const char *p; + + 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(); + + if (!p) { + LOG(log_info, logtype_afpd, "illegal shell %s for %s", pwd->pw_shell, pwd->pw_name); + return -1; + } #endif /* DISABLE_SHELLCHECK */ - return 0; + return 0; } -/* afp-specific functions */ -int uam_afpserver_option(void *private, const int what, void *option, - int *len) +int uam_random_string (AFPObj *obj, char *buf, int len) { - AFPObj *obj = private; - char **buf = (char **) option; /* most of the options are this */ - int32_t result; - int fd; - - if (!obj || !option) - return -1; - - switch (what) { - case UAM_OPTION_USERNAME: - *buf = (void *) obj->username; - if (len) - *len = sizeof(obj->username) - 1; - break; - - case UAM_OPTION_GUEST: - *buf = (void *) obj->options.guest; - if (len) - *len = strlen(obj->options.guest); - break; - - case UAM_OPTION_PASSWDOPT: - if (!len) - return -1; - - switch (*len) { - case UAM_PASSWD_FILENAME: - *buf = (void *) obj->options.passwdfile; - *len = strlen(obj->options.passwdfile); - break; - - case UAM_PASSWD_MINLENGTH: - *((int *) option) = obj->options.passwdminlen; - *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; - break; - } - break; - - case UAM_OPTION_SIGNATURE: - *buf = (void *) (((AFPConfig *)obj->config)->signature); - if (len) - *len = 16; - break; + u_int32_t result; + int ret; + int fd; - case UAM_OPTION_RANDNUM: /* returns a random number in 4-byte units. */ - if (!len || (*len < 0) || (*len % sizeof(result))) - return -1; + 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; - 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)); - } + 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->handle); + for (i = 0; i < len; i += sizeof(result)) { + result = random(); + memcpy(buf + i, &result, sizeof(result)); + } } else { - result = read(fd, option, *len); - close(fd); - if (result < 0) - return -1; + ret = read(fd, buf, len); + close(fd); + if (ret <= 0) + return -1; } - break; - - case UAM_OPTION_HOSTNAME: - *buf = (void *) obj->options.hostname; - if (len) - *len = strlen(obj->options.hostname); - break; - - case UAM_OPTION_PROTOCOL: - *buf = (void *) obj->proto; - 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 - * needs to do something like **buf = (void *) cookie to store - * the cookie. */ - *buf = (void *) &obj->uam_cookie; - break; - - default: - return -1; - break; - } - - return 0; + return 0; } -/* if we need to maintain a connection, this is how we do it. +/* afp-specific functions */ +int uam_afpserver_option(void *private, const int what, void *option, + size_t *len) +{ + 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 = obj->username; + if (len) + *len = sizeof(obj->username) - 1; + break; + + case UAM_OPTION_GUEST: + *buf = obj->options.guest; + if (len) + *len = strlen(obj->options.guest); + break; + + case UAM_OPTION_PASSWDOPT: + if (!len) + return -1; + + switch (*len) { + case UAM_PASSWD_FILENAME: + *buf = obj->options.passwdfile; + *len = strlen(obj->options.passwdfile); + break; + + case UAM_PASSWD_MINLENGTH: + *((int *) option) = obj->options.passwdminlen; + *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; + break; + } + break; + + case UAM_OPTION_SIGNATURE: + *buf = (void *) (((AFPConfig *)obj->config)->signature); + if (len) + *len = 16; + break; + + case UAM_OPTION_RANDNUM: /* returns a random number in 4-byte units. */ + if (!len) + return -1; + + return uam_random_string(obj, option, *len); + break; + + case UAM_OPTION_HOSTNAME: + *buf = obj->options.hostname; + if (len) + *len = strlen(obj->options.hostname); + break; + + case UAM_OPTION_PROTOCOL: + *((int *) option) = obj->proto; + break; + + case UAM_OPTION_CLIENTNAME: + { + struct DSI *dsi = obj->handle; + 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 + * needs to do something like **buf = (void *) cookie to store + * 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; + } + + return 0; +} + +/* 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 (*action)(void *, void *, const int)) +int uam_afp_read(void *handle, char *buf, size_t *buflen, + int (*action)(void *, void *, const int)) { - AFPObj *obj = handle; - int len; + AFPObj *obj = handle; + int len; - if (!obj) - return AFPERR_PARAM; + if (!obj) + return AFPERR_PARAM; - switch (obj->proto) { + 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; + 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); - if (!len || ((len = action(handle, buf, len)) < 0)) { - dsi_writeflush(obj->handle); - goto uam_afp_read_err; - } - - while ((len = (dsi_write(obj->handle, buf, *buflen)))) { - if ((len = action(handle, buf, len)) < 0) { - dsi_writeflush(obj->handle); - goto uam_afp_read_err; - } - } - break; - } - return 0; + len = dsi_writeinit(obj->handle, buf, *buflen); + if (!len || ((len = action(handle, buf, len)) < 0)) { + dsi_writeflush(obj->handle); + goto uam_afp_read_err; + } + + while ((len = (dsi_write(obj->handle, buf, *buflen)))) { + if ((len = action(handle, buf, len)) < 0) { + dsi_writeflush(obj->handle); + goto uam_afp_read_err; + } + } + break; + } + return 0; uam_afp_read_err: - *buflen = 0; - return len; + *buflen = 0; + return len; } +#ifdef TRU64 +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; + return; }