From: srittau Date: Mon, 9 Jun 2003 14:30:42 +0000 (+0000) Subject: Sam's bug fix in the AFP connection negotiation stage and his preliminary X-Git-Tag: netatalk-1-6-3rc1~3 X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=netatalk.git;a=commitdiff_plain;h=84613900bc932bcb1bfa86cd80b589c4f876c039 Sam's bug fix in the AFP connection negotiation stage and his preliminary support for an Kerberos 5 UAM. --- diff --git a/NEWS b/NEWS index 8890ca33..3ee7a52f 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,9 @@ Changes in 1.6.3 ================ +* UPD: afpd: Infrastructural support for an upcoming Kerberos 5 UAM. + [Sam Noble] +* FIX: afpd: Bug in AFP connection negotiation stage. [Sam] * FIX: afpd: Catsearch, when Mac and unix name differ, search on attributes. * FIX: afpd: Files could be opened for writing on read-only filesystems. * FIX: afpd: Debugging using SIGUSR1 was broken. [Stefan Muenkner] diff --git a/etc/afpd/afp_options.c b/etc/afpd/afp_options.c index f56b7ea1..eff24a7f 100644 --- a/etc/afpd/afp_options.c +++ b/etc/afpd/afp_options.c @@ -1,5 +1,5 @@ /* - * $Id: afp_options.c,v 1.27 2002-08-24 05:00:07 sibaz Exp $ + * $Id: afp_options.c,v 1.27.2.1 2003-06-09 14:30:43 srittau Exp $ * * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu) * Copyright (c) 1990,1993 Regents of The University of Michigan. @@ -122,6 +122,10 @@ void afp_options_free(struct afp_options *opt, free(opt->nlspath); if (opt->passwdfile && (opt->passwdfile != save->passwdfile)) free(opt->passwdfile); + if (opt->k5service && (opt->k5service != save->k5service)) + free(opt->k5service); + if (opt->k5realm && (opt->k5realm != save->k5realm)) + free(opt->k5realm); } /* initialize options */ @@ -148,6 +152,8 @@ void afp_options_init(struct afp_options *options) #ifdef ADMIN_GRP options->admingid = 0; #endif /* ADMIN_GRP */ + options->k5service = NULL; + options->k5realm = NULL; } /* parse an afpd.conf line. i'm doing it this way because it's @@ -371,6 +377,12 @@ int afp_options_parseline(char *buf, struct afp_options *options) } #endif /* ADMIN_GRP */ + if ((c = getoption(buf, "-k5service")) && (opt = strdup(c))) + options->k5service = opt; + if ((c = getoption(buf, "-k5realm")) && (opt = strdup(c))) + options->k5realm = opt; + if ((c = getoption(buf, "-k5keytab"))) + setenv( "KRB5_KTNAME", c, 1 ); if ((c = getoption(buf, "-authprintdir")) && (opt = strdup(c))) options->authprintdir = opt; if ((c = getoption(buf, "-uampath")) && (opt = strdup(c))) diff --git a/etc/afpd/globals.h b/etc/afpd/globals.h index 65ab4f77..7ec61aa1 100644 --- a/etc/afpd/globals.h +++ b/etc/afpd/globals.h @@ -1,5 +1,5 @@ /* - * $Id: globals.h,v 1.14 2002-08-31 05:35:10 jmarcus Exp $ + * $Id: globals.h,v 1.14.2.1 2003-06-09 14:30:44 srittau Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -59,6 +59,7 @@ struct afp_options { char *guest, *loginmesg, *keyfile, *passwdfile; char *uamlist; char *authprintdir; + char *k5service, *k5realm; mode_t umask; mode_t save_mask; #ifdef ADMIN_GRP diff --git a/etc/afpd/status.c b/etc/afpd/status.c index f5acacae..e90af43c 100644 --- a/etc/afpd/status.c +++ b/etc/afpd/status.c @@ -1,5 +1,5 @@ /* - * $Id: status.c,v 1.7 2002-02-06 21:58:50 jmarcus Exp $ + * $Id: status.c,v 1.7.4.1 2003-06-09 14:30:45 srittau Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -35,7 +35,7 @@ #include "icon.h" static void status_flags(char *data, const int notif, const int ipok, - const unsigned char passwdbits) + const unsigned char passwdbits, const int dirsrvcs) { u_int16_t status; @@ -58,6 +58,8 @@ static void status_flags(char *data, const int notif, const int ipok, status |= AFPSRVRINFO_SRVNOTIFY; } status |= AFPSRVRINFO_FASTBOZO; + if (dirsrvcs) + status |= AFPSRVRINFO_SRVRDIR; status = htons(status); memcpy(data + AFPSTATUS_FLAGOFF, &status, sizeof(status)); } @@ -82,14 +84,18 @@ static int status_server(char *data, const char *server) len++; data += len; - /* make room for signature and net address offset. save location of - * signature offset. + /* Make room for signature and net address offset. Save location of + * signature offset. We're also making room for directory names offset + * and the utf-8 server name offset. * - * NOTE: technically, we don't need to reserve space for the + * NOTE: Technically, we don't need to reserve space for the * signature and net address offsets if they're not going to be - * used. as there are no offsets after them, it doesn't hurt to - * have them specified though. so, we just do that to simplify - * things. + * used. As there are no offsets after them, it doesn't hurt to + * have them specified though. So, we just do that to simplify + * things. + * + * NOTE2: AFP3.1 Documentation states that the directory names offset + * is a required feature, even though it can be set to zero. */ len = data - start; status = htons(len + AFPSTATUS_POSTLEN); @@ -179,7 +185,7 @@ static u_int16_t status_signature(char *data, int *servoffset, DSI *dsi, return sigoff; } -static int status_netaddress(char *data, const int servoffset, +static int status_netaddress(char *data, int *servoffset, const ASP asp, const DSI *dsi, const char *fqdn) { @@ -189,7 +195,7 @@ static int status_netaddress(char *data, const int servoffset, begin = data; /* get net address offset */ - memcpy(&offset, data + servoffset, sizeof(offset)); + memcpy(&offset, data + *servoffset, sizeof(offset)); data += ntohs(offset); /* format: @@ -203,12 +209,12 @@ static int status_netaddress(char *data, const int servoffset, /* number of addresses. this currently screws up if we have a dsi connection, but we don't have the ip address. to get around this, we turn off the status flag for tcp/ip. */ - *data++ = (fqdn ? 1 : 0) + (dsi ? 1 : 0) + (asp ? 1 : 0); + *data++ = ((fqdn && dsi) ? 1 : 0) + (dsi ? 1 : 0) + (asp ? 1 : 0); /* handle DNS names */ - if (fqdn) { - int len = strlen(fqdn) + 2; - *data++ = len; + if (fqdn && dsi) { + int len = strlen(fqdn); + *data++ = len + 2; *data++ = 0x04; memcpy(data, fqdn, len); data += len; @@ -253,6 +259,85 @@ static int status_netaddress(char *data, const int servoffset, } #endif /* ! NO_DDP */ + /* calculate/store Directory Services Names offset */ + offset = htons(data - begin); + *servoffset += sizeof(offset); + memcpy(begin + *servoffset, &offset, sizeof(offset)); + + /* return length of buffer */ + return (data - begin); +} + +static int status_directorynames(char *data, int *diroffset, + const DSI *dsi, + const struct afp_options *options) +{ + char *begin = data; + u_int16_t offset; + memcpy(&offset, data + *diroffset, sizeof(offset)); + offset = ntohs(offset); + data += offset; + + /* I can not find documentation of any other purpose for the + * DirectoryNames field. + */ + /* + * Try to synthesize a principal: + * service '/' fqdn '@' realm + */ + if (options->k5service && options->k5realm && options->fqdn) { + /* should k5princ be utf8 encoded? */ + u_int8_t len; + char *p = strchr( options->fqdn, ':' ); + if (p) + *p = '\0'; + len = strlen( options->k5service ) + + strlen( options->fqdn ) + + strlen( options->k5realm ); + len+=2; /* '/' and '@' */ + *data++ = 1; /* DirectoryNamesCount */ + *data++ = len; + snprintf( data, len + 1, "%s/%s@%s", options->k5service, + options->fqdn, options->k5realm ); + data += len; + if (p) + *p = ':'; + } else { + memset(begin + *diroffset, 0, sizeof(offset)); + } + + /* Calculate and store offset for UTF8ServerName */ + *diroffset += sizeof(u_int16_t); + offset = htons(data - begin); + memcpy(begin + *diroffset, &offset, sizeof(u_int16_t)); + + /* return length of buffer */ + return (data - begin); +} + +static int status_utf8servername(char *data, int *nameoffset, + const DSI *dsi, + const struct afp_options *options) +{ + u_int16_t namelen, len; + char *begin = data; + u_int16_t offset; + memcpy(&offset, data + *nameoffset, sizeof(offset)); + offset = ntohs(offset); + data += offset; + + /* FIXME: For now we set the UTF-8 ServerName offset to 0 + * It's irrelevent anyway until we set the appropriate Flags value. + * Later this can be set to something meaningful. + * + * What is the valid character range for an nbpname? + * + * Apple's server likes to use the non-qualified hostname + * This obviously won't work very well if multiple servers are running + * on the box. + */ + memset(begin + *nameoffset, 0, sizeof(offset)); + /* return length of buffer */ return (data - begin); } @@ -287,7 +372,7 @@ void status_init(AFPConfig *aspconfig, AFPConfig *dsiconfig, ASP asp; DSI *dsi; char *status; - int c, sigoff; + int statuslen, c, sigoff; if (!(aspconfig || dsiconfig) || !options) return; @@ -327,7 +412,8 @@ void status_init(AFPConfig *aspconfig, AFPConfig *dsiconfig, status_flags(status, options->server_notif, options->fqdn || (dsiconfig && dsi->server.sin_addr.s_addr), - options->passwdbits); + options->passwdbits, + (options->k5service && options->k5realm && options->fqdn)); /* returns offset to signature offset */ c = status_server(status, options->server ? options->server : options->hostname); @@ -340,16 +426,21 @@ void status_init(AFPConfig *aspconfig, AFPConfig *dsiconfig, status_icon(status, apple_atalk_icon, sizeof(apple_atalk_icon), c); sigoff = status_signature(status, &c, dsi, options->hostname); + /* c now contains the offset where the netaddress offset lives */ + + status_netaddress(status, &c, asp, dsi, options->fqdn); + /* c now contains the offset where the Directory Names Count offset lives */ + status_directorynames(status, &c, dsi, options); + /* c now contains the offset where the UTF-8 ServerName offset lives */ - /* returns length */ - c = status_netaddress(status, c, asp, dsi, options->fqdn); + statuslen = status_utf8servername(status, &c, dsi, options); #ifndef NO_DDP if (aspconfig) { - asp_setstatus(asp, status, c); + asp_setstatus(asp, status, statuslen); aspconfig->signature = status + sigoff; - aspconfig->statuslen = c; + aspconfig->statuslen = statuslen; } #endif /* ! NO_DDP */ @@ -362,9 +453,9 @@ void status_init(AFPConfig *aspconfig, AFPConfig *dsiconfig, if ((options->flags & OPTION_CUSTOMICON) == 0) { status_icon(status, apple_tcp_icon, sizeof(apple_tcp_icon), 0); } - dsi_setstatus(dsi, status, c); + dsi_setstatus(dsi, status, statuslen); dsiconfig->signature = status + sigoff; - dsiconfig->statuslen = c; + dsiconfig->statuslen = statuslen; } } diff --git a/etc/afpd/status.h b/etc/afpd/status.h index f4e984b2..30738593 100644 --- a/etc/afpd/status.h +++ b/etc/afpd/status.h @@ -1,5 +1,5 @@ /* - * $Id: status.h,v 1.5 2001-12-03 05:03:38 jmarcus Exp $ + * $Id: status.h,v 1.5.4.1 2003-06-09 14:30:45 srittau Exp $ */ #ifndef AFPD_STATUS_H @@ -17,8 +17,20 @@ #define AFPSTATUS_UAMSOFF 4 #define AFPSTATUS_ICONOFF 6 #define AFPSTATUS_FLAGOFF 8 +/* AFPSTATUS_PRELEN is the number of bytes for status data prior to + * the ServerName field. + * + * This is two bytes of offset space for the MachineType, AFPVersionCount, + * UAMCount, VolumeIconAndMask, and the 16-bit "Fixed" status flags. + */ #define AFPSTATUS_PRELEN 10 -#define AFPSTATUS_POSTLEN 4 +/* AFPSTATUS_POSTLEN is the number of bytes for offset records + * after the ServerName field. + * + * Right now, this is 2 bytes each for ServerSignature, networkAddressCount, + * DirectoryNameCount, and UTF-8 ServerName + */ +#define AFPSTATUS_POSTLEN 8 #define AFPSTATUS_LEN (AFPSTATUS_PRELEN + AFPSTATUS_POSTLEN) diff --git a/etc/afpd/uam.c b/etc/afpd/uam.c index 7e18ee20..400b3092 100644 --- a/etc/afpd/uam.c +++ b/etc/afpd/uam.c @@ -1,5 +1,5 @@ /* - * $Id: uam.c,v 1.23 2002-10-17 18:01:54 didg Exp $ + * $Id: uam.c,v 1.22.4.1 2003-06-09 14:30:45 srittau Exp $ * * Copyright (c) 1999 Adrian Sun (asun@zoology.washington.edu) * All Rights Reserved. See COPYRIGHT. @@ -64,9 +64,6 @@ char *strchr (), *strrchr (); #endif /* TRU64 */ /* --- server uam functions -- */ -#ifndef NO_LOAD_UAM -extern int uam_setup(const char *path); -#endif /* uam_load. uams must have a uam_setup function. */ struct uam_mod *uam_load(const char *path, const char *name) @@ -75,12 +72,10 @@ struct uam_mod *uam_load(const char *path, const char *name) struct uam_mod *mod; void *module; -#ifndef NO_LOAD_UAM if ((module = mod_open(path)) == NULL) { LOG(log_error, logtype_afpd, "uam_load(%s): failed to load: %s", name, mod_error()); return NULL; } -#endif if ((mod = (struct uam_mod *) malloc(sizeof(struct uam_mod))) == NULL) { LOG(log_error, logtype_afpd, "uam_load(%s): malloc failed", name); @@ -91,8 +86,6 @@ struct uam_mod *uam_load(const char *path, const char *name) buf[sizeof(buf) - 1] = '\0'; if ((p = strchr(buf, '.'))) *p = '\0'; - -#ifndef NO_LOAD_UAM if ((mod->uam_fcn = mod_symbol(module, buf)) == NULL) { LOG(log_error, logtype_afpd, "uam_load(%s): mod_symbol error for symbol %s", name, @@ -113,9 +106,6 @@ struct uam_mod *uam_load(const char *path, const char *name) LOG(log_error, logtype_afpd, "uam_load(%s): uam_setup failed", name); goto uam_load_err; } -#else - uam_setup(name); -#endif mod->uam_module = module; return mod; @@ -134,15 +124,12 @@ void uam_unload(struct uam_mod *mod) { if (mod->uam_fcn->uam_cleanup) (*mod->uam_fcn->uam_cleanup)(); - -#ifndef NO_LOAD_UAM mod_close(mod->uam_module); -#endif free(mod); } /* -- client-side uam functions -- */ -#ifndef ATACC + /* set up stuff for this uam. */ int uam_register(const int type, const char *path, const char *name, ...) { @@ -174,15 +161,7 @@ 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 *); @@ -205,69 +184,6 @@ int uam_register(const int type, const char *path, const char *name, ...) return 0; } -#endif - -#ifdef ATACC -int uam_register_fn(const int type, const char *path, const char *name, void *fn1, void *fn2, - void *fn3, void *fn4) -{ - 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. */ - 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++; - - switch (type) { - case UAM_SERVER_LOGIN_EXT: /* expect four arguments */ - uam->u.uam_login.login_ext = fn4; - uam->u.uam_login.login = fn1; - uam->u.uam_login.logincont = fn2; - uam->u.uam_login.logout = fn3; - break; - case UAM_SERVER_LOGIN: /* expect three arguments */ - uam->u.uam_login.login_ext = NULL; - uam->u.uam_login.login = fn1; - uam->u.uam_login.logincont = fn2; - uam->u.uam_login.logout = fn3; - break; - case UAM_SERVER_CHANGEPW: /* one argument */ - uam->u.uam_changepw = fn1; - break; - case UAM_SERVER_PRINTAUTH: /* x arguments */ - default: - break; - } - - /* attach to other uams */ - if (auth_register(type, uam) < 0) { - free(uam->uam_path); - free(uam); - return -1; - } - - return 0; -} -#endif void uam_unregister(const int type, const char *name) { @@ -466,7 +382,11 @@ AFPObj *obj = private; * the cookie. */ *buf = (void *) &obj->uam_cookie; break; - + case UAM_OPTION_KRB5SERVICE: + *buf = obj->options.k5service; + if (len) + *len = strlen(obj->options.k5service); + break; default: return -1; break;