r23784: use the GPLv3 boilerplate as recommended by the FSF and the license text
[tprouty/samba.git] / source / libsmb / libsmbclient.c
index c74e18b13c152c91d70b7a29538e558748771006..90cde9100af4d33ca01ba7ea26bdcb53ee3a8e22 100644 (file)
@@ -9,7 +9,7 @@
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
 
 #include "include/libsmb_internal.h"
 
+struct smbc_dirent *smbc_readdir_ctx(SMBCCTX *context, SMBCFILE *dir);
+struct smbc_dir_list *smbc_check_dir_ent(struct smbc_dir_list *list, 
+                                        struct smbc_dirent *dirent);
 
 /*
  * DOS Attribute values (used internally)
@@ -336,14 +338,15 @@ smbc_parse_path(SMBCCTX *context,
            goto decoding;
 
        if (*p == '/') {
+               int wl = strlen(context->workgroup);
 
-               strncpy(server, context->workgroup, 
-                       ((strlen(context->workgroup) < 16)
-                         ? strlen(context->workgroup)
-                         : 16));
-                server[server_len - 1] = '\0';
+               if (wl > 16) {
+                       wl = 16;
+               }
+
+               strncpy(server, context->workgroup, wl);
+                server[wl] = '\0';
                return 0;
-               
        }
 
        /*
@@ -414,7 +417,15 @@ smbc_parse_path(SMBCCTX *context,
 
        }
 
-        safe_strcpy(path, p, path_len - 1);
+        /*
+         * Prepend a leading slash if there's a file path, as required by
+         * NetApp filers.
+         */
+        *path = '\0';
+        if (*p != '\0') {
+                *path = '/';
+                safe_strcpy(path + 1, p, path_len - 2);
+        }
 
        all_string_sub(path, "/", "\\", 0);
 
