X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=etc%2Fafpd%2Fauth.c;h=566a8d0e05b1b838ddc5e2dceef29463e9c33d03;hb=4054f4b3c85ecab060dafd46c0d3632cadbb5803;hp=0ac50eced3e11354e760a1a722abeebd012490fb;hpb=2f7e864e8af0cf66afe35a4b4b1c8b4e1b0e6611;p=netatalk.git diff --git a/etc/afpd/auth.c b/etc/afpd/auth.c index 0ac50ece..566a8d0e 100644 --- a/etc/afpd/auth.c +++ b/etc/afpd/auth.c @@ -1,6 +1,4 @@ /* - * $Id: auth.c,v 1.52 2008-05-16 04:19:41 didg Exp $ - * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. */ @@ -28,8 +26,6 @@ #include #include #include -#include -#include #ifdef TRU64 #include @@ -40,67 +36,88 @@ extern void afp_get_cmdline( int *ac, char ***av ); #endif /* TRU64 */ +#include +#include +#include + #include "globals.h" #include "auth.h" #include "uam_auth.h" #include "switch.h" #include "status.h" - #include "fork.h" +#include "extattrs.h" +#ifdef HAVE_ACLS +#include "acls.h" +#endif -int afp_version = 11; +int afp_version = 11; static int afp_version_index; -uid_t uuid; +uid_t uuid; #if defined( sun ) && !defined( __svr4__ ) || defined( ultrix ) -int *groups; +int *groups; #define GROUPS_SIZE sizeof(int) #else /* sun __svr4__ ultrix */ -gid_t *groups; +gid_t *groups; #define GROUPS_SIZE sizeof(gid_t) #endif /* sun ultrix */ -int ngroups; +int ngroups; /* * These numbers are scattered throughout the code. */ -static struct afp_versions afp_versions[] = { - { "AFPVersion 1.1", 11 }, - { "AFPVersion 2.0", 20 }, - { "AFPVersion 2.1", 21 }, - { "AFP2.2", 22 }, -#ifdef AFP3x - { "AFPX03", 30 }, - { "AFP3.1", 31 } -#endif - }; +static struct afp_versions afp_versions[] = { +#ifndef NO_DDP + { "AFPVersion 1.1", 11 }, + { "AFPVersion 2.0", 20 }, + { "AFPVersion 2.1", 21 }, +#endif /* ! NO_DDP */ + { "AFP2.2", 22 }, + { "AFPX03", 30 }, + { "AFP3.1", 31 }, + { "AFP3.2", 32 }, + { "AFP3.3", 33 } +}; static struct uam_mod uam_modules = {NULL, NULL, &uam_modules, &uam_modules}; static struct uam_obj uam_login = {"", "", 0, {{NULL, NULL, NULL, NULL }}, &uam_login, - &uam_login}; + &uam_login}; static struct uam_obj uam_changepw = {"", "", 0, {{NULL, NULL, NULL, NULL}}, &uam_changepw, - &uam_changepw}; + &uam_changepw}; static struct uam_obj *afp_uam = NULL; -void status_versions( data ) -char *data; +void status_versions( char *data, const ASP asp, const DSI *dsi) { char *start = data; u_int16_t status; - int len, num, i; + int len, num, i, count = 0; memcpy(&status, start + AFPSTATUS_VERSOFF, sizeof(status)); num = sizeof( afp_versions ) / sizeof( afp_versions[ 0 ] ); + + for ( i = 0; i < num; i++ ) { +#ifndef NO_DDP + if ( !asp && (afp_versions[ i ].av_number <= 21)) continue; +#endif /* ! NO_DDP */ + if ( !dsi && (afp_versions[ i ].av_number >= 22)) continue; + count++; + } data += ntohs( status ); - *data++ = num; + *data++ = count; + for ( i = 0; i < num; i++ ) { +#ifndef NO_DDP + if ( !asp && (afp_versions[ i ].av_number <= 21)) continue; +#endif /* ! NO_DDP */ + if ( !dsi && (afp_versions[ i ].av_number >= 22)) continue; len = strlen( afp_versions[ i ].av_name ); *data++ = len; memcpy( data, afp_versions[ i ].av_name , len ); @@ -115,7 +132,7 @@ void status_uams(char *data, const char *authlist) char *start = data; u_int16_t status; struct uam_obj *uams; - int len, num = 0; + int len, num = 0; memcpy(&status, start + AFPSTATUS_UAMSOFF, sizeof(status)); uams = &uam_login; @@ -154,58 +171,79 @@ static int send_reply(const AFPObj *obj, const int err) return AFP_OK; } -static int afp_errpwdexpired(obj, ibuf, ibuflen, rbuf, rbuflen ) -AFPObj *obj _U_; -char *ibuf _U_, *rbuf _U_; -int ibuflen _U_, *rbuflen; +static int afp_errpwdexpired(AFPObj *obj _U_, char *ibuf _U_, size_t ibuflen _U_, + char *rbuf _U_, size_t *rbuflen) { *rbuflen = 0; return AFPERR_PWDEXPR; } +static int afp_null_nolog(AFPObj *obj _U_, char *ibuf _U_, size_t ibuflen _U_, + char *rbuf _U_, size_t *rbuflen) +{ + *rbuflen = 0; + return( AFPERR_NOOP ); +} static int set_auth_switch(int expired) { int i; if (expired) { - /* - * BF: expired password handling - * to allow the user to change his/her password we have to allow login - * but every following call except for FPChangePassword will be thrown - * away with an AFPERR_PWDEXPR error. (thanks to Leland Wallace from Apple - * for clarifying this) + /* + * BF: expired password handling + * to allow the user to change his/her password we have to allow login + * but every following call except for FPChangePassword will be thrown + * away with an AFPERR_PWDEXPR error. (thanks to Leland Wallace from Apple + * for clarifying this) */ - for (i=0; i<=0xff; i++) { - uam_afpserver_action(i, UAM_AFPSERVER_PREAUTH, afp_errpwdexpired, NULL); - } - uam_afpserver_action(AFP_LOGOUT, UAM_AFPSERVER_PREAUTH, afp_logout, NULL); - uam_afpserver_action(AFP_CHANGEPW, UAM_AFPSERVER_PREAUTH, afp_changepw, NULL); + for (i=0; i<=0xff; i++) { + uam_afpserver_action(i, UAM_AFPSERVER_PREAUTH, afp_errpwdexpired, NULL); + } + uam_afpserver_action(AFP_LOGOUT, UAM_AFPSERVER_PREAUTH, afp_logout, NULL); + uam_afpserver_action(AFP_CHANGEPW, UAM_AFPSERVER_PREAUTH, afp_changepw, NULL); } else { afp_switch = postauth_switch; switch (afp_version) { + + case 33: + case 32: +#ifdef HAVE_ACLS + uam_afpserver_action(AFP_GETACL, UAM_AFPSERVER_POSTAUTH, afp_getacl, NULL); + uam_afpserver_action(AFP_SETACL, UAM_AFPSERVER_POSTAUTH, afp_setacl, NULL); + uam_afpserver_action(AFP_ACCESS, UAM_AFPSERVER_POSTAUTH, afp_access, NULL); +#endif /* HAVE_ACLS */ + uam_afpserver_action(AFP_GETEXTATTR, UAM_AFPSERVER_POSTAUTH, afp_getextattr, NULL); + uam_afpserver_action(AFP_SETEXTATTR, UAM_AFPSERVER_POSTAUTH, afp_setextattr, NULL); + uam_afpserver_action(AFP_REMOVEATTR, UAM_AFPSERVER_POSTAUTH, afp_remextattr, NULL); + uam_afpserver_action(AFP_LISTEXTATTR, UAM_AFPSERVER_POSTAUTH, afp_listextattr, NULL); + case 31: - uam_afpserver_action(AFP_ENUMERATE_EXT2, UAM_AFPSERVER_POSTAUTH, afp_enumerate_ext2, NULL); + uam_afpserver_action(AFP_SYNCDIR, UAM_AFPSERVER_POSTAUTH, afp_syncdir, NULL); + uam_afpserver_action(AFP_SYNCFORK, UAM_AFPSERVER_POSTAUTH, afp_syncfork, NULL); + uam_afpserver_action(AFP_SPOTLIGHT_PRIVATE, UAM_AFPSERVER_POSTAUTH, afp_null_nolog, NULL); + uam_afpserver_action(AFP_ENUMERATE_EXT2, UAM_AFPSERVER_POSTAUTH, afp_enumerate_ext2, NULL); + case 30: - uam_afpserver_action(AFP_ENUMERATE_EXT, UAM_AFPSERVER_POSTAUTH, afp_enumerate_ext, NULL); - uam_afpserver_action(AFP_BYTELOCK_EXT, UAM_AFPSERVER_POSTAUTH, afp_bytelock_ext, NULL); + uam_afpserver_action(AFP_ENUMERATE_EXT, UAM_AFPSERVER_POSTAUTH, afp_enumerate_ext, NULL); + uam_afpserver_action(AFP_BYTELOCK_EXT, UAM_AFPSERVER_POSTAUTH, afp_bytelock_ext, NULL); /* catsearch_ext uses the same packet as catsearch FIXME double check this, it wasn't true for enue enumerate_ext */ - uam_afpserver_action(AFP_CATSEARCH_EXT, UAM_AFPSERVER_POSTAUTH, afp_catsearch_ext, NULL); - uam_afpserver_action(AFP_GETSESSTOKEN, UAM_AFPSERVER_POSTAUTH, afp_getsession, NULL); - uam_afpserver_action(AFP_READ_EXT, UAM_AFPSERVER_POSTAUTH, afp_read_ext, NULL); - uam_afpserver_action(AFP_WRITE_EXT, UAM_AFPSERVER_POSTAUTH, afp_write_ext, NULL); - uam_afpserver_action(AFP_DISCTOLDSESS, UAM_AFPSERVER_POSTAUTH, afp_disconnect, NULL); + uam_afpserver_action(AFP_CATSEARCH_EXT, UAM_AFPSERVER_POSTAUTH, afp_catsearch_ext, NULL); + uam_afpserver_action(AFP_GETSESSTOKEN, UAM_AFPSERVER_POSTAUTH, afp_getsession, NULL); + uam_afpserver_action(AFP_READ_EXT, UAM_AFPSERVER_POSTAUTH, afp_read_ext, NULL); + uam_afpserver_action(AFP_WRITE_EXT, UAM_AFPSERVER_POSTAUTH, afp_write_ext, NULL); + uam_afpserver_action(AFP_DISCTOLDSESS, UAM_AFPSERVER_POSTAUTH, afp_disconnect, NULL); case 22: /* * If first connection to a server is done in classic AFP2.2 version is used * but OSX uses AFP3.x FPzzz command ! - */ - uam_afpserver_action(AFP_ZZZ, UAM_AFPSERVER_POSTAUTH, afp_zzz, NULL); - break; + */ + uam_afpserver_action(AFP_ZZZ, UAM_AFPSERVER_POSTAUTH, afp_zzz, NULL); + break; } } @@ -218,17 +256,17 @@ static int login(AFPObj *obj, struct passwd *pwd, void (*logout)(void), int expi int admin = 0; #endif /* ADMIN_GRP */ - /* UAM had syslog control; afpd needs to reassert itself */ +#if 0 set_processname("afpd"); - syslog_setup(log_debug, logtype_default, logoption_ndelay|logoption_pid, logfacility_daemon); +#endif - if ( pwd->pw_uid == 0 ) { /* don't allow root login */ + if ( pwd->pw_uid == 0 ) { /* don't allow root login */ LOG(log_error, logtype_afpd, "login: root login denied!" ); return AFPERR_NOTAUTH; } - LOG(log_info, logtype_afpd, "login %s (uid %d, gid %d) %s", pwd->pw_name, - pwd->pw_uid, pwd->pw_gid , afp_versions[afp_version_index].av_name); + LOG(log_note, logtype_afpd, "%s Login by %s", + afp_versions[afp_version_index].av_name, pwd->pw_name); #ifndef NO_DDP if (obj->proto == AFPPROTO_ASP) { @@ -240,7 +278,7 @@ static int login(AFPObj *obj, struct passwd *pwd, void (*logout)(void), int expi if(addr_net && addr_node) { /* Do we have a valid Appletalk address? */ char nodename[256]; FILE *fp; - int mypid = getpid(); + int mypid = getpid(); struct stat stat_buf; sprintf(nodename, "%s/net%d.%dnode%d", obj->options.authprintdir, @@ -285,7 +323,7 @@ static int login(AFPObj *obj, struct passwd *pwd, void (*logout)(void), int expi LOG(log_error, logtype_afpd, "login: %s getgroups: %s", pwd->pw_name, strerror(errno) ); return AFPERR_BADUAM; } - + if ( NULL == (groups = calloc(ngroups, GROUPS_SIZE)) ) { LOG(log_error, logtype_afpd, "login: %s calloc: %d", ngroups); return AFPERR_BADUAM; @@ -297,9 +335,8 @@ static int login(AFPObj *obj, struct passwd *pwd, void (*logout)(void), int expi } #ifdef ADMIN_GRP -#ifdef DEBUG - LOG(log_info, logtype_afpd, "obj->options.admingid == %d", obj->options.admingid); -#endif /* DEBUG */ + LOG(log_debug, logtype_afpd, "obj->options.admingid == %d", obj->options.admingid); + if (obj->options.admingid != 0) { int i; for (i = 0; i < ngroups; i++) { @@ -311,7 +348,7 @@ static int login(AFPObj *obj, struct passwd *pwd, void (*logout)(void), int expi LOG(log_info, logtype_afpd, "admin login -- %s", pwd->pw_name ); } if (!admin) -#endif /* DEBUG */ +#endif /* ADMIN_GRP */ #ifdef TRU64 { struct DSI *dsi = obj->handle; @@ -354,47 +391,102 @@ static int login(AFPObj *obj, struct passwd *pwd, void (*logout)(void), int expi } #endif /* TRU64 */ - /* There's probably a better way to do this, but for now, we just - play root */ + if (ngroups > 0) { + #define GROUPSTR_BUFSIZE 1024 + char groupsstr[GROUPSTR_BUFSIZE]; + char *s = groupsstr; + int j = GROUPSTR_BUFSIZE; + + int n = snprintf(groupsstr, GROUPSTR_BUFSIZE, "%u", groups[0]); + j -= n; + s += n; + + for (int i = 1; i < ngroups; i++) { + n = snprintf(s, j, ", %u", groups[i]); + if (n == j) { + /* Buffer full */ + LOG(log_debug, logtype_afpd, "login: group string buffer overflow"); + break; + } + j -= n; + s += n; + } + LOG(log_debug, logtype_afpd, "login: %u supplementary groups: %s", ngroups, groupsstr); + } + /* There's probably a better way to do this, but for now, we just play root */ #ifdef ADMIN_GRP - if (admin) uuid = 0; + if (admin) + uuid = 0; else #endif /* ADMIN_GRP */ uuid = pwd->pw_uid; set_auth_switch(expired); - + /* save our euid, we need it for preexec_close */ + obj->uid = geteuid(); obj->logout = logout; #ifdef FORCE_UIDGID obj->force_uid = 1; save_uidgid ( &obj->uidgid ); -#endif - +#endif + return( AFP_OK ); } /* ---------------------- */ -int afp_zzz (obj, ibuf, ibuflen, rbuf, rbuflen ) /* Function 122 */ -AFPObj *obj; -char *ibuf _U_, *rbuf; -unsigned int ibuflen _U_, *rbuflen; +int afp_zzz(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen) { - u_int32_t retdata; + uint32_t data; + DSI *dsi = (DSI *)AFPobj->handle; *rbuflen = 0; + ibuf += 2; + ibuflen -= 2; + + if (ibuflen < 4) + return AFPERR_MISC; + memcpy(&data, ibuf, 4); /* flag */ + data = ntohl(data); + + /* + * Possible sleeping states: + * 1) normal sleep: DSI_SLEEPING (up to 10.3) + * 2) extended sleep: DSI_SLEEPING | DSI_EXTSLEEP (starting with 10.4) + */ + + if (data & AFPZZZ_EXT_WAKEUP) { + /* wakeup request from exetended sleep */ + if (dsi->flags & DSI_EXTSLEEP) { + LOG(log_note, logtype_afpd, "afp_zzz: waking up from extended sleep"); + dsi->flags &= ~(DSI_SLEEPING | DSI_EXTSLEEP); + } + } else { + /* sleep request */ + dsi->flags |= DSI_SLEEPING; + if (data & AFPZZZ_EXT_SLEEP) { + LOG(log_note, logtype_afpd, "afp_zzz: entering extended sleep"); + dsi->flags |= DSI_EXTSLEEP; + } else { + LOG(log_note, logtype_afpd, "afp_zzz: entering normal sleep"); + } + } - retdata = obj->options.sleep /120; - if (!retdata) { - retdata = 1; + /* + * According to AFP 3.3 spec we should not return anything, + * but eg 10.5.8 server still returns the numbers of hours + * the server is keeping the sessino (ie max sleeptime). + */ + data = obj->options.sleep / 120; /* hours */ + if (!data) { + data = 1; } - *rbuflen = sizeof(retdata); - retdata = htonl(retdata); - memcpy(rbuf, &retdata, sizeof(retdata)); - if (obj->sleep) - obj->sleep(); - rbuf += sizeof(retdata); + *rbuflen = sizeof(data); + data = htonl(data); + memcpy(rbuf, &data, sizeof(data)); + rbuf += sizeof(data); + return AFP_OK; } @@ -405,12 +497,12 @@ static int create_session_token(AFPObj *obj) /* use 8 bytes for token as OSX, don't know if it helps */ if ( sizeof(pid_t) > SESSIONTOKEN_LEN) { - LOG(log_error, logtype_afpd, "sizeof(pid_t) > %u", SESSIONTOKEN_LEN ); - return AFPERR_MISC; + LOG(log_error, logtype_afpd, "sizeof(pid_t) > %u", SESSIONTOKEN_LEN ); + return AFPERR_MISC; } if ( NULL == (obj->sinfo.sessiontoken = malloc(SESSIONTOKEN_LEN)) ) - return AFPERR_MISC; + return AFPERR_MISC; memset(obj->sinfo.sessiontoken, 0, SESSIONTOKEN_LEN); obj->sinfo.sessiontoken_len = SESSIONTOKEN_LEN; @@ -425,30 +517,34 @@ static int create_session_key(AFPObj *obj) /* create session key */ if (obj->sinfo.sessionkey == NULL) { if (NULL == (obj->sinfo.sessionkey = malloc(SESSIONKEY_LEN)) ) - return AFPERR_MISC; + return AFPERR_MISC; uam_random_string(obj, obj->sinfo.sessionkey, SESSIONKEY_LEN); obj->sinfo.sessionkey_len = SESSIONKEY_LEN; } return AFP_OK; } - + /* ---------------------- */ -int afp_getsession(obj, ibuf, ibuflen, rbuf, rbuflen ) -AFPObj *obj; -char *ibuf, *rbuf; -unsigned int ibuflen, *rbuflen; +int afp_getsession( + AFPObj *obj, + char *ibuf, size_t ibuflen, + char *rbuf, size_t *rbuflen) { u_int16_t type; u_int32_t idlen = 0; - u_int32_t boottime; + u_int32_t boottime; u_int32_t tklen, tp; - char *token; + char *token; char *p; *rbuflen = 0; tklen = 0; + if (ibuflen < 2 + sizeof(type)) { + return AFPERR_PARAM; + } + ibuf += 2; ibuflen -= 2; @@ -463,12 +559,12 @@ unsigned int ibuflen, *rbuflen; } /* - * - */ + * + */ switch (type) { case 0: /* old version ?*/ - tklen = obj->sinfo.sessiontoken_len; - token = obj->sinfo.sessiontoken; + tklen = obj->sinfo.sessiontoken_len; + token = obj->sinfo.sessiontoken; break; case 1: /* disconnect */ case 2: /* reconnect update id */ @@ -485,30 +581,30 @@ unsigned int ibuflen, *rbuflen; token = obj->sinfo.sessiontoken; } break; - case 3: /* Jaguar */ + case 3: case 4: - if (ibuflen >= 8 ) { - p = ibuf; - memcpy( &idlen, ibuf, sizeof(idlen)); - idlen = ntohl(idlen); - ibuf += sizeof(idlen); - ibuflen -= sizeof(idlen); - ibuf += sizeof(boottime); - ibuflen -= sizeof(boottime); - if (ibuflen < idlen || idlen > (90-10)) { - return AFPERR_PARAM; - } - server_ipc_write(IPC_GETSESSION, idlen+8, p ); - tklen = obj->sinfo.sessiontoken_len; - token = obj->sinfo.sessiontoken; - } - break; - case 8: /* Panther Kerberos Token */ - tklen = obj->sinfo.cryptedkey_len; - token = obj->sinfo.cryptedkey; + if (ibuflen >= 8 ) { + p = ibuf; + memcpy( &idlen, ibuf, sizeof(idlen)); + idlen = ntohl(idlen); + ibuf += sizeof(idlen); + ibuflen -= sizeof(idlen); + ibuf += sizeof(boottime); + ibuflen -= sizeof(boottime); + if (ibuflen < idlen || idlen > (90-10)) { + return AFPERR_PARAM; + } + ipc_child_write(obj->ipc_fd, IPC_GETSESSION, idlen+8, p); + tklen = obj->sinfo.sessiontoken_len; + token = obj->sinfo.sessiontoken; + } break; - default: - return AFPERR_NOOP; + case 8: /* Panther Kerberos Token */ + tklen = obj->sinfo.cryptedkey_len; + token = obj->sinfo.cryptedkey; + break; + default: + return AFPERR_NOOP; break; } @@ -528,13 +624,10 @@ unsigned int ibuflen, *rbuflen; } /* ---------------------- */ -int afp_disconnect(obj, ibuf, ibuflen, rbuf, rbuflen ) -AFPObj *obj _U_; -char *ibuf, *rbuf _U_; -int ibuflen _U_, *rbuflen; +int afp_disconnect(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen) { + DSI *dsi = (DSI *)obj->handle; u_int16_t type; - u_int32_t tklen; pid_t token; int i; @@ -558,36 +651,62 @@ int ibuflen _U_, *rbuflen; ibuf += sizeof(tklen); if ( sizeof(pid_t) > SESSIONTOKEN_LEN) { - LOG(log_error, logtype_afpd, "sizeof(pid_t) > %u", SESSIONTOKEN_LEN ); - return AFPERR_MISC; + LOG(log_error, logtype_afpd, "sizeof(pid_t) > %u", SESSIONTOKEN_LEN ); + return AFPERR_MISC; } if (tklen != SESSIONTOKEN_LEN) { return AFPERR_MISC; - } + } tklen = sizeof(pid_t); memcpy(&token, ibuf, tklen); /* our stuff is pid + zero pad */ ibuf += tklen; for (i = tklen; i < SESSIONTOKEN_LEN; i++, ibuf++) { - if (*ibuf != 0) { - return AFPERR_MISC; - } + if (*ibuf != 0) { + return AFPERR_MISC; + } } - - /* killed old session, not easy */ - server_ipc_write(IPC_KILLTOKEN, tklen, &token); - sleep(1); - - return AFPERR_SESSCLOS; /* was AFP_OK */ + + LOG(log_note, logtype_afpd, "afp_disconnect: trying primary reconnect"); + dsi->flags |= DSI_RECONINPROG; + + /* Deactivate tickle timer */ + const struct itimerval none = {{0, 0}, {0, 0}}; + setitimer(ITIMER_REAL, &none, NULL); + + /* check for old session, possibly transfering session from here to there */ + if (ipc_child_write(obj->ipc_fd, IPC_DISCOLDSESSION, tklen, &token) == -1) + goto exit; + /* write uint16_t DSI request ID */ + if (writet(obj->ipc_fd, &dsi->header.dsi_requestID, 2, 0, 2) != 2) { + LOG(log_error, logtype_afpd, "afp_disconnect: couldn't send DSI request ID"); + goto exit; + } + /* now send our connected AFP client socket */ + if (send_fd(obj->ipc_fd, dsi->socket) != 0) + goto exit; + /* Now see what happens: either afpd master sends us SIGTERM because our session */ + /* has been transfered to a old disconnected session, or we continue */ + sleep(5); + + if (!(dsi->flags & DSI_RECONINPROG)) { /* deleted in SIGTERM handler */ + /* Reconnect succeeded, we exit now after sleeping some more */ + sleep(2); /* sleep some more to give the recon. session time */ + LOG(log_note, logtype_afpd, "afp_disconnect: primary reconnect succeeded"); + exit(0); + } + +exit: + /* Reinstall tickle timer */ + setitimer(ITIMER_REAL, &dsi->timer, NULL); + + LOG(log_error, logtype_afpd, "afp_disconnect: primary reconnect failed"); + return AFPERR_MISC; } /* ---------------------- */ -static int get_version(obj, ibuf, ibuflen, len) -AFPObj *obj; -char *ibuf; -int ibuflen; -int len; +static int get_version(AFPObj *obj, char *ibuf, size_t ibuflen, size_t len) { int num,i; @@ -602,7 +721,7 @@ int len; break; } } - if ( i == num ) /* An inappropo version */ + if ( i == num ) /* An inappropo version */ return AFPERR_BADVERS ; if (afp_version >= 30 && obj->proto != AFPPROTO_DSI) @@ -618,20 +737,18 @@ int len; } /* ---------------------- */ -int afp_login(obj, ibuf, ibuflen, rbuf, rbuflen ) -AFPObj *obj; -char *ibuf, *rbuf; -int ibuflen, *rbuflen; +int afp_login(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen) { struct passwd *pwd = NULL; - int len, i; + size_t len; + int i; *rbuflen = 0; if ( nologin & 1) return send_reply(obj, AFPERR_SHUTDOWN ); - if (ibuflen <= 1) + if (ibuflen < 2) return send_reply(obj, AFPERR_BADVERS ); ibuf++; @@ -639,15 +756,15 @@ int ibuflen, *rbuflen; ibuflen -= 2; i = get_version(obj, ibuf, ibuflen, len); - if (i) + if (i) return send_reply(obj, i ); + if (ibuflen <= len) + return send_reply(obj, AFPERR_BADUAM); + ibuf += len; ibuflen -= len; - if (ibuflen <= 1) - return send_reply(obj, AFPERR_BADUAM); - len = (unsigned char) *ibuf++; ibuflen--; @@ -671,44 +788,41 @@ int ibuflen, *rbuflen; } /* ---------------------- */ -int afp_login_ext(obj, ibuf, ibuflen, rbuf, rbuflen ) -AFPObj *obj; -char *ibuf, *rbuf; -unsigned int ibuflen, *rbuflen; +int afp_login_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen) { struct passwd *pwd = NULL; - unsigned int len; - int i; + size_t len; + int i; char type; u_int16_t len16; char *username; - + *rbuflen = 0; if ( nologin & 1) return send_reply(obj, AFPERR_SHUTDOWN ); - if (ibuflen <= 4) + if (ibuflen < 5) return send_reply(obj, AFPERR_BADVERS ); - ibuf++; + ibuf++; ibuf++; /* pad */ ibuf +=2; /* flag */ len = (unsigned char) *ibuf; ibuf++; ibuflen -= 5; - + i = get_version(obj, ibuf, ibuflen, len); - if (i) + if (i) return send_reply(obj, i ); + if (ibuflen <= len) + return send_reply(obj, AFPERR_BADUAM); + ibuf += len; ibuflen -= len; - if (ibuflen <= 1) - return send_reply(obj, AFPERR_BADUAM); - len = (unsigned char) *ibuf; ibuf++; ibuflen--; @@ -726,31 +840,31 @@ unsigned int ibuflen, *rbuflen; return send_reply(obj, AFPERR_BADUAM); } /* user name */ - if (len <= 1 +sizeof(len16)) + if (ibuflen <= 1 +sizeof(len16)) return send_reply(obj, AFPERR_PARAM); type = *ibuf; username = ibuf; ibuf++; ibuflen--; - if (type != 3) + if (type != 3) return send_reply(obj, AFPERR_PARAM); memcpy(&len16, ibuf, sizeof(len16)); ibuf += sizeof(len16); ibuflen -= sizeof(len16); len = ntohs(len16); - if (len > ibuflen) + if (len > ibuflen) return send_reply(obj, AFPERR_PARAM); ibuf += len; - ibuflen -= len; + ibuflen -= len; /* directory service name */ - if (!ibuflen) + if (!ibuflen) return send_reply(obj, AFPERR_PARAM); type = *ibuf; ibuf++; ibuflen--; - + switch(type) { case 1: case 2: @@ -762,7 +876,7 @@ unsigned int ibuflen, *rbuflen; break; case 3: /* With "No User Authen" it is equal */ - if (ibuflen < sizeof(len16)) + if (ibuflen < sizeof(len16)) return send_reply(obj, AFPERR_PARAM); memcpy(&len16, ibuf, sizeof(len16)); ibuf += sizeof(len16); @@ -771,7 +885,7 @@ unsigned int ibuflen, *rbuflen; break; default: return send_reply(obj, AFPERR_PARAM); - } + } #if 0 if (len != 0) { LOG(log_error, logtype_afpd, "login_ext: directory service path not null!" ); @@ -780,7 +894,7 @@ unsigned int ibuflen, *rbuflen; #endif ibuf += len; ibuflen -= len; - + /* Pad */ if (ibuflen && ((unsigned long) ibuf & 1)) { /* pad character */ ibuf++; @@ -791,7 +905,7 @@ unsigned int ibuflen, *rbuflen; return send_reply(obj, i); } - /* FIXME user name are in UTF8 */ + /* FIXME user name are in UTF8 */ i = afp_uam->u.uam_login.login_ext(obj, username, &pwd, ibuf, ibuflen, rbuf, rbuflen); if (!pwd || ( i != AFP_OK && i != AFPERR_PWDEXPR)) @@ -801,15 +915,12 @@ unsigned int ibuflen, *rbuflen; } /* ---------------------- */ -int afp_logincont(obj, ibuf, ibuflen, rbuf, rbuflen) -AFPObj *obj; -char *ibuf, *rbuf; -int ibuflen, *rbuflen; +int afp_logincont(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen) { struct passwd *pwd = NULL; int err; - if ( afp_uam == NULL || afp_uam->u.uam_login.logincont == NULL ) { + if ( afp_uam == NULL || afp_uam->u.uam_login.logincont == NULL || ibuflen < 2 ) { *rbuflen = 0; return send_reply(obj, AFPERR_NOTAUTH ); } @@ -824,14 +935,15 @@ int ibuflen, *rbuflen; } -int afp_logout(obj, ibuf, ibuflen, rbuf, rbuflen) -AFPObj *obj; -char *ibuf _U_, *rbuf _U_; -int ibuflen _U_, *rbuflen _U_; +int afp_logout(AFPObj *obj, char *ibuf _U_, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen) { - LOG(log_info, logtype_afpd, "logout %s", obj->username); + DSI *dsi = (DSI *)(obj->handle); + + LOG(log_note, logtype_afpd, "AFP logout by %s", obj->username); + of_close_all_forks(); close_all_vol(); - obj->exit(0); + dsi->flags = DSI_AFP_LOGGED_OUT; + *rbuflen = 0; return AFP_OK; } @@ -840,12 +952,9 @@ int ibuflen _U_, *rbuflen _U_; /* change password -- * NOTE: an FPLogin must already have completed successfully for this * to work. this also does a little pre-processing before it hands - * it off to the uam. + * it off to the uam. */ -int afp_changepw(obj, ibuf, ibuflen, rbuf, rbuflen ) -AFPObj *obj; -char *ibuf, *rbuf; -int ibuflen, *rbuflen; +int afp_changepw(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen) { char username[MACFILELEN + 1], *start = ibuf; struct uam_obj *uam; @@ -858,9 +967,9 @@ int ibuflen, *rbuflen; /* check if password change is allowed, OS-X ignores the flag. * we shouldn't trust the client on this anyway. - * not sure about the "right" error code, NOOP for now */ + * not sure about the "right" error code, NOOP for now */ if (!(obj->options.passwdbits & PASSWD_SET)) - return AFPERR_NOOP; + return AFPERR_NOOP; /* make sure we can deal w/ this uam */ len = (unsigned char) *ibuf++; @@ -882,15 +991,15 @@ int ibuflen, *rbuflen; if ((len + 1) & 1) /* pad byte */ ibuf++; } else { - /* AFP > 3.0 doesn't pass the username, APF 3.1 specs page 124 */ - if ( ibuf[0] != '\0' || ibuf[1] != '\0') - return AFPERR_PARAM; + /* AFP > 3.0 doesn't pass the username, APF 3.1 specs page 124 */ + if ( ibuf[0] != '\0' || ibuf[1] != '\0') + return AFPERR_PARAM; ibuf += 2; - len = MIN(sizeof(username), strlen(obj->username)); + len = MIN(sizeof(username), strlen(obj->username)); memcpy(username, obj->username, len); - username[ len ] = '\0'; + username[ len ] = '\0'; } - + LOG(log_info, logtype_afpd, "changing password for <%s>", username); @@ -898,6 +1007,9 @@ int ibuflen, *rbuflen; return AFPERR_PARAM; /* send it off to the uam. we really don't use ibuflen right now. */ + if (ibuflen < (size_t)(ibuf - start)) + return AFPERR_PARAM; + ibuflen -= (ibuf - start); ret = uam->u.uam_changepw(obj, username, pwd, ibuf, ibuflen, rbuf, rbuflen); @@ -905,21 +1017,21 @@ int ibuflen, *rbuflen; (ret == AFPERR_AUTHCONT) ? "continued" : (ret ? "failed" : "succeeded")); if ( ret == AFP_OK ) - set_auth_switch(0); - + set_auth_switch(0); + return ret; } /* FPGetUserInfo */ -int afp_getuserinfo(obj, ibuf, ibuflen, rbuf, rbuflen ) -AFPObj *obj _U_; -char *ibuf, *rbuf; -int ibuflen _U_, *rbuflen; +int afp_getuserinfo(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen) { u_int8_t thisuser; u_int32_t id; u_int16_t bitmap; + char *bitmapp; + + LOG(log_debug, logtype_afpd, "begin afp_getuserinfo:"); *rbuflen = 0; ibuf++; @@ -936,8 +1048,9 @@ int ibuflen _U_, *rbuflen; if ((bitmap & USERIBIT_ALL) != bitmap) return AFPERR_BITMAP; - /* copy the bitmap back to reply buffer */ + /* remember place where we store the possibly modified bitmap later */ memcpy(rbuf, ibuf, sizeof(bitmap)); + bitmapp = rbuf; rbuf += sizeof(bitmap); *rbuflen = sizeof(bitmap); @@ -956,17 +1069,40 @@ int ibuflen _U_, *rbuflen; *rbuflen += sizeof(id); } + if (bitmap & USERIBIT_UUID) { + if ( ! (obj->options.flags & OPTION_UUID)) { + bitmap &= ~USERIBIT_UUID; + bitmap = htons(bitmap); + memcpy(bitmapp, &bitmap, sizeof(bitmap)); + } else { + LOG(log_debug, logtype_afpd, "afp_getuserinfo: get UUID for \'%s\'", obj->username); + int ret; + atalk_uuid_t uuid; + ret = getuuidfromname( obj->username, UUID_USER, uuid); + if (ret != 0) { + LOG(log_info, logtype_afpd, "afp_getuserinfo: error getting UUID !"); + return AFPERR_NOITEM; + } + LOG(log_debug, logtype_afpd, "afp_getuserinfo: got UUID: %s", uuid_bin2string(uuid)); + + memcpy(rbuf, uuid, UUID_BINSIZE); + rbuf += UUID_BINSIZE; + *rbuflen += UUID_BINSIZE; + } + } + + LOG(log_debug, logtype_afpd, "END afp_getuserinfo:"); return AFP_OK; } #define UAM_LIST(type) (((type) == UAM_SERVER_LOGIN || (type) == UAM_SERVER_LOGIN_EXT) ? &uam_login : \ - (((type) == UAM_SERVER_CHANGEPW) ? \ - &uam_changepw : NULL)) + (((type) == UAM_SERVER_CHANGEPW) ? \ + &uam_changepw : NULL)) /* just do a linked list search. this could be sped up with a hashed * list, but i doubt anyone's going to have enough uams to matter. */ struct uam_obj *auth_uamfind(const int type, const char *name, - const int len) + const int len) { struct uam_obj *prev, *start; @@ -1020,14 +1156,14 @@ int auth_load(const char *path, const char *list) strlcpy(name + len, p, sizeof(name) - len); LOG(log_debug, logtype_afpd, "uam: loading (%s)", name); /* - if ((stat(name, &st) == 0) && (mod = uam_load(name, p))) { + if ((stat(name, &st) == 0) && (mod = uam_load(name, p))) { */ if (stat(name, &st) == 0) { if ((mod = uam_load(name, p))) { uam_attach(&uam_modules, mod); - LOG(log_info, logtype_afpd, "uam: %s loaded", p); + LOG(log_debug, logtype_afpd, "uam: %s loaded", p); } else { - LOG(log_info, logtype_afpd, "uam: %s load failure",p); + LOG(log_error, logtype_afpd, "uam: %s load failure",p); } } else { LOG(log_info, logtype_afpd, "uam: uam not found (status=%d)", stat(name, &st)); @@ -1039,7 +1175,7 @@ int auth_load(const char *path, const char *list) } /* get rid of all of the uams */ -void auth_unload() +void auth_unload(void) { struct uam_mod *mod, *prev, *start = &uam_modules;