From: didg Date: Mon, 21 Jul 2003 05:50:53 +0000 (+0000) Subject: MFH sleep and unix priv functionalities. X-Git-Tag: netatalk-2-0-alpha1~168 X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8754cfa162e9f8599744f6d9dca34f120fe6dc8b;p=netatalk.git MFH sleep and unix priv functionalities. --- diff --git a/bin/aecho/aecho.c b/bin/aecho/aecho.c index 3ce4fbfd..410888b5 100644 --- a/bin/aecho/aecho.c +++ b/bin/aecho/aecho.c @@ -1,5 +1,5 @@ /* - * $Id: aecho.c,v 1.5 2001-08-03 22:07:22 srittau Exp $ + * $Id: aecho.c,v 1.5.10.1 2003-07-21 05:50:53 didg Exp $ * * Copyright (c) 1990,1991 Regents of The University of Michigan. * All Rights Reserved. @@ -139,6 +139,8 @@ int main( ac, av ) fprintf(stderr, "Bad address.\n"); exit(1); } + break; + case 'c' : pings = atoi( optarg ); break; diff --git a/config/AppleVolumes.default b/config/AppleVolumes.default index 7859cc6c..9aae88e8 100644 --- a/config/AppleVolumes.default +++ b/config/AppleVolumes.default @@ -83,6 +83,7 @@ # preexec_close -> a non-zero return code from preexec close the # volume being mounted. # nostat -> don't stat volume path when enumerating volumes list +# upriv -> use unix privilege. # # # codepage:filename -> load filename from nls directory. diff --git a/config/afpd.conf.tmpl b/config/afpd.conf.tmpl index d32d8347..47d4b03a 100644 --- a/config/afpd.conf.tmpl +++ b/config/afpd.conf.tmpl @@ -121,6 +121,8 @@ # Note: Depending on the number of simultaneously # connected clients and the network's speed, this can # lead to a significant higher load on your network! +# -sleep AFP 3.x wait number hours before disconnecting +# clients in sleep mode. Default 10 hours # -tickleval Specify the tickle timeout interval (in seconds). # Note, this defaults to 30 seconds, and really # shouldn't be changed. If you want to control diff --git a/config/netatalk.conf b/config/netatalk.conf index 5a30697d..4d3bef9c 100644 --- a/config/netatalk.conf +++ b/config/netatalk.conf @@ -3,7 +3,7 @@ AFPD_MAX_CLIENTS=20 # Change this to set the machine's atalk name and zone. -# NOTE: if you're zone has spaces in it, you're better off specifying +# NOTE: if your zone has spaces in it, you're better off specifying # it in afpd.conf #ATALK_ZONE=@zone ATALK_NAME=`echo ${HOSTNAME}|cut -d. -f1` diff --git a/etc/afpd/afp_dsi.c b/etc/afpd/afp_dsi.c index efcb2fec..24d73511 100644 --- a/etc/afpd/afp_dsi.c +++ b/etc/afpd/afp_dsi.c @@ -1,5 +1,5 @@ /* - * $Id: afp_dsi.c,v 1.27.2.2 2003-06-23 10:25:07 didg Exp $ + * $Id: afp_dsi.c,v 1.27.2.3 2003-07-21 05:50:53 didg Exp $ * * Copyright (c) 1999 Adrian Sun (asun@zoology.washington.edu) * Copyright (c) 1990,1993 Regents of The University of Michigan. @@ -47,6 +47,7 @@ extern struct oforks *writtenfork; #define CHILD_DIE (1 << 0) #define CHILD_RUNNING (1 << 1) +#define CHILD_SLEEPING (1 << 2) static struct { AFPObj *obj; @@ -90,9 +91,14 @@ static void afp_dsi_die(int sig) } } -/* --------------------------------- - * SIGUSR1 down in five mn. -*/ +/* */ +static void afp_dsi_sleep(void) +{ + child.flags |= CHILD_SLEEPING; + dsi_sleep(child.obj->handle, 1); +} + +/* ------------------- */ static void afp_dsi_timedown() { struct sigaction sv; @@ -155,13 +161,15 @@ static void afp_dsi_getmesg (int sig) } #endif /* SERVERTEXT */ -/* ---------------------- */ static void alarm_handler() { -int err; + int err; + /* if we're in the midst of processing something, don't die. */ - if ((child.flags & CHILD_RUNNING) || (child.tickle++ < child.obj->options.timeout)) { + if ((child.flags & CHILD_SLEEPING) && child.tickle++ < child.obj->options.sleep) { + return; + } else if ((child.flags & CHILD_RUNNING) || (child.tickle++ < child.obj->options.timeout)) { if (!(err = pollvoltime(child.obj))) err = dsi_tickle(child.obj->handle); if (err <= 0) @@ -203,6 +211,7 @@ void afp_over_dsi(AFPObj *obj) obj->reply = (int (*)()) dsi_cmdreply; obj->attention = (int (*)(void *, AFPUserBytes)) dsi_attention; + obj->sleep = afp_dsi_sleep; child.obj = obj; child.tickle = child.flags = 0; @@ -270,6 +279,7 @@ void afp_over_dsi(AFPObj *obj) /* get stuck here until the end */ while ((cmd = dsi_receive(dsi))) { child.tickle = 0; + child.flags &= ~CHILD_SLEEPING; dsi_sleep(dsi, 0); /* wake up */ if (reload_request) { reload_request = 0; @@ -278,7 +288,7 @@ void afp_over_dsi(AFPObj *obj) if (cmd == DSIFUNC_TICKLE) { /* so we don't get killed on the client side. */ - if (child.flags & CHILD_DIE) + if ((child.flags & CHILD_DIE)) dsi_tickle(dsi); continue; } else if (!(child.flags & CHILD_DIE)) { /* reset tickle timer */ diff --git a/etc/afpd/afp_options.c b/etc/afpd/afp_options.c index ef6ddc14..31c923f0 100644 --- a/etc/afpd/afp_options.c +++ b/etc/afpd/afp_options.c @@ -1,5 +1,5 @@ /* - * $Id: afp_options.c,v 1.30.2.1 2003-05-26 11:17:25 didg Exp $ + * $Id: afp_options.c,v 1.30.2.2 2003-07-21 05:50:53 didg Exp $ * * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu) * Copyright (c) 1990,1993 Regents of The University of Michigan. @@ -159,6 +159,7 @@ void afp_options_init(struct afp_options *options) options->passwdfile = _PATH_AFPDPWFILE; options->tickleval = 30; options->timeout = 4; + options->sleep = 10* 120; /* 10 h in 30 seconds tick */ options->server_notif = 1; options->authprintdir = NULL; options->signature = "host"; @@ -264,6 +265,13 @@ int afp_options_parseline(char *buf, struct afp_options *options) } } + if ((c = getoption(buf, "-sleep"))) { + options->sleep = atoi(c) *120; + if (options->sleep <= 4) { + options->sleep = 4; + } + } + if ((c = getoption(buf, "-server_quantum"))) options->server_quantum = strtoul(c, NULL, 0); diff --git a/etc/afpd/auth.c b/etc/afpd/auth.c index 949f4ca7..afa85645 100644 --- a/etc/afpd/auth.c +++ b/etc/afpd/auth.c @@ -1,5 +1,5 @@ /* - * $Id: auth.c,v 1.44.2.2 2003-05-26 11:04:36 didg Exp $ + * $Id: auth.c,v 1.44.2.3 2003-07-21 05:50:53 didg Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -33,6 +33,7 @@ #include #include #include +#include #ifdef TRU64 #include @@ -272,6 +273,7 @@ static int login(AFPObj *obj, struct passwd *pwd, void (*logout)(void)) LOG(log_info, logtype_afpd, "session from %s (%s)", hostname, inet_ntoa( dsi->client.sin_addr ) ); + if (setegid( pwd->pw_gid ) < 0 || seteuid( pwd->pw_uid ) < 0) { LOG(log_error, logtype_afpd, "login: %s", strerror(errno) ); return AFPERR_BADUAM; @@ -334,14 +336,15 @@ unsigned int ibuflen, *rbuflen; *rbuflen = 0; - retdata = 1; + retdata = obj->options.sleep /120; + if (!retdata) { + retdata = 1; + } *rbuflen = sizeof(retdata); retdata = htonl(retdata); memcpy(rbuf, &retdata, sizeof(retdata)); - if (obj->proto == AFPPROTO_DSI) { - DSI *dsi = obj->handle; - dsi_sleep(dsi, 1); - } + if (obj->sleep) + obj->sleep(); rbuf += sizeof(retdata); return AFP_OK; } @@ -353,10 +356,12 @@ char *ibuf, *rbuf; unsigned int ibuflen, *rbuflen; { u_int16_t type; - u_int32_t idlen; + u_int32_t idlen = 0; + u_int32_t boottime; u_int16_t tklen; /* FIXME: spec u_int32_t? */ pid_t token; + char *p; *rbuflen = 0; @@ -388,6 +393,19 @@ unsigned int ibuflen, *rbuflen; break; case 3: /* Jaguar */ 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 ); + } type = 0; break; } @@ -434,6 +452,9 @@ int ibuflen, *rbuflen; } memcpy(&token, ibuf, tklen); /* killed old session, not easy */ + server_ipc_write(IPC_KILLTOKEN, tklen, &token); + sleep(1); + return AFPERR_SESSCLOS; /* was AFP_OK */ } @@ -509,7 +530,7 @@ int ibuflen, *rbuflen; if (!len || len > ibuflen) return send_reply(obj, AFPERR_BADUAM); - if ((afp_uam = auth_uamfind(UAM_SERVER_LOGIN, ibuf, len)) == NULL) + if (NULL == (afp_uam = auth_uamfind(UAM_SERVER_LOGIN, ibuf, len)) ) return send_reply(obj, AFPERR_BADUAM); ibuf += len; ibuflen -= len; diff --git a/etc/afpd/desktop.c b/etc/afpd/desktop.c index 749ab69a..a6375e4e 100644 --- a/etc/afpd/desktop.c +++ b/etc/afpd/desktop.c @@ -1,5 +1,5 @@ /* - * $Id: desktop.c,v 1.26.2.3 2003-06-23 10:25:07 didg Exp $ + * $Id: desktop.c,v 1.26.2.4 2003-07-21 05:50:54 didg Exp $ * * See COPYRIGHT. * @@ -911,7 +911,7 @@ int ibuflen, *rbuflen; clen = min( clen, 199 ); upath = path->u_name; - if (check_access(upath, OPENACC_WR ) < 0) { + if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) { return AFPERR_ACCESS; } @@ -1047,7 +1047,7 @@ int ibuflen, *rbuflen; } upath = s_path->u_name; - if (check_access(upath, OPENACC_WR ) < 0) { + if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) { return AFPERR_ACCESS; } diff --git a/etc/afpd/directory.c b/etc/afpd/directory.c index 50f0fca2..c6e7e015 100644 --- a/etc/afpd/directory.c +++ b/etc/afpd/directory.c @@ -1,5 +1,5 @@ /* - * $Id: directory.c,v 1.71.2.3 2003-05-20 14:49:18 didg Exp $ + * $Id: directory.c,v 1.71.2.4 2003-07-21 05:50:54 didg Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -164,6 +164,9 @@ struct dir *dir; /* ----------------------------------------- * if did is not in the cache resolve it with cnid * + * FIXME + * OSX call it with bogus id, ie file ID not folder ID, + * and we are really bad in this case. */ struct dir * dirlookup( vol, did ) @@ -1216,6 +1219,20 @@ char *p; return 0; } +/* --------------------- */ +int file_access(struct path *path, int mode) +{ +struct maccess ma; + + accessmode(path->u_name, &ma, curdir, &path->st); + if ((mode & OPENACC_WR) && !(ma.ma_user & AR_UWRITE)) + return -1; + if ((mode & OPENACC_RD) && !(ma.ma_user & AR_UREAD)) + return -1; + return 0; + +} + /* ------------------------------ (".", curdir) (name, dir) with curdir:name == dir, from afp_enumerate @@ -1403,6 +1420,28 @@ int getdirparams(const struct vol *vol, } break; + case DIRPBIT_UNIXPR : + aint = htonl(st->st_uid); + memcpy( data, &aint, sizeof( aint )); + data += sizeof( aint ); + aint = htonl(st->st_gid); + memcpy( data, &aint, sizeof( aint )); + data += sizeof( aint ); + + aint = st->st_mode; + aint = htonl ( aint & ~S_ISGID ); /* Remove SGID, OSX doesn't like it ... */ + memcpy( data, &aint, sizeof( aint )); + data += sizeof( aint ); + + accessmode( upath, &ma, dir , st); + + *data++ = ma.ma_user; + *data++ = ma.ma_world; + *data++ = ma.ma_group; + *data++ = ma.ma_owner; + break; + + default : if ( isad ) { ad_close( &ad, ADFLAGS_HF ); @@ -1776,6 +1815,56 @@ int setdirparams(const struct vol *vol, buf += 6; break; } + + case DIRPBIT_UNIXPR : + /* Skip UID and GID for now, there seems to be now way to set them from an OSX client anyway */ + buf += sizeof( aint ); + buf += sizeof( aint ); + + change_mdate = 1; + change_parent_mdate = 1; + memcpy( &aint, buf, sizeof( aint )); + buf += sizeof( aint ); + aint = ntohl (aint); + if (curdir->d_did == DIRDID_ROOT) + setdeskmode( aint ); +#if 0 /* don't error if we can't set the desktop mode */ + switch ( errno ) { + case EPERM : + case EACCES : + err = AFPERR_ACCESS; + goto setdirparam_done; + case EROFS : + err = AFPERR_VLOCK; + goto setdirparam_done; + default : + LOG(log_error, logtype_afpd, "setdirparam: setdeskmode: %s", + strerror(errno) ); + break; + err = AFPERR_PARAM; + goto setdirparam_done; + } +#endif /* 0 */ + + if ( setdirunixmode( aint, vol_noadouble(vol), + (vol->v_flags & AFPVOL_DROPBOX)) < 0 ) { + switch ( errno ) { + case EPERM : + case EACCES : + err = AFPERR_ACCESS; + goto setdirparam_done; + case EROFS : + err = AFPERR_VLOCK; + goto setdirparam_done; + default : + LOG(log_error, logtype_afpd, "setdirparam: setdirmode: %s", + strerror(errno) ); + err = AFPERR_PARAM; + goto setdirparam_done; + } + } + break; + default : err = AFPERR_BITMAP; goto setdirparam_done; diff --git a/etc/afpd/directory.h b/etc/afpd/directory.h index 832e28c0..b6e7cd1b 100644 --- a/etc/afpd/directory.h +++ b/etc/afpd/directory.h @@ -1,5 +1,5 @@ /* - * $Id: directory.h,v 1.13.2.3 2003-05-20 14:49:19 didg Exp $ + * $Id: directory.h,v 1.13.2.4 2003-07-21 05:50:54 didg Exp $ * * Copyright (c) 1990,1991 Regents of The University of Michigan. * All Rights Reserved. @@ -137,6 +137,7 @@ extern int path_isadir(struct path *o_path); #define DIRPBIT_GID 11 #define DIRPBIT_ACCESS 12 #define DIRPBIT_PDINFO 13 /* ProDOS Info */ +#define DIRPBIT_UNIXPR 15 /* directory attribute bits (see file.h for other bits) */ #define ATTRBIT_EXPFOLDER (1 << 1) /* shared point */ @@ -212,6 +213,7 @@ typedef int (*dir_loop)(struct dirent *, char *, void *); extern int for_each_dirent __P((const struct vol *, char *, dir_loop , void *)); extern int check_access __P((char *name , int mode)); +extern int file_access __P((struct path *path, int mode)); extern int netatalk_unlink __P((const char *name)); diff --git a/etc/afpd/file.c b/etc/afpd/file.c index 8b5cf25b..8a7fe254 100644 --- a/etc/afpd/file.c +++ b/etc/afpd/file.c @@ -1,5 +1,5 @@ /* - * $Id: file.c,v 1.92.2.1 2003-06-05 08:48:18 didg Exp $ + * $Id: file.c,v 1.92.2.2 2003-07-21 05:50:54 didg Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -58,6 +58,7 @@ char *strchr (), *strrchr (); #include "file.h" #include "filedir.h" #include "globals.h" +#include "unix.h" /* the format for the finderinfo fields (from IM: Toolbox Essentials): * field bytes subfield bytes @@ -142,7 +143,7 @@ char *set_name(const struct vol *vol, char *data, char *name, u_int32_t utf8) if (aint > 255) /* FIXME safeguard, anyway if no ascii char it's game over*/ aint = 255; - utf8 = 0; /* mac roman hint */ + utf8 = 0; /* htonl(utf8) */ memcpy(data, &utf8, sizeof(utf8)); data += sizeof(utf8); @@ -262,6 +263,8 @@ int getmetadata(struct vol *vol, u_char achar, fdType[4]; u_int32_t utf8 = 0; struct stat *st; + struct maccess ma; + #ifdef DEBUG LOG(log_info, logtype_afpd, "begin getmetadata:"); #endif /* DEBUG */ @@ -460,6 +463,26 @@ int getmetadata(struct vol *vol, memcpy(data, &aint, sizeof( aint )); data += sizeof( aint ); break; + case FILPBIT_UNIXPR : + aint = htonl(st->st_uid); + memcpy( data, &aint, sizeof( aint )); + data += sizeof( aint ); + aint = htonl(st->st_gid); + memcpy( data, &aint, sizeof( aint )); + data += sizeof( aint ); + + aint = htonl(st->st_mode); + memcpy( data, &aint, sizeof( aint )); + data += sizeof( aint ); + + accessmode( upath, &ma, dir , st); + + *data++ = ma.ma_user; + *data++ = ma.ma_world; + *data++ = ma.ma_group; + *data++ = ma.ma_owner; + break; + default : return( AFPERR_BITMAP ); } @@ -769,7 +792,7 @@ int setfilparams(struct vol *vol, adp = &ad; } - if (check_access(upath, OPENACC_WR ) < 0) { + if (!vol_unix_priv(vol) && check_access(upath, OPENACC_WR ) < 0) { return AFPERR_ACCESS; } @@ -871,6 +894,19 @@ int setfilparams(struct vol *vol, break; } /* fallthrough */ + case FILPBIT_UNIXPR : + /* Skip the UIG/GID, no way to set them from OSX clients */ + buf += sizeof( aint ); + buf += sizeof( aint ); + + change_mdate = 1; + change_parent_mdate = 1; + memcpy( &aint, buf, sizeof( aint )); + buf += sizeof( aint ); + aint = ntohl (aint); + + setfilemode(path, aint); + break; default : err = AFPERR_BITMAP; goto setfilparam_done; diff --git a/etc/afpd/file.h b/etc/afpd/file.h index bd45bf67..b3179db4 100644 --- a/etc/afpd/file.h +++ b/etc/afpd/file.h @@ -1,5 +1,5 @@ /* - * $Id: file.h,v 1.16.2.1 2003-06-23 10:25:07 didg Exp $ + * $Id: file.h,v 1.16.2.2 2003-07-21 05:50:54 didg Exp $ * * Copyright (c) 1990,1991 Regents of The University of Michigan. * All Rights Reserved. @@ -52,6 +52,7 @@ extern const u_char ufinderi[]; #define FILPBIT_EXTDFLEN 11 #define FILPBIT_PDINFO 13 /* ProDOS Info/ UTF8 name */ #define FILPBIT_EXTRFLEN 14 +#define FILPBIT_UNIXPR 15 /* attribute bits. (d) = directory attribute bit as well. */ #define ATTRBIT_INVISIBLE (1<<0) /* invisible (d) */ diff --git a/etc/afpd/filedir.c b/etc/afpd/filedir.c index 4917d42f..24e1e157 100644 --- a/etc/afpd/filedir.c +++ b/etc/afpd/filedir.c @@ -1,5 +1,5 @@ /* - * $Id: filedir.c,v 1.45.2.1 2003-05-10 10:33:16 didg Exp $ + * $Id: filedir.c,v 1.45.2.2 2003-07-21 05:50:54 didg Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -752,7 +752,8 @@ int ibuflen, *rbuflen; } else #endif /* DROPKLUDGE */ - if (!isdir) { + /* if unix priv don't try to match perm with dest folder */ + if (!isdir && !vol_unix_priv(vol)) { int admode = ad_mode("", 0777); setfilmode(upath, admode, NULL); diff --git a/etc/afpd/fork.c b/etc/afpd/fork.c index ddc01fb3..7a60db01 100644 --- a/etc/afpd/fork.c +++ b/etc/afpd/fork.c @@ -1,5 +1,5 @@ /* - * $Id: fork.c,v 1.51 2003-03-15 01:34:35 didg Exp $ + * $Id: fork.c,v 1.51.2.1 2003-07-21 05:50:54 didg Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -329,8 +329,15 @@ int ibuflen, *rbuflen; } /* FIXME should we check it first ? */ upath = s_path->u_name; - if (check_access(upath, access ) < 0) { - return AFPERR_ACCESS; + if (!vol_unix_priv(vol)) { + if (check_access(upath, access ) < 0) { + return AFPERR_ACCESS; + } + } + else { + if (file_access(s_path, access ) < 0) { + return AFPERR_ACCESS; + } } st = &s_path->st; diff --git a/etc/afpd/globals.h b/etc/afpd/globals.h index 41b067e6..9cb09f4a 100644 --- a/etc/afpd/globals.h +++ b/etc/afpd/globals.h @@ -1,5 +1,5 @@ /* - * $Id: globals.h,v 1.18.2.1 2003-05-26 11:17:25 didg Exp $ + * $Id: globals.h,v 1.18.2.2 2003-07-21 05:50:54 didg Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -72,6 +72,7 @@ struct afp_options { char *k5service, *k5realm; mode_t umask; mode_t save_mask; + int sleep; #ifdef ADMIN_GRP gid_t admingid; #endif /* ADMIN_GRP */ @@ -88,6 +89,7 @@ typedef struct AFPObj { void (*logout)(void), (*exit)(int); int (*reply)(void *, int); int (*attention)(void *, AFPUserBytes); + void (*sleep)(void); /* to prevent confusion, only use these in afp_* calls */ char oldtmp[AFPOBJ_TMPSIZ + 1], newtmp[AFPOBJ_TMPSIZ + 1]; void *uam_cookie; /* cookie for uams */ diff --git a/etc/afpd/main.c b/etc/afpd/main.c index 02c3e148..c6446141 100644 --- a/etc/afpd/main.c +++ b/etc/afpd/main.c @@ -1,5 +1,5 @@ /* - * $Id: main.c,v 1.20.4.1 2003-05-26 11:17:25 didg Exp $ + * $Id: main.c,v 1.20.4.2 2003-07-21 05:50:54 didg Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -41,6 +41,7 @@ #include #include #include +#include #include "globals.h" #include "afp_config.h" @@ -63,6 +64,7 @@ struct afp_options default_options; static AFPConfig *configs; static server_child *server_children; static fd_set save_rfds; +static int Ipc_fd = -1; #ifdef TRU64 void afp_get_cmdline( int *ac, char ***av) @@ -78,6 +80,25 @@ static void afp_exit(const int i) exit(i); } +/* ------------------ + initialize fd set we are waiting for. +*/ +static void set_fd(int ipc_fd) +{ + AFPConfig *config; + + FD_ZERO(&save_rfds); + for (config = configs; config; config = config->next) { + if (config->fd < 0) /* for proxies */ + continue; + FD_SET(config->fd, &save_rfds); + } + if (ipc_fd >= 0) { + FD_SET(ipc_fd, &save_rfds); + } +} + +/* ------------------ */ static void afp_goaway(int sig) { @@ -107,12 +128,7 @@ static void afp_goaway(int sig) LOG(log_error, logtype_afpd, "config re-read: no servers configured"); afp_exit(1); } - FD_ZERO(&save_rfds); - for (config = configs; config; config = config->next) { - if (config->fd < 0) - continue; - FD_SET(config->fd, &save_rfds); - } + set_fd(Ipc_fd); } else { LOG(log_info, logtype_afpd, "disallowing logins"); auth_unload(); @@ -147,6 +163,7 @@ char **av; { AFPConfig *config; fd_set rfds; + void *ipc; struct sigaction sv; sigset_t sigs; @@ -229,13 +246,11 @@ char **av; } sigprocmask(SIG_UNBLOCK, &sigs, NULL); - /* watch atp and dsi sockets. */ - FD_ZERO(&save_rfds); - for (config = configs; config; config = config->next) { - if (config->fd < 0) /* for proxies */ - continue; - FD_SET(config->fd, &save_rfds); + /* watch atp, dsi sockets and ipc parent/child file descriptor. */ + if ((ipc = server_ipc_create())) { + Ipc_fd = server_ipc_parent(ipc); } + set_fd(Ipc_fd); /* wait for an appleshare connection. parent remains in the loop * while the children get handled by afp_over_{asp,dsi}. this is @@ -251,7 +266,9 @@ char **av; LOG(log_error, logtype_afpd, "main: can't wait for input: %s", strerror(errno)); break; } - + if (Ipc_fd >=0 && FD_ISSET(Ipc_fd, &rfds)) { + server_ipc_read(server_children); + } for (config = configs; config; config = config->next) { if (config->fd < 0) continue; diff --git a/etc/afpd/unix.c b/etc/afpd/unix.c index 72b634e6..8c22d752 100644 --- a/etc/afpd/unix.c +++ b/etc/afpd/unix.c @@ -1,5 +1,5 @@ /* - * $Id: unix.c,v 1.43 2003-03-09 19:55:35 didg Exp $ + * $Id: unix.c,v 1.43.2.1 2003-07-21 05:50:54 didg Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -22,9 +22,8 @@ #include #include #include - /* STDC check */ -#if STDC_HEADERS +#ifdef STDC_HEADERS #include #else /* STDC_HEADERS */ #ifndef HAVE_STRCHR @@ -45,6 +44,7 @@ char *strchr (), *strrchr (); #include "directory.h" #include "volume.h" #include "unix.h" +#include "fork.h" /* * Get the free space on a partition. @@ -107,10 +107,10 @@ mode_t bits; mbits = 0; - mbits |= ( bits & ( S_IREAD >> 6 )) ? (AR_UREAD | AR_USEARCH) : 0; + mbits |= ( bits & ( S_IREAD >> 6 )) ? AR_UREAD : 0; mbits |= ( bits & ( S_IWRITE >> 6 )) ? AR_UWRITE : 0; - /* Do we really need this? - mbits |= ( bits & ( S_IEXEC >> 6) ) ? AR_USEARCH : 0; */ + /* Do we really need this? */ + mbits |= ( bits & ( S_IEXEC >> 6) ) ? AR_USEARCH : 0; return( mbits ); } @@ -363,6 +363,26 @@ const mode_t mode; return( 0 ); } +/* --------------------- */ +int setfilemode (path, mode) +struct path* path; +mode_t mode; +{ + if (!path->st_valid) { + of_stat(path); + } + + if (path->st_errno) { + return -1; + } + + if (setfilmode( path->u_name, mode, &path->st) < 0) + return -1; + /* we need to set write perm if read set for resource fork */ + return setfilmode(ad_path( path->u_name, ADFLAGS_HF ), ad_hf_mode(mode), &path->st); +} + +/* --------------------- */ int setfilmode(name, mode, st) char * name; mode_t mode; @@ -384,6 +404,21 @@ mode_t mask = S_IRUSR |S_IWUSR | S_IRGRP | S_IWGRP |S_IROTH | S_IWOTH; return 0; } +/* --------------------- */ +int setdirunixmode( mode, noadouble, dropbox ) +const mode_t mode; +const int noadouble; +const int dropbox; +{ + if ( stickydirmode(".AppleDouble", DIRBITS | mode, dropbox) < 0 && !noadouble) + return -1 ; + + if ( stickydirmode(".", DIRBITS | mode, dropbox) < 0 ) + return -1; + return 0; +} + +/* --------------------- */ int setdirmode( mode, noadouble, dropbox ) const mode_t mode; const int noadouble; @@ -675,10 +710,12 @@ recursive_chown_end: /* This is equivalent of unix rename(). */ int unix_rename(const char *oldpath, const char *newpath) { +#if 0 char pd_name[PATH_MAX+1]; int i; struct stat pd_stat; uid_t uid; +#endif if (rename(oldpath, newpath) < 0) return -1; diff --git a/etc/afpd/unix.h b/etc/afpd/unix.h index 3eba6c47..aa95930e 100644 --- a/etc/afpd/unix.h +++ b/etc/afpd/unix.h @@ -1,5 +1,5 @@ /* - * $Id: unix.h,v 1.12 2003-01-07 15:55:22 rlewczuk Exp $ + * $Id: unix.h,v 1.12.2.1 2003-07-21 05:50:54 didg Exp $ */ #ifndef AFPD_UNIX_H @@ -98,15 +98,17 @@ extern int uquota_getvolspace __P((const struct vol *, VolSpace *, VolSpace *, extern struct afp_options default_options; -extern int gmem __P((const gid_t)); -extern int setdeskmode __P((const mode_t)); -extern int setdirmode __P((const mode_t, const int, const int)); -extern int setdeskowner __P((const uid_t, const gid_t)); -extern int setdirowner __P((const uid_t, const gid_t, const int)); -extern int setfilmode __P((char *, mode_t , struct stat *)); -extern int unix_rename __P((const char *oldpath, const char *newpath)); - -extern void accessmode __P((char *, struct maccess *, struct dir *, struct stat *)); +extern int gmem __P((const gid_t)); +extern int setdeskmode __P((const mode_t)); +extern int setdirunixmode __P((const mode_t, const int, const int)); +extern int setdirmode __P((const mode_t, const int, const int)); +extern int setdeskowner __P((const uid_t, const gid_t)); +extern int setdirowner __P((const uid_t, const gid_t, const int)); +extern int setfilmode __P((char *, mode_t , struct stat *)); +extern int setfilemode __P((struct path*, const mode_t)); +extern int unix_rename __P((const char *oldpath, const char *newpath)); + +extern void accessmode __P((char *, struct maccess *, struct dir *, struct stat *)); #ifdef AFS #define accessmode afsmode diff --git a/etc/afpd/volume.c b/etc/afpd/volume.c index 466be9bb..db0f5017 100644 --- a/etc/afpd/volume.c +++ b/etc/afpd/volume.c @@ -1,5 +1,5 @@ /* - * $Id: volume.c,v 1.51.2.6 2003-06-23 10:25:08 didg Exp $ + * $Id: volume.c,v 1.51.2.7 2003-07-21 05:50:54 didg Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -432,6 +432,9 @@ static void volset(struct vol_option *options, struct vol_option *save, options[VOLOPT_PREEXEC].i_value = 1; else if (strcasecmp(p, "root_preexec_close") == 0) options[VOLOPT_ROOTPREEXEC].i_value = 1; + else if (strcasecmp(p, "upriv") == 0) + options[VOLOPT_FLAGS].i_value |= AFPVOL_UNIX_PRIV; + p = strtok(NULL, ","); } @@ -1175,6 +1178,8 @@ int *buflen; ashort |= VOLPBIT_ATTR_CATSEARCH; if (afp_version >= 30) { ashort |= VOLPBIT_ATTR_UTF8; + if (vol->v_flags & AFPVOL_UNIX_PRIV) + ashort |= VOLPBIT_ATTR_UNIXPRIV; } ashort = htons(ashort); memcpy(data, &ashort, sizeof( ashort )); @@ -1403,7 +1408,8 @@ int ibuflen, *rbuflen; completely worked this out, but it's related to booting from the server. Support for that function is a ways off.. */ - *data++ |= (volume->v_flags & AFPVOL_A2VOL) ? AFPSRVR_CONFIGINFO : 0; + *data |= (volume->v_flags & AFPVOL_A2VOL) ? AFPSRVR_CONFIGINFO : 0; + *data++ |= 0; /* UNIX PRIVS BIT ..., OSX doesn't seem to use it, so we don't either */ len = strlen( volume->v_name ); *data++ = len; memcpy(data, volume->v_name, len ); diff --git a/etc/afpd/volume.h b/etc/afpd/volume.h index e32130d8..debca377 100644 --- a/etc/afpd/volume.h +++ b/etc/afpd/volume.h @@ -1,5 +1,5 @@ /* - * $Id: volume.h,v 1.19.2.4 2003-06-23 10:25:08 didg Exp $ + * $Id: volume.h,v 1.19.2.5 2003-07-21 05:50:54 didg Exp $ * * Copyright (c) 1990,1994 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -118,6 +118,7 @@ this is going away. */ #define AFPVOL_NOFILEID (1 << 15) /* don't advertise createid resolveid and deleteid calls */ #define AFPVOL_UTF8 (1 << 16) /* unix name are in UTF8 */ #define AFPVOL_NOSTAT (1 << 17) /* unix name are in UTF8 */ +#define AFPVOL_UNIX_PRIV (1 << 18) /* support unix privileges */ /* FPGetSrvrParms options */ #define AFPSRVR_CONFIGINFO (1 << 0) @@ -178,6 +179,7 @@ int wincheck(const struct vol *vol, const char *path); #define vol_utf8(vol) (0) #define utf8_encoding() (0) #endif +#define vol_unix_priv(vol) (afp_version >= 30 && ((vol)->v_flags & AFPVOL_UNIX_PRIV)) extern struct vol *getvolbyvid __P((const u_int16_t)); extern int ustatfs_getvolspace __P((const struct vol *, diff --git a/include/atalk/server_child.h b/include/atalk/server_child.h index c983a863..7112e069 100644 --- a/include/atalk/server_child.h +++ b/include/atalk/server_child.h @@ -30,6 +30,10 @@ extern int server_child_remove __P((server_child *, const int, const pid_t)); extern void server_child_free __P((server_child *)); extern void server_child_kill __P((server_child *, const int, const int)); +extern void server_child_kill_one __P((server_child *children, const int forkid, const pid_t pid)); +extern void server_child_kill_one_by_id __P((server_child *children, const int forkid, const pid_t pid, + const u_int32_t len, char *id, u_int32_t boottime)); + extern void server_child_setup __P((server_child *, const int, void (*)())); extern void server_child_handler __P((server_child *)); diff --git a/include/atalk/server_ipc.h b/include/atalk/server_ipc.h new file mode 100644 index 00000000..b462c6f9 --- /dev/null +++ b/include/atalk/server_ipc.h @@ -0,0 +1,16 @@ + +#include + +#define IPC_KILLTOKEN 1 +#define IPC_GETSESSION 2 + +void *server_ipc_create(void); +int server_ipc_child(void *obj); +int server_ipc_parent(void *obj); +int server_ipc_read(server_child *children); +int server_ipc_write(uint16_t command, int len, void *token); + + + + + diff --git a/libatalk/util/Makefile.am b/libatalk/util/Makefile.am index 8ebacf30..21ae9e82 100644 --- a/libatalk/util/Makefile.am +++ b/libatalk/util/Makefile.am @@ -11,6 +11,7 @@ libutil_la_SOURCES = \ logger.c \ module.c \ server_child.c \ + server_ipc.c \ server_lock.c \ strcasestr.c \ strdicasecmp.c diff --git a/libatalk/util/server_child.c b/libatalk/util/server_child.c index d443eb2b..a4eb0a27 100644 --- a/libatalk/util/server_child.c +++ b/libatalk/util/server_child.c @@ -1,5 +1,5 @@ /* - * $Id: server_child.c,v 1.7 2002-10-07 19:14:41 didg Exp $ + * $Id: server_child.c,v 1.7.4.1 2003-07-21 05:50:54 didg Exp $ * * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu) * All rights reserved. See COPYRIGHT. @@ -43,6 +43,9 @@ #ifndef WIFSIGNALED #define WIFSIGNALED(status) (!WIFSTOPPED(status) && !WIFEXITED(status)) #endif +#ifndef WTERMSIG +#define WTERMSIG(status) ((status) & 0x7f) +#endif #include @@ -56,6 +59,10 @@ struct server_child_data { pid_t pid; + u_int32_t time; + u_int32_t idlen; + + char *clientid; struct server_child_data **prevp, *next; }; @@ -176,6 +183,9 @@ int server_child_remove(server_child *children, const int forkid, return 0; unhash_child(child); + if (child->clientid) { + free(child->clientid); + } free(child); children->count--; return 1; @@ -195,6 +205,9 @@ void server_child_free(server_child *children) child = fork->table[j]; /* start at the beginning */ while (child) { tmp = child->next; + if (child->clientid) { + free(child->clientid); + } free(child); child = tmp; } @@ -224,6 +237,72 @@ void server_child_kill(server_child *children, const int forkid, } } +/* send kill to a child processes. + * a plain-old linked list + * FIXME use resolve_child ? + */ +void server_child_kill_one(server_child *children, const int forkid, const pid_t pid) +{ + server_child_fork *fork; + struct server_child_data *child, *tmp; + int i; + + fork = (server_child_fork *) children->fork + forkid; + for (i = 0; i < CHILD_HASHSIZE; i++) { + child = fork->table[i]; + while (child) { + tmp = child->next; + if (child->pid == pid) { + kill(child->pid, SIGTERM); + } + child = tmp; + } + } +} + + +/* see if there is a process for the same mac */ +/* if the times don't match mac has been rebooted */ +void server_child_kill_one_by_id(server_child *children, const int forkid, const pid_t pid, + const u_int32_t idlen, char *id, u_int32_t boottime) +{ + server_child_fork *fork; + struct server_child_data *child, *tmp; + int i; + + fork = (server_child_fork *) children->fork + forkid; + for (i = 0; i < CHILD_HASHSIZE; i++) { + child = fork->table[i]; + while (child) { + tmp = child->next; + if ( child->pid != pid) { + if ( child->idlen == idlen && !memcmp(child->clientid, id, idlen)) { + if ( child->time != boottime ) { + kill(child->pid, SIGTERM); + LOG(log_info, logtype_default, "Disconnecting old session %d, client rebooted.", child->pid); + } + else { + LOG(log_info, logtype_default, "WARNING: 2 connections (%d, %d), boottime identical, don't know if one needs to be disconnected."); + } + + } + } + else + { + child->time = boottime; + /* free old token if any */ + if (child->clientid) { + free(child->clientid); + } + child->idlen = idlen; + child->clientid = id; + LOG(log_info, logtype_default, "Setting clientid (len %d) for %d, boottime %X", idlen, child->pid, boottime); + } + child = tmp; + } + } +} + /* for extra cleanup if necessary */ void server_child_setup(server_child *children, const int forkid, void (*fcn)(const pid_t)) @@ -266,7 +345,8 @@ void server_child_handler(server_child *children) } else { if (WIFSIGNALED(status)) { - LOG(log_info, logtype_default, "server_child[%d] %d killed", i, pid); + LOG(log_info, logtype_default, "server_child[%d] %d killed by signal %d", i, pid, + WTERMSIG (status)); } else { diff --git a/libatalk/util/server_ipc.c b/libatalk/util/server_ipc.c new file mode 100644 index 00000000..58eba00d --- /dev/null +++ b/libatalk/util/server_ipc.c @@ -0,0 +1,187 @@ +/* + * $Id: server_ipc.c,v 1.1.4.1 2003-07-21 05:50:55 didg Exp $ + * + * All rights reserved. See COPYRIGHT. + * + * + * ipc between parent and children. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include +#include + +#include +#include +#include + +typedef struct ipc_header { + u_int16_t command; + pid_t child_pid; + u_int32_t len; + char *msg; +} ipc_header; + +static int pipe_fd[2]; + +void *server_ipc_create(void) +{ + if (pipe(pipe_fd)) { + return NULL; + } + return &pipe_fd; +} + +/* ----------------- */ +int server_ipc_child(void *obj) +{ + /* close input */ + close(pipe_fd[0]); + return pipe_fd[1]; +} + +/* ----------------- */ +int server_ipc_parent(void *obj) +{ + return pipe_fd[0]; +} + +/* ----------------- */ +int ipc_kill_token (struct ipc_header *ipc, server_child *children) +{ + pid_t pid; + + if (ipc->len != sizeof(pid_t)) { + return -1; + } + /* assume signals SA_RESTART set */ + memcpy (&pid, ipc->msg, sizeof(pid_t)); + + LOG(log_info, logtype_default, "child %d disconnected", pid); + server_child_kill_one(children, CHILD_DSIFORK, pid); + return 0; +} + +/* ----------------- */ +int ipc_get_session (struct ipc_header *ipc, server_child *children) +{ + u_int32_t boottime; + u_int32_t idlen; + char *clientid, *p; + + + if (ipc->len < (sizeof(idlen) + sizeof(boottime)) ) { + return -1; + } + p = ipc->msg; + memcpy (&idlen, p, sizeof(idlen)); + idlen = ntohl (idlen); + p += sizeof(idlen); + + memcpy (&boottime, p, sizeof(boottime)); + p += sizeof(boottime); + + if (ipc->len < idlen + sizeof(idlen) + sizeof(boottime)) { + return -1; + } + if (NULL == (clientid = (char*) malloc(idlen)) ) { + return -1; + } + memcpy (clientid, p, idlen); + + server_child_kill_one_by_id (children, CHILD_DSIFORK, ipc->child_pid, idlen, clientid, boottime); + /* FIXME byte to ascii if we want to log clientid */ + LOG (log_info, logtype_afpd, "ipc_get_session: len: %u, idlen %d, time %x", ipc->len, idlen, boottime); + return 0; +} + +#define IPC_HEADERLEN 10 +#define IPC_MAXMSGSIZE 90 + +/* ----------------- */ +int server_ipc_read(server_child *children) +{ + int ret = 0; + struct ipc_header ipc; + char buf[IPC_MAXMSGSIZE], *p; + + if ((ret = read(pipe_fd[0], buf, IPC_HEADERLEN)) != IPC_HEADERLEN) { + LOG (log_info, logtype_afpd, "Reading IPC header failed (%u of %u bytes read)", ret, IPC_HEADERLEN); + return -1; + } + + p = buf; + memcpy(&ipc.command, p, sizeof(ipc.command)); + p += sizeof(ipc.command); + memcpy(&ipc.child_pid, p, sizeof(ipc.child_pid)); + p += sizeof(ipc.child_pid); + memcpy(&ipc.len, p, sizeof(ipc.len)); + + /* This should never happen */ + if (ipc.len > (IPC_MAXMSGSIZE - IPC_HEADERLEN)) + { + LOG (log_info, logtype_afpd, "IPC message exceeds allowed size (%u)", ipc.len); + return -1; + } + + memset (buf, 0, IPC_MAXMSGSIZE); + if ( ipc.len != 0) { + if ((ret = read(pipe_fd[0], buf, ipc.len)) != ipc.len) { + LOG (log_info, logtype_afpd, "Reading IPC message failed (%u of %u bytes read)", ret, ipc.len); + return -1; + } + } + ipc.msg = buf; + + LOG (log_info, logtype_afpd, "ipc_read: command: %u, pid: %u, len: %u", ipc.command, ipc.child_pid, ipc.len); + + switch (ipc.command) + { + case IPC_KILLTOKEN: + return (ipc_kill_token(&ipc, children)); + break; + case IPC_GETSESSION: + return (ipc_get_session(&ipc, children)); + break; + default: + LOG (log_info, logtype_afpd, "ipc_read: unknown command: %d", ipc.command); + return -1; + } + +} + +/* ----------------- */ +int server_ipc_write( u_int16_t command, int len, void *msg) +{ + char block[IPC_MAXMSGSIZE], *p; + pid_t pid; + p = block; + + memset ( p, 0 , IPC_MAXMSGSIZE); + if (len + IPC_HEADERLEN > IPC_MAXMSGSIZE) + return -1; + + memcpy(p, &command, sizeof(command)); + p += sizeof(command); + + pid = getpid(); + memcpy(p, &pid, sizeof(pid_t)); + p += sizeof(pid_t); + + memcpy(p, &len, 4); + p += 4; + + memcpy(p, msg, len); + + LOG (log_info, logtype_afpd, "ipc_write: command: %u, pid: %u, msglen: %u", command, pid, len); + return write(pipe_fd[1], block, len+IPC_HEADERLEN ); +} +