Coverage Report

Created: 2026-06-07 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
0
  NTSTATUS status;
70
71
0
  ZERO_STRUCT(D);
72
73
0
  if (!fsp || !fsp->conn || !qt) {
74
0
    return NT_STATUS_INTERNAL_ERROR;
75
0
  }
76
77
0
  ZERO_STRUCT(*qt);
78
79
0
  id.uid = -1;
80
81
0
  if (psid && !sid_to_uid(psid, &id.uid)) {
82
0
    struct dom_sid_buf buf;
83
0
    DEBUG(0,("sid_to_uid: failed, SID[%s]\n",
84
0
       dom_sid_str_buf(psid, &buf)));
85
0
    return NT_STATUS_NO_SUCH_USER;
86
0
  }
87
88
  /*
89
   * SMB_VFS_GET_QUOTA needs a "real" fsp, not a fake file one.
90
   */
91
0
  status = openat_pathref_fsp_dot(talloc_tos(),
92
0
          fsp->conn->cwd_fsp,
93
0
          0,
94
0
          &smb_fname_cwd);
95
0
  if (!NT_STATUS_IS_OK(status)) {
96
0
    return status;
97
0
  }
98
99
0
  ret = SMB_VFS_GET_QUOTA(smb_fname_cwd->fsp, qtype, id, &D);
100
0
  if (ret == -1) {
101
0
    saved_errno = errno;
102
0
  }
103
0
  TALLOC_FREE(smb_fname_cwd);
104
0
  if (saved_errno != 0) {
105
0
    errno = saved_errno;
106
0
  }
107
108
0
  if (psid)
109
0
    qt->sid    = *psid;
110
111
0
  if (ret!=0) {
112
0
    return map_nt_error_from_unix(errno);
113
0
  }
114
115
0
  qt->usedspace = (uint64_t)D.curblocks*D.bsize;
116
0
  qt->softlim = limit_unix2nt(D.softlimit, D.bsize);
117
0
  qt->hardlim = limit_unix2nt(D.hardlimit, D.bsize);
118
0
  qt->qflags = D.qflags;
119
120
0
  return NT_STATUS_OK;
