void unbecome_root(void) { if (getuid() == 0) { if (saved_uid == -1 || seteuid(saved_uid) < 0) AFP_PANIC("Can't seteuid back"); saved_uid = -1; } }
/* * seteuid(0) and back, if either fails and panic != 0 we PANIC */ void become_root(void) { if (getuid() == 0) { saved_uid = geteuid(); if (seteuid(0) != 0) AFP_PANIC("Can't seteuid(0)"); } }
static void dsi_init_buffer(DSI *dsi) { /* default is 12 * 300k = 3,6 MB (Apr 2011) */ if ((dsi->buffer = malloc(dsi->dsireadbuf * dsi->server_quantum)) == NULL) { LOG(log_error, logtype_dsi, "dsi_init_buffer: OOM"); AFP_PANIC("OOM in dsi_init_buffer"); } dsi->start = dsi->buffer; dsi->eof = dsi->buffer; dsi->end = dsi->buffer + (dsi->dsireadbuf * dsi->server_quantum); }
/* OpenSession. set up the connection */ void dsi_opensession(DSI *dsi) { u_int32_t i = 0; /* this serves double duty. it must be 4-bytes long */ int offs; dsi_init_buffer(dsi); if (setnonblock(dsi->socket, 1) < 0) { LOG(log_error, logtype_dsi, "dsi_opensession: setnonblock: %s", strerror(errno)); AFP_PANIC("setnonblock error"); } /* parse options */ while (i < dsi->cmdlen) { switch (dsi->commands[i++]) { case DSIOPT_ATTNQUANT: memcpy(&dsi->attn_quantum, dsi->commands + i + 1, dsi->commands[i]); dsi->attn_quantum = ntohl(dsi->attn_quantum); case DSIOPT_SERVQUANT: /* just ignore these */ default: i += dsi->commands[i] + 1; /* forward past length tag + length */ break; } } /* let the client know the server quantum. we don't use the * max server quantum due to a bug in appleshare client 3.8.6. */ dsi->header.dsi_flags = DSIFL_REPLY; dsi->header.dsi_code = 0; /* dsi->header.dsi_command = DSIFUNC_OPEN;*/ dsi->cmdlen = 2 * (2 + sizeof(i)); /* length of data. dsi_send uses it. */ /* DSI Option Server Request Quantum */ dsi->commands[0] = DSIOPT_SERVQUANT; dsi->commands[1] = sizeof(i); i = htonl(( dsi->server_quantum < DSI_SERVQUANT_MIN || dsi->server_quantum > DSI_SERVQUANT_MAX ) ? DSI_SERVQUANT_DEF : dsi->server_quantum); memcpy(dsi->commands + 2, &i, sizeof(i)); /* AFP replaycache size option */ offs = 2 + sizeof(i); dsi->commands[offs] = DSIOPT_REPLCSIZE; dsi->commands[offs+1] = sizeof(i); i = htonl(REPLAYCACHE_SIZE); memcpy(dsi->commands + offs + 2, &i, sizeof(i)); dsi_send(dsi); }
int ad_lock(struct adouble *ad, uint32_t eid, int locktype, off_t off, off_t len, int fork) { struct flock lock; struct ad_fd *adf; adf_lock_t *adflock; int oldlock; int i; int type; int ret = 0, fcntl_lock_err = 0; LOG(log_debug, logtype_default, "ad_lock(%s, %s, off: %jd (%s), len: %jd): BEGIN", eid == ADEID_DFORK ? "data" : "reso", locktypetostr(locktype), (intmax_t)off, shmdstrfromoff(off), (intmax_t)len); if ((locktype & ADLOCK_FILELOCK) && (len != 1)) AFP_PANIC("lock API error"); type = locktype; if (eid == ADEID_DFORK) { adf = &ad->ad_data_fork; lock.l_start = off; } else { /* rfork */ if (type & ADLOCK_FILELOCK) { adf = &ad->ad_data_fork; lock.l_start = rf2off(off); } else { adf = ad->ad_rfp; lock.l_start = off + ad_getentryoff(ad, ADEID_RFORK); } } /* NOTE: we can't write lock a read-only file. on those, we just * make sure that we have a read lock set. that way, we at least prevent * someone else from really setting a deny read/write on the file. */ if (!(adf->adf_flags & O_RDWR) && (type & ADLOCK_WR)) { type = (type & ~ADLOCK_WR) | ADLOCK_RD; } lock.l_type = XLATE_FCNTL_LOCK(type & ADLOCK_MASK); lock.l_whence = SEEK_SET; lock.l_len = len; /* byte_lock(len=-1) lock whole file */ if (len == BYTELOCK_MAX) { lock.l_len -= lock.l_start; /* otherwise EOVERFLOW error */ } /* see if it's locked by another fork. * NOTE: this guarantees that any existing locks must be at most * read locks. we use ADLOCK_WR/RD because F_RD/WRLCK aren't * guaranteed to be ORable. */ if (adf_findxlock(adf, fork, ADLOCK_WR | ((type & ADLOCK_WR) ? ADLOCK_RD : 0), lock.l_start, lock.l_len) > -1) { errno = EACCES; ret = -1; goto exit; } /* look for any existing lock that we may have */ i = adf_findlock(adf, fork, ADLOCK_RD | ADLOCK_WR, lock.l_start, lock.l_len); adflock = (i < 0) ? NULL : adf->adf_lock + i; /* here's what we check for: 1) we're trying to re-lock a lock, but we didn't specify an update. 2) we're trying to free only part of a lock. 3) we're trying to free a non-existent lock. */ if ( (!adflock && (lock.l_type == F_UNLCK)) || (adflock && !(type & ADLOCK_UPGRADE) && ((lock.l_type != F_UNLCK) || (adflock->lock.l_start != lock.l_start) || (adflock->lock.l_len != lock.l_len) )) ) { errno = EINVAL; ret = -1; goto exit; } /* now, update our list of locks */ /* clear the lock */ if (lock.l_type == F_UNLCK) { adf_freelock(adf, i); goto exit; } /* attempt to lock the file. */ if (set_lock(adf->adf_fd, F_SETLK, &lock) < 0) { ret = -1; goto exit; } /* we upgraded this lock. */ if (adflock && (type & ADLOCK_UPGRADE)) { memcpy(&adflock->lock, &lock, sizeof(lock)); goto exit; } /* it wasn't an upgrade */ oldlock = -1; if (lock.l_type == F_RDLCK) { oldlock = adf_findxlock(adf, fork, ADLOCK_RD, lock.l_start, lock.l_len); } /* no more space. this will also happen if lockmax == lockcount == 0 */ if (adf->adf_lockmax == adf->adf_lockcount) { adf_lock_t *tmp = (adf_lock_t *) realloc(adf->adf_lock, sizeof(adf_lock_t)* (adf->adf_lockmax + ARRAY_BLOCK_SIZE)); if (!tmp) { ret = fcntl_lock_err = -1; goto exit; } adf->adf_lock = tmp; adf->adf_lockmax += ARRAY_BLOCK_SIZE; } adflock = adf->adf_lock + adf->adf_lockcount; /* fill in fields */ memcpy(&adflock->lock, &lock, sizeof(lock)); adflock->user = fork; if (oldlock > -1) { adflock->refcount = (adf->adf_lock + oldlock)->refcount; } else if ((adflock->refcount = calloc(1, sizeof(int))) == NULL) { ret = fcntl_lock_err = 1; goto exit; } (*adflock->refcount)++; adf->adf_lockcount++; exit: if (ret != 0) { if (fcntl_lock_err != 0) { lock.l_type = F_UNLCK; set_lock(adf->adf_fd, F_SETLK, &lock); } } LOG(log_debug, logtype_default, "ad_lock: END: %d", ret); return ret; }