Coverage Report

Created: 2026-02-14 07:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source3/smbd/ntquotas.c
Line
Count
Source
1
/*
2
   Unix SMB/CIFS implementation.
3
   NT QUOTA support
4
   Copyright (C) Stefan (metze) Metzmacher  2003
5
6
   This program is free software; you can redistribute it and/or modify
7
   it under the terms of the GNU General Public License as published by
8
   the Free Software Foundation; either version 3 of the License, or
9
   (at your option) any later version.
10
11
   This program is distributed in the hope that it will be useful,
12
   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
   GNU General Public License for more details.
15
16
   You should have received a copy of the GNU General Public License
17
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
*/
19
20
#include "includes.h"
21
#include "smbd/smbd.h"
22
#include "../lib/util/util_pw.h"
23
#include "system/passwd.h"
24
#include "passdb/lookup_sid.h"
25
#include "source3/include/client.h"
26
#include "source3/libsmb/proto.h"
27
#include "libcli/security/dom_sid.h"
28
29
#undef DBGC_CLASS
30
0
#define DBGC_CLASS DBGC_QUOTA
31
32
static uint64_t limit_nt2unix(uint64_t in, uint64_t bsize)
33
0
{
34
0
  uint64_t ret = (uint64_t)0;
35
36
0
  ret =   (uint64_t)(in/bsize);
37
0
  if (in>0 && ret==0) {
38
    /* we have to make sure that a overflow didn't set NO_LIMIT */
39
0
    ret = (uint64_t)1;
40
0
  }
41
42
0
  if (in == SMB_NTQUOTAS_NO_LIMIT)
43
0
    ret = SMB_QUOTAS_NO_LIMIT;
44
0
  else if (in == SMB_NTQUOTAS_NO_SPACE)
45
0
    ret = SMB_QUOTAS_NO_SPACE;
46
0
  else if (in == SMB_NTQUOTAS_NO_ENTRY)
47
0
    ret = SMB_QUOTAS_NO_LIMIT;
48
49
0
  return ret;
50
0
}
51
52
static uint64_t limit_unix2nt(uint64_t in, uint64_t bsize)
53
0
{
54
0
  uint64_t ret = (uint64_t)0;
55
56
0
  ret = (uint64_t)(in*bsize);
57
58
0
  return ret;
59
0
}
60
61
NTSTATUS vfs_get_ntquota(files_struct *fsp, enum SMB_QUOTA_TYPE qtype,
62
       struct dom_sid *psid, SMB_NTQUOTA_STRUCT *qt)