121
0
}
122
123
int vfs_set_ntquota(files_struct *fsp, enum SMB_QUOTA_TYPE qtype, struct dom_sid *psid, SMB_NTQUOTA_STRUCT *qt)
124
0
{
125
0
  int ret;
126
0
  SMB_DISK_QUOTA D;
127
0
  unid_t id;
128
0
  ZERO_STRUCT(D);
129
130
0
  if (!fsp||!fsp->conn||!qt)
131
0
    return (-1);
132
133
0
  id.uid = -1;
134
135
0
  D.bsize     = (uint64_t)QUOTABLOCK_SIZE;
136
137
0
  D.softlimit = limit_nt2unix(qt->softlim,D.bsize);
138
0
  D.hardlimit = limit_nt2unix(qt->hardlim,D.bsize);
139
0
  D.qflags     = qt->qflags;
140
141
0
  if (psid && !sid_to_uid(psid, &id.uid)) {
142
0
    struct dom_sid_buf buf;
143
0
    DEBUG(0,("sid_to_uid: failed, SID[%s]\n",
144
0
       dom_sid_str_buf(psid, &buf)));
145
0
  }
146
147
0
  ret = SMB_VFS_SET_QUOTA(fsp, qtype, id, &D);
148
149
0
  return ret;
150
0
}
151
152
static bool already_in_quota_list(SMB_NTQUOTA_LIST *qt_list, uid_t uid)
153
0
{
154
0
  SMB_NTQUOTA_LIST *tmp_list = NULL;
155
156
0
  if (!qt_list)
157
0
    return False;
158
159
0
  for (tmp_list=qt_list;tmp_list!=NULL;tmp_list=tmp_list->next) {
160
0
    if (tmp_list->uid == uid) {
161
0
      return True;
162
0
    }
163
0
  }
164
165
0
  return False;
166
0
}
167
168
int vfs_get_user_ntquota_list(files_struct *fsp, SMB_NTQUOTA_LIST **qt_list)
169
0
{
170
0
  struct passwd *usr;
171
0
  TALLOC_CTX *mem_ctx = NULL;
172
173
0
  if (!fsp||!fsp->conn||!qt_list)
174
0
    return (-1);
175
176
0
  *qt_list = NULL;
177
178
0
  if ((mem_ctx=talloc_init("SMB_USER_QUOTA_LIST"))==NULL) {
179
0
    DEBUG(0,("talloc_init() failed\n"));
180
0
    return (-1);
181
0
  }
182
183
0
  setpwent();
184
0
  while ((usr = getpwent()) != NULL) {
185
0
    SMB_NTQUOTA_STRUCT tmp_qt;
186
0
    SMB_NTQUOTA_LIST *tmp_list_ent;
187
0
    struct dom_sid  sid;
188
0
    struct dom_sid_buf buf;
189
0
    NTSTATUS status;
190
191
0
    ZERO_STRUCT(tmp_qt);
192
193
0
    if (already_in_quota_list((*qt_list),usr->pw_uid)) {
194
0
      DEBUG(5,("record for uid[%ld] already in the list\n",(long)usr->pw_uid));
195
0
      continue;
196
0
    }
197
198
0
    uid_to_sid(&sid, usr->pw_uid);
199
200
0
    status =
201
0
        vfs_get_ntquota(fsp, SMB_USER_QUOTA_TYPE, &sid, &tmp_qt);
202
0
    if (!NT_STATUS_IS_OK(status)) {
203
0
      DEBUG(5, ("failed getting quota for uid[%ld] - %s\n",
204
0
          (long)usr->pw_uid, nt_errstr(status)));
205
0
      continue;
206
0
    }
207
0
    if (tmp_qt.softlim == 0 && tmp_qt.hardlim == 0) {
208
0
      DEBUG(5,("no quota entry for sid[%s] path[%s]\n",
209
0
         dom_sid_str_buf(&sid, &buf),
210
0
         fsp->conn->connectpath));
211
0
      continue;
212
0
    }
213
214
0
    DEBUG(15,("quota entry for id[%s] path[%s]\n",
215
0
        dom_sid_str_buf(&sid, &buf),
216
0
        fsp->conn->connectpath));
217
218
0
    if ((tmp_list_ent=talloc_zero(mem_ctx,SMB_NTQUOTA_LIST))==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
    if ((tmp_list_ent->quotas=talloc_zero(mem_ctx,SMB_NTQUOTA_STRUCT))==NULL) {
226
0
      DEBUG(0,("TALLOC_ZERO() failed\n"));
227
0
      *qt_list = NULL;
228
0
      TALLOC_FREE(mem_ctx);
229
0
      return (-1);
230
0
    }
231
232
0
    tmp_list_ent->uid = usr->pw_uid;
233
0
    memcpy(tmp_list_ent->quotas,&tmp_qt,sizeof(tmp_qt));
234
0
    tmp_list_ent->mem_ctx = mem_ctx;
235
236
0
    DLIST_ADD((*qt_list),tmp_list_ent);
237
238
0
  }
239
0
  endpwent();
240
241
0
  if (*qt_list == NULL) {
242
0
    TALLOC_FREE(mem_ctx);
243
0
  }
244
0
  return 0;
245
0
}
246
247
static int quota_handle_destructor(SMB_NTQUOTA_HANDLE *handle)
248
0
{
249
0
  free_ntquota_list(&handle->quota_list);
250
0
  return 0;
251
0
}
252
253
void *init_quota_handle(TALLOC_CTX *mem_ctx)
254
0
{
255
0
  SMB_NTQUOTA_HANDLE *qt_handle;
256
257
0
  if (!mem_ctx)
258
0
    return NULL;
259
260
0
  qt_handle = talloc_zero(mem_ctx,SMB_NTQUOTA_HANDLE);
261
0
  if (qt_handle==NULL) {
262
0
    DEBUG(0,("TALLOC_ZERO() failed\n"));
263
0
    return NULL;
264
0
  }
265
266
0
  talloc_set_destructor(qt_handle, quota_handle_destructor);
267
0
  return (void *)qt_handle;
268
0
}