+NTSTATUS build_user_quota_buffer(SMB_NTQUOTA_LIST *qt_list,
+ uint32_t maxlen,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *outbuf,
+ SMB_NTQUOTA_LIST **end_ptr)
+{
+ uint32_t qt_len = 0;
+ uint8_t *entry;
+ uint32_t entry_len;
+ int sid_len;
+ SMB_NTQUOTA_LIST *qtl;
+ DATA_BLOB qbuf = data_blob_null;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+
+ if (qt_list == NULL) {
+ status = NT_STATUS_OK;
+ *outbuf = data_blob_null;
+ if (end_ptr) {
+ *end_ptr = NULL;
+ }
+ return NT_STATUS_OK;
+ }
+
+ for (qtl = qt_list; qtl != NULL; qtl = qtl->next) {
+
+ sid_len = ndr_size_dom_sid(&qtl->quotas->sid, 0);
+ if (47 + sid_len < 47) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ entry_len = 40 + sid_len;
+ entry_len = ((entry_len + 7) / 8) * 8;
+
+ if (qt_len + entry_len < qt_len) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ qt_len += entry_len;
+ }
+
+ if (maxlen > 0 && qt_len > maxlen) {
+ qt_len = maxlen;
+ }
+
+ qbuf = data_blob_talloc_zero(mem_ctx, qt_len);
+ if (qbuf.data == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ for (qt_len = 0, entry = qbuf.data; qt_list != NULL;
+ qt_list = qt_list->next, qt_len += entry_len, entry += entry_len) {
+
+ sid_len = ndr_size_dom_sid(&qt_list->quotas->sid, 0);
+ entry_len = 40 + sid_len;
+ entry_len = ((entry_len + 7) / 8) * 8;
+
+ if (qt_len + entry_len > qbuf.length) {
+ /* check for not-enough room even for a single
+ * entry
+ */
+ if (qt_len == 0) {
+ status = NT_STATUS_BUFFER_TOO_SMALL;
+ goto fail;
+ }
+
+ break;
+ }
+
+ /* nextoffset entry 4 bytes */
+ SIVAL(entry, 0, entry_len);
+
+ /* then the len of the SID 4 bytes */
+ SIVAL(entry, 4, sid_len);
+
+ /* NTTIME of last record change */
+ SBIG_UINT(entry, 8, (uint64_t)0);
+
+ /* the used disk space 8 bytes uint64_t */
+ SBIG_UINT(entry, 16, qt_list->quotas->usedspace);
+
+ /* the soft quotas 8 bytes uint64_t */
+ SBIG_UINT(entry, 24, qt_list->quotas->softlim);
+
+ /* the hard quotas 8 bytes uint64_t */
+ SBIG_UINT(entry, 32, qt_list->quotas->hardlim);
+
+ /* and now the SID */
+ sid_linearize((uint8_t *)(entry + 40), sid_len,
+ &qt_list->quotas->sid);
+ }
+
+ /* overwrite the offset of the last entry */
+ SIVAL(entry - entry_len, 0, 0);
+
+ /*potentially shrink the buffer if max was given
+ * and we haven't quite reached the max
+ */
+ qbuf.length = qt_len;
+ *outbuf = qbuf;
+ qbuf = data_blob_null;
+ status = NT_STATUS_OK;
+
+ if (end_ptr) {
+ *end_ptr = qt_list;
+ }
+
+fail:
+ data_blob_free(&qbuf);
+
+ return status;
+}
+