63
0
{
64
0
  int ret;
65
0
  SMB_DISK_QUOTA D;
66
0
  unid_t id;
67
0
  struct smb_filename *smb_fname_cwd = NULL;
68
0
  int saved_errno = 0;
69
70
0
  ZERO_STRUCT(D);
71
72
0
  if (!fsp || !fsp->conn || !qt) {
73
0
    return NT_STATUS_INTERNAL_ERROR;
74
0
  }
75
76
0
  ZERO_STRUCT(*qt);
77
78
0
  id.uid = -1;
79
80
0
  if (psid && !sid_to_uid(psid, &id.uid)) {
81
0
    struct dom_sid_buf buf;
82
0
    DEBUG(0,("sid_to_uid: failed, SID[%s]\n",
83
0
       dom_sid_str_buf(psid, &buf)));
84
0
    return NT_STATUS_NO_SUCH_USER;
85
0
  }
86
87
0
  smb_fname_cwd = cp_smb_basename(talloc_tos(), ".");
88
0
  if (smb_fname_cwd == NULL) {
89
0
    return NT_STATUS_NO_MEMORY;
90
0
  }
91
92
0
  ret = SMB_VFS_GET_QUOTA(fsp->conn, smb_fname_cwd, qtype, id, &D);
93
0
  if (ret == -1) {
94
0
    saved_errno = errno;
95
0
  }
96
0
  TALLOC_FREE(smb_fname_cwd);
97
0
  if (saved_errno != 0) {
98
0
    errno = saved_errno;
99
0
  }
100
101
0
  if (psid)
102
0
    qt->sid    = *psid;
103
104
0
  if (ret!=0) {
105
0
    return map_nt_error_from_unix(errno);
106
0
  }
107
108
0
  qt->usedspace = (uint64_t)D.curblocks*D.bsize;
109
0
  qt->softlim = limit_unix2nt(D.softlimit, D.bsize);
110
0
  qt->hardlim = limit_unix2nt(D.hardlimit, D.bsize);
111
0
  qt->qflags = D.qflags;
112
113
0
  return NT_STATUS_OK;
114
0
}
115
116
int vfs_set_ntquota(files_struct *fsp, enum SMB_QUOTA_TYPE qtype, struct dom_sid *psid, SMB_NTQUOTA_STRUCT *qt)
117
0
{
118
0
  int ret;
119
0
  SMB_DISK_QUOTA D;
120
0
  unid_t id;
121
0
  ZERO_STRUCT(D);
122
123
0
  if (!fsp||!fsp->conn||!qt)
124
0
    return (-1);
125
126
0
  id.uid = -1;
127
128
0
  D.bsize     = (uint64_t)QUOTABLOCK_SIZE;
129
130
0
  D.softlimit = limit_nt2unix(qt->softlim,D.bsize);
131
0
  D.hardlimit = limit_nt2unix(qt->hardlim,D.bsize);
132
0
  D.qflags     = qt->qflags;
133
134
0
  if (psid && !sid_to_uid(psid, &id.uid)) {
135
0
    struct dom_sid_buf buf;
136
0
    DEBUG(0,("sid_to_uid: failed, SID[%s]\n",
137
0
       dom_sid_str_buf(psid, &buf)));
138
0
  }
139
140
0
  ret = SMB_VFS_SET_QUOTA(fsp->conn, qtype, id, &D);
141
142
0
  return ret;
143
0
}
144
145
static bool already_in_quota_list(SMB_NTQUOTA_LIST *qt_list, uid_t uid)
146
0
{
147
0
  SMB_NTQUOTA_LIST *tmp_list = NULL;
148
149
0
  if (!qt_list)
150
0
    return False;
151
152
0
  for (tmp_list=qt_list;tmp_list!=NULL;tmp_list=tmp_list->next) {
153
0
    if (tmp_list->uid == uid) {
154
0
      return True;
155
0
    }
156
0
  }
157
158
0
  return False;
159
0
}
160
161
int vfs_get_user_ntquota_list(files_struct *fsp, SMB_NTQUOTA_LIST **qt_list)
162
0
{
163
0
  struct passwd *usr;
164
0
  TALLOC_CTX *mem_ctx = NULL;
165
166
0
  if (!fsp||!fsp->conn||!qt_list)
167
0
    return (-1);
168
169
0
  *qt_list = NULL;
170
171
0
  if ((mem_ctx=talloc_init("SMB_USER_QUOTA_LIST"))==NULL) {
172
0
    DEBUG(0,("talloc_init() failed\n"));
173
0
    return (-1);
174
0
  }
175
176
0
  setpwent();
177
0
  while ((usr = getpwent()) != NULL) {
178
0
    SMB_NTQUOTA_STRUCT tmp_qt;
179
0
    SMB_NTQUOTA_LIST *tmp_list_ent;
180
0
    struct dom_sid  sid;
181
0
    struct dom_sid_buf buf;
182
0
    NTSTATUS status;
183
184
0
    ZERO_STRUCT(tmp_qt);
185
186
0
    if (already_in_quota_list((*qt_list),usr->pw_uid)) {
187
0
      DEBUG(5,("record for uid[%ld] already in the list\n",(long)usr->pw_uid));
188
0
      continue;
189
0
    }
190
191
0
    uid_to_sid(&sid, usr->pw_uid);
192
193
0
    status =
194
0
        vfs_get_ntquota(fsp, SMB_USER_QUOTA_TYPE, &sid, &tmp_qt);
195
0
    if (!NT_STATUS_IS_OK(status)) {
196
0
      DEBUG(5, ("failed getting quota for uid[%ld] - %s\n",
197
0
          (long)usr->pw_uid, nt_errstr(status)));
198
0
      continue;
199
0
    }
200
0
    if (tmp_qt.softlim == 0 && tmp_qt.hardlim == 0) {
201
0
      DEBUG(5,("no quota entry for sid[%s] path[%s]\n",
202
0
         dom_sid_str_buf(&sid, &buf),
203
0
         fsp->conn->connectpath));
204
0
      continue;
205
0
    }
206
207
0
    DEBUG(15,("quota entry for id[%s] path[%s]\n",
208
0
        dom_sid_str_buf(&sid, &buf),
209
0
        fsp->conn->connectpath));
210
211
0
    if ((tmp_list_ent=talloc_zero(mem_ctx,SMB_NTQUOTA_LIST))==NULL) {
212
0
      DEBUG(0,("TALLOC_ZERO() failed\n"));
213
0
      *qt_list = NULL;
214
0
      TALLOC_FREE(mem_ctx);
215
0
      return (-1);
216
0
    }
217
218
0
    if ((tmp_list_ent->quotas=talloc_zero(mem_ctx,SMB_NTQUOTA_STRUCT))==NULL) {
219
0
      DEBUG(0,("TALLOC_ZERO() failed\n"));
220
0
      *qt_list = NULL;
221
0
      TALLOC_FREE(mem_ctx);
222
0
      return (-1);
223
0
    }
224
225
0
    tmp_list_ent->uid = usr->pw_uid;
226
0
    memcpy(tmp_list_ent->quotas,&tmp_qt,sizeof(tmp_qt));
227
0
    tmp_list_ent->mem_ctx = mem_ctx;
228
229
0
    DLIST_ADD((*qt_list),tmp_list_ent);
230
231
0
  }
232
0
  endpwent();
233
234
0
  if (*qt_list == NULL) {
235
0
    TALLOC_FREE(mem_ctx);
236
0
  }
237
0
  return 0;
238
0
}
239
240
static int quota_handle_destructor(SMB_NTQUOTA_HANDLE *handle)
241
0
{
242
0
  free_ntquota_list(&handle->quota_list);
243
0
  return 0;
244
0
}
245
246
void *init_quota_handle(TALLOC_CTX *mem_ctx)
247
0
{
248
0
  SMB_NTQUOTA_HANDLE *qt_handle;
249
250
0
  if (!mem_ctx)
251
0
    return NULL;
252
253
0
  qt_handle = talloc_zero(mem_ctx,SMB_NTQUOTA_HANDLE);
254
0
  if (qt_handle==NULL) {
255
0
    DEBUG(0,("TALLOC_ZERO() failed\n"));
256
0
    return NULL;
257
0
  }
258
259
0
  talloc_set_destructor(qt_handle, quota_handle_destructor);
260
0
  return (void *)qt_handle;
261
0
}