X-Git-Url: http://git.samba.org/?a=blobdiff_plain;f=source%2Flibsmb%2Flibsmbclient.c;h=45226a028cbc57289596cfd1b657cb91ea7310b2;hb=5c6c8e1fe93;hp=2436cc9136fd1f7e11b0044f7b035605f537e7b8;hpb=203b4911c16bd7e10198a6f0e63960f2813025ef;p=samba.git diff --git a/source/libsmb/libsmbclient.c b/source/libsmb/libsmbclient.c index 2436cc9136f..45226a028cb 100644 --- a/source/libsmb/libsmbclient.c +++ b/source/libsmb/libsmbclient.c @@ -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, @@ -18,14 +18,16 @@ 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 . */ #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) @@ -33,9 +35,10 @@ typedef struct DOS_ATTR_DESC { int mode; SMB_OFF_T size; - time_t a_time; - time_t c_time; - time_t m_time; + time_t create_time; + time_t access_time; + time_t write_time; + time_t change_time; SMB_INO_T inode; } DOS_ATTR_DESC; @@ -236,7 +239,7 @@ smbc_urlencode(char * dest, char * src, int max_dest_len) * * * We accept: - * smb://[[[domain;]user[:password@]]server[/share[/path[/file]]]][?options] + * smb://[[[domain;]user[:password]@]server[/share[/path[/file]]]][?options] * * Meaning of URLs: * @@ -335,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; - } /* @@ -359,19 +363,19 @@ smbc_parse_path(SMBCCTX *context, pstring username, passwd, domain; const char *u = userinfo; - next_token(&p, userinfo, "@", sizeof(fstring)); + next_token_no_ltrim(&p, userinfo, "@", sizeof(fstring)); username[0] = passwd[0] = domain[0] = 0; if (strchr_m(u, ';')) { - next_token(&u, domain, ";", sizeof(fstring)); + next_token_no_ltrim(&u, domain, ";", sizeof(fstring)); } if (strchr_m(u, ':')) { - next_token(&u, username, ":", sizeof(fstring)); + next_token_no_ltrim(&u, username, ":", sizeof(fstring)); pstrcpy(passwd, u); @@ -413,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); @@ -487,11 +499,11 @@ static int smbc_check_server(SMBCCTX * context, SMBCSRV * server) { - if ( send_keepalive(server->cli.fd) == False ) - return 1; + socklen_t size; + struct sockaddr addr; - /* connection is ok */ - return 0; + size = sizeof(addr); + return (getpeername(server->cli->fd, &addr, &size) == -1); } /* @@ -524,11 +536,12 @@ smbc_remove_unused_server(SMBCCTX * context, DLIST_REMOVE(context->internal->_servers, srv); - cli_shutdown(&srv->cli); + cli_shutdown(srv->cli); + srv->cli = NULL; DEBUG(3, ("smbc_remove_usused_server: %p removed.\n", srv)); - context->callbacks.remove_cached_srv_fn(context, srv); + (context->callbacks.remove_cached_srv_fn)(context, srv); SAFE_FREE(srv); @@ -548,19 +561,19 @@ find_server(SMBCCTX *context, check_server_cache: - srv = context->callbacks.get_cached_srv_fn(context, server, share, - workgroup, username); + srv = (context->callbacks.get_cached_srv_fn)(context, server, share, + workgroup, username); if (!auth_called && !srv && (!username[0] || !password[0])) { if (context->internal->_auth_fn_with_context != NULL) { - context->internal->_auth_fn_with_context( + (context->internal->_auth_fn_with_context)( context, server, share, workgroup, sizeof(fstring), username, sizeof(fstring), password, sizeof(fstring)); } else { - context->callbacks.auth_fn( + (context->callbacks.auth_fn)( server, share, workgroup, sizeof(fstring), username, sizeof(fstring), @@ -578,22 +591,22 @@ find_server(SMBCCTX *context, } if (srv) { - if (context->callbacks.check_server_fn(context, srv)) { + if ((context->callbacks.check_server_fn)(context, srv)) { /* * This server is no good anymore * Try to remove it and check for more possible * servers in the cache */ - if (context->callbacks.remove_unused_server_fn(context, - srv)) { + if ((context->callbacks.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. */ - context->callbacks.remove_cached_srv_fn(context, - srv); + (context->callbacks.remove_cached_srv_fn)(context, + srv); } /* @@ -630,7 +643,7 @@ smbc_server(SMBCCTX *context, fstring password) { SMBCSRV *srv=NULL; - struct cli_state c; + struct cli_state *c; struct nmb_name called, calling; const char *server_n = server; pstring ipenv; @@ -639,7 +652,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); @@ -666,30 +680,31 @@ smbc_server(SMBCCTX *context, * disconnect if the requested share is not the same as the * one that was already connected. */ - if (srv->cli.cnum == (uint16) -1) { + if (srv->cli->cnum == (uint16) -1) { /* Ensure we have accurate auth info */ if (context->internal->_auth_fn_with_context != NULL) { - context->internal->_auth_fn_with_context( + (context->internal->_auth_fn_with_context)( context, server, share, workgroup, sizeof(fstring), username, sizeof(fstring), password, sizeof(fstring)); } else { - context->callbacks.auth_fn( + (context->callbacks.auth_fn)( server, share, workgroup, sizeof(fstring), username, sizeof(fstring), password, sizeof(fstring)); } - if (! cli_send_tconX(&srv->cli, share, "?????", + if (! cli_send_tconX(srv->cli, share, "?????", password, strlen(password)+1)) { - errno = smbc_errno(context, &srv->cli); - cli_shutdown(&srv->cli); - context->callbacks.remove_cached_srv_fn(context, - srv); + errno = smbc_errno(context, srv->cli); + cli_shutdown(srv->cli); + srv->cli = NULL; + (context->callbacks.remove_cached_srv_fn)(context, + srv); srv = NULL; } @@ -730,19 +745,19 @@ smbc_server(SMBCCTX *context, zero_ip(&ip); /* have to open a new connection */ - if (!cli_initialise(&c)) { + if ((c = cli_initialise()) == NULL) { errno = ENOMEM; return NULL; } if (context->flags & SMB_CTX_FLAG_USE_KERBEROS) { - c.use_kerberos = True; + c->use_kerberos = True; } if (context->flags & SMB_CTX_FLAG_FALLBACK_AFTER_KERBEROS) { - c.fallback_after_kerberos = True; + c->fallback_after_kerberos = True; } - c.timeout = context->timeout; + c->timeout = context->timeout; /* * Force use of port 139 for first try if share is $IPC, empty, or @@ -756,49 +771,49 @@ smbc_server(SMBCCTX *context, port_try_next = 139; } - c.port = port_try_first; + 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; + 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); + if (!cli_session_request(c, &calling, &called)) { + cli_shutdown(c); if (strcmp(called.name, "*SMBSERVER")) { make_nmb_name(&called , "*SMBSERVER", 0x20); goto again; - } - else { /* Try one more time, but ensure we don't loop */ - - /* Only try this if server is an IP address ... */ + } else { /* Try one more time, but ensure we don't loop */ - if (is_ipaddress(server) && !tried_reverse) { - fstring remote_name; - struct in_addr rem_ip; + /* Only try this if server is an IP address ... */ - if ((rem_ip.s_addr=inet_addr(server)) == INADDR_NONE) { - DEBUG(4, ("Could not convert IP address %s to struct in_addr\n", server)); - errno = ETIMEDOUT; - return NULL; - } + if (is_ipaddress(server) && !tried_reverse) { + fstring remote_name; + struct in_addr rem_ip; - tried_reverse++; /* Yuck */ - - if (name_status_find("*", 0, 0, rem_ip, remote_name)) { - make_nmb_name(&called, remote_name, 0x20); - goto again; - } + if ((rem_ip.s_addr=inet_addr(server)) == INADDR_NONE) { + DEBUG(4, ("Could not convert IP address " + "%s to struct in_addr\n", server)); + errno = ETIMEDOUT; + return NULL; + } + tried_reverse++; /* Yuck */ - } + if (name_status_find("*", 0, 0, rem_ip, remote_name)) { + make_nmb_name(&called, remote_name, 0x20); + goto again; + } + } } errno = ETIMEDOUT; return NULL; @@ -806,29 +821,29 @@ smbc_server(SMBCCTX *context, DEBUG(4,(" session request ok\n")); - if (!cli_negprot(&c)) { - cli_shutdown(&c); + if (!cli_negprot(c)) { + cli_shutdown(c); errno = ETIMEDOUT; return NULL; } username_used = username; - if (!cli_session_setup(&c, username_used, - password, strlen(password), - password, strlen(password), - workgroup)) { + if (!NT_STATUS_IS_OK(cli_session_setup(c, username_used, + password, strlen(password), + password, strlen(password), + workgroup))) { /* Failed. Try an anonymous login, if allowed by flags. */ username_used = ""; if ((context->flags & SMBCCTX_FLAG_NO_AUTO_ANONYMOUS_LOGON) || - !cli_session_setup(&c, username_used, - password, 1, - password, 0, - workgroup)) { + !NT_STATUS_IS_OK(cli_session_setup(c, username_used, + password, 1, + password, 0, + workgroup))) { - cli_shutdown(&c); + cli_shutdown(c); errno = EPERM; return NULL; } @@ -836,10 +851,10 @@ smbc_server(SMBCCTX *context, DEBUG(4,(" session setup ok\n")); - if (!cli_send_tconX(&c, share, "?????", + if (!cli_send_tconX(c, share, "?????", password, strlen(password)+1)) { - errno = smbc_errno(context, &c); - cli_shutdown(&c); + errno = smbc_errno(context, c); + cli_shutdown(c); return NULL; } @@ -858,7 +873,6 @@ smbc_server(SMBCCTX *context, ZERO_STRUCTP(srv); srv->cli = c; - srv->cli.allocated = False; srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share)); srv->no_pathinfo = False; srv->no_pathinfo2 = False; @@ -867,7 +881,9 @@ smbc_server(SMBCCTX *context, /* now add it to the cache (internal or external) */ /* Let the cache function set errno if it wants to */ errno = 0; - if (context->callbacks.add_cached_srv_fn(context, srv, server, share, workgroup, username)) { + if ((context->callbacks.add_cached_srv_fn)(context, srv, + server, share, + workgroup, username)) { int saved_errno = errno; DEBUG(3, (" Failed to add server to cache\n")); errno = saved_errno; @@ -884,8 +900,10 @@ smbc_server(SMBCCTX *context, return srv; failed: - cli_shutdown(&c); - if (!srv) return NULL; + cli_shutdown(c); + if (!srv) { + return NULL; + } SAFE_FREE(srv); return NULL; @@ -904,6 +922,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; @@ -923,14 +942,14 @@ smbc_attr_server(SMBCCTX *context, if (*password == '\0') { /* ... then retrieve it now. */ if (context->internal->_auth_fn_with_context != NULL) { - context->internal->_auth_fn_with_context( + (context->internal->_auth_fn_with_context)( context, server, share, workgroup, sizeof(fstring), username, sizeof(fstring), password, sizeof(fstring)); } else { - context->callbacks.auth_fn( + (context->callbacks.auth_fn)( server, share, workgroup, sizeof(fstring), username, sizeof(fstring), @@ -938,12 +957,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", @@ -960,19 +984,16 @@ smbc_attr_server(SMBCCTX *context, } ZERO_STRUCTP(ipc_srv); - ipc_srv->cli = *ipc_cli; - ipc_srv->cli.allocated = False; - - free(ipc_cli); + ipc_srv->cli = ipc_cli; if (pol) { - pipe_hnd = cli_rpc_pipe_open_noauth(&ipc_srv->cli, + pipe_hnd = cli_rpc_pipe_open_noauth(ipc_srv->cli, PI_LSARPC, &nt_status); if (!pipe_hnd) { DEBUG(1, ("cli_nt_session_open fail!\n")); errno = ENOTSUP; - cli_shutdown(&ipc_srv->cli); + cli_shutdown(ipc_srv->cli); free(ipc_srv); return NULL; } @@ -985,14 +1006,14 @@ smbc_attr_server(SMBCCTX *context, nt_status = rpccli_lsa_open_policy( pipe_hnd, - ipc_srv->cli.mem_ctx, + ipc_srv->cli->mem_ctx, True, GENERIC_EXECUTE_ACCESS, pol); if (!NT_STATUS_IS_OK(nt_status)) { - errno = smbc_errno(context, &ipc_srv->cli); - cli_shutdown(&ipc_srv->cli); + errno = smbc_errno(context, ipc_srv->cli); + cli_shutdown(ipc_srv->cli); return NULL; } } @@ -1000,16 +1021,16 @@ smbc_attr_server(SMBCCTX *context, /* now add it to the cache (internal or external) */ errno = 0; /* let cache function set errno if it likes */ - if (context->callbacks.add_cached_srv_fn(context, ipc_srv, - server, - "*IPC$", - workgroup, - username)) { + if ((context->callbacks.add_cached_srv_fn)(context, ipc_srv, + server, + "*IPC$", + workgroup, + username)) { DEBUG(3, (" Failed to add server to cache\n")); if (errno == 0) { errno = ENOMEM; } - cli_shutdown(&ipc_srv->cli); + cli_shutdown(ipc_srv->cli); free(ipc_srv); return NULL; } @@ -1098,7 +1119,7 @@ smbc_open_ctx(SMBCCTX *context, ZERO_STRUCTP(file); /*d_printf(">>>open: resolving %s\n", path);*/ - if (!cli_resolve_path( "", &srv->cli, path, &targetcli, targetpath)) + if (!cli_resolve_path( "", srv->cli, path, &targetcli, targetpath)) { d_printf("Could not resolve %s\n", path); SAFE_FREE(file); @@ -1106,14 +1127,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 ... */ @@ -1172,8 +1187,8 @@ smbc_open_ctx(SMBCCTX *context, if (fd == -1) { int eno = 0; - eno = smbc_errno(context, &srv->cli); - file = context->opendir(context, fname); + eno = smbc_errno(context, srv->cli); + file = (context->opendir)(context, fname); if (!file) errno = eno; return file; @@ -1275,7 +1290,7 @@ smbc_read_ctx(SMBCCTX *context, } /*d_printf(">>>read: resolving %s\n", path);*/ - if (!cli_resolve_path("", &file->srv->cli, path, + if (!cli_resolve_path("", file->srv->cli, path, &targetcli, targetpath)) { d_printf("Could not resolve %s\n", path); @@ -1283,7 +1298,7 @@ smbc_read_ctx(SMBCCTX *context, } /*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/ - ret = cli_read(targetcli, file->cli_fd, buf, offset, count); + ret = cli_read(targetcli, file->cli_fd, (char *)buf, offset, count); if (ret < 0) { @@ -1358,7 +1373,7 @@ smbc_write_ctx(SMBCCTX *context, } /*d_printf(">>>write: resolving %s\n", path);*/ - if (!cli_resolve_path("", &file->srv->cli, path, + if (!cli_resolve_path("", file->srv->cli, path, &targetcli, targetpath)) { d_printf("Could not resolve %s\n", path); @@ -1367,7 +1382,7 @@ smbc_write_ctx(SMBCCTX *context, /*d_printf(">>>write: resolved path as %s\n", targetpath);*/ - ret = cli_write(targetcli, file->cli_fd, 0, buf, offset, count); + ret = cli_write(targetcli, file->cli_fd, 0, (char *)buf, offset, count); if (ret <= 0) { @@ -1412,7 +1427,7 @@ smbc_close_ctx(SMBCCTX *context, /* IS a dir ... */ if (!file->file) { - return context->closedir(context, file); + return (context->closedir)(context, file); } @@ -1430,7 +1445,7 @@ smbc_close_ctx(SMBCCTX *context, } /*d_printf(">>>close: resolving %s\n", path);*/ - if (!cli_resolve_path("", &file->srv->cli, path, + if (!cli_resolve_path("", file->srv->cli, path, &targetcli, targetpath)) { d_printf("Could not resolve %s\n", path); @@ -1449,7 +1464,7 @@ smbc_close_ctx(SMBCCTX *context, DLIST_REMOVE(context->internal->_files, file); SAFE_FREE(file->fname); SAFE_FREE(file); - context->callbacks.remove_unused_server_fn(context, srv); + (context->callbacks.remove_unused_server_fn)(context, srv); return -1; @@ -1472,14 +1487,16 @@ smbc_getatr(SMBCCTX * context, char *path, uint16 *mode, SMB_OFF_T *size, - time_t *c_time, - time_t *a_time, - time_t *m_time, + struct timespec *create_time_ts, + struct timespec *access_time_ts, + struct timespec *write_time_ts, + struct timespec *change_time_ts, SMB_INO_T *ino) { pstring fixedpath; pstring targetpath; struct cli_state *targetcli; + time_t write_time; if (!context || !context->internal || !context->internal->_initialized) { @@ -1500,23 +1517,19 @@ smbc_getatr(SMBCCTX * context, } DEBUG(4,("smbc_getatr: sending qpathinfo\n")); - if (!cli_resolve_path( "", &srv->cli, fixedpath, &targetcli, targetpath)) + if (!cli_resolve_path( "", srv->cli, fixedpath, &targetcli, targetpath)) { d_printf("Couldn't resolve %s\n", path); 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, - c_time, a_time, m_time, NULL, size, mode, ino)) { + create_time_ts, + access_time_ts, + write_time_ts, + change_time_ts, + size, mode, ino)) { return True; } @@ -1526,11 +1539,28 @@ smbc_getatr(SMBCCTX * context, return False; } - if (cli_getatr(targetcli, targetpath, mode, size, m_time)) { - if (m_time != NULL) { - if (a_time != NULL) *a_time = *m_time; - if (c_time != NULL) *c_time = *m_time; + if (cli_getatr(targetcli, targetpath, mode, size, &write_time)) { + + struct timespec w_time_ts; + + w_time_ts = convert_time_t_to_timespec(write_time); + + if (write_time_ts != NULL) { + *write_time_ts = w_time_ts; + } + + if (create_time_ts != NULL) { + *create_time_ts = w_time_ts; } + + if (access_time_ts != NULL) { + *access_time_ts = w_time_ts; + } + + if (change_time_ts != NULL) { + *change_time_ts = w_time_ts; + } + srv->no_pathinfo2 = True; return True; } @@ -1552,7 +1582,10 @@ smbc_getatr(SMBCCTX * context, */ static BOOL smbc_setatr(SMBCCTX * context, SMBCSRV *srv, char *path, - time_t c_time, time_t a_time, time_t m_time, + time_t create_time, + time_t access_time, + time_t write_time, + time_t change_time, uint16 mode) { int fd; @@ -1565,7 +1598,12 @@ smbc_setatr(SMBCCTX * context, SMBCSRV *srv, char *path, * attributes manipulated. */ if (srv->no_pathinfo || - ! cli_setpathinfo(&srv->cli, path, c_time, a_time, m_time, mode)) { + ! cli_setpathinfo(srv->cli, path, + create_time, + access_time, + write_time, + change_time, + mode)) { /* * setpathinfo is not supported; go to plan B. @@ -1581,48 +1619,20 @@ smbc_setatr(SMBCCTX * context, SMBCSRV *srv, char *path, srv->no_pathinfo = True; /* Open the file */ - if ((fd = cli_open(&srv->cli, path, O_RDWR, DENY_NONE)) < 0) { + if ((fd = cli_open(srv->cli, path, O_RDWR, DENY_NONE)) < 0) { - errno = smbc_errno(context, &srv->cli); + errno = smbc_errno(context, srv->cli); return -1; } - /* - * Get the creat time of the file (if it wasn't provided). - * We'll need it in the set call - */ - if (c_time == 0) { - ret = cli_getattrE(&srv->cli, fd, - NULL, NULL, - &c_time, NULL, NULL); - } else { - ret = True; - } - - /* If we got create time, set times */ - if (ret) { - /* Some OS versions don't support create time */ - if (c_time == 0 || c_time == -1) { - c_time = time(NULL); - } + /* Set the new attributes */ + ret = cli_setattrE(srv->cli, fd, + change_time, + access_time, + write_time); - /* - * For sanity sake, since there is no POSIX function - * to set the create time of a file, if the existing - * create time is greater than either of access time - * or modification time, set create time to the - * smallest of those. This ensure that the create - * time of a file is never greater than its last - * access or modification time. - */ - if (c_time > a_time) c_time = a_time; - if (c_time > m_time) c_time = m_time; - - /* Set the new attributes */ - ret = cli_setattrE(&srv->cli, fd, - c_time, a_time, m_time); - cli_close(&srv->cli, fd); - } + /* Close the file */ + cli_close(srv->cli, fd); /* * Unfortunately, setattrE() doesn't have a provision for @@ -1631,11 +1641,11 @@ smbc_setatr(SMBCCTX * context, SMBCSRV *srv, char *path, * seems to work on win98. */ if (ret && mode != (uint16) -1) { - ret = cli_setatr(&srv->cli, path, mode, 0); + ret = cli_setatr(srv->cli, path, mode, 0); } if (! ret) { - errno = smbc_errno(context, &srv->cli); + errno = smbc_errno(context, srv->cli); return False; } } @@ -1695,7 +1705,7 @@ smbc_unlink_ctx(SMBCCTX *context, } /*d_printf(">>>unlink: resolving %s\n", path);*/ - if (!cli_resolve_path( "", &srv->cli, path, &targetcli, targetpath)) + if (!cli_resolve_path( "", srv->cli, path, &targetcli, targetpath)) { d_printf("Could not resolve %s\n", path); return -1; @@ -1711,11 +1721,17 @@ smbc_unlink_ctx(SMBCCTX *context, int saverr = errno; SMB_OFF_T size = 0; uint16 mode = 0; - time_t m_time = 0, a_time = 0, c_time = 0; + struct timespec write_time_ts; + struct timespec access_time_ts; + struct timespec change_time_ts; SMB_INO_T ino = 0; if (!smbc_getatr(context, srv, path, &mode, &size, - &c_time, &a_time, &m_time, &ino)) { + NULL, + &access_time_ts, + &write_time_ts, + &change_time_ts, + &ino)) { /* Hmmm, bad error ... What? */ @@ -1828,14 +1844,14 @@ smbc_rename_ctx(SMBCCTX *ocontext, } /*d_printf(">>>rename: resolving %s\n", path1);*/ - if (!cli_resolve_path( "", &srv->cli, path1, &targetcli1, targetpath1)) + if (!cli_resolve_path( "", srv->cli, path1, &targetcli1, targetpath1)) { d_printf("Could not resolve %s\n", path1); return -1; } /*d_printf(">>>rename: resolved path as %s\n", targetpath1);*/ /*d_printf(">>>rename: resolving %s\n", path2);*/ - if (!cli_resolve_path( "", &srv->cli, path2, &targetcli2, targetpath2)) + if (!cli_resolve_path( "", srv->cli, path2, &targetcli2, targetpath2)) { d_printf("Could not resolve %s\n", path2); return -1; @@ -1930,7 +1946,7 @@ smbc_lseek_ctx(SMBCCTX *context, } /*d_printf(">>>lseek: resolving %s\n", path);*/ - if (!cli_resolve_path("", &file->srv->cli, path, + if (!cli_resolve_path("", file->srv->cli, path, &targetcli, targetpath)) { d_printf("Could not resolve %s\n", path); @@ -2051,9 +2067,9 @@ smbc_stat_ctx(SMBCCTX *context, fstring password; fstring workgroup; pstring path; - time_t m_time = 0; - time_t a_time = 0; - time_t c_time = 0; + struct timespec write_time_ts; + struct timespec access_time_ts; + struct timespec change_time_ts; SMB_OFF_T size = 0; uint16 mode = 0; SMB_INO_T ino = 0; @@ -2097,9 +2113,13 @@ smbc_stat_ctx(SMBCCTX *context, } if (!smbc_getatr(context, srv, path, &mode, &size, - &c_time, &a_time, &m_time, &ino)) { + NULL, + &access_time_ts, + &write_time_ts, + &change_time_ts, + &ino)) { - errno = smbc_errno(context, &srv->cli); + errno = smbc_errno(context, srv->cli); return -1; } @@ -2108,9 +2128,9 @@ smbc_stat_ctx(SMBCCTX *context, smbc_setup_stat(context, st, path, size, mode); - st->st_atime = a_time; - st->st_ctime = c_time; - st->st_mtime = m_time; + set_atimespec(st, access_time_ts); + set_ctimespec(st, change_time_ts); + set_mtimespec(st, write_time_ts); st->st_dev = srv->dev; return 0; @@ -2126,9 +2146,9 @@ smbc_fstat_ctx(SMBCCTX *context, SMBCFILE *file, struct stat *st) { - time_t c_time; - time_t a_time; - time_t m_time; + struct timespec change_time_ts; + struct timespec access_time_ts; + struct timespec write_time_ts; SMB_OFF_T size; uint16 mode; fstring server; @@ -2157,7 +2177,7 @@ smbc_fstat_ctx(SMBCCTX *context, if (!file->file) { - return context->fstatdir(context, file, st); + return (context->fstatdir)(context, file, st); } @@ -2175,7 +2195,7 @@ smbc_fstat_ctx(SMBCCTX *context, } /*d_printf(">>>fstat: resolving %s\n", path);*/ - if (!cli_resolve_path("", &file->srv->cli, path, + if (!cli_resolve_path("", file->srv->cli, path, &targetcli, targetpath)) { d_printf("Could not resolve %s\n", path); @@ -2184,22 +2204,33 @@ smbc_fstat_ctx(SMBCCTX *context, /*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/ if (!cli_qfileinfo(targetcli, file->cli_fd, &mode, &size, - &c_time, &a_time, &m_time, NULL, &ino)) { - if (!cli_getattrE(targetcli, file->cli_fd, &mode, &size, - &c_time, &a_time, &m_time)) { + NULL, + &access_time_ts, + &write_time_ts, + &change_time_ts, + &ino)) { - errno = EINVAL; - return -1; - } + time_t change_time, access_time, write_time; + + if (!cli_getattrE(targetcli, file->cli_fd, &mode, &size, + &change_time, &access_time, &write_time)) { + + errno = EINVAL; + return -1; + } + + change_time_ts = convert_time_t_to_timespec(change_time); + access_time_ts = convert_time_t_to_timespec(access_time); + write_time_ts = convert_time_t_to_timespec(write_time); } st->st_ino = ino; smbc_setup_stat(context, st, file->fname, size, mode); - st->st_atime = a_time; - st->st_ctime = c_time; - st->st_mtime = m_time; + set_atimespec(st, access_time_ts); + set_ctimespec(st, change_time_ts); + set_mtimespec(st, write_time_ts); st->st_dev = file->srv->dev; return 0; @@ -2248,7 +2279,7 @@ add_dirent(SMBCFILE *dir, size = sizeof(struct smbc_dirent) + name_length + comment_len + 2; - dirent = SMB_MALLOC(size); + dirent = (struct smbc_dirent *)SMB_MALLOC(size); if (!dirent) { @@ -2517,6 +2548,7 @@ static SMBCFILE * smbc_opendir_ctx(SMBCCTX *context, const char *fname) { + int saved_errno; fstring server, share, user, password, options; pstring workgroup; pstring path; @@ -2524,6 +2556,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 || @@ -2622,7 +2655,9 @@ smbc_opendir_ctx(SMBCCTX *context, */ ip_list = NULL; - if (!name_resolve_bcast(MSBROWSE, 1, &ip_list, &count)) { + if (!NT_STATUS_IS_OK(name_resolve_bcast(MSBROWSE, 1, &ip_list, + &count))) + { SAFE_FREE(ip_list); @@ -2676,7 +2711,7 @@ smbc_opendir_ctx(SMBCCTX *context, /* Now, list the stuff ... */ - if (!cli_NetServerEnum(&srv->cli, + if (!cli_NetServerEnum(srv->cli, workgroup, SV_TYPE_DOMAIN_ENUM, list_unique_wg_fn, @@ -2772,7 +2807,7 @@ smbc_opendir_ctx(SMBCCTX *context, dir->srv = srv; /* Now, list the servers ... */ - if (!cli_NetServerEnum(&srv->cli, server, + if (!cli_NetServerEnum(srv->cli, server, 0x0000FFFE, list_fn, (void *)dir)) { @@ -2808,15 +2843,15 @@ smbc_opendir_ctx(SMBCCTX *context, /* List the shares ... */ if (net_share_enum_rpc( - &srv->cli, + srv->cli, list_fn, (void *) dir) < 0 && cli_RNetShareEnum( - &srv->cli, + srv->cli, list_fn, (void *)dir) < 0) { - errno = cli_errno(&srv->cli); + errno = cli_errno(srv->cli); if (dir) { SAFE_FREE(dir->fname); SAFE_FREE(dir); @@ -2866,7 +2901,7 @@ smbc_opendir_ctx(SMBCCTX *context, p = path + strlen(path); pstrcat(path, "\\*"); - if (!cli_resolve_path("", &srv->cli, path, + if (!cli_resolve_path("", srv->cli, path, &targetcli, targetpath)) { d_printf("Could not resolve %s\n", path); @@ -2885,9 +2920,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 @@ -2898,17 +2933,41 @@ smbc_opendir_ctx(SMBCCTX *context, if (smbc_getatr(context, srv, path, &mode, NULL, - NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL) && ! 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; } } @@ -3215,7 +3274,7 @@ smbc_mkdir_ctx(SMBCCTX *context, } /*d_printf(">>>mkdir: resolving %s\n", path);*/ - if (!cli_resolve_path( "", &srv->cli, path, &targetcli, targetpath)) + if (!cli_resolve_path( "", srv->cli, path, &targetcli, targetpath)) { d_printf("Could not resolve %s\n", path); return -1; @@ -3312,7 +3371,7 @@ smbc_rmdir_ctx(SMBCCTX *context, } /*d_printf(">>>rmdir: resolving %s\n", path);*/ - if (!cli_resolve_path( "", &srv->cli, path, &targetcli, targetpath)) + if (!cli_resolve_path( "", srv->cli, path, &targetcli, targetpath)) { d_printf("Could not resolve %s\n", path); return -1; @@ -3369,8 +3428,6 @@ static off_t smbc_telldir_ctx(SMBCCTX *context, SMBCFILE *dir) { - off_t ret_val; /* Squash warnings about cast */ - if (!context || !context->internal || !context->internal->_initialized) { @@ -3393,12 +3450,16 @@ smbc_telldir_ctx(SMBCCTX *context, } + /* See if we're already at the end. */ + if (dir->dir_next == NULL) { + /* We are. */ + return -1; + } + /* * We return the pointer here as the offset */ - ret_val = (off_t)(long)dir->dir_next; - return ret_val; - + return (off_t)(long)dir->dir_next->dirent; } /* @@ -3469,6 +3530,11 @@ smbc_lseekdir_ctx(SMBCCTX *context, } + if (offset == -1) { /* Seek to the end of the list */ + dir->dir_next = NULL; + return 0; + } + /* Now, run down the list and make sure that the entry is OK */ /* This may need to be changed if we change the format of the list */ @@ -3568,8 +3634,8 @@ smbc_chmod_ctx(SMBCCTX *context, if ((newmode & S_IXGRP) && lp_map_system(-1)) mode |= aSYSTEM; if ((newmode & S_IXOTH) && lp_map_hidden(-1)) mode |= aHIDDEN; - if (!cli_setatr(&srv->cli, path, mode, 0)) { - errno = smbc_errno(context, &srv->cli); + if (!cli_setatr(srv->cli, path, mode, 0)) { + errno = smbc_errno(context, srv->cli); return -1; } @@ -3588,8 +3654,8 @@ smbc_utimes_ctx(SMBCCTX *context, fstring password; fstring workgroup; pstring path; - time_t a_time; - time_t m_time; + time_t access_time; + time_t write_time; if (!context || !context->internal || !context->internal->_initialized) { @@ -3607,10 +3673,10 @@ smbc_utimes_ctx(SMBCCTX *context, } if (tbuf == NULL) { - a_time = m_time = time(NULL); + access_time = write_time = time(NULL); } else { - a_time = tbuf[0].tv_sec; - m_time = tbuf[1].tv_sec; + access_time = tbuf[0].tv_sec; + write_time = tbuf[1].tv_sec; } if (DEBUGLVL(4)) @@ -3619,13 +3685,13 @@ smbc_utimes_ctx(SMBCCTX *context, char atimebuf[32]; char mtimebuf[32]; - strncpy(atimebuf, ctime(&a_time), sizeof(atimebuf) - 1); + strncpy(atimebuf, ctime(&access_time), sizeof(atimebuf) - 1); atimebuf[sizeof(atimebuf) - 1] = '\0'; if ((p = strchr(atimebuf, '\n')) != NULL) { *p = '\0'; } - strncpy(mtimebuf, ctime(&m_time), sizeof(mtimebuf) - 1); + strncpy(mtimebuf, ctime(&write_time), sizeof(mtimebuf) - 1); mtimebuf[sizeof(mtimebuf) - 1] = '\0'; if ((p = strchr(mtimebuf, '\n')) != NULL) { *p = '\0'; @@ -3656,7 +3722,8 @@ smbc_utimes_ctx(SMBCCTX *context, return -1; /* errno set by smbc_server */ } - if (!smbc_setatr(context, srv, path, 0, a_time, m_time, 0)) { + if (!smbc_setatr(context, srv, path, + 0, access_time, write_time, 0, 0)) { return -1; /* errno set by smbc_setatr */ } @@ -3664,32 +3731,94 @@ smbc_utimes_ctx(SMBCCTX *context, } -/* The MSDN is contradictory over the ordering of ACE entries in an ACL. - However NT4 gives a "The information may have been modified by a - computer running Windows NT 5.0" if denied ACEs do not appear before - allowed ACEs. */ +/* + * Sort ACEs according to the documentation at + * http://support.microsoft.com/kb/269175, at least as far as it defines the + * order. + */ static int ace_compare(SEC_ACE *ace1, SEC_ACE *ace2) { - if (sec_ace_equal(ace1, ace2)) + BOOL b1; + BOOL b2; + + /* If the ACEs are equal, we have nothing more to do. */ + if (sec_ace_equal(ace1, ace2)) { return 0; + } + + /* Inherited follow non-inherited */ + b1 = ((ace1->flags & SEC_ACE_FLAG_INHERITED_ACE) != 0); + b2 = ((ace2->flags & SEC_ACE_FLAG_INHERITED_ACE) != 0); + if (b1 != b2) { + return (b1 ? 1 : -1); + } + + /* + * What shall we do with AUDITs and ALARMs? It's undefined. We'll + * sort them after DENY and ALLOW. + */ + b1 = (ace1->type != SEC_ACE_TYPE_ACCESS_ALLOWED && + ace1->type != SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT && + ace1->type != SEC_ACE_TYPE_ACCESS_DENIED && + ace1->type != SEC_ACE_TYPE_ACCESS_DENIED_OBJECT); + b2 = (ace2->type != SEC_ACE_TYPE_ACCESS_ALLOWED && + ace2->type != SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT && + ace2->type != SEC_ACE_TYPE_ACCESS_DENIED && + ace2->type != SEC_ACE_TYPE_ACCESS_DENIED_OBJECT); + if (b1 != b2) { + return (b1 ? 1 : -1); + } + + /* Allowed ACEs follow denied ACEs */ + b1 = (ace1->type == SEC_ACE_TYPE_ACCESS_ALLOWED || + ace1->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT); + b2 = (ace2->type == SEC_ACE_TYPE_ACCESS_ALLOWED || + ace2->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT); + if (b1 != b2) { + return (b1 ? 1 : -1); + } - if (ace1->type != ace2->type) + /* + * ACEs applying to an entity's object follow those applying to the + * entity itself + */ + b1 = (ace1->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT || + ace1->type == SEC_ACE_TYPE_ACCESS_DENIED_OBJECT); + b2 = (ace2->type == SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT || + ace2->type == SEC_ACE_TYPE_ACCESS_DENIED_OBJECT); + if (b1 != b2) { + return (b1 ? 1 : -1); + } + + /* + * If we get this far, the ACEs are similar as far as the + * characteristics we typically care about (those defined by the + * referenced MS document). We'll now sort by characteristics that + * just seems reasonable. + */ + + if (ace1->type != ace2->type) { return ace2->type - ace1->type; + } - if (sid_compare(&ace1->trustee, &ace2->trustee)) + if (sid_compare(&ace1->trustee, &ace2->trustee)) { return sid_compare(&ace1->trustee, &ace2->trustee); + } - if (ace1->flags != ace2->flags) + 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) + if (ace1->size != ace2->size) { return ace1->size - ace2->size; + } return memcmp(ace1, ace2, sizeof(SEC_ACE)); } @@ -3701,14 +3830,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;inum_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; jnum_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 { @@ -3727,7 +3856,7 @@ convert_sid_to_string(struct cli_state *ipc_cli, { char **domains = NULL; char **names = NULL; - uint32 *types = NULL; + enum lsa_SidType *types = NULL; struct rpc_pipe_client *pipe_hnd = find_lsa_pipe_hnd(ipc_cli); sid_to_string(str, sid); @@ -3763,7 +3892,7 @@ convert_string_to_sid(struct cli_state *ipc_cli, DOM_SID *sid, const char *str) { - uint32 *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); @@ -3782,7 +3911,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; @@ -3913,7 +4042,7 @@ parse_ace(struct cli_state *ipc_cli, } done: - mask.mask = amask; + mask = amask; init_sec_ace(ace, &sid, atype, mask, aflags); return True; } @@ -3932,8 +4061,10 @@ add_ace(SEC_ACL **the_acl, return True; } - aces = SMB_CALLOC_ARRAY(SEC_ACE, 1+(*the_acl)->num_aces); - memcpy(aces, (*the_acl)->ace, (*the_acl)->num_aces * sizeof(SEC_ACE)); + if ((aces = SMB_CALLOC_ARRAY(SEC_ACE, 1+(*the_acl)->num_aces)) == NULL) { + return False; + } + 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); @@ -3955,7 +4086,7 @@ sec_desc_parse(TALLOC_CTX *ctx, fstring tok; SEC_DESC *ret = NULL; size_t sd_size; - DOM_SID *grp_sid=NULL; + DOM_SID *group_sid=NULL; DOM_SID *owner_sid=NULL; SEC_ACL *dacl=NULL; int revision=1; @@ -4000,15 +4131,15 @@ sec_desc_parse(TALLOC_CTX *ctx, } if (StrnCaseCmp(tok,"GROUP:", 6) == 0) { - if (grp_sid) { + if (group_sid) { DEBUG(5, ("GROUP specified more than once!\n")); goto done; } - grp_sid = SMB_CALLOC_ARRAY(DOM_SID, 1); - if (!grp_sid || + group_sid = SMB_CALLOC_ARRAY(DOM_SID, 1); + if (!group_sid || !convert_string_to_sid(ipc_cli, pol, numeric, - grp_sid, tok+6)) { + group_sid, tok+6)) { DEBUG(5, ("Failed to parse group sid\n")); goto done; } @@ -4016,15 +4147,15 @@ sec_desc_parse(TALLOC_CTX *ctx, } if (StrnCaseCmp(tok,"GROUP+:", 7) == 0) { - if (grp_sid) { + if (group_sid) { DEBUG(5, ("GROUP specified more than once!\n")); goto done; } - grp_sid = SMB_CALLOC_ARRAY(DOM_SID, 1); - if (!grp_sid || + group_sid = SMB_CALLOC_ARRAY(DOM_SID, 1); + if (!group_sid || !convert_string_to_sid(ipc_cli, pol, False, - grp_sid, tok+6)) { + group_sid, tok+6)) { DEBUG(5, ("Failed to parse group sid\n")); goto done; } @@ -4062,10 +4193,10 @@ sec_desc_parse(TALLOC_CTX *ctx, } ret = make_sec_desc(ctx, revision, SEC_DESC_SELF_RELATIVE, - owner_sid, grp_sid, NULL, dacl, &sd_size); + owner_sid, group_sid, NULL, dacl, &sd_size); done: - SAFE_FREE(grp_sid); + SAFE_FREE(group_sid); SAFE_FREE(owner_sid); return ret; @@ -4079,7 +4210,10 @@ dos_attr_query(SMBCCTX *context, const char *filename, SMBCSRV *srv) { - time_t m_time = 0, a_time = 0, c_time = 0; + struct timespec create_time_ts; + struct timespec write_time_ts; + struct timespec access_time_ts; + struct timespec change_time_ts; SMB_OFF_T size = 0; uint16 mode = 0; SMB_INO_T inode = 0; @@ -4094,9 +4228,13 @@ dos_attr_query(SMBCCTX *context, /* Obtain the DOS attributes */ if (!smbc_getatr(context, srv, CONST_DISCARD(char *, filename), &mode, &size, - &c_time, &a_time, &m_time, &inode)) { + &create_time_ts, + &access_time_ts, + &write_time_ts, + &change_time_ts, + &inode)) { - errno = smbc_errno(context, &srv->cli); + errno = smbc_errno(context, srv->cli); DEBUG(5, ("dos_attr_query Failed to query old attributes\n")); return NULL; @@ -4104,9 +4242,10 @@ dos_attr_query(SMBCCTX *context, ret->mode = mode; ret->size = size; - ret->a_time = a_time; - ret->c_time = c_time; - ret->m_time = m_time; + ret->create_time = convert_timespec_to_time_t(create_time_ts); + ret->access_time = convert_timespec_to_time_t(access_time_ts); + ret->write_time = convert_timespec_to_time_t(write_time_ts); + ret->change_time = convert_timespec_to_time_t(change_time_ts); ret->inode = inode; return ret; @@ -4120,8 +4259,40 @@ dos_attr_parse(SMBCCTX *context, SMBCSRV *srv, char *str) { - const char *p = str; + int n; + const char *p = str; fstring tok; + struct { + const char * create_time_attr; + const char * access_time_attr; + const char * write_time_attr; + const char * change_time_attr; + } attr_strings; + + /* Determine whether to use old-style or new-style attribute names */ + if (context->internal->_full_time_names) { + /* new-style names */ + attr_strings.create_time_attr = "CREATE_TIME"; + attr_strings.access_time_attr = "ACCESS_TIME"; + attr_strings.write_time_attr = "WRITE_TIME"; + attr_strings.change_time_attr = "CHANGE_TIME"; + } else { + /* old-style names */ + attr_strings.create_time_attr = NULL; + attr_strings.access_time_attr = "A_TIME"; + attr_strings.write_time_attr = "M_TIME"; + attr_strings.change_time_attr = "C_TIME"; + } + + /* if this is to set the entire ACL... */ + if (*str == '*') { + /* ... then increment past the first colon if there is one */ + if ((p = strchr(str, ':')) != NULL) { + ++p; + } else { + p = str; + } + } while (next_token(&p, tok, "\t,\r\n", sizeof(tok))) { @@ -4135,21 +4306,34 @@ dos_attr_parse(SMBCCTX *context, continue; } - if (StrnCaseCmp(tok, "A_TIME:", 7) == 0) { - dad->a_time = (time_t)strtol(tok+7, NULL, 10); + n = strlen(attr_strings.access_time_attr); + if (StrnCaseCmp(tok, attr_strings.access_time_attr, n) == 0) { + dad->access_time = (time_t)strtol(tok+n+1, NULL, 10); continue; } - if (StrnCaseCmp(tok, "C_TIME:", 7) == 0) { - dad->c_time = (time_t)strtol(tok+7, NULL, 10); + n = strlen(attr_strings.change_time_attr); + if (StrnCaseCmp(tok, attr_strings.change_time_attr, n) == 0) { + dad->change_time = (time_t)strtol(tok+n+1, NULL, 10); continue; } - if (StrnCaseCmp(tok, "M_TIME:", 7) == 0) { - dad->m_time = (time_t)strtol(tok+7, NULL, 10); + n = strlen(attr_strings.write_time_attr); + if (StrnCaseCmp(tok, attr_strings.write_time_attr, n) == 0) { + dad->write_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) { dad->inode = (SMB_INO_T)atof(tok+6); continue; @@ -4187,9 +4371,10 @@ cacl_get(SMBCCTX *context, BOOL exclude_nt_acl = False; BOOL exclude_dos_mode = False; BOOL exclude_dos_size = False; - BOOL exclude_dos_ctime = False; - BOOL exclude_dos_atime = False; - BOOL exclude_dos_mtime = False; + BOOL exclude_dos_create_time = False; + BOOL exclude_dos_access_time = False; + BOOL exclude_dos_write_time = False; + BOOL exclude_dos_change_time = False; BOOL exclude_dos_inode = False; BOOL numeric = True; BOOL determine_size = (bufsize == 0); @@ -4200,11 +4385,55 @@ cacl_get(SMBCCTX *context, char *name; char *pExclude; char *p; - time_t m_time = 0, a_time = 0, c_time = 0; + struct timespec create_time_ts; + struct timespec write_time_ts; + struct timespec access_time_ts; + struct timespec change_time_ts; + time_t create_time = (time_t)0; + time_t write_time = (time_t)0; + time_t access_time = (time_t)0; + time_t change_time = (time_t)0; SMB_OFF_T size = 0; uint16 mode = 0; SMB_INO_T ino = 0; - struct cli_state *cli = &srv->cli; + struct cli_state *cli = srv->cli; + struct { + const char * create_time_attr; + const char * access_time_attr; + const char * write_time_attr; + const char * change_time_attr; + } attr_strings; + struct { + const char * create_time_attr; + const char * access_time_attr; + const char * write_time_attr; + const char * change_time_attr; + } excl_attr_strings; + + /* Determine whether to use old-style or new-style attribute names */ + if (context->internal->_full_time_names) { + /* new-style names */ + attr_strings.create_time_attr = "CREATE_TIME"; + attr_strings.access_time_attr = "ACCESS_TIME"; + attr_strings.write_time_attr = "WRITE_TIME"; + attr_strings.change_time_attr = "CHANGE_TIME"; + + excl_attr_strings.create_time_attr = "CREATE_TIME"; + excl_attr_strings.access_time_attr = "ACCESS_TIME"; + excl_attr_strings.write_time_attr = "WRITE_TIME"; + excl_attr_strings.change_time_attr = "CHANGE_TIME"; + } else { + /* old-style names */ + attr_strings.create_time_attr = NULL; + attr_strings.access_time_attr = "A_TIME"; + attr_strings.write_time_attr = "M_TIME"; + attr_strings.change_time_attr = "C_TIME"; + + excl_attr_strings.create_time_attr = NULL; + excl_attr_strings.access_time_attr = "dos_attr.A_TIME"; + excl_attr_strings.write_time_attr = "dos_attr.M_TIME"; + excl_attr_strings.change_time_attr = "dos_attr.C_TIME"; + } /* Copy name so we can strip off exclusions (if any are specified) */ strncpy(name_sandbox, attr_name, sizeof(name_sandbox) - 1); @@ -4262,14 +4491,22 @@ cacl_get(SMBCCTX *context, else if (StrCaseCmp(pExclude, "dos_attr.size") == 0) { exclude_dos_size = True; } - else if (StrCaseCmp(pExclude, "dos_attr.c_time") == 0) { - exclude_dos_ctime = True; + else if (excl_attr_strings.create_time_attr != NULL && + StrCaseCmp(pExclude, + excl_attr_strings.change_time_attr) == 0) { + exclude_dos_create_time = True; } - else if (StrCaseCmp(pExclude, "dos_attr.a_time") == 0) { - exclude_dos_atime = True; + else if (StrCaseCmp(pExclude, + excl_attr_strings.access_time_attr) == 0) { + exclude_dos_access_time = True; } - else if (StrCaseCmp(pExclude, "dos_attr.m_time") == 0) { - exclude_dos_mtime = True; + else if (StrCaseCmp(pExclude, + excl_attr_strings.write_time_attr) == 0) { + exclude_dos_write_time = True; + } + else if (StrCaseCmp(pExclude, + excl_attr_strings.change_time_attr) == 0) { + exclude_dos_change_time = True; } else if (StrCaseCmp(pExclude, "dos_attr.inode") == 0) { exclude_dos_inode = True; @@ -4352,6 +4589,7 @@ cacl_get(SMBCCTX *context, buf += n; n_used += n; bufsize -= n; + n = 0; } if (! exclude_nt_owner) { @@ -4374,7 +4612,7 @@ cacl_get(SMBCCTX *context, return -1; } n = strlen(p); - } else { + } else if (sidstr[0] != '\0') { n = snprintf(buf, bufsize, ",OWNER:%s", sidstr); } @@ -4399,13 +4637,14 @@ cacl_get(SMBCCTX *context, buf += n; n_used += n; bufsize -= n; + n = 0; } 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, ""); } @@ -4419,7 +4658,7 @@ cacl_get(SMBCCTX *context, return -1; } n = strlen(p); - } else { + } else if (sidstr[0] != '\0') { n = snprintf(buf, bufsize, ",GROUP:%s", sidstr); } @@ -4444,13 +4683,14 @@ cacl_get(SMBCCTX *context, buf += n; n_used += n; bufsize -= n; + n = 0; } if (! exclude_nt_acl) { /* 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); @@ -4464,7 +4704,7 @@ cacl_get(SMBCCTX *context, sidstr, ace->type, ace->flags, - ace->info.mask); + ace->access_mask); if (!p) { errno = ENOMEM; return -1; @@ -4477,7 +4717,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) || @@ -4489,7 +4729,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; @@ -4500,7 +4740,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) { @@ -4511,7 +4751,7 @@ cacl_get(SMBCCTX *context, sidstr, ace->type, ace->flags, - ace->info.mask); + ace->access_mask); if (!p) { errno = ENOMEM; return -1; @@ -4524,16 +4764,17 @@ 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; } buf += n; n_used += n; bufsize -= n; + n = 0; } } @@ -4547,13 +4788,22 @@ cacl_get(SMBCCTX *context, /* Obtain the DOS attributes */ if (!smbc_getatr(context, srv, filename, &mode, &size, - &c_time, &a_time, &m_time, &ino)) { + &create_time_ts, + &access_time_ts, + &write_time_ts, + &change_time_ts, + &ino)) { - errno = smbc_errno(context, &srv->cli); + errno = smbc_errno(context, srv->cli); return -1; } - + + create_time = convert_timespec_to_time_t(create_time_ts); + access_time = convert_timespec_to_time_t(access_time_ts); + write_time = convert_timespec_to_time_t(write_time_ts); + change_time = convert_timespec_to_time_t(change_time_ts); + if (! exclude_dos_mode) { if (all || all_dos) { if (determine_size) { @@ -4599,6 +4849,7 @@ cacl_get(SMBCCTX *context, buf += n; n_used += n; bufsize -= n; + n = 0; } if (! exclude_dos_size) { @@ -4643,14 +4894,17 @@ cacl_get(SMBCCTX *context, buf += n; n_used += n; bufsize -= n; + n = 0; } - if (! exclude_dos_ctime) { + if (! exclude_dos_create_time && + attr_strings.create_time_attr != NULL) { if (all || all_dos) { if (determine_size) { p = talloc_asprintf(ctx, - ",C_TIME:%lu", - c_time); + ",%s:%lu", + attr_strings.create_time_attr, + create_time); if (!p) { errno = ENOMEM; return -1; @@ -4658,11 +4912,13 @@ cacl_get(SMBCCTX *context, n = strlen(p); } else { n = snprintf(buf, bufsize, - ",C_TIME:%lu", c_time); + ",%s:%lu", + attr_strings.create_time_attr, + create_time); } - } else if (StrCaseCmp(name, "c_time") == 0) { + } else if (StrCaseCmp(name, attr_strings.create_time_attr) == 0) { if (determine_size) { - p = talloc_asprintf(ctx, "%lu", c_time); + p = talloc_asprintf(ctx, "%lu", create_time); if (!p) { errno = ENOMEM; return -1; @@ -4670,7 +4926,7 @@ cacl_get(SMBCCTX *context, n = strlen(p); } else { n = snprintf(buf, bufsize, - "%lu", c_time); + "%lu", create_time); } } @@ -4681,14 +4937,16 @@ cacl_get(SMBCCTX *context, buf += n; n_used += n; bufsize -= n; + n = 0; } - if (! exclude_dos_atime) { + if (! exclude_dos_access_time) { if (all || all_dos) { if (determine_size) { p = talloc_asprintf(ctx, - ",A_TIME:%lu", - a_time); + ",%s:%lu", + attr_strings.access_time_attr, + access_time); if (!p) { errno = ENOMEM; return -1; @@ -4696,11 +4954,13 @@ cacl_get(SMBCCTX *context, n = strlen(p); } else { n = snprintf(buf, bufsize, - ",A_TIME:%lu", a_time); + ",%s:%lu", + attr_strings.access_time_attr, + access_time); } - } else if (StrCaseCmp(name, "a_time") == 0) { + } else if (StrCaseCmp(name, attr_strings.access_time_attr) == 0) { if (determine_size) { - p = talloc_asprintf(ctx, "%lu", a_time); + p = talloc_asprintf(ctx, "%lu", access_time); if (!p) { errno = ENOMEM; return -1; @@ -4708,7 +4968,7 @@ cacl_get(SMBCCTX *context, n = strlen(p); } else { n = snprintf(buf, bufsize, - "%lu", a_time); + "%lu", access_time); } } @@ -4719,14 +4979,16 @@ cacl_get(SMBCCTX *context, buf += n; n_used += n; bufsize -= n; + n = 0; } - if (! exclude_dos_mtime) { + if (! exclude_dos_write_time) { if (all || all_dos) { if (determine_size) { p = talloc_asprintf(ctx, - ",M_TIME:%lu", - m_time); + ",%s:%lu", + attr_strings.write_time_attr, + write_time); if (!p) { errno = ENOMEM; return -1; @@ -4734,11 +4996,13 @@ cacl_get(SMBCCTX *context, n = strlen(p); } else { n = snprintf(buf, bufsize, - ",M_TIME:%lu", m_time); + ",%s:%lu", + attr_strings.write_time_attr, + write_time); } - } else if (StrCaseCmp(name, "m_time") == 0) { + } else if (StrCaseCmp(name, attr_strings.write_time_attr) == 0) { if (determine_size) { - p = talloc_asprintf(ctx, "%lu", m_time); + p = talloc_asprintf(ctx, "%lu", write_time); if (!p) { errno = ENOMEM; return -1; @@ -4746,7 +5010,7 @@ cacl_get(SMBCCTX *context, n = strlen(p); } else { n = snprintf(buf, bufsize, - "%lu", m_time); + "%lu", write_time); } } @@ -4757,6 +5021,49 @@ cacl_get(SMBCCTX *context, buf += n; n_used += n; bufsize -= n; + n = 0; + } + + if (! exclude_dos_change_time) { + if (all || all_dos) { + if (determine_size) { + p = talloc_asprintf(ctx, + ",%s:%lu", + attr_strings.change_time_attr, + change_time); + if (!p) { + errno = ENOMEM; + return -1; + } + n = strlen(p); + } else { + n = snprintf(buf, bufsize, + ",%s:%lu", + attr_strings.change_time_attr, + change_time); + } + } else if (StrCaseCmp(name, attr_strings.change_time_attr) == 0) { + if (determine_size) { + p = talloc_asprintf(ctx, "%lu", change_time); + if (!p) { + errno = ENOMEM; + return -1; + } + n = strlen(p); + } else { + n = snprintf(buf, bufsize, + "%lu", change_time); + } + } + + if (!determine_size && n > bufsize) { + errno = ERANGE; + return -1; + } + buf += n; + n_used += n; + bufsize -= n; + n = 0; } if (! exclude_dos_inode) { @@ -4801,6 +5108,7 @@ cacl_get(SMBCCTX *context, buf += n; n_used += n; bufsize -= n; + n = 0; } /* Restore name pointer to its original value */ @@ -4834,7 +5142,7 @@ cacl_set(TALLOC_CTX *ctx, SEC_DESC *sd = NULL, *old; SEC_ACL *dacl = NULL; DOM_SID *owner_sid = NULL; - DOM_SID *grp_sid = NULL; + DOM_SID *group_sid = NULL; uint32 i, j; size_t sd_size; int ret = 0; @@ -4895,9 +5203,6 @@ 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); - old->off_dacl = 0; dacl = old->dacl; break; @@ -4906,19 +5211,14 @@ cacl_set(TALLOC_CTX *ctx, BOOL found = False; for (j=0;old->dacl && jdacl->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; kdacl->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); - old->off_dacl = 0; - } found = True; dacl = old->dacl; break; @@ -4938,14 +5238,14 @@ cacl_set(TALLOC_CTX *ctx, BOOL found = False; for (j=0;old->dacl && jdacl->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; } @@ -4958,7 +5258,7 @@ cacl_set(TALLOC_CTX *ctx, } for (i=0;sd->dacl && idacl->num_aces;i++) { - add_ace(&old->dacl, &sd->dacl->ace[i], ctx); + add_ace(&old->dacl, &sd->dacl->aces[i], ctx); } } dacl = old->dacl; @@ -4967,7 +5267,7 @@ cacl_set(TALLOC_CTX *ctx, case SMBC_XATTR_MODE_SET: old = sd; owner_sid = old->owner_sid; - grp_sid = old->grp_sid; + group_sid = old->group_sid; dacl = old->dacl; break; @@ -4976,7 +5276,7 @@ cacl_set(TALLOC_CTX *ctx, break; case SMBC_XATTR_MODE_CHGRP: - grp_sid = sd->grp_sid; + group_sid = sd->group_sid; break; } @@ -4985,7 +5285,7 @@ cacl_set(TALLOC_CTX *ctx, /* Create new security descriptor and set it */ sd = make_sec_desc(ctx, old->revision, SEC_DESC_SELF_RELATIVE, - owner_sid, grp_sid, NULL, dacl, &sd_size); + owner_sid, group_sid, NULL, dacl, &sd_size); fnum = cli_nt_create(cli, filename, WRITE_DAC_ACCESS | WRITE_OWNER_ACCESS); @@ -5036,6 +5336,12 @@ smbc_setxattr_ctx(SMBCCTX *context, TALLOC_CTX *ctx; POLICY_HND pol; DOS_ATTR_DESC *dad; + struct { + const char * create_time_attr; + const char * access_time_attr; + const char * write_time_attr; + const char * change_time_attr; + } attr_strings; if (!context || !context->internal || !context->internal->_initialized) { @@ -5079,7 +5385,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; } @@ -5106,8 +5414,8 @@ smbc_setxattr_ctx(SMBCCTX *context, } if (ipc_srv) { - ret = cacl_set(ctx, &srv->cli, - &ipc_srv->cli, &pol, path, + ret = cacl_set(ctx, srv->cli, + ipc_srv->cli, &pol, path, namevalue, (*namevalue == '*' ? SMBC_XATTR_MODE_SET @@ -5125,9 +5433,10 @@ smbc_setxattr_ctx(SMBCCTX *context, /* Set the new DOS attributes */ if (! smbc_setatr(context, srv, path, - dad->c_time, - dad->a_time, - dad->m_time, + dad->create_time, + dad->access_time, + dad->write_time, + dad->change_time, dad->mode)) { /* cause failure if NT failed too */ @@ -5169,8 +5478,8 @@ smbc_setxattr_ctx(SMBCCTX *context, errno = ENOMEM; ret = -1; } else { - ret = cacl_set(ctx, &srv->cli, - &ipc_srv->cli, &pol, path, + ret = cacl_set(ctx, srv->cli, + ipc_srv->cli, &pol, path, namevalue, (*namevalue == '*' ? SMBC_XATTR_MODE_SET @@ -5200,8 +5509,8 @@ smbc_setxattr_ctx(SMBCCTX *context, errno = ENOMEM; ret = -1; } else { - ret = cacl_set(ctx, &srv->cli, - &ipc_srv->cli, &pol, path, + ret = cacl_set(ctx, srv->cli, + ipc_srv->cli, &pol, path, namevalue, SMBC_XATTR_MODE_CHOWN, 0); } talloc_destroy(ctx); @@ -5227,22 +5536,39 @@ smbc_setxattr_ctx(SMBCCTX *context, errno = ENOMEM; ret = -1; } else { - ret = cacl_set(ctx, &srv->cli, - &ipc_srv->cli, &pol, path, + ret = cacl_set(ctx, srv->cli, + ipc_srv->cli, &pol, path, namevalue, SMBC_XATTR_MODE_CHOWN, 0); } talloc_destroy(ctx); return ret; } + /* Determine whether to use old-style or new-style attribute names */ + if (context->internal->_full_time_names) { + /* new-style names */ + attr_strings.create_time_attr = "system.dos_attr.CREATE_TIME"; + attr_strings.access_time_attr = "system.dos_attr.ACCESS_TIME"; + attr_strings.write_time_attr = "system.dos_attr.WRITE_TIME"; + attr_strings.change_time_attr = "system.dos_attr.CHANGE_TIME"; + } else { + /* old-style names */ + attr_strings.create_time_attr = NULL; + attr_strings.access_time_attr = "system.dos_attr.A_TIME"; + attr_strings.write_time_attr = "system.dos_attr.M_TIME"; + attr_strings.change_time_attr = "system.dos_attr.C_TIME"; + } + /* * Are they asking to set a DOS attribute? */ if (StrCaseCmp(name, "system.dos_attr.*") == 0 || StrCaseCmp(name, "system.dos_attr.mode") == 0 || - StrCaseCmp(name, "system.dos_attr.c_time") == 0 || - StrCaseCmp(name, "system.dos_attr.a_time") == 0 || - StrCaseCmp(name, "system.dos_attr.m_time") == 0) { + (attr_strings.create_time_attr != NULL && + StrCaseCmp(name, attr_strings.create_time_attr) == 0) || + StrCaseCmp(name, attr_strings.access_time_attr) == 0 || + StrCaseCmp(name, attr_strings.write_time_attr) == 0 || + StrCaseCmp(name, attr_strings.change_time_attr) == 0) { /* get a DOS Attribute Descriptor with current attributes */ dad = dos_attr_query(context, ctx, path, srv); @@ -5259,9 +5585,10 @@ smbc_setxattr_ctx(SMBCCTX *context, /* Set the new DOS attributes */ ret2 = smbc_setatr(context, srv, path, - dad->c_time, - dad->a_time, - dad->m_time, + dad->create_time, + dad->access_time, + dad->write_time, + dad->change_time, dad->mode); /* ret2 has True (success) / False (failure) */ @@ -5303,6 +5630,12 @@ smbc_getxattr_ctx(SMBCCTX *context, pstring path; TALLOC_CTX *ctx; POLICY_HND pol; + struct { + const char * create_time_attr; + const char * access_time_attr; + const char * write_time_attr; + const char * change_time_attr; + } attr_strings; if (!context || !context->internal || @@ -5359,6 +5692,21 @@ smbc_getxattr_ctx(SMBCCTX *context, return -1; } + /* Determine whether to use old-style or new-style attribute names */ + if (context->internal->_full_time_names) { + /* new-style names */ + attr_strings.create_time_attr = "system.dos_attr.CREATE_TIME"; + attr_strings.access_time_attr = "system.dos_attr.ACCESS_TIME"; + attr_strings.write_time_attr = "system.dos_attr.WRITE_TIME"; + attr_strings.change_time_attr = "system.dos_attr.CHANGE_TIME"; + } else { + /* old-style names */ + attr_strings.create_time_attr = NULL; + attr_strings.access_time_attr = "system.dos_attr.A_TIME"; + attr_strings.write_time_attr = "system.dos_attr.M_TIME"; + attr_strings.change_time_attr = "system.dos_attr.C_TIME"; + } + /* Are they requesting a supported attribute? */ if (StrCaseCmp(name, "system.*") == 0 || StrnCaseCmp(name, "system.*!", 9) == 0 || @@ -5379,19 +5727,21 @@ smbc_getxattr_ctx(SMBCCTX *context, StrnCaseCmp(name, "system.dos_attr.*!", 18) == 0 || StrCaseCmp(name, "system.dos_attr.mode") == 0 || StrCaseCmp(name, "system.dos_attr.size") == 0 || - StrCaseCmp(name, "system.dos_attr.c_time") == 0 || - StrCaseCmp(name, "system.dos_attr.a_time") == 0 || - StrCaseCmp(name, "system.dos_attr.m_time") == 0 || + (attr_strings.create_time_attr != NULL && + StrCaseCmp(name, attr_strings.create_time_attr) == 0) || + StrCaseCmp(name, attr_strings.access_time_attr) == 0 || + StrCaseCmp(name, attr_strings.write_time_attr) == 0 || + StrCaseCmp(name, attr_strings.change_time_attr) == 0 || StrCaseCmp(name, "system.dos_attr.inode") == 0) { /* Yup. */ ret = cacl_get(context, ctx, srv, - ipc_srv == NULL ? NULL : &ipc_srv->cli, + ipc_srv == NULL ? NULL : ipc_srv->cli, &pol, path, CONST_DISCARD(char *, name), CONST_DISCARD(char *, value), size); if (ret < 0 && errno == 0) { - errno = smbc_errno(context, &srv->cli); + errno = smbc_errno(context, srv->cli); } talloc_destroy(ctx); return ret; @@ -5462,7 +5812,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; } @@ -5482,8 +5834,8 @@ smbc_removexattr_ctx(SMBCCTX *context, StrCaseCmp(name, "system.nt_sec_desc.*+") == 0) { /* Yup. */ - ret = cacl_set(ctx, &srv->cli, - &ipc_srv->cli, &pol, path, + ret = cacl_set(ctx, srv->cli, + ipc_srv->cli, &pol, path, NULL, SMBC_XATTR_MODE_REMOVE_ALL, 0); talloc_destroy(ctx); return ret; @@ -5502,8 +5854,8 @@ smbc_removexattr_ctx(SMBCCTX *context, StrnCaseCmp(name, "system.nt_sec_desc.acl+", 23) == 0) { /* Yup. */ - ret = cacl_set(ctx, &srv->cli, - &ipc_srv->cli, &pol, path, + ret = cacl_set(ctx, srv->cli, + ipc_srv->cli, &pol, path, name + 19, SMBC_XATTR_MODE_REMOVE, 0); talloc_destroy(ctx); return ret; @@ -5526,7 +5878,7 @@ smbc_listxattr_ctx(SMBCCTX *context, * the complete set of attribute names, always, rather than only those * attribute names which actually exist for a file. Hmmm... */ - const char supported[] = + const char supported_old[] = "system.*\0" "system.*+\0" "system.nt_sec_desc.revision\0" @@ -5545,6 +5897,33 @@ smbc_listxattr_ctx(SMBCCTX *context, "system.dos_attr.a_time\0" "system.dos_attr.m_time\0" ; + const char supported_new[] = + "system.*\0" + "system.*+\0" + "system.nt_sec_desc.revision\0" + "system.nt_sec_desc.owner\0" + "system.nt_sec_desc.owner+\0" + "system.nt_sec_desc.group\0" + "system.nt_sec_desc.group+\0" + "system.nt_sec_desc.acl.*\0" + "system.nt_sec_desc.acl\0" + "system.nt_sec_desc.acl+\0" + "system.nt_sec_desc.*\0" + "system.nt_sec_desc.*+\0" + "system.dos_attr.*\0" + "system.dos_attr.mode\0" + "system.dos_attr.create_time\0" + "system.dos_attr.access_time\0" + "system.dos_attr.write_time\0" + "system.dos_attr.change_time\0" + ; + const char * supported; + + if (context->internal->_full_time_names) { + supported = supported_new; + } else { + supported = supported_old; + } if (size == 0) { return sizeof(supported); @@ -5606,7 +5985,7 @@ smbc_open_print_job_ctx(SMBCCTX *context, /* What if the path is empty, or the file exists? */ - return context->open(context, fname, O_WRONLY, 666); + return (context->open)(context, fname, O_WRONLY, 666); } @@ -5647,7 +6026,7 @@ smbc_print_file_ctx(SMBCCTX *c_file, /* Try to open the file for reading ... */ - if ((long)(fid1 = c_file->open(c_file, fname, O_RDONLY, 0666)) < 0) { + if ((long)(fid1 = (c_file->open)(c_file, fname, O_RDONLY, 0666)) < 0) { DEBUG(3, ("Error, fname=%s, errno=%i\n", fname, errno)); return -1; /* smbc_open sets errno */ @@ -5656,24 +6035,24 @@ smbc_print_file_ctx(SMBCCTX *c_file, /* Now, try to open the printer file for writing */ - if ((long)(fid2 = c_print->open_print_job(c_print, printq)) < 0) { + if ((long)(fid2 = (c_print->open_print_job)(c_print, printq)) < 0) { saverr = errno; /* Save errno */ - c_file->close_fn(c_file, fid1); + (c_file->close_fn)(c_file, fid1); errno = saverr; return -1; } - while ((bytes = c_file->read(c_file, fid1, buf, sizeof(buf))) > 0) { + while ((bytes = (c_file->read)(c_file, fid1, buf, sizeof(buf))) > 0) { tot_bytes += bytes; - if ((c_print->write(c_print, fid2, buf, bytes)) < 0) { + if (((c_print->write)(c_print, fid2, buf, bytes)) < 0) { saverr = errno; - c_file->close_fn(c_file, fid1); - c_print->close_fn(c_print, fid2); + (c_file->close_fn)(c_file, fid1); + (c_print->close_fn)(c_print, fid2); errno = saverr; } @@ -5682,8 +6061,8 @@ smbc_print_file_ctx(SMBCCTX *c_file, saverr = errno; - c_file->close_fn(c_file, fid1); /* We have to close these anyway */ - c_print->close_fn(c_print, fid2); + (c_file->close_fn)(c_file, fid1); /* We have to close these anyway */ + (c_print->close_fn)(c_print, fid2); if (bytes < 0) { @@ -5753,10 +6132,10 @@ smbc_list_print_jobs_ctx(SMBCCTX *context, } - if (cli_print_queue(&srv->cli, + if (cli_print_queue(srv->cli, (void (*)(struct print_job_info *))fn) < 0) { - errno = smbc_errno(context, &srv->cli); + errno = smbc_errno(context, srv->cli); return -1; } @@ -5823,10 +6202,10 @@ smbc_unlink_print_job_ctx(SMBCCTX *context, } - if ((err = cli_printjob_del(&srv->cli, id)) != 0) { + if ((err = cli_printjob_del(srv->cli, id)) != 0) { if (err < 0) - errno = smbc_errno(context, &srv->cli); + errno = smbc_errno(context, srv->cli); else if (err == ERRnosuchprintjob) errno = EINVAL; return -1; @@ -5870,6 +6249,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; @@ -5931,7 +6312,7 @@ smbc_free_context(SMBCCTX *context, f = context->internal->_files; while (f) { - context->close_fn(context, f); + (context->close_fn)(context, f); f = f->next; } context->internal->_files = NULL; @@ -5945,10 +6326,10 @@ smbc_free_context(SMBCCTX *context, s = context->internal->_servers; while (s) { DEBUG(1, ("Forced shutdown: %p (fd=%d)\n", - s, s->cli.fd)); - cli_shutdown(&s->cli); - context->callbacks.remove_cached_srv_fn(context, - s); + s, s->cli->fd)); + cli_shutdown(s->cli); + (context->callbacks.remove_cached_srv_fn)(context, + s); next = s->next; DLIST_REMOVE(context->internal->_servers, s); SAFE_FREE(s); @@ -5959,7 +6340,7 @@ smbc_free_context(SMBCCTX *context, } else { /* This is the polite way */ - if (context->callbacks.purge_cached_fn(context)) { + if ((context->callbacks.purge_cached_fn)(context)) { DEBUG(1, ("Could not purge all servers, " "free_context failed.\n")); errno = EBUSY; @@ -6001,27 +6382,65 @@ smbc_free_context(SMBCCTX *context, void smbc_option_set(SMBCCTX *context, char *option_name, - void *option_value) + ... /* option_value */) { - if (strcmp(option_name, "debug_stderr") == 0) { + va_list ap; + union { + int i; + BOOL b; + smbc_get_auth_data_with_context_fn auth_fn; + void *v; + } option_value; + + va_start(ap, option_name); + + if (strcmp(option_name, "debug_to_stderr") == 0) { /* * Log to standard error instead of standard output. */ - context->internal->_debug_stderr = - (option_value == NULL ? False : True); + option_value.b = (BOOL) va_arg(ap, int); + context->internal->_debug_stderr = option_value.b; + + } else if (strcmp(option_name, "full_time_names") == 0) { + /* + * Use new-style time attribute names, e.g. WRITE_TIME rather + * than the old-style names such as M_TIME. This allows also + * setting/getting CREATE_TIME which was previously + * unimplemented. (Note that the old C_TIME was supposed to + * be CHANGE_TIME but was confused and sometimes referred to + * CREATE_TIME.) + */ + 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 * the context. */ - context->internal->_auth_fn_with_context = option_value; + option_value.auth_fn = + va_arg(ap, smbc_get_auth_data_with_context_fn); + context->internal->_auth_fn_with_context = + option_value.auth_fn; } else if (strcmp(option_name, "user_data") == 0) { /* * Save a user data handle which may be retrieved by the user * with smbc_option_get() */ - context->internal->_user_data = option_value; + option_value.v = va_arg(ap, void *); + context->internal->_user_data = option_value.v; } + + va_end(ap); } @@ -6036,7 +6455,26 @@ smbc_option_get(SMBCCTX *context, /* * Log to standard error instead of standard output. */ - return (void *) context->internal->_debug_stderr; +#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) + return (void *) (intptr_t) context->internal->_debug_stderr; +#else + return (void *) context->internal->_debug_stderr; +#endif + } else if (strcmp(option_name, "full_time_names") == 0) { + /* + * Use new-style time attribute names, e.g. WRITE_TIME rather + * than the old-style names such as M_TIME. This allows also + * setting/getting CREATE_TIME which was previously + * unimplemented. (Note that the old C_TIME was supposed to + * be CHANGE_TIME but was confused and sometimes referred to + * CREATE_TIME.) + */ +#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) + return (void *) (intptr_t) context->internal->_full_time_names; +#else + return (void *) context->internal->_full_time_names; +#endif + } else if (strcmp(option_name, "auth_function") == 0) { /* * Use the new-style authentication function which includes @@ -6191,7 +6629,7 @@ smbc_init_context(SMBCCTX *context) * lazy for the moment */ pid = sys_getpid(); - context->netbios_name = SMB_MALLOC(17); + context->netbios_name = (char *)SMB_MALLOC(17); if (!context->netbios_name) { errno = ENOMEM; return NULL;