smbd: Implement FSCTL_DELETE_REPARSE_POINT
[samba.git] / nsswitch / libwbclient / wbc_idmap.c
index 6735d3d3e9ee652570394a6ab36a82562ea58a0a..c3accedc248dfbbc741ee90569b978dd30bdb3c5 100644 (file)
 #include "replace.h"
 #include "libwbclient.h"
 #include "../winbind_client.h"
+#include "lib/util/smb_strtox.h"
 
 /* Convert a Windows SID to a Unix uid, allocating an uid if needed */
+_PUBLIC_
 wbcErr wbcCtxSidToUid(struct wbcContext *ctx, const struct wbcDomainSid *sid,
                      uid_t *puid)
 {
@@ -53,12 +55,14 @@ wbcErr wbcCtxSidToUid(struct wbcContext *ctx, const struct wbcDomainSid *sid,
        return wbc_status;
 }
 
+_PUBLIC_
 wbcErr wbcSidToUid(const struct wbcDomainSid *sid, uid_t *puid)
 {
        return wbcCtxSidToUid(NULL, sid, puid);
 }
 
 /* Convert a Windows SID to a Unix uid if there already is a mapping */
+_PUBLIC_
 wbcErr wbcQuerySidToUid(const struct wbcDomainSid *sid,
                        uid_t *puid)
 {
@@ -66,45 +70,45 @@ wbcErr wbcQuerySidToUid(const struct wbcDomainSid *sid,
 }
 
 /* Convert a Unix uid to a Windows SID, allocating a SID if needed */
+_PUBLIC_
 wbcErr wbcCtxUidToSid(struct wbcContext *ctx, uid_t uid,
-                     struct wbcDomainSid *sid)
+                     struct wbcDomainSid *psid)
 {
-       wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
-       struct winbindd_request request;
-       struct winbindd_response response;
+       struct wbcUnixId xid;
+       struct wbcDomainSid sid;
+       struct wbcDomainSid null_sid = { 0 };
+       wbcErr wbc_status;
 
-       if (!sid) {
+       if (!psid) {
                wbc_status = WBC_ERR_INVALID_PARAM;
                BAIL_ON_WBC_ERROR(wbc_status);
        }
 
-       /* Initialize request */
-
-       ZERO_STRUCT(request);
-       ZERO_STRUCT(response);
-
-       request.data.uid = uid;
+       xid = (struct wbcUnixId) { .type = WBC_ID_TYPE_UID, .id.uid = uid };
 
-       /* Make request */
-
-       wbc_status = wbcRequestResponse(ctx, WINBINDD_UID_TO_SID,
-                                       &request,
-                                       &response);
-       BAIL_ON_WBC_ERROR(wbc_status);
+       wbc_status = wbcCtxUnixIdsToSids(ctx, &xid, 1, &sid);
+       if (!WBC_ERROR_IS_OK(wbc_status)) {
+               goto done;
+       }
 
-       wbc_status = wbcStringToSid(response.data.sid.sid, sid);
-       BAIL_ON_WBC_ERROR(wbc_status);
+       if (memcmp(&sid, &null_sid, sizeof(sid)) != 0) {
+               *psid = sid;
+       } else {
+               wbc_status = WBC_ERR_DOMAIN_NOT_FOUND;
+       }
 
 done:
        return wbc_status;
 }
 
+_PUBLIC_
 wbcErr wbcUidToSid(uid_t uid, struct wbcDomainSid *sid)
 {
        return wbcCtxUidToSid(NULL, uid, sid);
 }
 
 /* Convert a Unix uid to a Windows SID if there already is a mapping */
+_PUBLIC_
 wbcErr wbcQueryUidToSid(uid_t uid,
                        struct wbcDomainSid *sid)
 {
@@ -120,40 +124,35 @@ wbcErr wbcQueryUidToSid(uid_t uid,
  *
  **/
 
+_PUBLIC_
 wbcErr wbcCtxSidToGid(struct wbcContext *ctx, const struct wbcDomainSid *sid,
                      gid_t *pgid)
 {
-       struct winbindd_request request;
-       struct winbindd_response response;
-       wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+       struct wbcUnixId xid;
+       wbcErr wbc_status;
 
        if (!sid || !pgid) {
                wbc_status = WBC_ERR_INVALID_PARAM;
                BAIL_ON_WBC_ERROR(wbc_status);
        }
 
-       /* Initialize request */
-
-       ZERO_STRUCT(request);
-       ZERO_STRUCT(response);
-
-        wbcSidToStringBuf(sid, request.data.sid, sizeof(request.data.sid));
-
-       /* Make request */
-
-       wbc_status = wbcRequestResponse(ctx, WINBINDD_SID_TO_GID,
-                                       &request,
-                                       &response);
-       BAIL_ON_WBC_ERROR(wbc_status);
-
-       *pgid = response.data.gid;
+       wbc_status = wbcCtxSidsToUnixIds(ctx, sid, 1, &xid);
+       if (!WBC_ERROR_IS_OK(wbc_status)) {
+               goto done;
+       }
 
-       wbc_status = WBC_ERR_SUCCESS;
+       if ((xid.type == WBC_ID_TYPE_GID) || (xid.type == WBC_ID_TYPE_BOTH)) {
+               *pgid = xid.id.gid;
+               wbc_status = WBC_ERR_SUCCESS;
+       } else {
+               wbc_status = WBC_ERR_DOMAIN_NOT_FOUND;
+       }
 
  done:
        return wbc_status;
 }
 
+_PUBLIC_
 wbcErr wbcSidToGid(const struct wbcDomainSid *sid, gid_t *pgid)
 {
        return wbcCtxSidToGid(NULL, sid, pgid);
@@ -161,6 +160,7 @@ wbcErr wbcSidToGid(const struct wbcDomainSid *sid, gid_t *pgid)
 
 /* Convert a Windows SID to a Unix gid if there already is a mapping */
 
+_PUBLIC_
 wbcErr wbcQuerySidToGid(const struct wbcDomainSid *sid,
                        gid_t *pgid)
 {
@@ -169,45 +169,45 @@ wbcErr wbcQuerySidToGid(const struct wbcDomainSid *sid,
 
 
 /* Convert a Unix gid to a Windows SID, allocating a SID if needed */
+_PUBLIC_
 wbcErr wbcCtxGidToSid(struct wbcContext *ctx, gid_t gid,
-                     struct wbcDomainSid *sid)
+                     struct wbcDomainSid *psid)
 {
-       struct winbindd_request request;
-       struct winbindd_response response;
-       wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+       struct wbcUnixId xid;
+       struct wbcDomainSid sid;
+       struct wbcDomainSid null_sid = { 0 };
+       wbcErr wbc_status;
 
-       if (!sid) {
+       if (!psid) {
                wbc_status = WBC_ERR_INVALID_PARAM;
                BAIL_ON_WBC_ERROR(wbc_status);
        }
 
-       /* Initialize request */
+       xid = (struct wbcUnixId) { .type = WBC_ID_TYPE_GID, .id.gid = gid };
 
-       ZERO_STRUCT(request);
-       ZERO_STRUCT(response);
-
-       request.data.gid = gid;
-
-       /* Make request */
-
-       wbc_status = wbcRequestResponse(ctx, WINBINDD_GID_TO_SID,
-                                       &request,
-                                       &response);
-       BAIL_ON_WBC_ERROR(wbc_status);
+       wbc_status = wbcCtxUnixIdsToSids(ctx, &xid, 1, &sid);
+       if (!WBC_ERROR_IS_OK(wbc_status)) {
+               goto done;
+       }
 
-       wbc_status = wbcStringToSid(response.data.sid.sid, sid);
-       BAIL_ON_WBC_ERROR(wbc_status);
+       if (memcmp(&sid, &null_sid, sizeof(sid)) != 0) {
+               *psid = sid;
+       } else {
+               wbc_status = WBC_ERR_DOMAIN_NOT_FOUND;
+       }
 
 done:
        return wbc_status;
 }
 
+_PUBLIC_
 wbcErr wbcGidToSid(gid_t gid, struct wbcDomainSid *sid)
 {
        return wbcCtxGidToSid(NULL, gid, sid);
 }
 
 /* Convert a Unix gid to a Windows SID if there already is a mapping */
+_PUBLIC_
 wbcErr wbcQueryGidToSid(gid_t gid,
                        struct wbcDomainSid *sid)
 {
@@ -215,6 +215,7 @@ wbcErr wbcQueryGidToSid(gid_t gid,
 }
 
 /* Obtain a new uid from Winbind */
+_PUBLIC_
 wbcErr wbcCtxAllocateUid(struct wbcContext *ctx, uid_t *puid)
 {
        struct winbindd_request request;
@@ -244,12 +245,14 @@ wbcErr wbcCtxAllocateUid(struct wbcContext *ctx, uid_t *puid)
        return wbc_status;
 }
 
+_PUBLIC_
 wbcErr wbcAllocateUid(uid_t *puid)
 {
        return wbcCtxAllocateUid(NULL, puid);
 }
 
 /* Obtain a new gid from Winbind */
+_PUBLIC_
 wbcErr wbcCtxAllocateGid(struct wbcContext *ctx, gid_t *pgid)
 {
        struct winbindd_request request;
@@ -279,6 +282,7 @@ wbcErr wbcCtxAllocateGid(struct wbcContext *ctx, gid_t *pgid)
        return wbc_status;
 }
 
+_PUBLIC_
 wbcErr wbcAllocateGid(gid_t *pgid)
 {
        return wbcCtxAllocateGid(NULL, pgid);
@@ -289,42 +293,49 @@ wbcErr wbcAllocateGid(gid_t *pgid)
 #define _ID_TYPE_GID 2
 
 /* Set an user id mapping - not implemented any more */
+_PUBLIC_
 wbcErr wbcSetUidMapping(uid_t uid, const struct wbcDomainSid *sid)
 {
        return WBC_ERR_NOT_IMPLEMENTED;
 }
 
 /* Set a group id mapping - not implemented any more */
+_PUBLIC_
 wbcErr wbcSetGidMapping(gid_t gid, const struct wbcDomainSid *sid)
 {
        return WBC_ERR_NOT_IMPLEMENTED;
 }
 
 /* Remove a user id mapping - not implemented any more */
+_PUBLIC_
 wbcErr wbcRemoveUidMapping(uid_t uid, const struct wbcDomainSid *sid)
 {
        return WBC_ERR_NOT_IMPLEMENTED;
 }
 
 /* Remove a group id mapping - not implemented any more */
+_PUBLIC_
 wbcErr wbcRemoveGidMapping(gid_t gid, const struct wbcDomainSid *sid)
 {
        return WBC_ERR_NOT_IMPLEMENTED;
 }
 
 /* Set the highwater mark for allocated uids - not implemented any more */
+_PUBLIC_
 wbcErr wbcSetUidHwm(uid_t uid_hwm)
 {
        return WBC_ERR_NOT_IMPLEMENTED;
 }
 
 /* Set the highwater mark for allocated gids - not implemented any more */
+_PUBLIC_
 wbcErr wbcSetGidHwm(gid_t gid_hwm)
 {
        return WBC_ERR_NOT_IMPLEMENTED;
 }
 
 /* Convert a list of SIDs */
+_PUBLIC_
 wbcErr wbcCtxSidsToUnixIds(struct wbcContext *ctx,
                           const struct wbcDomainSid *sids,
                           uint32_t num_sids, struct wbcUnixId *ids)
@@ -387,26 +398,39 @@ wbcErr wbcCtxSidsToUnixIds(struct wbcContext *ctx,
        for (i=0; i<num_sids; i++) {
                struct wbcUnixId *id = &ids[i];
                char *q;
+               int error = 0;
 
                switch (p[0]) {
                case 'U':
                        id->type = WBC_ID_TYPE_UID;
-                       id->id.uid = strtoul(p+1, &q, 10);
+                       id->id.uid = smb_strtoul(p+1,
+                                                &q,
+                                                10,
+                                                &error,
+                                                SMB_STR_STANDARD);
                        break;
                case 'G':
                        id->type = WBC_ID_TYPE_GID;
-                       id->id.gid = strtoul(p+1, &q, 10);
+                       id->id.gid = smb_strtoul(p+1,
+                                                &q,
+                                                10,
+                                                &error,
+                                                SMB_STR_STANDARD);
                        break;
                case 'B':
                        id->type = WBC_ID_TYPE_BOTH;
-                       id->id.uid = strtoul(p+1, &q, 10);
+                       id->id.uid = smb_strtoul(p+1,
+                                                &q,
+                                                10,
+                                                &error,
+                                                SMB_STR_STANDARD);
                        break;
                default:
                        id->type = WBC_ID_TYPE_NOT_SPECIFIED;
                        q = strchr(p, '\n');
                        break;
                };
-               if (q == NULL || q[0] != '\n') {
+               if (q == NULL || q[0] != '\n' || error != 0) {
                        goto wbc_err_invalid;
                }
                p = q+1;
@@ -421,12 +445,14 @@ done:
        return wbc_status;
 }
 
+_PUBLIC_
 wbcErr wbcSidsToUnixIds(const struct wbcDomainSid *sids, uint32_t num_sids,
                        struct wbcUnixId *ids)
 {
        return wbcCtxSidsToUnixIds(NULL, sids, num_sids, ids);
 }
 
+_PUBLIC_
 wbcErr wbcCtxUnixIdsToSids(struct wbcContext *ctx,
                           const struct wbcUnixId *ids, uint32_t num_ids,
                           struct wbcDomainSid *sids)
@@ -436,10 +462,20 @@ wbcErr wbcCtxUnixIdsToSids(struct wbcContext *ctx,
        wbcErr wbc_status;
        char *buf;
        char *s;
+       const size_t sidlen = (1 /* U/G */ + 10 /* 2^32 */ + 1 /* \n */);
        size_t ofs, buflen;
        uint32_t i;
 
-       buflen = num_ids * (1 /* U/G */ + 10 /* 2^32 */ + 1 /* \n */) + 1;
+       if (num_ids > SIZE_MAX / sidlen) {
+               return WBC_ERR_NO_MEMORY; /* overflow */
+       }
+       buflen = num_ids * sidlen;
+
+       buflen += 1;            /* trailing \0 */
+       if (buflen < 1) {
+               return WBC_ERR_NO_MEMORY; /* overflow */
+       }
+
        buf = malloc(buflen);
        if (buf == NULL) {
                return WBC_ERR_NO_MEMORY;
@@ -506,6 +542,7 @@ fail:
        return wbc_status;
 }
 
+_PUBLIC_
 wbcErr wbcUnixIdsToSids(const struct wbcUnixId *ids, uint32_t num_ids,
                        struct wbcDomainSid *sids)
 {