main() { if (getuid() != 0) { #if (defined(AIX) && defined(USE_SETREUID)) /* setreuid is badly broken on AIX 4.1, we avoid it completely */ fprintf(stderr,"avoiding possibly broken setreuid\n"); exit(1); #endif /* if not running as root then at least check to see if we get ENOSYS - this handles Linux 2.0.x with glibc 2.1 */ fprintf(stderr,"not running as root: checking for ENOSYS\n"); exit(have_syscall()); } gain_root_privilege(); gain_root_group_privilege(); set_effective_gid(1); set_effective_uid(1); save_re_uid(); restore_re_uid(); gain_root_privilege(); gain_root_group_privilege(); become_user_permanently(1, 1); setuid(0); if (getuid() == 0) { fprintf(stderr,"uid not set permanently\n"); exit(1); } printf("OK\n"); exit(0); }
static void gain_root(void) { if (non_root_mode()) { return; } if (geteuid() != 0) { set_effective_uid(0); if (geteuid() != 0) { DEBUG(0, ("Warning: You appear to have a trapdoor " "uid system\n")); } } if (getegid() != 0) { set_effective_gid(0); if (getegid() != 0) { DEBUG(0, ("Warning: You appear to have a trapdoor " "gid system\n")); } } }
void restore_re_uid_fromroot(void) { #if defined(USE_SETRESUID) || defined(USE_LINUX_THREAD_CREDENTIALS) samba_setresuid(saved_ruid, saved_euid, -1); #elif USE_SETREUID samba_setreuid(saved_ruid, -1); samba_setreuid(-1,saved_euid); #elif USE_SETUIDX samba_setuidx(ID_REAL, saved_ruid); samba_setuidx(ID_EFFECTIVE, saved_euid); #else set_effective_uid(saved_euid); if (getuid() != saved_ruid) samba_setuid(saved_ruid); set_effective_uid(saved_euid); #endif assert_uid(saved_ruid, saved_euid); }
static void restore_re_uid_fromroot(void) { #if USE_SETRESUID setresuid(saved_ruid, saved_euid, -1); #elif USE_SETREUID setreuid(saved_ruid, -1); setreuid(-1,saved_euid); #elif USE_SETUIDX setuidx(ID_REAL, saved_ruid); setuidx(ID_EFFECTIVE, saved_euid); #else set_effective_uid(saved_euid); if (getuid() != saved_ruid) setuid(saved_ruid); set_effective_uid(saved_euid); #endif assert_uid(saved_ruid, saved_euid); }
static bool become_uid(uid_t uid) { /* Check for dodgy uid values */ if (uid == (uid_t)-1 || ((sizeof(uid_t) == 2) && (uid == (uid_t)65535))) { if (!become_uid_done) { DEBUG(1,("WARNING: using uid %d is a security risk\n", (int)uid)); become_uid_done = true; } } /* Set effective user id */ set_effective_uid(uid); DO_PROFILE_INC(uid_changes); return True; }
void restore_re_uid(void) { set_effective_uid(0); restore_re_uid_fromroot(); }
static void krb5_ticket_gain_handler(struct tevent_context *event_ctx, struct tevent_timer *te, struct timeval now, void *private_data) { struct WINBINDD_CCACHE_ENTRY *entry = talloc_get_type_abort(private_data, struct WINBINDD_CCACHE_ENTRY); #ifdef HAVE_KRB5 int ret; struct timeval t; struct WINBINDD_MEMORY_CREDS *cred_ptr = entry->cred_ptr; struct winbindd_domain *domain = NULL; #endif DEBUG(10,("krb5_ticket_gain_handler called\n")); DEBUGADD(10,("event called for: %s, %s\n", entry->ccname, entry->username)); TALLOC_FREE(entry->event); #ifdef HAVE_KRB5 if (!cred_ptr || !cred_ptr->pass) { DEBUG(10,("krb5_ticket_gain_handler: no memory creds\n")); return; } if ((domain = find_domain_from_name(entry->realm)) == NULL) { DEBUG(0,("krb5_ticket_gain_handler: unknown domain\n")); return; } if (!domain->online) { goto retry_later; } set_effective_uid(entry->uid); ret = kerberos_kinit_password_ext(entry->principal_name, cred_ptr->pass, 0, /* hm, can we do time correction here ? */ &entry->refresh_time, &entry->renew_until, entry->ccname, False, /* no PAC required anymore */ True, WINBINDD_PAM_AUTH_KRB5_RENEW_TIME, NULL); gain_root_privilege(); if (ret) { DEBUG(3,("krb5_ticket_gain_handler: " "could not kinit: %s\n", error_message(ret))); /* evil. If we cannot do it, destroy any the __maybe__ * __existing__ ticket */ ads_kdestroy(entry->ccname); goto retry_later; } DEBUG(10,("krb5_ticket_gain_handler: " "successful kinit for: %s in ccache: %s\n", entry->principal_name, entry->ccname)); goto got_ticket; retry_later: #if defined(DEBUG_KRB5_TKT_RENEWAL) t = timeval_set(time(NULL) + 30, 0); #else t = timeval_current_ofs(MAX(30, lp_winbind_cache_time()), 0); #endif add_krb5_ticket_gain_handler_event(entry, t); return; got_ticket: #if defined(DEBUG_KRB5_TKT_RENEWAL) t = timeval_set(time(NULL) + 30, 0); #else t = timeval_set(krb5_event_refresh_time(entry->refresh_time), 0); #endif if (entry->refresh_time == 0) { entry->refresh_time = t.tv_sec; } entry->event = tevent_add_timer(winbind_event_context(), entry, t, krb5_ticket_refresh_handler, entry); return; #endif }
static void krb5_ticket_refresh_handler(struct tevent_context *event_ctx, struct tevent_timer *te, struct timeval now, void *private_data) { struct WINBINDD_CCACHE_ENTRY *entry = talloc_get_type_abort(private_data, struct WINBINDD_CCACHE_ENTRY); #ifdef HAVE_KRB5 int ret; time_t new_start; time_t expire_time = 0; struct WINBINDD_MEMORY_CREDS *cred_ptr = entry->cred_ptr; #endif DEBUG(10,("krb5_ticket_refresh_handler called\n")); DEBUGADD(10,("event called for: %s, %s\n", entry->ccname, entry->username)); TALLOC_FREE(entry->event); #ifdef HAVE_KRB5 /* Kinit again if we have the user password and we can't renew the old * tgt anymore * NB * This happens when machine are put to sleep for a very long time. */ if (entry->renew_until < time(NULL)) { rekinit: if (cred_ptr && cred_ptr->pass) { set_effective_uid(entry->uid); ret = kerberos_kinit_password_ext(entry->principal_name, cred_ptr->pass, 0, /* hm, can we do time correction here ? */ &entry->refresh_time, &entry->renew_until, entry->ccname, False, /* no PAC required anymore */ True, WINBINDD_PAM_AUTH_KRB5_RENEW_TIME, NULL); gain_root_privilege(); if (ret) { DEBUG(3,("krb5_ticket_refresh_handler: " "could not re-kinit: %s\n", error_message(ret))); /* destroy the ticket because we cannot rekinit * it, ignore error here */ ads_kdestroy(entry->ccname); /* Don't break the ticket refresh chain: retry * refreshing ticket sometime later when KDC is * unreachable -- BoYang. More error code handling * here? * */ if ((ret == KRB5_KDC_UNREACH) || (ret == KRB5_REALM_CANT_RESOLVE)) { #if defined(DEBUG_KRB5_TKT_RENEWAL) new_start = time(NULL) + 30; #else new_start = time(NULL) + MAX(30, lp_winbind_cache_time()); #endif add_krb5_ticket_gain_handler_event(entry, timeval_set(new_start, 0)); return; } TALLOC_FREE(entry->event); return; } DEBUG(10,("krb5_ticket_refresh_handler: successful re-kinit " "for: %s in ccache: %s\n", entry->principal_name, entry->ccname)); #if defined(DEBUG_KRB5_TKT_RENEWAL) new_start = time(NULL) + 30; #else /* The tkt should be refreshed at one-half the period from now to the expiration time */ expire_time = entry->refresh_time; new_start = krb5_event_refresh_time(entry->refresh_time); #endif goto done; } else { /* can this happen? * No cached credentials * destroy ticket and refresh chain * */ ads_kdestroy(entry->ccname); TALLOC_FREE(entry->event); return; } } set_effective_uid(entry->uid); ret = smb_krb5_renew_ticket(entry->ccname, entry->principal_name, entry->service, &new_start); #if defined(DEBUG_KRB5_TKT_RENEWAL) new_start = time(NULL) + 30; #else expire_time = new_start; new_start = krb5_event_refresh_time(new_start); #endif gain_root_privilege(); if (ret) { DEBUG(3,("krb5_ticket_refresh_handler: " "could not renew tickets: %s\n", error_message(ret))); /* maybe we are beyond the renewing window */ /* evil rises here, we refresh ticket failed, * but the ticket might be expired. Therefore, * When we refresh ticket failed, destory the * ticket */ ads_kdestroy(entry->ccname); /* avoid breaking the renewal chain: retry in * lp_winbind_cache_time() seconds when the KDC was not * available right now. * the return code can be KRB5_REALM_CANT_RESOLVE. * More error code handling here? */ if ((ret == KRB5_KDC_UNREACH) || (ret == KRB5_REALM_CANT_RESOLVE)) { #if defined(DEBUG_KRB5_TKT_RENEWAL) new_start = time(NULL) + 30; #else new_start = time(NULL) + MAX(30, lp_winbind_cache_time()); #endif /* ticket is destroyed here, we have to regain it * if it is possible */ add_krb5_ticket_gain_handler_event(entry, timeval_set(new_start, 0)); return; } /* This is evil, if the ticket was already expired. * renew ticket function returns KRB5KRB_AP_ERR_TKT_EXPIRED. * But there is still a chance that we can rekinit it. * * This happens when user login in online mode, and then network * down or something cause winbind goes offline for a very long time, * and then goes online again. ticket expired, renew failed. * This happens when machine are put to sleep for a long time, * but shorter than entry->renew_util. * NB * Looks like the KDC is reachable, we want to rekinit as soon as * possible instead of waiting some time later. */ if ((ret == KRB5KRB_AP_ERR_TKT_EXPIRED) || (ret == KRB5_FCC_NOFILE)) goto rekinit; return; } done: /* in cases that ticket will be unrenewable soon, we don't try to renew ticket * but try to regain ticket if it is possible */ if (entry->renew_until && expire_time && (entry->renew_until <= expire_time)) { /* try to regain ticket 10 seconds before expiration */ expire_time -= 10; add_krb5_ticket_gain_handler_event(entry, timeval_set(expire_time, 0)); return; } if (entry->refresh_time == 0) { entry->refresh_time = new_start; } entry->event = tevent_add_timer(winbind_event_context(), entry, timeval_set(new_start, 0), krb5_ticket_refresh_handler, entry); #endif }
void become_root_uid_only(void) { save_re_uid(); set_effective_uid(0); }
/******************************************************************* check on a DCE/DFS authentication ********************************************************************/ static BOOL dfs_auth(char *user, char *password) { error_status_t err; int err2; int prterr; signed32 expire_time, current_time; boolean32 password_reset; struct passwd *pw; sec_passwd_rec_t passwd_rec; sec_login_auth_src_t auth_src = sec_login_auth_src_network; unsigned char dce_errstr[dce_c_error_string_len]; gid_t egid; if (dcelogin_atmost_once) return (False); #ifdef HAVE_CRYPT /* * We only go for a DCE login context if the given password * matches that stored in the local password file.. * Assumes local passwd file is kept in sync w/ DCE RGY! */ if (strcmp((char *)crypt(password, this_salt), this_crypted)) { return (False); } #endif sec_login_get_current_context(&my_dce_sec_context, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr)); return (False); } sec_login_certify_identity(my_dce_sec_context, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE can't get current context. %s\n", dce_errstr)); return (False); } sec_login_get_expiration(my_dce_sec_context, &expire_time, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr)); return (False); } time(¤t_time); if (expire_time < (current_time + 60)) { struct passwd *pw; sec_passwd_rec_t *key; sec_login_get_pwent(my_dce_sec_context, (sec_login_passwd_t *) & pw, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr)); return (False); } sec_login_refresh_identity(my_dce_sec_context, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE can't refresh identity. %s\n", dce_errstr)); return (False); } sec_key_mgmt_get_key(rpc_c_authn_dce_secret, NULL, (unsigned char *)pw->pw_name, sec_c_key_version_none, (void **)&key, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE can't get key for %s. %s\n", pw->pw_name, dce_errstr)); return (False); } sec_login_valid_and_cert_ident(my_dce_sec_context, key, &password_reset, &auth_src, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE can't validate and certify identity for %s. %s\n", pw->pw_name, dce_errstr)); } sec_key_mgmt_free_key(key, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE can't free key.\n", dce_errstr)); } } if (sec_login_setup_identity((unsigned char *)user, sec_login_no_flags, &my_dce_sec_context, &err) == 0) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE Setup Identity for %s failed: %s\n", user, dce_errstr)); return (False); } sec_login_get_pwent(my_dce_sec_context, (sec_login_passwd_t *) & pw, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr)); return (False); } sec_login_purge_context(&my_dce_sec_context, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE can't purge context. %s\n", dce_errstr)); return (False); } /* * NB. I'd like to change these to call something like change_to_user() * instead but currently we don't have a connection * context to become the correct user. This is already * fairly platform specific code however, so I think * this should be ok. I have added code to go * back to being root on error though. JRA. */ egid = getegid(); set_effective_gid(pw->pw_gid); set_effective_uid(pw->pw_uid); if (sec_login_setup_identity((unsigned char *)user, sec_login_no_flags, &my_dce_sec_context, &err) == 0) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE Setup Identity for %s failed: %s\n", user, dce_errstr)); goto err; } sec_login_get_pwent(my_dce_sec_context, (sec_login_passwd_t *) & pw, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr)); goto err; } passwd_rec.version_number = sec_passwd_c_version_none; passwd_rec.pepper = NULL; passwd_rec.key.key_type = sec_passwd_plain; passwd_rec.key.tagged_union.plain = (idl_char *) password; sec_login_validate_identity(my_dce_sec_context, &passwd_rec, &password_reset, &auth_src, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE Identity Validation failed for principal %s: %s\n", user, dce_errstr)); goto err; } sec_login_certify_identity(my_dce_sec_context, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE certify identity failed: %s\n", dce_errstr)); goto err; } if (auth_src != sec_login_auth_src_network) { DEBUG(0, ("DCE context has no network credentials.\n")); } sec_login_set_context(my_dce_sec_context, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE login failed for principal %s, cant set context: %s\n", user, dce_errstr)); sec_login_purge_context(&my_dce_sec_context, &err); goto err; } sec_login_get_pwent(my_dce_sec_context, (sec_login_passwd_t *) & pw, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE can't get pwent. %s\n", dce_errstr)); goto err; } DEBUG(0, ("DCE login succeeded for principal %s on pid %d\n", user, sys_getpid())); DEBUG(3, ("DCE principal: %s\n" " uid: %d\n" " gid: %d\n", pw->pw_name, pw->pw_uid, pw->pw_gid)); DEBUG(3, (" info: %s\n" " dir: %s\n" " shell: %s\n", pw->pw_gecos, pw->pw_dir, pw->pw_shell)); sec_login_get_expiration(my_dce_sec_context, &expire_time, &err); if (err != error_status_ok) { dce_error_inq_text(err, dce_errstr, &err2); DEBUG(0, ("DCE can't get expiration. %s\n", dce_errstr)); goto err; } set_effective_uid(0); set_effective_gid(0); DEBUG(0, ("DCE context expires: %s", asctime(localtime(&expire_time)))); dcelogin_atmost_once = 1; return (True); err: /* Go back to root, JRA. */ set_effective_uid(0); set_effective_gid(egid); return (False); }
BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize) { int r; struct dqblk D; uid_t euser_id; #if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) char dev_disk[256]; SMB_STRUCT_STAT S; /* find the block device file */ #ifdef HPUX /* Need to set the cache flag to 1 for HPUX. Seems * to have a significant performance boost when * lstat calls on /dev access this function. */ if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 1)<0)) #else if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0)) return (False); #endif /* ifdef HPUX */ #endif /* !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) */ euser_id = geteuid(); #ifdef HPUX /* for HPUX, real uid must be same as euid to execute quotactl for euid */ save_re_uid(); if (set_re_uid() != 0) return False; r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D); restore_re_uid(); #else #if defined(__FreeBSD__) || defined(__OpenBSD__) { /* FreeBSD patches from Marty Moll <*****@*****.**> */ gid_t egrp_id; save_re_uid(); set_effective_uid(0); egrp_id = getegid(); r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D); /* As FreeBSD has group quotas, if getting the user quota fails, try getting the group instead. */ if (r) { r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D); } restore_re_uid(); } #elif defined(AIX) /* AIX has both USER and GROUP quotas: Get the USER quota ([email protected]) */ r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D); #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ */ r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D); #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ */ #endif /* HPUX */ /* Use softlimit to determine disk space, except when it has been exceeded */ #if defined(__FreeBSD__) || defined(__OpenBSD__) *bsize = DEV_BSIZE; #else /* !__FreeBSD__ && !__OpenBSD__ */ *bsize = 1024; #endif /*!__FreeBSD__ && !__OpenBSD__ */ if (r) { if (errno == EDQUOT) { *dfree =0; *dsize =D.dqb_curblocks; return (True); } else return(False); } /* If softlimit is zero, set it equal to hardlimit. */ if (D.dqb_bsoftlimit==0) D.dqb_bsoftlimit = D.dqb_bhardlimit; if (D.dqb_bsoftlimit==0) return(False); /* Use softlimit to determine disk space, except when it has been exceeded */ if ((D.dqb_curblocks>D.dqb_bsoftlimit) #if !defined(__FreeBSD__) && !defined(__OpenBSD__) ||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0)) #endif ) { *dfree = 0; *dsize = D.dqb_curblocks; } else { *dfree = D.dqb_bsoftlimit - D.dqb_curblocks; *dsize = D.dqb_bsoftlimit; } return (True); }
BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize) { uid_t euser_id; int r; struct dqblk D; struct fs_disk_quota F; SMB_STRUCT_STAT S; FILE *fp; struct mntent *mnt; SMB_DEV_T devno; int found; /* find the block device file */ if ( sys_stat(path, &S) == -1 ) { return(False) ; } devno = S.st_dev ; fp = setmntent(MOUNTED,"r"); found = False ; while ((mnt = getmntent(fp))) { if ( sys_stat(mnt->mnt_dir,&S) == -1 ) continue ; if (S.st_dev == devno) { found = True ; break ; } } endmntent(fp) ; if (!found) { return(False); } euser_id=geteuid(); save_re_uid(); set_effective_uid(0); /* Use softlimit to determine disk space, except when it has been exceeded */ *bsize = 512; if ( 0 == strcmp ( mnt->mnt_type, "efs" )) { r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D); restore_re_uid(); if (r==-1) return(False); /* Use softlimit to determine disk space, except when it has been exceeded */ if ( (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) || (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) || (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) || (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit) ) { *dfree = 0; *dsize = D.dqb_curblocks; } else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0) { return(False); } else { *dfree = D.dqb_bsoftlimit - D.dqb_curblocks; *dsize = D.dqb_bsoftlimit; } } else if ( 0 == strcmp ( mnt->mnt_type, "xfs" )) { r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F); restore_re_uid(); if (r==-1) return(False); /* Use softlimit to determine disk space, except when it has been exceeded */ if ( (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) || (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) || (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) || (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit) ) { *dfree = 0; *dsize = F.d_bcount; } else if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0) { return(False); } else { *dfree = (F.d_blk_softlimit - F.d_bcount); *dsize = F.d_blk_softlimit; } } else { restore_re_uid(); return(False); } return (True); }
BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize) { uid_t euser_id; int ret; struct dqblk D; #if defined(SUNOS5) struct quotctl command; int file; static struct mnttab mnt; static pstring name; pstring devopt; #else /* SunOS4 */ struct mntent *mnt; static pstring name; #endif FILE *fd; SMB_STRUCT_STAT sbuf; SMB_DEV_T devno ; static SMB_DEV_T devno_cached = 0 ; static int found ; euser_id = geteuid(); if ( sys_stat(path,&sbuf) == -1 ) return(False) ; devno = sbuf.st_dev ; DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n", path,(unsigned int)devno)); if ( devno != devno_cached ) { devno_cached = devno ; #if defined(SUNOS5) if ((fd = sys_fopen(MNTTAB, "r")) == NULL) return(False) ; found = False ; slprintf(devopt, sizeof(devopt) - 1, "dev=%x", (unsigned int)devno); while (getmntent(fd, &mnt) == 0) { if( !hasmntopt(&mnt, devopt) ) continue; DEBUG(5,("disk_quotas: testing \"%s\" %s\n", mnt.mnt_mountp,devopt)); /* quotas are only on vxfs, UFS or NFS */ if ( strcmp( mnt.mnt_fstype, MNTTYPE_UFS ) == 0 || strcmp( mnt.mnt_fstype, "nfs" ) == 0 || strcmp( mnt.mnt_fstype, "vxfs" ) == 0 ) { found = True ; break; } } pstrcpy(name,mnt.mnt_mountp) ; pstrcat(name,"/quotas") ; fclose(fd) ; #else /* SunOS4 */ if ((fd = setmntent(MOUNTED, "r")) == NULL) return(False) ; found = False ; while ((mnt = getmntent(fd)) != NULL) { if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 ) continue ; DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n", mnt->mnt_dir,(unsigned int)sbuf.st_dev)); if (sbuf.st_dev == devno) { found = True ; break; } } pstrcpy(name,mnt->mnt_fsname) ; endmntent(fd) ; #endif } if ( ! found ) return(False) ; save_re_uid(); set_effective_uid(0); #if defined(SUNOS5) if ( strcmp( mnt.mnt_fstype, "nfs" ) == 0) { BOOL retval; DEBUG(5,("disk_quotas: looking for mountpath (NFS) \"%s\"\n", mnt.mnt_special)); retval = nfs_quotas(mnt.mnt_special, euser_id, bsize, dfree, dsize); restore_re_uid(); return retval; } DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name)); if((file=sys_open(name, O_RDONLY,0))<0) { restore_re_uid(); return(False); } command.op = Q_GETQUOTA; command.uid = euser_id; command.addr = (caddr_t) &D; ret = ioctl(file, Q_QUOTACTL, &command); close(file); #else DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name)); ret = quotactl(Q_GETQUOTA, name, euser_id, &D); #endif restore_re_uid(); if (ret < 0) { DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n", strerror(errno) )); #if defined(SUNOS5) && defined(VXFS_QUOTA) /* If normal quotactl() fails, try vxfs private calls */ set_effective_uid(euser_id); DEBUG(5,("disk_quotas: mount type \"%s\"\n", mnt.mnt_fstype)); if ( 0 == strcmp ( mnt.mnt_fstype, "vxfs" )) { BOOL retval; retval = disk_quotas_vxfs(name, path, bsize, dfree, dsize); return(retval); } #else return(False); #endif } /* If softlimit is zero, set it equal to hardlimit. */ if (D.dqb_bsoftlimit==0) D.dqb_bsoftlimit = D.dqb_bhardlimit; /* Use softlimit to determine disk space. A user exceeding the quota is told * that there's no space left. Writes might actually work for a bit if the * hardlimit is set higher than softlimit. Effectively the disk becomes * made of rubber latex and begins to expand to accommodate the user :-) */ if (D.dqb_bsoftlimit==0) return(False); *bsize = DEV_BSIZE; *dsize = D.dqb_bsoftlimit; if (D.dqb_curblocks > D.dqb_bsoftlimit) { *dfree = 0; *dsize = D.dqb_curblocks; } else *dfree = D.dqb_bsoftlimit - D.dqb_curblocks; DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n", path,(double)*bsize,(double)*dfree,(double)*dsize)); return(True); }
BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize) { int r; SMB_STRUCT_STAT S; FILE *fp; LINUX_SMB_DISK_QUOTA D; struct mntent *mnt; SMB_DEV_T devno; int found; uid_t euser_id; euser_id = geteuid(); /* find the block device file */ if ( sys_stat(path, &S) == -1 ) return(False) ; devno = S.st_dev ; fp = setmntent(MOUNTED,"r"); found = False ; while ((mnt = getmntent(fp))) { if ( sys_stat(mnt->mnt_dir,&S) == -1 ) continue ; if (S.st_dev == devno) { found = True ; break; } } endmntent(fp) ; if (!found) return(False); save_re_uid(); set_effective_uid(0); if (strcmp(mnt->mnt_type, "xfs")) { r=get_smb_linux_gen_quota(mnt->mnt_fsname, euser_id, &D); if (r == -1) { r=get_smb_linux_v2_quota(mnt->mnt_fsname, euser_id, &D); if (r == -1) r=get_smb_linux_v1_quota(mnt->mnt_fsname, euser_id, &D); } } else { r=get_smb_linux_xfs_quota(mnt->mnt_fsname, euser_id, &D); } restore_re_uid(); /* Use softlimit to determine disk space, except when it has been exceeded */ *bsize = D.bsize; if (r == -1) { if (errno == EDQUOT) { *dfree =0; *dsize =D.curblocks; return (True); } else { return(False); } } /* Use softlimit to determine disk space, except when it has been exceeded */ if ( (D.softlimit && D.curblocks >= D.softlimit) || (D.hardlimit && D.curblocks >= D.hardlimit) || (D.isoftlimit && D.curinodes >= D.isoftlimit) || (D.ihardlimit && D.curinodes>=D.ihardlimit) ) { *dfree = 0; *dsize = D.curblocks; } else if (D.softlimit==0 && D.hardlimit==0) { return(False); } else { if (D.softlimit == 0) D.softlimit = D.hardlimit; *dfree = D.softlimit - D.curblocks; *dsize = D.softlimit; } return (True); }
BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize) { uid_t user_id, euser_id; int ret; struct vx_dqblk D; struct vx_quotctl quotabuf; struct vx_genioctl genbuf; pstring qfname; int file; /* * "name" may or may not include a trailing "/quotas". * Arranging consistency of calling here in "quotas.c" may not be easy and * it might be easier to examine and adjust it here. * Fortunately, VxFS seems not to mind at present. */ pstrcpy(qfname, name) ; /* pstrcat(qfname, "/quotas") ; */ /* possibly examine and adjust "name" */ euser_id = geteuid(); set_effective_uid(0); DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname)); if((file=sys_open(qfname, O_RDONLY,0))<0) { set_effective_uid(euser_id); return(False); } genbuf.ioc_cmd = VX_QUOTACTL; genbuf.ioc_up = (void *) "abuf; quotabuf.cmd = VX_GETQUOTA; quotabuf.uid = euser_id; quotabuf.addr = (caddr_t) &D; ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf); close(file); set_effective_uid(euser_id); if (ret < 0) { DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) )); return(False); } /* If softlimit is zero, set it equal to hardlimit. */ if (D.dqb_bsoftlimit==0) D.dqb_bsoftlimit = D.dqb_bhardlimit; /* Use softlimit to determine disk space. A user exceeding the quota is told * that there's no space left. Writes might actually work for a bit if the * hardlimit is set higher than softlimit. Effectively the disk becomes * made of rubber latex and begins to expand to accommodate the user :-) */ DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n", path, D.dqb_curblocks, D.dqb_bsoftlimit, D.dqb_bhardlimit, D.dqb_curfiles, D.dqb_fsoftlimit, D.dqb_fhardlimit)); if (D.dqb_bsoftlimit==0) return(False); *bsize = DEV_BSIZE; *dsize = D.dqb_bsoftlimit; if (D.dqb_curblocks > D.dqb_bsoftlimit) { *dfree = 0; *dsize = D.dqb_curblocks; } else *dfree = D.dqb_bsoftlimit - D.dqb_curblocks; DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n", path,(double)*bsize,(double)*dfree,(double)*dsize)); return(True); }