@@ -488,8 +499,30 @@ static int
 smbc_check_server(SMBCCTX * context,
                   SMBCSRV * server) 
 {
-       if ( send_keepalive(server->cli->fd) == False )
-               return 1;
+        socklen_t size;
+        struct sockaddr addr;
+
+        /*
+         * Although the use of port 139 is not a guarantee that we're using
+         * netbios, we assume so.  We don't want to send a keepalive packet if
+         * not netbios because it's not valid, and Vista, at least,
+         * disconnects the client on such a request.
+         */
+        if (server->cli->port == 139) {
+                /* Assuming netbios.  Send a keepalive packet */
+                if ( send_keepalive(server->cli->fd) == False ) {
+                        return 1;
+                }
+        } else {
+                /*
+                 * Assuming not netbios.  Try a different method to detect if
+                 * the connection is still alive.
+                 */
+                size = sizeof(addr);
+                if (getpeername(server->cli->fd, &addr, &size) == -1) {
+                        return 1;
+                }
+        }
 
        /* connection is ok */
        return 0;
@@ -641,7 +674,8 @@ smbc_server(SMBCCTX *context,
         int port_try_first;
         int port_try_next;
         const char *username_used;
-  
+       NTSTATUS status;
+
        zero_ip(&ip);
        ZERO_STRUCT(c);
 
@@ -761,17 +795,19 @@ smbc_server(SMBCCTX *context,
 
         c->port = port_try_first;
 
-       if (!cli_connect(c, server_n, &ip)) {
+       status = cli_connect(c, server_n, &ip);
+       if (!NT_STATUS_IS_OK(status)) {
 
                 /* First connection attempt failed.  Try alternate port. */
                 c->port = port_try_next;
 
-                if (!cli_connect(c, server_n, &ip)) {
-                        cli_shutdown(c);
-                        errno = ETIMEDOUT;
-                        return NULL;
-                }
-       }
+                status = cli_connect(c, server_n, &ip);
+               if (!NT_STATUS_IS_OK(status)) {
+                       cli_shutdown(c);
+                       errno = ETIMEDOUT;
+                       return NULL;
+               }
+       }
 
        if (!cli_session_request(c, &calling, &called)) {
                cli_shutdown(c);
@@ -906,6 +942,7 @@ smbc_attr_server(SMBCCTX *context,
                  fstring password,
                  POLICY_HND *pol)
 {
+        int flags;
         struct in_addr ip;
        struct cli_state *ipc_cli;
        struct rpc_pipe_client *pipe_hnd;
@@ -940,12 +977,17 @@ smbc_attr_server(SMBCCTX *context,
                         }
                 }
         
+                flags = 0;
+                if (context->flags & SMB_CTX_FLAG_USE_KERBEROS) {
+                        flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
+                }
+
                 zero_ip(&ip);
                 nt_status = cli_full_connection(&ipc_cli,
                                                 global_myname(), server, 
                                                 &ip, 0, "IPC$", "?????",  
                                                 username, workgroup,
-                                                password, 0,
+                                                password, flags,
                                                 Undefined, NULL);
                 if (! NT_STATUS_IS_OK(nt_status)) {
                         DEBUG(1,("cli_full_connection failed! (%s)\n",
@@ -1105,14 +1147,8 @@ smbc_open_ctx(SMBCCTX *context,
                }
                /*d_printf(">>>open: resolved %s as %s\n", path, targetpath);*/
                
-               if ( targetcli->dfsroot )
-               {
-                       pstring temppath;
-                       pstrcpy(temppath, targetpath);
-                       cli_dfs_make_full_path( targetpath, targetcli->desthost, targetcli->share, temppath);
-               }
-               
-               if ((fd = cli_open(targetcli, targetpath, flags, DENY_NONE)) < 0) {
+               if ((fd = cli_open(targetcli, targetpath, flags,
+                                   context->internal->_share_mode)) < 0) {
 
                        /* Handle the error ... */
 
@@ -1507,14 +1543,6 @@ smbc_getatr(SMBCCTX * context,
                return False;
        }
        
-       if ( targetcli->dfsroot )
-       {
-               pstring temppath;
-               pstrcpy(temppath, targetpath);
-               cli_dfs_make_full_path(targetpath, targetcli->desthost,
-                                       targetcli->share, temppath);
-       }
-  
        if (!srv->no_pathinfo2 &&
             cli_qpathinfo2(targetcli, targetpath,
                            create_time_ts,
@@ -2463,16 +2491,15 @@ net_share_enum_rpc(struct cli_state *cli,
                    void *state)
 {
         int i;
-       WERROR result;
-       ENUM_HND enum_hnd;
+       NTSTATUS result;
+       uint32 enum_hnd;
         uint32 info_level = 1;
        uint32 preferred_len = 0xffffffff;
-        uint32 type;
-       SRV_SHARE_INFO_CTR ctr;
-       fstring name = "";
-        fstring comment = "";
+       struct srvsvc_NetShareCtr1 ctr1;
+       union srvsvc_NetShareCtr ctr;
         void *mem_ctx;
        struct rpc_pipe_client *pipe_hnd;
+       uint32 numentries;
         NTSTATUS nt_status;
 
         /* Open the server service pipe */
@@ -2490,37 +2517,28 @@ net_share_enum_rpc(struct cli_state *cli,
                 return -1; 
         }
 
+       ZERO_STRUCT(ctr1);
+       ctr.ctr1 = &ctr1;
+
         /* Issue the NetShareEnum RPC call and retrieve the response */
-       init_enum_hnd(&enum_hnd, 0);
-       result = rpccli_srvsvc_net_share_enum(pipe_hnd,
-                                              mem_ctx,
-                                              info_level,
-                                              &ctr,
-                                              preferred_len,
-                                              &enum_hnd);
+       enum_hnd = 0;
+       result = rpccli_srvsvc_NetShareEnum(pipe_hnd, mem_ctx, NULL,
+                                           &info_level, &ctr, preferred_len,
+                                           &numentries, &enum_hnd);
 
         /* Was it successful? */
-       if (!W_ERROR_IS_OK(result) || ctr.num_entries == 0) {
+       if (!NT_STATUS_IS_OK(result) || numentries == 0) {
                 /*  Nope.  Go clean up. */
                goto done;
         }
 
         /* For each returned entry... */
-        for (i = 0; i < ctr.num_entries; i++) {
-
-                /* pull out the share name */
-                rpcstr_pull_unistr2_fstring(
-                        name, &ctr.share.info1[i].info_1_str.uni_netname);
-
-                /* pull out the share's comment */
-                rpcstr_pull_unistr2_fstring(
-                        comment, &ctr.share.info1[i].info_1_str.uni_remark);
-
-                /* Get the type value */
-                type = ctr.share.info1[i].info_1.type;
+        for (i = 0; i < numentries; i++) {
 
                 /* Add this share to the list */
-                (*fn)(name, type, comment, state);
+                (*fn)(ctr.ctr1->array[i].name, 
+                                         ctr.ctr1->array[i].type, 
+                                         ctr.ctr1->array[i].comment, state);
         }
 
 done:
@@ -2531,7 +2549,7 @@ done:
         TALLOC_FREE(mem_ctx);
 
         /* Tell 'em if it worked */
-        return W_ERROR_IS_OK(result) ? 0 : -1;
+        return NT_STATUS_IS_OK(result) ? 0 : -1;
 }
 
 
@@ -2540,6 +2558,7 @@ static SMBCFILE *
 smbc_opendir_ctx(SMBCCTX *context,
                  const char *fname)
 {
+        int saved_errno;
        fstring server, share, user, password, options;
        pstring workgroup;
        pstring path;
@@ -2547,6 +2566,7 @@ smbc_opendir_ctx(SMBCCTX *context,
         char *p;
        SMBCSRV *srv  = NULL;
        SMBCFILE *dir = NULL;
+        struct _smbc_callbacks *cb;
        struct in_addr rem_ip;
 
        if (!context || !context->internal ||
@@ -2908,9 +2928,9 @@ smbc_opendir_ctx(SMBCCTX *context,
                                        SAFE_FREE(dir->fname);
                                        SAFE_FREE(dir);
                                }
-                               errno = smbc_errno(context, targetcli);
+                               saved_errno = smbc_errno(context, targetcli);
 
-                                if (errno == EINVAL) {
+                                if (saved_errno == EINVAL) {
                                     /*
                                      * See if they asked to opendir something
                                      * other than a directory.  If so, the
@@ -2926,12 +2946,34 @@ smbc_opendir_ctx(SMBCCTX *context,
                                         ! IS_DOS_DIR(mode)) {
 
                                         /* It is.  Correct the error value */
-                                        errno = ENOTDIR;
+                                        saved_errno = ENOTDIR;
                                     }
                                 }
 
-                               return NULL;
+                                /*
+                                 * If there was an error and the server is no
+                                 * good any more...
+                                 */
+                                cb = &context->callbacks;
+                                if (cli_is_error(targetcli) &&
+                                    cb->check_server_fn(context, srv)) {
+
+                                    /* ... then remove it. */
+                                    if (cb->remove_unused_server_fn(context,
+                                                                    srv)) { 
+                                        /*
+                                         * We could not remove the server
+                                         * completely, remove it from the
+                                         * cache so we will not get it
+                                         * again. It will be removed when the
+                                         * last file/dir is closed.
+                                         */
+                                        cb->remove_cached_srv_fn(context, srv);
+                                    }
+                                }
 
+                                errno = saved_errno;
+                               return NULL;
                        }
                }
 
@@ -3709,8 +3751,8 @@ ace_compare(SEC_ACE *ace1,
        if (ace1->flags != ace2->flags) 
                return ace1->flags - ace2->flags;
 
-       if (ace1->info.mask != ace2->info.mask) 
-               return ace1->info.mask - ace2->info.mask;
+       if (ace1->access_mask != ace2->access_mask) 
+               return ace1->access_mask - ace2->access_mask;
 
        if (ace1->size != ace2->size) 
                return ace1->size - ace2->size;
@@ -3725,14 +3767,14 @@ sort_acl(SEC_ACL *the_acl)
        uint32 i;
        if (!the_acl) return;
 
-       qsort(the_acl->ace, the_acl->num_aces, sizeof(the_acl->ace[0]),
+       qsort(the_acl->aces, the_acl->num_aces, sizeof(the_acl->aces[0]),
               QSORT_CAST ace_compare);
 
        for (i=1;i<the_acl->num_aces;) {
-               if (sec_ace_equal(&the_acl->ace[i-1], &the_acl->ace[i])) {
+               if (sec_ace_equal(&the_acl->aces[i-1], &the_acl->aces[i])) {
                        int j;
                        for (j=i; j<the_acl->num_aces-1; j++) {
-                               the_acl->ace[j] = the_acl->ace[j+1];
+                               the_acl->aces[j] = the_acl->aces[j+1];
                        }
                        the_acl->num_aces--;
                } else {
@@ -3751,7 +3793,7 @@ convert_sid_to_string(struct cli_state *ipc_cli,
 {
        char **domains = NULL;
        char **names = NULL;
-       enum SID_NAME_USE *types = NULL;
+       enum lsa_SidType *types = NULL;
        struct rpc_pipe_client *pipe_hnd = find_lsa_pipe_hnd(ipc_cli);
        sid_to_string(str, sid);
 
@@ -3787,7 +3829,7 @@ convert_string_to_sid(struct cli_state *ipc_cli,
                       DOM_SID *sid,
                       const char *str)
 {
-       enum SID_NAME_USE *types = NULL;
+       enum lsa_SidType *types = NULL;
        DOM_SID *sids = NULL;
        BOOL result = True;
        struct rpc_pipe_client *pipe_hnd = find_lsa_pipe_hnd(ipc_cli);
@@ -3806,7 +3848,7 @@ convert_string_to_sid(struct cli_state *ipc_cli,
         }
 
        if (!NT_STATUS_IS_OK(rpccli_lsa_lookup_names(pipe_hnd, ipc_cli->mem_ctx, 
-                                                 pol, 1, &str, NULL, &sids, 
+                                                 pol, 1, &str, NULL, 1, &sids, 
                                                  &types))) {
                result = False;
                goto done;
@@ -3937,7 +3979,7 @@ parse_ace(struct cli_state *ipc_cli,
        }
 
  done:
-       mask.mask = amask;
+       mask = amask;
        init_sec_ace(ace, &sid, atype, mask, aflags);
        return True;
 }
@@ -3959,7 +4001,7 @@ add_ace(SEC_ACL **the_acl,
        if ((aces = SMB_CALLOC_ARRAY(SEC_ACE, 1+(*the_acl)->num_aces)) == NULL) {
                return False;
        }
-       memcpy(aces, (*the_acl)->ace, (*the_acl)->num_aces * sizeof(SEC_ACE));
+       memcpy(aces, (*the_acl)->aces, (*the_acl)->num_aces * sizeof(SEC_ACE));
        memcpy(aces+(*the_acl)->num_aces, ace, sizeof(SEC_ACE));
        newacl = make_sec_acl(ctx, (*the_acl)->revision,
                               1+(*the_acl)->num_aces, aces);
@@ -4219,11 +4261,14 @@ dos_attr_parse(SMBCCTX *context,
                        continue;
                }
 
-                n = strlen(attr_strings.create_time_attr);
-                if (attr_strings.create_time_attr != NULL &&
-                    StrnCaseCmp(tok, attr_strings.create_time_attr, n) == 0) {
-                        dad->create_time = (time_t)strtol(tok+n+1, NULL, 10);
-                       continue;
+               if (attr_strings.create_time_attr != NULL) {
+                       n = strlen(attr_strings.create_time_attr);
+                       if (StrnCaseCmp(tok, attr_strings.create_time_attr,
+                                       n) == 0) {
+                               dad->create_time = (time_t)strtol(tok+n+1,
+                                                                 NULL, 10);
+                               continue;
+                       }
                }
 
                if (StrnCaseCmp(tok, "INODE:", 6) == 0) {
@@ -4503,7 +4548,7 @@ cacl_get(SMBCCTX *context,
                                                 return -1;
                                         }
                                         n = strlen(p);
-                                } else {
+                                } else if (sidstr[0] != '\0') {
                                         n = snprintf(buf, bufsize,
                                                      ",OWNER:%s", sidstr);
                                 }
@@ -4531,10 +4576,10 @@ cacl_get(SMBCCTX *context,
                 }
 
                 if (! exclude_nt_group) {
-                        if (sd->grp_sid) {
+                        if (sd->group_sid) {
                                 convert_sid_to_string(ipc_cli, pol,
                                                       sidstr, numeric,
-                                                      sd->grp_sid);
+                                                      sd->group_sid);
                         } else {
                                 fstrcpy(sidstr, "");
                         }
@@ -4548,7 +4593,7 @@ cacl_get(SMBCCTX *context,
                                                 return -1;
                                         }
                                         n = strlen(p);
-                                } else {
+                                } else if (sidstr[0] != '\0') {
                                         n = snprintf(buf, bufsize,
                                                      ",GROUP:%s", sidstr);
                                 }
@@ -4579,7 +4624,7 @@ cacl_get(SMBCCTX *context,
                         /* Add aces to value buffer  */
                         for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
 
-                                SEC_ACE *ace = &sd->dacl->ace[i];
+                                SEC_ACE *ace = &sd->dacl->aces[i];
                                 convert_sid_to_string(ipc_cli, pol,
                                                       sidstr, numeric,
                                                       &ace->trustee);
@@ -4593,7 +4638,7 @@ cacl_get(SMBCCTX *context,
                                                         sidstr,
                                                         ace->type,
                                                         ace->flags,
-                                                        ace->info.mask);
+                                                        ace->access_mask);
                                                 if (!p) {
                                                         errno = ENOMEM;
                                                         return -1;
@@ -4606,7 +4651,7 @@ cacl_get(SMBCCTX *context,
                                                         sidstr,
                                                         ace->type,
                                                         ace->flags,
-                                                        ace->info.mask);
+                                                        ace->access_mask);
                                         }
                                 } else if ((StrnCaseCmp(name, "acl", 3) == 0 &&
                                             StrCaseCmp(name+3, sidstr) == 0) ||
@@ -4618,7 +4663,7 @@ cacl_get(SMBCCTX *context,
                                                         "%d/%d/0x%08x", 
                                                         ace->type,
                                                         ace->flags,
-                                                        ace->info.mask);
+                                                        ace->access_mask);
                                                 if (!p) {
                                                         errno = ENOMEM;
                                                         return -1;
@@ -4629,7 +4674,7 @@ cacl_get(SMBCCTX *context,
                                                              "%d/%d/0x%08x", 
                                                              ace->type,
                                                              ace->flags,
-                                                             ace->info.mask);
+                                                             ace->access_mask);
                                         }
                                 } else if (all_nt_acls) {
                                         if (determine_size) {
@@ -4640,7 +4685,7 @@ cacl_get(SMBCCTX *context,
                                                         sidstr,
                                                         ace->type,
                                                         ace->flags,
-                                                        ace->info.mask);
+                                                        ace->access_mask);
                                                 if (!p) {
                                                         errno = ENOMEM;
                                                         return -1;
@@ -4653,10 +4698,10 @@ cacl_get(SMBCCTX *context,
                                                              sidstr,
                                                              ace->type,
                                                              ace->flags,
-                                                             ace->info.mask);
+                                                             ace->access_mask);
                                         }
                                 }
-                                if (n > bufsize) {
+                                if (!determine_size && n > bufsize) {
                                         errno = ERANGE;
                                         return -1;
                                 }
@@ -5084,9 +5129,9 @@ cacl_set(TALLOC_CTX *ctx,
        switch (mode) {
        case SMBC_XATTR_MODE_REMOVE_ALL:
                 old->dacl->num_aces = 0;
-                SAFE_FREE(old->dacl->ace);
+                SAFE_FREE(old->dacl->aces);
                 SAFE_FREE(old->dacl);
-                old->off_dacl = 0;
+                old->dacl = NULL;
                 dacl = old->dacl;
                 break;
 
@@ -5095,18 +5140,18 @@ cacl_set(TALLOC_CTX *ctx,
                        BOOL found = False;
 
                        for (j=0;old->dacl && j<old->dacl->num_aces;j++) {
-                                if (sec_ace_equal(&sd->dacl->ace[i],
-                                                  &old->dacl->ace[j])) {
+                                if (sec_ace_equal(&sd->dacl->aces[i],
+                                                  &old->dacl->aces[j])) {
                                        uint32 k;
                                        for (k=j; k<old->dacl->num_aces-1;k++) {
-                                               old->dacl->ace[k] =
-                                                        old->dacl->ace[k+1];
+                                               old->dacl->aces[k] =
+                                                        old->dacl->aces[k+1];
                                        }
                                        old->dacl->num_aces--;
                                        if (old->dacl->num_aces == 0) {
-                                               SAFE_FREE(old->dacl->ace);
+                                               SAFE_FREE(old->dacl->aces);
                                                SAFE_FREE(old->dacl);
-                                               old->off_dacl = 0;
+                                               old->dacl = NULL;
                                        }
                                        found = True;
                                         dacl = old->dacl;
@@ -5127,14 +5172,14 @@ cacl_set(TALLOC_CTX *ctx,
                        BOOL found = False;
 
                        for (j=0;old->dacl && j<old->dacl->num_aces;j++) {
-                               if (sid_equal(&sd->dacl->ace[i].trustee,
-                                             &old->dacl->ace[j].trustee)) {
+                               if (sid_equal(&sd->dacl->aces[i].trustee,
+                                             &old->dacl->aces[j].trustee)) {
                                         if (!(flags & SMBC_XATTR_FLAG_CREATE)) {
                                                 err = EEXIST;
                                                 ret = -1;
                                                 goto failed;
                                         }
-                                        old->dacl->ace[j] = sd->dacl->ace[i];
+                                        old->dacl->aces[j] = sd->dacl->aces[i];
                                         ret = -1;
                                        found = True;
                                }
@@ -5147,7 +5192,7 @@ cacl_set(TALLOC_CTX *ctx,
                        }
                         
                         for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
-                                add_ace(&old->dacl, &sd->dacl->ace[i], ctx);
+                                add_ace(&old->dacl, &sd->dacl->aces[i], ctx);
                         }
                }
                 dacl = old->dacl;
@@ -5156,7 +5201,7 @@ cacl_set(TALLOC_CTX *ctx,
        case SMBC_XATTR_MODE_SET:
                old = sd;
                 owner_sid = old->owner_sid;
-                grp_sid = old->grp_sid;
+                grp_sid = old->group_sid;
                 dacl = old->dacl;
                break;
 
@@ -5165,7 +5210,7 @@ cacl_set(TALLOC_CTX *ctx,
                 break;
 
         case SMBC_XATTR_MODE_CHGRP:
-                grp_sid = sd->grp_sid;
+                grp_sid = sd->group_sid;
                 break;
        }
 
@@ -5274,7 +5319,9 @@ smbc_setxattr_ctx(SMBCCTX *context,
                 ipc_srv = smbc_attr_server(context, server, share,
                                            workgroup, user, password,
                                            &pol);
-                srv->no_nt_session = True;
+                if (! ipc_srv) {
+                        srv->no_nt_session = True;
+                }
         } else {
                 ipc_srv = NULL;
         }
@@ -5699,7 +5746,9 @@ smbc_removexattr_ctx(SMBCCTX *context,
                 ipc_srv = smbc_attr_server(context, server, share,
                                            workgroup, user, password,
                                            &pol);
-                srv->no_nt_session = True;
+                if (! ipc_srv) {
+                        srv->no_nt_session = True;
+                }
         } else {
                 ipc_srv = NULL;
         }
@@ -6134,6 +6183,8 @@ smbc_new_context(void)
        context->options.browse_max_lmb_count      = 3;    /* # LMBs to query */
        context->options.urlencode_readdir_entries = False;/* backward compat */
        context->options.one_share_per_server      = False;/* backward compat */
+        context->internal->_share_mode             = SMBC_SHAREMODE_DENY_NONE;
+                                /* backward compat */
 
         context->open                              = smbc_open_ctx;
         context->creat                             = smbc_creat_ctx;
@@ -6269,6 +6320,7 @@ smbc_option_set(SMBCCTX *context,
 {
         va_list ap;
         union {
+                int i;
                 BOOL b;
                 smbc_get_auth_data_with_context_fn auth_fn;
                 void *v;
@@ -6295,6 +6347,15 @@ smbc_option_set(SMBCCTX *context,
                 option_value.b = (BOOL) va_arg(ap, int);
                 context->internal->_full_time_names = option_value.b;
 
+        } else if (strcmp(option_name, "open_share_mode") == 0) {
+                /*
+                 * The share mode to use for files opened with
+                 * smbc_open_ctx().  The default is SMBC_SHAREMODE_DENY_NONE.
+                 */
+                option_value.i = va_arg(ap, int);
+                context->internal->_share_mode =
+                        (smbc_share_mode) option_value.i;
+
         } else if (strcmp(option_name, "auth_function") == 0) {
                 /*
                  * Use the new-style authentication function which includes